summaryrefslogtreecommitdiff
path: root/Build/source/texk/xdvik/gui
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/xdvik/gui')
-rw-r--r--Build/source/texk/xdvik/gui/Makefile.in80
-rw-r--r--Build/source/texk/xdvik/gui/Panner.c1230
-rw-r--r--Build/source/texk/xdvik/gui/Panner.h108
-rw-r--r--Build/source/texk/xdvik/gui/PannerP.h104
-rw-r--r--Build/source/texk/xdvik/gui/Tip.c607
-rw-r--r--Build/source/texk/xdvik/gui/Tip.h62
-rw-r--r--Build/source/texk/xdvik/gui/TipP.h95
-rw-r--r--Build/source/texk/xdvik/gui/depend.mk528
-rw-r--r--Build/source/texk/xdvik/gui/help-window.c1094
-rw-r--r--Build/source/texk/xdvik/gui/help-window.h29
-rw-r--r--Build/source/texk/xdvik/gui/mag.c861
-rw-r--r--Build/source/texk/xdvik/gui/mag.h45
-rw-r--r--Build/source/texk/xdvik/gui/menu.c395
-rw-r--r--Build/source/texk/xdvik/gui/menu.h73
-rw-r--r--Build/source/texk/xdvik/gui/message-window.c1207
-rw-r--r--Build/source/texk/xdvik/gui/message-window.h134
-rw-r--r--Build/source/texk/xdvik/gui/pagesel.c1591
-rw-r--r--Build/source/texk/xdvik/gui/pagesel.h71
-rw-r--r--Build/source/texk/xdvik/gui/print-dialog.c2973
-rw-r--r--Build/source/texk/xdvik/gui/print-dialog.h44
-rw-r--r--Build/source/texk/xdvik/gui/print-log.c552
-rw-r--r--Build/source/texk/xdvik/gui/print-log.h46
-rw-r--r--Build/source/texk/xdvik/gui/search-dialog.c1072
-rw-r--r--Build/source/texk/xdvik/gui/search-dialog.h68
-rw-r--r--Build/source/texk/xdvik/gui/selection.c242
-rw-r--r--Build/source/texk/xdvik/gui/selection.h32
-rw-r--r--Build/source/texk/xdvik/gui/sfDir.c165
-rw-r--r--Build/source/texk/xdvik/gui/sfDir.h63
-rw-r--r--Build/source/texk/xdvik/gui/sfDraw.c819
-rw-r--r--Build/source/texk/xdvik/gui/sfDraw.h99
-rw-r--r--Build/source/texk/xdvik/gui/sfPath.c908
-rw-r--r--Build/source/texk/xdvik/gui/sfPath.h45
-rw-r--r--Build/source/texk/xdvik/gui/sfSelFile.c1071
-rw-r--r--Build/source/texk/xdvik/gui/sfSelFile.h46
-rw-r--r--Build/source/texk/xdvik/gui/sfinternal.h59
-rw-r--r--Build/source/texk/xdvik/gui/statusline.c531
-rw-r--r--Build/source/texk/xdvik/gui/statusline.h52
-rw-r--r--Build/source/texk/xdvik/gui/topic-window.c650
-rw-r--r--Build/source/texk/xdvik/gui/topic-window.h80
-rw-r--r--Build/source/texk/xdvik/gui/xaw_bitmaps.c82
-rw-r--r--Build/source/texk/xdvik/gui/xaw_bitmaps.h21
-rw-r--r--Build/source/texk/xdvik/gui/xaw_menu.c1449
-rw-r--r--Build/source/texk/xdvik/gui/xaw_menu.h62
-rw-r--r--Build/source/texk/xdvik/gui/xicon.c168
-rw-r--r--Build/source/texk/xdvik/gui/xicon.h29
-rw-r--r--Build/source/texk/xdvik/gui/xlwradio.c677
-rw-r--r--Build/source/texk/xdvik/gui/xlwradio.h119
-rw-r--r--Build/source/texk/xdvik/gui/xlwradioP.h140
-rw-r--r--Build/source/texk/xdvik/gui/xm_colorsel.c664
-rw-r--r--Build/source/texk/xdvik/gui/xm_colorsel.h43
-rw-r--r--Build/source/texk/xdvik/gui/xm_filesel.c195
-rw-r--r--Build/source/texk/xdvik/gui/xm_menu.c364
-rw-r--r--Build/source/texk/xdvik/gui/xm_menu.h45
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs.c590
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs.h39
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefsP.h125
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_appearance.c540
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_appearance.h37
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_fonts.c696
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_fonts.h37
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_helpers.c946
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_helpers.h35
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_page.c695
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_page.h38
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_scroll.c470
-rw-r--r--Build/source/texk/xdvik/gui/xm_prefs_scroll.h34
-rw-r--r--Build/source/texk/xdvik/gui/xm_toolbar.c860
-rw-r--r--Build/source/texk/xdvik/gui/xm_toolbar.h50
68 files changed, 27181 insertions, 0 deletions
diff --git a/Build/source/texk/xdvik/gui/Makefile.in b/Build/source/texk/xdvik/gui/Makefile.in
new file mode 100644
index 00000000000..20343fd95b3
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/Makefile.in
@@ -0,0 +1,80 @@
+# Makefile for xdvik
+#
+# - 1999/05/08: janl: Removed submakes for libwww and kpathsea. That's what
+# the top makefile is for!
+#
+
+
+### NOTE: ac_include paths must be relative to texk/xdvik, since that
+### is from where the configure is run!
+kpse_include ../make/paths.mk
+kpse_include ../make/library.mk
+kpse_include ../make/common.mk
+kpse_include ../make/programs.mk
+
+kpathsea_parent = ../..
+
+CPP = @CPP@
+RANLIB = @RANLIB@
+
+# Make `#include <X11/...>' and `-lX...' work.
+# This matches web2c (needed only for Metafont).
+x_cppflags = @X_CFLAGS@
+
+# Extra xdvi-specific compiler options.
+ps_def = @PS_DEF@ -DXSERVER_INFO
+prog_cflags = @XTRA_WARN_CFLAGS@ -I.. -I$(srcdir)/.. $(x_cppflags) $(ps_def)
+
+# Note: to be able to use one depend.mk file for both Motif/Xaw (which
+# is needed since only maintainers are supposed to invoke `make depend')
+# we include *all* object files and have tests for #ifdef MOTIF/XAW inside
+# the files.
+objects = \
+ help-window.o \
+ message-window.o \
+ mag.o \
+ menu.o \
+ Panner.o \
+ pagesel.o \
+ print-dialog.o \
+ print-log.o \
+ search-dialog.o \
+ selection.o \
+ sfDir.o \
+ sfDraw.o \
+ sfPath.o \
+ sfSelFile.o \
+ statusline.o \
+ Tip.o \
+ topic-window.o \
+ xaw_bitmaps.o \
+ xaw_menu.o \
+ xicon.o \
+ xlwradio.o \
+ xm_colorsel.o \
+ xm_filesel.o \
+ xm_menu.o \
+ xm_prefs.o \
+ xm_prefs_appearance.o \
+ xm_prefs_fonts.o \
+ xm_prefs_page.o \
+ xm_prefs_scroll.o \
+ xm_prefs_helpers.o \
+ xm_toolbar.o
+
+libgui.a: $(objects)
+### hmm, I don't understand ar ... sometimes objects were NOT replaced.
+### Play it safe and always remove the archive before creating new one.
+ rm -f $@
+ $(AR) $(ARFLAGS) $@ $(objects)
+ $(RANLIB) $@
+
+kpse_include ../make/dist.mk
+kpse_include ../make/clean.mk
+
+clean::
+ rm -f *.o *.a
+
+c_auto_h_dir = ..
+kpse_include ../make/rdepend.mk
+kpse_include ./gui/depend.mk
diff --git a/Build/source/texk/xdvik/gui/Panner.c b/Build/source/texk/xdvik/gui/Panner.c
new file mode 100644
index 00000000000..1ff157b6242
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/Panner.c
@@ -0,0 +1,1230 @@
+/*
+ * $XConsortium: Panner.c,v 1.52 95/01/10 14:31:26 kaleb Exp $
+ *
+Copyright (c) 1989, 1994 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "string-utils.h"
+
+#if defined(MOTIF) && defined(USE_PANNER) && USE_XAW_PANNER /* entire file */
+
+#if defined(__GNUC__) && DEVEL_MODE
+#warning COMPILING Panner_c
+#endif
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h> /* for XtN and XtC defines */
+#include <X11/Xmu/CharSet.h> /* for XmuCompareISOLatin1() */
+#include "PannerP.h" /* us */
+#include <X11/Xos.h>
+#include <X11/Xmu/Misc.h> /* for Min */
+#include <X11/Xmu/Drawing.h>
+#include <ctype.h> /* for isascii() etc. */
+
+extern Bool XmuDistinguishablePixels(); /* not defined in any Xmu headers */
+
+/*
+ ======================================================================
+ begin copy from Simple.c
+ ======================================================================
+*/
+
+#define offset(field) XtOffsetOf(SimpleRec, simple.field)
+
+static XtResource resources[] = {
+ {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
+ offset(cursor), XtRImmediate, (XtPointer) None},
+ {XtNinsensitiveBorder, XtCInsensitive, XtRPixmap, sizeof(Pixmap),
+ offset(insensitive_border), XtRImmediate, (XtPointer) NULL},
+ {XtNpointerColor, XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(pointer_fg), XtRString, XtDefaultForeground},
+ {XtNpointerColorBackground, XtCBackground, XtRPixel, sizeof(Pixel),
+ offset(pointer_bg), XtRString, XtDefaultBackground},
+ {XtNcursorName, XtCCursor, XtRString, sizeof(String),
+ offset(cursor_name), XtRString, NULL},
+ {XtNinternational, XtCInternational, XtRBoolean, sizeof(Boolean),
+ offset(international), XtRImmediate, (XtPointer) FALSE},
+#undef offset
+};
+
+static void ClassPartInitialize(), ClassInitialize(),Realize(),ConvertCursor();
+static Bool SetValues(Widget current, Widget request, Widget new, ArgList args, Cardinal *num_args);
+static Bool ChangeSensitive(Widget w);
+
+SimpleClassRec simpleClassRec = {
+ { /* core fields */
+ /* superclass */ (WidgetClass) &widgetClassRec,
+ /* class_name */ "Simple",
+ /* widget_size */ sizeof(SimpleRec),
+ /* class_initialize */ ClassInitialize,
+ /* class_part_initialize */ ClassPartInitialize,
+ /* class_inited */ FALSE,
+ /* initialize */ NULL,
+ /* initialize_hook */ NULL,
+ /* realize */ Realize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ resources,
+ /* num_resources */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ TRUE,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ NULL,
+ /* resize */ NULL,
+ /* expose */ NULL,
+#warning FIXME: incompatible pointer type
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ NULL,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ { /* simple fields */
+ /* change_sensitive */ ChangeSensitive
+#ifndef HAVE_OLD_XAW
+ , NULL
+#endif
+ }
+};
+
+WidgetClass simpleWidgetClass = (WidgetClass)&simpleClassRec;
+
+static void ClassInitialize()
+{
+ static XtConvertArgRec convertArg[] = {
+ {XtWidgetBaseOffset, (XtPointer) XtOffsetOf(WidgetRec, core.screen),
+ sizeof(Screen *)},
+ {XtResourceString, (XtPointer) XtNpointerColor, sizeof(Pixel)},
+ {XtResourceString, (XtPointer) XtNpointerColorBackground,
+ sizeof(Pixel)},
+ {XtWidgetBaseOffset, (XtPointer) XtOffsetOf(WidgetRec, core.colormap),
+ sizeof(Colormap)}
+ };
+
+ XawInitializeWidgetSet();
+ XtSetTypeConverter( XtRString, XtRColorCursor, XmuCvtStringToColorCursor,
+ convertArg, XtNumber(convertArg),
+ XtCacheByDisplay, (XtDestructor)NULL);
+}
+
+static void ClassPartInitialize(class)
+ WidgetClass class;
+{
+ SimpleWidgetClass c = (SimpleWidgetClass) class;
+ SimpleWidgetClass super = (SimpleWidgetClass)
+ c->core_class.superclass;
+
+ if (c->simple_class.change_sensitive == NULL) {
+ char buf[BUFSIZ];
+
+ (void) sprintf(buf,
+ "%s Widget: The Simple Widget class method 'change_sensitive' is undefined.\nA function must be defined or inherited.",
+ c->core_class.class_name);
+ XtWarning(buf);
+ c->simple_class.change_sensitive = ChangeSensitive;
+ }
+
+ if (c->simple_class.change_sensitive == XtInheritChangeSensitive)
+ c->simple_class.change_sensitive = super->simple_class.change_sensitive;
+}
+
+static void Realize(w, valueMask, attributes)
+ Widget w;
+ Mask *valueMask;
+ XSetWindowAttributes *attributes;
+{
+ Pixmap border_pixmap = 0;
+ if (!XtIsSensitive(w)) {
+ /* change border to gray; have to remember the old one,
+ * so XtDestroyWidget deletes the proper one */
+ if (((SimpleWidget)w)->simple.insensitive_border == None)
+ ((SimpleWidget)w)->simple.insensitive_border =
+ XmuCreateStippledPixmap(XtScreen(w),
+ w->core.border_pixel,
+ w->core.background_pixel,
+ w->core.depth);
+ border_pixmap = w->core.border_pixmap;
+ attributes->border_pixmap =
+ w->core.border_pixmap = ((SimpleWidget)w)->simple.insensitive_border;
+
+ *valueMask |= CWBorderPixmap;
+ *valueMask &= ~CWBorderPixel;
+ }
+
+ ConvertCursor(w);
+
+ if ((attributes->cursor = ((SimpleWidget)w)->simple.cursor) != None)
+ *valueMask |= CWCursor;
+
+ XtCreateWindow( w, (unsigned int)InputOutput, (Visual *)CopyFromParent,
+ *valueMask, attributes );
+
+ if (!XtIsSensitive(w))
+ w->core.border_pixmap = border_pixmap;
+}
+
+/* Function Name: ConvertCursor
+ * Description: Converts a name to a new cursor.
+ * Arguments: w - the simple widget.
+ * Returns: none.
+ */
+
+static void
+ConvertCursor(w)
+Widget w;
+{
+ SimpleWidget simple = (SimpleWidget) w;
+ XrmValue from, to;
+ Cursor cursor;
+
+ if (simple->simple.cursor_name == NULL)
+ return;
+
+ from.addr = (XPointer) simple->simple.cursor_name;
+ from.size = strlen((char *) from.addr) + 1;
+
+ to.size = sizeof(Cursor);
+ to.addr = (XPointer) &cursor;
+
+ if (XtConvertAndStore(w, XtRString, &from, XtRColorCursor, &to)) {
+ if ( cursor != None)
+ simple->simple.cursor = cursor;
+ }
+ else {
+ XtAppErrorMsg(XtWidgetToApplicationContext(w),
+ "convertFailed","ConvertCursor","XawError",
+ "Simple: ConvertCursor failed.",
+ (String *)NULL, (Cardinal *)NULL);
+ }
+}
+
+
+/* ARGSUSED */
+static Bool
+SetValues(Widget current, Widget request, Widget new, ArgList args, Cardinal *num_args)
+{
+ SimpleWidget s_old = (SimpleWidget) current;
+ SimpleWidget s_new = (SimpleWidget) new;
+ Boolean new_cursor = FALSE;
+
+ UNUSED(request);
+ UNUSED(args);
+ UNUSED(num_args);
+ /* this disables user changes after creation*/
+ s_new->simple.international = s_old->simple.international;
+
+ if ( XtIsSensitive(current) != XtIsSensitive(new) )
+ (*((SimpleWidgetClass)XtClass(new))->
+ simple_class.change_sensitive) ( new );
+
+ if (s_old->simple.cursor != s_new->simple.cursor) {
+ new_cursor = TRUE;
+ }
+
+/*
+ * We are not handling the string cursor_name correctly here.
+ */
+
+ if ( (s_old->simple.pointer_fg != s_new->simple.pointer_fg) ||
+ (s_old->simple.pointer_bg != s_new->simple.pointer_bg) ||
+ (s_old->simple.cursor_name != s_new->simple.cursor_name) ) {
+ ConvertCursor(new);
+ new_cursor = TRUE;
+ }
+
+ if (new_cursor && XtIsRealized(new))
+ XDefineCursor(XtDisplay(new), XtWindow(new), s_new->simple.cursor);
+
+ return False;
+}
+
+
+static Bool ChangeSensitive(Widget w)
+{
+ if (XtIsRealized(w)) {
+ if (XtIsSensitive(w))
+ if (w->core.border_pixmap != XtUnspecifiedPixmap)
+ XSetWindowBorderPixmap( XtDisplay(w), XtWindow(w),
+ w->core.border_pixmap );
+ else
+ XSetWindowBorder( XtDisplay(w), XtWindow(w),
+ w->core.border_pixel );
+ else {
+ if (((SimpleWidget)w)->simple.insensitive_border == None)
+ ((SimpleWidget)w)->simple.insensitive_border =
+ XmuCreateStippledPixmap(XtScreen(w),
+ w->core.border_pixel,
+ w->core.background_pixel,
+ w->core.depth);
+ XSetWindowBorderPixmap( XtDisplay(w), XtWindow(w),
+ ((SimpleWidget)w)->
+ simple.insensitive_border );
+ }
+ }
+ return False;
+}
+
+/*
+ ======================================================================
+ end copy from Simple.c
+ ======================================================================
+*/
+
+
+/* following function copied from XawInit.c */
+void XawInitializeWidgetSet ()
+{
+ static int firsttime = 1;
+
+ if (firsttime) {
+ firsttime = 0;
+ XtInitializeWidgetClass (vendorShellWidgetClass);
+ }
+}
+
+static char defaultTranslations[] =
+ "<Btn1Down>: start() \n\
+ <Btn1Motion>: move() \n\
+ <Btn1Up>: notify() stop() \n\
+ <Btn2Down>: abort() \n\
+ :<Key>KP_Enter: set(rubberband,toggle) \n\
+ <Key>space: page(+1p,+1p) \n\
+ <Key>Delete: page(-1p,-1p) \n\
+ :<Key>KP_Delete: page(-1p,-1p) \n\
+ <Key>BackSpace: page(-1p,-1p) \n\
+ <Key>Left: page(-.5p,+0) \n\
+ :<Key>KP_Left: page(-.5p,+0) \n\
+ <Key>Right: page(+.5p,+0) \n\
+ :<Key>KP_Right: page(+.5p,+0) \n\
+ <Key>Up: page(+0,-.5p) \n\
+ :<Key>KP_Up: page(+0,-.5p) \n\
+ <Key>Down: page(+0,+.5p) \n\
+ :<Key>KP_Down: page(+0,+.5p) \n\
+ <Key>Home: page(0,0) \n\
+ :<Key>KP_Home: page(0,0)";
+
+
+static void ActionStart(), ActionStop(), ActionAbort(), ActionMove();
+static void ActionPage(), ActionNotify(), ActionSet();
+
+static XtActionsRec actions[] = {
+ { "start", ActionStart }, /* start tmp graphics */
+ { "stop", ActionStop }, /* stop tmp graphics */
+ { "abort", ActionAbort }, /* punt */
+ { "move", ActionMove }, /* move tmp graphics on Motion event */
+ { "page", ActionPage }, /* page around usually from keyboard */
+ { "notify", ActionNotify }, /* callback new position */
+ { "set", ActionSet }, /* set various parameters */
+};
+
+
+/*
+ * resources for the panner
+ */
+static XtResource panner_resources[] = {
+#define poff(field) XtOffsetOf(PannerRec, panner.field)
+ { XtNallowOff, XtCAllowOff, XtRBoolean, sizeof(Boolean),
+ poff(allow_off), XtRImmediate, (XtPointer) FALSE },
+ { XtNresize, XtCResize, XtRBoolean, sizeof(Boolean),
+ poff(resize_to_pref), XtRImmediate, (XtPointer) TRUE },
+ { XtNreportCallback, XtCReportCallback, XtRCallback, sizeof(XtPointer),
+ poff(report_callbacks), XtRCallback, (XtPointer) NULL },
+ { XtNdefaultScale, XtCDefaultScale, XtRDimension, sizeof(Dimension),
+ poff(default_scale), XtRImmediate, (XtPointer) PANNER_DEFAULT_SCALE },
+ { XtNrubberBand, XtCRubberBand, XtRBoolean, sizeof(Boolean),
+ poff(rubber_band), XtRImmediate, (XtPointer) FALSE },
+ { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
+ poff(foreground), XtRString, (XtPointer) XtDefaultBackground },
+ { XtNinternalSpace, XtCInternalSpace, XtRDimension, sizeof(Dimension),
+ poff(internal_border), XtRImmediate, (XtPointer) 4 },
+ { XtNlineWidth, XtCLineWidth, XtRDimension, sizeof(Dimension),
+ poff(line_width), XtRImmediate, (XtPointer) 0 },
+ { XtNcanvasWidth, XtCCanvasWidth, XtRDimension, sizeof(Dimension),
+ poff(canvas_width), XtRImmediate, (XtPointer) 0 },
+ { XtNcanvasHeight, XtCCanvasHeight, XtRDimension, sizeof(Dimension),
+ poff(canvas_height), XtRImmediate, (XtPointer) 0 },
+ { XtNsliderX, XtCSliderX, XtRPosition, sizeof(Position),
+ poff(slider_x), XtRImmediate, (XtPointer) 0 },
+ { XtNsliderY, XtCSliderY, XtRPosition, sizeof(Position),
+ poff(slider_y), XtRImmediate, (XtPointer) 0 },
+ { XtNsliderWidth, XtCSliderWidth, XtRDimension, sizeof(Dimension),
+ poff(slider_width), XtRImmediate, (XtPointer) 0 },
+ { XtNsliderHeight, XtCSliderHeight, XtRDimension, sizeof(Dimension),
+ poff(slider_height), XtRImmediate, (XtPointer) 0 },
+ { XtNshadowColor, XtCShadowColor, XtRPixel, sizeof(Pixel),
+ poff(shadow_color), XtRString, (XtPointer) XtDefaultForeground },
+ { XtNshadowThickness, XtCShadowThickness, XtRDimension, sizeof(Dimension),
+ poff(shadow_thickness), XtRImmediate, (XtPointer) 2 },
+ { XtNbackgroundStipple, XtCBackgroundStipple, XtRString, sizeof(String),
+ poff(stipple_name), XtRImmediate, (XtPointer) NULL },
+#undef poff
+};
+
+
+/*
+ * widget class methods used below
+ */
+static void Initialize(); /* create gc's */
+static void PannerRealize(); /* create window */
+static void Destroy(); /* clean up widget */
+static void Resize(); /* need to rescale ourselves */
+static void Redisplay(); /* draw ourselves */
+static Boolean PannerSetValues(); /* set all of the resources */
+static void SetValuesAlmost(); /* deal with failed setval geom req */
+static XtGeometryResult QueryGeometry(); /* say how big we would like to be */
+
+PannerClassRec pannerClassRec = {
+ { /* core fields */
+ /* superclass */ (WidgetClass) &simpleClassRec,
+ /* class_name */ "Panner",
+ /* widget_size */ sizeof(PannerRec),
+ /* class_initialize */ XawInitializeWidgetSet,
+ /* class_part_initialize */ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ PannerRealize,
+ /* actions */ actions,
+ /* num_actions */ XtNumber(actions),
+ /* resources */ panner_resources,
+ /* num_resources */ XtNumber(panner_resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposure */ TRUE,
+ /* compress_enterleave */ TRUE,
+ /* visible_interest */ FALSE,
+ /* destroy */ Destroy,
+ /* resize */ Resize,
+ /* expose */ Redisplay,
+ /* set_values */ PannerSetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ SetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+ /* tm_table */ defaultTranslations,
+ /* query_geometry */ QueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ },
+ { /* simple fields */
+ /* change_sensitive */ XtInheritChangeSensitive
+#ifndef HAVE_OLD_XAW
+ , NULL
+#endif
+ },
+ { /* panner fields */
+ /* ignore */ 0
+ }
+};
+
+WidgetClass pannerWidgetClass = (WidgetClass) &pannerClassRec;
+
+
+/*****************************************************************************
+ * *
+ * panner utility routines *
+ * *
+ *****************************************************************************/
+
+static void reset_shadow_gc (pw) /* used when resources change */
+ PannerWidget pw;
+{
+ XtGCMask valuemask = GCForeground;
+ XGCValues values;
+ unsigned long pixels[3];
+
+ if (pw->panner.shadow_gc) XtReleaseGC ((Widget) pw, pw->panner.shadow_gc);
+
+ pixels[0] = pw->panner.foreground;
+ pixels[1] = pw->core.background_pixel;
+ pixels[2] = pw->panner.shadow_color;
+ if (!pw->panner.stipple_name &&
+ !XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
+ pixels, 3) &&
+ XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
+ pixels, 2))
+ {
+ valuemask = GCTile | GCFillStyle;
+ values.fill_style = FillTiled;
+ values.tile = XmuCreateStippledPixmap(XtScreen((Widget)pw),
+ pw->panner.foreground,
+ pw->core.background_pixel,
+ pw->core.depth);
+ }
+ else
+ {
+ if (!pw->panner.line_width &&
+ !XmuDistinguishablePixels (XtDisplay (pw), pw->core.colormap,
+ pixels, 2))
+ pw->panner.line_width = 1;
+ valuemask = GCForeground;
+ values.foreground = pw->panner.shadow_color;
+ }
+ if (pw->panner.line_width > 0) {
+ values.line_width = pw->panner.line_width;
+ valuemask |= GCLineWidth;
+ }
+
+ pw->panner.shadow_gc = XtGetGC ((Widget) pw, valuemask, &values);
+}
+
+static void reset_slider_gc (pw) /* used when resources change */
+ PannerWidget pw;
+{
+ XtGCMask valuemask = GCForeground;
+ XGCValues values;
+
+ if (pw->panner.slider_gc) XtReleaseGC ((Widget) pw, pw->panner.slider_gc);
+
+ values.foreground = pw->panner.foreground;
+
+ pw->panner.slider_gc = XtGetGC ((Widget) pw, valuemask, &values);
+}
+
+static void reset_xor_gc (pw) /* used when resources change */
+ PannerWidget pw;
+{
+ if (pw->panner.xor_gc) XtReleaseGC ((Widget) pw, pw->panner.xor_gc);
+
+ if (pw->panner.rubber_band) {
+ XtGCMask valuemask = (GCForeground | GCFunction);
+ XGCValues values;
+ Pixel tmp;
+
+ tmp = ((pw->panner.foreground == pw->core.background_pixel) ?
+ pw->panner.shadow_color : pw->panner.foreground);
+ values.foreground = tmp ^ pw->core.background_pixel;
+ values.function = GXxor;
+ if (pw->panner.line_width > 0) {
+ valuemask |= GCLineWidth;
+ values.line_width = pw->panner.line_width;
+ }
+ pw->panner.xor_gc = XtGetGC ((Widget) pw, valuemask, &values);
+ } else {
+ pw->panner.xor_gc = NULL;
+ }
+}
+
+
+static void check_knob (pw, knob)
+ PannerWidget pw;
+ Boolean knob;
+{
+ Position pad = pw->panner.internal_border * 2;
+ Position maxx = (((Position) pw->core.width) - pad -
+ ((Position) pw->panner.knob_width));
+ Position maxy = (((Position) pw->core.height) - pad -
+ ((Position) pw->panner.knob_height));
+ Position *x = (knob ? &pw->panner.knob_x : &pw->panner.tmp.x);
+ Position *y = (knob ? &pw->panner.knob_y : &pw->panner.tmp.y);
+
+ /*
+ * note that positions are already normalized (i.e. internal_border
+ * has been subtracted out)
+ */
+ if (*x < 0) *x = 0;
+ if (*x > maxx) *x = maxx;
+
+ if (*y < 0) *y = 0;
+ if (*y > maxy) *y = maxy;
+
+ if (knob) {
+ pw->panner.slider_x = (Position) (((double) pw->panner.knob_x) /
+ pw->panner.haspect + 0.5);
+ pw->panner.slider_y = (Position) (((double) pw->panner.knob_y) /
+ pw->panner.vaspect + 0.5);
+ pw->panner.last_x = pw->panner.last_y = PANNER_OUTOFRANGE;
+ }
+}
+
+
+static void move_shadow (pw)
+ PannerWidget pw;
+{
+ if (pw->panner.shadow_thickness > 0) {
+ int lw = pw->panner.shadow_thickness + pw->panner.line_width * 2;
+ int pad = pw->panner.internal_border;
+
+ if ((int)pw->panner.knob_height > lw && (int)pw->panner.knob_width > lw) {
+ XRectangle *r = pw->panner.shadow_rects;
+ r->x = (short) (pw->panner.knob_x + pad + pw->panner.knob_width);
+ r->y = (short) (pw->panner.knob_y + pad + lw);
+ r->width = pw->panner.shadow_thickness;
+ r->height = (unsigned short) (pw->panner.knob_height - lw);
+ r++;
+ r->x = (short) (pw->panner.knob_x + pad + lw);
+ r->y = (short) (pw->panner.knob_y + pad + pw->panner.knob_height);
+ r->width = (unsigned short) (pw->panner.knob_width - lw +
+ pw->panner.shadow_thickness);
+ r->height = pw->panner.shadow_thickness;
+ pw->panner.shadow_valid = TRUE;
+ return;
+ }
+ }
+ pw->panner.shadow_valid = FALSE;
+}
+
+static void scale_knob (pw, location, size) /* set knob size and/or loc */
+ PannerWidget pw;
+ Boolean location, size;
+{
+ if (location) {
+ pw->panner.knob_x = (Position) PANNER_HSCALE (pw, pw->panner.slider_x);
+ pw->panner.knob_y = (Position) PANNER_VSCALE (pw, pw->panner.slider_y);
+ }
+ if (size) {
+ Dimension width, height;
+
+ if (pw->panner.slider_width < 1) {
+ pw->panner.slider_width = pw->panner.canvas_width;
+ }
+ if (pw->panner.slider_height < 1) {
+ pw->panner.slider_height = pw->panner.canvas_height;
+ }
+ width = Min (pw->panner.slider_width, pw->panner.canvas_width);
+ height = Min (pw->panner.slider_height, pw->panner.canvas_height);
+
+ pw->panner.knob_width = (Dimension) PANNER_HSCALE (pw, width);
+ pw->panner.knob_height = (Dimension) PANNER_VSCALE (pw, height);
+ }
+ if (!pw->panner.allow_off) check_knob (pw, TRUE);
+ move_shadow (pw);
+}
+
+static void rescale (pw)
+ PannerWidget pw;
+{
+ int hpad = pw->panner.internal_border * 2;
+ int vpad = hpad;
+
+ if (pw->panner.canvas_width < 1)
+ pw->panner.canvas_width = pw->core.width;
+ if (pw->panner.canvas_height < 1)
+ pw->panner.canvas_height = pw->core.height;
+
+ if ((int)pw->core.width <= hpad) hpad = 0;
+ if ((int)pw->core.height <= vpad) vpad = 0;
+
+ pw->panner.haspect = ((double) pw->core.width - hpad) /
+ (double) pw->panner.canvas_width;
+ pw->panner.vaspect = ((double) pw->core.height - vpad) /
+ (double) pw->panner.canvas_height;
+ scale_knob (pw, TRUE, TRUE);
+}
+
+
+static void get_default_size (pw, wp, hp)
+ PannerWidget pw;
+ Dimension *wp, *hp;
+{
+ Dimension pad = pw->panner.internal_border * 2;
+ *wp = PANNER_DSCALE (pw, pw->panner.canvas_width) + pad;
+ *hp = PANNER_DSCALE (pw, pw->panner.canvas_height) + pad;
+}
+
+static Boolean get_event_xy (pw, event, x, y)
+ PannerWidget pw;
+ XEvent *event;
+ int *x, *y;
+{
+ int pad = pw->panner.internal_border;
+
+ switch (event->type) {
+ case ButtonPress:
+ case ButtonRelease:
+ *x = event->xbutton.x - pad;
+ *y = event->xbutton.y - pad;
+ return TRUE;
+
+ case KeyPress:
+ case KeyRelease:
+ *x = event->xkey.x - pad;
+ *y = event->xkey.y - pad;
+ return TRUE;
+
+ case EnterNotify:
+ case LeaveNotify:
+ *x = event->xcrossing.x - pad;
+ *y = event->xcrossing.y - pad;
+ return TRUE;
+
+ case MotionNotify:
+ *x = event->xmotion.x - pad;
+ *y = event->xmotion.y - pad;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int parse_page_string (s, pagesize, canvassize, relative)
+ char *s;
+ int pagesize, canvassize;
+ Boolean *relative;
+{
+ char *cp;
+ double val = 1.0;
+ Boolean rel = FALSE;
+
+ /*
+ * syntax: spaces [+-] number spaces [pc\0] spaces
+ */
+
+ for (; isascii(*s) && isspace(*s); s++) ; /* skip white space */
+
+ if (*s == '+' || *s == '-') { /* deal with signs */
+ rel = TRUE;
+ if (*s == '-') val = -1.0;
+ s++;
+ }
+ if (!*s) { /* if null then return nothing */
+ *relative = TRUE;
+ return 0;
+ }
+
+ /* skip over numbers */
+ for (cp = s; isascii(*s) && (isdigit(*s) || *s == '.'); s++) ;
+ val *= atof(cp);
+
+ /* skip blanks */
+ for (; isascii(*s) && isspace(*s); s++) ;
+
+ if (*s) { /* if units */
+ switch (s[0]) {
+ case 'p': case 'P':
+ val *= (double) pagesize;
+ break;
+
+ case 'c': case 'C':
+ val *= (double) canvassize;
+ break;
+ }
+ }
+ *relative = rel;
+ return ((int) val);
+}
+
+
+#define DRAW_TMP(pw) \
+{ \
+ XDrawRectangle (XtDisplay(pw), XtWindow(pw), \
+ pw->panner.xor_gc, \
+ (int) (pw->panner.tmp.x + pw->panner.internal_border), \
+ (int) (pw->panner.tmp.y + pw->panner.internal_border), \
+ (unsigned int) (pw->panner.knob_width - 1), \
+ (unsigned int) (pw->panner.knob_height - 1)); \
+ pw->panner.tmp.showing = !pw->panner.tmp.showing; \
+}
+
+#define UNDRAW_TMP(pw) \
+{ \
+ if (pw->panner.tmp.showing) DRAW_TMP(pw); \
+}
+
+#define BACKGROUND_STIPPLE(pw) \
+ XmuLocatePixmapFile (pw->core.screen, pw->panner.stipple_name, \
+ pw->panner.shadow_color, pw->core.background_pixel, \
+ pw->core.depth, NULL, 0, NULL, NULL, NULL, NULL)
+
+#define PIXMAP_OKAY(pm) ((pm) != None && (pm) != XtUnspecifiedPixmap)
+
+
+/*****************************************************************************
+ * *
+ * panner class methods *
+ * *
+ *****************************************************************************/
+
+
+/*ARGSUSED*/
+static void Initialize (greq, gnew, args, num_args)
+ Widget greq, gnew;
+ ArgList args;
+ Cardinal *num_args;
+{
+ PannerWidget req = (PannerWidget) greq, new = (PannerWidget) gnew;
+ Dimension defwidth, defheight;
+
+ UNUSED(args);
+ UNUSED(num_args);
+
+ if (req->panner.canvas_width < 1) new->panner.canvas_width = 1;
+ if (req->panner.canvas_height < 1) new->panner.canvas_height = 1;
+ if (req->panner.default_scale < 1)
+ new->panner.default_scale = PANNER_DEFAULT_SCALE;
+
+ get_default_size (req, &defwidth, &defheight);
+ if (req->core.width < 1) new->core.width = defwidth;
+ if (req->core.height < 1) new->core.height = defheight;
+
+ new->panner.shadow_gc = NULL;
+ reset_shadow_gc (new); /* shadowColor */
+ new->panner.slider_gc = NULL;
+ reset_slider_gc (new); /* foreground */
+ new->panner.xor_gc = NULL;
+ reset_xor_gc (new); /* foreground ^ background */
+
+ rescale (new); /* does a position check */
+ new->panner.shadow_valid = FALSE;
+ new->panner.tmp.doing = FALSE;
+ new->panner.tmp.showing = FALSE;
+}
+
+
+static void PannerRealize (gw, valuemaskp, attr)
+ Widget gw;
+ XtValueMask *valuemaskp;
+ XSetWindowAttributes *attr;
+{
+ PannerWidget pw = (PannerWidget) gw;
+ Pixmap pm = XtUnspecifiedPixmap;
+ Boolean gotpm = FALSE;
+
+ if (pw->core.background_pixmap == XtUnspecifiedPixmap) {
+ if (pw->panner.stipple_name) pm = BACKGROUND_STIPPLE (pw);
+
+ if (PIXMAP_OKAY(pm)) {
+ attr->background_pixmap = pm;
+ *valuemaskp |= CWBackPixmap;
+ *valuemaskp &= ~CWBackPixel;
+ gotpm = TRUE;
+ }
+ }
+ (*pannerWidgetClass->core_class.superclass->core_class.realize)
+ (gw, valuemaskp, attr);
+
+ if (gotpm) XFreePixmap (XtDisplay(gw), pm);
+}
+
+
+static void Destroy (gw)
+ Widget gw;
+{
+ PannerWidget pw = (PannerWidget) gw;
+
+ XtReleaseGC (gw, pw->panner.shadow_gc);
+ XtReleaseGC (gw, pw->panner.slider_gc);
+ XtReleaseGC (gw, pw->panner.xor_gc);
+}
+
+
+static void Resize (gw)
+ Widget gw;
+{
+ rescale ((PannerWidget) gw);
+}
+
+
+/* ARGSUSED */
+static void Redisplay (Widget gw, XEvent *event, Region region)
+{
+ PannerWidget pw = (PannerWidget) gw;
+ Display *dpy = XtDisplay(gw);
+ Window w = XtWindow(gw);
+ int pad = pw->panner.internal_border;
+ Dimension lw = pw->panner.line_width;
+ Dimension extra = pw->panner.shadow_thickness + lw * 2;
+ int kx = pw->panner.knob_x + pad, ky = pw->panner.knob_y + pad;
+
+ UNUSED(event);
+ UNUSED(region);
+
+ pw->panner.tmp.showing = FALSE;
+ XClearArea (XtDisplay(pw), XtWindow(pw),
+ (int) pw->panner.last_x - ((int) lw) + pad,
+ (int) pw->panner.last_y - ((int) lw) + pad,
+ (unsigned int) (pw->panner.knob_width + extra),
+ (unsigned int) (pw->panner.knob_height + extra),
+ False);
+ pw->panner.last_x = pw->panner.knob_x;
+ pw->panner.last_y = pw->panner.knob_y;
+
+ XFillRectangle (dpy, w, pw->panner.slider_gc, kx, ky,
+ pw->panner.knob_width - 1, pw->panner.knob_height - 1);
+
+ if (lw)
+ {
+ XDrawRectangle (dpy, w, pw->panner.shadow_gc, kx, ky,
+ (unsigned int) (pw->panner.knob_width - 1),
+ (unsigned int) (pw->panner.knob_height - 1));
+ }
+
+ if (pw->panner.shadow_valid) {
+ XFillRectangles (dpy, w, pw->panner.shadow_gc,
+ pw->panner.shadow_rects, 2);
+ }
+ if (pw->panner.tmp.doing && pw->panner.rubber_band) DRAW_TMP (pw);
+}
+
+
+/* ARGSUSED */
+static Boolean PannerSetValues (Widget gcur, Widget greq, Widget gnew, ArgList args, Cardinal *num_args)
+{
+ PannerWidget cur = (PannerWidget) gcur;
+ PannerWidget new = (PannerWidget) gnew;
+ Boolean redisplay = FALSE;
+
+ UNUSED(greq);
+ UNUSED(args);
+ UNUSED(num_args);
+
+ if (cur->panner.foreground != new->panner.foreground) {
+ reset_slider_gc (new);
+ if (cur->panner.foreground != cur->core.background_pixel)
+ reset_xor_gc (new);
+ redisplay = TRUE;
+ } else if (cur->panner.line_width != new->panner.line_width ||
+ cur->core.background_pixel != new->core.background_pixel) {
+ reset_xor_gc (new);
+ redisplay = TRUE;
+ }
+ if (cur->panner.shadow_color != new->panner.shadow_color) {
+ reset_shadow_gc (new);
+ if (cur->panner.foreground == cur->core.background_pixel)
+ reset_xor_gc (new);
+ redisplay = TRUE;
+ }
+ if (cur->panner.shadow_thickness != new->panner.shadow_thickness) {
+ move_shadow (new);
+ redisplay = TRUE;
+ }
+ if (cur->panner.rubber_band != new->panner.rubber_band) {
+ reset_xor_gc (new);
+ if (new->panner.tmp.doing) redisplay = TRUE;
+ }
+
+ if ((cur->panner.stipple_name != new->panner.stipple_name ||
+ cur->panner.shadow_color != new->panner.shadow_color ||
+ cur->core.background_pixel != new->core.background_pixel) &&
+ XtIsRealized(gnew)) {
+ Pixmap pm = (new->panner.stipple_name ? BACKGROUND_STIPPLE (new)
+ : XtUnspecifiedPixmap);
+
+ if (PIXMAP_OKAY(pm)) {
+ XSetWindowBackgroundPixmap (XtDisplay (new), XtWindow(new), pm);
+ XFreePixmap (XtDisplay (new), pm);
+ } else {
+ XSetWindowBackground (XtDisplay (new), XtWindow(new),
+ new->core.background_pixel);
+ }
+ redisplay = TRUE;
+ }
+
+ if (new->panner.resize_to_pref &&
+ (cur->panner.canvas_width != new->panner.canvas_width ||
+ cur->panner.canvas_height != new->panner.canvas_height ||
+ cur->panner.resize_to_pref != new->panner.resize_to_pref)) {
+ get_default_size (new, &new->core.width, &new->core.height);
+ redisplay = TRUE;
+ } else if (cur->panner.canvas_width != new->panner.canvas_width ||
+ cur->panner.canvas_height != new->panner.canvas_height ||
+ cur->panner.internal_border != new->panner.internal_border) {
+ rescale (new); /* does a scale_knob as well */
+ redisplay = TRUE;
+ } else {
+ Boolean loc = (cur->panner.slider_x != new->panner.slider_x ||
+ cur->panner.slider_y != new->panner.slider_y);
+ Boolean siz = (cur->panner.slider_width != new->panner.slider_width ||
+ cur->panner.slider_height != new->panner.slider_height);
+ if (loc || siz ||
+ (cur->panner.allow_off != new->panner.allow_off &&
+ new->panner.allow_off)) {
+ scale_knob (new, loc, siz);
+ redisplay = TRUE;
+ }
+ }
+
+ return redisplay;
+}
+
+static void SetValuesAlmost (gold, gnew, req, reply)
+ Widget gold, gnew;
+ XtWidgetGeometry *req, *reply;
+{
+ if (reply->request_mode == 0) { /* got turned down, so cope */
+ Resize (gnew);
+ }
+ (*pannerWidgetClass->core_class.superclass->core_class.set_values_almost)
+ (gold, gnew, req, reply);
+}
+
+static XtGeometryResult QueryGeometry (gw, intended, pref)
+ Widget gw;
+ XtWidgetGeometry *intended, *pref;
+{
+ PannerWidget pw = (PannerWidget) gw;
+
+ pref->request_mode = (CWWidth | CWHeight);
+ get_default_size (pw, &pref->width, &pref->height);
+
+ if (((intended->request_mode & (CWWidth | CWHeight)) ==
+ (CWWidth | CWHeight)) &&
+ intended->width == pref->width &&
+ intended->height == pref->height)
+ return XtGeometryYes;
+ else if (pref->width == pw->core.width && pref->height == pw->core.height)
+ return XtGeometryNo;
+ else
+ return XtGeometryAlmost;
+}
+
+
+/*****************************************************************************
+ * *
+ * panner action procs *
+ * *
+ *****************************************************************************/
+
+/* ARGSUSED */
+static void ActionStart (Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget) gw;
+ int x, y;
+
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (!get_event_xy (pw, event, &x, &y)) {
+ XBell (XtDisplay(gw), 0); /* should do error message */
+ return;
+ }
+
+ pw->panner.tmp.doing = TRUE;
+ pw->panner.tmp.startx = pw->panner.knob_x;
+ pw->panner.tmp.starty = pw->panner.knob_y;
+ pw->panner.tmp.dx = (((Position) x) - pw->panner.knob_x);
+ pw->panner.tmp.dy = (((Position) y) - pw->panner.knob_y);
+ pw->panner.tmp.x = pw->panner.knob_x;
+ pw->panner.tmp.y = pw->panner.knob_y;
+ if (pw->panner.rubber_band) DRAW_TMP (pw);
+}
+
+/* ARGSUSED */
+static void ActionStop (Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget) gw;
+ int x, y;
+
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (get_event_xy (pw, event, &x, &y)) {
+ pw->panner.tmp.x = ((Position) x) - pw->panner.tmp.dx;
+ pw->panner.tmp.y = ((Position) y) - pw->panner.tmp.dy;
+ if (!pw->panner.allow_off) check_knob (pw, FALSE);
+ }
+ if (pw->panner.rubber_band) UNDRAW_TMP (pw);
+ pw->panner.tmp.doing = FALSE;
+}
+
+/* ARGSUSED */
+static void ActionAbort (Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget) gw;
+
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (!pw->panner.tmp.doing) return;
+
+ if (pw->panner.rubber_band) UNDRAW_TMP (pw);
+
+ if (!pw->panner.rubber_band) { /* restore old position */
+ pw->panner.tmp.x = pw->panner.tmp.startx;
+ pw->panner.tmp.y = pw->panner.tmp.starty;
+ ActionNotify (gw, event, params, num_params);
+ }
+ pw->panner.tmp.doing = FALSE;
+}
+
+
+/* ARGSUSED */
+static void ActionMove (Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget) gw;
+ int x, y;
+
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (!pw->panner.tmp.doing) return;
+
+ if (!get_event_xy (pw, event, &x, &y)) {
+ XBell (XtDisplay(gw), 0); /* should do error message */
+ return;
+ }
+
+ if (pw->panner.rubber_band) UNDRAW_TMP (pw);
+ pw->panner.tmp.x = ((Position) x) - pw->panner.tmp.dx;
+ pw->panner.tmp.y = ((Position) y) - pw->panner.tmp.dy;
+
+ if (!pw->panner.rubber_band) {
+ ActionNotify (gw, event, params, num_params); /* does a check */
+ } else {
+ if (!pw->panner.allow_off) check_knob (pw, FALSE);
+ DRAW_TMP (pw);
+ }
+}
+
+
+/* ARGSUSED */
+static void ActionPage (Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget) gw;
+ Cardinal zero = 0;
+ Boolean isin = pw->panner.tmp.doing;
+ int x, y;
+ Boolean relx, rely;
+ int pad = pw->panner.internal_border * 2;
+
+ UNUSED(event);
+ UNUSED(num_params);
+
+ if (*num_params != 2) {
+ XBell (XtDisplay(gw), 0);
+ return;
+ }
+
+ x = parse_page_string (params[0], (int) pw->panner.knob_width,
+ ((int) pw->core.width) - pad, &relx);
+ y = parse_page_string (params[1], (int) pw->panner.knob_height,
+ ((int) pw->core.height) - pad, &rely);
+
+ if (relx) x += pw->panner.knob_x;
+ if (rely) y += pw->panner.knob_y;
+
+ if (isin) { /* if in, then use move */
+ XEvent ev;
+ ev.xbutton.type = ButtonPress;
+ ev.xbutton.x = x;
+ ev.xbutton.y = y;
+ ActionMove (gw, &ev, (String *) NULL, &zero);
+ } else { /* else just do it */
+ pw->panner.tmp.doing = TRUE;
+ pw->panner.tmp.x = x;
+ pw->panner.tmp.y = y;
+ ActionNotify (gw, event, (String *) NULL, &zero);
+ pw->panner.tmp.doing = FALSE;
+ }
+}
+
+
+/* ARGSUSED */
+static void ActionNotify (Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget) gw;
+
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (!pw->panner.tmp.doing) return;
+
+ if (!pw->panner.allow_off) check_knob (pw, FALSE);
+ pw->panner.knob_x = pw->panner.tmp.x;
+ pw->panner.knob_y = pw->panner.tmp.y;
+ move_shadow (pw);
+
+ pw->panner.slider_x = (Position) (((double) pw->panner.knob_x) /
+ pw->panner.haspect + 0.5);
+ pw->panner.slider_y = (Position) (((double) pw->panner.knob_y) /
+ pw->panner.vaspect + 0.5);
+ if (!pw->panner.allow_off) {
+ Position tmp;
+
+ if (pw->panner.slider_x >
+ (tmp = (((Position) pw->panner.canvas_width) -
+ ((Position) pw->panner.slider_width))))
+ pw->panner.slider_x = tmp;
+ if (pw->panner.slider_x < 0) pw->panner.slider_x = 0;
+ if (pw->panner.slider_y >
+ (tmp = (((Position) pw->panner.canvas_height) -
+ ((Position) pw->panner.slider_height))))
+ pw->panner.slider_y = tmp;
+ if (pw->panner.slider_y < 0) pw->panner.slider_y = 0;
+ }
+
+ if (pw->panner.last_x != pw->panner.knob_x ||
+ pw->panner.last_y != pw->panner.knob_y) {
+ XawPannerReport rep;
+
+ Redisplay (gw, (XEvent*) NULL, (Region) NULL);
+ rep.changed = (XawPRSliderX | XawPRSliderY);
+ rep.slider_x = pw->panner.slider_x;
+ rep.slider_y = pw->panner.slider_y;
+ rep.slider_width = pw->panner.slider_width;
+ rep.slider_height = pw->panner.slider_height;
+ rep.canvas_width = pw->panner.canvas_width;
+ rep.canvas_height = pw->panner.canvas_height;
+ XtCallCallbackList (gw, pw->panner.report_callbacks, (XtPointer) &rep);
+ }
+}
+
+/* ARGSUSED */
+static void ActionSet (Widget gw, XEvent *event, String *params, Cardinal *num_params)
+{
+ PannerWidget pw = (PannerWidget) gw;
+ Boolean rb;
+
+ UNUSED(event);
+
+ if (*num_params < 2 ||
+ XmuCompareISOLatin1 (params[0], "rubberband") != 0) {
+ XBell (XtDisplay(gw), 0);
+ return;
+ }
+
+ if (XmuCompareISOLatin1 (params[1], "on") == 0) {
+ rb = TRUE;
+ } else if (XmuCompareISOLatin1 (params[1], "off") == 0) {
+ rb = FALSE;
+ } else if (XmuCompareISOLatin1 (params[1], "toggle") == 0) {
+ rb = !pw->panner.rubber_band;
+ } else {
+ XBell (XtDisplay(gw), 0);
+ return;
+ }
+
+ if (rb != pw->panner.rubber_band) {
+ Arg args[1];
+ XtSetArg (args[0], XtNrubberBand, rb);
+ XtSetValues (gw, args, (Cardinal) 1);
+ }
+}
+
+#endif /* MOTIF && USE_PANNER */
diff --git a/Build/source/texk/xdvik/gui/Panner.h b/Build/source/texk/xdvik/gui/Panner.h
new file mode 100644
index 00000000000..7ced64ebcad
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/Panner.h
@@ -0,0 +1,108 @@
+/*
+ * $XConsortium: Panner.h,v 1.22 94/04/17 20:12:32 rws Exp $
+ *
+Copyright (c) 1989 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#ifndef _XawPanner_h
+#define _XawPanner_H
+
+#include <X11/Xaw/Reports.h>
+
+/*****************************************************************************
+ *
+ * Panner Widget (subclass of Simple)
+ *
+ * This widget is used to represent navigation in a 2d coordinate system.
+ *
+ * Parameters:
+ *
+ * Name Class Type Default
+ * ---- ----- ---- -------
+ *
+ * allowOff AllowOff Boolean FALSE
+ * background Background Pixel XtDefaultBackground
+ * backgroundStipple BackgroundStipple String NULL
+ * canvasWidth CanvasWidth Dimension 0
+ * canvasHeight CanvasHeight Dimension 0
+ * defaultScale DefaultScale Dimension 8 percent
+ * foreground Foreground Pixel XtDefaultBackground
+ * internalSpace InternalSpace Dimension 4
+ * lineWidth LineWidth Dimension 0
+ * reportCallback ReportCallback XtCallbackList NULL
+ * resize Resize Boolean TRUE
+ * rubberBand RubberBand Boolean FALSE
+ * shadowColor ShadowColor Pixel XtDefaultForeground
+ * shadowThickness ShadowThickness Dimension 2
+ * sliderX SliderX Position 0
+ * sliderY SliderY Position 0
+ * sliderWidth SliderWidth Dimension 0
+ * sliderHeight SliderHeight Dimension 0
+ *
+ *****************************************************************************/
+
+ /* new instance and class names */
+#ifndef _XtStringDefs_h_
+#define XtNresize "resize"
+#define XtCResize "Resize"
+#endif
+
+#define XtNallowOff "allowOff"
+#define XtCAllowOff "AllowOff"
+#define XtNbackgroundStipple "backgroundStipple"
+#define XtCBackgroundStipple "BackgroundStipple"
+#define XtNdefaultScale "defaultScale"
+#define XtCDefaultScale "DefaultScale"
+#define XtNcanvasWidth "canvasWidth"
+#define XtCCanvasWidth "CanvasWidth"
+#define XtNcanvasHeight "canvasHeight"
+#define XtCCanvasHeight "CanvasHeight"
+#define XtNinternalSpace "internalSpace"
+#define XtCInternalSpace "InternalSpace"
+#define XtNlineWidth "lineWidth"
+#define XtCLineWidth "LineWidth"
+#define XtNrubberBand "rubberBand"
+#define XtCRubberBand "RubberBand"
+#define XtNshadowThickness "shadowThickness"
+#define XtCShadowThickness "ShadowThickness"
+#define XtNshadowColor "shadowColor"
+#define XtCShadowColor "ShadowColor"
+#define XtNsliderX "sliderX"
+#define XtCSliderX "SliderX"
+#define XtNsliderY "sliderY"
+#define XtCSliderY "SliderY"
+#define XtNsliderWidth "sliderWidth"
+#define XtCSliderWidth "SliderWidth"
+#define XtNsliderHeight "sliderHeight"
+#define XtCSliderHeight "SliderHeight"
+
+ /* external declarations */
+extern WidgetClass pannerWidgetClass;
+
+typedef struct _PannerClassRec *PannerWidgetClass;
+typedef struct _PannerRec *PannerWidget;
+
+#endif /* _XawPanner_h */
diff --git a/Build/source/texk/xdvik/gui/PannerP.h b/Build/source/texk/xdvik/gui/PannerP.h
new file mode 100644
index 00000000000..5c8fbc8cee5
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/PannerP.h
@@ -0,0 +1,104 @@
+/*
+ * $XConsortium: PannerP.h,v 1.19 94/04/17 20:12:33 jim Exp $
+ *
+Copyright (c) 1989 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+ *
+ * Author: Jim Fulton, MIT X Consortium
+ */
+
+#ifndef _XawPannerP_h
+#define _XawPannerP_h
+
+#include "Panner.h"
+#include <X11/Xaw/SimpleP.h> /* parent */
+
+typedef struct { /* new fields in widget class */
+ int dummy;
+} PannerClassPart;
+
+typedef struct _PannerClassRec { /* Panner widget class */
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+ PannerClassPart panner_class;
+} PannerClassRec;
+
+typedef struct { /* new fields in widget */
+ /* resources... */
+ XtCallbackList report_callbacks; /* callback/Callback */
+ Boolean allow_off; /* allowOff/AllowOff */
+ Boolean resize_to_pref; /* resizeToPreferred/Boolean */
+ Pixel foreground; /* foreground/Foreground */
+ Pixel shadow_color; /* shadowColor/ShadowColor */
+ Dimension shadow_thickness; /* shadowThickness/ShadowThickness */
+ Dimension default_scale; /* defaultScale/DefaultScale */
+ Dimension line_width; /* lineWidth/LineWidth */
+ Dimension canvas_width; /* canvasWidth/CanvasWidth */
+ Dimension canvas_height; /* canvasHeight/CanvasHeight */
+ Position slider_x; /* sliderX/SliderX */
+ Position slider_y; /* sliderY/SliderY */
+ Dimension slider_width; /* sliderWidth/SliderWidth */
+ Dimension slider_height; /* sliderHeight/SliderHeight */
+ Dimension internal_border; /* internalBorderWidth/BorderWidth */
+ String stipple_name; /* backgroundStipple/BackgroundStipple */
+ /* private data... */
+ GC slider_gc; /* background of slider */
+ GC shadow_gc; /* edge of slider and shadow */
+ GC xor_gc; /* for doing XOR tmp graphics */
+ double haspect, vaspect; /* aspect ratio of core to canvas */
+ Boolean rubber_band; /* true = rubber band, false = move */
+ struct {
+ Boolean doing; /* tmp graphics in progress */
+ Boolean showing; /* true if tmp graphics displayed */
+ Position startx, starty; /* initial position of slider */
+ Position dx, dy; /* offset loc for tmp graphics */
+ Position x, y; /* location for tmp graphics */
+ } tmp;
+ Position knob_x, knob_y; /* real upper left of knob in canvas */
+ Dimension knob_width, knob_height; /* real size of knob in canvas */
+ Boolean shadow_valid; /* true if rects are valid */
+ XRectangle shadow_rects[2]; /* location of shadows */
+ Position last_x, last_y; /* previous location of knob */
+} PannerPart;
+
+typedef struct _PannerRec {
+ CorePart core;
+ SimplePart simple;
+ PannerPart panner;
+} PannerRec;
+
+#define PANNER_HSCALE(pw,val) ((pw)->panner.haspect * ((double) (val)))
+#define PANNER_VSCALE(pw,val) ((pw)->panner.vaspect * ((double) (val)))
+
+#define PANNER_DSCALE(pw,val) (Dimension) \
+ ((((unsigned long) (val)) * (unsigned long) pw->panner.default_scale) / 100L)
+#define PANNER_DEFAULT_SCALE 8 /* percent */
+
+#define PANNER_OUTOFRANGE -30000
+
+/*
+ * external declarations
+ */
+extern PannerClassRec pannerClassRec;
+
+#endif /* _XawPannerP_h */
diff --git a/Build/source/texk/xdvik/gui/Tip.c b/Build/source/texk/xdvik/gui/Tip.c
new file mode 100644
index 00000000000..76a83f188b9
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/Tip.c
@@ -0,0 +1,607 @@
+/*
+ * Copyright (c) 2001-2004 Marcin Dalecki and others
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "Tip.h"
+#include "xdvi-debug.h"
+#include "util.h"
+
+#ifdef MOTIF /* needed for `make depend' */
+
+#ifndef UNUSED
+#define UNUSED(x) ((void)(x))
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <Xm/XmP.h>
+
+#include <Xm/PushB.h>
+#include <X11/ShellP.h>
+
+#define TIP_NUM 1024 /* FIXME: remove this hard-coded value */
+
+typedef struct {
+ int __empty;
+} TipClassPart;
+
+/* Full class record declaration */
+typedef struct _TipClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ShellClassPart shell_class;
+ OverrideShellClassPart override_shell_class;
+ TipClassPart tip_class;
+} TipClassRec;
+
+/* keep information about each widget we are keeping track of */
+struct tip_context {
+ Widget watched; /* the widget we are watching */
+ Window window; /* Window of the object we are monitoring */
+ TipWidget tw; /* pointer back to the tip widget */
+ Position abs_x, abs_y;
+ Boolean active; /* if False, tip is suppressed */
+ char *text; /* text to display */
+ short size; /* its size */
+};
+
+/* New fields for the widget record */
+typedef struct {
+ /* resources */
+ Pixel foreground;
+ XFontSet fontset; /* the font for text in box */
+ int waitPeriod; /* the delay resource - pointer must be
+ * in watched widget this long before
+ * help is popped up - in millisecs
+ */
+ unsigned int cwp; /* after help is popped down - normal
+ * wait period is cancelled for this
+ * period - in millisecs
+ */
+
+ /* private state */
+ struct tip_context twl[TIP_NUM]; /* list of widgets we are liteClue-ing */
+ Cardinal nr_twl; /* number of widgets we have attached */
+ Dimension font_width; /* width of '1' character */
+ Dimension font_height; /* height of font, rows are spaced using this */
+ Dimension font_baseline; /* relative displacement to baseline from top */
+ GC text_GC; /* for drawing text */
+ XtIntervalId tid; /* holds timer id */
+ Widget isup; /* the help popup is up on this widget */
+ Time HelpPopDownTime; /* the time at which help popup
+ was popped down */
+} TipPart;
+
+/*
+ * Full instance record declaration
+ */
+typedef struct _TipRec {
+ CorePart core;
+ CompositePart composite;
+ ShellPart shell;
+ OverrideShellPart override;
+ TipPart tip;
+} TipRec;
+
+#define CheckWidgetClass(routine) \
+ if (XtClass(w) != tipWidgetClass) \
+ wrong_widget(routine)
+
+static void initialize(Widget, Widget, ArgList, Cardinal *);
+static Boolean set_values(Widget, Widget, Widget, ArgList, Cardinal *);
+static void destroy(Widget);
+
+/*
+ * Widget resources: eg to set tip box background: *tipShell.background: yellow.
+ */
+
+#define offset(field) XtOffsetOf(TipRec, field)
+static XtResource resources[] = {
+ {XtNforeground, XtCForeground,
+ XtRPixel, sizeof(Pixel), offset(tip.foreground),
+ XtRString, "black"},
+ {XtNfontSet, XtCFontSet,
+ XtRFontSet, sizeof(XFontSet), offset(tip.fontset),
+ XtRString, "fixed"},
+ {XmNwaitPeriod, XmCWaitPeriod,
+ XtRInt, sizeof(int), offset(tip.waitPeriod),
+ XtRImmediate, (XtPointer) 800},
+ {XmNcancelWaitPeriod, XmCCancelWaitPeriod,
+ XtRInt, sizeof(int), offset(tip.cwp),
+ XtRImmediate, (XtPointer) 250},
+};
+#undef offset
+
+TipClassRec tipClassRec = {
+ {
+ /* superclass */ (WidgetClass) & overrideShellClassRec,
+ /* class_name */ "Tip",
+ /* widget size */ (Cardinal) sizeof(TipRec),
+ /* class_init */ NULL,
+ /* class_part_init */ (XtWidgetClassProc) NULL,
+ /* class_inited */ (XtEnum) FALSE,
+ /* initialize */ (XtInitProc) initialize,
+ /* init_hook */ (XtArgsProc) NULL,
+ /* realize */ XtInheritRealize,
+ /* actions */ (XtActionList) 0,
+ /* num_actions */ (Cardinal) 0,
+ /* resources */ (XtResourceList) resources,
+ /* num_resources */ (Cardinal) XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ TRUE,
+ /* compress_exposur */ (XtEnum) FALSE,
+ /* compress enterleave */ TRUE,
+ /* visibility_interest */ FALSE,
+ /* destroy */ destroy,
+ /* resize */ XtInheritResize,
+ /* expose, */ XtInheritExpose,
+ /* set_values */ (XtSetValuesFunc) set_values,
+ /* set_values_hook */ (XtArgsFunc) NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ (XtArgsProc) NULL,
+ /* accept_focus */ XtInheritAcceptFocus,
+ /* version */ XtVersion,
+ /* callback_private */ (XtPointer) NULL,
+ /* translations */ XtInheritTranslations,
+ /* query_geometry */ XtInheritQueryGeometry,
+ /* display_accelerator */ XtInheritDisplayAccelerator,
+ /* extension */ (XtPointer) 0,
+ },
+ /* composite part */
+ {
+ /* geometry_manager */ XtInheritGeometryManager,
+ /* change_managed */ XtInheritChangeManaged,
+ /* insert_child */ XtInheritInsertChild,
+ /* delete_child */ XtInheritDeleteChild,
+ /* extension */ NULL
+ },
+ /* Shell */
+ {
+ (XtPointer) NULL,
+ },
+ /* Override Shell */
+ {
+ 0,
+ },
+ /* tip */
+ {
+ 0,
+ }
+};
+
+WidgetClass tipWidgetClass = (WidgetClass) & tipClassRec;
+
+/*
+ * The font_information is derived.
+ */
+static void compute_font_info(TipWidget cw)
+{
+ XRectangle ink;
+ XRectangle logical;
+
+ if (!cw->tip.fontset)
+ return;
+ XmbTextExtents(cw->tip.fontset, "1", 1, &ink, &logical);
+
+ cw->tip.font_baseline = -logical.y; /* y offset from top to baseline, don't
+ know why this is returned as
+ negative */
+
+ cw->tip.font_width = logical.width; /* the width and height of the object */
+
+ cw->tip.font_height = logical.height;
+ TRACE_GUI((stderr, "baseline: %d, width: %d, height: %d\n",
+ cw->tip.font_baseline, cw->tip.font_width, cw->tip.font_height));
+}
+
+/*
+ * Creates the various graphic contexts we will need.
+ */
+static void create_GC(TipWidget cw)
+{
+ XtGCMask valuemask;
+ XGCValues myXGCV;
+
+ valuemask = GCForeground | GCBackground | GCFillStyle;
+ myXGCV.foreground = cw->tip.foreground;
+ myXGCV.background = cw->core.background_pixel;
+ myXGCV.fill_style = FillSolid;
+
+ if (cw->tip.text_GC)
+ XtReleaseGC((Widget) cw, cw->tip.text_GC);
+ cw->tip.text_GC = XtGetGC((Widget) cw, valuemask, &myXGCV);
+}
+
+/*
+ * A routine to halt execution and force a core dump for debugging analysis
+ * when a public routine is called with the wrong class of widget.
+ */
+
+static void wrong_widget(char *routine)
+{
+ XDVI_ABORT((stderr, "Wrong class of widget passed to %s", routine));
+}
+
+/*
+ * Global list of shells for tips that are in use.
+ */
+
+static TipWidget *shells = NULL;
+static int nr_shells = 0;
+
+/****************************************************************************
+ * Widget Methods
+ */
+
+static void initialize(Widget treq, Widget tnew, ArgList args,
+ Cardinal * nargs)
+{
+ TipWidget tw = (TipWidget) tnew;
+
+ UNUSED(treq);
+ UNUSED(args);
+ UNUSED(nargs);
+
+ tw->tip.text_GC = NULL;
+ tw->tip.isup = NULL;
+ tw->tip.HelpPopDownTime = 0;
+ tw->tip.tid = (XtIntervalId) 0;
+ tw->tip.nr_twl = 0;
+ compute_font_info(tw);
+ create_GC(tw);
+
+ /* Add to our list of tip shells.
+ */
+ if (!shells)
+ shells = (TipWidget *)XtMalloc(sizeof(TipWidget));
+ else
+ shells = (TipWidget *)XtRealloc((char *)shells,
+ sizeof(TipWidget) * (nr_shells + 1));
+
+ shells[nr_shells++] = tw;
+}
+
+static Boolean set_values(Widget _current, Widget _request, Widget _new,
+ ArgList args, Cardinal * nargs)
+{
+ TipWidget cw_new = (TipWidget) _new;
+ TipWidget cw_cur = (TipWidget) _current;
+
+ UNUSED(_request);
+ UNUSED(args);
+ UNUSED(nargs);
+
+ /* values of cw_new->tip.cwp and
+ cw_new->tip.waitPeriod are accepted without checking */
+
+ if (cw_new->tip.foreground != cw_cur->tip.foreground
+ || cw_new->core.background_pixel !=
+ cw_cur->core.background_pixel) {
+ create_GC(cw_new);
+ }
+ return FALSE;
+}
+
+static void destroy(Widget w)
+{
+ TipWidget tw = (TipWidget) w;
+ int i;
+ Boolean copy = False;
+
+ /* Remove this tip shell from our global list.
+ */
+ for (i = 0; i < nr_shells; ++i) {
+ if (shells[i] == tw) {
+ copy = True;
+ --nr_shells;
+ }
+ if (copy && nr_shells)
+ shells[i] = shells[i + 1];
+ }
+ if (!nr_shells) {
+ XtFree((char *) shells);
+ shells = NULL;
+ }
+}
+
+/****************************************************************************
+ * Event handlers
+ */
+
+/* callback to popup the tip window
+ */
+static void timeout_event(XtPointer client_data, XtIntervalId *id)
+{
+#define HBorderPix 3
+#define VBorderPix 3
+ struct tip_context *obj = (struct tip_context *) client_data;
+ TipWidget tw = obj->tw;
+ Position abs_x, abs_y;
+ int ptr_x, ptr_y;
+
+ XRectangle ink;
+ XRectangle logical;
+ Position w_height, w_width;
+ Widget w;
+
+ UNUSED(id);
+
+ TRACE_GUI((stderr, "timeout called!"));
+
+ if (tw->tip.tid == (XtIntervalId) 0)
+ return; /* timeout was removed but callback happened
+ anyway */
+
+ tw->tip.tid = (XtIntervalId) 0;
+ if (obj->active == False)
+ return;
+
+ w = obj->watched;
+
+ if (!XtIsManaged(w))
+ return;
+
+ { /* perform additional check that pointer is really still over the widget;
+ else, tooltips will sometimes pop up if window had received an Enter
+ event before (for some reason, not all Enters are followed by Leaves).
+ This is especially apparent when running xdvi from a remote display over
+ a slow connection.
+ */
+ Window root, child;
+ int root_x, root_y;
+ unsigned int keys_buttons;
+ if (!XQueryPointer(DISP, RootWindowOfScreen(SCRN), &root, &child,
+ &root_x, &root_y, &ptr_x, &ptr_y, &keys_buttons))
+ return;
+
+ TRACE_GUI((stderr, "Pointerlocate: %d, %d", root_x, root_y));
+
+ XtVaGetValues(w, XtNheight, &w_height, XtNwidth, &w_width, NULL);
+ XtTranslateCoords(w, 0, 0, &abs_x, &abs_y);
+
+ TRACE_GUI((stderr, "Window: %d,%d - %d,%d",
+ abs_x, abs_y, abs_x + w_width, abs_y + w_height));
+
+ if (root_x < abs_x || root_x > abs_x + w_width
+ || root_y < abs_y || root_y > abs_y + w_height) {
+ TRACE_GUI((stderr, "not really over toolbutton - returning!"));
+ return;
+ }
+ }
+
+ /* position just below the pointer
+ * (NOT the widget, in case the widget is large!)
+ */
+ ptr_y += 20;
+/* abs_x += w_width / 2; */
+/* abs_y += w_height; */
+
+ XmbTextExtents(tw->tip.fontset, obj->text, obj->size, &ink, &logical);
+
+ XtRealizeWidget((Widget)tw); /* so that setting the size etc. works */
+
+ XtResizeWidget((Widget) tw,
+ 2 * HBorderPix + logical.width,
+ 2 * VBorderPix + tw->tip.font_height,
+ tw->core.border_width);
+ TRACE_GUI((stderr, "Popup size: %d x %d (hborder: %d, vborder: %d)\n",
+ 2 * HBorderPix + logical.width, 2 * VBorderPix + tw->tip.font_height,
+ HBorderPix, VBorderPix));
+ XtMoveWidget((Widget)tw, ptr_x, ptr_y);
+
+ XtPopup((Widget) tw, XtGrabNone);
+ tw->tip.isup = obj->watched;
+
+ XmbDrawImageString(XtDisplay((Widget) tw),
+ XtWindow((Widget) tw),
+ tw->tip.fontset,
+ tw->tip.text_GC,
+ HBorderPix,
+ VBorderPix + tw->tip.font_baseline,
+ obj->text, obj->size);
+}
+
+/*
+ * Pointer enters watched widget, set a timer to popup the help.
+ */
+static void enter(struct tip_context *obj, XEvent * xevent,
+ XtAppContext app)
+{
+ TipWidget tw = obj->tw;
+ XEnterWindowEvent *event = &xevent->xcrossing;
+ int current_waitPeriod;
+
+ /* this doesn't help against the Enter/Leave problem mentioned above,
+ so it's not related to Widget creation ... */
+ if (!XtIsManaged(obj->watched)) {
+ TRACE_GUI((stderr, "%s:%d: Not yet managed!", __FILE__, __LINE__));
+ return;
+ }
+
+ TRACE_GUI((stderr, "%s:%d: Enter!", __FILE__, __LINE__));
+
+ if (obj->active == False)
+ return;
+
+ /* check for two enters in a row - happens when widget is
+ exposed under a pop-up */
+ if (tw->tip.tid != (XtIntervalId) 0)
+ return;
+
+ if (event->mode != NotifyNormal)
+ return;
+
+ /* it seems that this makes the tooltips somewhat unpredictable (they
+ don't show when hovering fast over several buttons, then staying on
+ one button); disabled this for the time being. */
+/* if ((event->time - tw->tip.HelpPopDownTime) > tw->tip.cwp) */
+/* current_waitPeriod = tw->tip.waitPeriod; */
+/* else */
+/* current_waitPeriod = 0; */
+
+/* current_waitPeriod = tw->tip.waitPeriod; */
+ current_waitPeriod = resource.tooltips_wait_period;
+ if (current_waitPeriod >= 0) {
+ tw->tip.tid = XtAppAddTimeOut(app, current_waitPeriod, timeout_event,
+ (XtPointer) obj);
+ }
+}
+
+/*
+ * Remove timer if its pending. Then popdown help.
+ */
+static void leave(struct tip_context *obj, XEvent * xevent)
+{
+ TipWidget tw = obj->tw;
+ XEnterWindowEvent *event = &xevent->xcrossing;
+
+ TRACE_GUI((stderr, "%s:%d: Leave!", __FILE__, __LINE__));
+
+ if (tw->tip.tid != (XtIntervalId) 0) {
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "%s:%d: removing timeout %ld\n", __FILE__, __LINE__, tw->tip.tid);
+ XtRemoveTimeOut(tw->tip.tid);
+ tw->tip.tid = (XtIntervalId) 0;
+ }
+
+ if (obj->active == False)
+ return;
+
+ if (tw->tip.isup) {
+ XtPopdown((Widget) tw);
+ tw->tip.isup = NULL;
+ tw->tip.HelpPopDownTime = event->time;
+ }
+}
+
+/****************************************************************************
+ * Public interface implementation.
+ */
+
+void TipAppHandle(XtAppContext app, XEvent *event)
+{
+ int i;
+
+ if (!(event->type == EnterNotify
+ || event->type == MotionNotify
+ || event->type == LeaveNotify
+ || event->type == ButtonPress)) {
+ return;
+ }
+
+ for (i = 0; i < nr_shells; ++i) {
+ unsigned int j;
+
+ for (j = 0; j < shells[i]->tip.nr_twl; ++j) {
+ if (event->xany.window == shells[i]->tip.twl[j].window) {
+ if (event->type == EnterNotify)
+ enter(shells[i]->tip.twl + j, event, app);
+ if (event->xany.type == LeaveNotify
+ || event->xany.type == MotionNotify /* FIXME: this doesn' work? */
+ /* might be useful to popdown tip when mouse is moved */
+ || event->xany.type == ButtonPress) {
+ leave(shells[i]->tip.twl + j, event);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * This has to replace the XtAppMainLoop in the application using
+ * tooltips.
+ */
+void TipAppMainLoop(XtAppContext app)
+{
+ XEvent event;
+
+ for (;;) {
+ XtAppNextEvent(app, &event);
+ TipAppHandle(app, &event);
+ XtDispatchEvent(&event);
+ }
+}
+
+/*
+ * Add a widget to be watched for tooltips.
+ *
+ * This function must be called after the widget has been realized!
+ * Further on please make sure that this function will not be called twice
+ * for one button!
+ *
+ * w - tip widget
+ * watch - the widget to give tips for
+ * text - pointer to tip text
+ */
+void TipAddWidget(Widget w, Widget watch, const String text)
+{
+#define ROUTINE "TipAddWidget"
+ TipWidget tw = (TipWidget) w;
+ int i;
+
+ CheckWidgetClass(ROUTINE); /* make sure we are called with a tip widget */
+
+ /* Make internal resource available via resource.tooltips_wait_period(_bak) and
+ * resource.show_tooltips.
+ */
+ resource.tooltips_wait_period_bak = resource.tooltips_wait_period = ABS(tw->tip.waitPeriod);
+ if (tw->tip.waitPeriod < 0) {
+ resource.show_tooltips = False;
+ }
+ else if (!resource.show_tooltips) {
+ if (resource.tooltips_wait_period == 0)
+ resource.tooltips_wait_period = -1;
+ else
+ resource.tooltips_wait_period = -resource.tooltips_wait_period;
+ }
+
+ for (i = 0; i < nr_shells; ++i)
+ if (shells[i] == tw) {
+ struct tip_context *obj;
+
+ if (tw->tip.nr_twl >= TIP_NUM) {
+ XDVI_FATAL((stderr, "Too many tip widgets, cannot add new tip"));
+ return;
+ }
+ obj = tw->tip.twl + tw->tip.nr_twl;
+ obj->text = XtNewString(text);
+ obj->size = strlen(text);
+ obj->watched = watch;
+ obj->window = XtWindow(watch);
+ obj->active = True;
+ obj->tw = tw;
+ tw->tip.nr_twl++;
+ }
+#undef ROUTINE
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/Tip.h b/Build/source/texk/xdvik/gui/Tip.h
new file mode 100644
index 00000000000..b4cb8a957c0
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/Tip.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2001-2004 Marcin Dalecki and others
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef TIP_H_
+#define TIP_H_
+
+#ifdef MOTIF
+/* Tooltip widget handling. This has somewhat of a library character,
+ * but we don't want to go into the trouble of making a library for just
+ * one function.
+ */
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+/* New resource names
+ */
+#define XmNcancelWaitPeriod "cancelWaitPeriod"
+#define XmNwaitPeriod "waitPeriod"
+
+/* New resource classes
+ */
+#define XmCCancelWaitPeriod "CancelWaitPeriod"
+#define XmCWaitPeriod "WaitPeriod"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+ extern WidgetClass tipWidgetClass;
+ typedef struct _TipClassRec *TipWidgetClass;
+ typedef struct _TipRec *TipWidget;
+
+ extern void TipAddWidget(Widget, Widget, const String);
+ extern void TipAppMainLoop(XtAppContext);
+ extern void TipAppHandle(XtAppContext, XEvent *);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif /* MOTIF */
+#endif /* TIP_H_ */
diff --git a/Build/source/texk/xdvik/gui/TipP.h b/Build/source/texk/xdvik/gui/TipP.h
new file mode 100644
index 00000000000..5c2f7daea24
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/TipP.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2001-2004 Marcin Dalecki and others
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef TIPP_h
+#define TIPP_h
+
+#include <X11/ShellP.h>
+
+#include "Tip.h"
+
+/* Doubly Linked List Processing.
+ */
+struct list_thread_str {
+ struct list_thread_str *forw;
+ struct list_thread_str *back;
+};
+typedef struct list_thread_str ListThread;
+
+typedef struct {
+ int __empty;
+} TipClassPart;
+
+/* Full class record declaration.
+ */
+typedef struct _TipClassRec {
+ CoreClassPart core_class;
+ CompositeClassPart composite_class;
+ ShellClassPart shell_class;
+ OverrideShellClassPart override_shell_class;
+ TipClassPart tip_class;
+} TipClassRec;
+
+extern TipClassRec xmTipClassRec;
+
+/* New fields for the widget record.
+ */
+typedef struct {
+ /* resources */
+ Pixel foreground;
+ XFontSet fontset; /* the font for text in box */
+ int waitPeriod; /* the delay resource - pointer must be
+ in watched widget this long before
+ tooltip is displayed - in milliseconds
+ */
+ int cancelWaitPeriod; /* after help is popped-down - normal
+ wait period is cancelled for this
+ period - in milliseconds
+ */
+
+ /* -------- private state --------- */
+ ListThread widget_list; /* list of widgets we are liteClue-ing */
+ Dimension font_width; /* width of '1' character */
+ Dimension font_height; /* height of font, rows are spaced using this */
+ Dimension font_baseline; /* relative displacement to baseline from top */
+ GC text_GC; /* for drawing text */
+ XtIntervalId tid; /* holds timer id */
+ XtIntervalId pid; /* holds pooler id for insensitive widgets */
+ Widget parent;
+ Widget isup; /* the help popup is up on this widget */
+ Time HelpPopDownTime; /* the time at which help popup was popped down */
+} TipPart;
+
+
+/*
+ * Full instance record declaration
+ */
+typedef struct _TipRec {
+ CorePart core;
+ CompositePart composite;
+ ShellPart shell;
+ OverrideShellPart override;
+ TipPart tip;
+} TipRec;
+
+#endif
diff --git a/Build/source/texk/xdvik/gui/depend.mk b/Build/source/texk/xdvik/gui/depend.mk
new file mode 100644
index 00000000000..2f62ce49923
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/depend.mk
@@ -0,0 +1,528 @@
+help-window.o: help-window.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ message-window.h ../util.h \
+ $(kpathsea_srcdir)/c-stat.h $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/tex-file.h \
+ ../events.h ../x_util.h ../string-utils.h ../my-vsnprintf.h \
+ topic-window.h help-window.h
+mag.o: mag.c \
+ ../xdvi-config.h ../c-auto.h \
+ ../c-openmx.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/systypes.h \
+ ../xdvi.h ../xdvi-debug.h ../version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h $(kpathsea_srcdir)/types.h \
+ $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../events.h ../dvi-draw.h ../dvi-init.h \
+ statusline.h ../hypertex.h mag.h xm_toolbar.h xm_menu.h menu.h \
+ xaw_menu.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ pagesel.h
+menu.o: menu.c ../xdvi-config.h ../c-auto.h ../xdvi.h ../xdvi-debug.h \
+ ../version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h \
+ $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../events.h menu.h xm_menu.h xaw_menu.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h
+message-window.o: message-window.c \
+ ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../string-utils.h ../my-vsnprintf.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h ../x_util.h message-window.h
+pagesel.o: pagesel.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ xm_toolbar.h xm_menu.h menu.h ../events.h \
+ xaw_menu.h ../x_util.h \
+ message-window.h pagesel.h ../util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../string-utils.h ../my-vsnprintf.h \
+ ../dvi-init.h statusline.h print-dialog.h ../search-internal.h \
+ search-dialog.h ../dvisel.h ../print-internal.h ../pagehist.h
+Panner.o: Panner.c ../xdvi-config.h ../c-auto.h ../xdvi.h ../xdvi-debug.h \
+ ../version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h \
+ $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../string-utils.h ../my-vsnprintf.h
+print-dialog.o: print-dialog.c \
+ ../xdvi-config.h ../c-auto.h ../xdvi.h ../xdvi-debug.h ../version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h \
+ $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../my-vsnprintf.h \
+ print-dialog.h print-log.h ../print-internal.h ../dvi-init.h \
+ ../events.h ../string-utils.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../x_util.h message-window.h pagesel.h \
+ ../my-snprintf.h sfSelFile.h ../dvisel.h xlwradio.h statusline.h \
+ search-dialog.h ../search-internal.h ../special.h
+print-log.o: print-log.c \
+ ../xdvi-config.h ../c-auto.h ../xdvi.h ../xdvi-debug.h ../version.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h \
+ $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ print-dialog.h print-log.h ../util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h ../x_util.h xlwradio.h
+search-dialog.o: search-dialog.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../events.h ../dvi-init.h search-dialog.h \
+ ../search-internal.h ../dvisel.h ../print-internal.h print-dialog.h \
+ xlwradio.h statusline.h ../string-utils.h ../my-vsnprintf.h ../util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ message-window.h ../x_util.h
+selection.o: selection.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../events.h ../util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../encodings.h message-window.h selection.h \
+ statusline.h
+sfDir.o: sfDir.c ../xdvi-config.h ../c-auto.h sfDir.h \
+ $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-stat.h
+sfDraw.o: sfDraw.c ../xdvi-config.h ../c-auto.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ ../xdvi.h ../xdvi-debug.h ../version.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ sfDraw.h sfDir.h sfPath.h
+sfPath.o: sfPath.c ../xdvi-config.h ../c-auto.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ ../xdvi.h ../xdvi-debug.h ../version.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ sfDir.h sfDraw.h sfPath.h sfSelFile.h
+sfSelFile.o: sfSelFile.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../dvi-init.h message-window.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ sfDir.h sfPath.h sfDraw.h sfSelFile.h \
+ ../util.h $(kpathsea_srcdir)/hash.h $(kpathsea_srcdir)/tex-file.h \
+ ../events.h $(kpathsea_srcdir)/c-fopen.h
+statusline.o: statusline.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ statusline.h xm_menu.h menu.h ../events.h \
+ xaw_menu.h ../x_util.h ../pagehist.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../my-vsnprintf.h
+Tip.o: Tip.c ../xdvi-config.h ../c-auto.h ../xdvi.h ../xdvi-debug.h \
+ ../version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h \
+ $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ Tip.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h
+topic-window.o: topic-window.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ topic-window.h ../string-utils.h ../my-vsnprintf.h ../util.h \
+ $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h ../x_util.h
+xaw_bitmaps.o: xaw_bitmaps.c xaw_bitmaps.h
+xaw_menu.o: xaw_menu.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../c-openmx.h ../events.h ../dvi-draw.h \
+ ../dvi-init.h statusline.h pagesel.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../x_util.h xaw_menu.h message-window.h \
+ ../my-snprintf.h ../filehist.h
+xicon.o: xicon.c ../xdvi-config.h ../c-auto.h ../xdvi.h ../xdvi-debug.h \
+ ../version.h $(kpathsea_dir)/c-auto.h $(kpathsea_srcdir)/config.h \
+ $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ xicon.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h \
+ ../xdvi.icon ../pixmaps/xdvi32x32.xpm ../pixmaps/xdvi16x16.xpm \
+ ../pixmaps/xdvi48x48.xpm
+xlwradio.o: xlwradio.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h xaw_bitmaps.h xlwradioP.h \
+ xlwradio.h
+xm_colorsel.o: xm_colorsel.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ Tip.h \
+ ../x_util.h xm_colorsel.h xm_prefsP.h \
+ xm_prefs.h ../events.h ../dvi-draw.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ topic-window.h ../search-internal.h \
+ search-dialog.h ../dvisel.h ../dvi-init.h ../print-internal.h \
+ print-dialog.h
+xm_filesel.o: xm_filesel.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ sfSelFile.h ../dvi.h ../string-utils.h \
+ ../my-vsnprintf.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h message-window.h ../dvi-init.h
+xm_menu.o: xm_menu.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ xm_menu.h menu.h ../events.h xaw_menu.h \
+ xm_toolbar.h ../my-snprintf.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../x_util.h statusline.h ../pagehist.h \
+ ../dvi-init.h ../filehist.h ../c-openmx.h message-window.h
+xm_prefs_appearance.o: xm_prefs_appearance.c ../xdvi-config.h ../c-auto.h \
+ ../xdvi.h ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../x_util.h ../my-snprintf.h xm_colorsel.h \
+ topic-window.h message-window.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h xm_toolbar.h xm_menu.h menu.h \
+ xaw_menu.h statusline.h pagesel.h xm_prefsP.h xm_prefs_appearance.h
+xm_prefs.o: xm_prefs.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../x_util.h xm_colorsel.h topic-window.h \
+ message-window.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h xm_prefsP.h xm_prefs.h \
+ xm_prefs_appearance.h xm_prefs_fonts.h xm_prefs_helpers.h \
+ xm_prefs_page.h xm_prefs_scroll.h ../dvi-draw.h ../search-internal.h \
+ search-dialog.h ../dvisel.h ../dvi-init.h ../print-internal.h \
+ print-dialog.h statusline.h xm_toolbar.h xm_menu.h menu.h xaw_menu.h \
+ pagesel.h
+xm_prefs_fonts.o: xm_prefs_fonts.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../x_util.h xm_colorsel.h topic-window.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h ../hypertex.h ../my-snprintf.h \
+ xm_prefsP.h xm_prefs_fonts.h
+xm_prefs_helpers.o: xm_prefs_helpers.c ../xdvi-config.h ../c-auto.h \
+ ../xdvi.h ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../x_util.h xm_colorsel.h topic-window.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h ../string-utils.h \
+ ../my-vsnprintf.h message-window.h xm_menu.h menu.h xaw_menu.h \
+ xm_prefsP.h xm_prefs.h xm_prefs_helpers.h
+xm_prefs_page.o: xm_prefs_page.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../x_util.h xm_colorsel.h topic-window.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h statusline.h xm_prefsP.h \
+ xm_prefs_page.h ../my-snprintf.h
+xm_prefs_scroll.o: xm_prefs_scroll.c ../xdvi-config.h ../c-auto.h \
+ ../xdvi.h ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ ../x_util.h xm_colorsel.h topic-window.h \
+ ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ $(kpathsea_srcdir)/tex-file.h \
+ ../events.h ../dvi-init.h statusline.h \
+ xm_prefsP.h xm_prefs_scroll.h ../my-snprintf.h
+xm_toolbar.o: xm_toolbar.c ../xdvi-config.h ../c-auto.h ../xdvi.h \
+ ../xdvi-debug.h ../version.h $(kpathsea_dir)/c-auto.h \
+ $(kpathsea_srcdir)/config.h $(kpathsea_srcdir)/c-std.h \
+ $(kpathsea_srcdir)/c-unistd.h $(kpathsea_srcdir)/systypes.h \
+ $(kpathsea_srcdir)/c-memstr.h \
+ $(kpathsea_srcdir)/c-errno.h \
+ $(kpathsea_srcdir)/c-minmax.h $(kpathsea_srcdir)/c-limits.h \
+ $(kpathsea_srcdir)/c-proto.h $(kpathsea_srcdir)/debug.h \
+ $(kpathsea_srcdir)/types.h $(kpathsea_srcdir)/lib.h $(kpathsea_srcdir)/progname.h \
+ $(kpathsea_srcdir)/c-pathmx.h \
+ $(kpathsea_srcdir)/c-dir.h \
+ $(kpathsea_srcdir)/c-vararg.h \
+ pagesel.h help-window.h message-window.h \
+ $(kpathsea_srcdir)/tex-file.h $(kpathsea_srcdir)/expand.h statusline.h \
+ ../dvi-init.h ../events.h ../dvi-draw.h xm_menu.h menu.h xaw_menu.h \
+ xm_toolbar.h ../util.h $(kpathsea_srcdir)/c-stat.h \
+ $(kpathsea_srcdir)/hash.h \
+ ../x_util.h Tip.h \
+ ../c-openmx.h ../pixmaps/toolbar.xpm
diff --git a/Build/source/texk/xdvik/gui/help-window.c b/Build/source/texk/xdvik/gui/help-window.c
new file mode 100644
index 00000000000..8f7e6612a0e
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/help-window.c
@@ -0,0 +1,1094 @@
+/*
+ * Copyright (c) 2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Help window for xdvik, using the `topics' window framework.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "version.h"
+
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+
+#if MOTIF
+# include <Xm/Xm.h>
+# include <Xm/Form.h>
+# include <Xm/Frame.h>
+# include <Xm/Text.h>
+# include <Xm/Protocols.h>
+#else /* MOTIF */
+# include <X11/Xaw/Paned.h>
+# include <X11/Xaw/Form.h>
+# include <X11/Xaw/AsciiText.h>
+#endif /* MOTIF */
+
+#include <sys/stat.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "message-window.h"
+#include "util.h"
+#include "x_util.h"
+#include "string-utils.h"
+#include "topic-window.h"
+#include "help-window.h"
+
+/* missing features that will be listed in the help window */
+#if !XDVI_XT_TIMER_HACK
+#define HAVE_MISSING_FEATURES 1
+#endif
+
+#if !HAVE_REGEX_H
+#define HAVE_MISSING_FEATURES 1
+#endif
+
+/*
+ * The number of help topics - must larger or equal to actual number of items,
+ * also keep in sync with elements resource.help_* !!!
+ */
+#define NUM_HELP_TOPICS 16
+
+/*
+ * helper routines
+ */
+
+static Widget
+create_help_text(Widget parent, const char *name, const char *value)
+{
+ Widget text;
+#if MOTIF
+ Arg args[20];
+ int n = 0;
+
+ XtSetArg(args[n], XmNeditable, False); n++;
+ XtSetArg(args[n], XmNcursorPositionVisible, False); n++;
+ XtSetArg(args[n], XmNvalue, value); n++;
+ XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
+ XtSetArg(args[n], XmNwordWrap, True); n++;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
+/* XtSetArg(args[n], XmNtopWidget, top_widget); n++; */
+/* XtSetArg(args[n], XmNtopOffset, 10); n++; */
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); n++;
+ XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmAS_NEEDED); n++;
+
+ text = XmCreateScrolledText(parent, (char *)name, args, n);
+
+ XtManageChild(text);
+#else /* MOTIF */
+ text = XtVaCreateManagedWidget(name, asciiTextWidgetClass, parent,
+ /* XtNfromVert, top_widget, */
+ /* XtNvertDistance, 10, */
+ XtNstring, value,
+ XtNheight, 400,
+ XtNwidth, 500,
+ /* resizing of pane by user isn't needed */
+ XtNshowGrip, False,
+ XtNscrollVertical, XawtextScrollAlways,
+ XtNscrollHorizontal, XawtextScrollNever,
+ XtNeditType, XawtextRead,
+ XtNleftMargin, 5,
+ NULL);
+ XawTextDisplayCaret(text, False);
+#endif /* MOTIF */
+ return text;
+}
+
+
+static void
+get_title_and_summary(const char *str, int len, char **title, char **summary)
+{
+ char *tmp = xmalloc(len + 1);
+ char *ptr;
+
+ memcpy(tmp, str, len);
+ tmp[len] = '\0';
+
+ if ((ptr = strchr(tmp, '\t')) == NULL) {
+ XDVI_WARNING((stderr, "Help resource label `%s' doesn't contain a tab character - ignoring it.", tmp));
+ *title = tmp;
+ *summary = NULL;
+ }
+ else {
+ *ptr++ = '\0';
+ *title = tmp;
+ *summary = ptr;
+ }
+
+ TRACE_GUI((stderr, "Title, Summary: |%s|%s|", *title, *summary));
+}
+
+static void
+init_item(const char *resource, const char **resource_default,
+ struct topic_info *info, size_t idx, Dimension *width)
+{
+ const char *ptr = NULL;
+ char *widget_text = NULL;
+ Widget help_form;
+ Widget text;
+ struct topic_item *item = &(info->items[idx]);
+ char *translation_str = get_string_va("#override \n"
+ "<Key>q:close-topic-window(%p)\n"
+#ifdef MOTIF
+ "<Key>osfCancel:close-topic-window(%p)\n"
+#else
+ "<Key>Escape:close-topic-window(%p)\n"
+#endif
+ "<Key>Return:close-topic-window(%p)",
+ info, info, info);
+
+ if (resource != NULL) {
+ if ((ptr = strchr(resource, '\n')) == NULL) {
+ XDVI_WARNING((stderr, "Help resource text `%s' doesn't contain a newline character.", resource));
+ ptr = resource;
+ }
+ else
+ ptr++;
+ get_title_and_summary(resource, ptr - resource - 1,
+ &(item->topic), &(item->title));
+ }
+ else { /* resource not set; copy resource_default into malloc()ed widget_text: */
+ size_t size = 0, alloc_len = 0, offset;
+ const size_t alloc_step = 1024;
+ int i;
+
+ for (i = 0; resource_default[i] != NULL; i++) {
+ if (i == 0) { /* special case */
+ get_title_and_summary(resource_default[i], strlen(resource_default[i]) - 1,
+ &(item->topic), &(item->title));
+ }
+ else {
+ offset = size;
+ size += strlen(resource_default[i]);
+ /*
+ * allocate chunks of `alloc_step' to avoid frequent calls to malloc.
+ * `alloc_len' is always 1 more than `size', for the terminating NULL character.
+ */
+ while (size + 1 > alloc_len) {
+ alloc_len += alloc_step;
+ widget_text = xrealloc(widget_text, alloc_len);
+ }
+ memcpy(widget_text + offset, resource_default[i], size - offset);
+ }
+ }
+ /* null-terminate string */
+ widget_text[size] = '\0';
+ }
+
+ help_form = XtVaCreateManagedWidget("help_form",
+#if MOTIF
+ xmFormWidgetClass, info->right_form,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+#else
+ formWidgetClass, info->right_form,
+ XtNborderWidth, 0,
+ XtNdefaultDistance, 0,
+#endif
+ NULL);
+ item->widget = help_form;
+ if (ptr != NULL) {
+ text = create_help_text(help_form, "help_text", ptr);
+ }
+ else {
+ text = create_help_text(help_form, "help_text", widget_text);
+ free(widget_text);
+ }
+ XtOverrideTranslations(text, XtParseTranslationTable(translation_str));
+ free(translation_str);
+#if !MOTIF
+ {
+ Dimension w;
+ XtVaGetValues(text, XtNwidth, &w, NULL);
+ if (w > *width)
+ *width = w;
+ }
+#else
+ UNUSED(width);
+#endif
+}
+
+static void
+initialize_items(struct topic_info *info)
+{
+ size_t k;
+ Dimension width;
+
+ /*
+ * Define fallbacks: default_xyz is used as fallback text if
+ * X resource xyz isn't specified.
+ *
+ * We use arrays of strings rather than simple strings because of C's
+ * limitations on maximum string length; but since the resource needs to
+ * be a simple `char *', these have to be copied into larger buffers
+ * later on (which is a bit wasteful to space). OTOH, splitting the
+ * strings into smaller pieces would make them hard to deal with as
+ * X resources. They are defined as static so that they are initialized
+ * only once.
+ *
+ * Last elem of each array is NULL for ease of looping through it.
+ *
+ * Advantages of this method vs. putting the help texts into a file:
+ * - couldn't use #ifdef's as easily
+ * - would need to invent our own file format
+ * - file searching is more error-prone (needs to be installed etc.)
+ */
+
+ static const char *default_help_general[] = {
+ "Introduction\tAbout this version of xdvi\n",
+ "This is xdvik, version ",
+ XDVI_TERSE_VERSION_INFO
+ ".\nThe program's homepage is located at:\n",
+ "http://sourceforge.net/projects/xdvi\n",
+ "where you can find updates, report bugs and submit feature requests.\n",
+ "\n",
+ "\n",
+ "Xdvi has many command-line options, too numerous to be listed here;\n",
+ "see the man page for a full description.\n",
+ "\n",
+ "The most important key bindings are listed in the help sections shown\n",
+ "in the left window.\n",
+ "\n",
+ "Note: Unless a key binding also has an uppercase version,\n",
+ "all bindings are case-insensitive.\n\n",
+ "\n",
+ "The major parts of Xdvik are licensed under the X Consortium license.\n",
+ "Parts (encoding.c) are licensed under the GNU General Public License.\n",
+ "Xdvik uses the following libraries:\n",
+ "- The kpathsea library, licensed in part under the GNU General Public\n",
+ " License, in part under the GNU Library General Public License.\n",
+ "- t1lib, licensed in parts under the GNU Library General Public License,\n",
+ " in parts under the X Consortium license.\n",
+ "There is NO WARRANTY of anything.\n",
+ "\n",
+ "Built on ",
+ __DATE__,
+ " using these configure options:\n",
+#if MOTIF
+ "- Motif toolkit (",
+ XmVERSION_STRING,
+ ")\n",
+#else
+ "- Athena toolkit\n",
+#endif
+#ifdef A4
+ "- paper: a4, units cm\n",
+#else
+ "- paper: letter, units inches\n",
+#endif
+#ifdef GREY
+ "- anti-aliasing (grey) enabled\n",
+#endif
+#ifdef T1LIB
+ "- T1lib (direct rendering of PS fonts) enabled\n",
+#endif
+#if HAVE_ICONV_H
+ "- Iconv support compiled in\n",
+#if USE_LANGINFO
+ "- Langinfo support compiled in\n",
+#else
+ "- Langinfo support not compiled in\n",
+#endif
+#else
+ "- Iconv/langinfo support not compiled in\n",
+#endif
+#ifdef TEXXET
+ "- left-to-right typesetting (TeXXeT) support enabled\n",
+#endif
+#ifdef USE_GF
+ "- gf file support enabled\n",
+#endif
+#if HAVE_MISSING_FEATURES
+ "\n",
+ "Features not available on this platform:\n",
+#if !XDVI_XT_TIMER_HACK
+ "- Could not redefine XtAppAddTimeOut(); some widgets may\n",
+ " not be updated until the mouse is moved.\n",
+#endif
+#if !HAVE_REGEX_H
+ "- regex.h header not available, regular expression support\n",
+ " in string search is disabled.\n",
+#endif
+#endif /* HAVE_MISSING_FEATURES */
+ NULL
+ };
+
+ static const char *default_help_hypertex[] = {
+ "Hyperlinks\tNavigating links\n",
+ "Whenever the mouse is positioned on a link, the cursor changes\n",
+ "to a `hand' shape and the target of the link is displayed\n",
+ "in the statusline at the bottom of the window.\n",
+ "\n",
+ "The following keybindings are pre-configured:\n",
+ "\n",
+ "Mouse-1\n",
+ " Follow the link at the cursor position.\n",
+ " If the link target is not a DVI file, try to launch\n",
+ " an application to view the file.\n",
+ "Mouse-2\n",
+ " Open a new xdvi window displaying the link\n",
+ " at the cursor position if the link is a DVI file;\n",
+ " else, try to launch an application to view the file.\n",
+ "B",
+#if MOTIF
+ ", toolbar button 9\n",
+#else
+ "\n",
+#endif
+ " Go back to the previous hyperlink in the history.\n",
+ "F",
+#if MOTIF
+ ", toolbar button 10\n",
+#else
+ "\n",
+#endif
+ " Go forward to the next hyperlink in the history.\n",
+ "\n",
+ "By default, the hyperlinks are displayed in the colors \n",
+ "`linkColor' and `visitedLinkColor' (for visited links) and \n",
+ "underlined in the same colors. This can be customized \n",
+ "by setting the resource or command-line option `linkstyle' \n",
+ "to a value between 0 and 3, which have the following meaning:\n",
+ " 0: no highlighting of links,\n",
+ " 1: underline links,\n",
+ " 2: color links,\n",
+ " 3: color and underline links.\n\n",
+ NULL
+ };
+
+ static const char *default_help_othercommands[] = {
+ "Other Commands\tMiscellaneous other commands\n",
+ "Ctrl-f\n",
+ " Opens a dialog window to search for a text string\n",
+ " in the DVI file.\n",
+ "\n",
+ "Ctrl-g\n",
+ " Search for the next string match.\n",
+ "\n",
+ "Ctrl-l\n",
+ " Toggles fullscreen mode (which may not work with your\n",
+ " window manager/desktop).\n",
+ "\n",
+ "Ctrl-o",
+#if MOTIF
+ ", toolbar button 1\n",
+#else
+ "\n",
+#endif
+ " Opens a popup window to select another DVI file.\n",
+ " With a prefix argument `n', the `n'th file from the file history\n",
+ " is opened instead.\n",
+ "\n",
+ "Ctrl-p",
+#if MOTIF
+ ", toolbar button 11\n",
+#else
+ "\n",
+#endif
+ " Opens a popup window for printing the DVI file, or parts of it.\n",
+ "\n",
+ "Ctrl-r or Clear\n",
+ " Redisplays the current page.\n",
+ "\n",
+ "Ctrl-s\n",
+ " Opens a popup window for saving the DVI file, or parts of it.\n",
+ "\n",
+ "G\n",
+ " Toggles the use of greyscale anti-aliasing for\n",
+ " displaying shrunken bitmaps. In addition, the key\n",
+ " sequences `0G' and `1G' clear and set this flag,\n",
+ " respectively. See also the -nogrey option.\n",
+ "\n",
+ "k\n",
+ " Normally when xdvi switches pages, it moves to the home\n",
+ " position as well. The `k' keystroke toggles a `keep-\n",
+ " position' flag which, when set, will keep the same\n",
+ " position when moving between pages. Also `0k' and `1k'\n",
+ " clear and set this flag, respectively. See also the\n",
+ " -keep option.\n",
+ "\n",
+ "M\n",
+ " Sets the margins so that the point currently under the\n",
+ " cursor is the upper left-hand corner of the text in the\n",
+ " page. Note that this command itself does not move the\n",
+ " image at all. For details on how the margins are used,\n",
+ " see the -margins option.\n",
+ "\n",
+ "P\n",
+ " ``This is page number n.'' This can be used to make\n",
+ " the `g' keystroke refer to a different page number.\n",
+ " (See also `Options->Use TeX Page Numbers' and the\n",
+ " `T' keystroke).\n",
+ "\n",
+ "R",
+#if MOTIF
+ ", toolbar button 2\n",
+#else
+ "\n",
+#endif
+ " Forces the DVI file to be reread.\n",
+ "\n",
+ "s\n",
+ " Changes the shrink factor to the given number.\n",
+ " If no number is given, the smallest factor that makes the\n",
+ " entire page fit in the window will be used. (Margins\n",
+ " are ignored in this computation.)\n",
+ "\n",
+ "S\n",
+ " Sets the density factor to be used when shrinking\n",
+ " bitmaps. This should be a number between 0 and 100;\n",
+ " higher numbers produce lighter characters.\n",
+ "\n",
+ "t\n",
+ " Switches to the next unit in a sorted list of TeX dimension\n",
+ " units for the popup magnifier ruler and `Ruler mode' (see the\n",
+ " section `Modes').\n"
+ "\n",
+ "V\n",
+ " Toggles Ghostscript anti-aliasing. Also `0V' and `1V' clear\n",
+ " and enables this mode, respectively. See also the the\n",
+ " -gsalpha option.\n",
+ "\n",
+ "\n",
+ "v\n",
+ " Toggles between several modes of displaying postscript specials:\n",
+ " Display specials, display specials with their bounding box\n",
+ " (if available), and display bounding boxes only (if available).\n",
+ " The prefix arguments 1, 2 and 0 also allow you to select one of\n"
+ " these states directly.\n",
+ "\n",
+ "x\n",
+ " Toggles expert mode (in which ",
+#if MOTIF
+ "the menu bar, the toolbar\n",
+#else
+ "the menu buttons,\n",
+#endif
+ " the page list and the statusline do not appear).\n",
+ " `1x' toggles the display of the statusline at the bottom of the window.\n",
+ " `2x' toggles the scrollbars,\n",
+#if MOTIF
+ " `3x' toggles the page list,\n",
+ " `4x' toggles the toolbar,\n",
+ " `5x' toggles the menu bar.\n",
+#else
+ " `3x' toggles the page list and menu buttons.\n",
+#endif
+ "\n",
+ "Ctrl-+",
+#if MOTIF
+ ", toolbar button 7\n",
+#else
+ "\n",
+#endif
+ " Makes the display of the page larger (zooms in).\n",
+ "\n",
+ "Ctrl-+",
+#if MOTIF
+ ", toolbar button 8\n",
+#else
+ "\n",
+#endif
+ " Makes the display of the page smaller (zooms out).\n",
+ "\n",
+ "Alt-Ctrl-+",
+#if MOTIF
+ ", toolbar button 16\n",
+#else
+ "\n",
+#endif
+ " Makes the fonts darker (by adding to the gamma value).\n",
+ "\n",
+ "Alt-Ctrl--",
+#if MOTIF
+ ", toolbar button 17\n",
+#else
+ "\n",
+#endif
+ " Makes the fonts lighter (by substracting from the gamma\n",
+ " value).\n",
+ "\n",
+ NULL
+ };
+
+ static const char *default_help_marking[] = {
+ "Printing and Saving\tMarking, printing and saving pages\n",
+ "The `Save' and `Print' dialogs allow you to save or print all,\n",
+ "pages, a range of pages, or all marked pages from a DVI file.\n",
+ "\n",
+ "Note that the page numbers for the `From ... to ...' range\n",
+ "refer to physical pages, not TeX pages (compare the option\n",
+ "`Use TeX Page Numbers' and the `T' keystroke).\n",
+ "\n",
+ "To mark a page or a range of pages, use one of the folllowing\n",
+ "methods:\n",
+ "- Click on the page in the page list with Mouse Button 2 to mark\n",
+ " a single page, or drag the mouse while holding down Button 2\n",
+ " to mark a range of pages.\n",
+ "- Use one of the following key combinations:\n",
+ " m: toggle the mark of the current page,\n",
+ " 1m toggle the marks of all odd pages,\n",
+ " 2m toggle the marks of all even pages,\n",
+ " 0m: unmark all pages,\n",
+ " Ctrl-n: toggle mark of current page, then move one page forward,\n",
+ " Ctrl-u: move one page back, then toggle mark of that page.\n",
+#if MOTIF
+ "- Use one of the toobar buttons 12 to 15 to toggle the marks\n",
+ " of odd pages, toggle the marks of even pages, toggle the mark\n",
+ " of the current page, or unmark all pages, respectively.\n",
+#endif
+ "\n",
+ "If the X resource or command line option `paper' has been used,\n",
+ "its value is inserted into the `Dvips Options' field of the printing\n",
+ "dialog so that the appropriate options can be passed to dvips.\n",
+ "This doesn't happen if the paper size has been specified explicitly\n",
+ "in the DVI file (e.g. by using the LaTeX `geometry' package).\n",
+ "Note that not all of the paper options used by xdvi\n",
+ "may be understood by dvips; dvips will ignore the option\n",
+ "in that case, and will use its default paper setting.\n",
+ NULL
+ };
+
+ static const char *default_help_pagemotion[] = {
+ "Page Motion\tMoving around in the document\n",
+ "\n",
+ "[\n",
+ " Moves back one item in the page history. With a prefix\n",
+ " argument n, move back n history items.\n"
+ "\n",
+ "]\n",
+ " Moves forward one item in the page history. With a prefix\n",
+ " argument n, move forward n history items.\n"
+ "\n",
+ "Ctr-[\n",
+ " Deletes current item in the page history and move\n",
+ " to the history item before the deleted one. With a prefix\n",
+ " argument n, delete n previous history items.\n",
+ "\n",
+ "Ctr-]\n",
+ " Deletes current item in the page history and move\n",
+ " to the history item after the deleted one. With a prefix\n",
+ " argument n, delete n next history items.\n",
+ "\n",
+ "n or f or Space or Return or LineFeed or PgDn",
+#if MOTIF
+ ", toolbar button 5\n",
+#else
+ "\n",
+#endif
+ " Moves to the next page (or to the nth next page if a\n",
+ " number is given).\n",
+ "\n",
+ "p or b or Ctrl-h or BackSpace or Del or PgUp",
+#if MOTIF
+ ", toolbar button 4\n",
+#else
+ "\n",
+#endif
+ " Moves to the previous page (or back n pages).\n",
+ "\n",
+ "Up-arrow\n",
+ " Scrolls page up.\n",
+ "\n",
+ "Down-arrow\n",
+ " Scrolls page down.\n",
+ "u\n",
+ " Moves page up two thirds of a window-full.\n",
+ "\n",
+ "d\n",
+ " Moves page down two thirds of a window-full.\n",
+ "\n",
+ "Left-arrow\n",
+ " Scrolls page left.\n",
+ "\n",
+ "Right-arrow\n",
+ " Scrolls page right.\n",
+ "\n",
+ "l\n",
+ " Moves page left two thirds of a window-full.\n",
+ "\n",
+ "r\n",
+ " Moves page right two thirds of a window-full.\n",
+ "\n",
+ "T\n",
+ " Toggle the use of TeX page numbers instead of physical\n",
+ " pages for the page list and the `g' command.\n",
+ " (See also the `Options -> Use TeX Pages' menu.)\n",
+ "\n",
+ "g\n",
+ " Moves to the page with the given number. Initially,\n",
+ " the first page is assumed to be page number 1, but this\n",
+ " can be changed with the `P' keystroke, described in the\n",
+ " section `Other Commands'. If no page number is given,\n",
+ " it moves to the last page.\n",
+ "\n",
+ "<, Ctrl-Home",
+#if MOTIF
+ ", toolbar button 3\n",
+#else
+ "\n",
+#endif
+ " Moves to first page in the document.\n",
+ "\n",
+ ">, Ctrl-End",
+#if MOTIF
+ ", toolbar button 6\n",
+#else
+ "\n",
+#endif
+ " Moves to last page in the document.\n",
+ "\n",
+ "^\n",
+ " Move to the ``home'' position of the page. This is\n",
+ " normally the upper left-hand corner of the page,\n",
+ " depending on the margins set via the -margins option.\n",
+ "\n",
+ "Home\n",
+ " Move to the ``home'' position of the page (the upper\n",
+ " left-hand corner), or to the top of the page if the `keep'\n",
+ " flag is set.\n",
+ "\n",
+ "End\n",
+ " Move to the end position of the page (the lower\n",
+ " right-hand corner), or to the bottom of the page if the\n",
+ " `keep' flag is set.\n",
+ "\n",
+ "c\n",
+ " Moves the page so that the point currently beneath the\n",
+ " cursor is moved to the middle of the window. It also\n",
+ " warps the cursor to the same place.\n",
+ "\n",
+ NULL
+ };
+
+
+ static const char *default_help_mousebuttons[] = {
+ "Mouse Buttons\tActions bound to the mouse buttons\n",
+ "The mouse buttons can be customized just like the keys;\n",
+ "however the bindings cannot be intermixed (since\n",
+ "a mouse event always requires the cursor location\n",
+ "to be present, which a key event doesn't).\n",
+ "The default bindings are as follows:\n"
+ "\n",
+ "Buttons 1-3\n",
+ " Pops up magnifier windows of different sizes.\n",
+ " When the mouse is over a hyperlink, the link overrides\n",
+ " the magnifier. In that case, Button 1 jumps to the link\n",
+ " in the current xdvi window, Button 2 opens the link target\n",
+ " in a new instance of xdvi.\n",
+ " In `Ruler Mode', Button1 shows/drags the ruler instead;\n",
+ " in `Text Selection Mode', Button1 can be used to select\n",
+ " a rectangular region of text from the DVI file.\n",
+ "\n",
+ "Shift-Button1 to Shift-Button3\n",
+ " Drag the page in each direction (Button 1), vertically\n",
+ " only (Button 2) or horizontally only (Button 3).\n",
+ "\n",
+ "Ctrl-Button1\n",
+ " Invoke a reverse search for the text on the cursor\n",
+ " location (see the section SOURCE SPECIALS for more\n",
+ " information on this).\n",
+ "\n",
+ "The buttons 4 and 5 (wheel up and down for wheel mice)\n",
+ "scroll the page up and down respectively, or jump to the\n",
+ "next/previous page when the mouse is over the page list.",
+ "\n",
+ "In the page list, Button 2 toggles the mark a page (see\n",
+ "section `Marking Pages'); moving the mouse while holding\n",
+ "Button 2 lets you toggle a range of pages.\n",
+ "\n",
+ NULL
+ };
+
+ static const char *default_help_sourcespecials[] = {
+ "Source Specials\tNavigating between the TeX and the DVI file\n",
+ "Some TeX implementations have an option to automatically\n",
+ "include so-called `source specials' into a DVI file. These\n",
+ "contain the line number and the filename of the TeX source\n",
+ "and make it possible to go from a DVI file to the\n",
+ "(roughly) corresponding place in the TeX source and back\n",
+ "(this is also called `reverse search' and `forward search').\n",
+ "\n",
+ "On the TeX side, you need a TeX version that supports the `-src'\n",
+ "option (e.g. teTeX >= 2.0) or a macro package like srcltx.sty\n",
+ "to insert the specials into the DVI file.\n",
+ "\n",
+ "Source special mode can be customized for various editors\n",
+ "by using the command line option \"-editor\" or one of the\n",
+ "environment variables \"XEDITOR\", \"VISUAL\" or \"EDITOR\".\n",
+ "See the xdvi man page on the \"-editor\" option for details\n",
+ "and examples.\n",
+ "\n",
+ "Forward search can be performed by a program (i.e. your editor)\n",
+ "invoking xdvi with the \"-sourceposition\" option like this:\n",
+ "xdvi -sourceposition \"<line> <filename>\" <main file>\n",
+ "If there is already an instance of xdvi running that displays\n",
+ "<main file>, it will try to open the page specified by\n",
+ "<line> and <filename> an highlight this location on the page.\n",
+ "Else, a new instance of xdvi will be started that will try to\n",
+ "do the same.\n",
+ "\n",
+ "The following keybindings are pre-configured:\n",
+ "\n",
+ "Ctrl-Mouse1\n",
+ " [source-special()] Invoke the editor (the value\n",
+ " of the \"editor\" resource ) to display the line in the\n",
+ " TeX file corresponding to special at cursor position.\n",
+ "\n",
+ "Ctrl-v\n",
+ " [show-source-specials()] Show bounding boxes for every\n",
+ " source special on the current page, and print the strings\n",
+ " contained in these specials to stderr. With prefix 1,\n",
+ " show every bounding box on the page (for debugging purposes).\n",
+ "\n",
+ "Ctrl-x\n",
+ " [source-what-special()] Display information about the\n",
+ " source special next to the cursor, similar to\n",
+ " \"source-special()\", but without actually invoking\n",
+ " the editor (for debugging purposes).\n",
+ "\n",
+ NULL
+ };
+
+ static const char *default_help_modes[] = {
+ "Mouse Modes\tMagnifier Mode, Ruler Mode and Text Selection Mode\n",
+ "The keystroke Ctrl-m [switch-mode()] switches between\n",
+ "three different bindings for Mouse-1, which can also be\n",
+ "activated via the Modes menu (in Motif, this is a submenu\n",
+ "of the Options menu). The default mode at startup can be\n",
+ "customized via the X resource `mouseMode' or the command-line\n",
+ "option `-mousemode'. The default startup mode is Magnifier Mode.\n",
+ "\n",
+ "Note: The modes are activated by changing the magnifier()\n",
+ "action. Switching the mode will not work if Mouse-1 has\n",
+ "been customized to an action sequence that does not contain\n",
+ "the magnifier() action.\n",
+ "\n",
+ "Magnifier Mode\n",
+ "\n",
+ " In this mode, the mouse buttons 1 to 5 will pop up a\n",
+ " ``magnifying glass'' that shows an unshrunken image of\n",
+ " the page (i.e. an image at the resolution determined by\n",
+ " the option/X resource pixels or mfmode) at varying sizes.\n",
+ " When the magnifier is moved, small ruler-like tick marks\n",
+ " are displayed at the edges of the magnifier (unless\n",
+ " the X resource delayRulers is set to false, in which case\n",
+ " the tick marks are always displayed).\n",
+ "\n",
+ " The unit of the marks is determined by the X resource\n",
+ " `tickUnits' (mm by default). This unit can be changed at\n",
+ " runtime via the action `switch-magnifier-units()', by\n",
+ " default bound to the keystroke `t' (see the description\n",
+ " of that key, and of `switch-magnifier-units()' for more\n",
+ " details on the units available). The length of the tick\n",
+ " marks can be changed via the X resource `tickLength'\n",
+ " (4 by default). A zero or negative value suppresses the\n",
+ " tick marks.\n",
+ "\n",
+ "\n",
+ "Text Selection Mode\n",
+ "\n",
+ " This mode allows you to select a rectangular region of\n",
+ " text in the DVI file by holding down Mouse-1 and moving\n",
+ " the mouse. The text is put into the X primary selection\n",
+ " so that it can be pasted into other X applications with\n",
+ " Mouse-2.\n",
+ "\n",
+ " If xdvi has been compiled with locale, nl_langinfo() and\n",
+ " iconv support, the selected text is converted into the\n",
+ " character set of the current locale (see the output of\n",
+ " `locale -a' for a list of locale settings available on\n",
+ " your system). If nl_langinfo() is not available, but\n",
+ " iconv is, you can specify the input encoding for iconv\n",
+ " via the X resource `textEncoding' (see the output of\n",
+ " `iconv -l' for a list of valid encodings). If iconv support\n",
+ " is not available, only the encodings ISO-8859-1 and UTF-8\n",
+ " are supported (these names are case-insensitive).\n",
+ "\n",
+ " Note that UTF-8 is the only encoding that can render all\n",
+ " characters (e.g. mathematical symbols). If ISO-8859-1 is\n",
+ " active, characters that cannot be displayed are replaced\n",
+ " by `\' followed by the hexadecimal character code. If a\n",
+ " character is not recognized at all, it is replaced by\n",
+ " `?'. For other encodings, such characters may trigger\n",
+ " iconv error messages.\n",
+ "\n",
+ " If you want to extract larger portions of text, you\n",
+ " can also save selected pages or the entire file in\n",
+ " text format from the `File > Save as ...' menu.\n",
+ "\n",
+ "\n",
+ "Ruler Mode\n",
+ "\n",
+ " This mode provides a simple way of measuring distances\n",
+ " on the page. When this mode is activated, the mouse\n",
+ " cursor changes into a thin cross, and a larger, cross-\n",
+ " shaped ruler is drawn in the highlight color at the\n",
+ " mouse location. The ruler doesn't have units attached\n",
+ " to it; instead, the current distance between the ruler\n",
+ " and the mouse cursor is continously printed to the\n",
+ " statusline.\n",
+ "\n",
+ " When activating Ruler Mode, the ruler is at first\n",
+ " attached to the mouse and can be moved around. It can\n",
+ " then be positioned at a fixed place by clicking Mouse-1.\n",
+ " After that, the mouse cursor can be moved to measure the\n",
+ " horizontal (dx), vertical (dy) and direct (shortest)\n",
+ " (dr) distance between the ruler center point and the\n",
+ " mouse.\n",
+ "\n",
+ " Clicking Mouse-1 again will move the ruler to the\n",
+ " current mouse position, and holding down Mouse-1 will\n",
+ " drag the ruler around.\n",
+ "\n",
+ " In Ruler Mode, the following special keybindings extend\n",
+ " or replace the default bindings:\n",
+ "\n",
+ " o [ruler-snap-origin()] Snap the ruler back to\n",
+ " the origin coordinate (0,0).\n",
+ "\n",
+ " t [overrides switch-magnifier-units()] Toggle\n",
+ " between various ruler units, which can be\n",
+ " specified by the X resource tickUnits (`mm'\n",
+ " by default).\n",
+ "\n",
+ " P [overrides declare-page-number()] Print the\n",
+ " distances shown in the statusline to standard\n",
+ " output.\n",
+ NULL
+ };
+
+ static const char *default_help_search[] = {
+ "String Search\tSearching for strings in the DVI file\n",
+ "The keystroke Ctrl-f or the menu entry File->Find ...\n",
+ "opens a dialog window to search for a text string or a\n",
+ "regular expression in the DVI file. The keystroke Ctrl-g\n",
+ "jumps to the next match.\n",
+#ifdef MOTIF
+ "(With Motif, you can also click on the `Binoculars' symbol\n",
+ "in the toolbar.)\n",
+#endif
+ "\n",
+#if HAVE_ICONV_H
+#if USE_LANGINFO
+ "The search term is converted from the character set specified\n",
+ "by the current locale into UTF-8. (See the output of `locale -a'\n",
+ "for a list of locale settings available on your system).\n",
+#else /* USE_LANGINFO */
+ "Since langinfo() support is not available on this platform,\n",
+ "the character set of the search string should be specified\n",
+ "via the X resource/command-line option textEncoding if the\n",
+ "encoding is different from iso_8859-1.\n",
+#endif /* USE_LANGINFO */
+#else /* HAVE_ICONV_H */
+ "Since iconv() support is not available on this platform,\n",
+ "the search term should be a string in the encoding specified\n",
+ "by the X resource/command-line option textEncoding;\n",
+ "currently, only the values iso_8859-1 and utf-8 are suported.\n",
+#endif
+ "Internally, the text in the DVI file is represented in\n",
+ "UTF-8 encoding (you can view the text by saving the DVI\n",
+ "file to a text file in UTF-8 encoding via the `File -> Save As ...'\n",
+ "dialog).\n",
+ "\n",
+ "Ideographic characters from CJKV fonts are treated specially:\n",
+ "All white space (spaces and newlines) before and after such\n",
+ "characters is ignored in the search string and in the DVI file.\n",
+ "\n",
+ "To match a newline character, use `\\n' in the search string;\n",
+ "to match the string `\\n', use `\\\\n'.\n",
+ "\n",
+ "If the checkbox Regular Expression is activated, the\n",
+ "string is teated as a regular expression in extended POSIX\n",
+ "format, with the following properties:\n",
+ "\n",
+ " a? matches a zero or one times\n",
+ "\n",
+ " a* matches a zero or more times\n",
+ "\n",
+ " a+ matches a one or more times. Note that * and + are\n",
+ " greedy, i.e. they match the longest possible\n",
+ " sub string.\n",
+ "\n",
+ " a{n} matches a exactly n times\n",
+ "\n",
+ " a{n,m} matches a at least n and no more than m times\n",
+ "\n",
+ " a|b matches a or b. Brackets can be used for grouping,\n",
+ " e.g.: (a|b)|c.\n",
+ "\n",
+ " The string matched by the nth group can be referenced\n",
+ " by \\n, e.g. \\1 refers to the first match.\n",
+ "\n",
+ " The characters ^ and $ match the beginning and the end\n",
+ " of a line, respectively.\n",
+ "\n",
+ " [abc] matches any of the letters a, b, c, and [a-z]\n",
+ " matches all characters from a to z.\n",
+ "\n",
+ " The patterns . and [...] without an explicit newline\n",
+ " don't match a newline character.\n",
+ "\n",
+ " Each item in a regular expression can also be one of\n",
+ " the following POSIX character classes:\n",
+ " [[:alnum:]] [[:alpha:]] [[:blank:]] [[:cntrl:]] [[:digit:]]\n",
+ " [[:graph:]] [[:lower:]] [[:print:]] [[:space:]] [[:upper:]]\n",
+ "\n",
+ " These can be negated by inserting a ^ symbol after the\n",
+ " first bracket: [^[:alpha:]]\n",
+ "\n",
+ " For more details on POSIX regular expressions, see\n",
+ " e.g. the IEEE Std 1003.1 available online from:\n",
+ "\n",
+ " http://www.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap09.html\n",
+ "\n",
+ " As a non-standard extension, the following Perl-like\n",
+ " abbreviations can be used instead of the POSIX classes:\n",
+ "\n",
+ "\n",
+ " Symbol Meaning POSIX Class\n",
+ "\n",
+ " \\w an alphanumeric character [[:alnum:]]\n",
+ " \\W a non-alphanumeric character [^[:alnum:]]\n",
+ " \\d a digit character [[:digit:]]\n",
+ " \\D a non-digit character [^[:digit:]]\n",
+ " \\s a whitespace character [[:space:]]\n",
+ " \\S a non-whitespace character [^[:space:]]\n",
+ "\n",
+ " The following characters are special symbols; they\n",
+ " need to be escaped with \\ in order to match them\n",
+ " literally: ( ) [ ] . * ? + ^ $ \\.\n",
+ "\n",
+ "The dialog also provides checkboxes to search backwards,\n",
+ "to match in a case-sensitive manner (the default is to\n",
+ "ignore case, i.e. a search string Test will match both\n",
+ "the strings test and TEST in the DVI file) and to ignore\n",
+ "newlines and hyphens in the DVI file.\n",
+ "\n",
+ NULL
+ };
+
+ k = width = 0;
+
+ init_item(resource.help_general, default_help_general, info, k++, &width);
+ init_item(resource.help_pagemotion, default_help_pagemotion, info, k++, &width);
+ init_item(resource.help_othercommands, default_help_othercommands, info, k++, &width);
+ init_item(resource.help_hypertex, default_help_hypertex, info, k++, &width);
+ init_item(resource.help_mousebuttons, default_help_mousebuttons, info, k++, &width);
+ init_item(resource.help_modes, default_help_modes, info, k++, &width);
+ init_item(resource.help_search, default_help_search, info, k++, &width);
+ init_item(resource.help_pagemotion, default_help_marking, info, k++, &width);
+ init_item(resource.help_sourcespecials, default_help_sourcespecials, info, k++, &width);
+
+ ASSERT(k < NUM_HELP_TOPICS, "Too many elements in help topics!");
+
+ /* NULL-terminate items info */
+ info->items[k].widget = 0;
+ info->items[k].topic = info->items[k].title = NULL;
+
+ /* adjust width of topics label to longest text */
+#if !MOTIF
+ XtVaSetValues(info->topic_label, XtNwidth, width, NULL);
+#endif
+}
+
+
+
+/*
+ * Pops up the help window. If topic != NULL, also selects the topic.
+ */
+void
+show_help(Widget toplevel, const char *topic)
+{
+ size_t i;
+ static Widget help_shell = 0;
+ static struct topic_info info;
+ static struct topic_item items[NUM_HELP_TOPICS];
+ static Boolean first_time = True;
+
+ if (help_shell == 0) { /* called 1st time; create widget */
+
+ /* no special callbacks for OK/Cancel buttons */
+ info.ok_callback = NULL;
+ info.cancel_callback = NULL;
+ info.items = items;
+/* info.items_size = NUM_HELP_TOPICS; */
+
+ help_shell = create_topic_window(toplevel,
+ "xdvik: Help",
+ "help_window",
+ &info,
+ initialize_items,
+ "Close",
+ /* no Cancel button needed */
+ NULL);
+ info.shell = help_shell;
+
+ center_window(help_shell, globals.widgets.top_level);
+ }
+
+#if MOTIF
+ { /* check if resources are set properly */
+ Dimension w, h;
+ XtVaGetValues(help_shell, XtNwidth, &w, XtNheight, &h, NULL);
+ if (h < 200 || w < 400) {
+ XDVI_WARNING((stderr, "Initial help window size too small (%dx%d); overriding size.\n"
+ "Please check/update your application defaults file, and set both of\n"
+ "`XDvi*help_text.rows' and `XDvi*help_text.columns' to a realistic value.",
+ h, w));
+ XtVaSetValues(help_shell, XtNwidth, 620, XtNheight, 520, NULL);
+ }
+ }
+#endif
+ XtPopup(help_shell, XtGrabNone);
+
+ if (topic != NULL) {
+ Boolean matched = False;
+ for (i = 0; info.items[i].topic != NULL; i++) {
+ if (strcmp(info.items[i].topic, topic) == 0) { /* match */
+ select_topic(&info, i);
+ matched = True;
+ }
+ }
+ if (!matched) {
+ XBell(DISP, 0);
+ popup_message(help_shell,
+ MSG_WARN,
+ NULL,
+ "Shouldn't happen: Could not find topic `%s' in help list!\n"
+ REPORT_XDVI_BUG_TEMPLATE,
+ topic);
+ }
+ }
+ else if (first_time) {
+ first_time = False;
+ select_topic(&info, 0);
+ }
+}
diff --git a/Build/source/texk/xdvik/gui/help-window.h b/Build/source/texk/xdvik/gui/help-window.h
new file mode 100644
index 00000000000..5464756395f
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/help-window.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2001-2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef HELP_WINDOW_H_
+#define HELP_WINDOW_H_
+
+extern void show_help(Widget parent, const char *topic);
+
+#endif /* HELP_WINDOW_H_ */
diff --git a/Build/source/texk/xdvik/gui/mag.c b/Build/source/texk/xdvik/gui/mag.c
new file mode 100644
index 00000000000..1df6cd92cab
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/mag.c
@@ -0,0 +1,861 @@
+/*
+ * Copyright (c) 1990-2004 Paul Vojta and others
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * NOTE: xdvi is based on prior work, as noted in the modification history in
+ * xdvi.c.
+ *
+ */
+
+/*
+ * Implementation of the magnifier window.
+ */
+
+#include <math.h>
+
+#include "xdvi-config.h"
+/* one of the following should define OPEN_MAX: */
+#include <limits.h>
+#include "c-openmx.h"
+
+#include "xdvi.h"
+
+#ifdef MOTIF
+#include <Xm/Xm.h>
+#endif
+
+#include "events.h"
+#include "dvi-draw.h"
+#include "dvi-init.h"
+#include "statusline.h"
+#include "hypertex.h"
+#include "mag.h"
+#include "xm_toolbar.h"
+#include "xm_menu.h" /* for get_last_ungrab() */
+#include "util.h"
+#include "pagesel.h"
+
+/* to measure distance of pointer from ruler in ruler mode */
+static int g_ruler_pos_x = 0, g_ruler_pos_y = 0;
+
+struct WindowRec magnifier = { (Window) 0, 1, 0, 0, 0, 0, MAXDIM, 0, MAXDIM, 0 };
+
+/*
+ * Mechanism to keep track of the magnifier window. The problems are,
+ *
+ * - if the button is released while the window is being drawn, this could
+ * cause an X error if we continue drawing in it after it is destroyed, and
+ *
+ * - creating and destroying the window too quickly confuses the window
+ * manager, which is avoided by waiting for an expose event before destroying
+ * it.
+ */
+
+short magnifier_stat; /* 1 = wait for expose, -1 = destroy upon expose */
+
+static Position main_x;
+static Position main_y;
+
+static Position mag_x = 0;
+static Position mag_y = 0;
+
+/* Under Motif the following two remain always constant */
+static int mag_conv_x = 0;
+static int mag_conv_y = 0;
+
+static Position new_mag_x = 0;
+static Position new_mag_y = 0;
+
+static void
+can_exposures(struct WindowRec *windowrec)
+{
+ windowrec->min_x = windowrec->min_y = MAXDIM;
+ windowrec->max_x = windowrec->max_y = 0;
+}
+
+static void
+mag_motion(XEvent * event)
+{
+ MYTRACE((stderr, "mag_motion!\n"));
+ new_mag_x = event->xmotion.x + mag_conv_x;
+ main_x = event->xmotion.x_root - new_mag_x;
+ new_mag_y = event->xmotion.y + mag_conv_y;
+ main_y = event->xmotion.y_root - new_mag_y;
+
+ if (new_mag_x != mag_x || new_mag_y != mag_y)
+ globals.ev.flags |= EV_MAG_MOVE;
+ else
+ globals.ev.flags &= ~EV_MAG_MOVE;
+}
+
+void
+mag_release(XEvent * event)
+{
+ UNUSED(event);
+ if (magnifier.win != (Window) 0) {
+ if (magnifier_stat) {
+ magnifier_stat = -1; /* destroy upon expose */
+ }
+ else {
+ XDestroyWindow(DISP, magnifier.win);
+ if (drawing_mag) {
+ globals.ev.flags |= EV_MAG_GONE;
+ }
+ magnifier.win = (Window) 0;
+ mouse_motion = mouse_release = null_mouse;
+ globals.ev.flags &= ~EV_MAG_MOVE;
+ globals.cursor.flags &= ~CURSOR_MAG;
+ globals.ev.flags |= EV_CURSOR;
+ can_exposures(&magnifier);
+ /*
+ Workaround for bug #703304:
+ For obscure reasons, XFree 3.3.5 (and apparently also Solaris 8)
+ doesn't generate an expose event after the magnifier has beed
+ destroyed. But only a redraw() event caused by expose would reset
+ currwin.win back to mane.win, which is needed e.g. for getting the
+ hyperlink info updated (otherwise, the mouse will not become active
+ over a hyperlink).
+
+ Forcing a redraw with
+ redraw(&mane);
+ may cause a `BadDrawable' X error with color material (e.g. from #702288),
+ or a `draw_part: shouldn't happen: POST encountered' error. Neither do
+ the following work:
+ globals.ev.flags |= EV_EXPOSE; (doesn't fix the bug)
+ draw_page(); (same effect as redraw(&mane))
+ globals.ev.flags |= EV_NEWPAGE; (works, but is crude and causes flicker)
+
+ So I decided to use expose() for the time being, which
+ sets mane.min_x to the current x point (which doesn't happen
+ with EV_EXPOSE; this causes the test for `mane.min_x < MAXDIM'
+ to fail in events.c; look for `see comment in mag.c').
+ */
+/* fprintf(stderr, "========triggering expose!\n"); */
+ expose(&mane, event->xbutton.x_root, event->xbutton.y_root, 10, 10);
+ }
+ }
+}
+
+static int
+tick_scale(int k)
+{
+ if (k == 0)
+ return 3;
+ else if ((k % 1000) == 0)
+ return 7;
+ else if ((k % 500) == 0)
+ return 6;
+ else if ((k % 100) == 0)
+ return 5;
+ else if ((k % 50) == 0)
+ return 4;
+ else if ((k % 10) == 0)
+ return 3;
+ else if ((k % 5) == 0)
+ return 2;
+ else
+ return 1;
+}
+
+static void
+draw_ticks(unsigned int width, unsigned int height, GC ourGC)
+{
+ int k; /* tick counter */
+ double old_pixels_per_tick;
+ double pixels_per_tick;
+ int scale;
+ int tick_offset; /* offset along axes */
+ int x; /* coordinates of top-left popup */
+ int y; /* window corner */
+ double xx; /* coordinates of tick */
+ double yy; /* coordinates of tick */
+ static char *last_tick_units = ""; /* memory of last tick units */
+
+ if (resource.tick_length <= 0) /* user doesn't want tick marks */
+ return;
+
+ x = 0; /* the pop-up window always has origin (0,0) */
+ y = 0;
+
+ /* We need to clear the existing window to remove old rulers. I think
+ that this could be avoided if draw_ticks() could be invoked earlier.
+ The expose argument in XClearArea() must be True to force redrawing
+ of the text inside the popup window. Also, it would be better to draw
+ the rulers before painting the text, so that rulers would not
+ overwrite the text, but I haven't figured out yet how to arrange
+ that. */
+
+ XClearArea(DISP, magnifier.win, x, y, width, height, True);
+
+ /* The global resource.pixels_per_inch tells us how to find the ruler
+ scale. For example, 300dpi corresponds to these TeX units:
+
+ 1 TeX point (pt) = 4.151 pixels
+ 1 big point (bp) = 4.167 pixels
+ 1 pica (pc) = 49.813 pixels
+ 1 cicero (cc) = 53.501 pixels
+ 1 didot point (dd) = 4.442 pixels
+ 1 millimeter (mm) = 11.811 pixels
+ 1 centimeter (cm) = 118.110 pixels
+ 1 inch (in) = 300.000 pixels
+ 1 scaled point (sp) = 0.00006334 pixels
+
+ The user can select the units via a resource (e.g. XDvi*tickUnits: bp),
+ or a command-line option (e.g. -xrm '*tickUnits: cm'). The length of
+ the ticks can be controlled by a resource (e.g. XDvi*tickLength: 10), or
+ a command-line option (e.g. -xrm '*tickLength: 10000'). If the tick
+ length exceeds the popup window size, then a graph-paper grid is drawn
+ over the whole window. Zero, or negative, tick length completely
+ suppresses rulers. */
+
+ pixels_per_tick = (double)resource.pixels_per_inch;
+ if (strcmp(resource.tick_units, "pt") == 0)
+ pixels_per_tick /= 72.27;
+ else if (strcmp(resource.tick_units, "bp") == 0)
+ pixels_per_tick /= 72.0;
+ else if (strcmp(resource.tick_units, "in") == 0)
+ /* NO-OP */ ;
+ else if (strcmp(resource.tick_units, "cm") == 0)
+ pixels_per_tick /= 2.54;
+ else if (strcmp(resource.tick_units, "mm") == 0)
+ pixels_per_tick /= 25.4;
+ else if (strcmp(resource.tick_units, "dd") == 0)
+ pixels_per_tick *= (1238.0 / 1157.0) / 72.27;
+ else if (strcmp(resource.tick_units, "cc") == 0)
+ pixels_per_tick *= 12.0 * (1238.0 / 1157.0) / 72.27;
+ else if (strcmp(resource.tick_units, "pc") == 0)
+ pixels_per_tick *= 12.0 / 72.27;
+ else if (strcmp(resource.tick_units, "sp") == 0)
+ pixels_per_tick /= (65536.0 * 72.27);
+ else if (strcmp(resource.tick_units, "px") == 0)
+ pixels_per_tick = 10;
+ else {
+ XDVI_WARNING((stderr, "Unrecognized tickUnits [%s]: defaulting to TeX points [pt]",
+ resource.tick_units));
+ resource.tick_units = "pt";
+ pixels_per_tick /= 72.27;
+ }
+
+ /* To permit accurate measurement in the popup window, we can reasonably
+ * place tick marks about 3 to 10 pixels apart, so we scale the computed
+ * pixels_per_tick by a power of ten to bring it into that range.
+ */
+
+ old_pixels_per_tick = pixels_per_tick; /* remember the original scale */
+ while (pixels_per_tick < 3.0)
+ pixels_per_tick *= 10.0;
+ while (pixels_per_tick > 30.0)
+ pixels_per_tick /= 10.0;
+
+ /* tell user what the ruler scale is, but only when it changes */
+ if (strcmp(last_tick_units, resource.tick_units) != 0) {
+ if (old_pixels_per_tick != pixels_per_tick)
+ printf("Ruler tick interval adjusted to represent %.2f%s\n",
+ pixels_per_tick / old_pixels_per_tick, resource.tick_units);
+ else if (globals.debug & DBG_EVENT)
+ printf("Ruler tick interval represents 1%s\n", resource.tick_units);
+ }
+
+ /* In order to make the ruler as accurate as possible, given the coarse
+ * screen resolution, we compute tick positions in floating-point
+ * arithmetic, then round to nearest integer values.
+ */
+
+ /* draw vertical ticks on top and bottom */
+ for (k = 0, xx = 0.0; xx < (double)width; k++, xx += pixels_per_tick) {
+ tick_offset = (int)(0.5 + xx); /* round to nearest pixel */
+ scale = tick_scale(k);
+ XDrawLine(DISP, magnifier.win, ourGC,
+ x + tick_offset, y, x + tick_offset, y + scale * resource.tick_length);
+ XDrawLine(DISP, magnifier.win, ourGC,
+ x + tick_offset, y + height,
+ x + tick_offset, y + height - scale * resource.tick_length);
+ }
+
+ /* draw horizontal ticks on left and right */
+ for (k = 0, yy = 0.0; yy < (double)height; k++, yy += pixels_per_tick) {
+ tick_offset = (int)(0.5 + yy); /* round to nearest pixel */
+ scale = tick_scale(k);
+ XDrawLine(DISP, magnifier.win, ourGC,
+ x, y + tick_offset, x + scale * resource.tick_length, y + tick_offset);
+ XDrawLine(DISP, magnifier.win, ourGC,
+ x + width, y + tick_offset,
+ x + width - scale * resource.tick_length, y + tick_offset);
+ }
+
+ last_tick_units = resource.tick_units;
+
+ XFlush(DISP); /* bring window up-to-date */
+}
+
+static void
+compute_mag_pos(int *xp, int *yp)
+{
+ int t;
+
+ t = mag_x + main_x - magnifier.width / 2;
+ if (t > WidthOfScreen(SCRN) - (int)magnifier.width - 2 * MAGBORD)
+ t = WidthOfScreen(SCRN) - (int)magnifier.width - 2 * MAGBORD;
+ if (t < 0)
+ t = 0;
+ *xp = t;
+ t = mag_y + main_y - magnifier.height / 2;
+ if (t > HeightOfScreen(SCRN) - (int)magnifier.height - 2 * MAGBORD)
+ t = HeightOfScreen(SCRN) - (int)magnifier.height - 2 * MAGBORD;
+ if (t < 0)
+ t = 0;
+ *yp = t;
+}
+
+static void
+scroll_window(struct WindowRec *windowrec, int x0, int y0)
+{
+ int x, y;
+ int x2 = 0, y2 = 0;
+ int ww, hh;
+
+ x = x0 - windowrec->base_x;
+ y = y0 - windowrec->base_y;
+ ww = windowrec->width - x;
+ hh = windowrec->height - y;
+ windowrec->base_x = x0;
+ windowrec->base_y = y0;
+ if (currwin.win == windowrec->win) {
+ currwin.base_x = x0;
+ currwin.base_y = y0;
+ }
+ windowrec->min_x -= x;
+ if (windowrec->min_x < 0)
+ windowrec->min_x = 0;
+ windowrec->max_x -= x;
+ if ((unsigned int)windowrec->max_x > windowrec->width)
+ windowrec->max_x = windowrec->width;
+ windowrec->min_y -= y;
+ if (windowrec->min_y < 0)
+ windowrec->min_y = 0;
+ windowrec->max_y -= y;
+ if ((unsigned int)windowrec->max_y > windowrec->height)
+ windowrec->max_y = windowrec->height;
+ if (x < 0) {
+ x2 = -x;
+ x = 0;
+ ww = windowrec->width - x2;
+ }
+ if (y < 0) {
+ y2 = -y;
+ y = 0;
+ hh = windowrec->height - y2;
+ }
+ if (ww <= 0 || hh <= 0) {
+ XClearWindow(DISP, windowrec->win);
+ windowrec->min_x = windowrec->min_y = 0;
+ windowrec->max_x = windowrec->width;
+ windowrec->max_y = windowrec->height;
+ }
+ else {
+ XCopyArea(DISP, windowrec->win, windowrec->win, globals.gc.copy,
+ x, y, (unsigned int)ww, (unsigned int)hh, x2, y2);
+ if (x > 0)
+ clearexpose(windowrec, ww, 0, (unsigned int)x, windowrec->height);
+ if (x2 > 0)
+ clearexpose(windowrec, 0, 0, (unsigned int)x2, windowrec->height);
+ if (y > 0)
+ clearexpose(windowrec, 0, hh, windowrec->width, (unsigned int)y);
+ if (y2 > 0)
+ clearexpose(windowrec, 0, 0, windowrec->width, (unsigned int)y2);
+ }
+}
+
+static void
+do_movemag(int x, int y)
+{
+ int xx, yy;
+
+ mag_x = x;
+ mag_y = y;
+ if (mag_x == new_mag_x && mag_y == new_mag_y)
+ globals.ev.flags &= ~EV_MAG_MOVE;
+ compute_mag_pos(&xx, &yy);
+ XMoveWindow(DISP, magnifier.win, xx, yy);
+ scroll_window(&magnifier,
+ (x + mane_base_x) * mane.shrinkfactor - (int)magnifier.width / 2,
+ (y + mane_base_y) * mane.shrinkfactor - (int)magnifier.height / 2);
+ draw_ticks(magnifier.width, magnifier.height, globals.gc.ruler);
+}
+
+extern jmp_buf next_env;
+
+void
+show_distance_from_ruler(XEvent *event, Boolean to_stdout)
+{
+ int loc_x, loc_y;
+ int precision = 2;
+ double factor;
+
+ if (event == NULL) /* when option is toggled */
+ return;
+
+ loc_x = event->xbutton.x;
+ loc_y = event->xbutton.y;
+ if (event->xbutton.window != mane.win) {
+ Window ww;
+ (void)XTranslateCoordinates(DISP,
+ RootWindowOfScreen(SCRN), mane.win,
+ event->xbutton.x_root,
+ event->xbutton.y_root,
+ &loc_x,
+ &loc_y,
+ &ww); /* throw away last argument */
+ }
+
+ /* map everything below 0 to the origin */
+ if (loc_x < 0)
+ loc_x = 0;
+ if (loc_y < 0)
+ loc_y = 0;
+
+ if (strcmp(resource.tick_units, "pt") == 0) {
+ factor = 72.27 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+ else if (strcmp(resource.tick_units, "bp") == 0) {
+ factor = 72.0 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+ else if (strcmp(resource.tick_units, "in") == 0) {
+ factor = currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+ else if (strcmp(resource.tick_units, "cm") == 0) {
+ factor = 2.54 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ precision = 3;
+ }
+ else if (strcmp(resource.tick_units, "mm") == 0) {
+ factor = 25.4 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+ else if (strcmp(resource.tick_units, "dd") == 0) {
+ factor = 72.27 / (1238.0 / 1157.0) * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+ else if (strcmp(resource.tick_units, "cc") == 0) {
+ factor = 72.27 / (12.0 * (1238.0 / 1157.0)) * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+ else if (strcmp(resource.tick_units, "pc") == 0) {
+ factor = 72.27 / 12.0 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+ else if (strcmp(resource.tick_units, "sp") == 0) {
+ factor = 65536.0 * 72.27 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ precision = 1;
+ }
+ else if (strcmp(resource.tick_units, "px") == 0) { /* pixel units */
+ factor = 1;
+ }
+ else {
+ XDVI_WARNING((stderr, "Unrecognized tickUnits [%s]: defaulting to TeX points [pt]",
+ resource.tick_units));
+ resource.tick_units = "pt";
+ factor = 72.27 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
+ }
+
+ if (mouse_release != null_mouse) {
+ if (to_stdout) {
+ XDVI_INFO((stdout, "Ruler/Point: %d,%d, dx: %.*f %s, dy: %.*f %s, dr: %.*f %s",
+ loc_x, loc_y,
+ precision, 0.000, resource.tick_units,
+ precision, 0.000, resource.tick_units,
+ precision, 0.000, resource.tick_units));
+ }
+ else {
+ statusline_print(STATUS_FOREVER,
+ "Ruler/Point: %d,%d, dx: %.*f %s, dy: %.*f %s, dt: %.*f %s",
+ loc_x, loc_y,
+ precision, 0.000, resource.tick_units,
+ precision, 0.000, resource.tick_units,
+ precision, 0.000, resource.tick_units);
+ }
+ }
+ else {
+ int d_x = loc_x - g_ruler_pos_x;
+ int d_y = loc_y - g_ruler_pos_y;
+ double d_z = sqrt((double)d_x * d_x + (double)d_y * d_y);
+ double unit_x = (double)d_x * factor;
+ double unit_y = (double)d_y * factor;
+ double unit_z = d_z * factor;
+ if (to_stdout) {
+ XDVI_INFO((stdout, "Ruler: %d,%d, Point: %d,%d, dx: %.*f %s, dy: %.*f %s, dr: %.*f %s",
+ g_ruler_pos_x, g_ruler_pos_y, loc_x, loc_y,
+ precision, unit_x, resource.tick_units,
+ precision, unit_y, resource.tick_units,
+ precision, unit_z, resource.tick_units));
+ }
+ else {
+ statusline_print(STATUS_FOREVER,
+ "Ruler: %d,%d, Point: %d,%d, dx: %.*f %s, dy: %.*f %s, dr: %.*f %s",
+ g_ruler_pos_x, g_ruler_pos_y, loc_x, loc_y,
+ precision, unit_x, resource.tick_units,
+ precision, unit_y, resource.tick_units,
+ precision, unit_z, resource.tick_units);
+ }
+ }
+}
+
+void
+move_magnifier(void)
+{
+ if (magnifier.win == (Window) 0)
+ globals.ev.flags &= ~EV_MAG_MOVE;
+ else if (abs(new_mag_x - mag_x) > 2 * abs(new_mag_y - mag_y))
+ do_movemag(new_mag_x, mag_y);
+ else if (abs(new_mag_y - mag_y) > 2 * abs(new_mag_x - mag_x))
+ do_movemag(mag_x, new_mag_y);
+ else
+ do_movemag(new_mag_x, new_mag_y);
+}
+
+static void
+Act_href(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int x, y;
+ Window dummy;
+
+ UNUSED(w);
+ UNUSED(num_params);
+ UNUSED(params);
+
+ if (resource.mouse_mode == MOUSE_RULER_MODE)
+ return;
+
+ (void)XTranslateCoordinates(DISP, event->xkey.window, mane.win,
+ event->xkey.x, event->xkey.y, &x, &y, &dummy);
+ if (htex_handleref(x, y, False)) {
+ block_next_mouse_event();
+ }
+}
+
+static void
+Act_href_newwindow(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ int x, y;
+ Window dummy;
+
+ UNUSED(w);
+ UNUSED(num_params);
+ UNUSED(params);
+
+ if (resource.mouse_mode == MOUSE_RULER_MODE)
+ return;
+
+ (void)XTranslateCoordinates(DISP, event->xkey.window, mane.win,
+ event->xkey.x, event->xkey.y, &x, &y, &dummy);
+ if (htex_handleref(x, y, True)) {
+ block_next_mouse_event();
+ }
+}
+
+void
+clear_ruler(void)
+{
+ /* maybe we should do this only for mouse-1? */
+ clearexpose(&mane, 0, g_ruler_pos_y,
+ ROUNDUP(pageinfo_get_page_width(current_page), currwin.shrinkfactor) + 2, 1);
+ clearexpose(&mane, g_ruler_pos_x, 0,
+ 1, ROUNDUP(pageinfo_get_page_height(current_page), currwin.shrinkfactor) + 2);
+}
+
+void
+show_ruler(XEvent *event)
+{
+ if (mouse_release == null_mouse) {
+ if (mouse_release != null_mouse && mouse_release != drag_ruler_release)
+ return;
+ if (mouse_release == null_mouse) {
+ mouse_motion = drag_ruler_motion;
+ mouse_release = drag_ruler_release;
+ }
+ drag_ruler_motion(event);
+ }
+}
+
+static void
+draw_ruler(int x, int y)
+{
+ /* don't draw if outside page region (will be clipped automatically by Motif,
+ but not by Xaw, where draw widget is entire window) */
+ if (x > (int)ROUNDUP(pageinfo_get_page_width(current_page), currwin.shrinkfactor) + 1
+ || y > (int)ROUNDUP(pageinfo_get_page_height(current_page), currwin.shrinkfactor) + 1)
+ return;
+
+ XFillRectangle(DISP, mane.win, globals.gc.high,
+ 0, y,
+ ROUNDUP(pageinfo_get_page_width(current_page), currwin.shrinkfactor) + 2, 1);
+ XFillRectangle(DISP, mane.win, globals.gc.high,
+ x, 0,
+ 1, ROUNDUP(pageinfo_get_page_height(current_page), currwin.shrinkfactor) + 2);
+}
+
+
+/* snap ruler back to origing (0,0) */
+void
+ruler_snap_origin(XEvent *event)
+{
+ clear_ruler();
+ g_ruler_pos_x = g_ruler_pos_y = 0;
+ draw_ruler(g_ruler_pos_x, g_ruler_pos_y);
+ /* deactivate mouse dragging */
+ mouse_motion = mouse_release = null_mouse;
+ show_distance_from_ruler(event, False);
+}
+
+void
+redraw_ruler(void)
+{
+ draw_ruler(g_ruler_pos_x, g_ruler_pos_y);
+}
+
+void
+drag_ruler_motion(XEvent *event)
+{
+ int loc_x, loc_y;
+ if (event == NULL) { /* toggled via menu */
+ /* hack to avoid redrawing ruler at last g_* positions when mode is
+ toggled on via menu, then off via keystroke */
+ g_ruler_pos_x = g_ruler_pos_y = 0;
+ return;
+ }
+
+ loc_x = event->xbutton.x;
+ loc_y = event->xbutton.y;
+
+ if (event->xbutton.window != mane.win) {
+ Window dummy;
+ (void)XTranslateCoordinates(DISP,
+ RootWindowOfScreen(SCRN), mane.win,
+ event->xbutton.x_root,
+ event->xbutton.y_root,
+ &loc_x,
+ &loc_y,
+ &dummy);
+ }
+
+ /* map everything below 0 to the origin */
+ if (loc_x < 0)
+ loc_x = 0;
+ if (loc_y < 0)
+ loc_y = 0;
+
+ clear_ruler();
+ draw_ruler(loc_x, loc_y);
+ g_ruler_pos_x = loc_x;
+ g_ruler_pos_y = loc_y;
+}
+
+void
+drag_ruler_release(XEvent *event)
+{
+ UNUSED(event);
+ mouse_motion = mouse_release = null_mouse;
+}
+
+/****************************************************************************
+ * Actions specific to the handling of the magnifier
+ */
+
+static void
+Act_magnifier(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ const char *p;
+ int x, y;
+ XSetWindowAttributes attr;
+#ifndef MOTIF
+ Window throwaway;
+#endif
+ UNUSED(w);
+
+ MYTRACE((stderr, "magnifier!\n"));
+
+ if (block_this_mouse_event())
+ return;
+ else if (dvi_file_changed()) {
+ globals.ev.flags |= EV_RELOAD;
+ return;
+ }
+
+#ifdef MOTIF
+ /* see xm_menu.c for an explanation of this */
+ if (pulldown_menu_active(event->xany.serial)) {
+ return;
+ }
+#endif
+
+ if (bg_current == NULL) {
+ /*
+ HACK ALERT: we can arrive here after loading a new file via the file selector
+ for which not all fonts have been generated. In that case, dereferencing
+ bg_current would bomb. Try to recover by simply returning here.
+ */
+ return;
+ }
+
+ if (resource.mouse_mode == MOUSE_RULER_MODE && event->xbutton.button == 1) {
+ show_ruler(event);
+ XDefineCursor(DISP, CURSORWIN, globals.cursor.rule);
+ show_distance_from_ruler(event, False);
+ return;
+ }
+ else if (resource.mouse_mode == MOUSE_TEXT_MODE && event->xbutton.button == 1) {
+ text_selection_start(event);
+ text_motion(event);
+ return;
+ }
+
+ if (event->type != ButtonPress || mouse_release != null_mouse
+ || magnifier.win != (Window)0 || mane.shrinkfactor == 1 || *num_params != 1) {
+ XBell(DISP, 0);
+ if (mane.shrinkfactor == 1) {
+ statusline_print(STATUS_SHORT,
+ "No magnification available at shrink factor 1");
+ }
+ return;
+ }
+
+ p = *params;
+ if (*p == '*') {
+ int n = atoi(p + 1) - 1;
+
+ if (n < 0 || n >= (int)get_magglass_items() || get_magglass_width(n) <= 0) {
+ XBell(DISP, 0);
+ return;
+ }
+ magnifier.width = get_magglass_width(n);
+ magnifier.height = get_magglass_height(n);
+ }
+ else {
+ magnifier.width = magnifier.height = atoi(p);
+ p = strchr(p, 'x');
+ if (p != NULL) {
+ magnifier.height = atoi(p + 1);
+ if (magnifier.height == 0)
+ magnifier.width = 0;
+ }
+ if (magnifier.width == 0) {
+ XBell(DISP, 0);
+ return;
+ }
+ }
+#ifndef MOTIF
+ XTranslateCoordinates(DISP, event->xbutton.window, mane.win,
+ 0, 0, &mag_conv_x, &mag_conv_y, &throwaway);
+#endif
+
+ globals.cursor.flags |= CURSOR_MAG;
+ globals.ev.flags |= EV_CURSOR;
+
+ mag_x = event->xbutton.x + mag_conv_x;
+ mag_y = event->xbutton.y + mag_conv_y;
+ main_x = event->xbutton.x_root - mag_x;
+ main_y = event->xbutton.y_root - mag_y;
+ compute_mag_pos(&x, &y);
+ magnifier.base_x = (mag_x + mane_base_x) * mane.shrinkfactor - magnifier.width / 2;
+ magnifier.base_y = (mag_y + mane_base_y) * mane.shrinkfactor - magnifier.height / 2;
+ attr.save_under = True;
+ attr.border_pixel = resource.rule_pixel;
+#if COLOR
+ attr.background_pixel = bg_current->pixel;
+#else
+ attr.background_pixel = resource.back_Pixel;
+#endif
+ attr.override_redirect = True;
+#ifdef GREY
+ attr.colormap = G_colormap;
+#endif
+ magnifier.win = XCreateWindow(DISP, RootWindowOfScreen(SCRN),
+ x, y, magnifier.width, magnifier.height, MAGBORD,
+ G_depth, InputOutput, G_visual,
+ CWSaveUnder | CWBorderPixel | CWBackPixel |
+#ifdef GREY
+ CWColormap |
+#endif
+ CWOverrideRedirect, &attr);
+ XSelectInput(DISP, magnifier.win, ExposureMask);
+ XMapWindow(DISP, magnifier.win);
+
+ /*
+ * This call will draw the point rulers when the magnifier first pops up,
+ * if the XDvi*delayRulers resource is false. Some users may prefer rulers
+ * to remain invisible until the magnifier is moved, so the default is
+ * true. Rulers can be suppressed entirely by setting the XDvi*tickLength
+ * resource to zero or negative.
+ */
+
+ if (!resource.delay_rulers)
+ draw_ticks(magnifier.width, magnifier.height, globals.gc.ruler);
+
+ magnifier_stat = 1; /* waiting for exposure */
+ mouse_motion = mag_motion;
+ mouse_release = mag_release;
+}
+
+static void
+Act_switch_magnifier_units(Widget w, XEvent *event,
+ String *params, Cardinal *num_params)
+{
+ size_t k = 0;
+ static char *TeX_units[] = {
+ "mm", "pt", "in", "sp", "bp", "cc", "dd", "pc", "px",
+ };
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ for (k = 0; k < XtNumber(TeX_units); ++k)
+ if (strcmp(resource.tick_units, TeX_units[k]) == 0)
+ break;
+ k++;
+ if (k >= XtNumber(TeX_units))
+ k = 0;
+ resource.tick_units = TeX_units[k];
+ if (resource.mouse_mode != MOUSE_RULER_MODE) {
+ statusline_print(STATUS_SHORT, "Ruler units: %s\n", resource.tick_units);
+ }
+ else {
+ show_distance_from_ruler(event, False);
+ }
+}
+
+XtActionsRec mag_actions[] = {
+ {"magnifier", Act_magnifier},
+ {"do-href", Act_href},
+ {"do-href-newwindow", Act_href_newwindow},
+ {"switch-magnifier-units", Act_switch_magnifier_units},
+};
+
+/*
+ * This isn't creating the actual magnifier. It is created lazily on demand
+ * if one of the corresponding actions is taken. Therefore we are here
+ * just adding the record of actions related to magnifier handling to the
+ * application.
+ */
+
+void
+create_magnifier(void)
+{
+ XtAppAddActions(app, mag_actions, XtNumber(mag_actions));
+}
diff --git a/Build/source/texk/xdvik/gui/mag.h b/Build/source/texk/xdvik/gui/mag.h
new file mode 100644
index 00000000000..608019f3ac2
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/mag.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1990-2004 Paul Vojta and others
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * NOTE: xdvi is based on prior work, as noted in the modification history in
+ * xdvi.c.
+ *
+ */
+
+#ifndef MAG_H_
+#define MAG_H_
+
+#define MAGBORD 1 /* border size for magnifier */
+
+extern void show_distance_from_ruler(XEvent *event, Boolean to_stdout);
+extern void drag_ruler_motion(XEvent *event);
+extern void drag_ruler_release(XEvent *event);
+extern void clear_ruler(void);
+extern void show_ruler(XEvent *event);
+extern void redraw_ruler(void);
+extern void ruler_snap_origin(XEvent *event);
+
+extern void mag_release(XEvent * event);
+extern void move_magnifier(void);
+extern void create_magnifier(void);
+
+#endif /* MAG_H_ */
+
diff --git a/Build/source/texk/xdvik/gui/menu.c b/Build/source/texk/xdvik/gui/menu.c
new file mode 100644
index 00000000000..575ef162f9b
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/menu.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2003-2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Common code for Xaw and Motif menu bar creation.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "events.h"
+#include "menu.h"
+#include "util.h"
+
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+
+#ifdef MOTIF
+# include <Xm/RowColumn.h>
+# include <Xm/ToggleB.h>
+#else
+# include <X11/Intrinsic.h>
+# include <X11/Xatom.h>
+# include <X11/StringDefs.h>
+# include <X11/Xaw/Label.h>
+#endif
+
+
+/* translate string argument into corresponding buttonTypeT */
+static buttonTypeT
+get_type(const char *str)
+{
+ if (strcmp(str, "PUSH") == 0)
+ return BT_PUSH;
+ else if (strcmp(str, "RADIO") == 0)
+ return BT_RADIO;
+ else if (strcmp(str, "CHECK") == 0)
+ return BT_CHECK;
+ else if (strcmp(str, "SEP") == 0)
+ return BT_SEP;
+ else
+ return BT_INVALID;
+}
+
+static struct button_info *m_button_info = NULL; /* toplevel node of pulldown menu structure */
+
+
+static void
+set_menu_info(void *val, XtActionProc proc, Boolean (*cmp)(), struct button_info *item)
+{
+ size_t i;
+ ASSERT(item != NULL, "item in set_menu_info musn't be NULL!");
+ for (i = 0; i < item->size; i++) {
+ if ((item->elems[i].type == BT_RADIO || item->elems[i].type == BT_CHECK)
+ && item->elems[i].action != NULL
+ && item->elems[i].action->proc != NULL
+ && item->elems[i].action->proc == proc
+ && item->elems[i].action->param != NULL) {
+ Boolean on;
+ ASSERT(cmp != NULL, "comparison function musn't be NULL!");
+ on = cmp(val, item->elems[i].action->param);
+#ifdef MOTIF
+ ASSERT(item->elems[i].widget != 0, "Widget musn't be NULL!");
+ XmToggleButtonSetState(item->elems[i].widget, on, False);
+#else
+#ifdef NEW_MENU_CREATION
+ ASSERT(item->elems[i].widget != 0, "Widget musn't be NULL!");
+ xaw_set_button_state(item->elems + i, on);
+#else
+ static Arg args = { XtNleftBitmap, (XtArgVal) 0 };
+ if (on)
+ args.value = (XtArgVal) menu_check_bitmap;
+ else
+ args.value = (XtArgVal) menu_uncheck_bitmap;
+ XtSetValues(item->elems[i].widget, &args, 1);
+#endif /* NEW_MENU_CREATION */
+#endif
+ }
+ if (item->elems[i].submenu != NULL) { /* invoke it recursively */
+ set_menu_info(val, proc, cmp, item->elems[i].submenu);
+ }
+ }
+}
+
+
+/* set a menu according to val and the compare function cmp */
+void
+set_menu(void *val, XtActionProc proc, Boolean (*cmp)())
+{
+ /* non-standard cast function ptr -> void ptr */
+ /* TRACE_GUI((stderr, "set_menu_info: %d, %p, %p", *(int *)val, (void *)proc, (void *)cmp)); */
+ set_menu_info(val, proc, cmp, m_button_info);
+}
+
+static void
+initialize_menus(void)
+{
+ int use_gs;
+ int shrinkval;
+
+ /* initialize tickmarks for all possible actions */
+ use_gs = resource.postscript;
+#ifdef PS_GS
+ if (!resource.useGS)
+ use_gs = 0;
+#endif
+
+ set_menu(&use_gs, Act_set_ps, check_int);
+ set_menu(&resource.gs_alpha, Act_set_gs_alpha, check_toggle);
+ set_menu(&resource.keep_flag, Act_set_keep_flag, check_toggle);
+ shrinkval = resource.pixels_per_inch / mane.shrinkfactor;
+ set_menu(&shrinkval, Act_shrink_to_dpi, check_int);
+ set_menu(&mane.shrinkfactor, Act_set_shrink_factor, check_int);
+ set_menu(&resource.use_tex_pages, Act_use_tex_pages, check_toggle);
+ set_menu((char *)resource.paper, Act_set_paper_landscape, check_paper_landscape);
+ set_menu((char *)resource.paper, Act_set_papersize, check_papersize);
+ set_menu(&resource.mouse_mode, Act_switch_mode, check_int);
+ set_menu(&resource.expert_mode, Act_set_expert_mode, check_resource_expert);
+}
+
+static void
+free_items(char **items, size_t len)
+{
+ size_t curr = 0;
+ while(curr < len) {
+ free(items[curr++]);
+ }
+ free(items);
+}
+
+#if 0
+static void
+show_items(char *descr, char **items, size_t len)
+{
+ size_t i;
+ for (i = 0; i < len; i++) {
+ fprintf(stderr, "%s %d: |%s|\n", descr, i, items[i]);
+ }
+}
+#endif
+
+static void
+add_info(struct button_info **info, buttonTypeT bt_type,
+ char mnemonic, const char *title,
+ const char *accelerator, struct xdvi_action *action)
+{
+/* fprintf(stderr, "creating new item for info %p: |%s|\n", *info, title); */
+ size_t idx = (*info)->size++;
+ (*info)->elems = xrealloc((*info)->elems, (*info)->size * sizeof *((*info)->elems));
+ (*info)->elems[idx].title = xstrdup(title);
+ (*info)->elems[idx].type = bt_type;
+ if (accelerator == NULL || accelerator[0] == '\0')
+ (*info)->elems[idx].accelerator = NULL;
+ else
+ (*info)->elems[idx].accelerator = xstrdup(accelerator);
+ (*info)->elems[idx].mnemonic = mnemonic;
+ (*info)->elems[idx].action = action;
+ (*info)->elems[idx].widget = 0;
+ (*info)->elems[idx].submenu = NULL;
+}
+
+static void
+insert_items(struct button_info **info, char **items, size_t num_items,
+ const char *button_type, const char *accelerator, const char *action)
+{
+ const char ENTRY_SEP = '|';
+ size_t i = 0;
+ size_t entry_len;
+ size_t entry_count = 0;
+ char **entry_items = NULL;
+ size_t idx;
+
+ Boolean found = False;
+ Boolean have_error = False;
+
+/* fprintf(stderr, "------ insert_items called for |%s|, %p, |%s|\n", *items, *info, action); */
+
+ if (*items == NULL) {
+ /* should be a separator, which is treated as a special case since
+ there's no menu title: */
+ if (strcmp (button_type, "SEP") == 0)
+ add_info(info, BT_SEP, '\0', "SEP", NULL, NULL);
+ else
+ XDVI_WARNING((stderr, "Shouldn't happen: items == NULL!"));
+ return;
+ }
+
+ entry_len = strlen(items[0]);
+ entry_items = split_line(items[0], ENTRY_SEP, 0, entry_len, &entry_count);
+
+ if (entry_count < 2) {
+ XDVI_WARNING((stderr, "Missing Mnemonic in button info `%s'\n", items[0]));
+ entry_count++;
+ entry_items = xrealloc(entry_items, entry_count * sizeof *entry_items);
+ entry_items[1] = xstrdup("");
+ entry_items[2] = NULL;
+ }
+
+ for (i = 0; i < (*info)->size; i++) {
+ if (strcmp(entry_items[0], (*info)->elems[i].title) == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ idx = i;
+
+ if (!found) { /* new item, resize info and add this item */
+ struct xdvi_action *my_action = NULL;
+ buttonTypeT my_type = BT_NONE;
+
+ /* if it's a `leaf' in the menu hierarchy, compile the action and set the button type */
+ if (num_items == 1) {
+/* fprintf(stderr, "button_type: |%s|\n", button_type); */
+
+ char *fmt = strchr(entry_items[0], '$');
+ if (fmt != NULL
+ && (fmt == entry_items[0] || (fmt > entry_items[0] && *(fmt - 1) != '\\'))
+ && (fmt[1] == '#' || fmt[1] == '%' ||fmt[1] == '_')) {
+ XDVI_WARNING((stderr, "Xdvik doesn't support format characters in button labels; "
+ "skipping button \"%s\"", items[0]));
+ have_error = True;
+ }
+
+ if (strlen(action) == 0
+ || (my_action = compile_action(action)) == NULL) {
+ XDVI_WARNING((stderr, "Invalid action \"%s\" for button \"%s\" (skipping this line).",
+ action, items[0]));
+ have_error = True;
+ }
+
+ if ((my_type = get_type(button_type)) == BT_INVALID) {
+ XDVI_WARNING((stderr, "Invalid type \"%s\" for button \"%s\" (skipping this line).",
+ button_type, items[0]));
+ have_error = True;
+ }
+ }
+
+ if (!have_error) {
+ add_info(info, my_type, entry_items[1][0], entry_items[0], accelerator, my_action);
+ }
+ }
+ free_items(entry_items, entry_count);
+
+ if (num_items > 1 || (num_items == 1 && strcmp(button_type, "SEP") == 0)) { /* not a leaf, invoke recursivly for next level */
+/* fprintf(stderr, "invoking recursively for %d, %p\n", idx, (*info)->elems[idx].submenu); */
+ if ((*info)->elems[idx].submenu == NULL) { /* submenu didn't exist yet, create it */
+ struct button_info *new_submenu = xmalloc(sizeof *new_submenu);
+ new_submenu->elems = NULL;
+ new_submenu->size = 0;
+ (*info)->elems[idx].submenu = new_submenu;
+ }
+ insert_items(&((*info)->elems[idx].submenu), items + 1, num_items - 1, button_type, accelerator, action);
+ }
+}
+
+static void
+show_button_info(int depth, struct button_info *info)
+{
+ size_t i;
+ for (i = 0; i < info->size; i++) {
+ TRACE_GUI((stderr, "%*c-->%s; type=%d; mnemonic=%c; accel=%s; submenu=%p; w=%lu; action: %p",
+ depth, ' ',
+ info->elems[i].title,
+ info->elems[i].type,
+ info->elems[i].mnemonic,
+ info->elems[i].accelerator ? info->elems[i].accelerator : "<NULL>",
+ (void *)info->elems[i].submenu,
+ (unsigned long)info->elems[i].widget,
+ (void *)info->elems[i].action));
+ if (info->elems[i].submenu != NULL) {
+ show_button_info(depth + 3, info->elems[i].submenu);
+ }
+ }
+}
+
+static void
+parse_button_translations(struct button_info **info)
+{
+ const char *curr_p, *end_p;
+
+ const char LINE_SEP = ':';
+ const char MENU_SEP = '>';
+
+ for (curr_p = resource.menu_translations;
+ curr_p != NULL && *curr_p != '\0';
+ curr_p = end_p + 1) {
+ end_p = strchr(curr_p, '\n');
+ if (end_p != NULL) {
+ size_t line_len = end_p - curr_p;
+ size_t line_count = 0;
+ char **line_items;
+ line_items = split_line(curr_p, LINE_SEP, 0, line_len, &line_count);
+/* fprintf(stderr, "length of line: %d; %d items\n", line_len, line_count); */
+/* show_items("LINE", line_items, line_count); */
+ if (line_count != 4) { /* error */
+ XDVI_WARNING((stderr, "Wrong number of items (%lu) in translations line:\n\"%.*s\" "
+ "(skipping this line).\n",
+ (unsigned long)line_count, (int)line_len, curr_p));
+ free_items(line_items, line_count);
+ continue;
+ }
+ else { /* split first elem into menu description */
+ size_t menu_len = strlen(line_items[0]);
+ size_t menu_count = 0;
+ char **menu_items;
+ if (menu_len == 0) { /* error */
+ XDVI_WARNING((stderr, "Menu description (1st item) mustn't be empty:\n\"%.*s\" "
+ "(skipping this line).\n",
+ (int)line_len, curr_p));
+ free_items(line_items, line_count);
+ continue;
+ }
+ menu_items = split_line(line_items[0], MENU_SEP, 0, menu_len, &menu_count);
+/* show_items(" MENU", menu_items, menu_count); */
+
+ insert_items(info, menu_items, menu_count, line_items[1], line_items[2], line_items[3]);
+ free_items(menu_items, menu_count);
+ }
+ free_items(line_items, line_count);
+ }
+ }
+ show_button_info(0, *info);
+}
+
+/*
+ Top-level routine: creates the pulldown menu buttons for Motif and Xaw.
+ For Motif, sets *globals.widgets.menu_bar to the address of the new widget created,
+ for Xaw, sets *width to the width of the button panel created.
+*/
+void
+create_menu_buttons(Widget parent,
+#ifdef MOTIF
+ Widget *menu_bar
+#else
+ int *width
+#endif
+ )
+{
+#ifdef MOTIF
+ Widget menu = 0;
+#else /* MOTIF */
+ Widget panel = 0;
+ Boolean first_time = True;
+ int menu_depth = 0;
+#endif
+ size_t i;
+
+ m_button_info = xmalloc(sizeof *m_button_info);
+ m_button_info->elems = NULL;
+ m_button_info->size = 0;
+
+#ifdef MOTIF
+ *menu_bar = XmCreateMenuBar(parent, "menuBar", NULL, 0);
+ parse_button_translations(&m_button_info);
+/* menu = xm_create_menu(*menu_bar, m_button_info); */
+ for (i = 0; i < m_button_info->size; i++) {
+ menu = xm_create_menu(*menu_bar,
+ m_button_info->elems[i].title,
+ m_button_info->elems[i].mnemonic,
+ m_button_info->elems[i].submenu);
+ }
+ if (menu != 0) {
+ XtVaSetValues(*menu_bar, XmNmenuHelpWidget, menu, NULL);
+ }
+#else /* MOTIF */
+ if (first_time) {
+ first_time = False;
+ xaw_initialize_menu_bitmaps();
+ panel = xaw_create_menu_widgets(parent);
+ parse_button_translations(&m_button_info);
+ }
+ xaw_create_menu(m_button_info, panel, menu_depth, width);
+#endif /* MOTIF */
+ initialize_menus();
+}
+#endif /* NEW_MENU_CREATION || MOTIF */
diff --git a/Build/source/texk/xdvik/gui/menu.h b/Build/source/texk/xdvik/gui/menu.h
new file mode 100644
index 00000000000..3c5f4487f1f
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/menu.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2003-2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Common code for Xaw and Motif menu bar creation.
+ */
+#ifndef MENU_H_
+#define MENU_H_
+
+#include "xdvi-config.h"
+#include "events.h"
+#include "xdvi.h"
+
+typedef enum {
+ BT_INVALID = -1, /* error code */
+ BT_NONE = 0,
+ BT_PUSH, /* pushbutton */
+ BT_RADIO, /* radio button (1 of n) */
+ BT_CHECK, /* check button (m of n) */
+ BT_SEP /* separator */
+} buttonTypeT;
+
+
+/* structures for menu data */
+struct button_elems {
+ char *title; /* menu item label string */
+ buttonTypeT type; /* button type */
+ char mnemonic; /* 0 if none */
+ char *accelerator; /* NULL if none */
+ struct button_info *submenu;/* submenu, or NULL */
+ Widget widget; /* the widget in this item, for later use, or 0 */
+ struct xdvi_action *action; /* translated action, for later use, or NULL */
+};
+
+struct button_info {
+ size_t size;
+ struct button_elems *elems;
+};
+
+#include "xm_menu.h"
+#include "xaw_menu.h"
+
+extern void create_menu_buttons(Widget parent,
+#ifdef MOTIF
+ Widget *child
+#else
+ int *ret_panel_width
+#endif
+ );
+
+extern void set_menu(void *val, XtActionProc proc, Boolean (*cmp)());
+
+#endif /* MENU_H_ */
diff --git a/Build/source/texk/xdvik/gui/message-window.c b/Build/source/texk/xdvik/gui/message-window.c
new file mode 100644
index 00000000000..55e148daa1b
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/message-window.c
@@ -0,0 +1,1207 @@
+/*------------------------------------------------------------
+message-window.c: message popups for xdvi.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+------------------------------------------------------------*/
+
+
+
+/*
+
+============================================
+Suggested Policy for using the GUI messages:
+============================================
+
+- Use the statusline for shorter messages, a message window for more
+ important messages or such where you'd like to give further help info
+ (see the `helptext' argument of popup_message()). When in doubt,
+ prefer the statusline (excessive use of popup windows is a nuisance
+ for the user).
+
+- Don't use any of the GUI messages to report internal workings of
+ the program; for important internal information, there should be a
+ debugging setting to print it to stderr. Use the GUI messages
+ only in situations such as the following:
+
+ - to give the user feedback on actions that (s)he initiated
+
+ - to indicate that an internal action causes a delay perceptible
+ by the user (as a rough guide: a delay of more than half a second)
+
+ - to report situations that might require new actions by the user.
+
+*/
+
+#include <ctype.h>
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "string-utils.h"
+
+/* Xaw specific stuff */
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#ifdef MOTIF
+# include <Xm/DialogS.h>
+# include <Xm/MessageB.h>
+# include <Xm/PushB.h>
+# include <Xm/Label.h>
+# include <Xm/Form.h>
+# include <Xm/MenuShell.h>
+# include <Xm/Protocols.h>
+# include <Xm/AtomMgr.h>
+#else
+# include <X11/Xaw/Paned.h>
+# include <X11/Xaw/Box.h>
+# include <X11/Xaw/MenuButton.h>
+# include <X11/Xaw/SimpleMenu.h>
+# include <X11/Xaw/Sme.h>
+# include <X11/Xaw/SmeBSB.h>
+# include <X11/Xaw/AsciiText.h>
+# include <X11/Xaw/Dialog.h>
+#endif
+
+#include "kpathsea/c-vararg.h"
+#include "xdvi.h"
+#include "util.h"
+#include "string-utils.h"
+#include "x_util.h"
+#include "message-window.h"
+
+/* have no more than MAX_POPUPS open simultaneously */
+#define MAX_POPUPS 10
+
+/* offset for cascading popups */
+#define POPUP_OFFSET ((my_popup_num * 20))
+
+#ifdef MOTIF
+/* wrap messages after MSG_WRAP_LEN characters at whitespace */
+#define MSG_WRAP_LEN 60
+#endif
+
+/* array of active popups: */
+static int g_popup_array[MAX_POPUPS];
+
+static Atom WM_DELETE_WINDOW;
+
+/* arrays for saving the widgets of multiple popups;
+ * same index as in g_popup_array:
+ */
+#ifdef MOTIF
+static Widget popup_window[MAX_POPUPS], dialog[MAX_POPUPS];
+#else
+static Widget popup_window[MAX_POPUPS], message_box[MAX_POPUPS],
+ message_text[MAX_POPUPS], message_paned[MAX_POPUPS],
+ message_ok[MAX_POPUPS], message_help[MAX_POPUPS], message_not_ok[MAX_POPUPS];
+#endif
+
+/* map popupMessageT's to strings/motif dialog elements */
+static struct message_map {
+ char *window_title;
+#ifdef MOTIF
+ int motif_msg_type;
+#endif
+} my_msg_map[] = {
+ { "Xdvi Question"
+#ifdef MOTIF
+ , XmDIALOG_QUESTION
+#endif
+ }, /* MSG_QUESTION */
+ { "Xdvi Help"
+#ifdef MOTIF
+ , XmDIALOG_INFORMATION
+#endif
+ }, /* MSG_HELP */
+ { "Xdvi Info"
+#ifdef MOTIF
+ , XmDIALOG_INFORMATION
+#endif
+ }, /* MSG_INFO */
+ { "Xdvi Warning"
+#ifdef MOTIF
+ , XmDIALOG_WARNING
+#endif
+ }, /* MSG_WARN */
+ { "Xdvi Error"
+#ifdef MOTIF
+ , XmDIALOG_ERROR
+#endif
+ }, /* MSG_ERR */
+};
+
+struct ok_or_cancel_cb {
+ message_cbT callback; /* callback function */
+ XtPointer arg; /* arg for callback function */
+};
+
+struct pre_ok_or_cancel_cb {
+ pre_message_cbT callback; /* callback function */
+ XtPointer arg; /* arg for callback function */
+};
+
+static struct ok_or_cancel_cb yes_callbacks[MAX_POPUPS];
+static struct ok_or_cancel_cb no_callbacks[MAX_POPUPS];
+static struct ok_or_cancel_cb cancel_callbacks[MAX_POPUPS];
+static struct pre_ok_or_cancel_cb pre_callbacks[MAX_POPUPS];
+
+
+static void
+popdown_cancel(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ size_t idx;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ ASSERT(*num_params == 1, "Wrong number of parameters in callback");
+ idx = strtoul(*params, (char **)NULL, 10);
+
+ /* First call pre_message_cb with window widget ID
+ * as additional parameter.
+ */
+ if (pre_callbacks[idx].callback != NULL) {
+ pre_callbacks[idx].callback(popup_window[idx], pre_callbacks[idx].arg);
+ }
+
+ /* Then pop down window and mark its position as free, then
+ * invoke the OK callback. The reason for this is that the callback
+ * may need to wait for open windows.
+ */
+ XtPopdown(popup_window[idx]);
+ XtDestroyWidget(popup_window[idx]);
+ g_popup_array[idx] = 0;
+ XSync(DISP, True);
+
+ /* invoke the callback if present */
+ if (cancel_callbacks[idx].callback != NULL) {
+ cancel_callbacks[idx].callback(cancel_callbacks[idx].arg);
+ }
+}
+
+#ifndef MOTIF
+static void
+xaw_popdown(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ size_t idx;
+
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ ASSERT(*num_params == 1, "Wrong number of parameters in callback");
+ idx = strtoul(*params, (char **)NULL, 10);
+
+ /*
+ NOTE: first pop down window and mark its position as free, then
+ invoke the callback. The reason for this is that the callback
+ may need to wait for open windows.
+ */
+ XtPopdown(popup_window[idx]);
+ XtDestroyWidget(popup_window[idx]);
+ g_popup_array[idx] = 0;
+ XSync(DISP, True);
+}
+
+#endif
+
+static XtActionsRec popdown_actions[] = {
+ {"close-popup-cancel", popdown_cancel },
+#if !MOTIF
+ {"WM_popdown", popdown_cancel },
+ {"close-popup", xaw_popdown },
+#endif
+};
+
+static void
+ok_action(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ int idx = -1;
+
+ UNUSED(call_data);
+
+#if MOTIF
+ UNUSED(client_data);
+ XtVaGetValues(w, XmNuserData, &idx, NULL);
+ ASSERT(idx >= 0, "Couldn't get idx from XmNuserData!");
+#else
+ UNUSED(w);
+ idx = (int)client_data;
+#endif
+
+#if DEBUG
+ fprintf(stderr, "quit_action called for popup %d\n", idx);
+#endif
+ ASSERT(idx >= 0 && idx < MAX_POPUPS, "Invalid widget index in ok_action()");
+
+ /* First call pre_message_cb with window widget ID
+ * as additional parameter.
+ */
+ if (pre_callbacks[idx].callback != NULL) {
+ pre_callbacks[idx].callback(popup_window[idx], pre_callbacks[idx].arg);
+ }
+
+ /* Then pop down window and mark its position as free, then
+ * invoke the OK callback. The reason for this is that the callback
+ * may need to wait for open windows.
+ */
+ XtPopdown(popup_window[idx]);
+ XtDestroyWidget(popup_window[idx]);
+ g_popup_array[idx] = 0;
+ XSync(DISP, True);
+
+ if (yes_callbacks[idx].callback != NULL) {
+ yes_callbacks[idx].callback(yes_callbacks[idx].arg);
+ }
+}
+
+/*------------------------------------------------------------
+ * help_action
+ *
+ * Arguments:
+ * Widget w, XtPointer call_data
+ * - (ignored)
+ * XtPointer client_data
+ * - the help string
+ *
+ * Returns:
+ * void
+ *
+ * Purpose:
+ * Callback for the `Help' button; opens another window
+ * containing the help text. The new window won't have
+ * another `Help' button.
+ *------------------------------------------------------------*/
+
+static void
+help_action(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ UNUSED(call_data);
+
+ /* open another window with the help text */
+ popup_message(get_matching_parent(w, globals.widgets.top_level, "message_popup", NULL), MSG_HELP, NULL, client_data);
+}
+
+
+/*
+ * Callback for cancel button in choice_dialog.
+*/
+static void
+cancel_action(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ int idx = -1;
+
+ UNUSED(call_data);
+
+#if MOTIF
+ /* for motif, the index is in XmNuserData */
+ UNUSED(client_data);
+ if (strcmp(XtName(w), Xdvi_MESSAGE_SHELL_NAME) == 0) {
+ /* invoked by the WM, get the messagebox child */
+ Widget child;
+ if (get_widget_by_name(&child, w, Xdvi_MESSAGE_DIALOG_NAME, True)) {
+ XtVaGetValues(child, XmNuserData, &idx, NULL);
+ }
+ }
+ else {
+ XtVaGetValues(w, XmNuserData, &idx, NULL);
+ }
+ ASSERT(idx >= 0, "Couldn't get idx from XmNuserData!");
+#else
+ UNUSED(w);
+ idx = (int)client_data;
+#endif
+ ASSERT(idx >= 0 && idx < MAX_POPUPS, "Invalid widget index in cancel_action()");
+
+ /* First call pre_message_cb with window widget ID
+ * as additional parameter.
+ */
+ if (pre_callbacks[idx].callback != NULL) {
+ pre_callbacks[idx].callback(popup_window[idx], pre_callbacks[idx].arg);
+ }
+
+ /* Then pop down window and mark its position as free, then
+ * invoke the OK callback. The reason for this is that the callback
+ * may need to wait for open windows.
+ */
+ XtPopdown(popup_window[idx]);
+ XtDestroyWidget(popup_window[idx]);
+ g_popup_array[idx] = 0;
+ XSync(DISP, True);
+
+ /* invoke the callback if present */
+ if (cancel_callbacks[idx].callback != NULL) {
+ cancel_callbacks[idx].callback(cancel_callbacks[idx].arg);
+ }
+}
+
+#if MOTIF
+static void
+not_ok_action(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ /* Note: unmanage the parent of the button */
+ int idx = -1;
+
+ UNUSED(client_data);
+
+ UNUSED(call_data);
+ XtVaGetValues(w, XmNuserData, &idx, NULL);
+ ASSERT(idx >= 0, "Couldn't get idx from XmNuserData!");
+ ASSERT(idx >= 0 && idx < MAX_POPUPS, "Invalid widget index in ok_action()");
+
+ /* First call pre_message_cb with window widget ID
+ * as additional parameter.
+ */
+ if (pre_callbacks[idx].callback != NULL) {
+ pre_callbacks[idx].callback(popup_window[idx], pre_callbacks[idx].arg);
+ }
+
+ /* Then pop down window and mark its position as free, then
+ * invoke the OK callback. The reason for this is that the callback
+ * may need to wait for open windows.
+ */
+ XtPopdown(popup_window[idx]);
+ XtDestroyWidget(popup_window[idx]);
+ g_popup_array[idx] = 0;
+ XSync(DISP, True);
+
+ if (no_callbacks[idx].callback != NULL) {
+ no_callbacks[idx].callback(no_callbacks[idx].arg);
+ }
+}
+#endif /* MOTIF */
+
+/*------------------------------------------------------------
+ * create_dialogs
+ *
+ * Arguments:
+ * Widget toplevel - parent for the dialog window
+ *
+ * helptext - if not-NULL, create an additional
+ * `help' button
+ *
+ * cnt - number of current popup dialog
+ *
+ * Returns:
+ * void
+ *
+ * Purpose:
+ * Create message dialog widgets
+ *------------------------------------------------------------*/
+
+static Widget
+create_dialogs(popupMessageSizeHintT size,
+ Widget parent,
+ int cnt,
+ const char *helptext,
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *yes_button, message_cbT yes_cb, XtPointer yes_arg,
+ const char *no_button, message_cbT no_cb, XtPointer no_arg,
+ const char *cancel_button, message_cbT cancel_cb, XtPointer cancel_arg)
+{
+ Widget new_popup_window;
+ char *translations_str = NULL;
+#ifdef MOTIF
+ Widget new_dialog;
+ UNUSED(size);
+#else
+ char *key_translations_str = NULL;
+ int msg_w = 400, msg_h = 100;
+ Widget new_message_paned, new_message_text, new_message_box, new_message_ok,
+ new_message_help = 0, new_message_not_ok;
+ XtTranslations wm_translations, key_translations;
+#endif
+
+ /* save callbacks to global arrays */
+ pre_callbacks[cnt].callback = pre_cb;
+ pre_callbacks[cnt].arg = arg;
+
+ yes_callbacks[cnt].callback = yes_cb;
+ yes_callbacks[cnt].arg = yes_arg;
+
+ no_callbacks[cnt].callback = no_cb;
+ no_callbacks[cnt].arg = no_arg;
+
+ cancel_callbacks[cnt].callback = cancel_cb;
+ cancel_callbacks[cnt].arg = cancel_arg;
+
+ XtAddActions(popdown_actions, XtNumber(popdown_actions));
+
+#ifndef MOTIF
+ /* get index into WM_popdown arg */
+ translations_str = get_string_va("<Message>WM_PROTOCOLS: WM_popdown(%d)", cnt);
+ wm_translations = XtParseTranslationTable(translations_str);
+ free(translations_str);
+#endif
+
+ if (!XtIsRealized(globals.widgets.top_level)) {
+ /* If toplevel window hasn't been realized yet, create a new toplevel shell
+ (otherwise, setting visual/color map wouldn't work); use same application names
+ so that resource settings will also apply to this window.
+ */
+ new_popup_window = XtVaAppCreateShell("xdvi", "Xdvi",
+ transientShellWidgetClass, DISP,
+ NULL);
+ }
+ else {
+ new_popup_window = XtVaCreatePopupShell(Xdvi_MESSAGE_SHELL_NAME,
+#ifdef MOTIF
+ xmDialogShellWidgetClass, parent,
+ XmNdeleteResponse, XmDO_NOTHING, /* we'll take care of that ourselves */
+#else
+ transientShellWidgetClass, parent,
+ XtNx, 60,
+ XtNy, 80,
+ XtNtranslations, wm_translations,
+ XtNaccelerators, G_accels_cr,
+#endif
+ XtNtransientFor, parent,
+ XtNmappedWhenManaged, False,
+ NULL);
+ }
+
+#ifdef MOTIF
+
+ WM_DELETE_WINDOW = XmInternAtom(XtDisplay(new_popup_window), "WM_DELETE_WINDOW", False);
+ XmAddWMProtocolCallback(new_popup_window, WM_DELETE_WINDOW, cancel_action, NULL);
+
+ /* We also need to override the default ESC binding to use our internal
+ housekeeping functions */
+ translations_str = get_string_va("#override\n<Key>osfCancel:close-popup-cancel(%d)", cnt);
+/* { */
+/* XtTranslations xlats; */
+/* char *translation_str = get_string_va("<Key>osfCancel:close-popup-cancel(%d)", cnt); */
+/* xlats = XtParseTranslationTable(translation_str); */
+/* free(translation_str); */
+/* XtOverrideTranslations(new_dialog, xlats); */
+/* } */
+
+ new_dialog = XtVaCreateWidget(Xdvi_MESSAGE_DIALOG_NAME, xmMessageBoxWidgetClass, new_popup_window,
+ XmNdialogType, XmDIALOG_WARNING, /* default */
+ XmNtraversalOn, True,
+ XmNhighlightOnEnter, True,
+ XmNuserData, cnt,
+ XmNtranslations, XtParseTranslationTable(translations_str),
+ NULL);
+ free(translations_str);
+ XtAddCallback(new_dialog, XmNokCallback, ok_action, NULL);
+
+ if (no_button != NULL) {
+ Arg args[4];
+ Widget b;
+ XmString b_str = XmStringCreateLocalized((char *)no_button);
+ XtSetArg(args[0], XmNlabelString, b_str);
+ b = XmCreatePushButton(new_dialog, "no_button", args, 1);
+ XtAddCallback(b, XmNactivateCallback, not_ok_action, NULL);
+ XtManageChild(b);
+ }
+
+ if (cancel_button != NULL) {
+ XmString cancel_label = XmStringCreateLtoR((char *)cancel_button, G_charset);
+ XtVaSetValues(XmMessageBoxGetChild(new_dialog, XmDIALOG_CANCEL_BUTTON),
+ XmNlabelString, cancel_label, NULL);
+ XmStringFree(cancel_label);
+ XtAddCallback(new_dialog, XmNcancelCallback, cancel_action, NULL);
+ }
+ else {
+ XtUnmanageChild(XmMessageBoxGetChild(new_dialog, XmDIALOG_CANCEL_BUTTON));
+ }
+ XtInstallAllAccelerators(new_dialog,
+ XmMessageBoxGetChild(new_dialog, XmDIALOG_OK_BUTTON));
+
+ if (helptext != NULL) {
+ XtAddCallback(new_dialog, XmNhelpCallback, help_action, (XtPointer)helptext);
+ }
+ else {
+ XtUnmanageChild(XmMessageBoxGetChild(new_dialog, XmDIALOG_HELP_BUTTON));
+ }
+
+ if (yes_button != NULL) { /* change `OK' button label */
+ XmString yes_label;
+ yes_label = XmStringCreateLtoR((char *)yes_button, G_charset);
+ XtVaSetValues(XmMessageBoxGetChild(new_dialog, XmDIALOG_OK_BUTTON),
+ XmNlabelString, yes_label, NULL);
+ XmStringFree(yes_label);
+ }
+
+ /* insert the new widgets into the global arrays */
+ dialog[cnt] = new_dialog;
+
+#else /* MOTIF */
+ switch (size) {
+ case SIZE_SMALL:
+ msg_w = 300;
+ msg_h = 100;
+ break;
+ case SIZE_MEDIUM:
+ msg_w = 430;
+ msg_h = 160;
+ break;
+ case SIZE_LARGE:
+ msg_w = 450;
+ msg_h = 180;
+ break;
+ }
+ WM_DELETE_WINDOW = XInternAtom(XtDisplay(new_popup_window), "WM_DELETE_WINDOW", False);
+
+ new_message_paned = XtVaCreateManagedWidget("message_paned", panedWidgetClass, new_popup_window,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+
+ new_message_text = XtVaCreateManagedWidget("message_text", asciiTextWidgetClass, new_message_paned,
+/* XtNheight, 100, */
+/* XtNwidth, 400, */
+ XtNwidth, msg_w,
+ XtNheight, msg_h,
+ /* wrap horizontally instead of scrolling
+ * TODO: this won't work for the first widget instance?
+ */
+ XtNwrap, XawtextWrapWord,
+ XtNscrollVertical, XAW_SCROLL_ALWAYS,
+ XtNeditType, XawtextRead,
+ XtNinput, True,
+ XtNdisplayCaret, False,
+ XtNleftMargin, 5,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+
+ /* box for the OK/Cancel button */
+ new_message_box = XtVaCreateManagedWidget("message_box", formWidgetClass, new_message_paned,
+ /* resizing by user isn't needed */
+ XtNshowGrip, False,
+ XtNdefaultDistance, 6, /* some padding */
+ /* resizing the window shouldn't influence this box,
+ * but only the text widget
+ */
+ XtNskipAdjust, True,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+
+ new_message_ok = XtVaCreateManagedWidget(yes_button == NULL ? "OK" : yes_button,
+ commandWidgetClass, new_message_box,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainBottom,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+ /* add quit_action callback for the "OK" button */
+ /* FIXME: how to make accelerators be accepted by new_popup_window as well? */
+ key_translations_str = get_string_va("<Key>q:close-popup-cancel(%d)\n"
+ "<Key>Return:close-popup-cancel(%d)\n"
+ "<Key>Escape:close-popup-cancel(%d)\n",
+ cnt, cnt, cnt);
+ key_translations = XtParseTranslationTable(key_translations_str);
+ free(key_translations_str);
+ XtOverrideTranslations(new_popup_window, key_translations);
+ XtOverrideTranslations(new_message_paned, key_translations);
+ XtOverrideTranslations(new_message_text, key_translations);
+
+ XtInstallAllAccelerators(new_message_box, new_message_ok);
+ XtAddCallback(new_message_ok, XtNcallback, ok_action, (XtPointer)cnt);
+
+ /* we create additional buttons in any case,
+ to make the sizing more consistent */
+ new_message_help = XtVaCreateManagedWidget("Help", commandWidgetClass, new_message_box,
+ XtNtop, XtChainTop,
+ XtNfromHoriz, new_message_ok,
+ XtNbottom, XtChainBottom,
+ XtNleft, XtChainRight,
+ XtNright, XtChainRight,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+ message_help[cnt] = new_message_help;
+
+ /* add cancel button */
+ new_message_not_ok = XtVaCreateManagedWidget(cancel_button == NULL ? "Cancel" : cancel_button,
+ commandWidgetClass, new_message_box,
+ XtNtop, XtChainTop,
+ XtNfromHoriz, new_message_ok,
+ XtNbottom, XtChainBottom,
+ XtNleft, helptext == NULL ? XtChainRight : XtChainLeft,
+ XtNright, helptext == NULL ? XtChainRight : XtChainLeft,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+ message_not_ok[cnt] = new_message_not_ok;
+
+ if (no_button != NULL) {
+ ASSERT(0, "third button not yet implemented in Xaw!!!");
+ }
+
+
+ { /* set all buttons to same size */
+ Dimension w1, w2, w3, max;
+ XtVaGetValues(new_message_ok, XtNwidth, &w1, NULL);
+ XtVaGetValues(new_message_help, XtNwidth, &w2, NULL);
+ XtVaGetValues(new_message_not_ok, XtNwidth, &w3, NULL);
+ max = w1;
+ if (w2 > max)
+ max = w2;
+ if (w3 > max)
+ max = w3;
+ XtVaSetValues(new_message_ok, XtNwidth, max, NULL);
+ XtVaSetValues(new_message_help, XtNwidth, max, NULL);
+ XtVaSetValues(new_message_not_ok, XtNwidth, max, NULL);
+ }
+ /* if helptext argument is not-NULL, add help_action callback,
+ else unmanage help button */
+ if (helptext != NULL) {
+ XtAddCallback(new_message_help, XtNcallback, help_action, (XtPointer)helptext);
+ }
+ else {
+ XtUnmanageChild(new_message_help);
+ }
+
+ if (cancel_button != NULL) {
+ XtAddCallback(new_message_not_ok, XtNcallback, cancel_action, (XtPointer)cnt);
+ }
+ else {
+ XtUnmanageChild(new_message_not_ok);
+ }
+ /* insert the new widgets into the global arrays */
+ message_box[cnt] = new_message_box;
+ message_paned[cnt] = new_message_paned;
+ message_text[cnt] = new_message_text;
+ message_ok[cnt] = new_message_ok;
+
+#endif /* MOTIF */
+ popup_window[cnt] = new_popup_window;
+
+ return new_popup_window;
+}
+
+
+/*
+ * Popup a window with wrapped text in it.
+ * For Motif, the text is explicitly wrapped inside this method.
+ */
+static Widget
+internal_popup_window(Widget parent,
+ popupMessageSizeHintT size,
+ popupMessageT type,
+ int x_coord, int y_coord,
+ const char *helptext,
+ char *msg_buf,
+#ifndef MOTIF
+ const char *xaw_ret_action_str,
+#endif
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *yes_button, message_cbT yes_cb, XtPointer yes_arg,
+ const char *no_button, message_cbT no_cb, XtPointer no_arg,
+ const char *cancel_button, message_cbT cancel_cb, XtPointer cancel_arg)
+{
+ char win_title[64];
+ int my_popup_num = 0;
+#ifdef MOTIF
+ XmString str;
+#endif
+ Widget ret;
+
+ ASSERT(type < (sizeof my_msg_map / sizeof my_msg_map[0]), "too few elements in my_msg_map");
+ sprintf(win_title, my_msg_map[type].window_title);
+
+#if DEBUG
+ fprintf(stderr, "internal_popup_window called with prompt: \"%s\"\n", msg_buf);
+#endif
+
+ if (globals.widgets.top_level == 0) {
+ /* If toplevel window hasn't been create yet, dump messages to STDERR and return.
+ All text must be passed as arguments to fprintf (NOT puts), since they are
+ supposed to be printf-format strings (i.e. with doubled `%' to escape them)
+ */
+ fprintf(stderr, "\n%s:\n", my_msg_map[type].window_title);
+ fprintf(stderr, msg_buf);
+ fprintf(stderr, "\n");
+ if (helptext) {
+ fprintf(stderr, "---------- helptext ----------\n");
+ fprintf(stderr, helptext);
+ fprintf(stderr, "\n---------- end of helptext ----------\n");
+ }
+ return NULL;
+ }
+ /* search for first free position in g_popup_array */
+ while (my_popup_num < MAX_POPUPS && (g_popup_array[my_popup_num] == 1)) {
+ my_popup_num++;
+ }
+ if (my_popup_num == MAX_POPUPS) {
+ /* already enough popups on screen, just dump it to stderr */
+ fprintf(stderr, "%s:\n", win_title);
+ fprintf(stderr, msg_buf);
+ /* Note: If a mad function continues to open popups, this will
+ * stop after MAX_POPUPS, but open a new window for each
+ * window the user pops down. Maybe we ought to do something
+ * about this.
+ */
+ return NULL;
+ }
+ else {
+ /* mark it as non-free */
+ g_popup_array[my_popup_num] = 1;
+ }
+#if DEBUG
+ fprintf(stderr, "first free position in g_popup_array: %d\n", my_popup_num);
+#endif
+
+ /* just to make sure ... */
+ if (parent == NULL)
+ parent = globals.widgets.top_level;
+
+ /* create a new set of widgets for the additional popup. */
+ ret = create_dialogs(size, parent,
+ my_popup_num,
+ helptext,
+ pre_cb, arg,
+ yes_button, yes_cb, yes_arg,
+ no_button, no_cb, no_arg,
+ cancel_button, cancel_cb, cancel_arg);
+#ifdef MOTIF
+ XtVaSetValues(popup_window[my_popup_num], XmNtitle, win_title, NULL);
+ XtVaSetValues(dialog[my_popup_num], XmNdialogType, my_msg_map[type].motif_msg_type, NULL);
+ { /* wrap message at space before MSG_WRAP_LEN */
+ char *testwrap = msg_buf;
+ int ctr;
+ for (ctr = 0; *testwrap++; ctr++) {
+ if (*testwrap == '\n') {
+ ctr = 0;
+ }
+ else if (ctr > MSG_WRAP_LEN) {
+ size_t before_len = 0, after_len = 0;
+ char *before_ptr, *after_ptr;
+ before_ptr = after_ptr = testwrap;
+ /* try to find shortest sequence before or after point to wrap at;
+ this seems to give the most pleasing results.
+ */
+ while (before_ptr > msg_buf && !isspace((int)*--before_ptr)) {
+ before_len++;
+ }
+ while (*after_ptr != '\0' && !isspace((int)*++after_ptr)) {
+ after_len++;
+ }
+
+ if (before_len < after_len && isspace((int)*before_ptr)) {
+ /* use last in sequence of multiple spaces */
+ while (isspace((int)*++before_ptr)) { ; }
+ /* back up, and wrap */
+ *--before_ptr = '\n';
+ ctr = 0;
+ }
+ else if (isspace((int)*after_ptr)) {
+ /* use last in sequence of multiple spaces */
+ while (isspace((int)*++after_ptr)) { ; }
+ /* back up, and wrap */
+ *--after_ptr = '\n';
+ ctr = 0;
+ }
+ }
+ }
+ }
+ str = XmStringCreateLtoR((char *)msg_buf, G_charset);
+ XtVaSetValues(dialog[my_popup_num],
+ XmNmessageString, str,
+ XmNtraversalOn, True,
+ XmNhighlightOnEnter, True,
+ NULL);
+ XmStringFree(str);
+
+ XtManageChild(dialog[my_popup_num]);
+
+ if (x_coord > 0 && y_coord > 0) {
+ position_window(XtParent(dialog[my_popup_num]), (Position)x_coord, (Position)y_coord);
+ }
+
+ XtPopup(XtParent(dialog[my_popup_num]), XtGrabNone);
+/* XtPopup(XtParent(dialog[my_popup_num]), XtGrabExclusive); */
+
+#else /* MOTIF */
+
+ /* add a binding of xaw_ret_action_str to <Return> to relevant widgets.
+ The callbacks (xaw_ret_action_str) are responsible for parsing the
+ passed arguments (pointers, or empty arguments).
+ */
+ if (xaw_ret_action_str != NULL) {
+ XtTranslations xlats;
+ char *translation_str;
+
+ if (yes_arg != NULL)
+ translation_str = get_string_va("<Key>Return:close-popup(%d)%s(%p)",
+ my_popup_num, xaw_ret_action_str, yes_arg);
+ else
+ translation_str = get_string_va("<Key>Return:close-popup(%d)%s()",
+ my_popup_num, xaw_ret_action_str);
+
+ xlats = XtParseTranslationTable(translation_str);
+ free(translation_str);
+ XtOverrideTranslations(popup_window[my_popup_num], xlats);
+ XtOverrideTranslations(message_paned[my_popup_num], xlats);
+ XtOverrideTranslations(message_text[my_popup_num], xlats);
+ }
+
+ XtVaSetValues(popup_window[my_popup_num], XtNtitle, win_title, NULL);
+ XtVaSetValues(message_text[my_popup_num], XtNstring, msg_buf, NULL);
+ XtRealizeWidget(popup_window[my_popup_num]);
+
+ XSetWMProtocols(XtDisplay(popup_window[my_popup_num]), XtWindow(popup_window[my_popup_num]),
+ &WM_DELETE_WINDOW, 1);
+
+ if (x_coord <= 0 || y_coord <= 0)
+ center_window(popup_window[my_popup_num], parent);
+ else
+ position_window(popup_window[my_popup_num], (Position)x_coord, (Position)y_coord);
+
+ if (my_popup_num > 0) {
+ /* some window managers position new windows exactly above the
+ existing one; to prevent this, move it with some offset
+ from the previous one: */
+ Position x = 0, y = 0;
+ XtVaGetValues(popup_window[my_popup_num-1], XtNx, &x, XtNy, &y, NULL);
+ XtVaSetValues(popup_window[my_popup_num], XtNx, x + POPUP_OFFSET, XtNy, y + POPUP_OFFSET, NULL);
+
+ }
+ XtPopup(popup_window[my_popup_num], XtGrabNone);
+/* XtPopup(XtParent(popup_window[my_popup_num]), XtGrabExclusive); */
+ if (XtIsManaged(message_not_ok[my_popup_num]) && XtIsManaged(message_help[my_popup_num])) {
+ /* center the help button. This is something of a sham, since it won't
+ survive resizing; but in general most users won't resize dialogs ;-) */
+ Position x1, x2, bw;
+ int w, dist;
+
+ XtVaGetValues(message_ok[my_popup_num], XtNx, &x1, XtNwidth, &w, XtNborderWidth, &bw, NULL);
+ XtVaGetValues(message_help[my_popup_num], XtNx, &x2, NULL);
+ /* following formula is measured, not calculated -
+ I have no idea why it's e.g. 2 * w, not 1.5 * w ... */
+ dist = (x2 - x1 - 2 * w) / 2 - 2 * bw;
+ XtVaSetValues(message_not_ok[my_popup_num], XtNhorizDistance, dist, NULL);
+ }
+
+#endif /* MOTIF */
+ return ret;
+}
+
+
+/*------------------------------------------------------------
+ * popup_message
+ *
+ * Arguments:
+ * popupMessageT - info, warning, error etc; see message-window.h for details
+ *
+ * char *helptext
+ * - if not-null, this will add a `Help'
+ * button to the message widget that pops
+ * up another message widget containing
+ * <helptext>.
+ *
+ *
+ * char *msg, ...
+ * - format string followed by a variable
+ * number of arguments to be formatted.
+ *
+ * Returns:
+ * void
+ *
+ * Purpose:
+ * Pop up a message window containing <msg>.
+ * If there are already n popups open, will open
+ * a new one unless n >= MAX_POPUPS.
+ *------------------------------------------------------------*/
+
+Widget
+popup_message(Widget parent, popupMessageT type, const char *helptext, const char *format, ...)
+{
+ char *msg_buf = NULL;
+ Widget w;
+
+ XDVI_GET_STRING_ARGP(msg_buf, format);
+
+ w = internal_popup_window(parent,
+ SIZE_SMALL,
+ type,
+ -1, -1, /* just center it */
+ helptext, msg_buf,
+#ifndef MOTIF
+ NULL,
+#endif
+ /* no special callbacks here */
+ NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ free(msg_buf);
+ return w;
+}
+
+Widget
+popup_message_sized(Widget parent,
+ popupMessageT type,
+ popupMessageSizeHintT sizehint,
+ const char *helptext,
+ const char *format, ...)
+{
+ char *msg_buf = NULL;
+ Widget w;
+
+ XDVI_GET_STRING_ARGP(msg_buf, format);
+
+ w = internal_popup_window(parent,
+ sizehint,
+ type,
+ -1, -1, /* just center it */
+ helptext, msg_buf,
+#ifndef MOTIF
+ NULL,
+#endif
+ /* empty callbacks */
+ NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ free(msg_buf);
+ return w;
+}
+
+Widget
+positioned_popup_message(Widget parent,
+ popupMessageT type,
+ int x, int y,
+ const char *helptext, const char *format, ...)
+{
+ char *msg_buf = NULL;
+ Widget w;
+
+ XDVI_GET_STRING_ARGP(msg_buf, format);
+
+ w = internal_popup_window(parent,
+ SIZE_SMALL,
+ type,
+ x, y, /* position at these coordinates */
+ helptext, msg_buf,
+#ifndef MOTIF
+ NULL,
+#endif
+ /* empty callbacks */
+ NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ free(msg_buf);
+ return w;
+}
+
+Widget
+choice_dialog(Widget parent,
+ popupMessageT type,
+ const char *helptext,
+#ifndef MOTIF
+ const char *xaw_ret_action_str,
+#endif
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *ok_label, message_cbT ok_cb, XtPointer ok_arg,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_arg,
+ const char *format, ...)
+{
+ char *msg_buf = NULL;
+ Widget w;
+
+ XDVI_GET_STRING_ARGP(msg_buf, format);
+
+ w = internal_popup_window(parent,
+ SIZE_SMALL,
+ type,
+ -1, -1, /* just center it */
+ helptext, msg_buf,
+#ifndef MOTIF
+ xaw_ret_action_str,
+#endif
+ pre_cb, arg,
+ ok_label, ok_cb, ok_arg,
+ NULL, NULL, NULL,
+ cancel_label, cancel_cb, cancel_arg);
+ free(msg_buf);
+ return w;
+}
+
+#if MOTIF
+Widget
+choice3_dialog(Widget parent,
+ popupMessageT type,
+ const char *helptext,
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *yes_label, message_cbT yes_cb, XtPointer yes_arg,
+ const char *no_label, message_cbT no_cb, XtPointer no_arg,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_arg,
+ const char *format, ...)
+{
+ char *msg_buf = NULL;
+ Widget w;
+
+ XDVI_GET_STRING_ARGP(msg_buf, format);
+
+ w = internal_popup_window(parent,
+ SIZE_SMALL,
+ type,
+ -1, -1, /* just center it */
+ helptext, msg_buf,
+ pre_cb, arg,
+ yes_label, yes_cb, yes_arg,
+ no_label, no_cb, no_arg,
+ cancel_label, cancel_cb, cancel_arg);
+ free(msg_buf);
+ return w;
+}
+#endif
+
+Widget
+choice_dialog_sized(Widget parent,
+ popupMessageT type,
+ popupMessageSizeHintT sizehint,
+ const char *helptext,
+#ifndef MOTIF
+ const char *xaw_ret_action_str,
+#endif
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *ok_label, message_cbT ok_cb, XtPointer ok_arg,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_arg,
+ const char *format, ...)
+{
+ char *msg_buf = NULL;
+ Widget w;
+
+ XDVI_GET_STRING_ARGP(msg_buf, format);
+
+ w = internal_popup_window(parent,
+ sizehint,
+ type,
+ -1, -1, /* just center it */
+ helptext, msg_buf,
+#ifndef MOTIF
+ xaw_ret_action_str,
+#endif
+ pre_cb, arg,
+ ok_label, ok_cb, ok_arg,
+ NULL, NULL, NULL,
+ cancel_label, cancel_cb, cancel_arg);
+ free(msg_buf);
+ return w;
+}
+
+Widget
+positioned_choice_dialog(Widget parent,
+ popupMessageT type,
+ int x_pos, int y_pos,
+ const char *helptext,
+#ifndef MOTIF
+ const char *xaw_ret_action_str,
+#endif
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *ok_label, message_cbT ok_cb, XtPointer ok_arg,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_arg,
+ const char *format, ...)
+{
+ char *msg_buf = NULL;
+ Widget w;
+
+ XDVI_GET_STRING_ARGP(msg_buf, format);
+
+ w = internal_popup_window(parent,
+ SIZE_SMALL,
+ type,
+ x_pos, y_pos,
+ helptext, msg_buf,
+#ifndef MOTIF
+ xaw_ret_action_str,
+#endif
+ pre_cb, arg,
+ ok_label, ok_cb, ok_arg,
+ NULL, NULL, NULL,
+ cancel_label, cancel_cb, cancel_arg);
+ free(msg_buf);
+ return w;
+}
+
+void
+warn_overstrike(void)
+{
+ static Boolean warned_overstrike = False;
+
+ if (!warned_overstrike) {
+ popup_message(globals.widgets.top_level,
+ MSG_WARN,
+ /* helptext */
+ "Greyscaling is running in copy mode; this will cause overstrike characters to "
+ "appear incorrectly, and may result in poor display quality. "
+ "Possible fixes are:\n"
+ "- Use the ``-thorough'' command-line option.\n"
+ "- Quit some other color-hungry applications (e.g. Netscape).\n"
+ "- Use the ``-install'' command-line option.\n"
+ "See the section ``GREYSCALING AND COLORMAPS'' in the "
+ "xdvi manual page for more details.",
+ /* text */
+ "Couldn't allocate enough colors - expect low display quality.");
+ warned_overstrike = True;
+ }
+}
+
+Boolean
+is_message_window(Widget w)
+{
+ int i;
+ for (i = 0; i < MAX_POPUPS; i++) {
+ if (w == popup_window[i])
+ return True;
+ }
+ return False;
+}
+
+Boolean
+kill_message_window(Widget w)
+{
+ int i;
+ for (i = 0; i < MAX_POPUPS; i++) {
+ if (g_popup_array[i] != 0 && XtIsRealized(popup_window[i]) && w == popup_window[i]) {
+ g_popup_array[i] = 0;
+ XtPopdown(popup_window[i]);
+ XtDestroyWidget(popup_window[i]);
+ XSync(DISP, True);
+ return True;
+ }
+ }
+ return False;
+}
+
+/*
+ Raise any popups that currently exist; return True iff such popups
+ exist, else False.
+*/
+Boolean
+raise_message_windows(void)
+{
+ int i;
+ Boolean have_popups = False;
+
+ for (i = 0; i < MAX_POPUPS; i++) {
+ if (g_popup_array[i] != 0 && XtIsRealized(popup_window[i])) {
+ XRaiseWindow(DISP, XtWindow(popup_window[i]));
+ have_popups = True;
+ }
+ }
+
+ return have_popups;
+}
diff --git a/Build/source/texk/xdvik/gui/message-window.h b/Build/source/texk/xdvik/gui/message-window.h
new file mode 100644
index 00000000000..7e38197abbc
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/message-window.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef MESSAGE_WINDOW_H_
+#define MESSAGE_WINDOW_H_
+
+#define Xdvi_MESSAGE_DIALOG_NAME "dialog"
+#define Xdvi_MESSAGE_SHELL_NAME "message_popup"
+
+
+/*
+ * Callback before the message window is closed. It is passed
+ * the message window widget ID, and the next XtPointer argument
+ * in the message dialog calls.
+ */
+typedef void (*pre_message_cbT)(Widget w, XtPointer arg);
+/*
+ * Additional callbacks passed in as argument. It is passed
+ * the next XtPointer argument in the message dialog calls.
+ */
+typedef void (*message_cbT)(XtPointer arg);
+
+/* preferred size of dialogs, only used for Xaw ... not really hints, but
+ hard-coded values ;-) */
+typedef enum popupMessageSizeHintT_ { SIZE_SMALL, SIZE_MEDIUM, SIZE_LARGE } popupMessageSizeHintT;
+typedef enum popupMessageT_ { MSG_QUESTION, MSG_HELP, MSG_INFO, MSG_WARN, MSG_ERR } popupMessageT;
+
+extern Widget popup_message(Widget parent,
+ popupMessageT type,
+ const char *helptext,
+ const char *format, ...);
+
+extern Widget popup_message_sized(Widget parent,
+ popupMessageT type,
+ popupMessageSizeHintT size,
+ const char *helptext,
+ const char *format, ...);
+
+extern Widget positioned_popup_message(Widget parent,
+ popupMessageT type,
+ int x, int y,
+ const char *helptext, const char *format, ...);
+
+extern Widget choice_dialog(Widget parent,
+ popupMessageT type,
+ const char *helptext,
+#ifndef MOTIF
+ const char *ret_action_str,
+#endif
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *ok_label, message_cbT ok_cb, XtPointer ok_args,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_args,
+ const char *format, ...);
+
+#if MOTIF
+/* 3 buttons currently only implemented for Motif */
+extern Widget choice3_dialog(Widget parent,
+ popupMessageT type,
+ const char *helptext,
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *yes_label, message_cbT yes_cb, XtPointer yes_args,
+ const char *no_label, message_cbT no_cb, XtPointer no_args,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_args,
+ const char *format, ...);
+#endif
+
+extern Widget choice_dialog_sized(Widget parent,
+ popupMessageT type,
+ popupMessageSizeHintT size,
+ const char *helptext,
+#ifndef MOTIF
+ const char *ret_action_str,
+#endif
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *ok_label, message_cbT ok_cb, XtPointer ok_args,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_args,
+ const char *format, ...);
+
+extern Widget positioned_choice_dialog(Widget parent,
+ popupMessageT type,
+ int x_pos, int y_pos,
+ const char *helptext,
+#ifndef MOTIF
+ const char *ret_action_str,
+#endif
+ pre_message_cbT pre_cb, XtPointer arg,
+ const char *ok_label, message_cbT ok_cb, XtPointer ok_args,
+ const char *cancel_label, message_cbT cancel_cb, XtPointer cancel_args,
+ const char *format, ...);
+extern void warn_overstrike(void);
+extern Boolean raise_message_windows(void);
+extern Boolean is_message_window(Widget w);
+extern Boolean kill_message_window(Widget w);
+
+/* XawtextScrollWhenNeeded has been ditched in Xaw7
+ (e.g. Xfree >= 4.x); from the man page:
+
+ The value XawtextScrollWhenNeeded (and whenNeeded, recognized by
+ the converter), is accepted for backwards compatibilty with
+ resource specifications written for the Xaw6 Text widget, but
+ ignored (effectively treated as XawtextScrollNever).
+
+ So we're forced to use `scrollAlways' here.
+*/
+#define XAW_SCROLL_ALWAYS XawtextScrollAlways
+
+/* the reconfig stuff has been fixed
+ in XFree 4.1.0, vendor release 6510 (Slackware 8.0) */
+#define BROKEN_RECONFIG (( \
+ (strstr(ServerVendor(DISP), "XFree") != NULL) \
+ && VendorRelease(DISP) >= 4000 \
+ && VendorRelease(DISP) < 4002 \
+ ))
+
+#endif /* MESSAGE_WINDOW_H_ */
diff --git a/Build/source/texk/xdvik/gui/pagesel.c b/Build/source/texk/xdvik/gui/pagesel.c
new file mode 100644
index 00000000000..b3db730e481
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/pagesel.c
@@ -0,0 +1,1591 @@
+/*
+ * Page selector for xdvi
+ *
+ * Copyright (c) 2001-2004 xdvik development team
+ *
+ * This code is derived from the page selector in xdvik-j, and
+ * parts of it are Copyright (c) 1993, 1995
+ * MATSUURA Syun syun@fuka.info.waseda.ac.jp
+ * HIRAHARA Atsushi hirahara@fuka.info.waseda.ac.jp
+ * ONO Kouichi onono@fuka.info.waseda.ac.jp
+ * All rights reserved.
+ *
+ *
+ * (SU: I was unsure how to interpret the `All rights reserved' in the
+ * previous line, so emailed Ono Kouichi about this. Here's a
+ * verbatim quote of the relevant part of his answer (which was CC'ed
+ * to Hirahara Atsushi - all three of them had left Waseda university
+ * around '95):
+ *
+ * You can modify, embed, copy and distribute a part of or the
+ * entire of our source code when you specify our copyright in your
+ * xdvik version.
+ *
+ * IANAL, but I think this is compatible with the X consortium
+ * license, which follows.)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ BUGS:
+
+ - with Xaw, the highlighting for the selected page (XawListHighlight)
+ vanishes when mouse is dragged outside the widget and then released
+ (but the respective page is selected, which is IMHO the desired behaviour).
+
+ - with Xaw, scrolling the list with PgUp/PgDown until the current page
+ gets `out of focus' should un-highlight the current page number
+
+ - The ASCII-based marks are *ugly*. Pixmaps (for the marked state)
+ would be better. The viewer gv has one (but it's Xaw only). Some
+ file directory widgets like
+ e.g. http://ftp.xfree86.org/pub/X.Org/contrib/widgets/ListTree-3.0b3.tar.gz
+ also have facilities for that, but most suffer from other
+ inadequacies (e.g. no such ting as browseSelection) and all kinds
+ of bitrot ... Another alternative would be using XmContainer
+ (see e.g. the `filemanager' example in demos/programs/filemanagers
+ in the openmotif distribution), but that's available for Motif >= 2.1 only.
+
+*/
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+
+#include "xm_toolbar.h"
+#include "xm_menu.h"
+#include "xaw_menu.h"
+
+#include "x_util.h"
+
+#ifdef MOTIF
+# include <Xm/Xm.h>
+# include <Xm/List.h>
+# include <Xm/ScrollBar.h> /* for XmScrollBarGetValues */
+#else /* MOTIF */
+# include <X11/Xaw/Dialog.h>
+# include <X11/Xaw/Cardinals.h>
+# include <X11/Xaw/Command.h>
+# include <X11/Xaw/List.h>
+# include <X11/Xaw/Viewport.h>
+#endif /* MOTIF */
+
+#include "message-window.h"
+#include "pagesel.h"
+#include "util.h"
+#include "string-utils.h"
+#include "dvi-init.h"
+#include "statusline.h"
+#include "events.h"
+#include "print-dialog.h"
+#include "search-internal.h"
+#include "pagehist.h"
+
+#define PAGENUMLEN 128
+#define SCROLL_LIST_SCROLLBAR 0
+
+#ifndef MAX_PAGE
+# define MAX_PAGE (1024)
+#endif /* MAX_PAGE */
+
+#define LONGESTPAGENUM 55
+
+
+/* for saving the GC of the pagelist widget
+ (when un-highlighting items in highlight_page_callback, and
+ drawing the `current' marker)
+*/
+static struct page_gc {
+ GC fore;
+ GC back;
+} m_page_gc;
+
+#define MOTIF_IDX_OFFSET 1 /* motif index starts at 1, not 0 */
+#if !defined(LESSTIF_VERSION)
+static Boolean my_list_pos_to_bounds(Widget widget, int idx, Position *x, Position *y, Dimension *w, Dimension *h);
+static void refresh_highlight_marker(Widget widget, GC gc, Position x, Position y, Dimension w, Dimension h);
+#endif /* !defined(LESSTIF_VERSION) */
+
+
+
+#ifdef MOTIF
+
+/* make button2 mark instead of drag&drop */
+static void xm_list_set_mark(Widget widget, XEvent *event, String *params, Cardinal *num_params);
+static void xm_list_drag_mark(Widget widget, XEvent *event, String *params, Cardinal *num_params);
+static XtActionsRec CustomListActions[] = {
+ { "ListSetMark", xm_list_set_mark },
+ { "ListDragMark", xm_list_drag_mark },
+};
+static char *motif_custom_translations =
+ "#override \n"
+ "s <Btn2Down>: ListDragMark(ListButtonMotion)\n"
+ "<Btn2Motion>: ListSetMark(ListButtonMotion)\n"
+ "<Btn2Up>: ListSetMark(ListButtonMotion)\n"
+ "<Btn2Down>: ListSetMark(ListButtonMotion)\n"
+/* /\* "s ~m ~a <Btn2Down>: ListMyProcessBtn2(ListBeginExtend)\n" *\/ */
+/* /\* "s ~m ~a <Btn2Up>: ListMyProcessBtn2(ListEndExtend)\n" *\/ */
+/* /\* "~c ~s ~m ~a <Btn2Down>: ListMyProcessBtn2(ListBeginSelect)\n" *\/ */
+/* /\* "~c ~s ~m ~a <Btn2Up>: ListMyProcessBtn2(ListEndSelect)\n" *\/ */
+/* /\* "c ~s ~m ~a <Btn2Down>: ListMyProcessBtn2(ListBeginToggle)\n" *\/ */
+/* /\* "c ~s ~m ~a <Btn2Up>: ListMyProcessBtn2(ListEndToggle)\n" *\/ */
+/* /\* "c ~s ~m a <Btn2Down>: ListProcessDrag()\n" *\/ */
+/* /\* "~c s ~m a <Btn2Down>: ListProcessDrag()\n" *\/ */
+;
+
+#define LIST_WIDGET page_list
+/* motif pagenumber is a string */
+static const char* const pageno_format = "%c %s ";
+
+#else /* MOTIF */
+
+static int view_y;
+extern Widget panel_widget;
+static Widget list_widget = NULL;
+static Widget viewport = NULL;
+#define LIST_WIDGET list_widget
+/* Xaw pagenumber is an integer, and we need to left-pad it */
+static const char* const pageno_format = "%c %*d ";
+
+static int xaw_maybe_scroll_pagelist(int new_page, Boolean force_recenter, int old);
+
+#define REDRAW_CURRENT_MARKER_HACK 1
+
+
+/*
+ The following hack tries to address the following 2 bugs with the
+ self-made page highlighting marker:
+
+ - the marker overlaps with the ordinary XawListHighlight marker;
+ when un-highlighting a page, 1 pixel (vertically) at the edge of
+ the ordinary marker is overdrawn.
+
+ - When the XawListHighlight crosses the self-drawn rectangle,
+ the vertical bars remain visible, but the horizontal bars
+ are erased.
+
+ The hack just redraws the appropriate items whenever one of
+ the above can happen, i.e. when the two markers are 2 or less
+ pages apart from each other.
+*/
+#if REDRAW_CURRENT_MARKER_HACK
+/* Store index of currently marked (with our own marker) list
+ item, or -1 if none is marked. */
+static int g_current_highlighted = -1;
+
+/* redraw the default Xaw list highlight (XawListHighlight()) */
+static void
+xaw_maybe_redraw_highlight(int idx)
+{
+ XawListReturnStruct *ret;
+ int high;
+
+ if (LIST_WIDGET == NULL)
+ return;
+
+ ret = XawListShowCurrent(LIST_WIDGET);
+ high = ret->list_index;
+ if (high != XAW_LIST_NONE && abs(idx - (high + MOTIF_IDX_OFFSET)) <= 2) {
+ /* re-highlight it */
+ XawListHighlight(LIST_WIDGET, high);
+ }
+ g_current_highlighted = -1;
+}
+
+/* redraw our own rectangle highlight marker: */
+static void
+xaw_maybe_redraw_current_marker(int idx)
+{
+ Position x, y;
+ Dimension w, h;
+
+/* fprintf(stderr, "idx: %d, high: %d; diff: %d\n", idx + MOTIF_IDX_OFFSET, g_current_highlighted, */
+/* abs(idx + MOTIF_IDX_OFFSET - g_current_highlighted)); */
+ if (abs((idx + MOTIF_IDX_OFFSET) - g_current_highlighted) <= 2
+ && my_list_pos_to_bounds(LIST_WIDGET, g_current_highlighted, &x, &y, &w, &h)) {
+ refresh_highlight_marker(LIST_WIDGET, m_page_gc.fore, x, y, w, h);
+ }
+}
+#endif /* REDRAW_CURRENT_MARKER_HACK */
+
+#endif /* MOTIF */
+
+/*
+ * Table of page offsets in DVI file, indexed by page number - 1,
+ * marked pages, and page sizes.
+ * Initialized in prepare_pages().
+ */
+struct page_index {
+ long offset;
+ int number;
+ Boolean marked;
+ unsigned int pw, ph; /* page size */
+ unsigned int ww, wh; /* window size */
+};
+
+struct page_index_info {
+ struct page_index *index; /* above struct */
+ size_t index_size; /* size of currently allocated index */
+ char **page_labels; /* label strings */
+};
+
+static struct page_index_info page_info;
+
+/* access functions used by dvi-draw.c and dvi-init.c */
+long
+pageinfo_get_offset(int page)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+/* fprintf(stderr, "offset for page %d is %ld\n", page, page_info.index[page].offset); */
+ return page_info.index[page].offset;
+}
+
+/* access functions used by dvi-draw.c and dvi-init.c */
+unsigned int
+pageinfo_get_page_width(int page)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ return page_info.index[page].pw;
+}
+
+unsigned int
+pageinfo_get_page_height(int page)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ return page_info.index[page].ph;
+}
+
+unsigned int
+pageinfo_get_window_width(int page)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ return page_info.index[page].ww;
+}
+
+unsigned int
+pageinfo_get_window_height(int page)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ return page_info.index[page].wh;
+}
+
+void
+pageinfo_set_page_width(int page, unsigned int width)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ page_info.index[page].pw = width;
+}
+
+void
+pageinfo_set_page_height(int page, unsigned int height)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ page_info.index[page].ph = height;
+}
+
+void
+pageinfo_set_window_width(int page, unsigned int width)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ page_info.index[page].ww = width;
+}
+
+void
+pageinfo_set_window_height(int page, unsigned int height)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ page_info.index[page].wh = height;
+}
+
+int
+pageinfo_get_number(int page)
+{
+ ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range");
+ return page_info.index[page].number;
+}
+
+/* search for page with TeX number `number', and return its index, or -1 if it's not found. */
+int
+pageinfo_get_index_of_number(int number)
+{
+ size_t i;
+ for (i = 0; i < page_info.index_size - 1; i++) {
+ if (number == page_info.index[i].number)
+ return i;
+ }
+ return -1;
+}
+
+void
+pageinfo_set_offset(int index, long offset)
+{
+ ASSERT(index >= 0 && index < (int)page_info.index_size, "");
+ page_info.index[index].offset = offset;
+}
+
+void
+pageinfo_set_number(int index, int number)
+{
+ ASSERT(index >= 0 && index < (int)page_info.index_size, "");
+ page_info.index[index].number = number;
+}
+
+void
+pageinfo_allocate(int total_pages)
+{
+ int i;
+ page_info.index = xmalloc(total_pages * sizeof *(page_info.index));
+ for (i = 0; i < total_pages; i++) {
+ page_info.index[i].marked = False;
+ }
+ /* following initializations are handled by the respective Motif/Xaw functions */
+ page_info.page_labels = NULL;
+ page_info.index_size = total_pages;
+}
+
+/*
+ Deallocate page_info. NOTE: We mustn't free the page_labels here,
+ since the page list might survive quite some time (e.g. while fonts
+ for the new file are being generated) and needs the labels.
+*/
+void
+pageinfo_deallocate(void)
+{
+ free(page_info.index);
+ page_info.index_size = 0;
+ page_info.index = NULL;
+}
+
+#ifdef MOTIF
+void
+toggle_pagelist(void)
+{
+ Dimension curr_w, curr_x;
+ XtVaGetValues(globals.widgets.main_window,
+ XmNwidth, &curr_w,
+ XmNx, &curr_x,
+ NULL);
+
+ if ((resource.expert_mode & XPRT_SHOW_PAGELIST) != 0) {
+ XtManageChild(XtParent(page_list));
+ XtManageChild(page_list);
+
+ curr_x += resource.pagelist_width;
+ curr_w -= resource.pagelist_width;
+ XtVaSetValues(globals.widgets.main_window,
+ XtNwidth, curr_w,
+ XtNx, curr_x,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, XtParent(page_list),
+ NULL);
+ }
+ else {
+ XtUnmanageChild(XtParent(page_list));
+ XtUnmanageChild(page_list);
+
+ curr_x -= resource.pagelist_width;
+ curr_w += resource.pagelist_width;
+ XtVaSetValues(globals.widgets.main_window,
+ XmNwidth, curr_w,
+ XmNx, curr_x,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ }
+
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+ set_menu(&resource.expert_mode, Act_set_expert_mode, check_resource_expert);
+#else
+ set_show_pagelist_option();
+#endif
+}
+#endif
+
+
+Boolean
+pageinfo_have_marked_pages(void)
+{
+ int i;
+ for (i = 0; i < total_pages; i++) {
+ if (page_info.index[i].marked) {
+ return True;
+ }
+ }
+ return False;
+}
+
+
+/* return True if page i is marked, False else */
+Boolean
+pageinfo_is_marked(int i)
+{
+ ASSERT(i <= (int)page_info.index_size, "");
+ return page_info.index[i].marked;
+}
+
+
+typedef enum { SCROLL_UP, SCROLL_DOWN, CLICK } saveCmdT;
+
+
+static void internal_process_button2(Widget widget, XEvent *event);
+static int get_item_index(Widget w, int mouse_y);
+
+static int
+get_page_size(void)
+{
+ int offset = 0;
+ int min_page = 0;
+ int max_page = 0;
+ int min_pageno_len = 0;
+ int max_pageno_len = 0;
+ int i;
+
+ if (globals.dvi_file.bak_fp == NULL)
+ return 0;
+
+ for (i = 0; i < total_pages; i++) {
+ max_page = MAX(page_info.index[i].number, max_page);
+ min_page = MIN(page_info.index[i].number, min_page);
+ }
+
+ if (min_page >= 0) {
+ offset = 0; /* plus symbol is hidden */
+ } else {
+ offset = 1; /* offset for minus symbol */
+ min_page = -min_page;
+ }
+ for (min_pageno_len = offset; min_page > 0;
+ min_page /= 10, min_pageno_len++);
+
+ if (max_page >= 0) {
+ offset = 0; /* plus symbol is hidden */
+ } else {
+ offset = 1; /* offset for minus symbol */
+ max_page = -max_page;
+ }
+ for (max_pageno_len = offset; max_page > 0;
+ max_page /= 10, max_pageno_len++);
+
+ return MAX(min_pageno_len, max_pageno_len);
+ /* Plus 1 for minus symbol */
+}
+
+#if !defined(LESSTIF_VERSION)
+/* draw or erase highlight marker at position x, y with widht w an height h,
+ using suitable offsets (for sake of consistency of the latter, and because
+ of the differences Xaw/Motif, this is a separate function).
+ */
+static void
+refresh_highlight_marker(Widget widget, GC gc,
+ Position x, Position y, Dimension w, Dimension h)
+{
+ XDrawRectangle(XtDisplay(widget), XtWindow(widget), gc,
+#ifdef MOTIF
+ x + 1, y + 1, w - 3, h - 3
+#else
+ x + 2, y, w - 1, h - 1
+#endif
+ );
+}
+#endif /* !defined(LESSTIF_VERSION) */
+
+#ifndef MOTIF
+
+/* update (redisplay) the list, saving the currently highlighted item.
+ * This is invoked whenever marking the page, and the re-construction of the
+ * entire list causes considerable flicker; but I guess that's unavoidable
+ * with the current simplistic labelling scheme (with changing the list items
+ * themselves). Gv does this considerably better (using custom widgets).
+ */
+static void
+xaw_update_list(void)
+{
+ static int pagelist_width = -1;
+ static int total_pages_bak = -1;
+
+ XawListReturnStruct *ret;
+ int idx, button_width;
+
+ if (pagelist_width == -1 || total_pages != total_pages_bak) {
+ pagelist_width = xaw_get_pagelist_size();
+ total_pages_bak = total_pages;
+ }
+
+ /* save selected item */
+ ret = XawListShowCurrent(LIST_WIDGET);
+ idx = ret->list_index;
+ button_width = get_panel_width() - 2 * (resource.btn_side_spacing + resource.btn_border_width);
+ /* delete and re-create list */
+ ASSERT(total_pages <= (int)page_info.index_size, "");
+ XawListChange(LIST_WIDGET, page_info.page_labels, 0,
+ MAX(button_width, pagelist_width), False);
+ /* restore selected item */
+ if (idx != XAW_LIST_NONE) {
+ XawListHighlight(LIST_WIDGET, idx);
+ }
+}
+
+/*
+ return height of a row in the list widget, and the initial offset of XtNinternalHeight
+ in parameters row_height and internal_h
+*/
+static void
+xaw_get_row_height(Widget w, Dimension *row_height, Dimension *internal_h)
+{
+ Dimension row_space;
+ XFontStruct *font;
+ Arg arglist[5];
+ int i = 0;
+
+ if (w == NULL || !XtIsRealized(w))
+ return;
+
+ XtSetArg(arglist[i], XtNfont, &font); ++i;
+ XtSetArg(arglist[i], XtNrowSpacing, &row_space); ++i;
+ XtSetArg(arglist[i], XtNinternalHeight, internal_h); i++;
+ XtGetValues(w, arglist, i);
+ *row_height = font->max_bounds.ascent + font->max_bounds.descent + row_space;
+}
+
+/*
+ * Get pagelist width.
+ */
+int
+xaw_get_pagelist_size(void)
+{
+ Widget w;
+ XFontStruct *font;
+
+ w = XtVaCreateWidget("list", listWidgetClass, globals.widgets.top_level, NULL);
+ XtVaGetValues(w, XtNfont, &font, NULL);
+ XtDestroyWidget(w);
+
+ /* have space for max. pageno + space + current-marker,
+ plus a few pixels for right margin */
+ return (get_page_size() + 2) * get_avg_font_width(font) + 6;
+}
+
+/* auto-scroll pagelist when mouse-1 is down and moved above top or below bottom of
+ page list.
+*/
+static void
+xaw_drag_page_callback(Widget widget, XtPointer data, XEvent *event, Boolean *cont)
+{
+ int y, idx, actual_idx = 0;
+
+ UNUSED(data);
+ UNUSED(cont);
+
+ if (event->xany.type == ButtonPress || ((event->xbutton.state & Button1Mask) == 0))
+ return;
+ if (event->xany.type == MotionNotify)
+ y = (int)event->xmotion.y;
+ else
+ y = (int)event->xbutton.y;
+
+ idx = get_item_index(widget, y);
+
+ if (idx <= 0) {
+ idx = 1;
+ }
+ else if (idx > total_pages) {
+ idx = total_pages;
+ }
+
+ actual_idx = xaw_maybe_scroll_pagelist(idx, False, actual_idx);
+ XawListHighlight(LIST_WIDGET, idx - MOTIF_IDX_OFFSET);
+
+/* if (event->xany.type == ButtonRelease) { */
+/* fprintf(stderr, "1\n"); */
+/* page_history_insert(idx - MOTIF_IDX_OFFSET); */
+/* goto_page(idx - MOTIF_IDX_OFFSET, resource.keep_flag ? NULL : home); */
+/* search_signal_page_changed(); */
+/* } */
+}
+
+static void
+xaw_SendReportProc(Widget w, XtPointer closure, XtPointer call_data)
+{
+ XawPannerReport *rep = (XawPannerReport *) call_data;
+
+ UNUSED(w);
+ UNUSED(closure);
+
+ view_y = rep->slider_y;
+}
+
+#endif /* not MOTIF */
+
+
+
+/* returns the index of the current item in `Motif'-style, i.e. first item has index 1, not 0 */
+static int
+get_item_index(Widget w, int mouse_y)
+{
+#ifdef MOTIF
+ return XmListYToPos(w, mouse_y);
+#else
+ Dimension row_height, internal_height;
+
+ xaw_get_row_height(w, &row_height, &internal_height);
+ return (mouse_y - internal_height) / row_height + MOTIF_IDX_OFFSET;
+#endif
+}
+
+#if !defined(LESSTIF_VERSION)
+/* idx is Motif-style index, i.e. 1 for 1st item, not 0 */
+static Boolean
+my_list_pos_to_bounds(Widget widget, int idx, Position *x, Position *y, Dimension *w, Dimension *h)
+{
+#ifdef MOTIF
+ Position x1, y1;
+ Dimension w1, h1;
+ if (XmListPosToBounds(widget, idx, &x1, &y1, &w1, &h1)) {
+ *x = x1;
+ *y = y1;
+ *w = w1;
+ *h = h1;
+ return True;
+ }
+ return False;
+#else
+ Dimension row_height, internal_height;
+ /* FIXME: Remove this hard-coded offset! */
+ const int X_OFFSET = 9;
+ const int RULE_OFFSET = 2;
+
+ if (idx <= 0 || idx > total_pages) {
+ return False;
+ }
+
+ if (viewport != NULL && XtIsRealized(viewport))
+ XtVaGetValues(viewport, XtNx, x, NULL);
+ xaw_get_row_height(widget, &row_height, &internal_height);
+ XtVaGetValues(widget, XtNwidth, w, NULL);
+
+ *x -= X_OFFSET;
+ *y = row_height * idx + internal_height - row_height - 1;
+ *w -= RULE_OFFSET;
+ *h = row_height + RULE_OFFSET;
+
+ return True;
+#endif
+}
+#endif /* !defined(LESSTIF_VERSION) */
+
+/* it seems that in order to support scrolling of the page list with wheel mice,
+ we need to program this explicitly.
+ */
+static void
+wheel_scroll_list_callback(Widget widget, XtPointer data, XEvent *event, Boolean *cont)
+{
+ int button = event->xbutton.button;
+
+ UNUSED(widget);
+ UNUSED(data);
+ UNUSED(cont);
+
+ if (event->xany.type == ButtonPress && (button == 4 || button == 5)) {
+#if SCROLL_LIST_SCROLLBAR
+ Widget vert = XtNameToWidget(viewport, "vertical");
+ static Dimension row_height = 0, dummy = 0;
+ int diff_y = 0;
+
+ if (row_height == 0)
+ xaw_get_row_height(LIST_WIDGET, &row_height, &dummy);
+
+ if (vert == NULL) {
+ XDVI_WARNING((stderr, "Couldn't get name of pagelist viewport widget!"));
+ return;
+ }
+ if (button == 5) {
+ diff_y = row_height;
+ }
+ else {
+ diff_y = -row_height;
+ }
+ XtCallCallbacks(vert, XtNscrollProc, (XtPointer)diff_y);
+#else
+ int pageno = current_page;
+ if (button == 5) {
+ if (current_page >= total_pages - 1) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "Last page of DVI file");
+ return;
+ }
+ pageno++;
+ }
+ else {
+ if (current_page == 0) {
+ XBell(DISP, 0);
+ statusline_print(STATUS_SHORT, "First page of DVI file");
+ return;
+ }
+ pageno--;
+ }
+ goto_page(check_goto_page(pageno), resource.keep_flag ? NULL : home, False);
+ search_signal_page_changed();
+#endif
+ }
+}
+
+
+#if !defined(LESSTIF_VERSION)
+/* draw a hightlight rectangle around the page the mouse is currently over, to
+ make e.g. marking easier.
+ */
+static void
+highlight_page_callback(Widget widget, XtPointer data, XEvent *event, Boolean *cont)
+{
+ int curr_idx = get_item_index(widget, event->xmotion.y);
+ Position x, y;
+ Dimension w, h;
+ static int idx_bak = -1;
+
+ UNUSED(data);
+ UNUSED(cont);
+
+ switch(event->xany.type) {
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ /* might need to un-highlight previous one */
+ if (idx_bak >= 0 && idx_bak != curr_idx
+ && my_list_pos_to_bounds(widget, idx_bak, &x, &y, &w, &h)) {
+/* fprintf(stderr, "index: %d, %d, h: %d, w: %d\n", x, y, h, w); */
+ refresh_highlight_marker(widget, m_page_gc.back, x, y, w, h);
+#if REDRAW_CURRENT_MARKER_HACK
+ xaw_maybe_redraw_highlight(curr_idx);
+#endif
+ }
+ idx_bak = curr_idx;
+ /* redraw unless out of bounds (when pagelist is shorter than view area) */
+ if (my_list_pos_to_bounds(widget, curr_idx, &x, &y, &w, &h)) {
+ refresh_highlight_marker(widget, m_page_gc.fore, x, y, w, h);
+#if REDRAW_CURRENT_MARKER_HACK
+ g_current_highlighted = curr_idx;
+#endif
+ }
+ break;
+ case LeaveNotify:
+ /* this might look overly complicated, but is neccessary to cover all
+ cases of 1-pixel movement up/down before leaving the list, or no
+ movement at all before leaving it. */
+ if ((idx_bak >= 0 && idx_bak != curr_idx && my_list_pos_to_bounds(widget, idx_bak, &x, &y, &w, &h))
+ || my_list_pos_to_bounds(widget, curr_idx, &x, &y, &w, &h)) {
+ refresh_highlight_marker(widget, m_page_gc.back, x, y, w, h);
+#if REDRAW_CURRENT_MARKER_HACK
+ xaw_maybe_redraw_highlight(curr_idx);
+#endif
+ }
+ break;
+ default:
+ break;
+ }
+}
+#endif /* !defined(LESSTIF_VERSION) */
+
+/*
+ * invoked on Button-1 Down.
+ */
+static void
+select_page_callback(Widget w, XtPointer closure, XtPointer call_data)
+{
+#ifdef MOTIF
+ XmListCallbackStruct *cbs = (XmListCallbackStruct *) call_data;
+ int new = cbs->item_position;
+
+ UNUSED(w);
+ UNUSED(closure);
+
+ maybe_scroll_pagelist(new - MOTIF_IDX_OFFSET, False);
+ page_history_insert(new - MOTIF_IDX_OFFSET);
+ goto_page(new - MOTIF_IDX_OFFSET, resource.keep_flag ? NULL : home, False);
+#else
+ XawListReturnStruct *item = (XawListReturnStruct *) call_data;
+ int new = item->list_index;
+
+ UNUSED(w);
+ UNUSED(closure);
+
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "got: button-1 for `%d'\n", new);
+
+#if 0
+ fprintf(stderr, "select page: %d\n", new);
+#endif
+ maybe_scroll_pagelist(new, False);
+ page_history_insert(new);
+ goto_page(new, resource.keep_flag ? NULL : home, False);
+#endif
+ search_signal_page_changed();
+}
+
+
+static void
+init_pagelabels(int start, int end)
+{
+ int i;
+ char s[PAGENUMLEN];
+#if 0
+ fprintf(stderr, "===== init_pagelabels from %d to %d\n", start, end);
+#endif
+ ASSERT(end < (int)page_info.index_size, "");
+
+ page_info.page_labels = xrealloc(page_info.page_labels, sizeof *(page_info.page_labels) * (end + 2));
+ for (i = start; i < end; i++) {
+ if (page_info.index[i].marked)
+ sprintf(s, "* %*d ", get_page_size(),
+ resource.use_tex_pages ? page_info.index[i].number : i + 1);
+ else
+ sprintf(s, " %*d ", get_page_size(),
+ resource.use_tex_pages ? page_info.index[i].number : i + 1);
+
+ page_info.page_labels[i] = xstrdup(s);
+ }
+ page_info.page_labels[i] = NULL; /* terminate - important for creating the widget. */
+}
+
+
+#ifdef MOTIF
+
+
+static int
+xm_get_top_visible(int start)
+{
+ int top = start;
+ while (top < total_pages && !XmListPosToBounds(LIST_WIDGET, top, NULL, NULL, NULL, NULL))
+ top++;
+ return top;
+}
+
+static int
+xm_get_bottom_visible(int start)
+{
+ int bot = start;
+ while (bot < total_pages && XmListPosToBounds(LIST_WIDGET, bot, NULL, NULL, NULL, NULL))
+ bot++;
+ bot--;
+ return bot;
+}
+
+/* Scroll pagelist down or up if needed, and update top_visible and
+ bot_visible. List is always scrolled so that 1 element is still
+ visible below or above pointer, to make it possible to flip through
+ document by repeatedly clicking on first/last.
+ */
+static void
+xm_maybe_scroll_pagelist(int current, saveCmdT curr_cmd, int *top_visible, int *bot_visible)
+{
+#if 0
+ fprintf(stderr, "topmost visible: %d, bottom: %d, current: %d, total: %d\n",
+ top_visible, bottom_visible, current, total_pages);
+#endif
+
+ if (current < *top_visible && curr_cmd != SCROLL_DOWN) {
+ XmListSetPos(LIST_WIDGET,
+ current < 1
+ ? 1
+ : current);
+ (*top_visible)--;
+ (*bot_visible)--;
+ }
+ else if (current + MOTIF_IDX_OFFSET >= *bot_visible && curr_cmd != SCROLL_UP) {
+ XmListSetBottomPos(LIST_WIDGET,
+ current + MOTIF_IDX_OFFSET >= total_pages
+ ? current + MOTIF_IDX_OFFSET
+ : current + MOTIF_IDX_OFFSET + 1);
+ (*top_visible)++;
+ (*bot_visible)++;
+ }
+}
+
+static void
+xm_set_page_labels(void)
+{
+ int i;
+ char buf[PAGENUMLEN];
+
+ XmString *motif_page_labels = xmalloc((total_pages + 2) * sizeof *motif_page_labels);
+
+ for (i = 0; i < total_pages; ++i) {
+ sprintf(buf, pageno_format, ' ', page_info.page_labels[i]);
+ motif_page_labels[i] = XmStringCreateLocalized(buf);
+ }
+ XmListDeleteAllItems(LIST_WIDGET);
+ XmListAddItems(LIST_WIDGET, motif_page_labels, total_pages, 0);
+
+ XmListSelectPos(LIST_WIDGET, current_page + MOTIF_IDX_OFFSET, False);
+ for (i = 0; i < total_pages; ++i) {
+ XmStringFree(motif_page_labels[i]);
+ }
+ free(motif_page_labels);
+}
+
+static void
+xm_toggle_label(Widget widget, int idx, Boolean update)
+{
+ /* TODO: use `update' to update all labels at once when toggling multiple */
+ XmString str;
+ char *mark_font, buf[128];
+
+ if (widget == NULL)
+ return;
+
+ UNUSED(update);
+
+/* ensure_labelinfo_size(idx); */
+ ASSERT(idx < (int)page_info.index_size, "");
+ if (!page_info.index[idx].marked) {
+ sprintf(buf, pageno_format, '*', page_info.page_labels[idx]);
+ mark_font = "MARKED";
+ page_info.index[idx].marked = True;
+ }
+ else {
+ sprintf(buf, pageno_format, ' ', page_info.page_labels[idx]);
+ mark_font = "UNMARKED";
+ page_info.index[idx].marked = False;
+ }
+/* str = XmStringCreateLocalized(buf); */
+ str = XmStringCreateLtoR(buf, mark_font);
+ XmListReplaceItemsPos(widget, &str, 1, idx + MOTIF_IDX_OFFSET);
+ XmStringFree(str);
+}
+
+
+#else /* MOTIF */
+
+static void
+mark_page_callback(Widget w, XtPointer data, XEvent *event, Boolean *cont)
+{
+ UNUSED(data);
+ UNUSED(cont);
+
+ /* moving button2 generates MotionNotify events for button0 */
+ if (event->type == MotionNotify || event->xbutton.button == Button2)
+ internal_process_button2(w, event);
+
+ if (pageinfo_have_marked_pages()) {
+ notify_print_dialog_have_marked(True);
+ }
+ else {
+ notify_print_dialog_have_marked(False);
+ }
+
+}
+
+void
+xaw_create_pagelist_widgets(Dimension height, Dimension width, Position y, Widget parent)
+{
+ viewport = XtVaCreateWidget("viewport",
+ viewportWidgetClass, parent,
+ XtNallowVert, True,
+ /* this is not related to the scroll bar: */
+ /* XtNforceBars, True, */
+ XtNx, resource.btn_side_spacing,
+ XtNy, y,
+ XtNheight, height,
+ XtNwidth, width,
+ NULL);
+ LIST_WIDGET = XtVaCreateWidget("list",
+ listWidgetClass, viewport,
+ XtNlist, page_info.page_labels,
+ XtNdefaultColumns, 1,
+ XtNforceColumns, True,
+ XtNx, 10,
+ XtNy, 10,
+ XtNheight, height,
+ XtNwidth, width - 10,
+ XtNlongest, LONGESTPAGENUM,
+ XtNverticalList, True,
+ NULL);
+ XtManageChild(LIST_WIDGET);
+ XtManageChild(viewport);
+ XtAddCallback(LIST_WIDGET, XtNcallback, select_page_callback,
+ (XtPointer) NULL);
+ /* for scrolling the list */
+ XtAddCallback(viewport, XtNreportCallback, xaw_SendReportProc,
+ (XtPointer) NULL);
+ XtAddEventHandler(LIST_WIDGET,
+ ButtonPressMask | ButtonReleaseMask | Button2MotionMask,
+ False, mark_page_callback, (XtPointer)NULL);
+
+ if (resource.pagelist_highlight_current)
+ XtAddEventHandler(LIST_WIDGET,
+ ButtonPressMask | ButtonReleaseMask | PointerMotionMask | LeaveWindowMask,
+ False, highlight_page_callback, (XtPointer)NULL);
+
+
+ XtAddEventHandler(LIST_WIDGET, ButtonPressMask | ButtonReleaseMask,
+ False, wheel_scroll_list_callback, (XtPointer)NULL);
+
+
+ XtAddEventHandler(LIST_WIDGET,
+ /* FIXME: We should add PointerMotionMask here, but handling PointerMotionMask
+ currently doesn't work with the Xaw list widget: the auto-scrolling code doesn't
+ realize when the mouse direction of the pointer movement changes, and continues
+ to scroll into the same direction. This will be rather annoying for users, so
+ we disabled PointerMotionMask for the time being.
+ */
+ ButtonReleaseMask /* | PointerMotionMask */ | Button1MotionMask,
+ False, xaw_drag_page_callback, (XtPointer)NULL);
+}
+
+static void
+xaw_toggle_label(Widget w, int idx, Boolean update)
+{
+ if (w == NULL)
+ return;
+
+/* ensure_labelinfo_size(idx); */
+ ASSERT(idx < (int)page_info.index_size, "");
+ if (!page_info.index[idx].marked) {
+/* sprintf(toc[idx], "* %*d ", get_page_size(), page_index[idx].number); */
+ sprintf(page_info.page_labels[idx], pageno_format, '*', get_page_size(),
+ resource.use_tex_pages ? page_info.index[idx].number : idx + 1);
+ page_info.index[idx].marked = True;
+ }
+ else {
+ sprintf(page_info.page_labels[idx], pageno_format, ' ', get_page_size(),
+ resource.use_tex_pages ? page_info.index[idx].number : idx + 1);
+/* sprintf(toc[idx], " %*d ", get_page_size(), page_index[idx].number); */
+ page_info.index[idx].marked = False;
+ }
+
+ if (update)
+ xaw_update_list();
+}
+
+static int
+xaw_maybe_scroll_pagelist(int new_page, Boolean force_recenter, int idx_bak)
+{
+ Position x;
+ Position y, new_y, bot_y;
+ Dimension view_height, row_height, internal_height;
+ /* Dimension clip_height; */
+ /* static Widget list_clip = 0; */
+
+ if (LIST_WIDGET == NULL || (resource.expert_mode & XPRT_SHOW_BUTTONS) == 0)
+ return idx_bak;
+
+/* if (list_clip == 0) { */
+/* list_clip = XtNameToWidget(viewport, "clip"); */
+/* } */
+/* if (XtIsRealized(list_clip)) */
+/* XtVaGetValues(list_clip, XtNheight, &clip_height, XtNx, &cx, XtNy, &y1, NULL); */
+ if (viewport != NULL && XtIsRealized(viewport))
+ XtVaGetValues(viewport, XtNheight, &view_height, XtNx, &x, NULL);
+/* fprintf(stderr, "diff: %d, %d, %d, %d, %d\n", cx - x, clip_height, view_height, y1, (int)y2); */
+ xaw_get_row_height(LIST_WIDGET, &row_height, &internal_height);
+ y = row_height * new_page;
+
+#if DEBUG
+ fprintf(stderr, "###### xaw_maybe_scroll_pagelist: y %d, view_y %d, view_height %d, row_height %d, internal_height %d; actual %d\n",
+ y, view_y, view_height, row_height, internal_height, idx_bak);
+#endif
+ /*FIXME: when page list is destroyed, view_y will be 0 until user scrolls page list */
+ bot_y = view_y + view_height;
+ if (force_recenter || ((y >= bot_y - row_height))) {
+#if DEBUG
+ fprintf(stderr, "scrolled below bottom; incrementing %d to %d\n", view_y, view_y + row_height);
+#endif
+ y += row_height;
+ XawViewportSetCoordinates(viewport, x, y - view_height > 0 ? y - view_height : 0);
+ return new_page + 1;
+ }
+ else if (force_recenter || ((y <= view_y + row_height + internal_height))) {
+#if DEBUG
+ fprintf(stderr, "scrolled over top; new_y: %d\n", y - row_height);
+#endif
+ new_y = y - 2 * row_height;
+ XawViewportSetCoordinates(viewport, x, new_y);
+ return new_page - 1;
+ }
+ /* not scrolled */
+ return -2;
+}
+
+#endif /* MOTIF */
+
+
+/* idx is C-style index (0-based), not Motif one (1-based) */
+static void
+toggle_label(Widget widget, int idx, Boolean update)
+{
+ if (idx >= total_pages)
+ return;
+ ASSERT(idx < total_pages, "");
+ ASSERT(idx >= 0, "");
+#ifdef MOTIF
+ xm_toggle_label(widget, idx, update);
+#else
+ xaw_toggle_label(widget, idx, update);
+#endif
+}
+
+
+void
+list_toggle_marks(int arg)
+{
+
+ int i;
+
+ if (arg < 0) { /* mark all */
+ for (i = 0; i < total_pages; i++) {
+ ASSERT(i < (int)page_info.index_size, "");
+/* ensure_labelinfo_size(i); */
+ if (!page_info.index[i].marked) {
+ toggle_label(LIST_WIDGET, i, False);
+ }
+ }
+ }
+ else if (arg == 0) { /* unmark all */
+ for (i = 0; i < total_pages; i++) {
+ ASSERT(i < (int)page_info.index_size, "");
+/* ensure_labelinfo_size(i); */
+ if (page_info.index[i].marked) {
+ toggle_label(LIST_WIDGET, i, False);
+ }
+ }
+ }
+ else { /* toggle odd/even */
+ if (arg == 2) /* toggle even */
+ arg = 0;
+ for (i = 0; i < total_pages; i++) {
+ if ((i + 1) % 2 == arg) {
+ toggle_label(LIST_WIDGET, i, False);
+ }
+ }
+ }
+ /* TODO: update widget once for Motif as well! */
+#ifndef MOTIF
+ xaw_update_list();
+#endif
+}
+
+static Boolean PagelistInitialized = False;
+
+#ifndef MOTIF
+void
+handle_pagelist_resize(void)
+{
+ /* TODO: the following will mess up the geometry of the list
+ (doesn't increase height, and incrementally decreases width):
+ if (list_widget) {
+ Dimension height;
+ --- without the (un)manage, I get an X Error:
+ XtMakeGeometryRequest - parent has no geometry manager
+ ---
+ XtUnmanageChild(viewport);
+ XtUnmanageChild(LIST_WIDGET);
+ XtVaGetValues(globals.widgets.clip_widget, XtNheight, &height, NULL);
+ height -= resource.btn_top_spacing + resource.btn_border_width + global_y_pos;
+ XtVaSetValues(viewport, XtNheight, height, NULL);
+ XtManageChild(LIST_WIDGET);
+ XtManageChild(viewport);
+ }
+ ... so we use brute force instead: */
+ handle_destroy_pagelist(LIST_WIDGET, NULL, NULL);
+ create_pagelist();
+}
+
+void
+handle_destroy_pagelist(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ if (viewport != NULL) {
+ XtDestroyWidget(viewport);
+ viewport = NULL;
+ LIST_WIDGET = NULL;
+ }
+ PagelistInitialized = False;
+}
+#endif /* MOTIF */
+
+void
+create_pagelist(void)
+{
+ Pixel background, foreground;
+#ifdef MOTIF
+
+/* items = xrealloc(items, sizeof *items * (total_pages + 2)); */
+ init_pagelabels(0, total_pages);
+ xm_set_page_labels();
+ if (!PagelistInitialized) {
+ XtAppContext app;
+
+ XtVaGetValues(LIST_WIDGET, XmNforeground, &foreground, XmNbackground, &background, NULL);
+ m_page_gc.back = set_or_make_gc(NULL, GXcopy, background, foreground);
+ m_page_gc.fore = set_or_make_gc(NULL, GXcopy, foreground, background);
+ XtManageChild(LIST_WIDGET);
+
+ XtAddCallback(LIST_WIDGET, XmNbrowseSelectionCallback, select_page_callback, NULL);
+#if !defined(LESSTIF_VERSION)
+ /*
+ Don't use the highlighting hack with LessTif, since its XmListPosToBounds()
+ is too broken to be usable (as of 0.93.36):
+ - it returns generally too low values, apparently it doesn't take
+ XmNlistSpacing into account;
+ - it doesn't take scrollbar position into account.
+ */
+ if (resource.pagelist_highlight_current)
+ XtAddEventHandler(LIST_WIDGET,
+ ButtonPressMask | ButtonReleaseMask | PointerMotionMask | LeaveWindowMask,
+ False, highlight_page_callback, (XtPointer)NULL);
+#endif /* !defined(LESSTIF_VERSION) */
+ XtAddEventHandler(LIST_WIDGET, ButtonPressMask | ButtonReleaseMask,
+ False, wheel_scroll_list_callback, (XtPointer)NULL);
+
+ app = XtWidgetToApplicationContext(globals.widgets.top_level);
+ XtAppAddActions(app, CustomListActions, XtNumber(CustomListActions));
+ XtOverrideTranslations(LIST_WIDGET, XtParseTranslationTable(motif_custom_translations));
+ PagelistInitialized = True;
+ }
+#else /* MOTIF */
+ if ((resource.expert_mode & XPRT_SHOW_BUTTONS) == 0) {
+ PagelistInitialized = False; /* might need to re-create widgets in this case */
+ return;
+ }
+
+ if (globals.debug & DBG_GUI)
+ fprintf(stderr, "allocating list with %d pages\n", total_pages);
+
+ init_pagelabels(0, total_pages);
+ if (!PagelistInitialized) {
+ xaw_create_pagelist();
+ XtVaGetValues(LIST_WIDGET, XtNforeground, &foreground, XtNbackground, &background, NULL);
+ m_page_gc.back = set_or_make_gc(NULL, GXcopy, background, foreground);
+ m_page_gc.fore = set_or_make_gc(NULL, GXcopy, foreground, background);
+ PagelistInitialized = True;
+ }
+#endif /* MOTIF */
+ /* scroll to the current page if needed */
+ maybe_scroll_pagelist(current_page, False);
+}
+
+#ifndef MOTIF
+static void
+free_pagelabels(void)
+{
+ int i;
+ for (i = 0; page_info.page_labels != NULL && page_info.page_labels[i] != NULL; i++) {
+ free(page_info.page_labels[i]);
+ }
+ free(page_info.page_labels);
+ page_info.page_labels = NULL;
+}
+#endif /* not MOTIF */
+
+
+void
+refresh_pagelist(int newsize, int newpage)
+{
+ if (
+#ifndef MOTIF
+ (resource.expert_mode & XPRT_SHOW_BUTTONS) == 0 ||
+#endif
+ !XtIsRealized(globals.widgets.top_level))
+ return;
+
+#ifdef DEBUG
+ fprintf(stderr, "=== refresh_pagelist: newsize %d, newpage %d\n", newsize, newpage);
+#endif
+#ifdef MOTIF
+/* items = xrealloc(items, sizeof *items * (newsize + 2)); */
+ init_pagelabels(0, newsize);
+ xm_set_page_labels();
+#else /* MOTIF */
+ if ((resource.expert_mode & XPRT_SHOW_BUTTONS) == 0)
+ return;
+
+ /* FIXME - is this really neccessary?? The alternative:
+ XawListChange(LIST_WIDGET, page_info.page_labels, newsize, 0, True);
+ has problems when freeing the page labels afterwards.
+ */
+ handle_destroy_pagelist(LIST_WIDGET, NULL, NULL);
+
+ free_pagelabels();
+ init_pagelabels(0, newsize);
+
+ xaw_create_pagelist();
+#endif /* MOTIF */
+ /* `True' since the pagelist is newly created */
+ maybe_scroll_pagelist(newpage, True);
+}
+
+void
+maybe_scroll_pagelist(int newpage, Boolean force_recenter)
+{
+#ifdef MOTIF
+ int top_visible, bot_visible;
+ UNUSED(force_recenter);
+#endif
+
+ if (
+#ifndef MOTIF
+ (resource.expert_mode & XPRT_SHOW_BUTTONS) == 0 ||
+#endif
+ !XtIsRealized(globals.widgets.top_level))
+ return;
+
+#ifdef MOTIF
+ XmListSelectPos(LIST_WIDGET, newpage + MOTIF_IDX_OFFSET, False);
+
+ top_visible = xm_get_top_visible(1);
+ bot_visible = xm_get_bottom_visible(top_visible);
+
+ xm_maybe_scroll_pagelist(newpage, CLICK, &top_visible, &bot_visible);
+#if HAVE_XPM
+ tb_check_navigation_sensitivity(current_page);
+#endif
+#else
+
+ if (LIST_WIDGET == NULL)
+ return;
+
+ (void)xaw_maybe_scroll_pagelist(newpage + 1, force_recenter, 0);
+
+ XawListHighlight(LIST_WIDGET, newpage);
+#if REDRAW_CURRENT_MARKER_HACK
+ /* if the XawListHighlight happens adjacent to the page that was
+ last highlighted with our home-made `current selected'
+ rectangle, it might overdraw that rectangle. In this case,
+ restore it:
+ */
+ xaw_maybe_redraw_current_marker(newpage);
+#endif
+#endif
+}
+
+#ifdef MOTIF
+static void
+set_all_marks(int from, int to)
+{
+ int i;
+ for (i = from; i < to; i++) {
+/* ensure_labelinfo_size(i); */
+ page_info.index[i].marked = True;
+ toggle_label(LIST_WIDGET, i, False);
+ }
+}
+
+static void
+internal_process_button2_drag(Widget widget, XEvent *event)
+{
+ int i, idx, min = total_pages, max = 0;
+ idx = get_item_index(widget, event->xbutton.y);
+
+ for (i = 0; i < total_pages; i++) {
+/* ensure_labelinfo_size(i); */
+ if (page_info.index[i].marked && i > max)
+ max = i;
+ }
+ for (i = total_pages; i > 0; i--) {
+/* ensure_labelinfo_size(i); */
+ if (page_info.index[i].marked && i < min)
+ min = i;
+ }
+
+ if (min == total_pages)
+ min = 0;
+ if (max == 0)
+ max = total_pages;
+
+ if (idx < min) {
+ set_all_marks(idx, min);
+ }
+ else if (idx > max) {
+ set_all_marks(max + 1, idx);
+ }
+ else {
+ set_all_marks(0, idx);
+ }
+}
+#endif /* MOTIF */
+
+static void
+internal_process_button2(Widget widget, XEvent *event)
+{
+ int curr_idx;
+ static int prev_idx = 0;
+#ifndef MOTIF
+ static int actual_idx = -2;
+#endif
+ static int top_visible = 0, bot_visible = 0;
+ static int prev_y = 0, curr_y = 0;
+ static saveCmdT prev_cmd = 0; /* previous command (CLICK/SCROLL_UP/SCROLL_DOWN) */
+ static saveCmdT curr_cmd = 0; /* current command (CLICK/SCROLL_UP/SCROLL_DOWN) */
+ static saveCmdT bak_cmd = 0; /* last command that started inside the pagelist (CLICK/SCROLL_UP/SCROLL_DOWN) */
+ static Boolean change_scroll_direction = False;
+
+ switch(event->xany.type) {
+ case ButtonPress:
+ prev_y = event->xbutton.y;
+ prev_idx = curr_idx = get_item_index(widget, prev_y);
+#ifdef MOTIF
+ top_visible = xm_get_top_visible(1);
+ bot_visible = xm_get_bottom_visible(top_visible);
+#endif
+ toggle_label(widget, curr_idx - 1, True);
+ prev_cmd = CLICK;
+#ifdef MOTIF
+ xm_maybe_scroll_pagelist(curr_idx - 1, CLICK, &top_visible, &bot_visible);
+#else
+ actual_idx = xaw_maybe_scroll_pagelist(curr_idx, False, actual_idx);
+#endif
+ break;
+ case ButtonRelease:
+ prev_cmd = CLICK;
+ break;
+ case MotionNotify:
+ curr_y = (int)event->xmotion.y;
+ curr_idx = get_item_index(widget, event->xmotion.y);
+#ifndef MOTIF
+ if (actual_idx > 0) {
+ curr_idx = actual_idx;
+ }
+#endif
+
+ if (curr_y < prev_y)
+ curr_cmd = SCROLL_UP;
+ else if (curr_y > prev_y)
+ curr_cmd = SCROLL_DOWN;
+ prev_y = curr_y;
+
+ if (prev_cmd != CLICK && curr_cmd != prev_cmd)
+ change_scroll_direction = True;
+
+ if ((curr_idx != prev_idx && !change_scroll_direction)
+ || (change_scroll_direction
+ /* last or first visible are always spared, unless they are really
+ the first or last page; this way, always 1 more page is visible
+ than is currently marked/selected
+ */
+ && !(curr_idx == top_visible) && !(curr_idx == bot_visible))) {
+ if (curr_idx <= 0) {
+ /* When user has scrolled off, mark this by setting curr_idx to 1 more or less
+ than the pagelist has so that the last/first page don't oscillate between
+ marked/unmarked state when user continues to scroll.
+ Also, we continue scrolling as long as user drags in the same direction as
+ the last `real' scrolling event (saved as bak_cmd).
+ */
+ if (curr_cmd == SCROLL_DOWN && bak_cmd == SCROLL_DOWN && prev_idx <= total_pages) {
+ curr_idx = prev_idx + 1;
+ }
+ else if (curr_cmd == SCROLL_UP && bak_cmd == SCROLL_UP && prev_idx > 0) {
+ curr_idx = prev_idx - 1;
+ }
+ }
+
+
+ if (curr_idx > 0 && curr_idx <= total_pages) {
+ toggle_label(widget, curr_idx - 1, True);
+#ifdef MOTIF
+ xm_maybe_scroll_pagelist(curr_idx - 1, curr_cmd, &top_visible, &bot_visible);
+#else
+ actual_idx = xaw_maybe_scroll_pagelist(curr_idx, False, actual_idx);
+#endif
+ prev_idx = curr_idx;
+ bak_cmd = curr_cmd;
+ change_scroll_direction = False;
+ }
+ else {
+#ifndef MOTIF
+ if (curr_idx > total_pages)
+ actual_idx = -2;
+ else
+ actual_idx = xaw_maybe_scroll_pagelist(curr_idx, False, actual_idx);
+#endif
+ }
+ prev_cmd = curr_cmd;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void
+list_toggle_current(int arg)
+{
+ toggle_label(LIST_WIDGET, arg, True);
+
+ if (pageinfo_have_marked_pages()) {
+ notify_print_dialog_have_marked(True);
+ }
+ else {
+ notify_print_dialog_have_marked(False);
+ }
+}
+
+#ifdef MOTIF
+
+static void
+xm_list_set_mark(Widget widget,
+ XEvent *event,
+ String *params,
+ Cardinal *num_params)
+{
+ UNUSED(params);
+
+ if ((*num_params != 1) || !XmIsList(widget))
+ return;
+
+ internal_process_button2(widget, event);
+
+ if (pageinfo_have_marked_pages()) {
+ notify_print_dialog_have_marked(True);
+ }
+ else {
+ notify_print_dialog_have_marked(False);
+ }
+}
+
+static void
+xm_list_drag_mark(Widget widget,
+ XEvent *event,
+ String *params,
+ Cardinal *num_params)
+{
+ UNUSED(params);
+
+ if ((*num_params != 1) || !XmIsList(widget))
+ return;
+
+ internal_process_button2_drag(widget, event);
+
+ if (pageinfo_have_marked_pages()) {
+ notify_print_dialog_have_marked(True);
+ }
+ else {
+ notify_print_dialog_have_marked(False);
+ }
+}
+
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/pagesel.h b/Build/source/texk/xdvik/gui/pagesel.h
new file mode 100644
index 00000000000..aad1b591456
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/pagesel.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2001-2004 the xdvik development team
+ *
+ * Page selector for xdvi
+ *
+ * Copyright (c) 1993, 1995
+ * MATSUURA Syun syun@fuka.info.waseda.ac.jp
+ * HIRAHARA Atsushi hirahara@fuka.info.waseda.ac.jp
+ * ONO Kouichi onono@fuka.info.waseda.ac.jp
+ *
+ * All rights reserved.
+ */
+
+/* SU: I was unsure how to interpret the `All rights reserved' in the
+ * previous line, so emailed Ono Kouichi about this. Here's (the
+ * relevant part of) his answer (which was CC'ed to Hirahara Atsushi -
+ * all three of them had left Waseda university around '95):
+ *
+ * You can modify, embed, copy and distribute a part of or the
+ * entire of our source code when you specify our copyright in your
+ * xdvik version.
+ *
+ * IANAL, but I think this is compatible with the X consortium
+ * license as specified in the other files.
+ */
+
+#ifndef PAGESEL_H_
+#define PAGESEL_H_
+
+#include "xdvi.h"
+
+extern void refresh_pagelist(int newsize, int newpage);
+extern void maybe_scroll_pagelist(int newpage, Boolean force_recenter);
+extern void create_pagelist(void);
+extern void list_toggle_current(int arg);
+extern void list_toggle_marks(int arg);
+
+# ifdef MOTIF
+extern Widget page_list;
+extern void toggle_pagelist(void);
+# else
+extern int xaw_get_pagelist_size(void);
+extern void xaw_create_pagelist_widgets(Dimension height, Dimension width, Position y, Widget parent);
+extern void handle_destroy_pagelist(Widget w, XtPointer client_data, XtPointer call_data);
+extern void handle_pagelist_resize(void);
+# endif
+
+/* pageinfo access methods */
+extern long pageinfo_get_offset(int page);
+extern int pageinfo_get_number(int page);
+extern int pageinfo_get_index_of_number(int number);
+
+extern unsigned int pageinfo_get_page_width(int page);
+extern unsigned int pageinfo_get_page_height(int page);
+extern unsigned int pageinfo_get_window_width(int page);
+extern unsigned int pageinfo_get_window_height(int page);
+
+extern void pageinfo_set_page_width(int page, unsigned int width);
+extern void pageinfo_set_page_height(int page, unsigned int height);
+extern void pageinfo_set_window_width(int page, unsigned int width);
+extern void pageinfo_set_window_height(int page, unsigned int height);
+
+extern void pageinfo_set_offset(int index, long offset);
+extern void pageinfo_set_number(int index, int number);
+
+extern void pageinfo_allocate(int total_pages);
+extern void pageinfo_deallocate(void);
+extern Boolean pageinfo_is_marked(int i);
+extern Boolean pageinfo_have_marked_pages(void);
+
+#endif /* PAGESEL_H_ */
diff --git a/Build/source/texk/xdvik/gui/print-dialog.c b/Build/source/texk/xdvik/gui/print-dialog.c
new file mode 100644
index 00000000000..c7187be6100
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/print-dialog.c
@@ -0,0 +1,2973 @@
+/*
+ * Copyright (c) 2002-2004 Paul Vojta and the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ SU: Adapted from non-k xdvi's popups.c
+
+ This implements a print popup (and a `save to file' popup). My idea
+ was to use the same window layout framework for both tasks, since
+ there's a big overlap in the widgets needed. However after looking
+ at the mess I've created, I'm no longer convinced this was a good
+ idea. (I reckon it's slightly better than the code duplication when
+ doing it in separate files, but only *slightly* ...)
+
+ We need a more intelligent approach that bans this ugly kind of
+ `data proliferation' (those global arrays of widgets and helper
+ structures). Custom Widgets? Factory methods? Needs investigation.
+
+ Also, in the long run, I guess we want the `Save' window to be more
+ similar to the file browser (i.e. to contain a file browser e.g.
+ in the upper part); in that case, the code will be moved into another
+ module anyway.
+
+ Moreover, the GUI code should be completely separated from the backend
+ code.
+*/
+
+#include <string.h>
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "my-vsnprintf.h"
+#include <ctype.h>
+
+#include "print-dialog.h"
+#include "print-log.h"
+#include "print-internal.h"
+#include "events.h"
+#include "dvi-init.h"
+#include "string-utils.h"
+#include "util.h"
+#include "x_util.h"
+#include "message-window.h"
+#include "pagesel.h"
+#include "my-snprintf.h"
+#include "sfSelFile.h"
+#include "dvisel.h" /* for select_marked_pages() */
+#include "xlwradio.h"
+#include "statusline.h"
+#include "search-dialog.h"
+#include "search-internal.h"
+#include "special.h"
+
+/* Xlib and Xutil are already included */
+
+
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+
+#ifdef MOTIF
+# include <Xm/BulletinB.h>
+# include <Xm/DialogS.h>
+# include <Xm/PanedW.h>
+# include <Xm/MessageB.h>
+# include <Xm/LabelG.h>
+# include <Xm/Form.h>
+# include <Xm/Frame.h>
+# include <Xm/ToggleBG.h>
+# include <Xm/Text.h>
+# include <Xm/TextF.h>
+# include <Xm/PushB.h>
+# include <Xm/Protocols.h>
+# include <Xm/AtomMgr.h>
+#define XTranslations XmNtranslations
+#else /* MOTIF */
+# include <X11/Shell.h>
+# include <X11/Xaw/Paned.h>
+# include <X11/Xaw/Box.h>
+# include <X11/Xaw/Form.h>
+# include <X11/Xaw/Label.h>
+# include <X11/Xaw/Command.h>
+# include <X11/Xaw/Toggle.h>
+# include <X11/Xaw/AsciiText.h>
+# include <X11/Xaw/SimpleMenu.h>
+# include <X11/Xaw/MenuButton.h>
+# include <X11/Xaw/Sme.h>
+# include <X11/Xaw/SmeBSB.h>
+#if 0
+#include "xaw_bitmaps.h"
+static Pixmap menu_double_arrow_bitmap;
+#endif
+#define XTranslations XtNtranslations
+#endif /* MOTIF */
+
+struct output_format_mapping {
+ const char *fmt_string;
+ outputFormatT fmt;
+ const char *extension;
+} output_format_mapping[] = {
+ { "Postscript", FMT_PS , ".ps" },
+ { "PDF", FMT_PS2PDF, ".pdf" },
+ { "DVI", FMT_DVI, ".dvi" },
+ { "Plain Text (ISO_8859-1)",FMT_ISO_8859_1, ".txt" },
+ { "Plain Text (UTF-8)", FMT_UTF8, ".txt" },
+ { NULL, FMT_NONE, NULL }
+};
+
+typedef enum printRadioT_ {
+ NO_PRINT_VAL = -1,
+ PRINT_TO_PRINTER = 1,
+ PRINT_TO_FILE,
+ SAVE_TO_FILE
+} printRadioT;
+
+
+typedef enum pageRadioT_ {
+ NO_PAGE_VAL = -1,
+ PRINT_ALL = 1,
+ PRINT_MARKED,
+ PRINT_RANGE,
+ SAVE_ALL,
+ SAVE_MARKED,
+ SAVE_RANGE
+} pageRadioT;
+
+static Boolean is_print_button(pageRadioT flag) {
+ return (flag <= PRINT_RANGE);
+}
+
+struct dialog_info {
+ char *printer_name;
+ char *file_name;
+ /* fully canonicalized filename, not visible in window, but used in error messages.
+ It is either NULL, or a malloc()ed buffer (which is free()d immediately before use). */
+ char *expanded_filename;
+ char *dvips_options;
+ char *from_page;
+ char *to_page;
+ printRadioT print_radio;
+ pageRadioT range_radio;
+ outputFormatT output_format;
+};
+
+/*
+ global widgets, and arrays of global widgets (mosly, one
+ for the printing and one for the saving dialog). Needs
+ cleanup!
+*/
+
+#define FORMAT_SEL_CNT 5
+
+/* top-level widgets: one for printing, one for saving to file */
+static Widget print_shell = NULL;
+static Widget save_shell = NULL;
+
+/* global structures for saving print info between invocations */
+static struct dialog_info save_pr_info = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NO_PRINT_VAL, NO_PAGE_VAL, FMT_NONE
+};
+static struct dialog_info save_save_info = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NO_PRINT_VAL, NO_PAGE_VAL, FMT_NONE
+};
+
+/*
+ these contain the currently selected values, or defaults;
+ used in communication between callbacks
+*/
+static struct dialog_info curr_pr_info = {
+ NULL, NULL, NULL, NULL, NULL, NULL, PRINT_TO_PRINTER, PRINT_ALL, FMT_NONE
+};
+static struct dialog_info curr_save_info = {
+ NULL, NULL, NULL, NULL, NULL, NULL, SAVE_TO_FILE, SAVE_ALL, FMT_NONE
+};
+
+static void print_precheck1(XtPointer info);
+static void print_precheck2(XtPointer info);
+
+/* access methods ... */
+const char *
+get_printer_options(void)
+{
+ return save_pr_info.printer_name;
+}
+
+char *
+get_dvips_options(printOrSaveActionT act)
+{
+ if (act == FILE_PRINT)
+ return save_pr_info.dvips_options;
+ else
+ return save_save_info.dvips_options;
+}
+
+#ifdef MOTIF
+static Widget from_label[FILE_ALL] = { None, None };
+static Widget format_selection_option;
+XmString format_selection_texts[FORMAT_SEL_CNT];
+
+#else /* MOTIF */
+
+static Widget format_selection_label;
+static Widget format_selection_button;
+#if 0
+static Widget format_selection_b1;
+#endif
+static Widget format_selection_popup;
+static Widget format_selection_menu[FORMAT_SEL_CNT];
+
+static void xaw_print_save_act_go(Widget, XEvent *, String *, Cardinal *);
+
+#endif /* MOTIF */
+
+static void print_cancel(Widget, XEvent *, String *, Cardinal *);
+static void save_cancel(Widget, XEvent *, String *, Cardinal *);
+
+static Widget to_printer_radio;
+static Widget to_file_radio_or_label[FILE_ALL] = { None, None };
+static Widget to_label[FILE_ALL] = { None, None };
+static Widget of_label[FILE_ALL] = { None, None };
+static Widget range_all_radio[FILE_ALL] = { None, None };
+static Widget range_marked_radio[FILE_ALL] = { None, None };
+static Widget range_from_to_radio[FILE_ALL] = { None, None };
+static Widget cancel_button[FILE_ALL] = { None, None };
+static Widget ok_button[FILE_ALL] = { None, None };
+static Widget print_to_printer_text;
+static Widget print_to_file_text[FILE_ALL] = { None, None };
+static Widget print_to_file_button[FILE_ALL] = { None, None };
+static Widget dvips_options_text[FILE_ALL] = { None, None };
+static Widget page_from_text[FILE_ALL] = { None, None };
+static Widget page_to_text[FILE_ALL] = { None, None };
+
+static int print_is_active = False; /* False if window is unmanaged or not created yet, True if managed */
+static int save_is_active = False; /* False if window is unmanaged or not created yet, True if managed */
+
+
+static XtActionsRec print_actions[] = {
+#ifndef MOTIF
+ {"saveInternal", xaw_print_save_act_go },
+ {"printInternal", xaw_print_save_act_go},
+#endif
+ {"WM_print_cancel", print_cancel },
+ {"WM_save_cancel", save_cancel },
+};
+
+/*
+ ============================================================
+ generic utility functions
+ ============================================================
+*/
+
+/*
+ Return the printer name, eventually followed by `-P$PRINTER',
+ since the `-o' option of dvips doesn't evaluate the environment
+ variable.
+*/
+static char *
+get_printer_name(void)
+{
+ char *printcmd, *printer;
+
+ if (resource.dvips_printer_str != NULL && strlen(resource.dvips_printer_str) > 0) {
+ return xstrdup(resource.dvips_printer_str);
+ }
+ printcmd = xstrdup("lpr");
+ printer = getenv("PRINTER");
+ if (printer != NULL) {
+ printcmd = xstrcat(printcmd, " -P");
+ printcmd = xstrcat(printcmd, printer);
+ }
+ return printcmd;
+}
+
+/* return basename of `old_name' with `old_ext' replaced by `new_ext', in fresh memory */
+static char *
+get_new_file_name(const char *old_name, const char *old_ext, const char *new_ext)
+{
+ /* old_name contains the normalized DVI file name, with path and extension */
+ char *basename, *new_name;
+ size_t len;
+
+ basename = strrchr(old_name, DIR_SEPARATOR);
+
+ if (basename != NULL) {
+ basename++;
+ new_name = xmalloc(strlen(basename) + strlen(new_ext) + 1);
+ new_name = strcpy(new_name, basename);
+ }
+ else {
+ new_name = xmalloc(strlen(old_name) + strlen(new_ext) + 1);
+ new_name = strcpy(new_name, old_name);
+ }
+
+ len = strlen(new_name);
+ strcpy(new_name + len - strlen(old_ext), new_ext);
+ return new_name;
+}
+
+/*
+ * Translate `non-standard' paper sizes for xdvi into options suitable
+ * for dvips. We don't do this always, since it would override the papersize
+ * specials inserted by e.g.
+ * \usepackage[dvips]{geometry}
+ * which is the preferred way to specify the papersize. If the papersize
+ * has been explicitly set by such a special, this function returns NULL.
+ * Else it returns the value of the `paper' resource, without the trailing
+ * `r', and sets the `landscape' argument to True if a trailing `r' was
+ * present.
+ *
+ * Note that we don't check/warn about whether the current paper
+ * resource is valid for dvips; dvips will ignore invalid paper sizes.
+ */
+static char *
+get_dvips_papersize(Boolean *landscape)
+{
+ char *papersize;
+ if (have_papersize_special())
+ return NULL;
+
+ papersize = xstrdup(resource.paper);
+ *landscape = False;
+ if (papersize[strlen(papersize) - 1] == 'r') { /* landscape size */
+ papersize[strlen(papersize) - 1] = '\0';
+ *landscape = True;
+ }
+ TRACE_GUI((stderr, "Using dvips arguments: `%s', %s", papersize, *landscape ? "landscape" : "portrait"));
+ return papersize;
+}
+
+static void
+set_outfile_name(struct dialog_info *info, struct dialog_info *save_info, printOrSaveActionT act)
+{
+ free(info->file_name);
+ if (act == FILE_PRINT) {
+ info->file_name = get_new_file_name(globals.dvi_name, ".dvi", ".ps");
+ }
+ else { /* saving to file */
+ if (save_info->range_radio == SAVE_ALL) {
+ info->file_name = get_new_file_name(globals.dvi_name, ".dvi",
+ output_format_mapping[resource.default_saving_format].extension);
+ }
+ else {
+ char *tmp = xstrdup("_pp");
+ tmp = xstrcat(tmp, output_format_mapping[resource.default_saving_format].extension);
+
+ info->file_name = get_new_file_name(globals.dvi_name, ".dvi", tmp);
+ free(tmp);
+ }
+ }
+}
+
+/* get initial values for dialog texts */
+static void
+get_initial_dialog_values(struct dialog_info *info, printOrSaveActionT act)
+{
+ if (act == FILE_PRINT && info->printer_name == NULL)
+ info->printer_name = get_printer_name();
+
+ if (info->dvips_options == NULL) {
+ info->dvips_options = xstrdup("");
+
+ /* add -t option if not already present */
+ if (resource.dvips_options_str != NULL
+ && strstr(resource.dvips_options_str, "-t ") == NULL) {
+ Boolean dvips_landscape = False;
+ char *dvips_paper_size = get_dvips_papersize(&dvips_landscape);
+ if (dvips_paper_size != NULL) {
+ info->dvips_options = xstrdup("-t ");
+ info->dvips_options = xstrcat(info->dvips_options, dvips_paper_size);
+ free(dvips_paper_size);
+ if (dvips_landscape) {
+ info->dvips_options = xstrcat(info->dvips_options, " -t landscape");
+ }
+ }
+ }
+
+ if (resource.dvips_options_str != NULL) {
+ if (strlen(info->dvips_options) > 0)
+ info->dvips_options = xstrcat(info->dvips_options, " ");
+ info->dvips_options = xstrcat(info->dvips_options, resource.dvips_options_str);
+ }
+ }
+
+ if (info->from_page == NULL) {
+ info->from_page = xmalloc(LENGTH_OF_INT + 1);
+ sprintf(info->from_page, "%d", current_page + globals.pageno_correct);
+ }
+
+ if (info->to_page == NULL) {
+ info->to_page = xmalloc(LENGTH_OF_INT + 1);
+ sprintf(info->to_page, "%d", current_page + globals.pageno_correct);
+ }
+}
+
+
+#if MOTIF
+static void
+set_sensitivity(int i)
+{
+ Boolean sensitivity;
+
+/* if (i == curr_pr_info.print_radio) /\* if no change *\/ */
+/* return; */
+
+ curr_pr_info.print_radio = i;
+
+ sensitivity = (i == PRINT_TO_PRINTER);
+ XtSetSensitive(print_to_printer_text, sensitivity);
+
+/* sensitivity ^= (True ^ False); */
+ XtSetSensitive(print_to_file_text[FILE_PRINT], !sensitivity);
+ XtSetSensitive(print_to_file_button[FILE_PRINT], !sensitivity);
+}
+#endif /* MOTIF */
+
+static void
+update_dvips_options_sensitivity(int idx, Widget top)
+{
+ Widget dvips_label;
+
+#if MOTIF
+ Widget dvips_options;
+
+ if (get_widget_by_name(&dvips_label, top, "dvips_options_name", True) &&
+ get_widget_by_name(&dvips_options, top, "dvips_options_text", True)) {
+ if (output_format_mapping[idx].fmt == FMT_PS ||
+ output_format_mapping[idx].fmt == FMT_PS2PDF) {
+ XtSetSensitive(dvips_label, True);
+ XtSetSensitive(dvips_options, True);
+ }
+ else {
+ XtSetSensitive(dvips_label, False);
+ XtSetSensitive(dvips_options, False);
+ }
+ }
+#else
+ if (get_widget_by_name(&dvips_label, top, "dvips_options_name", True)) {
+ XtSetSensitive(XtParent(dvips_label),
+ output_format_mapping[idx].fmt == FMT_PS ||
+ output_format_mapping[idx].fmt == FMT_PS2PDF);
+ }
+#endif
+}
+
+/* callbacks */
+
+static void
+select_format_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Widget file_text, top;
+
+ char *filename;
+ int i;
+#ifdef MOTIF
+ Widget f1, f2;
+ char *ptr;
+
+ i = (int)client_data;
+ UNUSED(call_data);
+ f1 = XtParent(w);
+ ASSERT(f1 != 0, "Parent of widget musn't be NULL!\n");
+ f2 = XtParent(f1);
+ ASSERT(f2 != 0, "Parent of f1 musn't be NULL!\n");
+ top = XtParent(f2);
+ ASSERT(top != 0, "Parent of f2 musn't be NULL!\n");
+
+ if ((file_text = XtNameToWidget(top, "*file_text")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"file_text\" widget!"));
+ return;
+ }
+ XtVaGetValues(file_text, XmNvalue, &filename, NULL);
+ if ((ptr = strrchr(filename, '.')) != NULL) {
+ char buf[1024];
+ replace_extension(filename, output_format_mapping[i].extension, buf, sizeof buf);
+ XtVaSetValues(file_text, XmNvalue, buf, NULL);
+ }
+#else /* MOTIF */
+
+ Widget popup, button;
+ char *ptr1, *ptr2;
+ char buf[1024];
+
+ UNUSED(call_data);
+ popup = XtParent(w);
+ ASSERT(popup != 0, "Parent of menu musn't be NULL!\n");
+ button = XtParent(popup);
+ ASSERT(button != 0, "Parent of popup musn't be NULL!\n");
+
+ top = (Widget)client_data;
+
+ if ((file_text = XtNameToWidget(top, "*file_text")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"file_text\" widget!"));
+ return;
+ }
+
+ XtVaGetValues(file_text, XtNstring, &filename, NULL);
+/* fprintf(stderr, "file text: |%s|\n", filename); */
+
+ /* swap title strings */
+ XtVaGetValues(button, XtNlabel, &ptr1, NULL);
+ XtVaGetValues(w, XtNlabel, &ptr2, NULL);
+ strncpy(buf, ptr1, sizeof buf);
+
+ for (i = 0; output_format_mapping[i].fmt_string != NULL; i++) {
+ if (strcmp(ptr2, output_format_mapping[i].fmt_string) == 0) {
+ char buf2[1024];
+ replace_extension(filename, output_format_mapping[i].extension, buf2, sizeof buf2);
+ XtVaSetValues(file_text, XtNstring, buf2, NULL);
+
+ break;
+ }
+ }
+ if (output_format_mapping[i].fmt_string == NULL) {
+ popup_message(get_matching_parent(w, globals.widgets.top_level, "print_popup", "save_popup", NULL),
+ MSG_WARN,
+ REPORT_XDVI_BUG_TEMPLATE,
+ "Unrecognized string in format selector: |%s|", ptr2);
+ }
+ XtVaSetValues(button, XtNlabel, ptr2, NULL);
+ XtVaSetValues(w, XtNlabel, buf, NULL);
+
+#endif /* MOTIF */
+
+ save_save_info.output_format = curr_save_info.output_format = output_format_mapping[i].fmt;
+
+ update_dvips_options_sensitivity(i, save_shell);
+
+ resource.default_saving_format = save_save_info.output_format;
+ set_outfile_name(&save_save_info, &curr_save_info, FILE_SAVE);
+}
+
+static void
+cb_print_cancel(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct save_or_print_info *info = (struct save_or_print_info *)client_data;
+ UNUSED(w);
+ UNUSED(call_data);
+
+ ASSERT(info != NULL, "client_data in cb_print_cancel musn't be NULL!");
+ if (info->message_popup != 0) {
+ kill_message_window(info->message_popup);
+ }
+ XtPopdown(print_shell);
+ print_is_active = False;
+}
+
+static void
+cb_save_cancel(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct save_or_print_info *info = (struct save_or_print_info *)client_data;
+ UNUSED(w);
+ UNUSED(call_data);
+
+ ASSERT(info != NULL, "client_data in cb_save_cancel musn't be NULL!");
+ if (info->message_popup != 0) {
+ kill_message_window(info->message_popup);
+ }
+ XtPopdown(save_shell);
+ save_is_active = False;
+}
+
+static void
+cb_print_or_save(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct save_or_print_info *info = (struct save_or_print_info *)client_data;
+ UNUSED(w);
+ UNUSED(call_data);
+
+ print_precheck1((XtPointer)info);
+}
+
+/* access from outside the module */
+void
+cancel_saving(struct save_or_print_info *info)
+{
+ cb_save_cancel(NULL, info, NULL);
+}
+
+
+static void
+print_cancel(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ struct save_or_print_info *info = NULL;
+ void *ptr;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ ASSERT(*num_params > 0, "params in print_cancel must be > 0!");
+ ASSERT(*params != NULL, "params in print_cancel mustn't be NULL!");
+
+ TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
+ sscanf(*params, "%p", &ptr);
+ info = (struct save_or_print_info *)ptr;
+
+ cb_print_cancel(NULL, info, NULL);
+}
+
+static void
+save_cancel(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ struct save_or_print_info *info = NULL;
+ void *ptr;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ ASSERT(*num_params > 0, "params in save_cancel must be > 0!");
+ ASSERT(*params != NULL, "params in save_cancel mustn't be NULL!");
+
+ TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
+ sscanf(*params, "%p", &ptr);
+ info = (struct save_or_print_info *)ptr;
+
+ cb_save_cancel(NULL, info, NULL);
+}
+
+#ifndef MOTIF
+
+/*
+ enable the `print to' button if user presses key or mouse button
+ inside that input field
+*/
+static void
+xaw_print_handle_key(Widget widget, XtPointer closure, XEvent *ev, Boolean *cont)
+{
+ char *number;
+ int i;
+
+ number = (char *)closure;
+ i = atoi(number);
+ ASSERT(i == 2 || i == 3, "Button index should be 2 or 3");
+ UNUSED(widget);
+ UNUSED(ev);
+ UNUSED(cont);
+
+ if (i == 2) {
+ XawToggleSetCurrent(to_printer_radio, (XtPointer)PRINT_TO_PRINTER);
+ }
+ else {
+ ASSERT(to_file_radio_or_label[FILE_PRINT] != NULL, "");
+ XawToggleSetCurrent(to_file_radio_or_label[FILE_PRINT], (XtPointer)PRINT_TO_FILE);
+ }
+}
+
+/*
+ enable the `print range' button if user presses key or mouse button
+ inside that input field
+*/
+static void
+xaw_range_handle_key(Widget widget, XtPointer closure, XEvent *ev, Boolean *cont)
+{
+ printOrSaveActionT act = (printOrSaveActionT)closure;
+ UNUSED(widget);
+ UNUSED(ev);
+ UNUSED(cont);
+
+ if (act == FILE_PRINT && curr_pr_info.range_radio != PRINT_RANGE) {
+ ASSERT(range_all_radio[act] != NULL, "button should have been initialized");
+ XawToggleSetCurrent(range_all_radio[act], (XtPointer)PRINT_RANGE);
+ }
+ else if (act == FILE_SAVE && curr_save_info.range_radio != SAVE_RANGE) {
+ ASSERT(range_all_radio[act] != NULL, "button should have been initialized");
+ XawToggleSetCurrent(range_all_radio[act], (XtPointer)SAVE_RANGE);
+ }
+}
+
+
+static void
+xaw_print_save_act_go(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ struct save_or_print_info *info = NULL;
+ void *ptr;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ ASSERT(*num_params > 0, "params in search_cancel must be > 0!");
+ ASSERT(*params != NULL, "params in search_cancel mustn't be NULL!");
+
+ TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
+ sscanf(*params, "%p", &ptr);
+ info = (struct save_or_print_info *)ptr;
+
+ print_precheck1((XtPointer)info);
+}
+
+#if 0
+static void
+xaw_popup_menu_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Position x, y;
+ Dimension h;
+ int pos_x, pos_y;
+ Window dummy;
+
+ Widget popup = (Widget)client_data;
+ fprintf(stderr, "popup: %p\n", popup);
+ XtVaGetValues(w, XtNx, &x, XtNy, &y, XtNheight, &h, NULL);
+ fprintf(stderr, "x: %d, y: %d, h: %d\n", x, y, h);
+ XTranslateCoordinates(DISP, XtWindow(w), RootWindowOfScreen(SCRN),
+ x, y, &pos_x, &pos_y, &dummy);
+ XtRealizeWidget(popup);
+ /* WRONG - would need to use x position of its left widget ... */
+ XtVaSetValues(popup, XtNx, pos_x, XtNy, pos_y + h + 1, NULL);
+ XtPopup(popup, XtGrabNone);
+}
+#endif /* 0 */
+
+#endif /* not MOTIF */
+
+static void
+cb_print_vs_file(Widget w, XtPointer client_data, XtPointer call_data)
+{
+#ifdef MOTIF
+ Boolean to_printer = False, to_file = False;
+ if (((XmToggleButtonCallbackStruct *)call_data)->set) {
+ if (w == to_printer_radio)
+ to_printer = True;
+ else
+ to_file = True;
+
+ }
+ else {
+ if (w == to_printer_radio)
+ to_file = True;
+ else
+ to_printer = True;
+ }
+
+ XmToggleButtonGadgetSetState(to_file_radio_or_label[FILE_PRINT], to_file, False);
+ XmToggleButtonGadgetSetState(to_printer_radio, to_printer, False);
+
+ set_sensitivity((int)client_data);
+ XmProcessTraversal(curr_pr_info.print_radio == PRINT_TO_PRINTER
+ ? print_to_printer_text
+ : print_to_file_text[FILE_PRINT],
+ XmTRAVERSE_CURRENT);
+#else /* MOTIF */
+ int i = (int) XawToggleGetCurrent(to_printer_radio);
+
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ /*
+ NOTE: Unlike non-k xdvi, we don't use set_sensitivity for the
+ Xaw version, since the text inside the textfield cannot be made
+ insensitive, so it won't be obvious to users why they cannot
+ change the text. Also, the page range isn't set insensitive
+ either.
+ */
+ if (i != 0)
+ curr_pr_info.print_radio = i;
+#endif /* MOTIF */
+
+}
+
+
+
+static void
+cb_range(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ pageRadioT flag = (pageRadioT)client_data;
+ printOrSaveActionT act;
+
+#ifdef MOTIF
+
+ Boolean sensitivity;
+ UNUSED(call_data);
+ ASSERT(flag != PRINT_MARKED || flag != SAVE_MARKED || pageinfo_have_marked_pages(),
+ "PRINT_MARKED or SAVE_MARKED shouldn't be togglable if there are no marked pages!");
+
+ if (is_print_button(flag)) {
+ curr_pr_info.range_radio = (int)client_data;
+ sensitivity = (curr_pr_info.range_radio == PRINT_RANGE);
+ act = FILE_PRINT;
+ }
+ else {
+ curr_save_info.range_radio = (int)client_data;
+ sensitivity = (curr_save_info.range_radio == SAVE_RANGE);
+ act = FILE_SAVE;
+ }
+
+ /* switch off other radio buttons, switch on current one */
+ XmToggleButtonGadgetSetState(range_all_radio[act], False, False);
+ XmToggleButtonGadgetSetState(range_marked_radio[act], False, False);
+ XmToggleButtonGadgetSetState(range_from_to_radio[act], False, False);
+ XmToggleButtonGadgetSetState(w, True, False);
+
+ /* set from-to range to sensitive if appropriate */
+ XtSetSensitive(from_label[act], sensitivity);
+ XtSetSensitive(page_from_text[act], sensitivity);
+ XtSetSensitive(to_label[act], sensitivity);
+ XtSetSensitive(page_to_text[act], sensitivity);
+ XtSetSensitive(of_label[act], sensitivity);
+
+#else /* MOTIF */
+
+ int i;
+ UNUSED(call_data);
+ if (is_print_button(flag)) {
+ act = FILE_PRINT;
+ }
+ else {
+ act = FILE_SAVE;
+ }
+
+ UNUSED(w);
+
+ i = (int) XawToggleGetCurrent(range_all_radio[act]);
+
+ if (i != 0) {
+ ASSERT(i != PRINT_MARKED || i != SAVE_MARKED || pageinfo_have_marked_pages(),
+ "PRINT_MARKED or SAVE_MARKED shouldn't be togglable if there are no marked pages!");
+
+ if (act == FILE_PRINT)
+ curr_pr_info.range_radio = i;
+ else
+ curr_save_info.range_radio = i;
+ }
+
+#endif /* MOTIF */
+}
+
+static void
+set_filename_callback(const char *fname, void *data)
+{
+ if (fname != NULL) {
+ Widget w = (Widget)data;
+ XtVaSetValues(w,
+#ifdef MOTIF
+ XmNvalue, fname,
+ XmNcursorPosition, strlen(fname),
+#else
+ XtNstring, fname,
+#endif
+ NULL);
+ }
+}
+
+
+static void
+cb_browse(Widget w, XtPointer client_data, XtPointer call_data)
+{
+/* char *fname; */
+ struct save_or_print_info *info = (struct save_or_print_info *)client_data;
+ printOrSaveActionT act = info->act;
+/* Widget ret_widget; */
+ Widget parent;
+
+ UNUSED(call_data);
+#ifdef MOTIF
+ UNUSED(w);
+#else
+ if (act == FILE_PRINT)
+ xaw_print_handle_key(w, (XtPointer)"3", NULL, NULL);
+#endif
+
+ if (act == FILE_SAVE) {
+ static struct filesel_callback cb; /* static so that we can pass its address */
+ cb.title = "Xdvi: Save to file";
+ cb.prompt = "Save to file:";
+ cb.ok = "OK";
+ cb.cancel = "Cancel";
+ cb.init_path = NULL;
+ cb.filemask = "*.dvi";
+ cb.must_exist = False;
+ cb.exit_on_cancel = False;
+ cb.func_ptr = set_filename_callback;
+ cb.data = print_to_file_text[act];
+
+ if (!get_widget_by_name(&parent, globals.widgets.top_level, Xdvi_SAVE_SHELL_NAME, True))
+ parent = globals.widgets.top_level;
+ XsraSelFile(parent, &cb);
+/* fprintf(stderr, "done saving: return widget = %p\n", ret_widget); */
+ }
+ else {
+ static struct filesel_callback cb; /* static so that we can pass its address */
+ cb.title = "Xdvi: Print to file";
+ cb.prompt = "Print to file:";
+ cb.ok = "OK";
+ cb.cancel = "Cancel";
+ cb.init_path = NULL;
+ cb.filemask = "*.ps";
+ cb.must_exist = False;
+ cb.exit_on_cancel = False;
+ cb.func_ptr = set_filename_callback;
+ cb.data = print_to_file_text[act];
+
+ if (!get_widget_by_name(&parent, globals.widgets.top_level, Xdvi_PRINT_SHELL_NAME, True))
+ parent = globals.widgets.top_level;
+ XsraSelFile(parent, &cb);
+/* fname = XsraSelFile(parent, "Xdvi: Print to file", "Print to file:", */
+/* "OK", "Cancel", */
+/* NULL, */
+/* "*.ps", False, &ret_widget); */
+/* fprintf(stderr, "done printing: return widget = %p\n", ret_widget); */
+ }
+
+/* if (fname != NULL) { */
+/* XtVaSetValues(print_to_file_text[act], */
+/* #ifdef MOTIF */
+/* XmNvalue, fname, XmNcursorPosition, strlen(fname), */
+/* #else */
+/* XtNstring, fname, */
+/* #endif */
+/* NULL); */
+/* } */
+/* free(fname); */
+}
+
+/* create a popup dialog for printing a DVI file OR saving pages from a DVI file */
+static Widget
+create_print_or_save_window(struct save_or_print_info *info, char *ofstring)
+{
+ printOrSaveActionT act = info->act;
+ Widget top_level_shell;
+ Atom WM_DELETE_WINDOW;
+#ifndef MOTIF
+ Widget form, paned, box;
+ Widget f01form, f02form; /* dummy forms to get indentation consistent */
+ Widget r1form;
+ Widget r1label;
+ Widget r2form, r3form, r4form = 0;
+ Widget r4label;
+ Widget r5label;
+ Widget r6form;
+ Widget r61form;
+ Widget r7form;
+ char *str;
+
+ XtTranslations xlats, xlats2, wm_translations;
+ XtAccelerators accels2;
+ int ddist;
+
+ static Dimension w_avg = 220;
+ Dimension w_curr;
+
+ /* handy abbrevs */
+#define HORIZONTAL_RESIZING_NO XtNleft, XtChainLeft, XtNright, XtChainLeft
+#define HORIZONTAL_RESIZING_YES XtNleft, XtChainLeft, XtNright, XtChainRight
+#define VERTICAL_RESIZING_NO XtNtop, XtChainTop, XtNbottom, XtChainTop
+
+ XtAddActions(print_actions, XtNumber(print_actions));
+
+ if (act == FILE_SAVE) {
+ str = get_string_va("<Message>WM_PROTOCOLS: WM_save_cancel(%p)\n"
+ "<Key>Escape:WM_save_cancel(%p)\n"
+ "<Key>q:WM_save_cancel(%p)",
+ info, info, info);
+ wm_translations = XtParseTranslationTable(str);
+ free(str);
+ }
+ else {
+ str = get_string_va("<Message>WM_PROTOCOLS: WM_print_cancel(%p)\n"
+ "<Key>Escape:WM_print_cancel(%p)\n"
+ "<Key>q:WM_print_cancel(%p)",
+ info, info, info);
+ wm_translations = XtParseTranslationTable(str);
+ free(str);
+ }
+
+ top_level_shell = XtVaCreatePopupShell(act == FILE_SAVE ? Xdvi_SAVE_SHELL_NAME : Xdvi_PRINT_SHELL_NAME,
+ transientShellWidgetClass,
+ globals.widgets.top_level,
+ XtNtitle, act == FILE_SAVE ? "xdvik: Save file" : "xdvik: Print DVI file",
+ XtNmappedWhenManaged, False,
+ XtNtransientFor, globals.widgets.top_level,
+ XtNallowShellResize, True,
+ XtNtranslations, wm_translations,
+ NULL);
+
+ WM_DELETE_WINDOW = XInternAtom(XtDisplay(top_level_shell), "WM_DELETE_WINDOW", False);
+
+ paned = XtVaCreateManagedWidget(act == FILE_SAVE ? "save_paned" : "print_paned",
+ panedWidgetClass, top_level_shell, NULL);
+
+ form = XtVaCreateManagedWidget("form", formWidgetClass,
+ paned,
+ XtNallowResize, True,
+ NULL);
+ XtVaGetValues(form, XtNdefaultDistance, &ddist, NULL);
+/* fprintf(stderr, "form1: %ld\n", (long)form); */
+
+ xlats = XtParseTranslationTable("<EnterWindow>:highlight(Always)\n"
+ "<LeaveWindow>:unhighlight()\n"
+ "<Btn1Down>,<Btn1Up>:set()notify()");
+
+ if (act == FILE_PRINT) {
+ str = get_string_va("<Key>Return:printInternal(%p)", info);
+ xlats2 = XtParseTranslationTable(str);
+ }
+ else {
+ str = get_string_va("<Key>Return:saveInternal(%p)", info);
+ xlats2 = XtParseTranslationTable(str);
+ }
+ free(str);
+
+ if (act == FILE_PRINT) { /* selection `to printer/to file' */
+ /* FIXME: set real sizes here */
+/* Dimension w_curr; */
+ f01form = XtVaCreateManagedWidget("dummy_print_to_label_form", formWidgetClass,
+ form,
+ XtNresizable, True,
+ XtNborderWidth, 0,
+ /* XtNvertDistance, 10, */
+ HORIZONTAL_RESIZING_YES,
+ NULL);
+ r1label = XtVaCreateManagedWidget("print_to", labelWidgetClass,
+ f01form,
+ XtNlabel, "Print to: ",
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_NO,
+ NULL);
+
+ r2form = XtVaCreateManagedWidget("print_to_printer_form", formWidgetClass,
+ form,
+ XtNresizable, True,
+ XtNborderWidth, 0,
+ XtNvertDistance, 0,
+ XtNfromVert, f01form,
+ HORIZONTAL_RESIZING_YES,
+ XtNallowResize, True,
+ NULL);
+
+ accels2 = XtParseAcceleratorTable("<Btn1Down>,<Btn1Up>:set()notify()");
+
+ to_printer_radio = XtVaCreateManagedWidget("to_printer",
+#ifdef XAW
+ radioWidgetClass,
+#else
+ toggleWidgetClass,
+#endif
+ r2form,
+ XtNlabel, "Printer: ",
+ XtNborderWidth, 0,
+ XtNhighlightThickness, 1,
+ XtNradioData, PRINT_TO_PRINTER,
+ XtNstate, resource.default_printing_target == PRINT_TO_PRINTER,
+ XtNtranslations, xlats,
+ XtNaccelerators, accels2,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+
+ XtAddCallback(to_printer_radio, XtNcallback, cb_print_vs_file, NULL);
+ XtInstallAccelerators(r2form, to_printer_radio);
+
+ print_to_printer_text = XtVaCreateManagedWidget("printer_text", asciiTextWidgetClass,
+ r2form,
+ XtNwidth, w_avg,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ /* XtNresize, XawtextResizeWidth, */
+ XtNfromHoriz, to_printer_radio,
+ HORIZONTAL_RESIZING_YES,
+ VERTICAL_RESIZING_NO,
+ /* XtNscrollHorizontal, XawtextScrollAlways, */
+ NULL);
+ XtOverrideTranslations(print_to_printer_text, xlats2);
+ XtAddEventHandler(print_to_printer_text, KeyPressMask | ButtonPressMask, False,
+ xaw_print_handle_key, (XtPointer)"2");
+
+ adjust_vertically(to_printer_radio, print_to_printer_text, ddist);
+
+ r3form = XtVaCreateManagedWidget("print_to_file_form", formWidgetClass,
+ form,
+ XtNborderWidth, 0,
+ XtNvertDistance, 0,
+ XtNfromVert, r2form,
+ HORIZONTAL_RESIZING_YES,
+ NULL);
+
+ to_file_radio_or_label[act] = XtVaCreateManagedWidget("to_file",
+#ifdef XAW
+ radioWidgetClass,
+#else
+ toggleWidgetClass,
+#endif
+ r3form,
+ XtNhighlightThickness, 1,
+ XtNborderWidth, 0,
+ XtNlabel, "File: ",
+ XtNstate, resource.default_printing_target == PRINT_TO_FILE,
+ XtNradioGroup, to_printer_radio,
+ XtNradioData, PRINT_TO_FILE,
+ XtNtranslations, xlats,
+ XtNaccelerators, accels2,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ XtAddCallback(to_file_radio_or_label[act], XtNcallback, cb_print_vs_file, NULL);
+ XtInstallAccelerators(r3form, to_file_radio_or_label[act]);
+
+ print_to_file_text[act] = XtVaCreateManagedWidget("file_text", asciiTextWidgetClass,
+ r3form,
+ XtNwidth, w_avg,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNfromHoriz, to_file_radio_or_label[act],
+ HORIZONTAL_RESIZING_YES,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ XtOverrideTranslations(print_to_file_text[act], xlats2);
+ XtAddEventHandler(print_to_file_text[act], KeyPressMask | ButtonPressMask, False,
+ xaw_print_handle_key, (XtPointer)"3");
+ }
+ else { /* not printing, but saving */
+ int i;
+ Dimension max_entry_width = 0;
+ f01form = XtVaCreateManagedWidget("dummy_save_as_form", formWidgetClass,
+ form,
+ XtNresizable, True,
+ XtNborderWidth, 0,
+ /* XtNvertDistance, 10, */
+ HORIZONTAL_RESIZING_YES,
+ NULL);
+ r1label = XtVaCreateManagedWidget("save_as", labelWidgetClass,
+ f01form,
+ XtNlabel, "Save as: ",
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_NO,
+ NULL);
+ r1form = XtVaCreateManagedWidget("save_to_file_form", formWidgetClass,
+ form,
+ XtNborderWidth, 0,
+ XtNfromVert, f01form,
+ HORIZONTAL_RESIZING_YES,
+ VERTICAL_RESIZING_NO,
+ NULL);
+/* fprintf(stderr, "formr1: %ld\n", (long)r1form); */
+#if 0
+ menu_double_arrow_bitmap
+ = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)menu_double_arrow_bits, MENU_DOUBLE_ARROW_W, MENU_DOUBLE_ARROW_H);
+#endif
+ format_selection_label = XtVaCreateManagedWidget("format_selection_label", labelWidgetClass,
+ r1form,
+ XtNlabel, "Format: ",
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ format_selection_button = XtVaCreateManagedWidget("format_selection_button", menuButtonWidgetClass,
+ r1form,
+ XtNmenuName, "format_selection_popup",
+ XtNlabel, output_format_mapping[resource.default_saving_format].fmt_string,
+ XtNjustify, XtJustifyLeft,
+ XtNborderWidth, resource.btn_border_width,
+ XtNfromHoriz, format_selection_label,
+#if 0
+ XtNhighlightThickness, 0,
+#endif
+ NULL);
+#if 0 /* Hack for arrow - menuButtonWidget cannot have a XtNrightBitmap!!! */
+ format_selection_b1 = XtVaCreateManagedWidget("format_selection_b1", commandWidgetClass,
+ r1form,
+ XtNborderWidth, resource.btn_border_width,
+ XtNfromHoriz, format_selection_button,
+ XtNhorizDistance, -1,
+ XtNhighlightThickness, 0,
+ XtNbitmap, menu_double_arrow_bitmap,
+ NULL);
+ adjust_heights(format_selection_button, format_selection_b1, NULL);
+#endif
+ format_selection_popup = XtCreatePopupShell("format_selection_popup", simpleMenuWidgetClass,
+ format_selection_button,
+/* globals.widgets.top_level, */
+ NULL, 0);
+#if 0
+ XtAddCallback(format_selection_b1, XtNcallback, xaw_popup_menu_cb, format_selection_popup);
+#endif
+ for (i = 1; i < FORMAT_SEL_CNT; i++) {
+ char name[1024];
+ Dimension curr_entry_width;
+ SNPRINTF(name, sizeof name, "format_selection_pulldown_%d", i);
+ format_selection_menu[i] = XtVaCreateManagedWidget(name, smeBSBObjectClass,
+ format_selection_popup,
+ XtNjustify, XtJustifyLeft,
+ XtNlabel,
+ i == resource.default_saving_format
+ ? output_format_mapping[0].fmt_string
+ : output_format_mapping[i].fmt_string,
+ NULL);
+ XtVaGetValues(format_selection_menu[i], XtNwidth, &curr_entry_width, NULL);
+ if (curr_entry_width > max_entry_width)
+ max_entry_width = curr_entry_width;
+ XtAddCallback(format_selection_menu[i], XtNcallback, select_format_cb, form);
+ }
+ XtVaSetValues(format_selection_button, XtNwidth, max_entry_width, NULL);
+
+ r3form = XtVaCreateManagedWidget("to_file_form", formWidgetClass,
+ form,
+ XtNborderWidth, 0,
+ XtNfromVert, r1form,
+ HORIZONTAL_RESIZING_YES,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ to_file_radio_or_label[act] = XtVaCreateManagedWidget("to_file", labelWidgetClass,
+ r3form,
+ XtNlabel, "File name: ",
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ print_to_file_text[act] = XtVaCreateManagedWidget("file_text", asciiTextWidgetClass,
+ r3form,
+ XtNwidth, w_avg,
+ XtNdataCompression, False,
+ /* XtNvertDistance, ddist + 5, */
+ XtNeditType, XawtextEdit,
+ XtNfromHoriz, to_file_radio_or_label[act],
+ HORIZONTAL_RESIZING_YES,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ XtOverrideTranslations(print_to_file_text[act], xlats2);
+
+
+ { /* align left edges of format selection pulldown and filename field */
+ Dimension w1, w2, w_max;
+ XtVaGetValues(format_selection_label, XtNwidth, &w1, NULL);
+ XtVaGetValues(to_file_radio_or_label[act], XtNwidth, &w2, NULL);
+ w_max = MAX(w1, w2);
+ XtVaSetValues(format_selection_button, XtNhorizDistance, ddist + (w_max - w1), NULL);
+ XtVaSetValues(print_to_file_text[act], XtNhorizDistance, ddist + (w_max - w2), NULL);
+ }
+ }
+
+#define DIST_1 8 /* FIXME */
+ print_to_file_button[act] = XtVaCreateManagedWidget("file_button", commandWidgetClass,
+ r3form,
+ XtNlabel, "Browse ...",
+ XtNfromHoriz, print_to_file_text[act],
+ XtNhorizDistance, DIST_1,
+ /* attach to right of form, no resizing: */
+ XtNleft, XtChainRight, XtNright, XtChainRight,
+ VERTICAL_RESIZING_NO,
+ NULL);
+
+ XtVaGetValues(print_to_file_button[act], XtNwidth, &w_curr, NULL);
+ XtVaSetValues(print_to_file_text[act], XtNwidth, w_avg - w_curr - DIST_1 - 2, NULL);
+#undef DIST_1
+
+ adjust_vertically(to_file_radio_or_label[act], print_to_file_text[act], ddist + 5);
+ adjust_vertically(print_to_file_text[act], to_file_radio_or_label[act], ddist + 5);
+ adjust_vertically(print_to_file_button[act], to_file_radio_or_label[act], ddist + 5);
+
+ XtAddCallback(print_to_file_button[act], XtNcallback, cb_browse, (XtPointer)info);
+
+ /* other dvips options */
+ r4form = XtVaCreateManagedWidget("dvips_options_form", formWidgetClass,
+ form,
+ XtNborderWidth, 0,
+ XtNfromVert, r3form,
+ XtNvertDistance, 0,
+ HORIZONTAL_RESIZING_YES,
+ NULL);
+
+ r4label = XtVaCreateManagedWidget("dvips_options_name", labelWidgetClass,
+ r4form,
+ XtNlabel, "Dvips Options:",
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+
+ dvips_options_text[act] = XtVaCreateManagedWidget("dvips_options_text", asciiTextWidgetClass,
+ r4form,
+ XtNwidth, w_avg,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNfromHoriz, r4label,
+ HORIZONTAL_RESIZING_YES,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ XtOverrideTranslations(dvips_options_text[act], xlats2);
+
+ { /* align left edges of input fields */
+ Dimension w1, w2, w3, w_max;
+
+ if (act == FILE_PRINT)
+ XtVaGetValues(to_printer_radio, XtNwidth, &w1, NULL);
+ else
+ XtVaGetValues(format_selection_label, XtNwidth, &w1, NULL);
+
+ XtVaGetValues(to_file_radio_or_label[act], XtNwidth, &w2, NULL);
+ XtVaGetValues(r4label, XtNwidth, &w3, NULL);
+
+ w_max = MAX(MAX(w1, w2), w3);
+
+ if (act == FILE_PRINT)
+ XtVaSetValues(print_to_printer_text, XtNhorizDistance, ddist + (w_max - w1), NULL);
+ else
+ XtVaSetValues(format_selection_button, XtNhorizDistance, ddist + (w_max - w1), NULL);
+
+ XtVaSetValues(print_to_file_text[act], XtNhorizDistance, ddist + (w_max - w2), NULL);
+ XtVaSetValues(dvips_options_text[act], XtNhorizDistance, ddist + (w_max - w3), NULL);
+ }
+
+ /* page selection */
+
+ f02form = XtVaCreateManagedWidget("dummy_pages_form", formWidgetClass,
+ form,
+ XtNfromVert, r4form,
+ XtNresizable, True,
+ XtNborderWidth, 0,
+ /* XtNvertDistance, 10, */
+ HORIZONTAL_RESIZING_NO,
+ NULL);
+
+ r5label = XtVaCreateManagedWidget("range_lab", labelWidgetClass,
+ f02form,
+ XtNlabel, "Pages:",
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_NO,
+ NULL);
+
+ r6form = XtVaCreateManagedWidget("page_range_form", formWidgetClass,
+ form,
+ XtNborderWidth, 0,
+ XtNfromVert, f02form,
+ /* XtNvertDistance, 0, */
+ HORIZONTAL_RESIZING_NO,
+ NULL);
+
+ accels2 = XtParseAcceleratorTable("<Btn1Down>,<Btn1Up>:set()notify()");
+ range_all_radio[act] = XtVaCreateManagedWidget("range_all",
+#ifdef XAW
+ radioWidgetClass,
+#else
+ toggleWidgetClass,
+#endif
+ r6form,
+ XtNlabel, "All ",
+ XtNborderWidth, 0,
+ XtNhighlightThickness, 1,
+ XtNradioData, act == FILE_PRINT ? PRINT_ALL : SAVE_ALL,
+ XtNstate, True, /* enable this button by default */
+ XtNtranslations, xlats,
+ XtNaccelerators, accels2,
+ /* XtNvertDistance, 0, */
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ if (act == FILE_PRINT)
+ XtAddCallback(range_all_radio[act], XtNcallback, cb_range, (XtPointer)PRINT_ALL);
+ else
+ XtAddCallback(range_all_radio[act], XtNcallback, cb_range, (XtPointer)SAVE_ALL);
+ XtInstallAccelerators(r6form, range_all_radio[act]);
+
+ r61form = XtVaCreateManagedWidget("range_marked_form", formWidgetClass,
+ form,
+ XtNborderWidth, 0,
+ XtNfromVert, r6form,
+ /* XtNvertDistance, 0, */
+ HORIZONTAL_RESIZING_NO,
+ NULL);
+
+ range_marked_radio[act] = XtVaCreateManagedWidget("range_marked",
+#ifdef XAW
+ radioWidgetClass,
+#else
+ toggleWidgetClass,
+#endif
+
+ r61form,
+ XtNlabel, "Marked ",
+ XtNborderWidth, 0,
+ XtNhighlightThickness, 1,
+ XtNradioGroup, range_all_radio[act],
+ XtNradioData, act == FILE_PRINT ? PRINT_MARKED : SAVE_MARKED,
+ XtNtranslations, xlats,
+ XtNaccelerators, accels2,
+ /* XtNvertDistance, 0, */
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ if (act == FILE_PRINT)
+ XtAddCallback(range_marked_radio[act], XtNcallback, cb_range, (XtPointer)PRINT_RANGE);
+ else
+ XtAddCallback(range_marked_radio[act], XtNcallback, cb_range, (XtPointer)SAVE_RANGE);
+ XtInstallAccelerators(r61form, range_marked_radio[act]);
+
+ r7form = XtVaCreateManagedWidget("range_from_to_form", formWidgetClass,
+ form,
+ XtNborderWidth, 0,
+ XtNfromVert, r61form,
+ /* XtNvertDistance, 0, */
+ XtNresizable, True,
+ /* HORIZONTAL_RESIZING_NO, */
+ NULL);
+
+ range_from_to_radio[act] = XtVaCreateManagedWidget("range_from_to",
+#ifdef XAW
+ radioWidgetClass,
+#else
+ toggleWidgetClass,
+#endif
+ r7form,
+ XtNlabel, "From: ",
+ XtNborderWidth, 0,
+ XtNhighlightThickness, 1,
+ XtNradioGroup, range_all_radio[act],
+ XtNradioData, act == FILE_PRINT ? PRINT_RANGE : SAVE_RANGE,
+ XtNtranslations, xlats,
+ XtNaccelerators, accels2,
+ /* XtNvertDistance, 0, */
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ if (act == FILE_PRINT)
+ XtAddCallback(range_from_to_radio[act], XtNcallback, cb_range, (XtPointer)PRINT_RANGE);
+ else
+ XtAddCallback(range_from_to_radio[act], XtNcallback, cb_range, (XtPointer)SAVE_RANGE);
+ XtInstallAccelerators(r7form, range_from_to_radio[act]);
+
+ page_from_text[act] = XtVaCreateManagedWidget("range_from", asciiTextWidgetClass,
+ r7form,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNwidth, 50,
+ XtNfromHoriz, range_from_to_radio[act],
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ XtOverrideTranslations(page_from_text[act], xlats2);
+ XtAddEventHandler(page_from_text[act], KeyPressMask | ButtonPressMask, False,
+ xaw_range_handle_key, (XtPointer)act);
+
+ to_label[act] = XtVaCreateManagedWidget("range_to_lab", labelWidgetClass,
+ r7form,
+ XtNlabel, "to: ",
+ XtNborderWidth, 0,
+ XtNfromHoriz, page_from_text[act],
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+
+ page_to_text[act] = XtVaCreateManagedWidget("range_to", asciiTextWidgetClass,
+ r7form,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNwidth, 50,
+ XtNfromHoriz, to_label[act],
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+ NULL);
+ XtOverrideTranslations(page_to_text[act], xlats2);
+ XtAddEventHandler(page_to_text[act], KeyPressMask | ButtonPressMask, False,
+ xaw_range_handle_key, (XtPointer)act);
+
+ of_label[act] = XtVaCreateManagedWidget("range_of", labelWidgetClass,
+ r7form,
+ XtNlabel, ofstring,
+ XtNborderWidth, 0,
+ XtNresizable, True,
+ XtNfromHoriz, page_to_text[act],
+ /* HORIZONTAL_RESIZING_NO, */
+ XtNleft, XtChainLeft,
+ VERTICAL_RESIZING_NO,
+ NULL);
+
+ adjust_vertically(range_from_to_radio[act], page_from_text[act], ddist);
+ adjust_vertically(to_label[act], page_from_text[act], ddist);
+ adjust_vertically(of_label[act], page_from_text[act], ddist);
+
+ /* box for the OK/Cancel button */
+ box = XtVaCreateManagedWidget("box", formWidgetClass,
+ paned,
+ /* resizing by user isn't needed */
+ XtNshowGrip, False,
+ XtNdefaultDistance, 6, /* some padding */
+ /* resizing the window shouldn't influence this box,
+ * but only the pane widget
+ */
+ XtNskipAdjust, True,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+
+ ok_button[act] = XtVaCreateManagedWidget(act == FILE_PRINT ? "print_button" : "save_button",
+ commandWidgetClass, box,
+ XtNlabel, act == FILE_PRINT ? "Print" : "Save",
+ XtNaccelerators, G_accels_cr,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainBottom,
+ HORIZONTAL_RESIZING_NO,
+ NULL);
+ if (act == FILE_PRINT)
+ XtAddCallback(ok_button[act], XtNcallback, cb_print_or_save, (XtPointer)info);
+ else
+ XtAddCallback(ok_button[act], XtNcallback, cb_print_or_save, (XtPointer)info);
+
+ XtInstallAccelerators(form, ok_button[act]);
+ if (act == FILE_PRINT)
+ XtInstallAccelerators(print_to_printer_text, ok_button[act]);
+ XtInstallAccelerators(print_to_file_text[act], ok_button[act]);
+
+ cancel_button[act] = XtVaCreateManagedWidget("cancel", commandWidgetClass,
+ box,
+ XtNlabel, "Cancel",
+ XtNfromHoriz, ok_button[act],
+ XtNbottom, XtChainBottom,
+ XtNjustify, XtJustifyRight,
+ XtNleft, XtChainRight,
+ XtNright, XtChainRight,
+ NULL);
+ if (act == FILE_PRINT)
+ XtAddCallback(cancel_button[act], XtNcallback, cb_print_cancel, (XtPointer)info);
+ else
+ XtAddCallback(cancel_button[act], XtNcallback, cb_save_cancel, (XtPointer)info);
+
+ XtManageChild(top_level_shell);
+ center_window(top_level_shell, globals.widgets.top_level);
+ XtMapWidget(top_level_shell);
+ XSetWMProtocols(XtDisplay(top_level_shell), XtWindow(top_level_shell), &WM_DELETE_WINDOW, 1);
+
+ if (pageinfo_have_marked_pages()) {
+ XawToggleSetCurrent(range_all_radio[act],
+ act == FILE_PRINT ? (XtPointer)PRINT_MARKED : (XtPointer)SAVE_MARKED);
+ }
+ else if ((act == FILE_PRINT && save_pr_info.range_radio == PRINT_MARKED)
+ || (act == FILE_SAVE && save_save_info.range_radio == SAVE_MARKED)) {
+ XawToggleSetCurrent(range_all_radio[act],
+ act == FILE_PRINT ? (XtPointer)PRINT_ALL : (XtPointer)SAVE_ALL);
+ }
+
+#else /* not MOTIF */
+ Widget form, pane, box;
+ Widget frame1, f1label, f1child;
+ Widget r4label;
+ Widget frame2, f2label, f2child;
+ XmString str;
+ XtTranslations xlats;
+
+ XtAddActions(print_actions, XtNumber(print_actions));
+
+ if (act == FILE_SAVE) {
+ char *ptr = get_string_va("#override \n<Key>osfCancel:WM_save_cancel(%p)", info);
+ xlats = XtParseTranslationTable(ptr);
+ free(ptr);
+ }
+ else {
+ char *ptr = get_string_va("#override \n<Key>osfCancel:WM_print_cancel(%p)", info);
+ xlats = XtParseTranslationTable(ptr);
+ free(ptr);
+ }
+
+ top_level_shell = XtVaCreatePopupShell(act == FILE_SAVE ? "save_popup" : "print_popup",
+ xmDialogShellWidgetClass, globals.widgets.top_level,
+ XmNtitle, act == FILE_SAVE ? "Save file" : "Print DVI file",
+ XmNallowShellResize, True,
+ XmNdeleteResponse, XmDO_NOTHING, /* we'll take care of that ourselves */
+ XmNmappedWhenManaged, False, /* so that we can center it first */
+ NULL);
+
+ /* make the window manager destroy action just pop down the dialog */
+ WM_DELETE_WINDOW = XmInternAtom(XtDisplay(top_level_shell), "WM_DELETE_WINDOW", False);
+ if (act == FILE_SAVE)
+ XmAddWMProtocolCallback(top_level_shell, WM_DELETE_WINDOW, cb_save_cancel, (XtPointer)info);
+ else
+ XmAddWMProtocolCallback(top_level_shell, WM_DELETE_WINDOW, cb_print_cancel, (XtPointer)info);
+
+
+ pane = XtVaCreateWidget(act == FILE_SAVE ? "save_paned" : "print_paned",
+ xmPanedWindowWidgetClass, top_level_shell,
+ /* make sashes invisible */
+ XmNsashWidth, 1,
+ XmNsashHeight, 1,
+ /* turn separator off, since it gives visual noise with the frames */
+ XmNseparatorOn, False,
+ NULL);
+
+
+ form = XtVaCreateWidget("form", xmFormWidgetClass,
+ pane,
+ XmNhorizontalSpacing, DDIST_MAJOR,
+ XmNverticalSpacing, DDIST_MAJOR,
+ XmNautoUnmanage, False,
+ XTranslations, xlats,
+ NULL);
+
+ if (act == FILE_PRINT) {
+ /* First frame: print to printer or file */
+
+ frame1 = XtVaCreateWidget("print_to_frame", xmFrameWidgetClass, form,
+ XmNmarginWidth, DDIST,
+ XmNmarginHeight, DDIST,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XTranslations, xlats,
+ NULL);
+
+ str = XmStringCreateLocalized("Print to:");
+ f1label = XtVaCreateManagedWidget("title", xmLabelGadgetClass,
+ frame1,
+ XmNchildType, XmFRAME_TITLE_CHILD,
+ XmNlabelString, str,
+ NULL);
+ XmStringFree(str);
+
+ f1child = XtVaCreateWidget("form", xmFormWidgetClass, frame1,
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XTranslations, xlats,
+ NULL);
+
+ str = XmStringCreateLocalized("Printer:");
+ to_printer_radio = XtVaCreateManagedWidget("to_printer",
+ xmToggleButtonGadgetClass, f1child,
+ XmNlabelString, str,
+ XmNindicatorType, XmONE_OF_MANY,
+ XmNset, resource.default_printing_target == PRINT_TO_PRINTER,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 0,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 0,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(to_printer_radio, XmNvalueChangedCallback, cb_print_vs_file, (XtPointer)1);
+
+ XtOverrideTranslations(to_printer_radio, xlats);
+
+ print_to_printer_text = XtVaCreateManagedWidget("print_text", xmTextFieldWidgetClass,
+ f1child,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 0,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftWidget, to_printer_radio,
+ XTranslations, xlats,
+ NULL);
+ XtAddCallback(print_to_printer_text, XmNactivateCallback, cb_print_or_save, info);
+
+ adjust_heights(to_printer_radio, print_to_printer_text, NULL);
+
+ str = XmStringCreateLocalized("File:");
+ to_file_radio_or_label[act] = XtVaCreateManagedWidget("to_file", xmToggleButtonGadgetClass,
+ f1child,
+ XmNlabelString, str,
+ XmNindicatorType, XmONE_OF_MANY,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, print_to_printer_text,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNset, resource.default_printing_target == PRINT_TO_FILE,
+ XmNleftOffset, 0,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(to_file_radio_or_label[act], XmNvalueChangedCallback, cb_print_vs_file, (XtPointer)2);
+
+ str = XmStringCreateLocalized("Browse ...");
+ print_to_file_button[act] = XtVaCreateManagedWidget("file_button", xmPushButtonWidgetClass,
+ f1child,
+ XmNlabelString, str,
+ XmNsensitive, resource.default_printing_target == PRINT_TO_FILE,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, print_to_printer_text,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+
+ XtOverrideTranslations(to_file_radio_or_label[act], xlats);
+ XtOverrideTranslations(print_to_file_button[act], xlats);
+
+ print_to_file_text[act] = XtVaCreateManagedWidget("file_text", xmTextFieldWidgetClass,
+ f1child,
+ XmNsensitive, resource.default_printing_target == PRINT_TO_FILE,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, print_to_printer_text,
+ XmNrightAttachment, XmATTACH_WIDGET,
+ XmNrightWidget, print_to_file_button[act],
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, to_file_radio_or_label[act],
+ XTranslations, xlats,
+ NULL);
+
+ adjust_heights(to_file_radio_or_label[act], print_to_file_button[act], print_to_file_text[act], NULL);
+
+ XtAddCallback(print_to_file_text[act], XmNactivateCallback, cb_print_or_save, (XtPointer)info);
+ XtAddCallback(print_to_file_button[act], XmNactivateCallback, cb_browse, (XtPointer)info);
+
+ XtManageChild(f1child);
+ XtManageChild(frame1);
+
+ } /* saving, not printing */
+ else {
+ frame1 = XtVaCreateWidget("save_as_frame", xmFrameWidgetClass,
+ form,
+ XmNmarginWidth, DDIST,
+ XmNmarginHeight, DDIST,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+
+ str = XmStringCreateLocalized("Save as:");
+ f1label = XtVaCreateManagedWidget("title", xmLabelGadgetClass,
+ frame1,
+ XmNchildType, XmFRAME_TITLE_CHILD,
+ XmNlabelString, str,
+ NULL);
+ XmStringFree(str);
+
+ f1child = XtVaCreateWidget("form", xmFormWidgetClass, frame1,
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XTranslations, xlats,
+ NULL);
+/* fprintf(stderr, "CHILD: 0x%x\n", (long)f1child); */
+ str = XmStringCreateLocalized("Format:");
+ format_selection_texts[0] = XmStringCreateLocalized((char *)output_format_mapping[0].fmt_string);
+ format_selection_texts[1] = XmStringCreateLocalized((char *)output_format_mapping[1].fmt_string);
+ format_selection_texts[2] = XmStringCreateLocalized((char *)output_format_mapping[2].fmt_string);
+ format_selection_texts[3] = XmStringCreateLocalized((char *)output_format_mapping[3].fmt_string);
+ format_selection_texts[4] = XmStringCreateLocalized((char *)output_format_mapping[4].fmt_string);
+ format_selection_option
+ = XmVaCreateSimpleOptionMenu(f1child, "format_selection_option",
+ str, 'F',
+ resource.default_saving_format, /*initial menu selection*/
+ select_format_cb, /* callback */
+ XmVaPUSHBUTTON, format_selection_texts[0], 'P', NULL, NULL,
+ XmVaPUSHBUTTON, format_selection_texts[1], 'F', NULL, NULL,
+ XmVaPUSHBUTTON, format_selection_texts[2], 'D', NULL, NULL,
+ XmVaPUSHBUTTON, format_selection_texts[3], 'T', NULL, NULL,
+ XmVaPUSHBUTTON, format_selection_texts[4], 'U', NULL, NULL,
+ NULL);
+
+ XmStringFree(str);
+ XmStringFree(format_selection_texts[0]);
+ XmStringFree(format_selection_texts[1]);
+ XmStringFree(format_selection_texts[2]);
+ XmStringFree(format_selection_texts[3]);
+ XmStringFree(format_selection_texts[4]);
+
+ str = XmStringCreateLocalized("File name:");
+ to_file_radio_or_label[act] = XtVaCreateManagedWidget("to_file", xmLabelGadgetClass,
+ f1child,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, format_selection_option,
+ XmNleftAttachment, XmATTACH_FORM,
+ /* XmNchildType, XmFRAME_TITLE_CHILD, */
+ XmNlabelString, str,
+ NULL);
+ XmStringFree(str);
+ str = XmStringCreateLocalized("Browse ...");
+ print_to_file_button[act] = XtVaCreateManagedWidget("file_button", xmPushButtonWidgetClass,
+ f1child,
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, format_selection_option,
+ XmNrightAttachment, XmATTACH_FORM,
+ XTranslations, xlats,
+ NULL);
+ print_to_file_text[act] = XtVaCreateManagedWidget("file_text", xmTextFieldWidgetClass,
+ f1child,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, format_selection_option,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, to_file_radio_or_label[act],
+ XmNrightAttachment, XmATTACH_WIDGET,
+ XmNrightWidget, print_to_file_button[act],
+ XTranslations, xlats,
+ NULL);
+
+ adjust_heights(to_file_radio_or_label[act], print_to_file_button[act], print_to_file_text[act], NULL);
+ XtAddCallback(print_to_file_button[act], XmNactivateCallback, cb_browse, (XtPointer)info);
+ }
+
+#if 1
+ { /* align left edges of widgets */
+ Dimension w1, w2;
+
+ XtVaGetValues(to_file_radio_or_label[act], XmNwidth, &w2, NULL);
+ if (act == FILE_PRINT)
+ XtVaGetValues(to_printer_radio, XmNwidth, &w1, NULL);
+ else {
+ Widget w;
+ if (get_widget_by_name(&w, format_selection_option, "OptionLabel", True)) {
+ XtVaGetValues(w, XmNwidth, &w1, NULL);
+ }
+ else {
+ w1 = w2;
+ }
+ }
+
+ if (w1 > w2) {
+ Dimension offset = DDIST;
+ offset += w1 - w2;
+ XtVaSetValues(print_to_file_text[act], XmNleftOffset, offset, NULL);
+ }
+ else if (w2 > w1) {
+ Dimension offset = DDIST;
+ offset += w2 - w1;
+ if (act == FILE_PRINT)
+ XtVaSetValues(print_to_printer_text, XmNleftOffset, offset, NULL);
+ else {
+ Widget w;
+ if (get_widget_by_name(&w, format_selection_option, "OptionLabel", True)) {
+ /* FIXME: Setting width would be cleaner, but it doesn't work ...?
+ Dimension curr_w;
+ XtVaGetValues(w, XmNwidth, &curr_w, NULL);
+ XtVaSetValues(w, XmNwidth, curr_w + offset, NULL);
+ */
+ /* fprintf(stderr, "Setting width from %d to: %d\n", curr_w, curr_w + offset); */
+ XtVaSetValues(w,
+ XmNmarginRight, offset,
+ XmNalignment, XmALIGNMENT_BEGINNING,
+ NULL);
+ }
+
+ }
+ }
+ }
+#endif /* 0 */
+
+ if (act == FILE_SAVE) {
+ XtManageChild(format_selection_option);
+ XtManageChild(f1child);
+ XtManageChild(frame1);
+ }
+
+ /* additional dvips options */
+ str = XmStringCreateLocalized("Dvips Options:");
+ r4label = XtVaCreateManagedWidget("dvips_options_name", xmLabelGadgetClass,
+ form,
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, frame1,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+
+ dvips_options_text[act] = XtVaCreateManagedWidget("dvips_options_text", xmTextFieldWidgetClass,
+ form,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, frame1,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftWidget, r4label,
+ XmNcolumns, 20,
+ XTranslations, xlats,
+ NULL);
+ XtAddCallback(dvips_options_text[act], XmNactivateCallback, cb_print_or_save, (XtPointer)info);
+ adjust_heights(r4label, dvips_options_text[act], NULL);
+
+ /* page selection */
+ frame2 = XtVaCreateWidget(act == FILE_PRINT ? "print_page_frame" : "save_page_frame", xmFrameWidgetClass,
+ form,
+ XmNmarginWidth, DDIST,
+ XmNmarginHeight, DDIST,
+ XmNresizable, True,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, dvips_options_text[act],
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XTranslations, xlats,
+ NULL);
+
+ str = XmStringCreateLocalized("Pages:");
+ f2label = XtVaCreateManagedWidget("title", xmLabelGadgetClass,
+ frame2,
+ XmNchildType, XmFRAME_TITLE_CHILD,
+ XmNlabelString, str,
+ NULL);
+ XmStringFree(str);
+
+ f2child = XtVaCreateWidget("form", xmFormWidgetClass, frame2,
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+ XmNresizable, True,
+ XTranslations, xlats,
+ XTranslations, xlats,
+ NULL);
+
+ str = XmStringCreateLocalized("All");
+ range_all_radio[act] = XtVaCreateManagedWidget("all",
+ xmToggleButtonGadgetClass, f2child,
+ XmNlabelString, str,
+ XmNindicatorType, XmONE_OF_MANY,
+ XmNset, True,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 0,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 0,
+ XTranslations, xlats,
+ NULL);
+ XmStringFree(str);
+ if (act == FILE_PRINT) {
+ XtAddCallback(range_all_radio[act], XmNvalueChangedCallback, cb_range, (XtPointer)PRINT_ALL);
+ }
+ else {
+ XtAddCallback(range_all_radio[act], XmNvalueChangedCallback, cb_range, (XtPointer)SAVE_ALL);
+ }
+
+ str = XmStringCreateLocalized("Marked");
+ range_marked_radio[act] = XtVaCreateManagedWidget("marked",
+ xmToggleButtonGadgetClass, f2child,
+ XmNlabelString, str,
+ XmNindicatorType, XmONE_OF_MANY,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, range_all_radio[act],
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 0,
+ XTranslations, xlats,
+ NULL);
+ XmStringFree(str);
+ if (act == FILE_PRINT) {
+ XtAddCallback(range_marked_radio[act], XmNvalueChangedCallback, cb_range, (XtPointer)PRINT_MARKED);
+ }
+ else {
+ XtAddCallback(range_marked_radio[act], XmNvalueChangedCallback, cb_range, (XtPointer)SAVE_MARKED);
+ }
+
+ str = XmStringCreateLocalized("Range:");
+ range_from_to_radio[act] = XtVaCreateManagedWidget("range",
+ xmToggleButtonGadgetClass, f2child,
+ XmNlabelString, str,
+ XmNindicatorType, XmONE_OF_MANY,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, range_marked_radio[act],
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 0,
+ XTranslations, xlats,
+ NULL);
+ XmStringFree(str);
+
+ if (act == FILE_PRINT) {
+ XtAddCallback(range_from_to_radio[act], XmNvalueChangedCallback, cb_range, (XtPointer)PRINT_RANGE);
+ }
+ else {
+ XtAddCallback(range_from_to_radio[act], XmNvalueChangedCallback, cb_range, (XtPointer)SAVE_RANGE);
+ }
+ str = XmStringCreateLocalized("From");
+ from_label[act] = XtVaCreateManagedWidget("from", xmLabelGadgetClass,
+ f2child,
+ XmNlabelString, str,
+ XmNsensitive, False,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, range_marked_radio[act],
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, range_from_to_radio[act],
+ NULL);
+ XmStringFree(str);
+
+ page_from_text[act] = XtVaCreateManagedWidget("from_page",
+ xmTextFieldWidgetClass, f2child,
+ XmNcolumns, 5,
+ XmNsensitive, False,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, range_marked_radio[act],
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, from_label[act],
+ XTranslations, xlats,
+ NULL);
+ XtAddCallback(page_from_text[act], XmNactivateCallback, cb_print_or_save, (XtPointer)info);
+
+ str = XmStringCreateLocalized("to");
+ to_label[act] = XtVaCreateManagedWidget("to", xmLabelGadgetClass,
+ f2child,
+ XmNlabelString, str,
+ XmNsensitive, False,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, range_marked_radio[act],
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, page_from_text[act],
+ NULL);
+ XmStringFree(str);
+
+ page_to_text[act] = XtVaCreateManagedWidget("to_page", xmTextFieldWidgetClass,
+ f2child,
+ XmNcolumns, 5,
+ XmNsensitive, False,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, range_marked_radio[act],
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, to_label[act],
+ XTranslations, xlats,
+ NULL);
+ XtAddCallback(page_to_text[act], XmNactivateCallback, cb_print_or_save, (XtPointer)info);
+
+ str = XmStringCreateLocalized(ofstring);
+ of_label[act] = XtVaCreateManagedWidget("of", xmLabelGadgetClass,
+ f2child,
+ XmNlabelString, str,
+ XmNsensitive, False,
+ XmNresizable, True,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, range_marked_radio[act],
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, page_to_text[act],
+ NULL);
+ XmStringFree(str);
+
+ adjust_heights(range_from_to_radio[act],
+ from_label[act], page_from_text[act],
+ to_label[act], page_to_text[act],
+ of_label[act],
+ NULL);
+
+ XtManageChild(f2child);
+ XtManageChild(frame2);
+
+ /* box for the OK/Cancel button */
+ box = XtVaCreateManagedWidget("box", xmFormWidgetClass,
+ pane,
+ XmNskipAdjust, True, /* don't resize this area */
+ XTranslations, xlats,
+ NULL);
+
+ if (act == FILE_PRINT)
+ str = XmStringCreateLocalized("Print");
+ else
+ str = XmStringCreateLocalized("Save");
+ ok_button[act] = XtVaCreateManagedWidget(act == FILE_PRINT ? "print_button" : "save_button",
+ xmPushButtonWidgetClass, box,
+ XmNlabelString, str,
+ XmNshowAsDefault, True,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ /* to mimick appearance of native dialog buttons: */
+ XmNmarginWidth, 6,
+ XmNmarginHeight, 4,
+ XmNtopOffset, 10,
+ XmNbottomOffset, 10,
+ XmNleftOffset, 10,
+ NULL);
+ XmStringFree(str);
+ if (act == FILE_PRINT)
+ XtAddCallback(ok_button[act], XmNactivateCallback, cb_print_or_save, (XtPointer)info);
+ else
+ XtAddCallback(ok_button[act], XmNactivateCallback, cb_print_or_save, (XtPointer)info);
+
+ XtOverrideTranslations(ok_button[act], XtParseTranslationTable("<Key>Return:ArmAndActivate()"));
+
+ str = XmStringCreateLocalized("Cancel");
+ cancel_button[act] = XtVaCreateManagedWidget("cancel",
+ xmPushButtonWidgetClass, box,
+ XmNlabelString, str,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ /* to mimick appearance of native dialog buttons: */
+ XmNmarginWidth, 6,
+ XmNmarginHeight, 4,
+ XmNtopOffset, 10,
+ XmNbottomOffset, 10,
+ XmNrightOffset, 10,
+ NULL);
+ XmStringFree(str);
+
+ XtOverrideTranslations(range_all_radio[act], xlats);
+ XtOverrideTranslations(range_marked_radio[act], xlats);
+ XtOverrideTranslations(range_from_to_radio[act], xlats);
+ XtOverrideTranslations(ok_button[act], xlats);
+ XtOverrideTranslations(cancel_button[act], xlats);
+
+ if (act == FILE_PRINT)
+ XtAddCallback(cancel_button[act], XmNactivateCallback, cb_print_cancel, (XtPointer)info);
+ else
+ XtAddCallback(cancel_button[act], XmNactivateCallback, cb_save_cancel, (XtPointer)info);
+
+ { /* make the buttons the same size: */
+ Dimension w1, w2;
+ XtVaGetValues(ok_button[act], XtNwidth, &w1, NULL);
+ XtVaGetValues(cancel_button[act], XtNwidth, &w2, NULL);
+ if (w1 < w2)
+ XtVaSetValues(ok_button[act], XtNwidth, w2, NULL);
+ else if (w2 > w1)
+ XtVaSetValues(cancel_button[act], XtNwidth, w1, NULL);
+ }
+
+ if (pageinfo_have_marked_pages()) {
+ XmToggleButtonGadgetSetState(range_marked_radio[act], True, True);
+ }
+ else if (save_pr_info.range_radio == PRINT_MARKED) {
+ XmToggleButtonGadgetSetState(range_all_radio[act], True, True);
+ }
+
+ XtManageChild(form);
+ XtManageChild(pane);
+ center_window(top_level_shell, globals.widgets.top_level);
+ XtMapWidget(top_level_shell);
+ XmProcessTraversal(ok_button[act], XmTRAVERSE_CURRENT);
+#endif /* not MOTIF */
+
+ /* set default output format */
+ save_save_info.output_format = curr_save_info.output_format =
+ output_format_mapping[resource.default_saving_format].fmt;
+
+ if (act == FILE_SAVE)
+ update_dvips_options_sensitivity(resource.default_saving_format, top_level_shell);
+
+ return top_level_shell;
+}
+#undef HORIZONTAL_RESIZING_NO
+#undef HORIZONTAL_RESIZING_YES
+#undef VERTICAL_RESIZING_NO
+
+
+static void
+set_target_radio(struct dialog_info *save_info, struct dialog_info *curr_info, printOrSaveActionT act)
+{
+#ifdef MOTIF
+ if (save_info->print_radio > 0 && save_info->print_radio != curr_info->print_radio) {
+ XmToggleButtonGadgetSetState(save_info->print_radio == PRINT_TO_PRINTER
+ ? to_printer_radio
+ : to_file_radio_or_label[act], True, True);
+ }
+#else /* MOTIF */
+ UNUSED(act);
+ UNUSED(curr_info);
+ XawToggleSetCurrent(to_printer_radio, (XtPointer)save_info->print_radio);
+#endif /* MOTIF */
+}
+
+static void
+set_range_radio(struct dialog_info *save_info, struct dialog_info *curr_info, printOrSaveActionT act)
+{
+#ifdef MOTIF
+ if (save_info->range_radio > 0 && save_info->range_radio != curr_info->range_radio) {
+ Widget selected = 0;
+ switch (save_info->range_radio) {
+ case PRINT_ALL:
+ case SAVE_ALL:
+ selected = range_all_radio[act];
+ break;
+ case PRINT_MARKED:
+ case SAVE_MARKED:
+ selected = range_marked_radio[act];
+ break;
+ case PRINT_RANGE:
+ case SAVE_RANGE:
+ selected = range_from_to_radio[act];
+ break;
+ default:
+ ASSERT(0, "wrong button type in set_range_radio()");
+ }
+ XmToggleButtonGadgetSetState(selected, True, True);
+ }
+#else /* MOTIF */
+ UNUSED(curr_info);
+ XawToggleSetCurrent(range_all_radio[act], (XtPointer)save_info->range_radio);
+#endif /* MOTIF */
+}
+
+void
+save_or_print_callback(struct save_or_print_info *info)
+{
+ printOrSaveActionT act = info->act;
+ static char ofstring[1024]; /* should be ample */
+ struct dialog_info *save_info = NULL, *curr_info = NULL;
+
+ if (act == FILE_PRINT) {
+ save_info = &save_pr_info;
+ curr_info = &curr_pr_info;
+ if (print_is_active) {
+ XBell(DISP, 0);
+ XRaiseWindow(DISP, XtWindow(print_shell));
+ return;
+ }
+
+ if (printlog_raise_active()) {
+ XBell(DISP, 0);
+ return;
+ }
+ }
+ else if (act == FILE_SAVE) {
+ save_info = &save_save_info;
+ curr_info = &curr_save_info;
+ if (save_is_active) {
+ XBell(DISP, 0);
+ XRaiseWindow(DISP, XtWindow(save_shell));
+ return;
+ }
+ }
+ else {
+ ASSERT(0, "wrong action type in save_or_print_callback()");
+ }
+
+ if (globals.dvi_file.bak_fp == NULL) {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ NULL,
+ "Empty or incomplete DVI file. "
+ "Please select a new DVI file via File -> Open.");
+ return;
+ }
+
+ if (globals.pageno_correct == 1)
+ sprintf(ofstring, "of %d physical pages", total_pages);
+ else
+ sprintf(ofstring, "of %d to %d pages", globals.pageno_correct, total_pages + globals.pageno_correct - 1);
+
+ if (act == FILE_PRINT && print_shell == NULL) {
+ curr_info->print_radio = resource.default_printing_target;
+ print_shell = create_print_or_save_window(info, ofstring);
+#ifdef MOTIF
+ set_sensitivity(resource.default_printing_target);
+#endif
+ }
+ else if (act == FILE_SAVE && save_shell == NULL)
+ save_shell = create_print_or_save_window(info, ofstring);
+ else { /* if the window was already created */
+#ifdef MOTIF
+ XmString str;
+#endif
+ /* XXX: is this actually needed??? */
+ /* XXX: To test, remove the following */
+ if (!pageinfo_have_marked_pages()) {
+ if (act == FILE_PRINT && save_pr_info.range_radio == PRINT_MARKED) {
+ save_pr_info.range_radio = PRINT_ALL;
+ }
+ else if (act == FILE_SAVE && save_save_info.range_radio == SAVE_MARKED) {
+ save_save_info.range_radio = SAVE_ALL;
+ }
+ }
+
+ if (act == FILE_PRINT)
+ set_target_radio(save_info, curr_info, act);
+ set_range_radio(save_info, curr_info, act);
+#ifdef MOTIF
+ str = XmStringCreateLocalized(ofstring);
+ XtVaSetValues(of_label[act], XmNlabelString, str, NULL);
+ XmStringFree(str);
+
+ /* FIXME: this seems neccessary, otherwise labels are misaligned
+ again if window is closed and opened a second time? */
+ adjust_heights(range_from_to_radio[act],
+ from_label[act], page_from_text[act],
+ to_label[act], page_to_text[act],
+ of_label[act],
+ NULL);
+
+ if (save_info->dvips_options != NULL) {
+ XtVaSetValues(dvips_options_text[act], XmNvalue, save_info->dvips_options,
+ XmNcursorPosition, strlen(save_info->dvips_options), NULL);
+ }
+ else {
+ XtVaSetValues(dvips_options_text[act], XmNvalue, "", NULL);
+ }
+#else /* MOTIF */
+ XtVaSetValues(of_label[act], XtNlabel, ofstring, NULL);
+
+ if (save_info->dvips_options != NULL) {
+ XtVaSetValues(dvips_options_text[act], XtNstring, save_info->dvips_options, NULL);
+ XawTextSetInsertionPoint(dvips_options_text[act], strlen(save_info->dvips_options));
+ }
+ else {
+ XtVaSetValues(dvips_options_text[act], XtNstring, "", NULL);
+ }
+#endif /* MOTIF */
+ }
+
+ get_initial_dialog_values(save_info, act);
+
+#ifdef MOTIF
+ if (act == FILE_PRINT)
+ XtVaSetValues(print_to_printer_text, XmNvalue, save_info->printer_name,
+ XmNcursorPosition, strlen(save_info->printer_name), NULL);
+
+ XtVaSetValues(dvips_options_text[act], XmNvalue, save_info->dvips_options,
+ XmNcursorPosition, strlen(save_info->dvips_options), NULL);
+
+ XtVaSetValues(page_from_text[act], XmNvalue, save_info->from_page,
+ XmNcursorPosition, strlen(save_info->from_page), NULL);
+
+ XtVaSetValues(page_to_text[act], XmNvalue, save_info->to_page,
+ XmNcursorPosition, strlen(save_info->to_page), NULL);
+#else /* MOTIF */
+ if (act == FILE_PRINT) {
+ XtVaSetValues(print_to_printer_text, XtNstring, save_info->printer_name, NULL);
+ XawTextSetInsertionPoint(print_to_printer_text, strlen(save_info->printer_name));
+ }
+
+ XtVaSetValues(dvips_options_text[act], XtNstring, save_info->dvips_options, NULL);
+ XawTextSetInsertionPoint(dvips_options_text[act], strlen(save_info->dvips_options));
+
+ XtVaSetValues(page_from_text[act], XtNstring, save_info->from_page, NULL);
+ XawTextSetInsertionPoint(page_from_text[act], strlen(save_info->from_page));
+
+ XtVaSetValues(page_to_text[act], XtNstring, save_info->to_page, NULL);
+ XawTextSetInsertionPoint(page_to_text[act], strlen(save_info->to_page));
+#endif /* MOTIF */
+
+ if (act == FILE_PRINT) {
+ if (pageinfo_have_marked_pages()) {
+ XtSetSensitive(range_marked_radio[FILE_PRINT], True);
+ }
+ else {
+ XtSetSensitive(range_marked_radio[FILE_PRINT], False);
+ }
+ ASSERT(save_pr_info.range_radio != PRINT_MARKED || pageinfo_have_marked_pages(),
+ "PRINT_MARKED shouldn't be togglable if there are no marked pages!");
+ }
+ else if (act == FILE_SAVE) {
+ if (pageinfo_have_marked_pages()) {
+ XtSetSensitive(range_marked_radio[FILE_SAVE], True);
+ }
+ else {
+ XtSetSensitive(range_marked_radio[FILE_SAVE], False);
+ }
+ ASSERT(save_save_info.range_radio != SAVE_MARKED || pageinfo_have_marked_pages(),
+ "SAVE_MARKED shouldn't be togglable if there are no marked pages!");
+ }
+
+ set_outfile_name(save_info, &curr_save_info, act);
+
+#ifdef MOTIF
+ XtVaSetValues(print_to_file_text[act], XmNvalue, save_info->file_name,
+ XmNcursorPosition, strlen(save_info->file_name), NULL);
+#else /* MOTIF */
+ XtVaSetValues(print_to_file_text[act], XtNstring, save_info->file_name, NULL);
+ XawTextSetInsertionPoint(print_to_file_text[act], strlen(save_info->file_name));
+#endif /* MOTIF */
+
+ if (act == FILE_PRINT) {
+ XtPopup(print_shell, XtGrabNone);
+ print_is_active = True;
+ }
+ else {
+ XtPopup(save_shell, XtGrabNone);
+ save_is_active = True;
+ }
+}
+
+static int
+getpageno(Widget w)
+{
+ char *s, *p;
+ int pageno;
+#ifndef MOTIF
+ XtVaGetValues(w, XtNstring, &s, NULL);
+#else /* MOTIF */
+ s = XmTextFieldGetString(w);
+#endif
+ p = s;
+ if (*p == '-')
+ ++p;
+ if (!isdigit((int)*p)) {
+ return 0;
+ }
+ do {
+ ++p;
+ } while (isdigit((int)*p));
+ if (*p != '\0')
+ return 0;
+
+ pageno = atoi(s) - globals.pageno_correct;
+#ifdef MOTIF
+ XtFree(s);
+#endif
+ return pageno;
+}
+
+
+/*
+ return text value of Widget w in newly allocated memory,
+ free()ing old_val as appropriate. Returns NULL if
+ text value starts with '\0'.
+*/
+static char *
+get_saved_command(char **old_val, Widget w)
+{
+ char *val = NULL;
+
+ if (*old_val != NULL) {
+#if MOTIF
+ XtFree((char *)*old_val);
+#else
+ free((char*)*old_val);
+#endif
+ *old_val = NULL;
+ }
+#if MOTIF
+ val = XmTextFieldGetString(w);
+ if (*val == '\0') {
+ XtFree((char *)val);
+ val = NULL;
+ }
+#else
+ XtVaGetValues(w, XtNstring, &val, NULL);
+ if (*val == '\0') {
+ val = NULL;
+ }
+ else {
+ val = xstrdup(val);
+ }
+#endif
+ return val;
+}
+
+/* fill curr_print_info and save_print_info with current values */
+static void
+get_save_window_state(struct dialog_info *save_info, struct dialog_info *curr_info, printOrSaveActionT act)
+{
+ save_info->print_radio = curr_info->print_radio;
+ save_info->range_radio = curr_info->range_radio;
+
+ if (act == FILE_PRINT) {
+ save_info->printer_name = get_saved_command(&(save_info->printer_name), print_to_printer_text);
+ curr_info->printer_name = get_saved_command(&(curr_info->printer_name), print_to_printer_text);
+ }
+ save_info->file_name = get_saved_command(&(save_info->file_name), print_to_file_text[act]);
+ curr_info->file_name = get_saved_command(&(curr_info->file_name), print_to_file_text[act]);
+
+ save_info->dvips_options = get_saved_command(&(save_info->dvips_options), dvips_options_text[act]);
+ curr_info->dvips_options = get_saved_command(&(curr_info->dvips_options), dvips_options_text[act]);
+
+ save_info->from_page = get_saved_command(&(save_info->from_page), page_from_text[act]);
+ save_info->to_page = get_saved_command(&(save_info->to_page), page_to_text[act]);
+
+ TRACE_GUI((stderr, "saved options:\nprinter: |%s|, file: |%s|, dvips: |%s|, from: |%s|, to: |%s|\n",
+ save_info->printer_name ? save_info->printer_name : "<NULL>",
+ save_info->file_name ? save_info->file_name : "<NULL>",
+ save_info->dvips_options ? save_info->dvips_options : "<NULL>",
+ save_info->from_page ? save_info->from_page : "<NULL>",
+ save_info->to_page ? save_info->to_page : "<NULL>"));
+}
+
+static void
+popdown_dialog_and_print_or_save(XtPointer myinfo)
+{
+ struct save_or_print_info *info = (struct save_or_print_info *)myinfo;
+ struct select_pages_info *pinfo = (struct select_pages_info *)info->pinfo;
+ struct dialog_info *curr_info = NULL;
+
+ /* pop down the dialog */
+ if (pinfo->act == FILE_PRINT) {
+ curr_info = &save_pr_info;
+ cb_print_cancel(NULL, info, NULL);
+ /* when printing to file, set ps_out.fname to non-NULL; this will
+ notify called routines that printing should go to the file */
+ if (curr_info->print_radio == PRINT_TO_FILE) {
+ pinfo->finfo->ps_out.fname = xstrdup(curr_info->expanded_filename);
+ }
+ }
+ else {
+ curr_info = &save_save_info;
+ cb_save_cancel(NULL, info, NULL);
+ }
+
+ if (globals.dvi_file.bak_fp == NULL) { /* shouldn't happen */
+ info->message_popup = popup_message(globals.widgets.top_level,
+ MSG_ERR, NULL,
+ "No active DVI file");
+ return;
+ }
+
+ ASSERT(pinfo->finfo->dvi_in.fp != NULL, "DVI input FILE * must have been set!");
+
+ /* when saving, set the final file names */
+ if (curr_info->range_radio == SAVE_RANGE
+ || curr_info->range_radio == SAVE_MARKED
+ || curr_info->range_radio == SAVE_ALL) {
+ switch (curr_info->output_format) {
+ case FMT_DVI:
+ pinfo->finfo->dvi_out.fname = xstrdup(curr_info->expanded_filename);
+ TRACE_GUI((stderr, "DVI out_name: |%s|", pinfo->finfo->dvi_out.fname));
+ break;
+ case FMT_PS:
+ pinfo->finfo->ps_out.fname = xstrdup(curr_info->expanded_filename);
+ TRACE_GUI((stderr, "PS out_name: |%s|", pinfo->finfo->ps_out.fname));
+ break;
+ case FMT_PS2PDF:
+ pinfo->finfo->pdf_out.fname = xstrdup(curr_info->expanded_filename);
+ TRACE_GUI((stderr, "PDF out_name: |%s|", pinfo->finfo->pdf_out.fname));
+ break;
+ case FMT_ISO_8859_1:
+ case FMT_UTF8:
+ pinfo->finfo->txt_out.fname = xstrdup(curr_info->expanded_filename);
+ TRACE_GUI((stderr, "TXT out_name: |%s|", pinfo->finfo->txt_out.fname));
+ break;
+ case FMT_NONE:
+ break;
+ }
+ }
+
+ /* add info about page ranges */
+ switch (curr_info->range_radio) {
+ case SAVE_RANGE:
+ case PRINT_RANGE:
+ /* convert from 1-based to 0-based */
+ pinfo->from = strtoul(curr_info->from_page, (char **)NULL, 10) - 1;
+ pinfo->to = strtoul(curr_info->to_page, (char **)NULL, 10) - 1;
+ pinfo->callback = check_pagerange;
+ break;
+ case SAVE_MARKED:
+ case PRINT_MARKED:
+ pinfo->callback = check_marked;
+ break;
+ case SAVE_ALL:
+ case PRINT_ALL:
+ pinfo->callback = NULL;
+ break;
+ case NO_PAGE_VAL:
+ ASSERT(0, "Shouldn't happen: NO_PAGE_VAL passed to popdown_dialog_and_print_or_save()");
+ break;
+ }
+
+ store_preference(NULL, "dvipsOptionsString", "%s", save_pr_info.dvips_options ? save_pr_info.dvips_options : "");
+ if (pinfo->act == FILE_PRINT) {
+ store_preference(NULL, "defaultPrintingTarget", "%d", save_pr_info.print_radio);
+ store_preference(NULL, "dvipsPrinterString", "%s", save_pr_info.printer_name ? save_pr_info.printer_name : "");
+ internal_print(pinfo);
+ }
+ else {
+ store_preference(NULL, "defaultSavingFormat", "%d", save_save_info.output_format);
+ internal_save(pinfo, curr_info->output_format);
+ }
+}
+
+/* Clean up after user has aborted printing/saving */
+static void
+do_cleanup(XtPointer arg)
+{
+ struct save_or_print_info *info = (struct save_or_print_info *)arg;
+ struct select_pages_info *pinfo = (struct select_pages_info *)info->pinfo;
+ struct file_info *finfo = pinfo->finfo;
+
+ cancel_saving(info);
+ unlink(finfo->dvi_tmp.fname);
+}
+
+/* XXX: is the save_* stuff actually *needed*??? */
+static Boolean
+validate_and_save_values(struct save_or_print_info *info)
+{
+ int page_range_begin, page_range_end;
+ printOrSaveActionT act = info->act;
+
+ if ((act == FILE_PRINT && curr_pr_info.range_radio == PRINT_RANGE)
+ || (act == FILE_SAVE && curr_save_info.range_radio == SAVE_RANGE)) {
+ page_range_begin = getpageno(page_from_text[act]);
+ page_range_end = getpageno(page_to_text[act]);
+ if (page_range_begin + 1 < 1) {
+ info->message_popup =
+ popup_message(act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR,
+ "Please specify a valid page range.",
+ "Invalid page range: start (%d) < 1.",
+ page_range_begin + 1);
+ return False;
+ }
+ else if (page_range_begin > page_range_end) {
+ info->message_popup =
+ popup_message(act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR,
+ "Please specify a valid page range.",
+ "Invalid page range: start (%d) > end (%d).",
+ page_range_begin + 1, page_range_end + 1);
+ return False;
+ }
+ else if (page_range_end + 1 > total_pages) {
+ info->message_popup =
+ popup_message(act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR,
+ "Please specify a valid page range.",
+ "Invalid page range: end (%d) > total_pages (%d).",
+ page_range_end + 1, total_pages);
+ return False;
+ }
+
+ if (act == FILE_PRINT) {
+ curr_pr_info.from_page = xrealloc(curr_pr_info.from_page, LENGTH_OF_INT + 1);
+ curr_pr_info.to_page = xrealloc(curr_pr_info.to_page, LENGTH_OF_INT + 1);
+ sprintf(curr_pr_info.from_page, "%d", page_range_begin);
+ sprintf(curr_pr_info.to_page, "%d", page_range_end);
+ }
+ else {
+ curr_save_info.from_page = xrealloc(curr_save_info.from_page, LENGTH_OF_INT + 1);
+ curr_save_info.to_page = xrealloc(curr_save_info.to_page, LENGTH_OF_INT + 1);
+ sprintf(curr_save_info.from_page, "%d", page_range_begin);
+ sprintf(curr_save_info.to_page, "%d", page_range_end);
+ }
+ }
+
+ if (act == FILE_PRINT)
+ get_save_window_state(&save_pr_info, &curr_pr_info, act);
+ else
+ get_save_window_state(&save_save_info, &curr_save_info, act);
+
+ return True;
+}
+
+/*
+ * Routines for freeing allocated resources in file_info:
+ * close file pointers, and free file name memory.
+ */
+static void
+free_file_info(struct file_IO *info)
+{
+ if (info->fp != NULL) {
+ fclose(info->fp);
+ info->fp = NULL;
+ }
+ free(info->fname);
+ info->fname = NULL;
+}
+
+static void
+reset_file_info(struct file_info *finfo)
+{
+ free_file_info(&(finfo->dvi_in));
+ free_file_info(&(finfo->dvi_tmp));
+ free_file_info(&(finfo->dvi_out));
+ free_file_info(&(finfo->ps_out));
+ free_file_info(&(finfo->pdf_out));
+ free_file_info(&(finfo->txt_out));
+}
+
+/*
+ First round of sanity checks. Note the use of curr_pr_info here;
+ this is before the values are saved to save_pr_info.
+*/
+static void
+print_precheck1(XtPointer myinfo)
+{
+ /* Initialize structures with defaults. Note: structures are
+ static, so that they survive between calls, and to make memory
+ management with callbacks (and all the stuff in print-internal.c)
+ easier.
+ */
+ struct save_or_print_info *info = (struct save_or_print_info *)myinfo;
+ printOrSaveActionT act = info->act;
+ static struct select_pages_info pinfo = {
+ FILE_ALL, 0, 0, NULL, check_marked, { 0, NULL }, NO_ERROR
+ };
+ static struct file_info finfo = {
+ { NULL, NULL },
+ { NULL, NULL },
+ { NULL, NULL },
+ { NULL, NULL },
+ { NULL, NULL },
+ { NULL, NULL }
+ };
+ char *ok_button_str = NULL;
+ FILE *fin = NULL;
+
+ /* Return if there are active popups; otherwise, the print process
+ may get messed up */
+ if (raise_message_windows()) {
+ XBell(DISP, 0);
+/* popup_message(pinfo.act == FILE_PRINT ? print_shell : save_shell, */
+/* MSG_WARN, NULL, */
+/* "Please close other open message windows first!"); */
+ return;
+ }
+
+ /* free all pointers in case we've been called again */
+ reset_file_info(&finfo);
+
+ pinfo.finfo= &finfo; /* pass finfo in data field of pinfo to callbacks etc. */
+ pinfo.act = act;
+ info->pinfo = &pinfo;
+
+ /* Validate page ranges, and if they are correct, save them to the
+ * appropriate save_save_info/save_print_info structure.
+ * NOTE: From here on, always use the save_* variants to retrieve values!
+ */
+ if (!validate_and_save_values(info))
+ return;
+
+ /* We need to create a temporary DVI file containing the selected or all pages
+ if we want to do one of the following:
+ - print the marked pages
+ - save to a DVI file
+ - print only the marked pages to a PS or a PDF file.
+ */
+ if ((pinfo.act == FILE_PRINT && curr_pr_info.range_radio == PRINT_MARKED)
+ || (pinfo.act == FILE_SAVE
+ && (save_save_info.output_format == FMT_DVI
+ || ((save_save_info.output_format == FMT_PS || save_save_info.output_format == FMT_PS2PDF)
+ && save_save_info.range_radio == SAVE_MARKED)))) {
+ /* need to create a temporary DVI file containing the selected pages */
+ int tmp_fd = xdvi_temp_fd(&(finfo.dvi_tmp.fname)); /* this allocates finfo.dvi_tmp.fname */
+
+ if (tmp_fd == -1) {
+ info->message_popup =
+ popup_message(pinfo.act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR, NULL,
+ "Couldn't create temporary DVI file for printing: %s", strerror(errno));
+ return;
+ }
+ /* don't use XFOPEN here, since we don't want to treat an error in opening the file as fatal. */
+ /* `b' in mode won't hurt ... */
+ if ((finfo.dvi_tmp.fp = try_fdopen(tmp_fd, "wb+")) == NULL) { /* failure */
+ info->message_popup =
+ popup_message(pinfo.act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR,
+ "Xdvi needs to create a temporary file containing the "
+ "currently marked pages, but creating that file failed. "
+ "Try to fix the cause of the problem, or choose "
+ "\"Print selected pages\" as a workaround.",
+ "Could not open temp file for writing: %s.\n",
+ strerror(errno));
+ return;
+ }
+ }
+ /* We try to use the original DVI file unless it's corrupted, in which case
+ we ask the user if they want to save the cached copy instead */
+ if ((fin = fopen(globals.dvi_name, "rb")) == NULL
+ || !find_postamble(fin, &(pinfo.errflag))) {
+ Boolean could_not_open = False;
+ if (fin == NULL)
+ could_not_open = True;
+ if (fin)
+ fclose(fin);
+
+ /* if we can't use the temporary file as source for our copy, this is a fatal error */
+ if (!resource.use_temp_fp) {
+ info->message_popup =
+ popup_message(pinfo.act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR, NULL,
+ "Could not copy DVI file %s: The file %s",
+ globals.dvi_name, could_not_open ? "doesn't exist any more" : "seems to be corrupted");
+ return;
+ }
+
+ /* else, we'll try to use the cached copy of the DVI file */
+ if ((fin = fopen(get_tmp_dvi_name(), "rb")) == NULL) {
+ info->message_popup =
+ popup_message(pinfo.act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR, NULL,
+ "Something's very wrong here - opening of both the "
+ "original DVI file and the cached copy failed!");
+ return;
+ }
+
+ if (!find_postamble(fin, &(pinfo.errflag))) {
+ info->message_popup =
+ popup_message(pinfo.act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR, NULL,
+ "Shouldn't happen: Cached copy of the DVI file seems corrupted!");
+ return;
+ }
+ finfo.dvi_in.fp = fin;
+
+ /* tell user about it */
+ if (pinfo.act == FILE_PRINT)
+ ok_button_str = "Print Copy";
+ else
+ ok_button_str = "Save Copy";
+
+ info->message_popup =
+ choice_dialog(pinfo.act == FILE_PRINT ? print_shell : save_shell,
+ MSG_QUESTION, NULL,
+#ifndef MOTIF
+ NULL, /* TODO: binding for RET? */
+#endif /* MOTIF */
+ NULL, NULL, /* no pre_callbacks */
+ ok_button_str, print_precheck2, (XtPointer)info,
+ "Cancel", do_cleanup, (XtPointer)info,
+ "The DVI file %s %s. Do you want to %s a cached copy of the file?",
+ globals.dvi_name,
+ could_not_open ? "doesn't exist any more" : "seems to be corrupted",
+ pinfo.act == FILE_PRINT ? "print" : "save");
+ }
+ else { /* original DVI file is OK, copy it */
+ finfo.dvi_in.fp = fin;
+ print_precheck2((XtPointer)info);
+ }
+}
+
+static void
+print_precheck2(XtPointer myinfo)
+{
+ struct save_or_print_info *info = (struct save_or_print_info *)myinfo;
+ char *expanded_filename = NULL;
+ struct select_pages_info *pinfo = (struct select_pages_info *)info->pinfo;
+ printOrSaveActionT act = pinfo->act;
+ const char *fname;
+
+ /* Return if there are active popups; otherwise, the print process
+ will be messed up. */
+ if (raise_message_windows()) {
+ XBell(DISP, 0);
+ return;
+ }
+
+ /* expand and canonicalize path name */
+ if (act == FILE_PRINT)
+ fname = save_pr_info.file_name;
+ else
+ fname = save_save_info.file_name;
+
+ if (fname == NULL) {
+ info->message_popup =
+ popup_message(act == FILE_PRINT ? print_shell : save_shell,
+ MSG_WARN,
+ NULL,
+ "No filename specified!");
+ return;
+ }
+ expanded_filename = expand_homedir(fname); /* this allocates expanded_filename */
+ if (expanded_filename == NULL) {
+ info->message_popup =
+ popup_message(act == FILE_PRINT ? print_shell : save_shell,
+ MSG_WARN,
+ "Please specify either a filename or a full path, without using \"~\" or \"~user\".",
+ "Couldn't expand filename \"%s\" to a full path.",
+ fname);
+ return;
+ }
+
+ if (act == FILE_PRINT) {
+ free(save_pr_info.expanded_filename);
+ save_pr_info.expanded_filename = expanded_filename;
+ }
+ else {
+ free(save_save_info.expanded_filename);
+ save_save_info.expanded_filename = expanded_filename;
+ }
+
+
+ if (act == FILE_SAVE && save_save_info.output_format == FMT_DVI) { /* canonicalize filename */
+ char *tmp = expand_filename_append_dvi(save_save_info.expanded_filename, USE_CWD_PATH, False);
+ if (strcmp(tmp, globals.dvi_name) == 0) {
+ info->message_popup =
+ popup_message(act == FILE_PRINT ? print_shell : save_shell,
+ MSG_ERR,
+ NULL,
+ "Cannot overwrite the current DVI file (%s). "
+ "Please select a different file name.",
+ save_save_info.expanded_filename);
+ free(tmp);
+ return;
+ }
+ free(save_save_info.expanded_filename);
+ save_save_info.expanded_filename = tmp;
+ }
+ if (act == FILE_SAVE || (act == FILE_PRINT && curr_pr_info.print_radio == PRINT_TO_FILE)) {
+ /* check whether to clobber existing file */
+ struct stat statbuf;
+
+ if ((act == FILE_SAVE
+ && stat(save_save_info.expanded_filename, &statbuf) == 0
+ && S_ISREG(statbuf.st_mode))
+ || (act == FILE_PRINT
+ && stat(save_pr_info.expanded_filename, &statbuf) == 0
+ && S_ISREG(statbuf.st_mode))) {
+
+ info->message_popup =
+ choice_dialog(act == FILE_PRINT ? print_shell : save_shell,
+ MSG_QUESTION, NULL,
+#ifndef MOTIF
+ NULL, /* TODO: binding for RET */
+#endif
+ NULL, NULL, /* no pre_callbacks */
+ "Replace", popdown_dialog_and_print_or_save, (XtPointer)info,
+ /*
+ do nothing if user selects `cancel'; this will return to the
+ printing dialog, since user hasn't changed their mind about
+ printing, but would probably just like to choose another filename
+ */
+ "Cancel", NULL, (XtPointer)NULL,
+ "%s already exists.\nDo you want to replace it?",
+ act == FILE_SAVE
+ ? save_save_info.expanded_filename
+ : save_pr_info.expanded_filename);
+ return;
+ }
+ else {
+ popdown_dialog_and_print_or_save(info);
+ }
+ }
+ else {
+ popdown_dialog_and_print_or_save(info);
+ }
+}
+
+/* called from pagesel.c if user marks or unmarks a page in the page list */
+void
+notify_print_dialog_have_marked(Boolean flag)
+{
+ /* Note: check for *both* windows, save and print: */
+
+ static pageRadioT old_value = NO_PAGE_VAL;
+
+ if (save_is_active) {
+ if (!flag && curr_save_info.range_radio == SAVE_MARKED) {
+ /* switch button from `marked' to its previous value */
+ switch (old_value) {
+ case SAVE_ALL:
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(range_all_radio[FILE_SAVE], True, True);
+#else
+ XawToggleSetCurrent(range_all_radio[FILE_SAVE], (XtPointer)old_value);
+#endif
+ break;
+ case SAVE_RANGE:
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(range_from_to_radio[FILE_SAVE], True, True);
+#else
+ XawToggleSetCurrent(range_from_to_radio[FILE_SAVE], (XtPointer)old_value);
+#endif
+ break;
+ default: break;
+ }
+ }
+ else if (flag) {
+ /* switch button to `marked', saving the current value */
+ if (curr_save_info.range_radio != SAVE_MARKED) /* guard for second invocation on mouse release */
+ old_value = curr_save_info.range_radio;
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(range_marked_radio[FILE_SAVE], True, True);
+#else
+ XawToggleSetCurrent(range_marked_radio[FILE_SAVE], (XtPointer)SAVE_MARKED);
+#endif /* MOTIF */
+ }
+ XtSetSensitive(range_marked_radio[FILE_SAVE], flag);
+ }
+
+ if (print_is_active) {
+ if (!flag && curr_pr_info.range_radio == PRINT_MARKED) {
+ /* switch button from `marked' to its previous value */
+ switch (old_value) {
+ case PRINT_ALL:
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(range_all_radio[FILE_PRINT], True, True);
+#else
+ XawToggleSetCurrent(range_all_radio[FILE_PRINT], (XtPointer)old_value);
+#endif
+ break;
+ case PRINT_RANGE:
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(range_from_to_radio[FILE_PRINT], True, True);
+#else
+ XawToggleSetCurrent(range_from_to_radio[FILE_PRINT], (XtPointer)old_value);
+#endif
+ break;
+ default: break;
+ }
+ }
+ else if (flag) {
+ /* switch button to `marked', saving the current value */
+ if (curr_pr_info.range_radio != PRINT_MARKED) /* guard for second invocation on mouse release */
+ old_value = curr_pr_info.range_radio;
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(range_marked_radio[FILE_PRINT], True, True);
+#else
+ XawToggleSetCurrent(range_marked_radio[FILE_PRINT], (XtPointer)PRINT_MARKED);
+#endif /* MOTIF */
+ }
+ XtSetSensitive(range_marked_radio[FILE_PRINT], flag);
+ }
+}
diff --git a/Build/source/texk/xdvik/gui/print-dialog.h b/Build/source/texk/xdvik/gui/print-dialog.h
new file mode 100644
index 00000000000..95f73de3e18
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/print-dialog.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2003-2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PRINT_DIALOG_H_
+#define PRINT_DIALOG_H_
+
+#define Xdvi_SAVE_SHELL_NAME "save_popup"
+#define Xdvi_PRINT_SHELL_NAME "print_popup"
+
+typedef enum { FILE_PRINT = 0, FILE_SAVE = 1, FILE_ALL = 2 } printOrSaveActionT;
+
+struct save_or_print_info {
+ printOrSaveActionT act;
+ Widget message_popup;
+ struct select_pages_info *pinfo;
+};
+
+extern void save_or_print_callback(struct save_or_print_info *info);
+extern void cancel_saving(struct save_or_print_info *info);
+extern const char *get_printer_options(void);
+extern char *get_dvips_options(printOrSaveActionT act);
+
+extern void notify_print_dialog_have_marked(Boolean flag);
+
+#endif /* PRINT_DIALOG_H_ */
diff --git a/Build/source/texk/xdvik/gui/print-log.c b/Build/source/texk/xdvik/gui/print-log.c
new file mode 100644
index 00000000000..dd1c26bc008
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/print-log.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 2002-2004 Paul Vojta and the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <string.h>
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "xdvi-debug.h"
+#include "print-dialog.h"
+#include "print-log.h" /* for adjust_vertically() */
+#include "util.h"
+#include "x_util.h"
+#include "xlwradio.h"
+
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+
+/* FIXME: change #if XAW to #if !defined(MOTIF) to make it consistent with other files */
+
+#ifdef MOTIF
+# include <Xm/BulletinB.h>
+# include <Xm/DialogS.h>
+# include <Xm/MessageB.h>
+# include <Xm/LabelG.h>
+# include <Xm/Form.h>
+# include <Xm/Frame.h>
+# include <Xm/ToggleBG.h>
+# include <Xm/PanedW.h>
+# include <Xm/Text.h>
+# include <Xm/TextF.h>
+# include <Xm/PushB.h>
+# include <Xm/Protocols.h>
+# include <Xm/AtomMgr.h>
+#else
+# include <X11/Shell.h>
+# include <X11/Xaw/Paned.h>
+# include <X11/Xaw/Box.h>
+# include <X11/Xaw/Form.h>
+# include <X11/Xaw/Label.h>
+# include <X11/Xaw/Command.h>
+# include <X11/Xaw/Toggle.h>
+# include <X11/Xaw/AsciiText.h>
+
+/* XawFmt8Bit is only available starting with X11R6: */
+# if XtSpecificationRelease < 6
+# define XawFmt8Bit FMT8BIT
+# endif
+
+#endif /* MOTIF */
+
+static Boolean printlog_active = False; /* if the print log is active */
+static Widget printlog_shell = NULL;
+
+/* global callbacks - FIXME: avoid this, by passing the callback as argument to the action? */
+static void (*g_close_callback)(Widget w, XtPointer client_data, XtPointer call_data);
+static void (*g_cancel_callback)(Widget w, XtPointer client_data, XtPointer call_data);
+static void (*g_destroy_callback)(Widget w, XtPointer client_data, XtPointer call_data);
+
+static void printlog_act_close(Widget, XEvent *, String *, Cardinal *);
+static void printlog_act_keep(Widget, XEvent *, String *, Cardinal *);
+static void printlog_act_unkeep(Widget, XEvent *, String *, Cardinal *);
+static void printlog_act_cancel(Widget, XEvent *, String *, Cardinal *);
+static void printlog_act_destroy(Widget, XEvent *, String *, Cardinal *);
+
+#ifdef MOTIF
+static void xm_printlog_act_destroy(Widget w, XtPointer a, XtPointer b)
+{
+ UNUSED(w);
+ UNUSED(a);
+ UNUSED(b);
+ ASSERT(g_destroy_callback != NULL, "Callback not initialized");
+ (g_destroy_callback)(NULL, NULL, NULL);
+}
+#endif
+
+static Atom WM_DELETE_WINDOW;
+
+static XtActionsRec printlog_actions[] = {
+ {"printlogIntClose", printlog_act_close},
+ {"printlogIntKeep", printlog_act_keep},
+ {"printlogIntUnkeep", printlog_act_unkeep},
+ {"printlogIntCancel", printlog_act_cancel},
+ {"WM_destroy", printlog_act_destroy },
+};
+
+static char *text_translations = \
+ "<Key>Return:printlogIntClose()\n"
+ "^<Key>c:printlogIntCancel()\n"
+ "^<Key>s:printlogIntKeep()\n"
+ "^<Key>q:printlogIntUnkeep()";
+
+static Widget printlog_text;
+static Widget printlog_close;
+static Widget printlog_unkeep;
+static Widget printlog_cancel;
+
+
+#ifdef MOTIF
+static XmTextPosition printlog_length;
+#else
+static XawTextPosition printlog_length;
+#endif
+
+Boolean
+printlog_raise_active(void)
+{
+ if (printlog_active) {
+ XRaiseWindow(DISP, XtWindow(printlog_shell));
+ return True;
+ }
+ return False;
+}
+
+void
+printlog_popup(void)
+{
+ printlog_length = 0;
+ center_window(printlog_shell, globals.widgets.top_level);
+ XtMapWidget(printlog_shell);
+/* XtPopup(printlog_shell, XtGrabNone); */
+ printlog_active = True;
+#ifndef MOTIF
+ XSetWMProtocols(XtDisplay(printlog_shell), XtWindow(printlog_shell), &WM_DELETE_WINDOW, 1);
+#else
+ XmProcessTraversal(printlog_cancel, XmTRAVERSE_CURRENT);
+ XtOverrideTranslations(printlog_text, XtParseTranslationTable(text_translations));
+#endif
+}
+
+void
+printlog_reset(void)
+{
+ printlog_length = 0;
+}
+
+
+
+void
+printlog_create(const char *title,
+ const char *close_label,
+ void (*close_callback)(Widget w, XtPointer client_data, XtPointer call_data),
+ void (*cancel_callback)(Widget w, XtPointer client_data, XtPointer call_data),
+ void (*destroy_callback)(Widget w, XtPointer client_data, XtPointer call_data),
+ void (*unkeep_callback)(Widget w, XtPointer client_data, XtPointer call_data))
+{
+ /*
+ FIXME BETA: The printlog presents too much detail and is confusing for users.
+ Re-implement it using an `printing page n of m' message,
+ i.e. according to the spec on:
+ http://xdvi.sourceforge.net/gui.html#file-print
+ Possible save the detailed log to a different window that can be viewed
+ via `File -> logs', as described on:
+ http://xdvi.sourceforge.net/gui.html#file-logs
+ */
+ XtAddActions(printlog_actions, XtNumber(printlog_actions));
+ g_destroy_callback = destroy_callback;
+
+#ifndef MOTIF
+ /* Create popup window */
+ if (printlog_shell == NULL) {
+ Widget form, box, paned;
+/* int ddist; */
+/* Dimension w0, w1, w2, w3, b; */
+
+ XtTranslations wm_translations = XtParseTranslationTable("<Message>WM_PROTOCOLS: WM_destroy()");
+ printlog_shell = XtVaCreatePopupShell("printlog",
+ transientShellWidgetClass, globals.widgets.top_level,
+ XtNtitle, title,
+ XtNtransientFor, globals.widgets.top_level,
+ XtNmappedWhenManaged, False,
+ XtNtranslations, wm_translations,
+ XtNtransientFor, globals.widgets.top_level,
+ NULL);
+
+ WM_DELETE_WINDOW = XInternAtom(XtDisplay(printlog_shell), "WM_DELETE_WINDOW", False);
+
+ paned = XtVaCreateManagedWidget("paned", panedWidgetClass, printlog_shell, NULL);
+
+ form = XtVaCreateManagedWidget("form", formWidgetClass,
+ paned,
+ XtNdefaultDistance, 6,
+ NULL);
+ printlog_text = XtVaCreateManagedWidget("text",
+ asciiTextWidgetClass, form,
+ XtNstring, "",
+ XtNdataCompression, False,
+ XtNeditType, XawtextAppend,
+ XtNscrollHorizontal, XawtextScrollAlways,
+ XtNscrollVertical, XawtextScrollAlways,
+ XtNwidth, 600,
+ XtNheight, 400,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainRight,
+ XtNtop, XawChainTop,
+ XtNbottom, XawChainBottom,
+ NULL);
+ XtOverrideTranslations(printlog_text, XtParseTranslationTable(text_translations));
+
+ printlog_unkeep = XtVaCreateManagedWidget("keep",
+#ifdef XAW
+ radioWidgetClass,
+#else
+ toggleWidgetClass,
+#endif
+ form,
+ XtNlabel, close_label,
+ XtNborderWidth, 0,
+ XtNisRadio, False,
+ XtNhighlightThickness, 1,
+ XtNfromVert, printlog_text,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ XtNtop, XawChainBottom,
+ XtNbottom, XawChainBottom,
+ NULL);
+ XtVaSetValues(printlog_unkeep,
+ XtNstate, resource.dvips_hang > 0 && resource.dvips_fail_hang > 0,
+ NULL);
+ XtAddCallback(printlog_unkeep, XtNcallback, unkeep_callback, NULL);
+
+ /* box for the Close/Cancel button */
+ box = XtVaCreateManagedWidget("box", formWidgetClass,
+ paned,
+ /* resizing by user isn't needed */
+ XtNshowGrip, False,
+ XtNdefaultDistance, 6, /* some padding */
+ /* resizing the window shouldn't influence this box,
+ * but only the pane widget
+ */
+ XtNskipAdjust, True,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+
+ printlog_close = XtVaCreateManagedWidget("close",
+ commandWidgetClass, box,
+ XtNlabel, "Close",
+ XtNsensitive, False,
+ XtNleft, XawChainLeft,
+ XtNright, XawChainLeft,
+ XtNtop, XawChainBottom,
+ XtNbottom, XawChainBottom,
+ NULL);
+ XtAddCallback(printlog_close, XtNcallback, close_callback, NULL);
+ g_close_callback = close_callback;
+
+ printlog_cancel = XtVaCreateManagedWidget("cancel",
+ commandWidgetClass, box,
+ XtNlabel, "Cancel",
+ XtNfromHoriz, printlog_unkeep,
+ XtNleft, XawChainRight,
+ XtNright, XawChainRight,
+ XtNtop, XawChainBottom,
+ XtNbottom, XawChainBottom,
+ NULL);
+ XtAddCallback(printlog_cancel, XtNcallback, cancel_callback, NULL);
+ g_cancel_callback = cancel_callback;
+ XtManageChild(printlog_shell);
+ }
+ else {
+ XtSetSensitive(printlog_close, False);
+ XtSetSensitive(printlog_cancel, True);
+ }
+
+#else /* MOTIF */
+
+ /* Create popup window */
+ if (printlog_shell == NULL) {
+ Widget form, pane, box;
+ XmString str;
+ Arg args[10];
+ int n;
+
+ printlog_shell = XtVaCreatePopupShell("printlog",
+ xmDialogShellWidgetClass, globals.widgets.top_level,
+ XmNdeleteResponse, XmDO_NOTHING, /* we'll take care of that ourselves */
+ XmNtitle, title,
+ XtNmappedWhenManaged, False,
+ NULL);
+
+ WM_DELETE_WINDOW = XmInternAtom(XtDisplay(printlog_shell), "WM_DELETE_WINDOW", False);
+ XmAddWMProtocolCallback(printlog_shell, WM_DELETE_WINDOW, xm_printlog_act_destroy, NULL);
+
+ pane = XtVaCreateWidget("printlog_pane", xmPanedWindowWidgetClass, printlog_shell,
+ /* make sashes invisible */
+ XmNsashWidth, 1,
+ XmNsashHeight, 1,
+ NULL);
+
+ form = XtVaCreateWidget("form", xmFormWidgetClass, pane,
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+ XmNautoUnmanage, False,
+ NULL);
+ /* force vertical scrollbars. Under Motif 2.x (2.1.0 and 2.2.2 at least),
+ XmNeditMode must be set early in order to have an effect. */
+ n = 0;
+ XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
+ XtSetArg(args[n], XmNeditable, False); n++;
+ XtSetArg(args[n], XmNrows, 24); n++;
+ XtSetArg(args[n], XmNcolumns, 80); n++;
+
+ printlog_text = XmCreateScrolledText(form, "text", args, n);
+
+ XtVaSetValues(XtParent(printlog_text),
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+
+ XtManageChild(printlog_text);
+
+ str = XmStringCreateLocalized((char *)close_label);
+ printlog_unkeep = XtVaCreateManagedWidget("keep",
+ xmToggleButtonGadgetClass, form,
+ XmNlabelString, str,
+ XmNnavigationType, XmTAB_GROUP,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, XtParent(printlog_text),
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(printlog_unkeep, XmNvalueChangedCallback, unkeep_callback, NULL);
+ XmToggleButtonGadgetSetState(printlog_unkeep, resource.dvips_hang > 0 && resource.dvips_fail_hang > 0, False);
+
+ /* box for Close/Cancel button */
+ box = XtVaCreateManagedWidget("box", xmFormWidgetClass,
+ pane,
+ NULL);
+
+ str = XmStringCreateLocalized("Close");
+ printlog_close = XtVaCreateManagedWidget("close",
+ xmPushButtonWidgetClass, box,
+ XmNlabelString, str,
+ XmNshowAsDefault, True,
+ XmNsensitive, False,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ /* to mimick appearance of native dialog buttons: */
+ XmNmarginWidth, 6,
+ XmNmarginHeight, 4,
+ XmNtopOffset, 10,
+ XmNbottomOffset, 10,
+ XmNleftOffset, 10,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(printlog_close, XmNactivateCallback, close_callback, NULL);
+ g_close_callback = close_callback;
+
+ str = XmStringCreateLocalized("Cancel");
+ printlog_cancel = XtVaCreateManagedWidget("cancel",
+ xmPushButtonWidgetClass, box,
+ XmNlabelString, str,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ /* to mimick appearance of native dialog buttons: */
+ XmNmarginWidth, 6,
+ XmNmarginHeight, 4,
+ XmNtopOffset, 10,
+ XmNbottomOffset, 10,
+ XmNrightOffset, 10,
+ NULL);
+ XmStringFree(str);
+ XtAddCallback(printlog_cancel, XmNactivateCallback, cancel_callback, NULL);
+ g_cancel_callback = cancel_callback;
+
+ XtManageChild(box);
+ XtManageChild(form);
+ XtManageChild(pane);
+/* center_window(printlog_shell, globals.widgets.top_level); */
+/* XtMapWidget(printlog_shell); */
+ /* this doesn't help */
+ /* XtOverrideTranslations(form, XtParseTranslationTable(text_translations)); */
+ /* XtOverrideTranslations(pane, XtParseTranslationTable(text_translations)); */
+ }
+ else {
+ XtSetSensitive(printlog_close, False);
+ XtSetSensitive(printlog_cancel, True);
+ }
+#endif
+ adjust_width(printlog_close, printlog_cancel);
+}
+
+void
+printlog_append(const char *str, size_t len)
+{
+#ifndef MOTIF
+
+ static XawTextBlock block = {0, 0, NULL, 0};
+
+ block.ptr = (char *) str;
+ block.length = len;
+ block.format = XawFmt8Bit;
+ while (XawTextReplace(printlog_text, printlog_length, printlog_length, &block)
+ != XawEditDone) {
+ int length;
+
+ XtVaGetValues(printlog_text, XtNlength, &length, NULL);
+ printlog_length = length;
+ }
+ printlog_length += len;
+ XawTextSetInsertionPoint(printlog_text, printlog_length);
+
+#else /* MOTIF */
+
+ XmTextInsert(printlog_text, printlog_length, (char *) str);
+ printlog_length += len;
+ XtVaSetValues(printlog_text, XmNcursorPosition, printlog_length, NULL);
+ XmTextShowPosition(printlog_text, printlog_length);
+
+#endif /* MOTIF */
+}
+
+void
+printlog_append_str(const char *str)
+{
+ printlog_append(str, strlen(str));
+}
+
+/* disable cancel button, enable close button */
+void
+printlog_enable_closebutton(void)
+{
+ XtSetSensitive(printlog_close, True);
+ XtSetSensitive(printlog_cancel, False);
+#if MOTIF
+ XmProcessTraversal(printlog_close, XmTRAVERSE_CURRENT);
+#endif
+}
+
+static void
+printlog_internal_close(void)
+{
+ XtUnmapWidget(printlog_shell);
+ printlog_active = False;
+#ifndef MOTIF
+ XtVaSetValues(printlog_text, XtNstring, "", NULL);
+#else
+ XmTextSetString(printlog_text, "");
+#endif
+}
+
+void
+printlog_popdown(Boolean force)
+{
+ if (force) { /* user clicked on `Close' */
+ printlog_internal_close();
+ }
+ else { /* timer elapsed */
+#ifndef MOTIF
+ Boolean state;
+ XtVaGetValues(printlog_unkeep, XtNstate, &state, NULL);
+ if (state) {
+ printlog_internal_close();
+ }
+#else
+ if (XmToggleButtonGadgetGetState(printlog_unkeep)) {
+ printlog_internal_close();
+ }
+#endif
+ }
+}
+
+
+static void
+printlog_act_close(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ ASSERT(g_close_callback != NULL, "Callback not initialized");
+ (g_close_callback)(NULL, NULL, NULL);
+}
+
+static void
+printlog_act_keep(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(printlog_unkeep, False, False);
+#else
+ XtVaSetValues(printlog_unkeep, XtNstate, False, NULL);
+#endif
+}
+
+
+
+static void
+printlog_act_unkeep(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(printlog_unkeep, True, False);
+#else
+ XtVaSetValues(printlog_unkeep, XtNstate, True, NULL);
+#endif
+}
+
+static void
+printlog_act_cancel(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ ASSERT(g_cancel_callback != NULL, "Callback not initialized");
+ (g_cancel_callback)(NULL, NULL, NULL);
+}
+
+static void
+printlog_act_destroy(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ ASSERT((g_destroy_callback) != NULL, "Callback not initialized");
+ (g_destroy_callback)(NULL, NULL, NULL);
+}
diff --git a/Build/source/texk/xdvik/gui/print-log.h b/Build/source/texk/xdvik/gui/print-log.h
new file mode 100644
index 00000000000..90e69be8343
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/print-log.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2002-2004 Paul Vojta and the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef PRINT_LOG_H_
+#define PRINT_LOG_H_
+
+/* printlog access functions */
+
+extern void printlog_create(const char *title,
+ const char *close_label,
+ /* callback for `close' button */
+ void (*close_callback)(Widget w, XtPointer client_data, XtPointer call_data),
+ /* callback for `cancel' button */
+ void (*cancel_callback)(Widget w, XtPointer client_data, XtPointer call_data),
+ /* callback for destroying window via window manager */
+ void (*destroy_callback)(Widget w, XtPointer client_data, XtPointer call_data),
+ /* callback for `close automatically' checkbox */
+ void (*unkeep_callback)(Widget w, XtPointer client_data, XtPointer call_data));
+extern Boolean printlog_raise_active(void);
+extern void printlog_popup(void);
+extern void printlog_reset(void);
+extern void printlog_append(const char *str, size_t len);
+extern void printlog_append_str(const char *str);
+extern void printlog_enable_closebutton(void);
+extern void printlog_popdown(Boolean override_timer);
+
+#endif /* PRINT_LOG_H_ */
diff --git a/Build/source/texk/xdvik/gui/search-dialog.c b/Build/source/texk/xdvik/gui/search-dialog.c
new file mode 100644
index 00000000000..c77fa9d219e
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/search-dialog.c
@@ -0,0 +1,1072 @@
+/*
+ * Copyright (c) 2003-2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "events.h"
+#include "dvi-init.h"
+#include "search-dialog.h"
+#include "search-internal.h"
+#include "xlwradio.h"
+#include "statusline.h"
+#include "string-utils.h"
+#include "util.h"
+#include "message-window.h"
+#include "x_util.h"
+
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+
+#ifdef MOTIF
+# include <Xm/BulletinB.h>
+# include <Xm/DialogS.h>
+# include <Xm/PanedW.h>
+# include <Xm/MessageB.h>
+# include <Xm/LabelG.h>
+# include <Xm/Form.h>
+# include <Xm/Frame.h>
+# include <Xm/ToggleBG.h>
+# include <Xm/Text.h>
+# include <Xm/TextF.h>
+# include <Xm/PushB.h>
+# include <Xm/Protocols.h>
+# include <Xm/AtomMgr.h>
+#else /* MOTIF */
+# include <X11/Shell.h>
+# include <X11/Xaw/Paned.h>
+# include <X11/Xaw/Box.h>
+# include <X11/Xaw/Form.h>
+# include <X11/Xaw/Label.h>
+# include <X11/Xaw/Command.h>
+# include <X11/Xaw/Toggle.h>
+# include <X11/Xaw/AsciiText.h>
+#endif /* MOTIF */
+
+/* #defines for widgets that are used in common code */
+#ifdef MOTIF
+# define SHELL_WIDGET xmDialogShellWidgetClass
+# define PANED_WIDGET xmPanedWindowWidgetClass
+# define FORM_WIDGET xmFormWidgetClass
+# define LABEL_WIDGET xmLabelGadgetClass
+# define TEXT_WIDGET xmTextFieldWidgetClass
+# define CHECKBOX_WIDGET xmToggleButtonGadgetClass
+# define CHECKBUTTON_IS_SET XmNset
+# define PUSHBUTTON_WIDGET xmPushButtonWidgetClass
+# define VALUE_CALLBACK_NAME XmNvalueChangedCallback
+# define ACTIVATE_CALLBACK_NAME XmNactivateCallback
+#else /* MOTIF */
+# define SHELL_WIDGET transientShellWidgetClass
+# define PANED_WIDGET panedWidgetClass
+# define FORM_WIDGET formWidgetClass
+# define LABEL_WIDGET labelWidgetClass
+# define TEXT_WIDGET asciiTextWidgetClass
+# ifdef XAW
+# define CHECKBOX_WIDGET radioWidgetClass
+# else /* XAW */
+# define CHECKBOX_WIDGET toggleWidgetClass
+# endif /* XAW */
+# define CHECKBUTTON_IS_SET XtNstate
+# define PUSHBUTTON_WIDGET commandWidgetClass
+# define VALUE_CALLBACK_NAME XtNcallback
+# define ACTIVATE_CALLBACK_NAME XtNcallback
+#endif /* MOTIF */
+
+static Boolean m_find_popup_active = False;
+
+/* flags for setting single bits in resource.search_window_defaults */
+static const int SETTINGS_USE_REGEXP_FLAG = 1;
+static const int SETTINGS_CASE_SENSITIVE_FLAG = 2;
+static const int SETTINGS_BACKWARDS_FLAG = 4;
+static const int SETTINGS_IGNORE_LINEBREAKS_FLAG = 8;
+
+
+static void
+cb_search_go(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct search_settings *settings = (struct search_settings *)client_data;
+ Widget find_popup;
+ Position x = 0, y = 0;
+
+ ASSERT(settings != NULL, "client_data cb_search_go mustn't be NULL!");
+ UNUSED(call_data);
+
+ TRACE_FIND((stderr, "cb_search_go: settings: searchterm=|%s|, down = %d, re = %d, case = %d",
+ settings->term, settings->direction, settings->use_regexp, settings->case_sensitive));
+
+ /* retrieve the find popup window */
+ if ((find_popup = XtNameToWidget(globals.widgets.top_level, "*find_popup")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"find_popup\" widget!"));
+ x = y = 0;
+ }
+ else {
+ XtVaGetValues(find_popup, XtNx, &x, XtNy, &y, NULL);
+ /* add some offsets */
+ settings->x_pos = x + 10;
+ settings->y_pos = y + 10;
+ TRACE_GUI((stderr, "SHELL: %ld; x: %d, y: %d", (unsigned long)w, x, y));
+ }
+
+ settings->from_page = current_page;
+ settings->message_window = 0;
+ TRACE_FIND((stderr, "starting search from page: %d", settings->from_page));
+ search_dvi((XtPointer)settings);
+}
+
+static void
+show_settings(const char *func_name, struct search_settings *settings)
+{
+ TRACE_FIND((stderr, "%s: settings: str=|%s|, down = %d, re = %d, "
+ "case = %d, ignore_hyphens = %d, ignore_linebreaks = %d\n",
+ func_name,
+ settings->term,
+ settings->direction,
+ settings->use_regexp,
+ settings->case_sensitive,
+ settings->ignore_hyphens,
+ settings->ignore_linebreaks));
+
+}
+
+
+static void
+cb_regexp_search(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct search_settings *settings = (struct search_settings *)client_data;
+ /* Hack: Since XawToggleUnsetCurrent() will invoke this callback again,
+ return every second time to avoid multiple popups. This is done by
+ setting the flag `do_return'.
+ */
+#if !HAVE_REGEX_H
+ static Boolean do_return = False;
+#endif
+ ASSERT(settings != NULL, "client_data cb_search_go mustn't be NULL!");
+ UNUSED(call_data);
+
+#if !HAVE_REGEX_H
+ if (do_return) {
+ do_return = False;
+ return;
+ }
+
+ XBell(DISP, 0);
+ popup_message(get_matching_parent(w, globals.widgets.top_level, "find_popup", NULL),
+ MSG_ERR,
+ NULL,
+ "Sorry, regular expression support (regex.h) is not available on this platform.");
+ do_return = True;
+#ifdef MOTIF
+ XmToggleButtonGadgetSetState(w, True, False);
+#else
+ XawToggleUnsetCurrent(w);
+#endif
+
+#else
+ UNUSED(w);
+ settings->use_regexp = !(settings->use_regexp);
+
+ /* force re-initialization of search term by resetting utf8_term: */
+ free(settings->utf8_term);
+ settings->utf8_term = NULL;
+
+ show_settings("cb_regexp_search", settings);
+#endif
+
+ if (settings->use_regexp)
+ resource.search_window_defaults |= SETTINGS_USE_REGEXP_FLAG;
+ else
+ resource.search_window_defaults &= ~SETTINGS_USE_REGEXP_FLAG;
+ store_preference(NULL, "searchWindowDefaults", "%u", resource.search_window_defaults);
+}
+
+static void
+cb_backwards_search(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct search_settings *settings = (struct search_settings *)client_data;
+ ASSERT(settings != NULL, "client_data cb_search_go mustn't be NULL!");
+ UNUSED(w);
+ UNUSED(call_data);
+
+ switch (settings->direction) {
+ case SEARCH_UP: settings->direction = SEARCH_DOWN; break;
+ case SEARCH_DOWN: settings->direction = SEARCH_UP; break;
+ default: ASSERT(0, "shouldn't happen: settings->direction is neither SEARCH_UP nor SEARCH_DOWN!"); break;
+ }
+
+ show_settings("cb_backwards_search", settings);
+
+ if (settings->direction == SEARCH_UP)
+ resource.search_window_defaults |= SETTINGS_BACKWARDS_FLAG;
+ else
+ resource.search_window_defaults &= ~SETTINGS_BACKWARDS_FLAG;
+ store_preference(NULL, "searchWindowDefaults", "%u", resource.search_window_defaults);
+}
+
+static void
+cb_match_case(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct search_settings *settings = (struct search_settings *)client_data;
+ ASSERT(settings != NULL, "client_data cb_search_go mustn't be NULL!");
+ UNUSED(w);
+ UNUSED(call_data);
+
+ settings->case_sensitive = !(settings->case_sensitive);
+
+ show_settings("cb_match_case", settings);
+
+ if (settings->case_sensitive)
+ resource.search_window_defaults |= SETTINGS_CASE_SENSITIVE_FLAG;
+ else
+ resource.search_window_defaults &= ~SETTINGS_CASE_SENSITIVE_FLAG;
+ store_preference(NULL, "searchWindowDefaults", "%u", resource.search_window_defaults);
+}
+
+static void
+cb_linebreaks(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct search_settings *settings = (struct search_settings *)client_data;
+ ASSERT(settings != NULL, "client_data cb_search_go mustn't be NULL!");
+ UNUSED(w);
+ UNUSED(call_data);
+
+ settings->ignore_linebreaks = !(settings->ignore_linebreaks);
+ settings->ignore_hyphens = !(settings->ignore_hyphens);
+
+ show_settings("cb_linebreaks", settings);
+
+ if (settings->ignore_linebreaks)
+ resource.search_window_defaults |= SETTINGS_IGNORE_LINEBREAKS_FLAG;
+ else
+ resource.search_window_defaults &= ~SETTINGS_IGNORE_LINEBREAKS_FLAG;
+ store_preference(NULL, "searchWindowDefaults", "%u", resource.search_window_defaults);
+}
+
+static void
+cb_search_cancel(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Widget find_popup;
+ struct search_settings *settings = (struct search_settings *)client_data;
+
+ UNUSED(w);
+ UNUSED(call_data);
+
+ /* retrieve the find popup window */
+ if ((find_popup = XtNameToWidget(globals.widgets.top_level, "*find_popup")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"find_popup\" widget!"));
+ return;
+ }
+
+ /* This flag is checked in the scanning routines, and
+ will be eventually reset by do_pages() in events.c.
+ (The scanning routines musn't reset it, since they
+ might not be called again after this point!) */
+ globals.ev.flags |= EV_FIND_CANCEL;
+
+ search_signal_page_changed(); /* Hack to make search restart anew */
+ search_erase_highlighting(True);
+ if (settings->message_window != 0) {
+ TRACE_GUI((stderr, "kill_message_window: %p\n", (void *)settings->message_window));
+ kill_message_window(settings->message_window);
+ }
+ XtPopdown(find_popup);
+ m_find_popup_active = False;
+}
+
+static void
+cb_search_get_term_button(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct search_settings *settings = (struct search_settings *)client_data;
+ char *searchterm = NULL;
+
+ Widget searchbox_input, paned, box;
+ UNUSED(call_data);
+
+ box = XtParent(w);
+ ASSERT(box != 0, "Parent of button widget mustn't be NULL!");
+ paned = XtParent(box);
+ ASSERT(paned != 0, "Parent of box widget mustn't be NULL!");
+
+ if ((searchbox_input = XtNameToWidget(paned, "*searchbox_input")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"searchbox_input\" widget!"));
+ return;
+ }
+
+#ifdef MOTIF
+ XtVaGetValues(searchbox_input, XmNvalue, &searchterm, NULL);
+#else
+ XtVaGetValues(searchbox_input, XtNstring, &searchterm, NULL);
+#endif
+ if (searchterm == NULL) {
+ XDVI_WARNING((stderr, "Searchterm in cb_search_get_term callback shouldn't be NULL!"));
+ return;
+ }
+ TRACE_FIND((stderr, "searchterm1: |%s|", searchterm));
+ settings->term = searchterm;
+
+ cb_search_go(w, settings, NULL);
+}
+
+static void
+search_cancel(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ struct search_settings *settings = NULL;
+ void *ptr;
+ UNUSED(event);
+
+ ASSERT(*num_params > 0, "params in search_cancel must be > 0!");
+ ASSERT(*params != NULL, "params in search_cancel mustn't be NULL!");
+
+ /*
+ * the *params char pointer contains the pointer value (address) of `settings';
+ * convert it back to a pointer:
+ */
+ TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
+ sscanf(*params, "%p", &ptr);
+ settings = (struct search_settings *)ptr;
+ TRACE_GUI((stderr, "Pointer address: |%p|", (void *)settings));
+ ASSERT(settings != NULL, "Shouldn't happen: Couldn't get string representation of argument pointer.");
+
+ cb_search_cancel(w, settings, NULL);
+}
+
+#ifdef MOTIF
+
+static void
+cb_search_get_term(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct search_settings *settings = (struct search_settings *)client_data;
+ char *searchterm = NULL;
+ Widget form, paned, searchbox_form;
+ Widget button;
+ XEvent ev;
+ UNUSED(call_data);
+
+ /* retrieve the `Find' button widget */
+ searchbox_form = XtParent(w);
+ ASSERT(searchbox_form != 0, "Parent of button widget mustn't be NULL!");
+ form = XtParent(searchbox_form);
+ ASSERT(form != 0, "Parent of searchbox_form widget mustn't be NULL!");
+ paned = XtParent(form);
+ ASSERT(paned != 0, "Parent of form widget mustn't be NULL!");
+ if ((button = XtNameToWidget(paned, "*find_button")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"find_button\" widget!"));
+ return;
+ }
+
+ if (settings != NULL) {
+ /* retrieve search term from text input field */
+ XtVaGetValues(w, XmNvalue, &searchterm, NULL);
+ if (searchterm == NULL) {
+ XDVI_WARNING((stderr, "Searchterm in cb_search_get_term callback shouldn't be NULL!"));
+ return;
+ }
+
+ TRACE_FIND((stderr, "searchterm2: |%s|", searchterm));
+ settings->term = (const char *)searchterm;
+ }
+
+ /* make the `Find' button think it got pushed.
+ Also synthetisize an event, just to be sure ... */
+ synthetisize_event(&ev, button);
+
+ XtCallActionProc(button, "ArmAndActivate", &ev, NULL, 0);
+ /* the following don't make the button appear visually pressed: */
+ /* XtCallCallbacks(button, XmNarmCallback, NULL); */
+ /* XtCallCallbacks(button, XmNactivateCallback, NULL); */
+}
+
+static void
+xm_search_go(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ struct search_settings *settings = NULL;
+ void *ptr;
+ Widget input;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (params != NULL) { /* re-initialize search term */
+ ASSERT(*num_params == 1, "num_params in xm_search_go should be 1 if *params != NULL");
+ /*
+ * the *params char pointer contains the pointer value (address) of `settings';
+ * convert it back to a pointer:
+ */
+ TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
+ sscanf(*params, "%p", &ptr);
+ settings = (struct search_settings *)ptr;
+ TRACE_GUI((stderr, "Pointer address: |%p|", (void *)settings));
+ ASSERT(settings != NULL, "Shouldn't happen: Couldn't get string representation of argument pointer.");
+ }
+
+ if ((input = XtNameToWidget(globals.widgets.top_level, "*searchbox_input")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"searchbox_input\" widget!"));
+ return;
+ }
+ cb_search_get_term(input, settings, NULL);
+}
+
+#else /* MOTIF */
+
+static void
+xaw_unset_button(XtPointer client_data, XtIntervalId *id)
+{
+ XEvent ev;
+ Widget button = (Widget)client_data;
+
+ UNUSED(id);
+
+ synthetisize_event(&ev, button);
+ XtCallActionProc(button, "unset", &ev, NULL, 0);
+}
+
+static void
+xaw_search_go(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ struct search_settings *settings = NULL;
+ void *ptr;
+ char *searchterm = NULL;
+ Widget button, input;
+ XtIntervalId timeout;
+
+ UNUSED(w);
+
+ /* retrieve the `Find' button widget */
+ if ((button = XtNameToWidget(globals.widgets.top_level, "*find_button")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"find_button\" widget!"));
+ return;
+ }
+ if ((input = XtNameToWidget(globals.widgets.top_level, "*searchbox_input")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"searchbox_input\" widget!"));
+ return;
+ }
+
+ XtVaGetValues(input, XtNstring, &searchterm, NULL);
+ if (searchterm == NULL) {
+ XDVI_WARNING((stderr, "Searchterm in xaw_search_go callback shouldn't be NULL!"));
+ return;
+ }
+
+ if (params != NULL) { /* re-initialize search term */
+ ASSERT(*num_params == 1, "num_params in xaw_search_go should be 1 if *params != NULL");
+ /*
+ * the *params char pointer contains the pointer value (address) of `settings';
+ * convert it back to a pointer:
+ */
+ TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
+ sscanf(*params, "%p", &ptr);
+ settings = (struct search_settings *)ptr;
+ TRACE_GUI((stderr, "Pointer address: |%p|", (void *)settings));
+ ASSERT(settings != NULL, "Shouldn't happen: Couldn't get string representation of argument pointer.");
+
+ settings->term = (const char *)searchterm;
+ }
+
+ /*
+ * Again, we want the button to appear activated when <RETURN> is pressed.
+ * For this, we explicitly invoke set()notify(), and unset() after a timeout
+ * of 150 milliseconds, which seems to correspond to the Motif default.
+ */
+ XtCallActionProc(button, "set", event, NULL, 0);
+ XtCallActionProc(button, "notify", event, NULL, 0);
+ XSync(DISP, False);
+ timeout = XtAppAddTimeOut(app, 150, xaw_unset_button, (XtPointer)button);
+}
+
+
+/*
+ * Restart search from within another popup (confirmation) window.
+ */
+static void
+xaw_search_restart(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ void *ptr;
+ struct search_settings *settings;
+
+ UNUSED(event);
+ UNUSED(w);
+
+ ASSERT(*num_params > 0, "params in xaw_search_restart must be > 0!");
+ ASSERT(*params != NULL, "params in xaw_search_restart mustn't be NULL!");
+
+ TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
+ sscanf(*params, "%p", &ptr);
+ settings = (struct search_settings *)ptr;
+
+ search_restart((XtPointer)settings);
+}
+
+static XtActionsRec xaw_search_actions[] = {
+ { "do-search-restart", xaw_search_restart },
+ { "do-search", xaw_search_go },
+};
+#endif /* MOTIF */
+
+static XtActionsRec search_actions[] = {
+ { "do-search",
+#ifdef MOTIF
+ xm_search_go
+#else
+ xaw_search_go
+#endif
+ },
+ { "cancel-search", search_cancel },
+};
+
+static Widget
+create_search_window(struct search_settings *settings)
+{
+ Widget top_level_shell;
+ Atom WM_DELETE_WINDOW;
+ Widget form, find_paned, box;
+ unsigned char curr_state;
+
+ Widget searchbox_form, searchbox_label, searchbox_input;
+ /* left and right column */
+ Widget options_left_form, options_right_form;
+ /* checkboxes in left column */
+ Widget regexp_checkbox, matchcase_checkbox, backwards_checkbox;
+ /* checkboxes in right column */
+ Widget linebreaks_checkbox;
+ Widget find_button, cancel_button;
+
+ XtTranslations xlats;
+ char *translation_str = NULL;
+#ifdef MOTIF
+ XmString str;
+#else /* MOTIF */
+ XtTranslations wm_translations;
+ int ddist;
+#endif
+
+ XtAddActions(search_actions, XtNumber(search_actions));
+
+#ifndef MOTIF
+
+ XtAddActions(xaw_search_actions, XtNumber(xaw_search_actions));
+#define HORIZONTAL_RESIZING_NO XtNleft, XtChainLeft, XtNright, XtChainLeft
+#define HORIZONTAL_RESIZING_YES XtNleft, XtChainLeft, XtNright, XtChainRight
+#define VERTICAL_RESIZING_NO XtNtop, XtChainTop, XtNbottom, XtChainTop
+
+ /*
+ * hacky: Since translations can only contain strings, pass
+ * the pointer address as string in the callback. But the only
+ * portability problem should be the size of the pointer
+ * representation, and we deal with that by using VSNPRINTF().
+ */
+ translation_str = get_string_va("<Message>WM_PROTOCOLS: cancel-search(%p)\nCtrl<Key>g:find-next()",
+ (void *)settings);
+ wm_translations = XtParseTranslationTable(translation_str);
+ free(translation_str);
+ translation_str = NULL;
+#endif /* not MOTIF */
+
+ top_level_shell = XtVaCreatePopupShell("find_popup",
+ SHELL_WIDGET,
+ globals.widgets.top_level,
+ XtNtitle, "xdvik: Find in DVI file",
+ XtNmappedWhenManaged, False, /* so that we can center it first */
+ XtNtransientFor, globals.widgets.top_level,
+ XtNallowShellResize, True,
+#ifdef MOTIF
+ XmNdeleteResponse, XmDO_NOTHING, /* we'll take care of that ourselves */
+#else
+ XtNtranslations, wm_translations,
+#endif
+ NULL);
+
+ TRACE_GUI((stderr, "toplevel: %ld", (unsigned long)top_level_shell));
+
+ WM_DELETE_WINDOW = XInternAtom(XtDisplay(top_level_shell), "WM_DELETE_WINDOW", False);
+#ifdef MOTIF
+ XmAddWMProtocolCallback(top_level_shell, WM_DELETE_WINDOW, cb_search_cancel, settings);
+#endif
+
+ find_paned = XtVaCreateWidget("find_paned",
+ PANED_WIDGET,
+ top_level_shell,
+#ifdef MOTIF
+ /* make sashes invisible */
+ XmNsashWidth, 1,
+ XmNsashHeight, 1,
+#endif
+ NULL);
+
+ form = XtVaCreateWidget("form",
+ FORM_WIDGET,
+ find_paned,
+#ifdef MOTIF
+ XmNhorizontalSpacing, DDIST_MAJOR,
+ XmNverticalSpacing, DDIST_MAJOR,
+ XmNautoUnmanage, False,
+#else
+ XtNallowResize, True,
+#endif
+ NULL);
+
+#ifdef MOTIF
+ str = XmStringCreateLocalized("Find:");
+#else
+ XtVaGetValues(form, XtNdefaultDistance, &ddist, NULL);
+#endif
+
+ /* search term input field */
+ searchbox_form = XtVaCreateWidget("searchbox_form",
+ FORM_WIDGET,
+ form,
+#ifdef MOTIF
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+#else
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_YES,
+#endif
+ NULL);
+ searchbox_label = XtVaCreateManagedWidget("searchbox_label",
+ LABEL_WIDGET,
+ searchbox_form,
+#ifdef MOTIF
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNalignment, XmALIGNMENT_BEGINNING,
+#else
+ XtNlabel, "Find:",
+ XtNborderWidth, 0,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+#endif
+ NULL);
+
+ searchbox_input = XtVaCreateManagedWidget("searchbox_input",
+ TEXT_WIDGET,
+ searchbox_form,
+#ifdef MOTIF
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, searchbox_label,
+ XmNbottomAttachment, XmATTACH_FORM,
+#else
+ XtNwidth, 260,
+ XtNdataCompression, False,
+ XtNeditType, XawtextEdit,
+ XtNfromHoriz, searchbox_label,
+ HORIZONTAL_RESIZING_YES,
+ VERTICAL_RESIZING_NO,
+#endif
+ NULL);
+
+
+ if (settings->term != NULL) {
+ XtVaSetValues(searchbox_input,
+#ifdef MOTIF
+ XmNvalue,
+#else
+ XtNstring,
+#endif
+ settings->term, NULL);
+ }
+
+ XtManageChild(searchbox_form);
+
+#ifdef MOTIF
+ XtAddCallback(searchbox_input, XmNactivateCallback, cb_search_get_term, settings);
+#endif
+
+ /*
+ * form for left row of options checkbuttons
+ */
+ options_left_form = XtVaCreateManagedWidget("options_left_form",
+ FORM_WIDGET,
+ form,
+#ifdef MOTIF
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+ XmNresizable, True,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, searchbox_form,
+ XmNleftAttachment, XmATTACH_FORM,
+/* XmNrightAttachment, XmATTACH_FORM, */
+/* XmNbottomAttachment, XmATTACH_FORM, */
+#else
+ XtNborderWidth, 0,
+ XtNfromVert, searchbox_form,
+ HORIZONTAL_RESIZING_NO,
+#endif
+ NULL);
+ /*
+ * form for right row of options checkbuttons
+ */
+ options_right_form = XtVaCreateManagedWidget("options_right_form",
+ FORM_WIDGET,
+ form,
+#ifdef MOTIF
+ XmNhorizontalSpacing, DDIST,
+ XmNverticalSpacing, DDIST,
+ XmNresizable, True,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, searchbox_form,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, options_left_form,
+ XmNrightAttachment, XmATTACH_FORM,
+/* XmNbottomAttachment, XmATTACH_FORM, */
+#else
+ XtNborderWidth, 0,
+ XtNfromVert, searchbox_form,
+ XtNfromHoriz, options_left_form,
+ HORIZONTAL_RESIZING_NO,
+#endif
+ NULL);
+#ifdef MOTIF
+ XmStringFree(str);
+ str = XmStringCreateLocalized("Regular expression");
+#endif
+
+ regexp_checkbox = XtVaCreateManagedWidget("regexp_checkbox",
+ CHECKBOX_WIDGET,
+ options_left_form,
+#ifdef MOTIF
+ XmNlabelString, str,
+ XmNindicatorType, XmN_OF_MANY,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+#else
+ XtNlabel, "Regular expression",
+ XtNborderWidth, 0,
+ XtNisRadio, False,
+ XtNhighlightThickness, 1,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+#endif
+ NULL);
+
+ XtAddCallback(regexp_checkbox, VALUE_CALLBACK_NAME, cb_regexp_search, settings);
+
+#ifdef MOTIF
+ XmStringFree(str);
+ str = XmStringCreateLocalized("Find backwards");
+#endif
+
+ backwards_checkbox = XtVaCreateManagedWidget("backwards_checkbox",
+ CHECKBOX_WIDGET,
+ options_left_form,
+#ifdef MOTIF
+ XmNlabelString, str,
+ XmNindicatorType, XmN_OF_MANY,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, regexp_checkbox,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+#else
+ XtNlabel, "Find backwards",
+ XtNfromVert, regexp_checkbox,
+ XtNborderWidth, 0,
+ XtNisRadio, False,
+ XtNhighlightThickness, 1,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+#endif
+ NULL);
+
+ XtAddCallback(backwards_checkbox, VALUE_CALLBACK_NAME, cb_backwards_search, settings);
+
+#ifdef MOTIF
+ XmStringFree(str);
+ str = XmStringCreateLocalized("Case sensitive");
+#endif
+
+ matchcase_checkbox = XtVaCreateManagedWidget("matchcase_checkbox",
+ CHECKBOX_WIDGET,
+ options_right_form,
+#ifdef MOTIF
+ XmNlabelString, str,
+ XmNindicatorType, XmN_OF_MANY,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+#else
+ XtNlabel, "Case sensitive",
+ XtNborderWidth, 0,
+ XtNisRadio, False,
+ XtNhighlightThickness, 1,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+#endif
+ NULL);
+
+ XtAddCallback(matchcase_checkbox, VALUE_CALLBACK_NAME, cb_match_case, settings);
+
+#ifdef MOTIF
+ XmStringFree(str);
+ str = XmStringCreateLocalized("Ignore newlines/hyphens");
+#endif
+
+ linebreaks_checkbox = XtVaCreateManagedWidget("linebreaks_checkbox",
+ CHECKBOX_WIDGET,
+ options_right_form,
+#ifdef MOTIF
+ XmNlabelString, str,
+ XmNindicatorType, XmN_OF_MANY,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, matchcase_checkbox,
+ XmNleftAttachment, XmATTACH_FORM,
+#else
+ XtNlabel, "Ignore newlines/hyphens",
+ XtNfromVert, matchcase_checkbox,
+ XtNborderWidth, 0,
+ XtNisRadio, False,
+ XtNhighlightThickness, 1,
+ HORIZONTAL_RESIZING_NO,
+ VERTICAL_RESIZING_NO,
+#endif
+ NULL);
+
+ XtAddCallback(linebreaks_checkbox, VALUE_CALLBACK_NAME, cb_linebreaks, settings);
+
+ /*
+ * box for Find/Cancel buttons
+ */
+ box = XtVaCreateManagedWidget("box",
+ FORM_WIDGET,
+ find_paned,
+#ifdef MOTIF
+ XmNskipAdjust, True, /* don't resize this area */
+#else
+ /* resizing by user isn't needed */
+ XtNshowGrip, False,
+ XtNdefaultDistance, 6, /* some padding */
+ /* resizing the window shouldn't influence this box,
+ * but only the pane widget
+ */
+ XtNskipAdjust, True,
+ XtNaccelerators, G_accels_cr,
+#endif
+ NULL);
+
+#ifdef MOTIF
+ XmStringFree(str);
+ str = XmStringCreateLocalized("Find");
+#endif
+
+ find_button = XtVaCreateManagedWidget("find_button",
+ PUSHBUTTON_WIDGET,
+ box,
+#ifdef MOTIF
+ XmNlabelString, str,
+ XmNshowAsDefault, True,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ /* to mimick appearance of native dialog buttons: */
+ XmNmarginWidth, 6,
+ XmNmarginHeight, 4,
+ XmNtopOffset, 10,
+ XmNbottomOffset, 10,
+ XmNleftOffset, 10,
+#else
+ XtNlabel, "Find",
+ XtNaccelerators, G_accels_cr,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainBottom,
+ HORIZONTAL_RESIZING_NO,
+#endif
+ NULL);
+#ifdef MOTIF
+ XmStringFree(str);
+ str = XmStringCreateLocalized("Cancel");
+#endif
+
+ cancel_button = XtVaCreateManagedWidget("cancel_button",
+ PUSHBUTTON_WIDGET,
+ box,
+#ifdef MOTIF
+ XmNlabelString, str,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ /* to mimick appearance of native dialog buttons: */
+ XmNmarginWidth, 6,
+ XmNmarginHeight, 4,
+ XmNtopOffset, 10,
+ XmNbottomOffset, 10,
+ XmNrightOffset, 10,
+#else
+ XtNlabel, "Cancel",
+ XtNfromHoriz, find_button,
+ XtNbottom, XtChainBottom,
+ XtNjustify, XtJustifyRight,
+ XtNleft, XtChainRight,
+ XtNright, XtChainRight,
+#endif
+ NULL);
+
+#ifdef MOTIF
+ XmStringFree(str);
+#endif
+
+ XtAddCallback(cancel_button, ACTIVATE_CALLBACK_NAME, cb_search_cancel, settings);
+ XtAddCallback(find_button, ACTIVATE_CALLBACK_NAME, cb_search_get_term_button, settings);
+
+ translation_str = get_string_va(
+#ifdef MOTIF
+ "<Key>osfCancel:cancel-search(%p)\n"
+#else
+ "<Key>Escape:cancel-search(%p)\n"
+#endif
+ "<Key>Return:do-search(%p)\n"
+ "Ctrl<Key>g:find-next()",
+ (void *)settings, (void *)settings);
+
+ xlats = XtParseTranslationTable(translation_str);
+ free(translation_str);
+
+ XtOverrideTranslations(searchbox_form, xlats);
+ XtOverrideTranslations(options_left_form, xlats);
+ XtOverrideTranslations(options_right_form, xlats);
+ XtOverrideTranslations(regexp_checkbox, xlats);
+ XtOverrideTranslations(matchcase_checkbox, xlats);
+ XtOverrideTranslations(backwards_checkbox, xlats);
+ XtOverrideTranslations(box, xlats);
+ XtOverrideTranslations(find_button, xlats);
+ XtOverrideTranslations(cancel_button, xlats);
+ XtOverrideTranslations(searchbox_input, xlats);
+
+ /* following doesn't help to force input to textbox in xaw: */
+ /* XtInstallAllAccelerators(find_paned, find_paned); */
+ /* XtInstallAllAccelerators(searchbox_input, find_paned); */
+
+ XtManageChild(form);
+ XtManageChild(find_paned);
+
+ { /* set all buttons to same size */
+ Dimension w1, w2, max;
+ XtVaGetValues(find_button, XtNwidth, &w1, NULL);
+ XtVaGetValues(cancel_button, XtNwidth, &w2, NULL);
+ max = MAX(w1, w2);
+ XtVaSetValues(find_button, XtNwidth, max, NULL);
+ XtVaSetValues(cancel_button, XtNwidth, max, NULL);
+ }
+
+ XtManageChild(top_level_shell);
+ /* don't center this one - would just get in the way in this case. */
+ /* center_window(top_level_shell, globals.widgets.top_level); */
+ XtPopup(top_level_shell, XtGrabNone);
+ m_find_popup_active = True;
+
+#ifdef MOTIF
+ XmProcessTraversal(searchbox_input, XmTRAVERSE_CURRENT);
+/* XmProcessTraversal(find_button, XmTRAVERSE_CURRENT); */
+#endif
+ XSetWMProtocols(XtDisplay(top_level_shell), XtWindow(top_level_shell), &WM_DELETE_WINDOW, 1);
+
+ /* check if we have default values from resource.search_window_defaults */
+ if (resource.search_window_defaults & SETTINGS_USE_REGEXP_FLAG)
+ XtVaSetValues(regexp_checkbox, CHECKBUTTON_IS_SET, True, NULL);
+ if (resource.search_window_defaults & SETTINGS_CASE_SENSITIVE_FLAG)
+ XtVaSetValues(matchcase_checkbox, CHECKBUTTON_IS_SET, True, NULL);
+ if (resource.search_window_defaults & SETTINGS_BACKWARDS_FLAG)
+ XtVaSetValues(backwards_checkbox, CHECKBUTTON_IS_SET, True, NULL);
+ if (resource.search_window_defaults & SETTINGS_IGNORE_LINEBREAKS_FLAG)
+ XtVaSetValues(linebreaks_checkbox, CHECKBUTTON_IS_SET, True, NULL);
+
+ /* initialize `settings' values according to the checkbox states
+ (in case user has assigned values via X defaults): */
+ XtVaGetValues(regexp_checkbox, CHECKBUTTON_IS_SET, &curr_state, NULL);
+ settings->use_regexp = curr_state;
+ XtVaGetValues(matchcase_checkbox, CHECKBUTTON_IS_SET, &curr_state, NULL);
+ settings->case_sensitive = curr_state;
+ XtVaGetValues(backwards_checkbox, CHECKBUTTON_IS_SET, &curr_state, NULL);
+ settings->direction = curr_state ? SEARCH_UP : SEARCH_DOWN;
+ XtVaGetValues(linebreaks_checkbox, CHECKBUTTON_IS_SET, &curr_state, NULL);
+ settings->ignore_hyphens = settings->ignore_linebreaks = curr_state;
+
+#ifndef MOTIF
+
+#undef HORIZONTAL_RESIZING_NO
+#undef HORIZONTAL_RESIZING_YES
+#undef VERTICAL_RESIZING_NO
+
+#endif /* MOTIF */
+ return top_level_shell;
+}
+
+void
+dvi_find_string(const char *str, Boolean find_next)
+{
+ /* Synthesize a RET keystroke for the find dialog.
+ * Also pops up the find dialog, to make it easier for user to
+ * edit options, change direction etc. */
+ Widget find_popup;
+ if ((find_popup = XtNameToWidget(globals.widgets.top_level, "*find_popup")) == 0) {
+ static struct search_settings settings;
+ static struct search_info searchinfo = { False, False, False, 0, 0, 0, 0 };
+ settings.term = str;
+ settings.use_regexp = False;
+ settings.case_sensitive = False;
+ settings.direction = SEARCH_DOWN;
+ settings.ignore_hyphens = False;
+ settings.ignore_linebreaks = False;
+ settings.x_pos = -1;
+ settings.y_pos = -1;
+ settings.searchinfo = &searchinfo;
+ settings.hyphen_delta = 0;
+
+ find_popup = create_search_window(&settings);
+
+ if (find_next)
+ return;
+ }
+ else if (str != NULL) { /* change the search term */
+ Widget searchbox_input;
+ if ((searchbox_input = XtNameToWidget(find_popup, "*searchbox_input")) == 0) {
+ XDVI_WARNING((stderr, "Couldn't find \"searchbox_input\" widget!"));
+ return;
+ }
+ XtVaSetValues(searchbox_input,
+#ifdef MOTIF
+ XmNvalue,
+#else
+ XtNstring,
+#endif
+ str, NULL);
+ }
+ if (m_find_popup_active) {
+ XRaiseWindow(DISP, XtWindow(find_popup));
+ }
+ else {
+ XtPopup(find_popup, XtGrabNone);
+ m_find_popup_active = True;
+ }
+
+ if (str != NULL || find_next) {
+#ifdef MOTIF
+ xm_search_go(NULL, NULL, NULL, NULL);
+#else
+ xaw_search_go(NULL, NULL, NULL, NULL);
+#endif
+ }
+}
+
diff --git a/Build/source/texk/xdvik/gui/search-dialog.h b/Build/source/texk/xdvik/gui/search-dialog.h
new file mode 100644
index 00000000000..c272658d021
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/search-dialog.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003-2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SEARCH_DIALOG_H_
+#define SEARCH_DIALOG_H_
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+typedef enum { SEARCH_UP = 0, SEARCH_DOWN, SEARCH_UNINITIALIZED } searchDirectionT;
+
+/* bounding box info for words. */
+struct bbox {
+ int ulx, uly, lrx, lry;
+};
+
+struct search_info {
+ Boolean have_match;
+ Boolean locked; /* to block multiple searches */
+ Boolean search_wrapped; /* if restarting from start (or end) */
+ int from_pos;
+ int to_pos;
+ int scan_page;
+ int page_offset; /* start of current scan */
+};
+
+
+struct search_settings {
+ const char *term; /* original search term */
+ char *utf8_term; /* term in UTF-8 encoding */
+ char *posix_term; /* utf8_term with Perl abbreviations mapped to POSIX */
+ Boolean use_regexp;
+ Boolean case_sensitive;
+ Boolean ignore_hyphens;
+ Boolean ignore_linebreaks;
+ searchDirectionT direction;
+ struct search_info *searchinfo;
+ /* internal state management */
+ int x_pos, y_pos; /* position of the search popup window */
+ int from_page; /* page to start search from */
+ int curr_page; /* current page of search search from */
+ int to_page; /* highest page already scanned */
+ int hyphen_delta; /* difference in offsets when hyphenation is removed */
+ Widget message_window; /* warning popup, or NULL if it doesn't exist */
+};
+
+extern void dvi_find_string(const char *str, Boolean find_next);
+
+#endif /* SEARCH_DIALOG_H_ */
diff --git a/Build/source/texk/xdvik/gui/selection.c b/Build/source/texk/xdvik/gui/selection.c
new file mode 100644
index 00000000000..e0bef1e5f1e
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/selection.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include <string.h>
+
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+
+#if HAVE_X11_XMU_XMU_H
+#include <X11/Xmu/Atoms.h>
+#include <X11/Xmu/Xmu.h>
+#endif
+
+#include "events.h"
+#include "util.h"
+#include "encodings.h"
+#include "message-window.h"
+#include "selection.h"
+#include "statusline.h"
+
+/*
+ * Set the current X selection (i.e. the primary selection AKA XA_PRIMARY).
+ * Most of this is copied from Asente/Converse/Swick: X Window System Toolkit Manual
+ */
+
+/* This is file scope since deliver_selection_cb() needs access to it.
+ * I guess we could also store it in an Atom, but why bother ...
+ */
+static char *m_selection_text = NULL;
+static char *m_cvt_selection_text = NULL;
+static size_t m_selection_size = 0;
+
+/* helper routine */
+static Atom
+fetch_atom(Widget w, const char *name)
+{
+ Atom a;
+ XrmValue source, dest;
+
+ source.size = strlen(name) + 1;
+ source.addr = (char *)name;
+ dest.size = sizeof a;
+ dest.addr = (caddr_t)&a;
+
+ (void)XtConvertAndStore(w, XtRString, &source, XtRAtom, &dest);
+ return a;
+}
+
+/* Lose the selection */
+static void
+lose_selection_cb(Widget w, Atom *selection)
+{
+ UNUSED(w);
+ UNUSED(selection);
+
+ text_change_region(TEXT_SEL_CLEAR, NULL);
+}
+
+static char *
+utf8_to_native_encoding(const char *utf8)
+{
+ static const char *text_encoding = NULL;
+
+ /* convert to user encoding, similar to search-internal.c */
+ if (text_encoding == NULL) {
+ text_encoding = get_text_encoding();
+ }
+
+ if (memicmp(text_encoding, "iso-8859-1", strlen("iso-8859-1")) == 0
+ || memicmp(text_encoding, "iso8859-1", strlen("iso8859-1")) == 0) {
+ return str_utf8_to_iso_8859_1(utf8);
+ }
+ else if (memicmp(text_encoding, "utf-8", strlen("utf-8")) != 0
+ && memicmp(text_encoding, "utf8", strlen("utf8")) != 0) {
+ /* some other encoding */
+ return iconv_convert_string("utf-8", text_encoding, utf8);
+ }
+ /* fallback */
+ return xstrdup(utf8);
+}
+
+/* Deliver the selection. Only supports XA_STRING. */
+static Boolean
+deliver_selection_cb(Widget w,
+ Atom *selection,
+ Atom *target,
+ Atom *type,
+ XtPointer *value,
+ unsigned long *length,
+ int *format)
+{
+ Atom targets = fetch_atom(w, "TARGETS");
+ Atom utf8_string = fetch_atom(w, "UTF8_STRING");
+
+ TRACE_GUI((stderr, "selection target = %lu (%s)",
+ *target, XGetAtomName(DISP, *target)));
+
+ if (m_selection_text == NULL) /* paranoia */
+ return False;
+
+#if HAVE_X11_XMU_XMU_H
+ if (*target == targets) {
+ /* TARGETS handling copied from xclipboard.c */
+ Atom* targetP;
+ Atom* std_targets;
+ unsigned long std_length;
+ XSelectionRequestEvent* req = XtGetSelectionRequest(w, *selection, (XtRequestId)NULL);
+
+ TRACE_GUI((stderr, "Selection type: targets"));
+ XmuConvertStandardSelection(w, req->time, selection,
+ target, type, (XPointer*)&std_targets, &std_length, format);
+ *value = XtMalloc(sizeof(Atom)*(std_length + 2));
+ targetP = *(Atom**)value;
+ *length = std_length + 2;
+ *targetP++ = XA_COMPOUND_TEXT(DISP);
+ *targetP++ = XA_STRING;
+ memcpy((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
+ XtFree((char*)std_targets);
+ *type = XA_ATOM;
+ *format = sizeof(Atom) * 8;
+ return True;
+ }
+ else
+#endif
+ if (*target == utf8_string) {
+ TRACE_GUI((stderr, "Selection type: UTF8_STRING"));
+ *type = *target;
+ *value = (XtPointer)XtNewString(m_selection_text);
+ /* *value = (XtPointer)m_selection_text; */
+ *length = strlen(m_selection_text);
+ *format = 8;
+ return True;
+ }
+ else if (*target == XA_STRING) {
+ char *ptr = utf8_to_native_encoding(m_selection_text);
+ TRACE_GUI((stderr, "Selection type: XA_STRING"));
+ strncpy(m_cvt_selection_text, ptr, m_selection_size);
+ m_cvt_selection_text[m_selection_size - 1] = '\0'; /* ensure termination */
+ free(ptr);
+ *type = *target;
+ *value = (XtPointer)XtNewString(m_cvt_selection_text);
+ /* *value = (XtPointer)m_selection_text; */
+ *length = strlen(m_cvt_selection_text);
+ *format = 8;
+ return True;
+ }
+#if HAVE_X11_XMU_XMU_H
+ else if (*target == XA_COMPOUND_TEXT(DISP) || *target == XA_TEXT(DISP)) {
+ const char *cl[1];
+ char *ptr;
+ int retval;
+
+ XTextProperty ct;
+ XICCEncodingStyle style = XStdICCTextStyle;
+
+ TRACE_GUI((stderr, "Selection type: XA_COMPOUND_TEXT"));
+ ptr = utf8_to_native_encoding(m_selection_text);
+ strncpy(m_cvt_selection_text, ptr, m_selection_size);
+ m_cvt_selection_text[m_selection_size - 1] = '\0'; /* ensure termination */
+ cl[0] = m_cvt_selection_text;
+
+ *type = *target;
+ retval = XmbTextListToTextProperty(DISP, (char **)cl, 1, style, &ct);
+
+ if (retval == XNoMemory || retval == XLocaleNotSupported || retval == XConverterNotFound) {
+ statusline_print(STATUS_MEDIUM, "XmbTextListToTextProperty failed: %d", retval);
+ return False;
+ }
+
+ *value = ct.value;
+ *length = ct.nitems;
+ *format = 8;
+ return True;
+ }
+#endif
+ else {
+#if HAVE_X11_XMU_XMU_H
+ TRACE_GUI((stderr, "Selection type: standard selection"));
+ if (XmuConvertStandardSelection(w, CurrentTime, selection,
+ target, type, (XPointer *)value, length, format))
+ return True;
+ else {
+#endif
+ TRACE_GUI((stderr, "Selection type unsupported: %lu (%s)",
+ (unsigned long)*target, XGetAtomName(DISP, *target)));
+ statusline_print(STATUS_MEDIUM,
+ "X client asked for an unsupported selection target type: %lu (%s)",
+ (unsigned long)*target, XGetAtomName(DISP, *target));
+ return False ;
+#if HAVE_X11_XMU_XMU_H
+ }
+#endif
+ }
+}
+
+/* do it */
+Boolean
+set_selection(const char *text, Widget w)
+{
+ /* caller should make sure that text is never longer than 4 * XMaxRequestSize(DISP) - 32 */
+ if (m_selection_text == NULL) {
+ m_selection_size = 4 * XMaxRequestSize(DISP);
+ m_selection_text = xmalloc(m_selection_size);
+ m_cvt_selection_text = xmalloc(m_selection_size);
+ }
+ strncpy(m_selection_text, text, m_selection_size);
+ m_selection_text[m_selection_size - 1] = '\0'; /* ensure termination */
+
+ return XtOwnSelection(w, XA_PRIMARY, XtLastTimestampProcessed(XtDisplay(w)),
+ deliver_selection_cb,
+ lose_selection_cb,
+ (XtSelectionDoneProc)NULL);
+}
+
+void
+unset_selection(Widget w)
+{
+ XtDisownSelection(w, XA_PRIMARY, XtLastTimestampProcessed(XtDisplay(w)));
+}
+
diff --git a/Build/source/texk/xdvik/gui/selection.h b/Build/source/texk/xdvik/gui/selection.h
new file mode 100644
index 00000000000..1dcb8416cbb
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/selection.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SELECTION_H_
+#define SELECTION_H_
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+Boolean set_selection(const char *text, Widget w);
+void unset_selection(Widget w);
+
+#endif /* SELECTION_H_ */
diff --git a/Build/source/texk/xdvik/gui/sfDir.c b/Build/source/texk/xdvik/gui/sfDir.c
new file mode 100644
index 00000000000..de39ccf3678
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfDir.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Software Research Associates not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Software Research Associates
+ * makes no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Erik M. van der Poel
+ * Software Research Associates, Inc., Tokyo, Japan
+ * erik@sra.co.jp
+ */
+
+#include "xdvi-config.h"
+#include "sfDir.h"
+
+#if !defined(MOTIF) /* entire file */
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+#undef wchar_t
+
+#include <stdio.h>
+
+#ifdef SEL_FILE_IGNORE_CASE
+#include <ctype.h>
+#endif /* def SEL_FILE_IGNORE_CASE */
+
+
+#ifdef SEL_FILE_IGNORE_CASE
+int
+SFcompareEntries(const void *vp, const void *vq)
+{
+ SFEntry *p = vp;
+ SFEntry *q = vq;
+ char *r, *s;
+ char c1, c2;
+
+ r = p->real;
+ s = q->real;
+
+ c1 = *r++;
+ if (islower(c1)) {
+ c1 = toupper(c1);
+ }
+ c2 = *s++;
+ if (islower(c2)) {
+ c2 = toupper(c2);
+ }
+
+ while (c1 == c2) {
+ if (!c1) {
+ return strcmp(p->real, q->real);
+ }
+ c1 = *r++;
+ if (islower(c1)) {
+ c1 = toupper(c1);
+ }
+ c2 = *s++;
+ if (islower(c2)) {
+ c2 = toupper(c2);
+ }
+ }
+
+ return c1 - c2;
+}
+#else /* def SEL_FILE_IGNORE_CASE */
+int
+SFcompareEntries(const void *vp, const void *vq)
+{
+ const SFEntry *p = vp;
+ const SFEntry *q = vq;
+ return strcmp(p->real, q->real);
+}
+#endif /* def SEL_FILE_IGNORE_CASE */
+
+int
+SFgetDir(SFDir *dir)
+{
+ SFEntry *result = NULL;
+ int alloc = 0;
+ int i;
+ DIR *dirp;
+ struct dirent *dp;
+ char *str;
+ int len;
+ int maxChars;
+ struct stat statBuf;
+
+ maxChars = strlen(dir->dir) - 1;
+
+ dir->entries = NULL;
+ dir->nEntries = 0;
+ dir->nChars = 0;
+
+ result = NULL;
+ i = 0;
+
+ dirp = opendir(".");
+ if (!dirp) {
+ return 1;
+ }
+
+ (void)stat(".", &statBuf);
+ dir->mtime = statBuf.st_mtime;
+
+ (void)readdir(dirp); /* throw away "." */
+
+#ifndef S_IFLNK
+ (void)readdir(dirp); /* throw away ".." */
+#endif /* ndef S_IFLNK */
+
+ while ((dp = readdir(dirp))) {
+ if (i >= alloc) {
+ alloc = 2 * (alloc + 1);
+ result = (SFEntry *) XtRealloc((char *)result,
+ (unsigned)(alloc * sizeof(SFEntry)));
+ }
+ result[i].statDone = 0;
+ str = dp->d_name;
+ len = strlen(str);
+ result[i].real = XtMalloc((unsigned)(len + 2));
+ (void)strcat(strcpy(result[i].real, str), " ");
+ if (len > maxChars) {
+ maxChars = len;
+ }
+ result[i].shown = result[i].real;
+ i++;
+ }
+
+#if defined(SVR4) || defined(SYSV) || defined(USG)
+ qsort((char *)result, (unsigned)i, sizeof(SFEntry), SFcompareEntries);
+#else /* defined(SVR4) || defined(SYSV) || defined(USG) */
+ qsort((char *)result, i, sizeof(SFEntry), SFcompareEntries);
+#endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
+
+ dir->entries = result;
+ dir->nEntries = i;
+ dir->nChars = maxChars + 1;
+
+ closedir(dirp);
+
+ return 0;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* !defined(MOTIF) */
diff --git a/Build/source/texk/xdvik/gui/sfDir.h b/Build/source/texk/xdvik/gui/sfDir.h
new file mode 100644
index 00000000000..0207ec4f1a0
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfDir.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef SFDIR_H_
+#define SFDIR_H_
+
+#include "xdvi-config.h"
+
+#include "kpathsea/c-auto.h"
+#include "kpathsea/config.h"
+#include "kpathsea/c-dir.h"
+#include "kpathsea/c-stat.h"
+
+#ifndef MOTIF
+
+typedef struct {
+ int statDone;
+ char *real;
+ char *shown;
+} SFEntry;
+
+typedef struct {
+ char *dir;
+ char *path;
+ SFEntry *entries;
+ int nEntries;
+ int vOrigin;
+ int nChars;
+ int hOrigin;
+ int changed;
+ int beginSelection;
+ int endSelection;
+ time_t mtime;
+} SFDir;
+
+extern int SFcompareEntries(const void *vp, const void *vq);
+extern int SFgetDir(SFDir *dir);
+
+extern SFDir *SFdirs;
+
+#endif /* MOTIF */
+
+#endif /* SFDIR_H_ */
diff --git a/Build/source/texk/xdvik/gui/sfDraw.c b/Build/source/texk/xdvik/gui/sfDraw.c
new file mode 100644
index 00000000000..7a3ddd8cf06
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfDraw.c
@@ -0,0 +1,819 @@
+/*
+ * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Software Research Associates not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Software Research Associates
+ * makes no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Erik M. van der Poel
+ * Software Research Associates, Inc., Tokyo, Japan
+ * erik@sra.co.jp
+ */
+
+#include "xdvi-config.h"
+
+#include "kpathsea/c-auto.h"
+#include "kpathsea/config.h"
+#include "kpathsea/c-stat.h"
+#include "xdvi.h"
+
+#include "sfDraw.h"
+#include "sfDir.h"
+#include "sfPath.h"
+
+#if !defined(MOTIF) /* for xdvik */
+
+#define SF_DEFAULT_FONT "9x15"
+
+typedef struct {
+ char *font;
+} TextData, *textPtr;
+
+int SFcharWidth, SFcharAscent, SFcharHeight;
+
+int SFcurrentInvert[3] = { -1, -1, -1 };
+
+static GC SFlineGC, SFscrollGC, SFinvertGC, SFtextGC;
+
+static XtResource textResources[] = {
+ {XtNfont, XtCFont, XtRString, sizeof(char *),
+ XtOffset(textPtr, font), XtRString, SF_DEFAULT_FONT},
+};
+
+static XFontStruct *SFfont;
+
+static int SFcurrentListY;
+
+static XtIntervalId SFscrollTimerId;
+
+void
+SFinitFont(void)
+{
+ TextData *data;
+
+ data = XtNew(TextData);
+
+ XtGetApplicationResources(selFileForm, (XtPointer) data, textResources,
+ XtNumber(textResources), (Arg *) NULL, ZERO);
+
+ SFfont = XLoadQueryFont(SFdisplay, data->font);
+ if (!SFfont) {
+ SFfont = XLoadQueryFont(SFdisplay, SF_DEFAULT_FONT);
+ if (!SFfont) {
+ char sbuf[256];
+
+ (void)sprintf(sbuf, "XsraSelFile: can't get font %s",
+ SF_DEFAULT_FONT);
+
+ XtAppError(SFapp, sbuf);
+ }
+ }
+
+ TRACE_GUI((stderr, "FONT: width %d, %d\n", SFfont->max_bounds.width, SFfont->min_bounds.width));
+ SFcharWidth = (SFfont->max_bounds.width + SFfont->min_bounds.width) / 2;
+ SFcharAscent = SFfont->max_bounds.ascent;
+ SFcharHeight = SFcharAscent + SFfont->max_bounds.descent;
+ if (SFcharWidth == 0) {
+ /* if min_bounds.width = -max_bounds.width, we probably
+ have a scalable TT font; try to determine its actual
+ width by measuring the letter `x':
+ */
+ SFcharWidth = XTextWidth(SFfont, "x", 1);
+ }
+ if (SFcharWidth == 0) { /* last resort */
+ SFcharWidth = SFfont->max_bounds.width / 2;
+ }
+ TRACE_GUI((stderr,
+ "Using font measures: charwidth %d, ascent %d, height %d",
+ SFcharWidth, SFcharAscent, SFcharHeight));
+}
+
+void
+SFcreateGC(void)
+{
+ XGCValues gcValues;
+ XRectangle rectangles[1];
+
+/* XtVaGetValues(selFileLists[0], */
+/* XtNforeground, &(gcValues.foreground), */
+/* XtNbackground, &(gcValues.background), */
+/* NULL); */
+ gcValues.foreground = SFfore;
+
+ SFlineGC = XtGetGC(selFileLists[0], (XtGCMask)
+ GCForeground | 0, &gcValues);
+
+ SFscrollGC = XtGetGC(selFileLists[0], (XtGCMask)
+ 0, &gcValues);
+
+ gcValues.function = GXinvert;
+/* gcValues.plane_mask = (gcValues.foreground ^ gcValues.background); */
+ gcValues.plane_mask = (SFfore ^ SFback);
+
+ SFinvertGC = XtGetGC(selFileLists[0], (XtGCMask)
+ GCFunction | GCPlaneMask | 0, &gcValues);
+
+ gcValues.foreground = SFfore;
+ gcValues.background = SFback;
+ gcValues.font = SFfont->fid;
+
+ SFtextGC = XCreateGC(SFdisplay, XtWindow(selFileLists[0]), (unsigned long)
+ GCForeground | GCBackground | GCFont | 0, &gcValues);
+
+ rectangles[0].x = SFlineToTextH + SFbesideText;
+ rectangles[0].y = 0;
+ rectangles[0].width = SFcharsPerEntry * SFcharWidth;
+ rectangles[0].height = SFupperY + 1;
+
+ XSetClipRectangles(SFdisplay, SFtextGC, 0, 0, rectangles, 1, Unsorted);
+}
+
+void
+SFclearList(int n, int doScroll)
+{
+ SFDir *dir;
+
+ SFcurrentInvert[n] = -1;
+
+ XClearWindow(SFdisplay, XtWindow(selFileLists[n]));
+
+ XDrawSegments(SFdisplay, XtWindow(selFileLists[n]), SFlineGC, SFsegs, 2);
+
+ if (doScroll) {
+ dir = &(SFdirs[SFdirPtr + n]);
+
+ if ((SFdirPtr + n < SFdirEnd) && dir->nEntries && dir->nChars) {
+ XawScrollbarSetThumb(selFileVScrolls[n],
+ (double)dir->vOrigin / dir->nEntries,
+ (double)(dir->nEntries < SFlistSize
+ ? dir->nEntries
+ : SFlistSize)
+ / dir->nEntries);
+
+ XawScrollbarSetThumb(selFileHScrolls[n],
+ (double)(dir->hOrigin) / dir->nChars,
+ (double)(dir->nChars < SFcharsPerEntry
+ ? dir-> nChars : SFcharsPerEntry)
+ / dir->nChars);
+ }
+ else {
+ XawScrollbarSetThumb(selFileVScrolls[n], 0.0, 1.0);
+ XawScrollbarSetThumb(selFileHScrolls[n], 0.0, 1.0);
+ }
+ }
+}
+
+static void
+SFdeleteEntry(SFDir *dir, SFEntry *entry)
+{
+ SFEntry *e;
+ SFEntry *end;
+ int n;
+ int idx;
+
+ idx = entry - dir->entries;
+
+ if (idx < dir->beginSelection) {
+ dir->beginSelection--;
+ }
+ if (idx <= dir->endSelection) {
+ dir->endSelection--;
+ }
+ if (dir->beginSelection > dir->endSelection) {
+ dir->beginSelection = dir->endSelection = -1;
+ }
+
+ if (idx < dir->vOrigin) {
+ dir->vOrigin--;
+ }
+
+ XtFree(entry->real);
+
+ end = &(dir->entries[dir->nEntries - 1]);
+
+ for (e = entry; e < end; e++) {
+ *e = *(e + 1);
+ }
+
+ if (!(--dir->nEntries)) {
+ return;
+ }
+
+ n = dir - &(SFdirs[SFdirPtr]);
+ if ((n < 0) || (n > 2)) {
+ return;
+ }
+
+ XawScrollbarSetThumb(selFileVScrolls[n],
+ (double)(dir->vOrigin) / dir->nEntries,
+ (double)(dir->nEntries < SFlistSize
+ ? dir->nEntries : SFlistSize)
+ / dir->nEntries);
+}
+
+static void
+SFwriteStatChar(char *name, int last, struct stat *statBuf)
+{
+ name[last] = SFstatChar(statBuf);
+}
+
+static int
+SFstatAndCheck(SFDir *dir, SFEntry *entry)
+{
+ struct stat statBuf;
+ char save;
+ int last;
+ extern int SFchdir();
+
+ /*
+ * must be restored before returning
+ */
+ save = *(dir->path);
+ *(dir->path) = 0;
+
+ if (!SFchdir(SFcurrentPath)) {
+ last = strlen(entry->real) - 1;
+ entry->real[last] = 0;
+ entry->statDone = 1;
+ if ((!stat(entry->real, &statBuf))
+#ifdef S_IFLNK
+ || (!lstat(entry->real, &statBuf))
+#endif /* ndef S_IFLNK */
+ ) {
+ if (SFfunc) {
+ char *shown;
+
+ shown = NULL;
+ if (SFfunc(entry->real, &shown, &statBuf)) {
+ if (shown) {
+ int len;
+
+ len = strlen(shown);
+ entry->shown = XtMalloc((unsigned)(len + 2)
+ );
+ (void)strcpy(entry->shown, shown);
+ SFwriteStatChar(entry->shown, len, &statBuf);
+ entry->shown[len + 1] = 0;
+ }
+ }
+ else {
+ SFdeleteEntry(dir, entry);
+
+ *(dir->path) = save;
+ return 1;
+ }
+ }
+ SFwriteStatChar(entry->real, last, &statBuf);
+ }
+ else {
+ entry->real[last] = ' ';
+ }
+ }
+
+ *(dir->path) = save;
+ return 0;
+}
+
+static void
+SFdrawStrings(Window w, SFDir *dir, int from, int to)
+{
+ int i;
+ SFEntry *entry;
+ int x;
+
+ x = SFtextX - dir->hOrigin * SFcharWidth;
+
+ if (dir->vOrigin + to >= dir->nEntries) {
+ to = dir->nEntries - dir->vOrigin - 1;
+ }
+ for (i = from; i <= to; i++) {
+ entry = &(dir->entries[dir->vOrigin + i]);
+ if (!(entry->statDone)) {
+ if (SFstatAndCheck(dir, entry)) {
+ if (dir->vOrigin + to >= dir->nEntries) {
+ to = dir->nEntries - dir->vOrigin - 1;
+ }
+ i--;
+ continue;
+ }
+ }
+ XDrawImageString(SFdisplay,
+ w,
+ SFtextGC,
+ x,
+ SFtextYoffset + i * SFentryHeight,
+ entry->shown, strlen(entry->shown));
+ if (dir->vOrigin + i == dir->beginSelection) {
+ XDrawLine(SFdisplay,
+ w,
+ SFlineGC,
+ SFlineToTextH + 1,
+ SFlowerY + i * SFentryHeight,
+ SFlineToTextH + SFentryWidth - 2,
+ SFlowerY + i * SFentryHeight);
+ }
+ if (
+ (dir->vOrigin + i >= dir->beginSelection) &&
+ (dir->vOrigin + i <= dir->endSelection)) {
+ SFcompletionSegs[0].y1 = SFcompletionSegs[1].y1 =
+ SFlowerY + i * SFentryHeight;
+ SFcompletionSegs[0].y2 = SFcompletionSegs[1].y2 =
+ SFlowerY + (i + 1) * SFentryHeight - 1;
+ XDrawSegments(SFdisplay, w, SFlineGC, SFcompletionSegs, 2);
+ }
+ if (dir->vOrigin + i == dir->endSelection) {
+ XDrawLine(SFdisplay,
+ w,
+ SFlineGC,
+ SFlineToTextH + 1,
+ SFlowerY + (i + 1) * SFentryHeight - 1,
+ SFlineToTextH + SFentryWidth - 2,
+ SFlowerY + (i + 1) * SFentryHeight - 1);
+ }
+ }
+}
+
+void
+SFdrawList(int n, int doScroll)
+{
+ SFDir *dir;
+ Window w;
+
+ SFclearList(n, doScroll);
+
+ if (SFdirPtr + n < SFdirEnd) {
+ dir = &(SFdirs[SFdirPtr + n]);
+ w = XtWindow(selFileLists[n]);
+ XDrawImageString(SFdisplay,
+ w,
+ SFtextGC,
+ SFtextX - dir->hOrigin * SFcharWidth,
+ SFlineToTextV + SFaboveAndBelowText + SFcharAscent,
+ dir->dir, strlen(dir->dir)
+ );
+ SFdrawStrings(w, dir, 0, SFlistSize - 1);
+ }
+}
+
+void
+SFdrawLists(int doScroll)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ SFdrawList(i, doScroll);
+ }
+}
+
+static void
+SFinvertEntry(int n)
+{
+ XFillRectangle(SFdisplay,
+ XtWindow(selFileLists[n]),
+ SFinvertGC,
+ SFlineToTextH,
+ SFcurrentInvert[n] * SFentryHeight + SFlowerY,
+ SFentryWidth, SFentryHeight);
+}
+
+static unsigned long
+SFscrollTimerInterval(void)
+{
+ static int maxVal = 200;
+ static int varyDist = 50;
+ static int minDist = 50;
+ int t;
+ int dist;
+
+ if (SFcurrentListY < SFlowerY) {
+ dist = SFlowerY - SFcurrentListY;
+ }
+ else if (SFcurrentListY > SFupperY) {
+ dist = SFcurrentListY - SFupperY;
+ }
+ else {
+ return (unsigned long)1;
+ }
+
+ t = maxVal - ((maxVal / varyDist) * (dist - minDist));
+
+ if (t < 1) {
+ t = 1;
+ }
+
+ if (t > maxVal) {
+ t = maxVal;
+ }
+
+ return (unsigned long)t;
+}
+
+static void
+SFscrollTimer(XtPointer p, XtIntervalId *id)
+{
+ SFDir *dir;
+ int save;
+ int n;
+
+ UNUSED(id);
+
+ n = (int)p;
+
+ fprintf(stderr, "SFscrollTimer called!\n");
+
+ dir = &(SFdirs[SFdirPtr + n]);
+ save = dir->vOrigin;
+
+ if (SFcurrentListY < SFlowerY) {
+ if (dir->vOrigin > 0) {
+ SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin - 1);
+ }
+ }
+ else if (SFcurrentListY > SFupperY) {
+ if (dir->vOrigin < dir->nEntries - SFlistSize) {
+ SFvSliderMovedCallback(selFileVScrolls[n], n, dir->vOrigin + 1);
+ }
+ }
+
+ if (dir->vOrigin != save) {
+ if (dir->nEntries) {
+ XawScrollbarSetThumb(selFileVScrolls[n],
+ (double)(dir->vOrigin) / dir->nEntries,
+ (double)(dir->nEntries < SFlistSize
+ ? dir-> nEntries : SFlistSize)
+ / dir->nEntries);
+ }
+ }
+
+ if (SFbuttonPressed) {
+ SFscrollTimerId = XtAppAddTimeOut(SFapp,
+ SFscrollTimerInterval(),
+ SFscrollTimer, (XtPointer) n);
+ }
+}
+
+static int
+SFnewInvertEntry(int n, XMotionEvent *event)
+{
+ int x, y;
+ int new;
+ static int SFscrollTimerAdded = 0;
+
+ x = event->x;
+ y = event->y;
+
+ if (SFdirPtr + n >= SFdirEnd) {
+ return -1;
+ }
+ else if ((x >= 0) && (x <= SFupperX) && (y >= SFlowerY) && (y <= SFupperY)
+ ) {
+ SFDir *dir = &(SFdirs[SFdirPtr + n]);
+
+ if (SFscrollTimerAdded) {
+ SFscrollTimerAdded = 0;
+ XtRemoveTimeOut(SFscrollTimerId);
+ }
+
+ new = (y - SFlowerY) / SFentryHeight;
+ if (dir->vOrigin + new >= dir->nEntries) {
+ return -1;
+ }
+ return new;
+ }
+ else {
+ if (SFbuttonPressed) {
+ SFcurrentListY = y;
+ if (!SFscrollTimerAdded) {
+ SFscrollTimerAdded = 1;
+ SFscrollTimerId = XtAppAddTimeOut(SFapp,
+ SFscrollTimerInterval(),
+ SFscrollTimer, (XtPointer) n);
+ }
+ }
+
+ return -1;
+ }
+}
+
+void
+SFenterList(Widget w, int n, XEnterWindowEvent *event)
+{
+ int new;
+
+ UNUSED(w);
+
+ /* sanity */
+ if (SFcurrentInvert[n] != -1) {
+ SFinvertEntry(n);
+ SFcurrentInvert[n] = -1;
+ }
+
+ new = SFnewInvertEntry(n, (XMotionEvent *) event);
+ if (new != -1) {
+ SFcurrentInvert[n] = new;
+ SFinvertEntry(n);
+ }
+}
+
+void
+SFleaveList(Widget w, int n, XEvent *event)
+{
+ UNUSED(w);
+ UNUSED(event);
+
+ if (SFcurrentInvert[n] != -1) {
+ SFinvertEntry(n);
+ SFcurrentInvert[n] = -1;
+ }
+}
+
+void
+SFmotionList(Widget w, int n, XMotionEvent *event)
+{
+ int new;
+
+ UNUSED(w);
+
+ new = SFnewInvertEntry(n, event);
+
+ if (new != SFcurrentInvert[n]) {
+ if (SFcurrentInvert[n] != -1) {
+ SFinvertEntry(n);
+ }
+ SFcurrentInvert[n] = new;
+ if (new != -1) {
+ SFinvertEntry(n);
+ }
+ }
+}
+
+void
+SFvFloatSliderMovedCallback(Widget w, int n, float *fnew)
+{
+ int new;
+
+ new = (*fnew) * SFdirs[SFdirPtr + n].nEntries;
+
+ SFvSliderMovedCallback(w, n, new);
+}
+
+void
+SFvSliderMovedCallback(Widget w, int n, int new)
+{
+ int old;
+ Window win;
+ SFDir *dir;
+
+ UNUSED(w);
+
+ dir = &(SFdirs[SFdirPtr + n]);
+
+ old = dir->vOrigin;
+ dir->vOrigin = new;
+
+ if (old == new) {
+ return;
+ }
+
+ win = XtWindow(selFileLists[n]);
+
+ if (ABS(new - old) < SFlistSize) {
+ if (new > old) {
+ XCopyArea(SFdisplay,
+ win,
+ win,
+ SFscrollGC,
+ SFlineToTextH,
+ SFlowerY + (new - old) * SFentryHeight,
+ SFentryWidth + SFlineToTextH,
+ (SFlistSize - (new - old)) * SFentryHeight,
+ SFlineToTextH, SFlowerY);
+ XClearArea(SFdisplay,
+ win,
+ SFlineToTextH,
+ SFlowerY + (SFlistSize - (new - old)) *
+ SFentryHeight,
+ SFentryWidth + SFlineToTextH,
+ (new - old) * SFentryHeight, False);
+ SFdrawStrings(win, dir, SFlistSize - (new - old), SFlistSize - 1);
+ }
+ else {
+ XCopyArea(SFdisplay,
+ win,
+ win,
+ SFscrollGC,
+ SFlineToTextH,
+ SFlowerY,
+ SFentryWidth + SFlineToTextH,
+ (SFlistSize - (old - new)) * SFentryHeight,
+ SFlineToTextH, SFlowerY + (old - new) * SFentryHeight);
+ XClearArea(SFdisplay,
+ win,
+ SFlineToTextH,
+ SFlowerY,
+ SFentryWidth + SFlineToTextH,
+ (old - new) * SFentryHeight, False);
+ SFdrawStrings(win, dir, 0, old - new);
+ }
+ }
+ else {
+ XClearArea(SFdisplay,
+ win,
+ SFlineToTextH,
+ SFlowerY,
+ SFentryWidth + SFlineToTextH,
+ SFlistSize * SFentryHeight, False);
+ SFdrawStrings(win, dir, 0, SFlistSize - 1);
+ }
+}
+
+void
+SFvAreaSelectedCallback(Widget w, int n, int pnew)
+{
+ SFDir *dir;
+ int new;
+
+ dir = &(SFdirs[SFdirPtr + n]);
+
+ new = dir->vOrigin + ((double)pnew / SFvScrollHeight) * dir->nEntries;
+
+ if (new > dir->nEntries - SFlistSize) {
+ new = dir->nEntries - SFlistSize;
+ }
+
+ if (new < 0) {
+ new = 0;
+ }
+
+ if (dir->nEntries) {
+ float f;
+
+ f = ((double)new) / dir->nEntries;
+
+ XawScrollbarSetThumb(w, f,
+ (double)(dir->nEntries < SFlistSize
+ ? dir->nEntries
+ : SFlistSize)
+ / dir->nEntries);
+ }
+
+ SFvSliderMovedCallback(w, n, new);
+}
+
+void
+SFhSliderMovedCallback(Widget w, int n, float *new)
+{
+ SFDir *dir;
+ int save;
+
+ UNUSED(w);
+
+ dir = &(SFdirs[SFdirPtr + n]);
+ save = dir->hOrigin;
+ dir->hOrigin = (*new) * dir->nChars;
+ if (dir->hOrigin == save) {
+ return;
+ }
+
+ SFdrawList(n, SF_DO_NOT_SCROLL);
+}
+
+void
+SFhAreaSelectedCallback(Widget w, int n, int pnew)
+{
+ SFDir *dir;
+ int new;
+
+ dir = &(SFdirs[SFdirPtr + n]);
+
+ new = dir->hOrigin + (((double)pnew) / SFhScrollWidth) * dir->nChars;
+
+ if (new > dir->nChars - SFcharsPerEntry) {
+ new = dir->nChars - SFcharsPerEntry;
+ }
+
+ if (new < 0) {
+ new = 0;
+ }
+
+ if (dir->nChars) {
+ float f;
+
+ f = (double)new / dir->nChars;
+
+ XawScrollbarSetThumb(w, f,
+ (double)(dir->nChars < SFcharsPerEntry
+ ? dir->nChars
+ : SFcharsPerEntry)
+ / dir->nChars);
+
+ SFhSliderMovedCallback(w, n, &f);
+ }
+}
+
+void
+SFpathSliderMovedCallback(Widget w, XtPointer client_data, float *new)
+{
+ SFDir *dir;
+ int n;
+ XawTextPosition pos;
+ int SFdirPtrSave;
+
+ UNUSED(w);
+ UNUSED(client_data);
+
+ SFdirPtrSave = SFdirPtr;
+ SFdirPtr = (*new) * SFdirEnd;
+ if (SFdirPtr == SFdirPtrSave) {
+ return;
+ }
+
+ SFdrawLists(SF_DO_SCROLL);
+
+ n = 2;
+ while (SFdirPtr + n >= SFdirEnd) {
+ n--;
+ }
+
+ dir = &(SFdirs[SFdirPtr + n]);
+
+ pos = dir->path - SFcurrentPath;
+
+ if (!strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
+ pos -= strlen(SFstartDir);
+ if (pos < 0) {
+ pos = 0;
+ }
+ }
+
+ XawTextSetInsertionPoint(selFileField, pos);
+}
+
+void
+SFpathAreaSelectedCallback(Widget w, XtPointer client_data, int pnew)
+{
+ int new;
+ float f;
+
+ UNUSED(client_data);
+
+ new = SFdirPtr + (((double)pnew) / SFpathScrollWidth) * SFdirEnd;
+
+ if (new > SFdirEnd - 3) {
+ new = SFdirEnd - 3;
+ }
+
+ if (new < 0) {
+ new = 0;
+ }
+
+ f = ((double)new) / SFdirEnd;
+
+ XawScrollbarSetThumb(w, f,
+ (double)(SFdirEnd < 3 ? SFdirEnd : 3) / SFdirEnd);
+
+ SFpathSliderMovedCallback(w, (XtPointer) NULL, &f);
+}
+
+Boolean
+SFworkProc(void)
+{
+ SFDir *dir;
+ SFEntry *entry;
+
+ for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--) {
+ if (!(dir->nEntries)) {
+ continue;
+ }
+ for (entry = &(dir->entries[dir->nEntries - 1]);
+ entry >= dir->entries; entry--) {
+ if (!(entry->statDone)) {
+ (void)SFstatAndCheck(dir, entry);
+ return False;
+ }
+ }
+ }
+
+ SFworkProcAdded = 0;
+
+ return True;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* !defined(MOTIF) */
diff --git a/Build/source/texk/xdvik/gui/sfDraw.h b/Build/source/texk/xdvik/gui/sfDraw.h
new file mode 100644
index 00000000000..e9199793df8
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfDraw.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef SFDRAW_H_
+#define SFDRAW_H_
+
+#include "xdvi-config.h"
+
+#if !defined(MOTIF) /* for xdvik */
+
+#include <stdio.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Scrollbar.h>
+#include <X11/Xaw/Cardinals.h>
+
+#define SF_DO_SCROLL 1
+#define SF_DO_NOT_SCROLL 0
+
+extern Pixel SFfore, SFback;
+
+void SFinitFont(void);
+void SFcreateGC(void);
+void SFclearList(int n, int doScroll);
+void SFdrawList(int n, int doScroll);
+void SFdrawLists(int doScroll);
+void SFenterList(Widget w, int n, XEnterWindowEvent *event);
+void SFleaveList(Widget w, int n, XEvent *event);
+void SFmotionList(Widget w, int n, XMotionEvent *event);
+void SFvFloatSliderMovedCallback(Widget w, int n, float *fnew);
+void SFvSliderMovedCallback(Widget w, int n, int new);
+void SFvAreaSelectedCallback(Widget w, int n, int pnew);
+void SFhSliderMovedCallback(Widget w, int n, float *new);
+void SFhAreaSelectedCallback(Widget w, int n, int pnew);
+void SFpathSliderMovedCallback(Widget w, XtPointer client_data, float *new);
+void SFpathAreaSelectedCallback(Widget w, XtPointer client_data, int pnew);
+Boolean SFworkProc(void);
+extern int (*SFfunc)();
+
+extern Widget selFileField, selFileForm, selFileHScroll, selFileHScrolls[], selFileLists[], selFileVScrolls[];
+extern Display *SFdisplay;
+extern int SFcharWidth, SFcharHeight, SFcharAscent;
+extern XSegment SFsegs[], SFcompletionSegs[];
+extern XawTextPosition SFtextPos;
+
+extern int SFupperX, SFlowerY, SFupperY;
+
+extern int SFtextX, SFtextYoffset;
+
+extern int SFentryWidth, SFentryHeight;
+
+extern int SFlineToTextH, SFlineToTextV;
+
+extern int SFbesideText, SFaboveAndBelowText;
+
+extern int SFcharsPerEntry;
+
+extern int SFlistSize;
+
+extern int SFcurrentInvert[];
+
+extern int SFworkProcAdded;
+
+extern XtAppContext SFapp;
+
+extern int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth;
+
+extern char SFtextBuffer[];
+
+extern int SFbuttonPressed;
+
+extern XtIntervalId SFdirModTimerId;
+
+#endif /* !defined(MOTIF) */
+
+#endif /* SFDRAW_H_ */
diff --git a/Build/source/texk/xdvik/gui/sfPath.c b/Build/source/texk/xdvik/gui/sfPath.c
new file mode 100644
index 00000000000..3349919391b
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfPath.c
@@ -0,0 +1,908 @@
+/*
+ * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Software Research Associates not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Software Research Associates
+ * makes no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Erik M. van der Poel
+ * Software Research Associates, Inc., Tokyo, Japan
+ * erik@sra.co.jp
+ */
+
+#include "xdvi-config.h"
+
+#include "kpathsea/c-auto.h"
+#include "kpathsea/config.h"
+#include "kpathsea/c-stat.h"
+
+#include "xdvi.h"
+#include "sfDir.h"
+#include "sfDraw.h"
+#include "sfPath.h"
+#include "sfSelFile.h"
+
+#if !defined(MOTIF) /* entire file */
+
+#include <stdio.h>
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Scrollbar.h>
+#include <X11/Xaw/Cardinals.h>
+
+
+#ifdef SEL_FILE_IGNORE_CASE
+#include <ctype.h>
+#endif /* def SEL_FILE_IGNORE_CASE */
+
+#ifndef S_IXUSR
+#define S_IXUSR 0100
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 0010
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 0001
+#endif
+
+#define S_ISXXX(m) ((m) & (S_IXUSR | S_IXGRP | S_IXOTH))
+
+#include <X11/Xos.h>
+#include <pwd.h>
+#include <X11/Xaw/Scrollbar.h>
+
+typedef struct {
+ char *name;
+ char *dir;
+} SFLogin;
+
+SFDir *SFdirs = NULL;
+
+int SFdirEnd;
+
+int SFdirPtr;
+
+int SFbuttonPressed = 0;
+
+static int SFdoNotTouchDirPtr = 0;
+
+static int SFdoNotTouchVorigin = 0;
+
+static SFDir SFrootDir, SFhomeDir;
+
+static SFLogin *SFlogins;
+
+static int SFtwiddle = 0;
+
+int
+SFchdir(char *path)
+{
+ int result;
+
+ result = 0;
+
+ if (strcmp(path, SFcurrentDir)) {
+ result = chdir(path);
+ if (!result) {
+ (void)strcpy(SFcurrentDir, path);
+ }
+ }
+
+ return result;
+}
+
+static void
+SFfree(int i)
+{
+ SFDir *dir;
+ int j;
+
+ dir = &(SFdirs[i]);
+
+ for (j = dir->nEntries - 1; j >= 0; j--) {
+ if (dir->entries[j].shown != dir->entries[j].real) {
+ XtFree(dir->entries[j].shown);
+ }
+ XtFree(dir->entries[j].real);
+ }
+
+ XtFree((char *)dir->entries);
+
+ XtFree(dir->dir);
+
+ dir->dir = NULL;
+}
+
+static void
+SFstrdup(char **s1, char *s2)
+{
+ *s1 = strcpy(XtMalloc((unsigned)(strlen(s2) + 1)), s2);
+}
+
+static void
+SFunreadableDir(SFDir *dir)
+{
+ char *cannotOpen = "<cannot open> ";
+
+ dir->entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
+ dir->entries[0].statDone = 1;
+ SFstrdup(&dir->entries[0].real, cannotOpen);
+ dir->entries[0].shown = dir->entries[0].real;
+ dir->nEntries = 1;
+ dir->nChars = strlen(cannotOpen);
+}
+
+#ifdef SEL_FILE_IGNORE_CASE
+static
+SFstrncmp(char *p, char *q, int n)
+{
+ char c1, c2;
+ char *psave, *qsave;
+ int nsave;
+
+ psave = p;
+ qsave = q;
+ nsave = n;
+
+ c1 = *p++;
+ if (islower(c1)) {
+ c1 = toupper(c1);
+ }
+ c2 = *q++;
+ if (islower(c2)) {
+ c2 = toupper(c2);
+ }
+
+ while ((--n >= 0) && (c1 == c2)) {
+ if (!c1) {
+ return strncmp(psave, qsave, nsave);
+ }
+ c1 = *p++;
+ if (islower(c1)) {
+ c1 = toupper(c1);
+ }
+ c2 = *q++;
+ if (islower(c2)) {
+ c2 = toupper(c2);
+ }
+ }
+
+ if (n < 0) {
+ return strncmp(psave, qsave, nsave);
+ }
+
+ return c1 - c2;
+}
+#endif /* def SEL_FILE_IGNORE_CASE */
+
+static void
+SFreplaceText(SFDir *dir, char *str)
+{
+ int len;
+
+ *(dir->path) = 0;
+ len = strlen(str);
+ if (str[len - 1] == '/') {
+ (void)strcat(SFcurrentPath, str);
+ }
+ else {
+ (void)strncat(SFcurrentPath, str, len - 1);
+ }
+/* if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) { */
+/* SFsetText(SFcurrentPath); */
+/* } */
+/* else { */
+/* SFsetText(&(SFcurrentPath[strlen(SFstartDir)])); */
+/* } */
+ SFsetText(SFcurrentPath);
+
+ SFtextChanged();
+}
+
+static void
+SFexpand(char *str)
+{
+ int len;
+ int cmp;
+ char *name, *growing;
+ SFDir *dir;
+ SFEntry *entry, *max;
+
+ len = strlen(str);
+
+ dir = &(SFdirs[SFdirEnd - 1]);
+
+ if (dir->beginSelection == -1) {
+ SFstrdup(&str, str);
+ SFreplaceText(dir, str);
+ XtFree(str);
+ return;
+ }
+ else if (dir->beginSelection == dir->endSelection) {
+ SFreplaceText(dir, dir->entries[dir->beginSelection].shown);
+ return;
+ }
+
+ max = &(dir->entries[dir->endSelection + 1]);
+
+ name = dir->entries[dir->beginSelection].shown;
+ SFstrdup(&growing, name);
+
+ cmp = 0;
+ while (!cmp) {
+ entry = &(dir->entries[dir->beginSelection]);
+ while (entry < max) {
+ if ((cmp = strncmp(growing, entry->shown, len))) {
+ break;
+ }
+ entry++;
+ }
+ len++;
+ }
+
+ /*
+ * SFreplaceText() expects filename
+ */
+ growing[len - 2] = ' ';
+
+ growing[len - 1] = 0;
+ SFreplaceText(dir, growing);
+ XtFree(growing);
+}
+
+static int
+SFfindFile(SFDir *dir, char *str)
+{
+ int i, last, max;
+ char *name, save;
+ SFEntry *entries;
+ int len;
+ int begin, end;
+ int result;
+
+ len = strlen(str);
+
+ if (str[len - 1] == ' ') {
+ SFexpand(str);
+ return 1;
+ }
+ else if (str[len - 1] == '/') {
+ len--;
+ }
+
+ max = dir->nEntries;
+
+ entries = dir->entries;
+
+ i = 0;
+ while (i < max) {
+ name = entries[i].shown;
+ last = strlen(name) - 1;
+ save = name[last];
+ name[last] = 0;
+
+#ifdef SEL_FILE_IGNORE_CASE
+ result = SFstrncmp(str, name, len);
+#else /* def SEL_FILE_IGNORE_CASE */
+ result = strncmp(str, name, len);
+#endif /* def SEL_FILE_IGNORE_CASE */
+
+ name[last] = save;
+ if (result <= 0) {
+ break;
+ }
+ i++;
+ }
+ begin = i;
+ while (i < max) {
+ name = entries[i].shown;
+ last = strlen(name) - 1;
+ save = name[last];
+ name[last] = 0;
+
+#ifdef SEL_FILE_IGNORE_CASE
+ result = SFstrncmp(str, name, len);
+#else /* def SEL_FILE_IGNORE_CASE */
+ result = strncmp(str, name, len);
+#endif /* def SEL_FILE_IGNORE_CASE */
+
+ name[last] = save;
+ if (result) {
+ break;
+ }
+ i++;
+ }
+ end = i;
+
+ if (begin != end) {
+ if ((dir->beginSelection != begin) || (dir->endSelection != end - 1)
+ ) {
+ dir->changed = 1;
+ dir->beginSelection = begin;
+ if (str[strlen(str) - 1] == '/') {
+ dir->endSelection = begin;
+ }
+ else {
+ dir->endSelection = end - 1;
+ }
+ }
+ }
+ else {
+ if (dir->beginSelection != -1) {
+ dir->changed = 1;
+ dir->beginSelection = -1;
+ dir->endSelection = -1;
+ }
+ }
+
+ if (SFdoNotTouchVorigin ||
+ ((begin > dir->vOrigin) && (end < dir->vOrigin + SFlistSize))) {
+ SFdoNotTouchVorigin = 0;
+ return 0;
+ }
+
+ i = begin - 1;
+ if (i > max - SFlistSize) {
+ i = max - SFlistSize;
+ }
+ if (i < 0) {
+ i = 0;
+ }
+
+ if (dir->vOrigin != i) {
+ dir->vOrigin = i;
+ dir->changed = 1;
+ }
+
+ return 0;
+}
+
+static void
+SFunselect(void)
+{
+ SFDir *dir;
+
+ dir = &(SFdirs[SFdirEnd - 1]);
+ if (dir->beginSelection != -1) {
+ dir->changed = 1;
+ }
+ dir->beginSelection = -1;
+ dir->endSelection = -1;
+}
+
+static int
+SFcompareLogins(const void *vp, const void *vq)
+{
+ const SFLogin *p = vp;
+ const SFLogin *q = vq;
+ return strcmp(p->name, q->name);
+}
+
+static void
+SFgetHomeDirs(void)
+{
+ struct passwd *pw;
+ int alloc;
+ int i;
+ SFEntry *entries = NULL;
+ int len;
+ int maxChars;
+
+ {
+ alloc = 1;
+ i = 1;
+ entries = (SFEntry *) XtMalloc(sizeof(SFEntry));
+ SFlogins = (SFLogin *) XtMalloc(sizeof(SFLogin));
+ entries[0].real = XtMalloc(3);
+ (void)strcpy(entries[0].real, "~");
+ entries[0].shown = entries[0].real;
+ entries[0].statDone = 1;
+ SFlogins[0].name = "";
+ pw = getpwuid((int)getuid());
+ SFstrdup(&SFlogins[0].dir, pw ? pw->pw_dir : "/");
+ maxChars = 0;
+ }
+
+ (void)setpwent();
+
+ while ((pw = (struct passwd *)getpwent()) && (*(pw->pw_name))) {
+ if (i >= alloc) {
+ alloc *= 2;
+ entries = (SFEntry *) XtRealloc(
+ (char *)entries,
+ (unsigned)(alloc *
+ sizeof(SFEntry)));
+ SFlogins =
+ (SFLogin *) XtRealloc((char *)SFlogins,
+ (unsigned)(alloc * sizeof(SFLogin))
+ );
+ }
+ len = strlen(pw->pw_name);
+ entries[i].real = XtMalloc((unsigned)(len + 3));
+ (void)strcat(strcpy(entries[i].real, "~"), pw->pw_name);
+ entries[i].shown = entries[i].real;
+ entries[i].statDone = 1;
+ if (len > maxChars) {
+ maxChars = len;
+ }
+ SFstrdup(&SFlogins[i].name, pw->pw_name);
+ SFstrdup(&SFlogins[i].dir, pw->pw_dir);
+ i++;
+ }
+
+ SFhomeDir.dir = XtMalloc(1);
+ SFhomeDir.dir[0] = 0;
+ SFhomeDir.path = SFcurrentPath;
+ SFhomeDir.entries = entries;
+ SFhomeDir.nEntries = i;
+ SFhomeDir.vOrigin = 0; /* :-) */
+ SFhomeDir.nChars = maxChars + 2;
+ SFhomeDir.hOrigin = 0;
+ SFhomeDir.changed = 1;
+ SFhomeDir.beginSelection = -1;
+ SFhomeDir.endSelection = -1;
+
+#if defined(SVR4) || defined(SYSV) || defined(USG)
+ qsort((char *)entries, (unsigned)i, sizeof(SFEntry), SFcompareEntries);
+ qsort((char *)SFlogins, (unsigned)i, sizeof(SFLogin), SFcompareLogins);
+#else /* defined(SVR4) || defined(SYSV) || defined(USG) */
+ qsort((char *)entries, i, sizeof(SFEntry), SFcompareEntries);
+ qsort((char *)SFlogins, i, sizeof(SFLogin), SFcompareLogins);
+#endif /* defined(SVR4) || defined(SYSV) || defined(USG) */
+
+ for (i--; i >= 0; i--) {
+ (void)strcat(entries[i].real, "/");
+ }
+}
+
+static int
+SFfindHomeDir(char *begin, char *end)
+{
+ char save;
+ char *theRest;
+ int i;
+
+ save = *end;
+ *end = 0;
+
+ for (i = SFhomeDir.nEntries - 1; i >= 0; i--) {
+ if (!strcmp(SFhomeDir.entries[i].real, begin)) {
+ *end = save;
+ SFstrdup(&theRest, end);
+ (void)strcat(strcat(strcpy(SFcurrentPath,
+ SFlogins[i].dir), "/"), theRest);
+ XtFree(theRest);
+ SFsetText(SFcurrentPath);
+ SFtextChanged();
+ return 1;
+ }
+ }
+
+ *end = save;
+
+ return 0;
+}
+
+void
+SFupdatePath(void)
+{
+ static int alloc;
+ static int wasTwiddle = 0;
+ char *begin, *end;
+ int i, j;
+ int prevChange;
+ int SFdirPtrSave, SFdirEndSave;
+ SFDir *dir;
+
+ if (!SFdirs) {
+ SFdirs = (SFDir *) XtMalloc((alloc = 10) * sizeof(SFDir));
+ dir = &(SFdirs[0]);
+ SFstrdup(&dir->dir, "/");
+ (void)SFchdir("/");
+ (void)SFgetDir(dir);
+ for (j = 1; j < alloc; j++) {
+ SFdirs[j].dir = NULL;
+ }
+ dir->path = SFcurrentPath + 1;
+ dir->vOrigin = 0;
+ dir->hOrigin = 0;
+ dir->changed = 1;
+ dir->beginSelection = -1;
+ dir->endSelection = -1;
+ SFhomeDir.dir = NULL;
+ }
+
+ SFdirEndSave = SFdirEnd;
+ SFdirEnd = 1;
+
+ SFdirPtrSave = SFdirPtr;
+ SFdirPtr = 0;
+
+ begin = NULL;
+
+ if (SFcurrentPath[0] == '~') {
+ if (!SFtwiddle) {
+ SFtwiddle = 1;
+ dir = &(SFdirs[0]);
+ SFrootDir = *dir;
+ if (!SFhomeDir.dir) {
+ SFgetHomeDirs();
+ }
+ *dir = SFhomeDir;
+ dir->changed = 1;
+ }
+ end = SFcurrentPath;
+ SFdoNotTouchDirPtr = 1;
+ wasTwiddle = 1;
+ }
+ else {
+ if (SFtwiddle) {
+ SFtwiddle = 0;
+ dir = &(SFdirs[0]);
+ *dir = SFrootDir;
+ dir->changed = 1;
+ }
+ end = SFcurrentPath + 1;
+ }
+
+ i = 0;
+
+ prevChange = 0;
+
+ while (*end) {
+ while (*end++ == '/') {
+ ;
+ }
+ end--;
+ begin = end;
+ while ((*end) && (*end++ != '/')) {
+ ;
+ }
+ if ((end - SFcurrentPath <= SFtextPos) && (*(end - 1) == '/')) {
+ SFdirPtr = i - 1;
+ if (SFdirPtr < 0) {
+ SFdirPtr = 0;
+ }
+ }
+ if (*begin) {
+ if (*(end - 1) == '/') {
+ char save = *end;
+
+ if (SFtwiddle) {
+ if (SFfindHomeDir(begin, end)) {
+ return;
+ }
+ }
+ *end = 0;
+ i++;
+ SFdirEnd++;
+ if (i >= alloc) {
+ SFdirs = (SFDir *) XtRealloc(
+ (char *)SFdirs,
+ (unsigned)((alloc *= 2) *
+ sizeof(SFDir))
+ );
+ for (j = alloc / 2; j < alloc; j++) {
+ SFdirs[j].dir = NULL;
+ }
+ }
+ dir = &(SFdirs[i]);
+ if ((!(dir->dir)) || prevChange || strcmp(dir->dir, begin)
+ ) {
+ if (dir->dir) {
+ SFfree(i);
+ }
+ prevChange = 1;
+ SFstrdup(&dir->dir, begin);
+ dir->path = end;
+ dir->vOrigin = 0;
+ dir->hOrigin = 0;
+ dir->changed = 1;
+ dir->beginSelection = -1;
+ dir->endSelection = -1;
+ (void)SFfindFile(dir - 1, begin);
+ if (SFchdir(SFcurrentPath) || SFgetDir(dir)
+ ) {
+ SFunreadableDir(dir);
+ break;
+ }
+ }
+ *end = save;
+ if (!save) {
+ SFunselect();
+ }
+ }
+ else {
+ if (SFfindFile(&(SFdirs[SFdirEnd - 1]), begin)) {
+ return;
+ }
+ }
+ }
+ else {
+ SFunselect();
+ }
+ }
+
+ if ((end == SFcurrentPath + 1) && (!SFtwiddle)) {
+ SFunselect();
+ }
+
+ for (i = SFdirEnd; i < alloc; i++) {
+ if (SFdirs[i].dir) {
+ SFfree(i);
+ }
+ }
+
+ if (SFdoNotTouchDirPtr) {
+ if (wasTwiddle) {
+ wasTwiddle = 0;
+ SFdirPtr = SFdirEnd - 2;
+ if (SFdirPtr < 0) {
+ SFdirPtr = 0;
+ }
+ }
+ else {
+ SFdirPtr = SFdirPtrSave;
+ }
+ SFdoNotTouchDirPtr = 0;
+ }
+
+ if ((SFdirPtr != SFdirPtrSave) || (SFdirEnd != SFdirEndSave)) {
+ XawScrollbarSetThumb(selFileHScroll,
+ (double)(SFdirPtr) / SFdirEnd,
+ (double)(SFdirEnd < 3 ? SFdirEnd : 3) / SFdirEnd);
+ }
+
+ if (SFdirPtr != SFdirPtrSave) {
+ SFdrawLists(SF_DO_SCROLL);
+ }
+ else {
+ for (i = 0; i < 3; i++) {
+ if (SFdirPtr + i < SFdirEnd) {
+ if (SFdirs[SFdirPtr + i].changed) {
+ SFdirs[SFdirPtr + i].changed = 0;
+ SFdrawList(i, SF_DO_SCROLL);
+ }
+ }
+ else {
+ SFclearList(i, SF_DO_SCROLL);
+ }
+ }
+ }
+}
+
+void
+SFsetText(char *path)
+{
+ XawTextBlock text;
+
+ text.firstPos = 0;
+ text.length = strlen(path);
+ text.ptr = path;
+ text.format = FMT8BIT;
+
+ XawTextReplace(selFileField, 0, strlen(SFtextBuffer), &text);
+ XawTextSetInsertionPoint(selFileField, strlen(SFtextBuffer));
+}
+
+void
+SFbuttonPressList(Widget w, int n, XButtonPressedEvent *event)
+{
+ UNUSED(w);
+ UNUSED(n);
+ UNUSED(event);
+
+ SFbuttonPressed = 1;
+}
+
+void
+SFbuttonReleaseList(Widget w, int n, XButtonReleasedEvent *event)
+{
+ SFDir *dir;
+
+ SFbuttonPressed = 0;
+
+ if (SFcurrentInvert[n] != -1) {
+ if (n < 2) {
+ SFdoNotTouchDirPtr = 1;
+ }
+ SFdoNotTouchVorigin = 1;
+ dir = &(SFdirs[SFdirPtr + n]);
+ SFreplaceText(dir,
+ dir->entries[dir->vOrigin + SFcurrentInvert[n]].shown);
+ SFmotionList(w, n, (XMotionEvent *)event);
+ }
+}
+
+static int
+SFcheckDir(int n, SFDir *dir)
+{
+ struct stat statBuf;
+ int i;
+
+ if ((!stat(".", &statBuf)) && (statBuf.st_mtime != dir->mtime)
+ ) {
+
+ /*
+ * If the pointer is currently in the window that we are about
+ * to update, we must warp it to prevent the user from
+ * accidentally selecting the wrong file.
+ */
+ if (SFcurrentInvert[n] != -1) {
+ XWarpPointer(SFdisplay,
+ None, XtWindow(selFileLists[n]), 0, 0, 0, 0, 0, 0);
+ }
+
+ for (i = dir->nEntries - 1; i >= 0; i--) {
+ if (dir->entries[i].shown != dir->entries[i].real) {
+ XtFree(dir->entries[i].shown);
+ }
+ XtFree(dir->entries[i].real);
+ }
+ XtFree((char *)dir->entries);
+ if (SFgetDir(dir)) {
+ SFunreadableDir(dir);
+ }
+ if (dir->vOrigin > dir->nEntries - SFlistSize) {
+ dir->vOrigin = dir->nEntries - SFlistSize;
+ }
+ if (dir->vOrigin < 0) {
+ dir->vOrigin = 0;
+ }
+ if (dir->hOrigin > dir->nChars - SFcharsPerEntry) {
+ dir->hOrigin = dir->nChars - SFcharsPerEntry;
+ }
+ if (dir->hOrigin < 0) {
+ dir->hOrigin = 0;
+ }
+ dir->beginSelection = -1;
+ dir->endSelection = -1;
+ SFdoNotTouchVorigin = 1;
+ if ((dir + 1)->dir) {
+ (void)SFfindFile(dir, (dir + 1)->dir);
+ }
+ else {
+ (void)SFfindFile(dir, dir->path);
+ }
+
+ if (!SFworkProcAdded) {
+ (void)XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
+ SFworkProcAdded = 1;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+SFcheckFiles(SFDir *dir)
+{
+ int from, to;
+ int result;
+ char old, new;
+ int i;
+ char *str;
+ int last;
+ struct stat statBuf;
+
+ result = 0;
+
+ from = dir->vOrigin;
+ to = dir->vOrigin + SFlistSize;
+ if (to > dir->nEntries) {
+ to = dir->nEntries;
+ }
+
+ for (i = from; i < to; i++) {
+ str = dir->entries[i].real;
+ last = strlen(str) - 1;
+ old = str[last];
+ str[last] = 0;
+ if (stat(str, &statBuf)) {
+ new = ' ';
+ }
+ else {
+ new = SFstatChar(&statBuf);
+ }
+ str[last] = new;
+ if (new != old) {
+ result = 1;
+ }
+ }
+
+ return result;
+}
+
+void
+SFdirModTimer(XtPointer cl, XtIntervalId *id)
+{
+ static int n = -1;
+ static int f = 0;
+ char save;
+ SFDir *dir;
+
+ UNUSED(cl);
+ UNUSED(id);
+
+ fprintf(stderr, "sfdirmodtimer called!\n");
+
+ if ((!SFtwiddle) && (SFdirPtr < SFdirEnd)) {
+ n++;
+ if ((n > 2) || (SFdirPtr + n >= SFdirEnd)) {
+ n = 0;
+ f++;
+ if ((f > 2) || (SFdirPtr + f >= SFdirEnd)) {
+ f = 0;
+ }
+ }
+ dir = &(SFdirs[SFdirPtr + n]);
+ save = *(dir->path);
+ *(dir->path) = 0;
+ if (SFchdir(SFcurrentPath)) {
+ *(dir->path) = save;
+
+ /*
+ * force a re-read
+ */
+ *(dir->dir) = 0;
+
+ SFupdatePath();
+ }
+ else {
+ *(dir->path) = save;
+ if (SFcheckDir(n, dir) || ((f == n) && SFcheckFiles(dir))
+ ) {
+ SFdrawList(n, SF_DO_SCROLL);
+ }
+ }
+ }
+
+ SFdirModTimerId = XtAppAddTimeOut(SFapp, 1500UL,
+ SFdirModTimer, (XtPointer) NULL);
+}
+
+/* Return a single character describing what kind of file STATBUF is. */
+
+char
+SFstatChar(struct stat *statBuf)
+{
+ if (S_ISDIR(statBuf->st_mode)) {
+ return '/';
+ }
+ else if (S_ISREG(statBuf->st_mode)) {
+ return S_ISXXX(statBuf->st_mode) ? '*' : ' ';
+#ifdef S_ISSOCK
+ }
+ else if (S_ISSOCK(statBuf->st_mode)) {
+ return '=';
+#endif /* S_ISSOCK */
+ }
+ else {
+ return ' ';
+ }
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* !defined(MOTIF) */
diff --git a/Build/source/texk/xdvik/gui/sfPath.h b/Build/source/texk/xdvik/gui/sfPath.h
new file mode 100644
index 00000000000..d087c0f804c
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfPath.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef SFPATH_H_
+#define SFPATH_H_
+
+#include "xdvi-config.h"
+
+#ifndef MOTIF
+
+extern int SFchdir(char *path);
+extern void SFupdatePath(void);
+extern void SFsetText(char *path);
+extern void SFbuttonPressList(Widget w, int n, XButtonPressedEvent *event);
+extern void SFbuttonReleaseList(Widget w, int n, XButtonReleasedEvent *event);
+extern void SFdirModTimer(XtPointer cl, XtIntervalId *id);
+extern char SFstatChar(struct stat *statBuf);
+
+extern char SFcurrentPath[], SFstartDir[], SFcurrentDir[];
+extern SFDir *SFdirs;
+extern int SFdirEnd, SFdirPtr;
+
+#endif /* MOTIF */
+
+#endif /* SFPATH_H_ */
diff --git a/Build/source/texk/xdvik/gui/sfSelFile.c b/Build/source/texk/xdvik/gui/sfSelFile.c
new file mode 100644
index 00000000000..9964c69ad37
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfSelFile.c
@@ -0,0 +1,1071 @@
+/*
+ * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Software Research Associates not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Software Research Associates
+ * makes no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Erik M. van der Poel
+ * Software Research Associates, Inc., Tokyo, Japan
+ * erik@sra.co.jp
+ */
+
+#include "xdvi-config.h"
+
+#include "xdvi.h"
+#include "dvi-init.h" /* for dviErrFlagT */
+#include "message-window.h"
+
+#include "kpathsea/c-stat.h"
+
+#include <string.h>
+
+#include "sfDir.h"
+#include "sfPath.h"
+#include "sfDraw.h"
+#include "sfSelFile.h"
+#include "util.h"
+
+#include <ctype.h>
+#include "kpathsea/c-fopen.h"
+#include "kpathsea/c-stat.h"
+
+#if !defined(MOTIF) /* entire file */
+
+
+#include <errno.h>
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+#define SEL_FILE_CANCEL -1
+#define SEL_FILE_OK 0
+#define SEL_FILE_NULL 1
+#define SEL_FILE_TEXT 2
+
+/*
+ * Author's address:
+ *
+ * erik@sra.co.jp
+ * OR
+ * erik%sra.co.jp@uunet.uu.net
+ * OR
+ * erik%sra.co.jp@mcvax.uucp
+ * OR
+ * try junet instead of co.jp
+ * OR
+ * Erik M. van der Poel
+ * Software Research Associates, Inc.
+ * 1-1-1 Hirakawa-cho, Chiyoda-ku
+ * Tokyo 102 Japan. TEL +81-3-234-2692
+ */
+
+#include <sys/param.h>
+#include <X11/cursorfont.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Composite.h>
+#include <X11/Shell.h>
+#include <X11/Xaw/Paned.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/Command.h>
+#include <X11/Xaw/Scrollbar.h>
+#include <X11/Xaw/Label.h>
+#include <X11/Xaw/Cardinals.h>
+
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif /* ndef MAXPATHLEN */
+
+/* global vars for communication with sfDraw.c */
+char SFstartDir[MAXPATHLEN], SFcurrentPath[MAXPATHLEN], SFcurrentDir[MAXPATHLEN];
+Widget selFileField, selFileForm, selFileHScroll, selFileHScrolls[3], selFileLists[3], selFileVScrolls[3];
+Display *SFdisplay;
+Pixel SFfore, SFback;
+XSegment SFsegs[2], SFcompletionSegs[2];
+XawTextPosition SFtextPos;
+int SFupperX, SFlowerY, SFupperY;
+int SFtextX, SFtextYoffset;
+int SFentryWidth, SFentryHeight;
+int SFlineToTextH = 3;
+int SFlineToTextV = 3;
+int SFbesideText = 3;
+int SFaboveAndBelowText = 2;
+int SFcharsPerEntry = 15;
+int SFlistSize = 10;
+int SFworkProcAdded = 0;
+XtAppContext SFapp;
+int SFpathScrollWidth, SFvScrollHeight, SFhScrollWidth;
+char SFtextBuffer[MAXPATHLEN];
+XtIntervalId SFdirModTimerId;
+int (*SFfunc) ();
+
+static int SFstatus = SEL_FILE_NULL;
+
+static Widget selFile, selFileCancel, selFileOK, selFilePrompt;
+/* For file filter. */
+static Widget selFileLabel, selFileMask, selFileHide;
+
+#define MASKWIDTH 16
+static char fileMask[MASKWIDTH + 2] = "*.dvi";
+
+static Atom SFwmDeleteWindow;
+
+static char *oneLineTextEditTranslations =
+ "<Key>Return: redraw-display()\n"
+ "Ctrl<Key>M: redraw-display()\n";
+
+#if !defined (HAVE_STRERROR) && !defined (strerror)
+static char *
+strerror(int errnum)
+{
+ return 0 < errnum && errnum <= sys_nerr
+ ? sys_errlist[errnum] : "Unknown system error";
+}
+#endif /* not HAVE_STRERROR && not strerror */
+
+void
+raise_file_selector(void)
+{
+ if (selFile != 0) {
+ XRaiseWindow(DISP, XtWindow(selFile));
+ }
+}
+
+static void
+SFexposeList(Widget w, XtPointer n, XEvent *event, Boolean *cont)
+{
+ UNUSED(w);
+ UNUSED(cont);
+
+ if ((event->type == NoExpose) || event->xexpose.count) {
+ return;
+ }
+
+ SFdrawList((int)n, SF_DO_NOT_SCROLL);
+}
+
+static void
+SFmodVerifyCallback(Widget w, XtPointer client_data, XEvent *event, Boolean *cont)
+{
+ char buf[2];
+
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(cont);
+
+ if ((XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) &&
+ ((*buf) == '\r')) {
+ SFstatus = SEL_FILE_OK;
+ }
+ else {
+ SFstatus = SEL_FILE_TEXT;
+ }
+}
+
+static void
+SFokCallback(Widget w, XtPointer cl, XtPointer cd)
+{
+ UNUSED(w);
+ UNUSED(cl);
+ UNUSED(cd);
+
+ SFstatus = SEL_FILE_OK;
+}
+
+static XtCallbackRec SFokSelect[] = {
+ {SFokCallback, (XtPointer) NULL},
+ {NULL, (XtPointer) NULL},
+};
+
+static void
+SFcancelCallback(Widget w, XtPointer cl, XtPointer cd)
+{
+ UNUSED(w);
+ UNUSED(cl);
+ UNUSED(cd);
+
+ SFstatus = SEL_FILE_CANCEL;
+}
+
+static XtCallbackRec SFcancelSelect[] = {
+ {SFcancelCallback, (XtPointer) NULL},
+ {NULL, (XtPointer) NULL},
+};
+
+static void
+SFdismissAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (event->type == ClientMessage && (unsigned)(event->xclient.data.l[0]) != SFwmDeleteWindow)
+ return;
+
+ SFstatus = SEL_FILE_CANCEL;
+}
+
+static char *wmDeleteWindowTranslation = "<Message>WM_PROTOCOLS: SelFileDismiss()\n";
+
+static XtActionsRec sf_actions[] = {
+ {"SelFileDismiss", SFdismissAction},
+};
+
+/* Don't show files that don't get through the filter. */
+
+/* return 1 if file is masked (mask does not match filename), 0 otherwise */
+static int
+maskFile(const char *mask, char *filename)
+{
+ int c, c1;
+
+ while ((c = *mask++)) {
+ if (c == '*') {
+ while ((c1 = *mask++)) {
+ if (c1 != '*') {
+ if (!(*filename))
+ return 1;
+ if (c1 != '?') {
+ while ((filename = strchr(filename, c1))) {
+ if (!maskFile(mask, ++filename))
+ return 0;
+ }
+ return 1;
+ }
+ else
+ filename++;
+ }
+ }
+ return 0;
+ }
+ if (c == '?') {
+ if (!*filename)
+ return 1;
+ }
+ else if (c != *filename)
+ return 1;
+ filename++;
+ }
+ return (*filename) ? 1 : 0;
+}
+
+Boolean hideFlag = False;
+static int
+showEntry(char *entryReal, char **entryShown, struct stat *statBuf)
+{
+ UNUSED(entryShown);
+
+ if ((hideFlag && entryReal[0] == '.') || (!S_ISDIR(statBuf->st_mode) && maskFile(fileMask, entryReal)))
+ return 0;
+ entryReal[strlen(entryReal)] = SFstatChar(statBuf);
+ return 1;
+}
+
+static void
+maskChanged(Widget w, XtPointer client_data, XEvent *call_data, Boolean *cont)
+{
+ char buf[2];
+ SFDir *dir;
+
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(cont);
+
+ if ((XLookupString((XKeyPressedEvent *)call_data, buf, 2, NULL, NULL) == 1) && ((*buf) == '\r')) {
+ for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--)
+ *(dir->dir) = 0; /* force a re-read */
+ SFupdatePath();
+ }
+}
+
+static void
+hideFiles(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ SFDir *dir;
+ SFEntry *entry;
+
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ hideFlag = !hideFlag;
+ if (hideFlag) {
+ XtVaSetValues(w, XtNlabel, "hidden", NULL);
+ for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--) {
+ if (!(dir->nEntries))
+ continue;
+ dir->vOrigin = 0;
+ for (entry = &(dir->entries[dir->nEntries - 1]);
+ entry >= dir->entries; entry--)
+ entry->statDone = 0;
+ SFdrawLists(SF_DO_SCROLL);
+ }
+ }
+ else {
+ XtVaSetValues(w, XtNlabel, "shown", NULL);
+ for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--)
+ *(dir->dir) = 0; /* force a re-read */
+ SFupdatePath();
+ }
+}
+
+
+static Widget
+SFcreateWidgets(Widget parent, const char *title, const char *prompt, const char *ok, const char *cancel)
+{
+ Cardinal i, n;
+ int listWidth, listHeight;
+ int listSpacing = 10;
+ int scrollThickness = 15;
+ int hScrollX, hScrollY;
+ int vScrollX, vScrollY;
+ Cursor xtermCursor, sbRightArrowCursor, arrowCursor;
+ Arg arglist[20];
+ Widget paned, box;
+
+ i = 0;
+ XtSetArg(arglist[i], XtNtransientFor, parent);
+ XtSetArg(arglist[i], XtNtitle, title);
+ i++;
+
+ selFile = XtAppCreateShell("xdviSelFile", "XdviSelFile",
+ transientShellWidgetClass, SFdisplay,
+ arglist, i);
+
+ /* Add WM_DELETE_WINDOW protocol */
+ XtAppAddActions(XtWidgetToApplicationContext(selFile),
+ sf_actions, XtNumber(sf_actions));
+ XtOverrideTranslations(selFile,
+ XtParseTranslationTable(wmDeleteWindowTranslation));
+
+ paned = XtVaCreateManagedWidget("paned", panedWidgetClass, selFile, NULL);
+ i = 0;
+ XtSetArg(arglist[i], XtNdefaultDistance, 6);
+ i++;
+ selFileForm = XtCreateManagedWidget("selFileForm",
+ formWidgetClass, paned, arglist, i);
+
+ i = 0;
+ XtSetArg(arglist[i], XtNlabel, prompt);
+ i++;
+ XtSetArg(arglist[i], XtNresizable, True);
+ i++;
+ XtSetArg(arglist[i], XtNtop, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNbottom, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNleft, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNright, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNborderWidth, 0);
+ i++;
+ XtSetArg(arglist[i], XtNvertDistance, 20);
+ i++;
+ selFilePrompt = XtCreateManagedWidget("selFilePrompt",
+ labelWidgetClass, selFileForm,
+ arglist, i);
+
+#if 1
+ i = 0;
+ XtSetArg(arglist[i], XtNforeground, &SFfore);
+ i++;
+ XtSetArg(arglist[i], XtNbackground, &SFback);
+ i++;
+ XtGetValues(selFilePrompt, arglist, i);
+#endif
+
+ SFinitFont();
+
+ SFentryWidth = SFbesideText + SFcharsPerEntry * SFcharWidth + SFbesideText;
+ SFentryHeight = SFaboveAndBelowText + SFcharHeight + SFaboveAndBelowText;
+
+ listWidth = SFlineToTextH + SFentryWidth + SFlineToTextH + 1 +
+ scrollThickness;
+ listHeight = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
+ SFlineToTextV + SFlistSize * SFentryHeight +
+ SFlineToTextV + 1 + scrollThickness;
+
+ SFpathScrollWidth = 3 * listWidth + 2 * listSpacing + 4;
+
+ hScrollX = -1;
+ hScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
+ SFlineToTextV + SFlistSize * SFentryHeight + SFlineToTextV;
+ SFhScrollWidth = SFlineToTextH + SFentryWidth + SFlineToTextH;
+
+ vScrollX = SFlineToTextH + SFentryWidth + SFlineToTextH;
+ vScrollY = SFlineToTextV + SFentryHeight + SFlineToTextV;
+ SFvScrollHeight = SFlineToTextV + SFlistSize * SFentryHeight +
+ SFlineToTextV;
+
+ SFupperX = SFlineToTextH + SFentryWidth + SFlineToTextH - 1;
+ SFlowerY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
+ SFlineToTextV;
+ SFupperY = SFlineToTextV + SFentryHeight + SFlineToTextV + 1 +
+ SFlineToTextV + SFlistSize * SFentryHeight - 1;
+
+ SFtextX = SFlineToTextH + SFbesideText;
+ SFtextYoffset = SFlowerY + SFaboveAndBelowText + SFcharAscent;
+
+ SFsegs[0].x1 = 0;
+ SFsegs[0].y1 = vScrollY;
+ SFsegs[0].x2 = vScrollX - 1;
+ SFsegs[0].y2 = vScrollY;
+ SFsegs[1].x1 = vScrollX;
+ SFsegs[1].y1 = 0;
+ SFsegs[1].x2 = vScrollX;
+ SFsegs[1].y2 = vScrollY - 1;
+
+ SFcompletionSegs[0].x1 = SFcompletionSegs[0].x2 = SFlineToTextH;
+ SFcompletionSegs[1].x1 = SFcompletionSegs[1].x2 =
+ SFlineToTextH + SFentryWidth - 1;
+
+ i = 0;
+/* XtSetArg(arglist[i], XtNwidth, 3 * listWidth + 2 * listSpacing + 4 - w - 10); */
+ XtSetArg(arglist[i], XtNwidth, 3 * listWidth + 2 * listSpacing + 4);
+ i++;
+/* XtSetArg(arglist[i], XtNborderColor, SFfore); */
+/* i++; */
+
+/* XtSetArg(arglist[i], XtNfromHoriz, selFilePrompt); */
+/* i++; */
+/* XtSetArg(arglist[i], XtNhorizDistance, 10); */
+ XtSetArg(arglist[i], XtNfromVert, selFilePrompt);
+ i++;
+/* XtSetArg(arglist[i], XtNvertDistance, 0); */
+/* i++; */
+ XtSetArg(arglist[i], XtNresizable, True);
+ i++;
+ XtSetArg(arglist[i], XtNtop, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNbottom, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNleft, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNright, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNstring, SFtextBuffer);
+ i++;
+ XtSetArg(arglist[i], XtNlength, MAXPATHLEN);
+ i++;
+ XtSetArg(arglist[i], XtNeditType, XawtextEdit);
+ i++;
+ XtSetArg(arglist[i], XtNwrap, XawtextWrapWord);
+ i++;
+ XtSetArg(arglist[i], XtNresize, XawtextResizeHeight);
+ i++;
+ XtSetArg(arglist[i], XtNuseStringInPlace, True);
+ i++;
+ XtSetArg(arglist[i], XtNvertDistance, 5);
+ i++;
+ selFileField = XtCreateManagedWidget("selFileField",
+ asciiTextWidgetClass, selFileForm,
+ arglist, i);
+
+ XtOverrideTranslations(selFileField,
+ XtParseTranslationTable
+ (oneLineTextEditTranslations));
+/* XtSetKeyboardFocus(selFileForm, selFileField);
+ need focus for selFileMask widget to set the filter */
+
+ i = 0;
+ XtSetArg(arglist[i], XtNorientation, XtorientHorizontal);
+ i++;
+ XtSetArg(arglist[i], XtNwidth, SFpathScrollWidth);
+ i++;
+ XtSetArg(arglist[i], XtNheight, scrollThickness);
+ i++;
+/* XtSetArg(arglist[i], XtNborderColor, SFfore); */
+/* i++; */
+ XtSetArg(arglist[i], XtNfromVert, selFileField);
+ i++;
+ XtSetArg(arglist[i], XtNvertDistance, 30);
+ i++;
+ XtSetArg(arglist[i], XtNtop, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNbottom, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNleft, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNright, XtChainLeft);
+ i++;
+ selFileHScroll = XtCreateManagedWidget("selFileHScroll",
+ scrollbarWidgetClass, selFileForm,
+ arglist, i);
+
+ XtAddCallback(selFileHScroll, XtNjumpProc,
+ (XtCallbackProc)SFpathSliderMovedCallback, (XtPointer) NULL);
+ XtAddCallback(selFileHScroll, XtNscrollProc,
+ (XtCallbackProc)SFpathAreaSelectedCallback, (XtPointer) NULL);
+
+ i = 0;
+ XtSetArg(arglist[i], XtNwidth, listWidth);
+ i++;
+ XtSetArg(arglist[i], XtNheight, listHeight);
+ i++;
+/* XtSetArg(arglist[i], XtNborderColor, SFfore); */
+/* i++; */
+ XtSetArg(arglist[i], XtNfromVert, selFileHScroll);
+ i++;
+ XtSetArg(arglist[i], XtNvertDistance, 10);
+ i++;
+ XtSetArg(arglist[i], XtNtop, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNbottom, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNleft, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNright, XtChainLeft);
+ i++;
+ selFileLists[0] = XtCreateManagedWidget("selFileList1",
+ compositeWidgetClass, selFileForm,
+ arglist, i);
+
+ i = 0;
+ XtSetArg(arglist[i], XtNwidth, listWidth);
+ i++;
+ XtSetArg(arglist[i], XtNheight, listHeight);
+ i++;
+/* XtSetArg(arglist[i], XtNborderColor, SFfore); */
+/* i++; */
+ XtSetArg(arglist[i], XtNfromHoriz, selFileLists[0]);
+ i++;
+ XtSetArg(arglist[i], XtNfromVert, selFileHScroll);
+ i++;
+ XtSetArg(arglist[i], XtNhorizDistance, listSpacing);
+ i++;
+ XtSetArg(arglist[i], XtNvertDistance, 10);
+ i++;
+ XtSetArg(arglist[i], XtNtop, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNbottom, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNleft, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNright, XtChainLeft);
+ i++;
+ selFileLists[1] = XtCreateManagedWidget("selFileList2",
+ compositeWidgetClass, selFileForm,
+ arglist, i);
+
+ i = 0;
+ XtSetArg(arglist[i], XtNwidth, listWidth);
+ i++;
+ XtSetArg(arglist[i], XtNheight, listHeight);
+ i++;
+/* XtSetArg(arglist[i], XtNborderColor, SFfore); */
+/* i++; */
+ XtSetArg(arglist[i], XtNfromHoriz, selFileLists[1]);
+ i++;
+ XtSetArg(arglist[i], XtNfromVert, selFileHScroll);
+ i++;
+ XtSetArg(arglist[i], XtNhorizDistance, listSpacing);
+ i++;
+ XtSetArg(arglist[i], XtNvertDistance, 10);
+ i++;
+ XtSetArg(arglist[i], XtNtop, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNbottom, XtChainTop);
+ i++;
+ XtSetArg(arglist[i], XtNleft, XtChainLeft);
+ i++;
+ XtSetArg(arglist[i], XtNright, XtChainLeft);
+ i++;
+ selFileLists[2] = XtCreateManagedWidget("selFileList3",
+ compositeWidgetClass, selFileForm,
+ arglist, i);
+
+ for (n = 0; n < 3; n++) {
+
+ i = 0;
+ XtSetArg(arglist[i], XtNx, vScrollX);
+ i++;
+ XtSetArg(arglist[i], XtNy, vScrollY);
+ i++;
+ XtSetArg(arglist[i], XtNwidth, scrollThickness);
+ i++;
+ XtSetArg(arglist[i], XtNheight, SFvScrollHeight);
+ i++;
+/* XtSetArg(arglist[i], XtNborderColor, SFfore); */
+/* i++; */
+ selFileVScrolls[n] = XtCreateManagedWidget("selFileVScroll",
+ scrollbarWidgetClass,
+ selFileLists[n], arglist, i);
+
+ XtAddCallback(selFileVScrolls[n], XtNjumpProc,
+ (XtCallbackProc)SFvFloatSliderMovedCallback, (XtPointer) n);
+ XtAddCallback(selFileVScrolls[n], XtNscrollProc,
+ (XtCallbackProc)SFvAreaSelectedCallback, (XtPointer) n);
+
+ i = 0;
+
+ XtSetArg(arglist[i], XtNorientation, XtorientHorizontal);
+ i++;
+ XtSetArg(arglist[i], XtNx, hScrollX);
+ i++;
+ XtSetArg(arglist[i], XtNy, hScrollY);
+ i++;
+ XtSetArg(arglist[i], XtNwidth, SFhScrollWidth);
+ i++;
+ XtSetArg(arglist[i], XtNheight, scrollThickness);
+ i++;
+/* XtSetArg(arglist[i], XtNborderColor, SFfore); */
+/* i++; */
+ selFileHScrolls[n] = XtCreateManagedWidget("selFileHScroll",
+ scrollbarWidgetClass,
+ selFileLists[n], arglist, i);
+
+ XtAddCallback(selFileHScrolls[n], XtNjumpProc,
+ (XtCallbackProc)SFhSliderMovedCallback, (XtPointer) n);
+ XtAddCallback(selFileHScrolls[n], XtNscrollProc,
+ (XtCallbackProc)SFhAreaSelectedCallback, (XtPointer) n);
+ }
+
+ /* Do the file filter stuff. */
+ selFileLabel = XtVaCreateManagedWidget("selFileLabel",
+ labelWidgetClass, selFileForm,
+ XtNfromVert, selFileLists[0],
+ XtNvertDistance, 30,
+/* XtNfromHoriz, selFileCancel, */
+/* XtNhorizDistance, 60, */
+ XtNlabel, "File Mask:",
+ XtNborderWidth, 0,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop, NULL);
+
+ selFileMask = XtVaCreateManagedWidget("selFileMask",
+ asciiTextWidgetClass, selFileForm,
+ XtNwidth, MASKWIDTH / 2 * SFcharWidth,
+ XtNfromVert, selFileLists[0],
+ XtNvertDistance, 30,
+ XtNfromHoriz, selFileLabel,
+ XtNhorizDistance, 0,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop,
+ XtNstring, fileMask,
+ XtNlength, MASKWIDTH,
+ XtNeditType, XawtextEdit,
+ XtNwrap, XawtextWrapNever,
+ XtNuseStringInPlace, True, NULL);
+
+ for (i = 0; i < 3; i++)
+ XtSetKeyboardFocus(selFileLists[i], selFileField);
+
+ XtOverrideTranslations(selFileMask,
+ XtParseTranslationTable
+ (oneLineTextEditTranslations));
+
+ XtAddEventHandler(selFileMask, KeyPressMask, False,
+ (XtEventHandler)maskChanged, (XtPointer) NULL);
+
+ selFileLabel = XtVaCreateManagedWidget("selFileLabel",
+ labelWidgetClass, selFileForm,
+ XtNfromVert, selFileLists[0],
+ XtNvertDistance, 30,
+ XtNfromHoriz, selFileMask,
+ XtNhorizDistance, 40,
+ XtNlabel, "Dot files are:",
+ XtNborderWidth, 0,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainTop, NULL);
+
+ selFileHide = XtVaCreateManagedWidget("selFileHide",
+ commandWidgetClass, selFileForm,
+/* XtNwidth, 7 * SFcharWidth, */
+ XtNfromVert, selFileLists[0],
+ XtNvertDistance, 30,
+ XtNfromHoriz, selFileLabel,
+ XtNhorizDistance, 2,
+ XtNlabel, hideFlag ? "hidden" : "shown",
+/* XtNborderWidth, 1, */
+ XtNtop, XtChainTop,
+/* XtNjustify, XtJustifyLeft, */
+ XtNbottom, XtChainTop,
+ NULL);
+ XtAddCallback(selFileHide, XtNcallback, (XtCallbackProc)hideFiles, NULL);
+
+ box = XtVaCreateManagedWidget("box", formWidgetClass,
+ paned,
+ XtNshowGrip, False,
+ XtNdefaultDistance, 6,
+ XtNskipAdjust, True,
+ XtNaccelerators, G_accels_cr,
+ NULL);
+ selFileOK = XtVaCreateManagedWidget("selFileOK", commandWidgetClass,
+ box,
+ XtNlabel, ok,
+ XtNcallback, SFokSelect,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainBottom,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ NULL);
+ selFileCancel = XtVaCreateManagedWidget("selFileCancel", commandWidgetClass,
+ box,
+ XtNlabel, cancel,
+ XtNcallback, SFcancelSelect,
+/* XtNborderColor, SFfore, */
+ XtNfromHoriz, selFileOK,
+ XtNbottom, XtChainBottom,
+ XtNleft, XtChainRight,
+ XtNright, XtChainRight,
+ NULL);
+
+ XtSetMappedWhenManaged(selFile, False);
+ XtRealizeWidget(selFile);
+
+ /* Add WM_DELETE_WINDOW protocol */
+ SFwmDeleteWindow = XInternAtom(SFdisplay, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(SFdisplay, XtWindow(selFile), &SFwmDeleteWindow, 1);
+
+ SFcreateGC();
+
+ xtermCursor = XCreateFontCursor(SFdisplay, XC_xterm);
+
+ sbRightArrowCursor = XCreateFontCursor(SFdisplay, XC_sb_right_arrow);
+ arrowCursor = XCreateFontCursor(SFdisplay, XC_left_ptr);
+
+ XDefineCursor(SFdisplay, XtWindow(selFileForm), arrowCursor);
+ XDefineCursor(SFdisplay, XtWindow(selFileField), xtermCursor);
+
+ for (n = 0; n < 3; n++) {
+ XDefineCursor(SFdisplay, XtWindow(selFileLists[n]), sbRightArrowCursor);
+ }
+ XDefineCursor(SFdisplay, XtWindow(selFileOK), arrowCursor);
+ XDefineCursor(SFdisplay, XtWindow(selFileCancel), arrowCursor);
+
+ for (n = 0; n < 3; n++) {
+ XtAddEventHandler(selFileLists[n], ExposureMask, True,
+ (XtEventHandler)SFexposeList, (XtPointer) n);
+ XtAddEventHandler(selFileLists[n], EnterWindowMask, False,
+ (XtEventHandler)SFenterList, (XtPointer) n);
+ XtAddEventHandler(selFileLists[n], LeaveWindowMask, False,
+ (XtEventHandler)SFleaveList, (XtPointer) n);
+ XtAddEventHandler(selFileLists[n], PointerMotionMask, False,
+ (XtEventHandler)SFmotionList, (XtPointer) n);
+ XtAddEventHandler(selFileLists[n], ButtonPressMask, False,
+ (XtEventHandler)SFbuttonPressList, (XtPointer) n);
+ XtAddEventHandler(selFileLists[n], ButtonReleaseMask, False,
+ (XtEventHandler)SFbuttonReleaseList, (XtPointer) n);
+ }
+
+ XtAddEventHandler(selFileField, KeyPressMask, False,
+ (XtEventHandler)SFmodVerifyCallback, (XtPointer) NULL);
+
+ SFapp = XtWidgetToApplicationContext(selFile);
+ return selFile;
+}
+
+/* position widget under the cursor */
+void
+SFpositionWidget(Widget w)
+{
+ Arg args[3];
+ Cardinal num_args;
+ Dimension width, height, b_width;
+ int x, y, max_x, max_y;
+ Window root, child;
+ int dummyx, dummyy;
+ unsigned int dummymask;
+
+ XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child, &x, &y,
+ &dummyx, &dummyy, &dummymask);
+ num_args = 0;
+ XtSetArg(args[num_args], XtNwidth, &width);
+ num_args++;
+ XtSetArg(args[num_args], XtNheight, &height);
+ num_args++;
+ XtSetArg(args[num_args], XtNborderWidth, &b_width);
+ num_args++;
+ XtGetValues(w, args, num_args);
+
+ width += 2 * b_width;
+ height += 2 * b_width;
+
+ x -= ((Position) width / 2);
+ if (x < 0)
+ x = 0;
+ if (x > (max_x = (Position) (XtScreen(w)->width - width)))
+ x = max_x;
+
+ y -= ((Position) height / 2);
+ if (y < 0)
+ y = 0;
+ if (y > (max_y = (Position) (XtScreen(w)->height - height)))
+ y = max_y;
+
+ num_args = 0;
+ XtSetArg(args[num_args], XtNx, x);
+ num_args++;
+ XtSetArg(args[num_args], XtNy, y);
+ num_args++;
+ XtSetValues(w, args, num_args);
+}
+
+
+FILE *
+SFopenFile(const char *name, const char *mode, const char *prompt, const char *failed)
+{
+ Arg args[1];
+ FILE *fp;
+
+ UNUSED(args);
+ UNUSED(prompt);
+ UNUSED(failed);
+
+ SFchdir(SFstartDir);
+ errno = 0;
+ if (!name || *name == 0 || (fp = XFOPEN(name, mode)) == NULL) {
+ XBell(DISP, 0);
+ return NULL;
+ }
+ return fp;
+}
+
+void
+SFtextChanged(void)
+{
+ if ((SFtextBuffer[0] == '/') || (SFtextBuffer[0] == '~')) {
+ (void)strcpy(SFcurrentPath, SFtextBuffer);
+
+ SFtextPos = XawTextGetInsertionPoint(selFileField);
+ }
+ else {
+ (void)strcat(strcpy(SFcurrentPath, SFstartDir), SFtextBuffer);
+
+ SFtextPos = XawTextGetInsertionPoint(selFileField) + strlen(SFstartDir);
+ }
+
+ if (!SFworkProcAdded) {
+ (void)XtAppAddWorkProc(SFapp, (XtWorkProc)SFworkProc, NULL);
+ SFworkProcAdded = 1;
+ }
+
+ SFupdatePath();
+}
+
+static void
+SFprepareToReturn(void)
+{
+ SFstatus = SEL_FILE_NULL;
+ /* XtRemoveGrab(selFile); */
+ XtUnmapWidget(selFile);
+
+ if (SFdirModTimerId) {
+ XtRemoveTimeOut(SFdirModTimerId);
+ SFdirModTimerId = 0;
+ }
+ if (SFchdir(SFstartDir)) {
+ XtAppError(SFapp, "XsraSelFile: can't return to current directory");
+ }
+}
+
+void
+XsraSelFile(Widget parent, struct filesel_callback *callback)
+/* const char *title, const char *prompt, */
+/* const char *ok, const char *cancel, */
+/* const char *init_path, */
+/* const char *mask, */
+/* Boolean must_exist, */
+/* Widget *ret_widget */
+{
+ static Boolean firstTime = True;
+ Widget w;
+ Cardinal i;
+ Arg arglist[20];
+ XEvent event;
+
+ if (!callback->prompt) {
+ callback->prompt = "Pathname:";
+ }
+
+ if (!callback->title) {
+ callback->title = "Xdvi: select filename";
+ }
+
+ if (!callback->ok) {
+ callback->ok = "OK";
+ }
+
+ if (!callback->cancel) {
+ callback->cancel = "Cancel";
+ }
+
+ if (firstTime) {
+ firstTime = False;
+ SFdisplay = XtDisplay(parent);
+ w = SFcreateWidgets(parent, callback->title, callback->prompt, callback->ok, callback->cancel);
+ }
+ else {
+ i = 0;
+ XtSetArg(arglist[i], XtNlabel, callback->prompt);
+ i++;
+ XtSetValues(selFilePrompt, arglist, i);
+
+ i = 0;
+ XtSetArg(arglist[i], XtNlabel, callback->ok);
+ i++;
+ XtSetValues(selFileOK, arglist, i);
+
+ i = 0;
+ XtSetArg(arglist[i], XtNlabel, callback->cancel);
+ i++;
+ XtSetValues(selFileCancel, arglist, i);
+ }
+
+ SFpositionWidget(selFile);
+ XtMapWidget(selFile);
+
+ {
+ char *cwd = xgetcwd();
+ strcpy(SFstartDir, cwd);
+ free(cwd);
+ }
+ if (SFstartDir[0] == 0) {
+ XtAppError(SFapp, "XsraSelFile: can't get current directory");
+ }
+ (void)strcat(SFstartDir, "/");
+ (void)strcpy(SFcurrentDir, SFstartDir);
+
+ if (callback->init_path) {
+ if (callback->init_path[0] == '/') {
+ (void)strcpy(SFcurrentPath, callback->init_path);
+ if (strncmp(SFcurrentPath, SFstartDir, strlen(SFstartDir))) {
+ SFsetText(SFcurrentPath);
+ }
+ else {
+ SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
+ }
+ }
+ else {
+ (void)strcat(strcpy(SFcurrentPath, SFstartDir), callback->init_path);
+ SFsetText(&(SFcurrentPath[strlen(SFstartDir)]));
+ }
+ }
+ else {
+ SFsetText(SFcurrentDir);
+ (void)strcpy(SFcurrentPath, SFstartDir);
+ }
+
+ SFfunc = showEntry;
+
+ SFtextChanged();
+
+ /* don't grab the pointer so that warning popups still work */
+ /* XtAddGrab(selFile, True, True); */
+
+ SFdirModTimerId = XtAppAddTimeOut(SFapp, 1200UL,
+ SFdirModTimer, (XtPointer) NULL);
+
+ if (strcmp(fileMask, callback->filemask) != 0) { /* if mask changed */
+ SFDir *dir;
+ strncpy(fileMask, callback->filemask, MASKWIDTH);
+ XtVaSetValues(selFileMask, XtNstring, fileMask, NULL);
+ for (dir = &(SFdirs[SFdirEnd - 1]); dir >= SFdirs; dir--)
+ *(dir->dir) = 0; /* force a re-read */
+ SFupdatePath();
+ }
+
+ while (1) {
+ XtAppNextEvent(SFapp, &event);
+ switch (event.type) {
+ Widget w;
+#if 0 /* don't do this, it may send the X server into a busy loop if the File selector
+ is positioned over a window that is `on top' by default */
+ case Expose:
+ if (!raise_message_windows())
+ raise_file_selector();
+ break;
+#endif
+ case KeyPress:
+ case ButtonPress:
+ /* beep if keypress was inside main window */
+ w = XtWindowToWidget(DISP, event.xany.window);
+ while ((w != NULL) && (w != selFile)) {
+ /* exception: message windows */
+ if (is_message_window(w))
+ break;
+ w = XtParent(w);
+ }
+ if (w == NULL || w == globals.widgets.top_level) {
+ XBell(DISP, 0);
+ }
+ break;
+ }
+
+ XtDispatchEvent(&event);
+
+ switch (SFstatus) {
+ case SEL_FILE_TEXT:
+ SFstatus = SEL_FILE_NULL;
+ SFtextChanged();
+ break;
+ case SEL_FILE_OK:
+ if (callback->must_exist) {
+ FILE *tmp_fp = XFOPEN(SFtextBuffer, "r");
+ dviErrFlagT errflag = NO_ERROR;
+ if (tmp_fp == NULL) {
+ popup_message(selFile,
+ MSG_ERR, NULL, "Could not open %s: %s.\n",
+ SFtextBuffer, strerror(errno));
+ SFstatus = SEL_FILE_NULL;
+ break;
+ }
+ else if (!process_preamble(tmp_fp, &errflag)
+ || !find_postamble(tmp_fp, &errflag)
+ || !read_postamble(tmp_fp, &errflag, False)) {
+ popup_message(selFile,
+ MSG_ERR, NULL, "Error opening %s:\n%s.",
+ SFtextBuffer, get_dvi_error(errflag));
+ fclose(tmp_fp);
+ SFstatus = SEL_FILE_NULL;
+ break;
+ }
+ else { /* file is OK */
+ fclose(tmp_fp);
+ SFprepareToReturn();
+ callback->func_ptr(SFtextBuffer, callback->data);
+ return;
+/* return xstrdup(SFtextBuffer); */
+ }
+ }
+ else {
+ SFprepareToReturn();
+ callback->func_ptr(SFtextBuffer, callback->data);
+ return;
+/* return xstrdup(SFtextBuffer); */
+ }
+ case SEL_FILE_CANCEL:
+ SFprepareToReturn();
+ if (callback->exit_on_cancel)
+ exit(0);
+ return;
+/* return NULL; */
+ case SEL_FILE_NULL:
+ break;
+ }
+ }
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* !defined(MOTIF) */
diff --git a/Build/source/texk/xdvik/gui/sfSelFile.h b/Build/source/texk/xdvik/gui/sfSelFile.h
new file mode 100644
index 00000000000..298d15ea45a
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfSelFile.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef SFSELFILE_H_
+#define SFSELFILE_H_
+
+struct filesel_callback {
+ const char *title;
+ const char *prompt;
+ const char *ok;
+ const char *cancel;
+ const char *init_path;
+ const char *filemask;
+ Boolean must_exist;
+ Boolean exit_on_cancel;
+ void (*func_ptr)(const char *filename, void *data);
+ void *data;
+};
+
+extern void SFpositionWidget(Widget w);
+extern FILE *SFopenFile(const char *name, const char *mode, const char *prompt, const char *failed);
+extern void SFtextChanged(void);
+extern void XsraSelFile(Widget parent, struct filesel_callback *callback);
+void raise_file_selector(void);
+
+#endif /* SF_SEL_FILE_H_ */
diff --git a/Build/source/texk/xdvik/gui/sfinternal.h b/Build/source/texk/xdvik/gui/sfinternal.h
new file mode 100644
index 00000000000..c776bfc6c97
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/sfinternal.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 1989 Software Research Associates, Inc., Tokyo, Japan
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Software Research Associates not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. Software Research Associates
+ * makes no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * SOFTWARE RESEARCH ASSOCIATES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL SOFTWARE RESEARCH ASSOCIATES BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Erik M. van der Poel
+ * Software Research Associates, Inc., Tokyo, Japan
+ * erik@sra.co.jp
+ */
+
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+#undef wchar_t
+
+#define SEL_FILE_CANCEL -1
+#define SEL_FILE_OK 0
+#define SEL_FILE_NULL 1
+#define SEL_FILE_TEXT 2
+
+#define SF_DO_SCROLL 1
+#define SF_DO_NOT_SCROLL 0
+
+
+extern void
+ SFenterList(),
+ SFleaveList(),
+ SFmotionList(),
+ SFbuttonPressList(),
+ SFbuttonReleaseList();
+
+extern void
+ SFvSliderMovedCallback(),
+ SFvFloatSliderMovedCallback(),
+ SFhSliderMovedCallback(),
+ SFpathSliderMovedCallback(),
+ SFvAreaSelectedCallback(),
+ SFhAreaSelectedCallback(),
+ SFpathAreaSelectedCallback();
+
+
diff --git a/Build/source/texk/xdvik/gui/statusline.c b/Build/source/texk/xdvik/gui/statusline.c
new file mode 100644
index 00000000000..16715283cf4
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/statusline.c
@@ -0,0 +1,531 @@
+/*------------------------------------------------------------
+ statusline for the xdvi(k) previewer
+
+ written by S. Ulrich (ulrich@cis.uni-muenchen.de) 2000/02/25
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to
+ deal in the Software without restriction, including without limitation the
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ sell copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ ------------------------------------------------------------*/
+
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "version.h"
+#include "statusline.h"
+#include "xm_menu.h"
+#include "x_util.h"
+#include "pagehist.h"
+#include "util.h"
+
+#include "kpathsea/c-vararg.h"
+#include "my-vsnprintf.h"
+
+#include <ctype.h>
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+
+# ifdef MOTIF
+# include <Xm/Label.h>
+# include <Xm/Frame.h>
+# include <Xm/Text.h>
+# include <Xm/TextF.h>
+# else
+# include <X11/Xaw/Viewport.h>
+# include <X11/Xaw/Label.h>
+# endif
+
+
+Widget statusline;
+
+static Boolean initialized = False;
+
+/*
+ * only print MAX_LEN characters to the statusline
+ * (it's only 1 line after all)
+ */
+#define MAX_LEN 512
+
+/* for saving the statusline string if the statusline is
+ * destroyed and recreated
+ */
+static char g_string_savebuf[MAX_LEN + 2];
+
+int global_statusline_h = 20;
+
+#if MOTIF
+static void
+handle_statusline_event(Widget w, XtPointer client_data,
+ XEvent *ev, Boolean *cont)
+{
+/* const char *text = (const char *)client_data; */
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(cont);
+
+/* fprintf(stderr, "text: |%s|; event: %p\n", text, ev); */
+ /* only used to do this if page history was already active, but it's probably
+ nicer to be able to get the history by clicking on the statusline ...
+ */
+ if (/* strncmp(text, "Page history:", sizeof "Page history:" - 1) == 0 && */ ev != NULL) {
+ XmTextPosition pos = XmTextGetCursorPosition(statusline);
+ char *ptr1, *ptr2;
+ int diff = 0;
+/* fprintf(stderr, "pos: %d\n", pos); */
+ if (pos == 0) { /* just display the page history */
+ page_history_move(0);
+ return;
+ }
+ ptr1 = g_string_savebuf + pos;
+ ptr2 = strchr(g_string_savebuf, '[');
+ if (ptr2 == NULL) { /* some other string, also display the page history */
+ page_history_move(0);
+ return;
+ }
+/* fprintf(stderr, "ptr1: |%s|; ptr2: |%s|\n", ptr1, ptr2); */
+ while (ptr1 < ptr2) {
+ if (*ptr1 == ' ' && *(ptr1 + 1) != '-') /* separator */
+ diff--;
+ ptr1++;
+ }
+
+ while (ptr1 > ptr2) {
+ if (*ptr1 == ' ' && *(ptr1 - 1) != '-') /* separator */
+ diff++;
+ ptr1--;
+ }
+/* fprintf(stderr, "diff: %d\n", diff); */
+ page_history_move(diff);
+ }
+}
+#endif /* MOTIF */
+
+/*
+ * Create the statusline widget. To be called at the beginning
+ * of the program, and when expert mode is switched off.
+ *
+ * Side effects:
+ * sets <global_statusline_h> to the height of the statusline in pixels.
+ */
+
+Widget
+create_statusline(
+#ifdef MOTIF
+ Widget parent
+#else
+ void
+#endif
+ )
+{
+#ifndef MOTIF
+ Position vport_h;
+ Position clip_x;
+ Position clip_w;
+ static Position my_h = 0;
+#endif
+
+ /*
+ * FIXME: is there a better way to set the y position depending on
+ * the height of the widget?
+ * It doesn't work to change the value of XtNy *after* creating
+ * the widget!
+ */
+
+ if (!initialized) {
+#ifndef MOTIF
+ /*
+ * determine height of statusline (depending on the font used).
+ * This is not changeable at runtime, so it's determined once and
+ * for all at program start.
+ */
+ statusline = XtVaCreateWidget("statusline", labelWidgetClass, globals.widgets.vport_widget,
+ XtNlabel, (XtArgVal) "test",
+ NULL);
+ XtVaGetValues(statusline, XtNheight, &my_h, NULL);
+ global_statusline_h = my_h;
+ XtDestroyWidget(statusline);
+#endif
+ initialized = True;
+ /* initialize g_string_savebuf */
+ sprintf(g_string_savebuf, "This is xdvik %s", XDVI_TERSE_VERSION_INFO);
+ }
+#ifndef MOTIF
+ /* determine position and width of statusline */
+ XtVaGetValues(globals.widgets.clip_widget, XtNx, &clip_x, XtNwidth, &clip_w, NULL);
+ XtVaGetValues(globals.widgets.vport_widget, XtNheight, &vport_h, NULL);
+ if (vport_h - my_h <= 0) {
+ XDVI_FATAL((stderr, "Window height too small for statusline (minimum value: %d).", my_h));
+ return NULL;
+ }
+ statusline = XtVaCreateManagedWidget("statusline",
+ labelWidgetClass, globals.widgets.vport_widget,
+ XtNlabel, (XtArgVal) g_string_savebuf,
+ XtNwidth, clip_w,
+ XtNx, clip_x - 1, /* so that left border becomes invisible */
+ XtNy, vport_h - my_h,
+ XtNjustify, XtJustifyLeft,
+ /* same as for the buttons line */
+ XtNborder, (XtArgVal) resource.fore_Pixel,
+ NULL);
+#else
+ statusline = XtVaCreateManagedWidget("statusline",
+ xmTextFieldWidgetClass, parent,
+ XmNalignment, XmALIGNMENT_END,
+ XmNdepth, (XtArgVal) G_depth,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftOffset, 1,
+ XmNrightOffset, 1,
+ XmNbottomOffset, 1,
+ XmNtopOffset, 0,
+ XmNcursorPositionVisible, False,
+ XmNautoShowCursorPosition, False,
+ XmNmarginWidth, 4,
+ XmNmarginHeight, 1,
+ XmNeditable, False,
+ XmNtraversalOn, False,
+ XmNvalue, g_string_savebuf,
+ NULL);
+
+ /* Block processing of most interactive events on this widget, except
+ * for button events that should navigate the page history.
+ */
+ XtInsertEventHandler(statusline,
+ KeyPressMask | KeyReleaseMask |
+ PointerMotionMask| PointerMotionHintMask |
+ ButtonMotionMask |
+#if !MOTIF
+ ButtonPressMask | ButtonReleaseMask |
+#endif
+ FocusChangeMask,
+ /* ButtonPressMask | ButtonReleaseMask | */
+ /* PointerMotionMask| PointerMotionHintMask | */
+ /* ButtonMotionMask | */
+ True, block_event_callback,
+ (XtPointer)0, 0);
+#if MOTIF
+ XtInsertEventHandler(statusline,
+ /* suboptimal, but needs to be release not press
+ * since we want to query the current cursor position,
+ * and that may not be set yet in the press event(?).
+ */
+ ButtonReleaseMask,
+ True, handle_statusline_event,
+ (XtPointer)g_string_savebuf, XtListTail);
+
+#endif /* MOTIF */
+
+#endif
+
+ return statusline;
+}
+
+
+void
+toggle_statusline(void)
+{
+#ifdef MOTIF
+ if ((resource.expert_mode & XPRT_SHOW_STATUSLINE) == 0)
+ XtUnmanageChild(statusline);
+ else
+ XtManageChild(statusline);
+
+#if defined(NEW_MENU_CREATION) || defined(MOTIF)
+ set_menu(&resource.expert_mode, Act_set_expert_mode, check_resource_expert);
+#else
+ set_show_statusline_option();
+#endif
+#else
+ static Boolean initialized = False;
+ static Boolean statusline_mapped = False;
+
+ Boolean make_statusline_visible = False;
+ Boolean make_statusline_invisible = False;
+
+ if (!initialized) {
+ statusline_mapped = (resource.expert_mode & XPRT_SHOW_STATUSLINE) != 0;
+ initialized = True;
+ }
+
+ if ((resource.expert_mode & XPRT_SHOW_STATUSLINE) == 0) {
+ if (statusline_mapped)
+ make_statusline_invisible = True;
+ }
+ else {
+ if (!statusline_mapped)
+ make_statusline_visible = True;
+ }
+
+ if (make_statusline_invisible) {
+ XtDestroyWidget(statusline);
+ statusline_mapped = False;
+ }
+ if (make_statusline_visible) {
+ static Dimension window_w, window_h;
+
+ static Arg arg_wh[] = {
+ {XtNwidth, (XtArgVal) &window_w},
+ {XtNheight, (XtArgVal) &window_h},
+ };
+#ifdef MOTIF
+ XtGetValues(globals.widgets.main_window, arg_wh, XtNumber(arg_wh));
+#else
+ XtGetValues(globals.widgets.vport_widget, arg_wh, XtNumber(arg_wh));
+#endif
+ XtVaSetValues(globals.widgets.vport_widget, XtNresizable, (XtArgVal)True, NULL);
+ TRACE_GUI((stderr, "statusline: w %d, h %d", window_w, window_h));
+ XtVaSetValues(globals.widgets.vport_widget, XtNwidth, (XtArgVal)window_w, XtNheight, (XtArgVal)window_h, NULL);
+ TRACE_GUI((stderr, "after statusline"));
+ create_statusline();
+ statusline_mapped = True;
+ }
+#endif /* MOTIF */
+}
+
+
+/*------------------------------------------------------------
+ * handle_statusline_resize
+ *
+ * Arguments:
+ * void
+ *
+ * Returns:
+ * void
+ *
+ * Purpose:
+ * Resize the statusline when the total window size changes.
+ *
+ *------------------------------------------------------------*/
+
+void
+handle_statusline_resize(void)
+{
+#ifndef MOTIF
+ if ((resource.expert_mode & XPRT_SHOW_STATUSLINE) == 0) {
+ return;
+ }
+
+ if (!statusline)
+ return;
+
+ /* apparently the x,y values of a widget can only be set at creation time, so
+ * the following won't work:
+ */
+
+#if 0
+ /*
+ BROKEN Position vport_h, clip_x, clip_w;
+ BROKEN static Position my_h = 0;
+ BROKEN
+ BROKEN XtVaGetValues(globals.widgets.clip_widget,
+ BROKEN XtNx, &clip_x,
+ BROKEN XtNwidth, &clip_w,
+ BROKEN NULL);
+ BROKEN XtVaGetValues(globals.widgets.vport_widget,
+ BROKEN XtNheight, &vport_h,
+ BROKEN NULL);
+ BROKEN
+ BROKEN XtUnmanageChild(statusline);
+ BROKEN XtVaSetValues(statusline,
+ BROKEN XtNlabel, (XtArgVal) "",
+ BROKEN XtNwidth, clip_w,
+ BROKEN XtNx, clip_x - 1,
+ BROKEN XtNy, vport_h - my_h,
+ BROKEN XtNborderWidth, 1,
+ BROKEN XtNjustify, XtJustifyLeft,
+ BROKEN XtNborder, (XtArgVal) resource.fore_Pixel,
+ BROKEN NULL);
+ BROKEN XtManageChild(statusline);
+ BROKEN XFlush(DISP);
+ */
+#endif
+
+ /* only this will: */
+ XtDestroyWidget(statusline);
+ create_statusline();
+#endif
+}
+
+
+
+
+/*
+ * clear statusline by printing an empty message to it.
+ */
+
+
+static void
+clear_statusline(void)
+{
+ if ((resource.expert_mode & XPRT_SHOW_STATUSLINE) != 0) {
+# ifdef MOTIF
+ XmTextFieldSetString(statusline, " ");
+# else
+ XtVaSetValues(statusline, XtNlabel, " ", NULL);
+# endif
+ XFlush(DISP);
+ }
+ strcpy(g_string_savebuf, " ");
+}
+
+
+/* force a statusline update, no matter how busy the application is.
+ Use this with care (only for important messages).
+*/
+void
+force_statusline_update(void)
+{
+#ifdef MOTIF
+ XmUpdateDisplay(globals.widgets.top_level);
+#else
+ XEvent event;
+ XSync(DISP, False);
+ while (XCheckMaskEvent(DISP, ExposureMask, &event))
+ XtDispatchEvent(&event);
+#endif /* MOTIF */
+}
+
+
+/*
+ * timeout - if > 0, timeout in seconds after which the message will
+ * be deleted again. If < 0, message will remain (until
+ * another message overprints it)
+ * fmt - message, a C format string
+ *
+ * If expert mode is off, print <fmt> to the statusline; else, print
+ * <fmt> to stdout, unless the `hushstdout' option is specified.
+ */
+static XtIntervalId clear_timeout_id = 0;
+
+static void
+clear_statusline_timer_proc(XtPointer client_data, XtIntervalId *id)
+{
+ UNUSED(client_data);
+ UNUSED(id);
+
+ if (clear_timeout_id) {
+ clear_statusline();
+ clear_timeout_id = 0;
+ }
+}
+
+static void
+internal_print_statusline(statusTimerT timeout, const char *old_content, const char *fmt, va_list argp)
+{
+ if (!XtIsRealized(globals.widgets.top_level) || !initialized || (resource.expert_mode & XPRT_SHOW_STATUSLINE) == 0) {
+ if (!resource.hush_stdout && strlen(fmt) > 0) { /* check for strlen since sometimes we clear the statusline
+ by printing "" to it, and we don't want that on stdout */
+ fprintf(stdout, "xdvi: ");
+ if (old_content != NULL)
+ (void)fputs(old_content, stdout);
+ (void)vfprintf(stdout, fmt, argp);
+ fputc('\n', stdout);
+ fflush(stdout);
+ }
+ }
+ else {
+ char buf[MAX_LEN + 1];
+ size_t offset = 0;
+
+ if (old_content != NULL && old_content[0] != '\0') {
+ offset += strlen(old_content);
+ strncpy(buf, old_content, MAX_LEN);
+ /* append separating space */
+ if (strlen(old_content) < MAX_LEN - 1) {
+ strcat(buf, " ");
+ offset++;
+ }
+ }
+ VSNPRINTF(buf + offset, MAX_LEN - offset, fmt, argp); /* just throw away strings longer than MAX_LEN */
+ buf[MAX_LEN] = '\0'; /* terminate buf */
+ /*
+ * save current contents of statusline so that toggling the statusline
+ * on and off will display the same text again
+ */
+ strcpy(g_string_savebuf, buf);
+#ifdef MOTIF
+ XmTextFieldSetString(statusline, buf);
+#else
+ XtVaSetValues(statusline, XtNlabel, buf, NULL);
+#endif
+/* fprintf(stderr, "timeout: %d, id: %ld\n", timeout, clear_timeout_id); */
+ if (timeout > 0) {
+ timeout *= 1000; /* convert to miliseconds */
+
+ if (clear_timeout_id) {
+/* fprintf(stderr, "clearing!\n"); */
+ if (globals.debug & DBG_EVENT)
+ fprintf(stderr, "%s:%d: removing timeout %ld\n", __FILE__, __LINE__, clear_timeout_id);
+ XtRemoveTimeOut(clear_timeout_id);
+ }
+ clear_timeout_id = XtAppAddTimeOut(app, timeout,
+ clear_statusline_timer_proc, (XtPointer) NULL);
+ }
+ }
+}
+
+/*
+ * Append the varargs-string `fmt' to the currnent contents of the statusline
+ * erasing it after `timeout' seconds if timeout > 0, unless the current statusline
+ * contents matches pattern - in that case, overwrite the contents.
+ */
+void
+statusline_append(statusTimerT timeout, const char *pattern, const char *fmt, ...)
+{
+ const char *buf = NULL;
+ va_list argp;
+
+ if (XtIsRealized(globals.widgets.top_level) && initialized && (resource.expert_mode & XPRT_SHOW_STATUSLINE) != 0) {
+ /* get current statusline contents */
+#ifdef MOTIF
+ XtVaGetValues(statusline, XmNvalue, &buf, NULL);
+#else
+ XtVaGetValues(statusline, XtNlabel, &buf, NULL);
+#endif
+ }
+
+ while (buf != NULL && isspace((int)*buf)) /* skip spaces inserted by statusline appending */
+ buf++;
+ va_start(argp, fmt);
+
+ if (buf != NULL && memcmp(buf, pattern, strlen(pattern)) == 0) {
+ buf = NULL;
+ }
+ internal_print_statusline(timeout, buf, fmt, argp);
+ va_end(argp);
+}
+
+/*
+ * Print the varargs-string `fmt' to the currnent contents of the statusline,
+ * erasing it after `timeout' seconds if timeout > 0.
+ */
+
+void
+statusline_print(statusTimerT timeout, const char *fmt, ...)
+{
+ va_list argp;
+ va_start(argp, fmt);
+ internal_print_statusline(timeout, NULL, fmt, argp);
+ va_end(argp);
+}
+
+void
+statusline_clear(void)
+{
+ statusline_print(STATUS_SHORT, "");
+}
diff --git a/Build/source/texk/xdvik/gui/statusline.h b/Build/source/texk/xdvik/gui/statusline.h
new file mode 100644
index 00000000000..5f9f5dcd10c
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/statusline.h
@@ -0,0 +1,52 @@
+#ifndef STATUSLINE_H_
+#define STATUSLINE_H_
+/*
+ * Copyright (c) 2001-2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#define STAT_BUF_LEN 512
+
+
+/* statusline stuff. The following function and #defines are also
+ * needed when compiling without statusline support.
+ */
+typedef enum statusTimerT_ {
+ STATUS_FOREVER = 0,
+ STATUS_SHORT = 5,
+ STATUS_MEDIUM = 10,
+ STATUS_LONG = 30
+} statusTimerT;
+
+extern void statusline_clear(void);
+extern void statusline_print(statusTimerT timeout, const char *fmt, ...);
+extern void statusline_append(statusTimerT timeout, const char *pattern, const char *fmt, ...);
+#ifdef MOTIF
+extern Widget create_statusline(Widget parent);
+#else
+extern Widget create_statusline(void);
+#endif
+extern void handle_statusline_resize(void);
+
+extern void force_statusline_update(void);
+extern void toggle_statusline(void);
+
+#endif /* STATUSLINE_H_ */
diff --git a/Build/source/texk/xdvik/gui/topic-window.c b/Build/source/texk/xdvik/gui/topic-window.c
new file mode 100644
index 00000000000..7a87a03b5c8
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/topic-window.c
@@ -0,0 +1,650 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * `Topics' window framework used by help and preferences windows.
+ * Contains a list of topics on the left-hand side, and corresponding
+ * contents on the right-hand side.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#if MOTIF
+# include <Xm/Xm.h>
+# include <Xm/Form.h>
+# include <Xm/DialogS.h>
+# include <Xm/PushB.h>
+# include <Xm/Frame.h>
+# include <Xm/PanedW.h>
+# include <Xm/LabelG.h>
+# include <Xm/Label.h>
+# include <Xm/Protocols.h>
+# include <Xm/List.h>
+# include <Xm/AtomMgr.h>
+#else /* MOTIF */
+# include <X11/Xaw/Paned.h>
+# include <X11/Xaw/Box.h>
+# include <X11/Xaw/Form.h>
+# include <X11/Xaw/Cardinals.h>
+# include <X11/Xaw/Command.h>
+# include <X11/Xaw/List.h>
+#endif /* MOTIF */
+
+#include "version.h"
+#include "topic-window.h"
+#include "string-utils.h"
+#include "util.h"
+#include "x_util.h"
+
+#if MOTIF
+
+/* special formatting for headings in right window, if desired */
+const char *const TAG_NORMAL = "NORMAL";
+const char *const TAG_TOPIC_HEADING = "TOPIC_HEADING";
+const char *const TAG_TOPIC_LABEL = "TOPIC_LABEL";
+
+# define SHELL_WIDGET_CLASS xmDialogShellWidgetClass
+# define PANED_WIDGET_CLASS xmPanedWindowWidgetClass
+# define FORM_WIDGET_CLASS xmFormWidgetClass
+
+# define FORM_ARGS XmNhorizontalSpacing, 10, \
+ NULL
+# define HELP_SHELL_ARGS XmNdeleteResponse, XmDO_NOTHING, \
+ XtNmappedWhenManaged, False, \
+ NULL
+# define HELP_PANED_ARGS XmNsashWidth, 1, \
+ XmNuserData, info, \
+ XmNsashHeight, 1, \
+ NULL
+# define LEFT_FORM_ARGS XmNtopAttachment, XmATTACH_FORM, \
+ XmNleftAttachment, XmATTACH_FORM, \
+ XmNbottomAttachment, XmATTACH_FORM, \
+ XmNtopOffset, 9, \
+ XmNbottomOffset, 10, \
+ NULL
+# define RIGHT_FORM_ARGS XmNtopAttachment, XmATTACH_FORM, \
+ XmNleftAttachment, XmATTACH_WIDGET, \
+ XmNleftWidget, left_form, \
+ XmNrightAttachment, XmATTACH_FORM, \
+ XmNbottomAttachment, XmATTACH_FORM, \
+ XmNbottomOffset, 10, \
+ NULL
+# define ACTION_AREA_ARGS NULL
+
+#else /* MOTIF */
+
+# define SHELL_WIDGET_CLASS transientShellWidgetClass
+# define PANED_WIDGET_CLASS panedWidgetClass
+# define FORM_WIDGET_CLASS formWidgetClass
+
+# define FORM_ARGS XtNdefaultDistance, 14, \
+ NULL
+# define HELP_SHELL_ARGS XtNx, 60, \
+ XtNy, 80, \
+ XtNtransientFor, globals.widgets.top_level, \
+ XtNtranslations, xlats, \
+ XtNtransientFor, parent, \
+ XtNallowShellResize, False, \
+ NULL
+# define HELP_PANED_ARGS NULL
+# define LEFT_FORM_ARGS XtNtop, XtChainTop, \
+ XtNbottom, XtChainBottom, \
+ XtNleft, XtChainLeft, \
+ XtNright, XtChainLeft, \
+ XtNborderWidth, 0, \
+ NULL
+# define RIGHT_FORM_ARGS XtNfromHoriz, left_form, \
+ XtNtop, XtChainTop, \
+ XtNbottom, XtChainBottom, \
+ XtNleft, XtChainLeft, \
+ XtNright, XtChainRight, \
+ XtNborderWidth, 0, \
+ NULL
+# define ACTION_AREA_ARGS XtNdefaultDistance, 6, \
+ XtNshowGrip, False, \
+ XtNskipAdjust, True, \
+ NULL
+#endif /* MOTIF */
+
+
+static void
+ok_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+
+ UNUSED(w);
+ UNUSED(call_data);
+
+ ASSERT(info != NULL, "No info passed to callback!");
+
+ if (info->ok_callback != NULL)
+ info->ok_callback(info);
+ XtPopdown(info->shell);
+}
+
+static void
+cancel_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+
+ UNUSED(w);
+ UNUSED(call_data);
+
+ ASSERT(info != NULL, "No info passed to callback!");
+
+ if (info->cancel_callback != NULL)
+ info->cancel_callback(info);
+ XtPopdown(info->shell);
+}
+
+#if MOTIF
+/*
+ * We are overriding this since otherwise the Text widget would attempt to
+ * first move the invisible cursor instead of the scroll bars.
+ */
+/* FIXME: This gives a warning:
+ Warning: Actions not found: scroll-one-line-down, scroll-one-line-up
+*/
+/* "<Key>osfUp: scroll-one-line-down()\n" */
+/* "<Key>osfDown: scroll-one-line-up()\n" */
+#endif
+
+#if MOTIF
+static XmString
+#else
+static char *
+#endif
+create_label_string(const char *title, const char *subtitle)
+{
+#if MOTIF
+ XmString label;
+ if (subtitle == NULL) { /* simple bold label */
+ label = XmStringCreate((char *)title, (char *)TAG_TOPIC_LABEL);
+ }
+ else { /* two-part title with subheading */
+ XmString s1, s2, s3, s4;
+ s1 = XmStringCreate((char *)title, (char *)TAG_TOPIC_HEADING);
+ s2 = XmStringCreate((char *)" ", (char *)TAG_NORMAL);
+ s3 = XmStringCreate((char *)subtitle, (char *)TAG_NORMAL);
+ s4 = XmStringConcat(s1, s2);
+ label = XmStringConcat(s4, s3);
+ XmStringFree(s1);
+ XmStringFree(s2);
+ XmStringFree(s3);
+ XmStringFree(s4);
+ }
+#else
+ char *label = xstrdup(title);
+ if (subtitle != NULL && strlen(subtitle) > 0) {
+ label = xstrcat(label, " - ");
+ label = xstrcat(label, subtitle);
+ }
+#endif
+ return label;
+}
+
+static Widget
+create_label_widget(Widget parent, const char *name, struct topic_info *info)
+{
+ Widget label;
+
+#if MOTIF
+
+ XmString label_string = create_label_string(info->items[0].topic, info->items[0].title);
+ label = XtVaCreateWidget(name, xmLabelWidgetClass, parent,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNtopOffset, 14,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNlabelString, label_string,
+ XmNalignment, XmALIGNMENT_BEGINNING,
+ NULL);
+ XmStringFree(label_string);
+
+#else /* MOTIF */
+
+ char *label_string = create_label_string(info->items[0].topic, info->items[0].title);
+ label = XtVaCreateWidget(name, labelWidgetClass, parent,
+ XtNlabel, label_string,
+ XtNborderWidth, 0,
+ /* XtNinternalHeight, 2, */
+ XtNjustify, XtJustifyLeft,
+ NULL);
+ free(label_string);
+
+#endif /* MOTIF */
+
+ return label;
+}
+
+void
+select_topic(struct topic_info *info, size_t idx)
+{
+#if MOTIF
+ XmString label;
+#else
+ char *label;
+#endif
+
+ /* change the heading in right window */
+ label = create_label_string(info->items[idx].topic, info->items[idx].title);
+ XtVaSetValues(info->topic_label,
+#if MOTIF
+ XmNlabelString,
+#else
+ XtNlabel,
+#endif
+ label, NULL);
+
+#if MOTIF
+ XmStringFree(label);
+ XmListSelectPos(info->topics_list, idx + 1, False);
+#else
+ free(label);
+ XawListHighlight(info->topics_list, idx);
+#endif
+
+ if (info->curr_selected != 0) {
+ XtUnmanageChild(info->curr_selected);
+ }
+ else {
+ /* Note: doesn't matter if not managed yet */
+/* XtUnmanageChild(info->items[0].widget); */
+ }
+
+ XtManageChild(info->items[idx].widget);
+ info->curr_selected = info->items[idx].widget;
+
+#if MOTIF
+ XmUpdateDisplay(info->shell);
+#endif
+}
+
+static void
+select_topic_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ size_t idx;
+
+#if MOTIF
+ idx = ((XmListCallbackStruct *)call_data)->item_position - 1;
+#else
+ idx = ((XawListReturnStruct *)call_data)->list_index;
+#endif
+ UNUSED(w);
+
+ /* ASSERT(idx < info->items_size, "list position exceeds items_size!"); */
+
+ select_topic(info, idx);
+}
+
+static Widget
+create_button(Widget parent, const char *name, Boolean show_as_default, Boolean left_position)
+{
+ Widget button;
+#if MOTIF
+ XmString s1 = XmStringCreateLocalized((char *)name);
+ button = XtVaCreateWidget(name, xmPushButtonWidgetClass, parent,
+ XmNlabelString, s1,
+ XmNdefaultButtonShadowThickness, 1,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNmarginWidth, 6,
+ XmNmarginHeight, 4,
+ XmNtopOffset, 10,
+ XmNbottomOffset, 10,
+ NULL);
+ if (left_position)
+ XtVaSetValues(button,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 10,
+ NULL);
+ else
+ XtVaSetValues(button,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNrightOffset, 10,
+ NULL);
+ if (show_as_default)
+ XtVaSetValues(button, XmNshowAsDefault, True, NULL);
+
+ XtManageChild(button);
+ XmStringFree(s1);
+#else /* MOTIF */
+ UNUSED(show_as_default);
+ button = XtVaCreateManagedWidget(name, commandWidgetClass, parent,
+ XtNtop, XtChainTop,
+ XtNbottom, XtChainBottom,
+ NULL);
+ if (left_position)
+ XtVaSetValues(button,
+ XtNleft, XtChainLeft,
+ XtNright, XtChainLeft,
+ NULL);
+ else
+ XtVaSetValues(button,
+ XtNleft, XtChainRight,
+ XtNright, XtChainRight,
+ NULL);
+#endif /* MOTIF */
+ return button;
+}
+
+static void
+close_topic_window(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ Widget button;
+ void *ptr;
+ struct topic_info *info;
+
+ UNUSED(w);
+ UNUSED(event);
+
+ if (*num_params < 1) {
+ XDVI_WARNING((stderr, "Wrong argument number (%d) in callback!", *num_params));
+ return;
+ }
+
+ sscanf(*params, "%p", &ptr);
+ info = (struct topic_info *)ptr;
+
+ /* get a callback to close the button, in decreasing order of preference */
+ if (get_widget_by_name(&button, info->shell, "Cancel", False)
+ || get_widget_by_name(&button, info->shell, "Close", False)
+ || get_widget_by_name(&button, info->shell, "OK", False)) {
+ XtCallCallbacks(button,
+#if MOTIF
+ XmNactivateCallback,
+#else
+ XtNcallback,
+#endif
+ info);
+ }
+ else {
+ XDVI_WARNING((stderr, "No button found for widget %p!\n", (void *)info->shell));
+ }
+}
+
+static XtActionsRec popdown_actions[] = {
+#if !MOTIF
+ { "WM_popdown", close_topic_window },
+#endif
+ { "close-topic-window", close_topic_window },
+};
+
+static Widget
+create_list_widget(Widget parent, const char *w_name, struct topic_info *info)
+{
+ Widget list;
+ size_t tnum;
+#if MOTIF
+ XmString *topics = NULL;
+#else
+ static char **topics = NULL;
+#endif
+
+ for (tnum = 0; info->items[tnum].topic != NULL; tnum++) {
+ /* 1 more for terminating NULL needed for Xaw */
+ topics = xrealloc(topics, (tnum + 2) * sizeof *topics);
+#if MOTIF
+ topics[tnum] = XmStringCreateLocalized(info->items[tnum].topic);
+#else
+ topics[tnum] = xstrdup(info->items[tnum].topic);
+#endif
+ }
+
+#ifndef MOTIF
+ /* list needs to be terminated for Xaw */
+ topics[tnum] = NULL;
+#endif
+
+#if MOTIF
+ {
+ size_t i;
+ Arg args[20];
+ int n = 0;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNlistSpacing, 4); n++;
+ XtSetArg(args[n], XmNlistMarginHeight, 4); n++;
+ XtSetArg(args[n], XmNlistMarginWidth, 4); n++;
+ XtSetArg(args[n], XmNhighlightThickness, 0); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+
+ list = XmCreateScrolledList(parent, (char *)w_name, args, n);
+
+#if defined(__GNUC__) && DEVEL_MODE
+#warning TODO: make up/down scroll the list, and PgUp/PgDown scroll help text
+#warning TODO: add wheel mouse bindings
+ /*
+ * also fix bug with arrow keys first moving invisible cursor, then scrollbars
+ */
+#endif
+
+ XmListDeleteAllItems(list);
+ XmListAddItems(list, topics, tnum, 0);
+
+ for (i = 0; i < tnum; ++i) {
+ XmStringFree(topics[i]);
+ }
+ free(topics);
+ }
+ XtAddCallback(list, XmNbrowseSelectionCallback, select_topic_cb, info);
+ XmListSelectPos(list, 1, False); /* default position */
+#else /* MOTIF */
+ list = XtVaCreateWidget(w_name, listWidgetClass, parent,
+ XtNlist, topics,
+ XtNdefaultColumns, 1,
+ XtNforceColumns, True,
+ XtNverticalList, True,
+ XtNrowSpacing, 4,
+ XtNheight, 429,
+ NULL);
+ XtAddCallback(list, XtNcallback, select_topic_cb, info);
+ XawListHighlight(list, 0); /* default position */
+#endif /* MOTIF */
+ XtManageChild(list);
+ return list;
+}
+
+
+Widget
+create_topic_window(Widget parent,
+ const char *window_title,
+ const char *widget_name,
+ struct topic_info *info,
+ void (*init_items_func)(struct topic_info *info),
+ /* OK button/callbacks */
+ const char *ok_label,
+ /* Cancel button/callbacks (can be NULL) */
+ const char *cancel_label)
+{
+ Widget topic_window, topics_list, topic_label;
+ Widget pane, form, left_form, right_container_form, right_form;
+ Widget action_area, ok_button, cancel_button;
+ XtTranslations xlats;
+
+ XtAppContext app = NULL;
+ Atom WM_DELETE_WINDOW;
+
+ char *translation_str;
+ size_t i;
+
+#if !MOTIF
+ translation_str = get_string_va("<Message>WM_PROTOCOLS: WM_popdown(%p)", info);
+ xlats = XtParseTranslationTable(translation_str);
+ free(translation_str);
+#endif
+
+ topic_window = XtVaCreatePopupShell(widget_name, SHELL_WIDGET_CLASS,
+ parent,
+ XtNtitle, window_title,
+ HELP_SHELL_ARGS);
+
+#if MOTIF
+ /* make the window manager destroy action pop down the window */
+ WM_DELETE_WINDOW = XmInternAtom(XtDisplay(topic_window), "WM_DELETE_WINDOW", False);
+ XmAddWMProtocolCallback(topic_window, WM_DELETE_WINDOW, cancel_cb, info);
+#else
+ WM_DELETE_WINDOW = XInternAtom(XtDisplay(topic_window), "WM_DELETE_WINDOW", False);
+#endif
+ app = XtWidgetToApplicationContext(topic_window);
+ XtAppAddActions(app, popdown_actions, XtNumber(popdown_actions));
+
+ pane = XtVaCreateWidget("topic_pane", PANED_WIDGET_CLASS, topic_window, HELP_PANED_ARGS);
+
+ form = XtVaCreateWidget("form", FORM_WIDGET_CLASS, pane, FORM_ARGS);
+
+ /* left pane for topics selection */
+ left_form = XtVaCreateWidget("left_form", FORM_WIDGET_CLASS, form, LEFT_FORM_ARGS);
+
+ /* right form for topics display */
+ right_container_form = XtVaCreateWidget("right_container_form", FORM_WIDGET_CLASS, form, RIGHT_FORM_ARGS);
+
+ /*
+ Initialize the topic label and title string with dummy values - the real values
+ are only known inside init_items_func(). For Xaw, the size of the widget will be
+ adjusted below (for Motif it's always the full width of the right form, which is
+ what we want).
+ */
+ /* FIXME: Motif label is still chopped off if it's longer than right form -
+ work around by putting longest possible lable here ... */
+ /* Also, not all children will be sized correctly, e.g. the colors - work around
+ by specifying a rather large dummy text ... */
+ info->items[0].topic = "text text text";
+ info->items[0].title = "text text text text text text text text text text text text text text text text text";
+ topic_label = create_label_widget(right_container_form, "topic_label", info);
+ info->topic_label = topic_label;
+
+ right_form = XtVaCreateWidget("right_form", FORM_WIDGET_CLASS,
+ right_container_form,
+#if MOTIF
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, topic_label,
+ XmNtopOffset, 10,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+#else
+ XtNborderWidth, 0,
+ XtNfromVert, topic_label,
+ XtNvertDistance, 6,
+#endif /* MOTIF */
+ NULL);
+ info->right_form = right_form;
+
+ /*
+ Call the init_items_func callback. This will populate the info->items list
+ with the appropriate info, and create the forms (info->items[i].widget)
+ which are the children of right_form (which is accessed inside init_items_func()
+ through info->right_form), and all their subchildren.
+
+ It is important that every child form is already managed inside init_items_func
+ so that the total size of the preferences window is set to the maximum size of
+ the children. (The children will be unmanaged again below). All these widgets
+ are never destroyed, and are managed by demand via the list selection callback
+ (select_topic_cb).
+ */
+ init_items_func(info);
+
+ XtManageChild(topic_label);
+
+ topics_list = create_list_widget(left_form, "topics_list", info);
+ info->topics_list = topics_list;
+
+ translation_str = get_string_va("#override \n"
+ "<Key>q:close-topic-window(%p)\n"
+#ifdef MOTIF
+ "<Key>osfCancel:close-topic-window(%p)\n"
+#else
+ "<Key>Escape:close-topic-window(%p)\n"
+#endif
+ "<Key>Return:close-topic-window(%p)",
+ info, info, info);
+ xlats = XtParseTranslationTable(translation_str);
+ free(translation_str);
+ translation_str = NULL;
+
+ XtOverrideTranslations(pane, xlats);
+ XtOverrideTranslations(topics_list, xlats);
+
+ XtManageChild(left_form);
+
+ XtManageChild(right_form);
+ XtManageChild(right_container_form);
+
+ /* action area at bottom */
+ action_area = XtVaCreateWidget("action_area", FORM_WIDGET_CLASS, pane, ACTION_AREA_ARGS);
+
+ ok_button = create_button(action_area, ok_label, True, True);
+ XtOverrideTranslations(ok_button, xlats);
+
+ if (cancel_label != NULL) {
+ cancel_button = create_button(action_area, cancel_label, False, False);
+ adjust_width(ok_button, cancel_button);
+#if MOTIF
+ XtAddCallback(cancel_button, XmNactivateCallback, cancel_cb, info);
+#else
+ XtAddCallback(cancel_button, XtNcallback, cancel_cb, info);
+#endif
+ XtOverrideTranslations(cancel_button, xlats);
+ }
+
+ XtManageChild(action_area);
+
+ XtManageChild(form);
+
+ XtManageChild(pane);
+
+ XtRealizeWidget(topic_window);
+
+ /* Now unmanage all children of right_form, as described above. */
+ for (i = 0; info->items[i].topic != NULL; i++) {
+ XtUnmanageChild(info->items[i].widget);
+ }
+ info->curr_selected = 0;
+
+#if MOTIF
+ /* enable OK button */
+ XmProcessTraversal(ok_button, XmTRAVERSE_CURRENT);
+ XtOverrideTranslations(ok_button,
+ XtParseTranslationTable("<Key>Return:ArmAndActivate()\n"
+ "<Key>q:ArmAndActivate()"));
+ XtAddCallback(ok_button, XmNactivateCallback, ok_cb, info);
+ XmAddWMProtocolCallback(topic_window, WM_DELETE_WINDOW, cancel_cb, info);
+ { /* disable resizing of lower part of pane (and button) */
+ Dimension h;
+ XtVaGetValues(ok_button, XmNheight, &h, NULL);
+ XtVaSetValues(action_area,
+ XmNpaneMaximum, h + 20,
+ XmNpaneMinimum, h + 20,
+ NULL);
+ }
+#else
+ XSetWMProtocols(XtDisplay(topic_window), XtWindow(topic_window), &WM_DELETE_WINDOW, 1);
+ XtAddCallback(ok_button, XtNcallback, ok_cb, info);
+#endif
+ return topic_window;
+}
diff --git a/Build/source/texk/xdvik/gui/topic-window.h b/Build/source/texk/xdvik/gui/topic-window.h
new file mode 100644
index 00000000000..b9df8f14db7
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/topic-window.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef TOPIC_WINDOW_H_
+#define TOPIC_WINDOW_H_
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "version.h"
+
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+
+struct topic_info; /* forward declaration */
+
+struct topic_item {
+ /* topic name */
+ char *topic;
+ /* longer title of topic, displayed as heading in the right window */
+ char *title;
+ /* the widget (subwindow of the right window) associated with the topic */
+ Widget widget;
+};
+
+struct topic_info {
+ /* the toplevel shell */
+ Widget shell;
+ /* the topics list */
+ Widget topics_list;
+ /* the right form, parent of the dummy form which
+ contains the right topic-specific window */
+ Widget right_form;
+ /* the topic label in right window */
+ Widget topic_label;
+ /* the currently selected widget */
+ Widget curr_selected;
+ /* callbacks for OK button (may be NULL); it's invoked from within
+ the `real' widget callback and is passed a pointer to this(!) struct topic_info */
+ void (*ok_callback)(XtPointer arg);
+ /* like ok_callback, for the Cancel button */
+ void (*cancel_callback)(XtPointer arg);
+ /* list of topic_items */
+ struct topic_item *items;
+ size_t items_size;
+ /* additional data the callback may need ... */
+ void *data;
+};
+
+extern Widget create_topic_window(Widget parent,
+ const char *window_title,
+ const char *widget_name,
+ struct topic_info *info,
+ void (*init_items_func)(struct topic_info *info),
+ /* OK button label (can be NULL) */
+ const char *ok_label,
+ /* Cancel button label (can be NULL) */
+ const char *cancel_label);
+extern void select_topic(struct topic_info *info, size_t idx);
+#endif /* TOPIC_WINDOW_H_ */
diff --git a/Build/source/texk/xdvik/gui/xaw_bitmaps.c b/Build/source/texk/xdvik/gui/xaw_bitmaps.c
new file mode 100644
index 00000000000..6b45ca60a74
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xaw_bitmaps.c
@@ -0,0 +1,82 @@
+#include "xaw_bitmaps.h"
+
+/*
+ * Bitmaps for indicating checkbuttons and radiobuttons in Xaw popup windows.
+ * The size of these is 16x16.
+ */
+
+/* checkbuttons: rectangular box containing a tick mark if on, empty box else */
+unsigned char button_check_on_bits[] = {
+ 0x00, 0x00, 0x00, 0x80, 0xfc, 0xff, 0x04, 0x60, 0x04, 0x30, 0x04, 0x38,
+ 0x64, 0x2c, 0xe4, 0x26, 0xc4, 0x23, 0x84, 0x21, 0x04, 0x20, 0x04, 0x20,
+ 0x04, 0x20, 0xfc, 0x3f, 0x00, 0x00, 0x00, 0x00
+};
+unsigned char button_check_off_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20,
+ 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20,
+ 0x04, 0x20, 0xfc, 0x3f, 0x00, 0x00, 0x00, 0x00
+};
+
+/* radiobuttons: round and filled with dot if on, empty else */
+unsigned char button_radio_on_bits[] = {
+/* 0x70, 0x00, 0x8c, 0x01, 0x02, 0x02, 0x72, 0x02, 0xf9, 0x04, 0xf9, 0x04, */
+/* 0xf9, 0x04, 0x72, 0x02, 0x02, 0x02, 0x8c, 0x01, 0x70, 0x00 */
+ 0x00,0x00,0x00,0x00,0xc0,0x03,0x30,0x0c,0x08,0x10,0xc8,0x13,0xe4,0x27,0xe4,
+ 0x27,0xe4,0x27,0xe4,0x27,0xc8,0x13,0x08,0x10,0x30,0x0c,0xc0,0x03,0x00,0x00,
+ 0x00,0x00
+};
+unsigned char button_radio_off_bits[] = {
+/* 0x70, 0x00, 0x8c, 0x01, 0x02, 0x02, 0x02, 0x02, 0x01, 0x04, 0x01, 0x04, */
+/* 0x01, 0x04, 0x02, 0x02, 0x02, 0x02, 0x8c, 0x01, 0x70, 0x00 */
+ 0x00,0x00,0x00,0x00,0xc0,0x03,0x30,0x0c,0x08,0x10,0x08,0x10,0x04,0x20,0x04,
+ 0x20,0x04,0x20,0x04,0x20,0x08,0x10,0x08,0x10,0x30,0x0c,0xc0,0x03,0x00,0x00,
+ 0x00,0x00
+};
+
+/*
+ * Bitmaps for left-hand markers in Xaw pulldown menus; these only
+ * use the mark elements from the button markers (dot, or tick).
+ */
+
+/* check options: similar to button_check_*_bits. */
+unsigned char menu_check_on_bits[] = {
+ 0x00, 0x04, 0x00, 0x06, 0x00, 0x03, 0x80, 0x01, 0xc6, 0x00, 0x6e, 0x00,
+ 0x3c, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+unsigned char menu_check_off_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* radio options: tick mark if on, else empty. These are different from
+ the `round' buttons in button_radio_* (not ideal ...) since the round
+ buttons are too large for menus.
+*/
+unsigned char menu_radio_on_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xf8, 0x00, 0xf8, 0x00,
+ 0xf8, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+unsigned char menu_radio_off_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/* arrow for Xaw submenus */
+unsigned char menu_arrow_bits[] = {
+/* 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x38, 0x00, 0x78, 0x00, 0xf8, 0x00, */
+/* 0x78, 0x00, 0x38, 0x00, 0x18, 0x00, 0x08, 0x00, 0x00, 0x00 */
+
+ 0x00, 0x00, 0x20, 0x00, 0x60, 0x00, 0xe0, 0x00, 0xe0, 0x01, 0xe0, 0x03,
+ 0xe0, 0x01, 0xe0, 0x00, 0x60, 0x00, 0x20, 0x00, 0x00, 0x00
+/* 0x00, 0x00, 0x00, 0x08, 0x00, 0x18, 0x00, 0x38, 0x00, 0x78, 0x00, 0xf8, */
+/* 0x00, 0x78, 0x00, 0x38, 0x00, 0x18, 0x00, 0x08, 0x00, 0x00 */
+/* 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00 */
+};
+
+
+/* double arrow for popup menus */
+unsigned char menu_double_arrow_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x70, 0x00, 0xf8, 0x00,
+ 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0xf8, 0x00, 0x70, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
diff --git a/Build/source/texk/xdvik/gui/xaw_bitmaps.h b/Build/source/texk/xdvik/gui/xaw_bitmaps.h
new file mode 100644
index 00000000000..21daf9e2bea
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xaw_bitmaps.h
@@ -0,0 +1,21 @@
+#define BUTTON_BITMAP_H 16
+#define BUTTON_BITMAP_W 16
+extern unsigned char button_check_on_bits[];
+extern unsigned char button_check_off_bits[];
+extern unsigned char button_radio_on_bits[];
+extern unsigned char button_radio_off_bits[];
+
+#define MENU_BITMAP_H 11
+#define MENU_BITMAP_W 11
+extern unsigned char menu_check_on_bits[];
+extern unsigned char menu_check_off_bits[];
+extern unsigned char menu_radio_on_bits[];
+extern unsigned char menu_radio_off_bits[];
+
+#define MENU_ARROW_H 11
+#define MENU_ARROW_W 11
+extern unsigned char menu_arrow_bits[];
+
+#define MENU_DOUBLE_ARROW_H 16
+#define MENU_DOUBLE_ARROW_W 11
+extern unsigned char menu_double_arrow_bits[];
diff --git a/Build/source/texk/xdvik/gui/xaw_menu.c b/Build/source/texk/xdvik/gui/xaw_menu.c
new file mode 100644
index 00000000000..ef9b387f8c1
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xaw_menu.c
@@ -0,0 +1,1449 @@
+/*
+ * Copyright (c) 2001-2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Menu bar implementation for the Athena widget set.
+ */
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "c-openmx.h"
+#include "events.h"
+#include "dvi-draw.h"
+#include "dvi-init.h"
+#include "statusline.h"
+#include "pagesel.h"
+#include "util.h"
+#include "x_util.h"
+#include "xaw_menu.h"
+#include "message-window.h"
+#include "my-snprintf.h"
+#include "filehist.h"
+#ifdef NEW_MENU_CREATION
+#include "menu.h"
+#endif /* NEW_MENU_CREATION */
+
+#ifndef MOTIF /* entire file */
+
+#include <ctype.h>
+
+#include <X11/Intrinsic.h>
+#include <X11/Xatom.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h> /* needed for def. of XtNiconX */
+
+#include <X11/Xaw/Viewport.h>
+#include <X11/Xaw/SimpleMenu.h>
+#include <X11/Xaw/MenuButton.h>
+#include <X11/Xaw/Sme.h>
+#include <X11/Xaw/SmeBSB.h>
+#include <X11/Xaw/SmeLine.h>
+#include <X11/Xaw/Dialog.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/Panner.h>
+#include <X11/Xaw/Porthole.h>
+#include <X11/Xaw/Command.h>
+
+#ifndef MAX
+# define MAX(i, j) ( (i) > (j) ? (i) : (j) )
+#endif
+
+
+#ifndef NEW_MENU_CREATION
+#define SEP_CHAR ':' /* character separating entries in translations lines */
+#endif
+
+/* needed to count the callbacks */
+static int destroy_count = 0;
+
+/* width of button panel */
+static int my_panel_width = 0;
+
+/* access method for panel width */
+int
+get_panel_width(void)
+{
+ int retval = 0;
+ if (resource.expert_mode & XPRT_SHOW_BUTTONS)
+ retval = my_panel_width;
+ TRACE_GUI((stderr, "get_panel_width: %d", retval));
+ return retval;
+}
+
+#ifndef NEW_MENU_CREATION
+typedef enum { INVALID, /* some error */
+ NONE, /* no new button created */
+ MENU_SEPARATOR, MENU_BUTTON, MENU_ENTRY, COMMAND_BUTTON } buttonTypeT;
+
+struct button_info {
+ struct button_info *next;
+ char *label;
+ struct xdvi_action *action;
+ Widget widget;
+ buttonTypeT type;
+};
+
+static Widget panner = 0;
+static struct button_info *b_head = NULL;
+
+#define MAX_MENU_NUM 128
+#define MAX_BUTTON_NUM 128
+
+static struct menu_list_ {
+ char *name;
+ Widget button_widget;
+ Widget popup_widget;
+} menu_list[MAX_MENU_NUM];
+
+#endif /* not NEW_MENU_CREATION */
+
+#ifdef NEW_MENU_CREATION
+/*
+ ================================================================================
+ Pixmaps indicating the state of menu buttons (radiobutton/checkbox
+ on/off, cascading menu). Inspired by menu.c, `check_bits' in the xterm source.
+ ================================================================================
+*/
+#include "xaw_bitmaps.h"
+static Pixmap menu_check_on_bitmap;
+static Pixmap menu_check_off_bitmap;
+static Pixmap menu_radio_on_bitmap;
+static Pixmap menu_radio_off_bitmap;
+static Pixmap menu_arrow_bitmap;
+#else
+#include "xaw_bitmaps.h"
+/* lifted from menu.c, check_bits in xterm */
+static Pixmap menu_check_bitmap;
+static Pixmap menu_arrow_bitmap;
+#endif /* NEW_MENU_CREATION */
+
+/*
+ ============================================================
+ Hack for pullright menus part I: data
+ ============================================================
+*/
+
+/* There are a few custom widgets for pullright menus out there, but
+ * these are old and potentially buggy, so just do it manually via an
+ * event handler, similar to Motif tooltips.
+ */
+static XtIntervalId m_timeout = 0;
+static Widget m_active_submenu = NULL; /* if not NULL, the currently active pullright */
+static Widget m_submenu = NULL; /* parent of the currently active pullright
+ (i.e. the menu label in the parent window) */
+
+static void ActPopdownSubmenus(Widget w, XEvent *event, String *params, Cardinal *num_params);
+
+/* to safely pop down the pullright, this callback is added to its parent menu */
+static XtActionsRec menu_actions[] = {
+ { "popdown-submenus", ActPopdownSubmenus }
+};
+
+static XtAccelerators menu_accels;
+
+struct pullright_position_info {
+ Position y;
+ Dimension w;
+ Dimension h;
+ Dimension border_width;
+ Widget menu;
+};
+
+
+#ifdef NEW_MENU_CREATION
+/*
+ * Set all pixmaps indicating the state of the wigdet pointed to by `elems'.
+ */
+void
+xaw_set_button_state(struct button_elems *elems, Boolean on)
+{
+ static Arg args[] = {
+ { XtNleftBitmap, (XtArgVal)0 },
+ { XtNrightBitmap, (XtArgVal)0 }
+ };
+
+ if (elems->type == BT_CHECK)
+ args[0].value = on ? menu_check_on_bitmap : menu_check_off_bitmap;
+ else if (elems->type == BT_RADIO)
+ args[0].value = on ? menu_radio_on_bitmap : menu_radio_off_bitmap;
+ if (elems->submenu != NULL)
+ args[1].value = menu_arrow_bitmap;
+
+ XtSetValues(elems->widget, args, XtNumber(args));
+}
+
+/*
+ * Initialize the bitmaps.
+ */
+void
+xaw_initialize_menu_bitmaps(void)
+{
+ static Boolean initialized = False;
+ if (!initialized) {
+ initialized = True;
+ menu_check_on_bitmap
+ = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)menu_check_on_bits, MENU_BITMAP_W, MENU_BITMAP_H);
+ menu_check_off_bitmap
+ = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)menu_check_off_bits, MENU_BITMAP_W, MENU_BITMAP_H);
+ menu_radio_on_bitmap
+ = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)menu_radio_on_bits, MENU_BITMAP_W, MENU_BITMAP_H);
+ menu_radio_off_bitmap
+ = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)menu_radio_off_bits, MENU_BITMAP_W, MENU_BITMAP_H);
+ menu_arrow_bitmap
+ = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)menu_arrow_bits, MENU_ARROW_W, MENU_ARROW_H);
+ }
+}
+
+#else
+
+/* toggle `checked' symbol on xaw menu w */
+void
+toggle_tick(Boolean val, Widget w)
+{
+ static Arg args = { XtNleftBitmap, (XtArgVal) 0 };
+ if (val)
+ args.value = (XtArgVal) menu_check_bitmap;
+ else
+ args.value = None;
+ XtSetValues(w, &args, 1);
+}
+
+void
+toggle_menu(int val, XtActionProc proc)
+{
+ struct button_info *bp;
+
+ for (bp = b_head; bp != NULL; bp = bp->next) {
+ if (bp->action != NULL && bp->action->proc == proc && bp->action->param != NULL) {
+ TRACE_GUI((stderr, "found proc; param: |%s|", bp->action->param));
+ if (strcmp(bp->action->param, "toggle") == 0) {
+ if (val != 0)
+ toggle_tick(True, bp->widget);
+ else
+ toggle_tick(False, bp->widget);
+ }
+ else if (strcmp(bp->action->param, "a") == 0) {
+ if (val == shrink_to_fit())
+ toggle_tick(True, bp->widget);
+ else
+ toggle_tick(False, bp->widget);
+ }
+ else {
+ int testval = strtoul(bp->action->param, (char **)NULL, 10);
+ if (testval == val) {
+ TRACE_GUI((stderr, "enabling param |%s|", bp->action->param));
+ toggle_tick(True, bp->widget);
+ }
+ else
+ toggle_tick(False, bp->widget);
+ }
+ }
+ }
+}
+
+/* initialize `checked' symbol on xaw menu w */
+static void
+initialize_tick_marks(void)
+{
+ int use_gs;
+ if (menu_check_bitmap == None) {
+ int check_width = 9;
+ int check_height = 8;
+ unsigned char check_bits[] = {
+ 0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x60, 0x00,
+ 0x31, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04, 0x00
+ };
+
+ menu_check_bitmap = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)check_bits, check_width, check_height);
+ }
+
+ /* initialize tickmarks for all possible actions */
+ use_gs = resource.postscript;
+#ifdef PS_GS
+ if (!resource.useGS)
+ use_gs = 0;
+#endif
+
+ toggle_menu(use_gs, Act_set_ps);
+ toggle_menu(resource.gs_alpha, Act_set_gs_alpha);
+ toggle_menu(resource.keep_flag, Act_set_keep_flag);
+ toggle_menu(resource.pixels_per_inch / mane.shrinkfactor, Act_shrink_to_dpi);
+ toggle_menu(mane.shrinkfactor, Act_set_shrink_factor);
+ toggle_menu(resource.use_tex_pages, Act_use_tex_pages);
+ toggle_menu(resource.mouse_mode, Act_switch_mode);
+}
+#endif /* NEW_MENU_CREATION */
+
+/* ================================================================================
+ ================================================================================
+*/
+
+static Widget line_widget, panel_widget;
+
+/* used for communication with the pagelist in xaw_create_pagelist */
+static int my_y_pos;
+
+/* access function: panel, height of buttons etc. */
+void
+xaw_create_pagelist(void)
+{
+ Dimension height, width;
+ int button_width = get_panel_width() - 2 * (resource.btn_side_spacing + resource.btn_border_width);
+
+ XtVaGetValues(globals.widgets.clip_widget, XtNheight, &height, NULL);
+ width = MAX(button_width, xaw_get_pagelist_size());
+ height -= resource.btn_top_spacing + resource.btn_border_width + my_y_pos;
+ xaw_create_pagelist_widgets(height, width, my_y_pos, panel_widget);
+}
+
+
+static XtCallbackRec command_call[] = {
+ {handle_command, NULL},
+ {NULL, NULL},
+};
+
+#ifdef NEW_MENU_CREATION
+void xaw_create_menu(struct button_info *items, Widget parent, int menu_depth, int *ret_width)
+{
+
+}
+
+Widget
+xaw_create_menu_widgets(Widget parent)
+{
+ /* hack to disable the magnifier in the panel: */
+ XtTranslations panel_translations = XtParseTranslationTable("#augment <ButtonPress>:");
+
+ line_widget = XtVaCreateWidget("line", widgetClass, parent,
+ XtNbackground, (XtArgVal)resource.fore_Pixel,
+ XtNwidth, (XtArgVal)1,
+ XtNfromHoriz, (XtArgVal)globals.widgets.vport_widget,
+ XtNborderWidth, (XtArgVal)0,
+ XtNtop, (XtArgVal)XtChainTop,
+ XtNbottom, (XtArgVal)XtChainBottom,
+ XtNleft, (XtArgVal)XtChainRight,
+ XtNright, (XtArgVal)XtChainRight,
+ NULL);
+ panel_widget = XtVaCreateWidget("panel", compositeWidgetClass, parent,
+ XtNborderWidth, (XtArgVal)0,
+ XtNfromHoriz, (XtArgVal)line_widget,
+ XtNtranslations, (XtArgVal)panel_translations,
+ XtNtop, (XtArgVal)XtChainTop,
+ XtNbottom, (XtArgVal)XtChainBottom,
+ XtNleft, (XtArgVal)XtChainRight,
+ XtNright, (XtArgVal)XtChainRight,
+ NULL);
+ return panel_widget;
+}
+
+#else /* NEW_MENU_CREATION */
+
+
+static void
+filehist_select_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ char *label, *ptr;
+ int idx;
+
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ XtVaGetValues(w, XtNlabel, &label, NULL);
+
+ idx = strtol(label, &ptr, 10) - 1;
+ while (isspace(*ptr))
+ ptr++;
+ TRACE_GUI((stderr, "User selected: %d, `%s'", idx, ptr));
+ if (idx == 0) {
+ globals.ev.flags |= EV_RELOAD;
+ return;
+ }
+ file_history_open(ptr);
+}
+
+static void
+update_menu_labels(Widget menu)
+{
+ WidgetList children;
+ int num_children;
+ int i;
+
+ static char *buf = NULL;
+ static size_t buf_len = 0;
+ size_t new_len;
+
+ XtVaGetValues(menu,
+ XtNnumChildren, &num_children,
+ XtNchildren, &children,
+ NULL);
+ for (i = 0; i < (int)file_history_size(); i++) {
+ int dummy_page;
+ char *filename;
+
+ if ((filename = file_history_get_elem(i, &dummy_page)) == NULL) {
+ XDVI_ERROR((stderr, "Error accessing element %d of file history", i));
+ continue;
+ }
+
+ new_len = LENGTH_OF_INT + strlen(filename) + 1;
+ if (new_len > buf_len) {
+ buf = xrealloc(buf, new_len);
+ buf_len = new_len;
+ }
+
+ sprintf(buf, "%d %s", i + 1, filename);
+ XtVaSetValues(children[i], XtNlabel, buf, NULL);
+ TRACE_GUI((stderr, "child %d: `%s'", i, buf));
+ }
+
+ /* if history size < number of menu entries, destroy excess menu entries */
+ for (; i < num_children; i++) {
+ XtDestroyWidget(children[i]);
+ }
+}
+
+void
+filehist_menu_add_entry(const char *filename)
+{
+ static char *buf = NULL;
+ static size_t buf_len = 0;
+ size_t new_len = LENGTH_OF_INT + strlen(filename) + 1;
+
+ Widget menu;
+ /* Don't report an error here, since "filehist_pullright" is only created on-demand
+ when user clicks on menu, but this may be called before from the event loop.
+ (The menu will still contain this entry when it's created later.) */
+ if (get_widget_by_name(&menu, globals.widgets.top_level, "filehist_pullright", False)) {
+ int num_children;
+ Widget w;
+
+ if (new_len > buf_len) {
+ buf = xrealloc(buf, new_len);
+ buf_len = new_len;
+ }
+
+ XtVaGetValues(menu, XtNnumChildren, &num_children, NULL);
+ sprintf(buf, "%d %s", num_children + 1, filename);
+
+ w = XtVaCreateManagedWidget("_filehist", smeBSBObjectClass, menu,
+ XtNlabel, buf,
+ XtNleftMargin, 10,
+ NULL);
+ XtAddCallback(w, XtNcallback, filehist_select_cb, NULL);
+ update_menu_labels(menu);
+ }
+}
+
+void
+filehist_menu_refresh(void)
+{
+ Widget menu;
+
+ /* Don't report an error here, since "filehist_pullright" is only created on-demand
+ when user clicks on menu, but this may be called before from the event loop.
+ (The menu will still contain this entry when it's created later.) */
+ if (get_widget_by_name(&menu, globals.widgets.top_level, "filehist_pullright", False)) {
+ update_menu_labels(menu);
+ }
+}
+
+
+static void
+filehist_insert_submenu(int idx, const char *filename, int pageno, void *data)
+{
+ Widget menu = (Widget)data;
+ Widget w;
+ static char *buf = NULL;
+ static size_t buf_len = 0;
+ size_t new_len = LENGTH_OF_INT + strlen(filename) + 1;
+
+ UNUSED(pageno);
+
+ if (new_len > buf_len) {
+ buf = xrealloc(buf, new_len);
+ buf_len = new_len;
+ }
+
+ sprintf(buf, "%d %s", idx + 1, filename);
+ TRACE_GUI((stderr, "Creating menu `%s'", buf));
+ w = XtVaCreateManagedWidget("_filehist", smeBSBObjectClass, menu,
+ XtNlabel, buf,
+ XtNleftMargin, 10,
+ NULL);
+ XtAddCallback(w, XtNcallback, filehist_select_cb, NULL);
+}
+
+
+/*
+ ============================================================
+ Hack for pullright menus part II: callbacks and functions
+ ============================================================
+*/
+
+/* callback to pop down the currently active pullright */
+static void
+ActPopdownSubmenus(Widget w, XEvent *event, String *params, Cardinal *num_params)
+{
+ UNUSED(w);
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if (m_timeout != 0)
+ XtRemoveTimeOut(m_timeout);
+ m_timeout = 0;
+ if (m_active_submenu != NULL)
+ XtPopdown(m_active_submenu);
+}
+/* create a parent shell for the pullright menu entries */
+static Widget
+create_files_submenu(void)
+{
+ Widget popup = XtCreatePopupShell("filehist_pullright", simpleMenuWidgetClass, globals.widgets.top_level,
+ NULL, 0);
+ file_history_enumerate(filehist_insert_submenu, popup);
+ return popup;
+}
+
+/* Acutally pop up the pullright menu */
+static void
+popup_pullright(XtPointer client_data, XtIntervalId *id)
+{
+ int pos_x, pos_y;
+ Dimension w1;
+ Window dummy;
+ static Widget files_submenu = NULL;
+ struct pullright_position_info *info = (struct pullright_position_info *)client_data;
+
+ UNUSED(id);
+
+ if (files_submenu == NULL)
+ files_submenu = create_files_submenu();
+ /* XtManageChild(files_submenu); */
+ XTranslateCoordinates(DISP, XtWindow(XtParent(m_submenu)), RootWindowOfScreen(SCRN),
+ info->w, info->y, &pos_x, &pos_y, &dummy);
+ XtRealizeWidget(files_submenu);
+ XtVaGetValues(files_submenu, XtNwidth, &w1, NULL);
+ TRACE_GUI((stderr, "Popping up at %d, %d, %d, %d", pos_x, pos_y, w1, WidthOfScreen(SCRN)));
+
+ /* if not sufficient place on the right, pop it up on the left */
+ /* fprintf(stderr, "border_width: %d\n", info->border_width); */
+ if (pos_x + w1 > WidthOfScreen(SCRN)) {
+ /* fprintf(stderr, "%d > %d!\n", pos_x + w1, WidthOfScreen(SCRN)); */
+ pos_x -= (w1 + info->w + 3 * info->border_width);
+ /* fprintf(stderr, "new x: %d\n", pos_x); */
+ }
+ else {
+ pos_x += info->border_width;
+ }
+ XtVaSetValues(files_submenu,
+ XtNx, pos_x,
+ XtNy, pos_y,
+ NULL);
+ /* use XtPopupSpringLoaded() instead of XtPopup() since it does a few things
+ that make the pullright behave like a proper menu, like highlighting the
+ current selection, setting the cursor shape etc. */
+ XtPopupSpringLoaded(files_submenu);
+ m_active_submenu = files_submenu;
+}
+
+/*
+ * This event handler (to be called by read_events(), the main event handling loop)
+ * creates a timeout for the pullright to pop up.
+*/
+void
+SubMenuHandleEvent(XtAppContext app, XEvent *event)
+{
+ static int flag = 0;
+ static struct pullright_position_info info = { -1, 0, 0, 0, NULL };
+
+ UNUSED(app);
+
+ if (m_submenu == NULL)
+ return;
+
+ if (event->type == EnterNotify
+ || event->type == MotionNotify
+ || event->type == LeaveNotify
+ || event->type == ButtonPress) {
+
+/* fprintf(stderr, "SubMenuHandleEvent: 0x%lx, 0x%lx\n", event->xany.window, XtWindow(m_submenu)); */
+
+ /* Could also loop through a list of windows here ...
+ We need to check for the parent of the menu item, since smeBSBObject is not
+ a real window, and then manually check whether the pointer is inside the menu
+ item.
+ */
+ if (XtParent(m_submenu) != NULL &&
+ event->xany.window == XtWindow(XtParent(m_submenu))) {
+ /* don't need to check for x coordinates since we already
+ know that pointer is inside the parent */
+ if (info.y == -1) { /* initialize info */
+ XtVaGetValues(m_submenu,
+ XtNy, &(info.y),
+ XtNwidth, &(info.w),
+ XtNheight, &(info.h),
+ NULL);
+ XtVaGetValues(XtParent(m_submenu),
+ XtNborderWidth, &(info.border_width),
+ NULL);
+
+ info.menu = m_submenu;
+ }
+ if (info.y < event->xbutton.y && info.y + info.h > event->xbutton.y) {
+ if (flag == 0) {
+ /* Create a timeout of 200ms to pop up the menu, so that it doesn't
+ pop up always when the cursor is only moved over the pulldown menu.
+ I think this is about the same delay as the one used by Motif.
+ */
+ flag = 1;
+ TRACE_GUI((stderr, "ENTER: %d, %d, %d; %d, %d",
+ info.y, info.w, info.h, event->xbutton.x, event->xbutton.y));
+ m_timeout = XtAppAddTimeOut(app, 200, popup_pullright, &info);
+ return;
+ }
+ }
+ else if (flag == 1) {
+ flag = 0;
+ TRACE_GUI((stderr, "LEAVE!"));
+ if (m_timeout != 0)
+ XtRemoveTimeOut(m_timeout);
+ m_timeout = 0;
+ if (m_active_submenu != NULL)
+ XtPopdown(m_active_submenu);
+ m_active_submenu = NULL;
+ }
+ }
+ }
+}
+
+static Widget
+create_pulldown_entry(const char *menu_name,
+ Widget parent,
+ const char *item_name,
+ const char *accelerator, /* accelerator, or NULL */
+ struct xdvi_action *action,
+ buttonTypeT *type)
+{
+ Widget w;
+ char buf[1024];
+ char *m_name = xstrdup(menu_name);
+ m_name = xstrcat(m_name, item_name);
+
+#ifdef SHOW_ACCELERATORS
+ if (accelerator != NULL && *accelerator != '\0')
+ SNPRINTF(buf, 1024, "%s [%s]", item_name, accelerator);
+ else
+ strncpy(buf, item_name, 1024);
+#else
+ UNUSED(accelerator);
+ strncpy(buf, item_name, 1024);
+#endif
+
+/* fprintf(stderr, "creating pulldown for parent %p: `%s', `%s'\n", */
+/* (void *)parent, menu_name, item_name); */
+
+ if (strcmp(item_name, "SEP") == 0) { /* it's a separator */
+ *type = MENU_SEPARATOR;
+ w = XtCreateManagedWidget(m_name, smeLineObjectClass, parent, NULL, 0);
+ }
+ else if (action->proc != NULL && action->proc == Act_recent_files) { /* special case: submenu with recent files */
+/* w = recent_files_submenu(m_name, parent, buf); */
+/* *type = MENU_ENTRY; */
+ w = XtVaCreateManagedWidget(m_name, smeBSBObjectClass, parent,
+ XtNlabel, buf,
+ XtNleftMargin, 20,
+ XtNrightMargin, 16,
+ XtNrightBitmap, menu_arrow_bitmap,
+ NULL);
+ m_submenu = w;
+ /* fprintf(stderr, "setting translations for %p\n", (void *)XtParent(parent)); */
+ XtOverrideTranslations(parent, menu_accels);
+ /* XtOverrideTranslations(XtParent(parent), menu_accels); */
+
+ *type = MENU_ENTRY;
+ }
+ else { /* normal menu item */
+ w = XtVaCreateManagedWidget(m_name, smeBSBObjectClass, parent,
+ XtNlabel, buf,
+ XtNleftMargin, 20,
+ NULL);
+ *type = MENU_ENTRY;
+ XtAddCallback(w, XtNcallback, handle_command, action);
+ }
+ free(m_name);
+ return w;
+}
+
+static Widget
+create_pulldown_menu(const char *menu_name,
+ Dimension *width,
+ int *index,
+ Dimension *y_pos,
+ buttonTypeT *type,
+ int *menu_number)
+{
+ int i;
+
+ /* check whether a pulldown menu with this name already exists,
+ and if yes, return its position in index: */
+ for (i = 0; i < *menu_number; i++) {
+ if (menu_list[i].name != NULL && (strcmp(menu_list[i].name, menu_name)) == 0) {
+ *index = i;
+ break;
+ }
+ }
+ if (i == *menu_number) { /* doesn't exist, create one */
+ Dimension w, h;
+ Widget n_button_widget, n_popup_widget;
+ char *button_widget_name = NULL;
+
+ (*menu_number)++;
+ if (*menu_number > MAX_MENU_NUM) {
+ XDVI_WARNING((stderr, "Too many menus (max=%d), skipping all from \"%s\"",
+ MAX_MENU_NUM, menu_name));
+ *type = INVALID;
+ return 0;
+ }
+
+ /* save menu_name to list for later comparison */
+ menu_list[i].name = xrealloc(menu_list[i].name, strlen(menu_name) + 1);
+ strcpy(menu_list[i].name, menu_name);
+
+ button_widget_name = xstrdup(menu_name);
+ button_widget_name = xstrcat(button_widget_name, "B"); /* make it unique */
+
+ if (globals.debug & DBG_ALL) {
+ fprintf(stderr, "ypos: %d; h: %d; between: %d; border: %d\n",
+ *y_pos,
+ h,
+ resource.btn_between_spacing,
+ resource.btn_border_width);
+ }
+
+ n_button_widget = XtVaCreateWidget(menu_list[i].name, menuButtonWidgetClass, panel_widget,
+ XtNmenuName, button_widget_name,
+ XtNx, resource.btn_side_spacing,
+ XtNy, *y_pos,
+ XtNborderWidth, resource.btn_border_width,
+ NULL);
+ n_popup_widget = XtVaCreatePopupShell(button_widget_name, simpleMenuWidgetClass, n_button_widget,
+ NULL);
+ /* Mustn't free this one?? */
+/* free(button_widget_name); */
+ menu_list[i].button_widget = n_button_widget;
+ menu_list[i].popup_widget = n_popup_widget;
+ XtVaGetValues(n_button_widget, XtNwidth, &w, XtNheight, &h, NULL);
+ *width = w;
+ *index = i;
+ *y_pos += h + resource.btn_between_spacing + 2 * resource.btn_border_width;
+ *type = MENU_BUTTON;
+ return n_button_widget;
+ }
+ *type = NONE;
+ return 0;
+}
+
+static struct button_info *
+create_button_info(const char *label, struct xdvi_action *action, Widget w, buttonTypeT type)
+{
+ struct button_info *info = xmalloc(sizeof *info);
+ info->label = xstrdup(label);
+ info->action = action;
+ info->widget = w;
+ info->type = type;
+ return info;
+}
+
+typedef enum shrinkArgT_ { NO_SHRINK_ARG, HASH, PERCENT, UNDERSCORE } shrinkArgT;
+
+static shrinkArgT
+test_for_shrink_arg(const char *item, int *idx)
+{
+ const char *ptr = item;
+ size_t i;
+ for (i = 0; ptr[i] != '\0'; i++) {
+ if (ptr[i] == '$') {
+ i++;
+ if (ptr[i] == '#') {
+ *idx = i;
+ return HASH;
+ }
+ else if (ptr[i] == '%') {
+ *idx = i;
+ return PERCENT;
+ }
+ else if (ptr[i] == '_') {
+ *idx = i;
+ return UNDERSCORE;
+ }
+ }
+ }
+ *idx = 0;
+ return NO_SHRINK_ARG;
+}
+
+static Boolean
+create_shrink_button(char **label, int offset, shrinkArgT type, struct xdvi_action *action)
+{
+ int shrink_arg = 0;
+#define TEMPSTR_LEN 128 /* enough for printing a number into */
+ char tempstr[TEMPSTR_LEN];
+ char *new_label = NULL;
+
+ for (;; action = action->next) {
+ if (action == NULL) {
+ return False;
+ }
+ if (action->proc == Act_set_shrink_factor || action->proc == Act_shrink_to_dpi) {
+ /* NOTE: the shrinkbutton[] resource isn't implemented. It probably makes
+ less sense with the pulldown menu resources??
+ */
+ if (action->num_params > 0) {
+ shrink_arg = atoi(action->param);
+ if (action->proc == Act_shrink_to_dpi)
+ shrink_arg = (double)resource.pixels_per_inch / shrink_arg + 0.5;
+ if (shrink_arg < 1)
+ shrink_arg = 1;
+ else if (shrink_arg > 99)
+ shrink_arg = 99;
+ }
+ break; /* found shrink action */
+ }
+ }
+
+ if (type == HASH)
+ SNPRINTF(tempstr, TEMPSTR_LEN, "%d", shrink_arg);
+ else if (type == PERCENT) {
+ if (shrink_arg <= 15)
+ SNPRINTF(tempstr, TEMPSTR_LEN, "%d", (int)(100.0 / shrink_arg + .5));
+ else
+ SNPRINTF(tempstr, TEMPSTR_LEN, "%.2f", 100.0 / shrink_arg);
+ }
+ /* NOTE: I think UNDERSCORE is related to the shrinkbutton[] resource,
+ which is not implemented */
+
+ /* return resized label */
+ new_label = xmalloc(offset - 1 + strlen(tempstr) + strlen(*label + offset + 1) + 1);
+ memcpy(new_label, *label, offset - 1);
+ strcpy(new_label + offset - 1, tempstr); /* now it's null-terminated */
+ strcat(new_label, *label + offset + 1);
+ free(*label);
+ *label = new_label;
+
+#undef TEMPSTR_LEN
+ return True;
+}
+
+static Dimension
+create_button(int button_number, /* number of this button */
+ int *menu_num, /* number of submenus in this button */
+ char **items, /* description of label and action strings */
+ size_t item_count, /* number of items in description */
+ Widget parent, /* parent of widget to create */
+ struct button_info ***bipp, /* button info to insert new button into */
+ Dimension *y_pos, /* vertical position after creating button */
+ const char *c_ptr, /* entire rest of resource string, for error messages */
+ size_t len) /* length of current line in resource string, for error messages*/
+{
+ int menu_idx = -1, label_idx = -1, accelerator_idx = -1, action_idx = -1;
+#define NAME_LEN 16
+ char name[NAME_LEN];
+ struct button_info *bp;
+ shrinkArgT shrink_arg_type;
+ struct xdvi_action *action;
+ Widget widget;
+ buttonTypeT b_type;
+/* static int menu_num = 0; /\* count number of created menus *\/ */
+ Dimension width = 0;
+
+ ASSERT(item_count >= 2, "Too few items");
+
+ if (item_count == 4) { /* submenu for a button */
+ menu_idx = 0;
+ label_idx = 1;
+ accelerator_idx = 2;
+ action_idx = 3;
+ }
+ else if (item_count == 3) { /* command button */
+ label_idx = 0;
+ accelerator_idx = 1;
+ action_idx = 2;
+ }
+ else { /* separator */
+ if (strcmp(items[1], "SEP") == 0) { /* separator */
+ menu_idx = 0;
+ label_idx = 1;
+ }
+ else {
+ XDVI_WARNING((stderr, "Wrong number of items (%d) in translations line:\n\"%.*s\" (skipping this line).",
+ item_count, (int)len, c_ptr));
+ return 0;
+ }
+ }
+
+ if (action_idx != -1) {
+ int offset;
+ shrink_arg_type = test_for_shrink_arg(items[label_idx], &offset);
+
+/* fprintf(stderr, "compiling action: |%s|\n", items[action_idx]); */
+ if ((action = compile_action(items[action_idx])) == NULL) {
+ XDVI_WARNING((stderr, "Invalid action \"%s\" in translations line:\n\"%.*s\" (skipping this line).",
+ items[action_idx], (int)len, c_ptr));
+ return 0;
+ }
+
+ if (shrink_arg_type != NO_SHRINK_ARG) { /* search for corresponding shrink action */
+ if (!create_shrink_button(&(items[label_idx]), offset, shrink_arg_type, action)) {
+ XDVI_WARNING((stderr, "Non-existent shrink action \"%s\" in translations line:\n\"%.*s\"",
+ items[action_idx], (int)len, c_ptr));
+ return 0;
+ }
+ }
+ }
+ else {
+ action = NULL;
+ }
+
+ command_call[0].closure = (XtPointer) action;
+ SNPRINTF(name, NAME_LEN, "button%d", button_number);
+
+ if (menu_idx != -1) { /* it's a pulldown menu */
+ int index;
+
+ /* create a new pulldown menu if it doesn't exist yet */
+ widget = create_pulldown_menu(items[menu_idx], &width, &index, y_pos, &b_type, menu_num);
+ if (b_type == INVALID)
+ return 0;
+ if (b_type != NONE) { /* it didn't exist yet */
+ bp = create_button_info(items[label_idx], NULL, widget, b_type);
+ **bipp = bp;
+ *bipp = &bp->next;
+ }
+
+ /* create an entry for this item */
+ widget = create_pulldown_entry(menu_list[index].name,
+ menu_list[index].popup_widget,
+ items[label_idx],
+ accelerator_idx > 0 ? items[accelerator_idx] : NULL,
+ action,
+ &b_type);
+ bp = create_button_info(items[label_idx], action, widget, b_type);
+ **bipp = bp;
+ *bipp = &bp->next;
+ }
+ else { /* not a pulldown menu, but a simple command button */
+ command_call[0].closure = (XtPointer) action;
+ widget = XtVaCreateWidget(name, commandWidgetClass, parent,
+ XtNlabel, (XtArgVal)items[label_idx],
+ XtNx, resource.btn_side_spacing,
+ XtNy, (XtArgVal)*y_pos,
+ XtNborderWidth, resource.btn_border_width,
+ XtNcallback, (XtArgVal)command_call,
+ NULL);
+ bp = create_button_info(items[label_idx], action, widget, COMMAND_BUTTON);
+ **bipp = bp;
+ *bipp = &bp->next;
+ }
+#undef NAME_LEN
+ return width;
+}
+
+void
+scroll_x_panner(int x)
+{
+ static int old_x = 0;
+ if (panner != 0 && ABS(x - old_x) > 8) {
+ XtVaSetValues(panner, XtNsliderX, x, NULL);
+ old_x = x;
+ }
+}
+
+void
+scroll_y_panner(int y)
+{
+ static int old_y = 0;
+ if (panner != 0 && ABS(y - old_y) > 8) {
+ XtVaSetValues(panner, XtNsliderY, y, NULL);
+ old_y = y;
+ }
+}
+
+#ifdef USE_PANNER
+static void
+panner_cb(Widget widget, XtPointer closure, XtPointer report_ptr)
+{
+ XawPannerReport *report = (XawPannerReport *)report_ptr;
+ static int orig_x = 0, orig_y = 0;
+ int x = report->slider_x;
+ int y = report->slider_y;
+ static Dimension w, h;
+ static Arg arg_wh_clip[] = {
+ {XtNwidth, (XtArgVal) &w},
+ {XtNheight, (XtArgVal) &h},
+ };
+
+ UNUSED(closure);
+
+ XtGetValues(globals.widgets.clip_widget, arg_wh_clip, XtNumber(arg_wh_clip));
+
+ fprintf(stderr, "w: %d, h: %d, globals.page.w: %d, globals.page.h: %d\n",
+ w, h, globals.page.w, globals.page.h);
+ XtVaSetValues(widget,
+ XtNsliderWidth, w, XtNsliderHeight, h,
+ XtNcanvasWidth, globals.page.w, XtNcanvasHeight, globals.page.h,
+ NULL);
+
+ fprintf(stderr, "panner moved: %d, %d\n", report->slider_x, report->slider_y);
+ if (globals.widgets.x_bar != NULL)
+ XtCallCallbacks(globals.widgets.x_bar, XtNscrollProc, (XtPointer)(x - orig_x));
+ if (globals.widgets.y_bar != NULL)
+ XtCallCallbacks(globals.widgets.y_bar, XtNscrollProc, (XtPointer)(y - orig_y));
+ orig_x = x;
+ orig_y = y;
+}
+#endif /* USE_PANNER */
+
+void
+create_menu_buttons(Widget form, int *ret_panel_width)
+{
+ Dimension max_button_width = 0, curr_width;
+ Dimension y_pos;
+ struct button_info **bipp;
+ struct button_info *bp;
+ const char *c_ptr, *e_ptr;
+ int max_size;
+ int button_number = 0;
+ int menu_number = 0; /* number of menus created; passed through to create_pulldown_menu */
+
+ /* disable the magnifier in the panel: */
+ XtTranslations panel_translations = XtParseTranslationTable("#augment <ButtonPress>:");
+
+ XtAppAddActions(XtWidgetToApplicationContext(form), menu_actions, XtNumber(menu_actions));
+ /* add our own popdown-submenus() action to the default translations of this menu */
+ menu_accels = XtParseAcceleratorTable("<BtnUp>:MenuPopdown()notify()unhighlight()popdown-submenus()");
+
+ line_widget = XtVaCreateWidget("line", widgetClass, form,
+ XtNbackground, (XtArgVal)resource.fore_Pixel,
+ XtNwidth, (XtArgVal) 1,
+ XtNfromHoriz, (XtArgVal)globals.widgets.vport_widget,
+ XtNborderWidth, (XtArgVal)0,
+ XtNtop, (XtArgVal)XtChainTop,
+ XtNbottom, (XtArgVal)XtChainBottom,
+ XtNleft, (XtArgVal)XtChainRight,
+ XtNright, (XtArgVal)XtChainRight,
+ NULL);
+ panel_widget = XtVaCreateWidget("panel", compositeWidgetClass, form,
+ XtNborderWidth, (XtArgVal)0,
+ XtNfromHoriz, (XtArgVal)line_widget,
+ XtNtranslations, (XtArgVal)panel_translations,
+ XtNtop, (XtArgVal)XtChainTop,
+ XtNbottom, (XtArgVal)XtChainBottom,
+ XtNleft, (XtArgVal)XtChainRight,
+ XtNright, (XtArgVal)XtChainRight,
+ NULL);
+ menu_arrow_bitmap
+ = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
+ RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
+ (char *)menu_arrow_bits, MENU_ARROW_W, MENU_ARROW_H);
+
+ b_head = NULL;
+ bipp = &b_head;
+
+ *ret_panel_width = 0;
+ y_pos = resource.btn_top_spacing;
+
+#define FREE_LINE_ITEMS do { \
+ for (curr = 0; curr < item_count; curr++) { \
+ free(line_items[curr]); \
+ } \
+ free(line_items); \
+ } while (0)
+
+ for (c_ptr = resource.menu_translations;
+ c_ptr != NULL && *c_ptr != '\0';
+ c_ptr = e_ptr + 1) {
+ e_ptr = strchr(c_ptr, '\n');
+ if (e_ptr != NULL) {
+ char **line_items = NULL;
+ size_t len, curr, item_count = 0;
+
+ if (e_ptr == c_ptr) { /* single '\n' marks additional space between buttons */
+ y_pos += resource.btn_between_extra;
+ continue;
+ }
+ len = e_ptr - c_ptr;
+
+ if (++button_number > MAX_BUTTON_NUM) {
+ XDVI_WARNING((stderr, "Too many buttons (max=%d), skipping all from:\n\"%.*s\"",
+ MAX_BUTTON_NUM, (int)len, c_ptr));
+ break;
+ }
+
+ line_items = split_line(c_ptr, SEP_CHAR, 0, len, &item_count);
+ if (item_count < 3 && !(item_count > 1 && strcmp(line_items[1], "SEP") == 0)) {
+ XDVI_WARNING((stderr, "Too few separators \"%c\" in translations line:\n\"%.*s\" (skipping this line).\n",
+ SEP_CHAR, (int)len, c_ptr));
+ FREE_LINE_ITEMS;
+ continue;
+ }
+ curr_width = create_button(button_number,
+ &menu_number,
+ line_items,
+ item_count,
+ panel_widget,
+ &bipp,
+ &y_pos,
+ c_ptr, len);
+ if (curr_width == 0) { /* no button created */
+ FREE_LINE_ITEMS;
+ continue;
+ }
+ /* adjust max_button_width to this new entry */
+ if (curr_width > max_button_width)
+ max_button_width = curr_width;
+
+ FREE_LINE_ITEMS;
+ }
+ }
+
+#undef FREE_LINE_ITEMS
+
+ /* null-terminate button info */
+ *bipp = NULL;
+
+ max_size = xaw_get_pagelist_size();
+ if (max_size > max_button_width) {
+ max_button_width = max_size;
+ }
+
+ *ret_panel_width = max_button_width + 2 * (resource.btn_side_spacing + resource.btn_border_width);
+ TRACE_GUI((stderr, "panel_widget: w: %d", *ret_panel_width));
+ XtVaSetValues(panel_widget, XtNwidth, (XtArgVal)*ret_panel_width, NULL);
+ ++(*ret_panel_width);
+ my_panel_width = *ret_panel_width; /* make it available */
+
+ for (bp = b_head; bp != NULL; bp = bp->next) {
+ if (bp->type == MENU_BUTTON || bp->type == COMMAND_BUTTON) {
+ TRACE_GUI((stderr, "bp->widget: w: %d", max_button_width));
+ XtVaSetValues(bp->widget, XtNwidth, (XtArgVal)max_button_width, NULL);
+ XtManageChild(bp->widget);
+ }
+ }
+
+ my_y_pos = y_pos - resource.btn_between_spacing + resource.btn_top_spacing + 2 * resource.btn_border_width;
+ initialize_tick_marks();
+#ifdef USE_PANNER
+ {
+ static Dimension w, h;
+ static Arg arg_wh_clip[] = {
+ {XtNwidth, (XtArgVal) &w},
+ {XtNheight, (XtArgVal) &h},
+ };
+ XtGetValues(globals.widgets.clip_widget, arg_wh_clip, XtNumber(arg_wh_clip));
+
+ fprintf(stderr, "w: %d, h: %d, globals.page.w: %d, globals.page.h: %d\n",
+ w, h, globals.page.w, globals.page.h);
+ if (w == 0)
+ w = globals.page.w - 2;
+ if (h == 0)
+ h = globals.page.h - 2;
+ panner = XtVaCreateManagedWidget("panner", pannerWidgetClass, panel_widget,
+ XtNx, resource.btn_side_spacing,
+ XtNy, my_y_pos,
+ XtNheight, 60,
+ XtNwidth, max_button_width,
+ XtNshadowThickness, 0,
+ XtNsliderWidth, w,
+ XtNsliderHeight, h,
+ XtNcanvasWidth, globals.page.w,
+ XtNcanvasHeight, globals.page.h,
+ XtNsliderX, 5,
+ XtNsliderY, 7,
+ XtNinternalSpace, 0,
+ NULL);
+ }
+ my_y_pos += 60 + resource.btn_top_spacing + 2 * resource.btn_border_width;
+ XtAddCallback(panner, XtNreportCallback, panner_cb, (XtPointer)NULL);
+
+#endif /* USE_PANNER */
+
+}
+#endif /* NEW_MENU_CREATION */
+
+
+void
+set_button_panel_height(XtArgVal h)
+{
+ TRACE_GUI((stderr, "line_widget: h %d", (int)h));
+ XtVaSetValues(line_widget, XtNheight, h, NULL);
+ XtManageChild(line_widget);
+
+ XtVaSetValues(panel_widget, XtNheight, h, NULL);
+ XtManageChild(panel_widget);
+}
+
+/****************************************************************************
+ * Action handling code.
+ */
+
+
+static void
+handle_destroy_buttons(Widget widget, XtPointer client_data, XtPointer call_data)
+{
+ int panel_width;
+ Dimension window_w, window_h;
+
+ UNUSED(widget);
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ if (--destroy_count != 0) {
+ return;
+ }
+ XtVaSetValues(globals.widgets.vport_widget, XtNresizable, (XtArgVal)True, NULL);
+ XtVaGetValues(globals.widgets.form_widget,
+ XtNwidth, &window_w,
+ XtNheight, &window_h,
+ NULL);
+
+ if ((resource.expert_mode & XPRT_SHOW_BUTTONS) == 0) {
+ /* destroy buttons */
+ TRACE_GUI((stderr, "globals.widgets.vport_widget: h %d, w %d", window_w, window_h));
+ XtVaSetValues(globals.widgets.vport_widget, XtNwidth, window_w, XtNheight, window_h, NULL);
+ }
+ else {
+ create_menu_buttons(globals.widgets.form_widget, &panel_width);
+ window_w -= panel_width;
+ TRACE_GUI((stderr, "globals.widgets.vport_widget: h %d, w %d", window_h, window_w));
+ XtVaSetValues(globals.widgets.vport_widget, XtNwidth, window_w, XtNheight, window_h, NULL);
+ set_button_panel_height((XtArgVal) window_h);
+ }
+}
+
+
+static void
+reconfig_window(void) {
+ Dimension x_top, y_top, h_top, w_top;
+ XWindowChanges sizeconfigure;
+ int sizeconfiguremask;
+
+ /* brute-force method to bring the scrollbars back. Apparently a single XConfigureWindow()
+ isn't enough to get the scrollbars back, we actually need to move the window a bit,
+ and then move it back. */
+ sizeconfiguremask = CWWidth | CWHeight;
+ XtVaGetValues(globals.widgets.top_level, XtNx, &x_top, XtNy, &y_top, XtNheight, &h_top, XtNwidth, &w_top, NULL);
+ sizeconfigure.width = w_top + 1;
+ sizeconfigure.height = h_top + 1;
+ XConfigureWindow(DISP, XtWindow(globals.widgets.top_level), sizeconfiguremask, &sizeconfigure);
+ sizeconfigure.width = w_top;
+ sizeconfigure.height = h_top;
+ XConfigureWindow(DISP, XtWindow(globals.widgets.top_level), sizeconfiguremask, &sizeconfigure);
+}
+
+/* toggle scrollbars to state `visible' */
+void
+toggle_scrollbars(void)
+{
+ Widget v_bar = XtNameToWidget(globals.widgets.vport_widget, "vertical");
+ Widget h_bar = XtNameToWidget(globals.widgets.vport_widget, "horizontal");
+ static Dimension bar_thick;
+ static Boolean v_bar_mapped = False, h_bar_mapped = False;
+ static Boolean initialized = False;
+
+ Boolean make_v_bar_visible = False;
+ Boolean make_v_bar_invisible = False;
+
+ Boolean make_h_bar_visible = False;
+ Boolean make_h_bar_invisible = False;
+
+ if (v_bar != 0) {
+ int test_v = 0;
+ XtVaGetValues(v_bar, XtNwidth, &test_v, NULL);
+ if (test_v > 1)
+ v_bar_mapped = True;
+ }
+ if (h_bar != 0) {
+ int test_h = 0;
+ XtVaGetValues(h_bar, XtNheight, &test_h, NULL);
+ if (test_h > 1)
+ h_bar_mapped = True;
+ }
+
+ if (!initialized) {
+ v_bar_mapped = h_bar_mapped = (resource.expert_mode & XPRT_SHOW_SCROLLBARS) != 0;
+ initialized = True;
+ if (v_bar != 0)
+ XtVaGetValues(v_bar, XtNwidth, &bar_thick, NULL);
+ else if (h_bar != 0)
+ XtVaGetValues(h_bar, XtNheight, &bar_thick, NULL);
+ else
+ bar_thick = 15; /* FIXME */
+ }
+
+ if ((resource.expert_mode & XPRT_SHOW_SCROLLBARS) == 0) {
+ if (v_bar_mapped)
+ make_v_bar_invisible = True;
+ if (h_bar_mapped)
+ make_h_bar_invisible = True;
+ }
+ else {
+ if (!v_bar_mapped)
+ make_v_bar_visible = True;
+ if (!h_bar_mapped)
+ make_h_bar_visible = True;
+ }
+
+ if (make_h_bar_visible || make_v_bar_visible) {
+ if (make_h_bar_visible && h_bar != 0) {
+ TRACE_GUI((stderr, "h_bar: h %d", bar_thick));
+ XtVaSetValues(h_bar, XtNheight, bar_thick, XtNx, bar_thick, XtNy, 0, XtNborderWidth, 1, NULL);
+ XtManageChild(h_bar);
+ h_bar_mapped = True;
+ }
+ if (make_v_bar_visible && v_bar != 0) {
+ TRACE_GUI((stderr, "v_bar: w %d", bar_thick));
+ XtVaSetValues(v_bar, XtNwidth, bar_thick, XtNx, 0, XtNy, bar_thick, XtNborderWidth, 1, NULL);
+ XtManageChild(v_bar);
+ v_bar_mapped = True;
+ }
+ if (h_bar != 0 || v_bar != 0) { /* need to reconfigure screen */
+ reconfig_window();
+ }
+ }
+ else if (make_h_bar_invisible || make_v_bar_invisible) {
+ if (make_h_bar_invisible && h_bar != 0) {
+ XtUnmanageChild(h_bar);
+ XtVaSetValues(h_bar, XtNheight, 1, XtNx, 0, XtNy, 0, XtNborderWidth, 0, NULL);
+ h_bar_mapped = False;
+ }
+ if (make_v_bar_invisible && v_bar != 0) {
+ XtUnmanageChild(v_bar);
+ XtVaSetValues(v_bar, XtNwidth, 1, XtNy, 0, XtNy, 0, XtNborderWidth, 0, NULL);
+ v_bar_mapped = False;
+ }
+ if (h_bar != 0 || v_bar != 0) { /* need to reconfigure screen */
+ reconfig_window();
+ }
+ }
+
+}
+
+void
+toggle_buttons(void)
+{
+ static Boolean buttons_active = False;
+ static Boolean initialized = False;
+ Dimension window_w, window_h;
+
+
+ Boolean make_buttons_visible = False;
+ Boolean make_buttons_invisible = False;
+
+ int panel_width;
+
+ if (!initialized) {
+ buttons_active = (resource.expert_mode & XPRT_SHOW_BUTTONS) != 0;
+ initialized = True;
+ }
+
+ if ((resource.expert_mode & XPRT_SHOW_BUTTONS) == 0) {
+ if (buttons_active)
+ make_buttons_invisible = True;
+ }
+ else {
+ if (!buttons_active)
+ make_buttons_visible = True;
+ }
+
+ if (make_buttons_visible) {
+ if (destroy_count != 0) {
+ return;
+ }
+
+ create_menu_buttons(globals.widgets.form_widget, &panel_width);
+ XtVaGetValues(globals.widgets.form_widget,
+ XtNwidth, &window_w,
+ XtNheight, &window_h,
+ NULL);
+ XtVaSetValues(globals.widgets.vport_widget, XtNresizable, (XtArgVal)True, NULL);
+ window_w -= panel_width;
+ TRACE_GUI((stderr, "globals.widgets.vport_widget: w: %d, h: %d", window_w, window_h));
+ XtVaSetValues(globals.widgets.vport_widget, XtNwidth, window_w, XtNheight, window_h, NULL);
+ set_button_panel_height((XtArgVal) window_h);
+ buttons_active = True;
+ }
+ else if (make_buttons_invisible) {
+ if (destroy_count != 0) {
+ return;
+ }
+ /* this counts the callback calls; 1 for the panel, 1 for the line */
+ destroy_count = 2;
+
+ XtAddCallback(panel_widget, XtNdestroyCallback,
+ handle_destroy_buttons, (XtPointer)0);
+ XtAddCallback(panel_widget, XtNdestroyCallback,
+ handle_destroy_pagelist, (XtPointer)0);
+ XtAddCallback(line_widget, XtNdestroyCallback,
+ handle_destroy_buttons, (XtPointer)0);
+ XtDestroyWidget(panel_widget);
+ XtDestroyWidget(line_widget);
+ buttons_active = False;
+/* window_w += get_panel_width(); */
+
+ while (b_head != NULL) {
+ struct button_info *bp = b_head;
+ struct xdvi_action *action;
+
+ b_head = bp->next;
+ free(bp->label);
+ /* free bp->action */
+ for (action = bp->action; action != NULL;) {
+ struct xdvi_action *act2 = action;
+ action = act2->next;
+ if (act2->num_params > 0) {
+ free(act2->param);
+ }
+ free(act2);
+ }
+ free(bp);
+ }
+ }
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* ifndef MOTIF */
diff --git a/Build/source/texk/xdvik/gui/xaw_menu.h b/Build/source/texk/xdvik/gui/xaw_menu.h
new file mode 100644
index 00000000000..750f79cfeb5
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xaw_menu.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2001-2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef XAW_MENU_H_
+#define XAW_MENU_H_
+
+#ifdef NEW_MENU_CREATION
+#include "menu.h"
+#endif /* NEW_MENU_CREATION */
+
+#ifndef MOTIF
+
+#ifdef NEW_MENU_CREATION
+extern void xaw_set_button_state(struct button_elems *elems, Boolean on);
+extern void xaw_initialize_menu_bitmaps(void);
+extern Widget xaw_create_menu_widgets(Widget parent);
+extern void xaw_create_menu(struct button_info *items, Widget parent, int *ret_width);
+extern void xaw_set_button_state(struct button_elems *elems, Boolean on);
+
+extern Pixmap menu_check_bitmap;
+extern Pixmap menu_uncheck_bitmap;
+#else
+extern void create_menu_buttons(Widget menu_bar, int *ret_panel_width);
+extern void toggle_menu(int val, XtActionProc proc);
+#endif /* NEW_MENU_CREATION */
+
+extern void SubMenuHandleEvent(XtAppContext app, XEvent *event);
+extern void filehist_menu_add_entry(const char *filename);
+extern int get_panel_width(void);
+
+extern void toggle_tick(Boolean val, Widget w);
+extern void set_button_panel_height(XtArgVal);
+extern void filehist_menu_refresh(void);
+
+extern void xaw_create_pagelist(void);
+extern void toggle_scrollbars(void);
+extern void toggle_buttons(void);
+extern void scroll_y_panner(int y);
+extern void scroll_x_panner(int x);
+#endif /* not MOTIF */
+
+#endif /* XAW_MENU_H_ */
diff --git a/Build/source/texk/xdvik/gui/xicon.c b/Build/source/texk/xdvik/gui/xicon.c
new file mode 100644
index 00000000000..15faa32442a
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xicon.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2001 Marcin Dalecki
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Implement a nice and well behaved application icon.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "xicon.h"
+#include "util.h"
+#include "xdvi-debug.h"
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#include <X11/Xfuncs.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+
+#ifdef MOTIF
+# include <Xm/XmStrDefs.h>
+#endif
+
+#if defined(HAVE_X11_XPM_H)
+# include <X11/xpm.h>
+#elif defined(HAVE_XPM_H)
+# include <xpm.h>
+#elif defined(HAVE_XM_XPMP_H)
+# include <Xm/XpmP.h>
+#endif
+
+#include "xdvi.icon"
+#include "pixmaps/xdvi32x32.xpm"
+#include "pixmaps/xdvi16x16.xpm"
+#include "pixmaps/xdvi48x48.xpm"
+void
+add_icon(Widget top_level,
+ String title_name,
+ String icon_name)
+{
+#if !HAVE_XPM
+
+ static Arg args[] = {
+ {XtNiconX, (XtArgVal) 0},
+ {XtNiconY, (XtArgVal) 0},
+ };
+ static Pixmap icon_pm;
+ static Arg temp_args4 = { XtNiconPixmap, (XtArgVal) &icon_pm };
+
+ UNUSED(xdvi16x16_xpm);
+ UNUSED(xdvi32x32_xpm);
+ UNUSED(xdvi48x48_xpm);
+
+ if (resource.icon_geometry != NULL) {
+ int junk;
+
+ (void)XGeometry(DISP, XScreenNumberOfScreen(SCRN),
+ resource.icon_geometry, "",
+ 0, 0, 0, 0, 0,
+ (int *)&args[0].value,
+ (int *)&args[1].value,
+ &junk,
+ &junk);
+ XtSetValues(top_level, args, XtNumber(args));
+ }
+ /* Set icon pixmap */
+ XtGetValues(top_level, &temp_args4, 1);
+ if (icon_pm == (Pixmap) 0) {
+ temp_args4.value =
+ (XtArgVal)XCreateBitmapFromData(DISP,
+ RootWindowOfScreen(SCRN),
+ (const char *)xdvi_bits,
+ xdvi_width,
+ xdvi_height);
+ XtSetValues(top_level, &temp_args4, 1);
+ }
+#else /* HAVE_XPM */
+
+ /* Use Pixmaps, looking much nicer. */
+
+ static Pixmap icon = 0;
+ static Pixmap icon_mask = 0;
+ static const char **pixmap_data = xdvi32x32_xpm;
+ XIconSize *size;
+ int number_sizes;
+ Display *dsp;
+ Screen *scr;
+ XpmAttributes attr;
+
+ UNUSED(xdvi_bits);
+ /*
+ * get the icon size preferred by the window manager
+ */
+ if (XGetIconSizes(XtDisplay(top_level), RootWindowOfScreen(SCRN),
+ &size, &number_sizes) != 0) {
+ if (number_sizes > 0) {
+ if (size->max_height >= 48 && size->max_height >= 48)
+ pixmap_data = xdvi48x48_xpm;
+ else if (size->max_height >= 32 && size->max_height >= 32)
+ pixmap_data = xdvi32x32_xpm;
+ else if (size->max_height >= 16 && size->max_height >= 16)
+ pixmap_data = xdvi16x16_xpm;
+ }
+ }
+
+ dsp = XtDisplay(top_level);
+ scr = XtScreen(top_level);
+
+ attr.valuemask = 0L;
+ attr.valuemask = XpmCloseness | XpmReturnPixels | XpmColormap | XpmDepth | XpmVisual;
+ attr.closeness = 65535; /* accuracy isn't crucial */
+ /* use the same visual/colormap/depth as main window, else BadMatch ... */
+ attr.visual = G_visual;
+ attr.colormap = G_colormap;
+ attr.depth = G_depth;
+
+ if (!icon) {
+ Window rootWindow = XtWindow(globals.widgets.top_level);
+ ASSERT(rootWindow != 0, "");
+ XpmCreatePixmapFromData(dsp, rootWindow, (char **)pixmap_data,
+ &icon, &icon_mask, &attr);
+ }
+
+# ifdef MOTIF
+ XtVaSetValues(top_level, XmNiconPixmap, icon, XmNiconMask, icon_mask, NULL);
+# else
+ XtVaSetValues(top_level, XtNiconPixmap, icon, XtNiconMask, icon_mask, NULL);
+# endif
+
+ XpmFreeAttributes(&attr);
+#endif
+
+ {
+ /* code locality ... */
+ static Arg args[] = {
+ { XtNtitle, (XtArgVal) 0 },
+ { XtNiconName, (XtArgVal) 0 },
+ { XtNinput, (XtArgVal) True },
+ };
+
+ args[0].value = (XtArgVal)title_name;
+ args[1].value = (XtArgVal)icon_name;
+ XtSetValues(top_level, args, XtNumber(args));
+ }
+}
diff --git a/Build/source/texk/xdvik/gui/xicon.h b/Build/source/texk/xdvik/gui/xicon.h
new file mode 100644
index 00000000000..47991b5b092
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xicon.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2001 Marcin Dalecki
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef XICON_H_
+#define XICON_H_
+
+extern void add_icon(Widget toplevel, String title_name, String icon_name);
+
+#endif /* XICON_H_ */
diff --git a/Build/source/texk/xdvik/gui/xlwradio.c b/Build/source/texk/xdvik/gui/xlwradio.c
new file mode 100644
index 00000000000..27bb14c3eb2
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xlwradio.c
@@ -0,0 +1,677 @@
+/* adapted from xlwradio.c in the XEmacs distribution.
+ Changes are Copyright (C) 2002-2004 the xdvik development team.
+
+ Note SU: This widget doesn't work with Xaw3d, and I have little
+ inclination to make it work - the design would need to be utterly
+ different, e.g. the radio would need to be a diamond instead of a
+ circle, since 3d-shadowed circles don't look circular; colormap
+ issues would need to be settled, etc. And besides, I don't like Xaw3d ;)
+
+ So instead, the caller should just do:
+
+ myWidget = XtVaCreateManagedWidget("foo",
+ #ifdef XAW
+ radioWidgetClass,
+ #else
+ toggleWidgetClass,
+ #endif
+ ... arglist ...);
+
+ Feel free to submit patches if you want this implemented.
+
+ Original copyright follows:
+*/
+
+/* Radio Widget for XEmacs.
+ Copyright (C) 1999 Edward A. Falk
+
+This file is part of XEmacs.
+
+XEmacs is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Synched up with: Radio.c 1.1 */
+
+/*
+ * Radio.c - Radio button widget
+ *
+ * Author: Edward A. Falk
+ * falk@falconer.vip.best.com
+ *
+ * Date: June 30, 1997
+ *
+ *
+ * Overview: This widget is identical to the Toggle widget in behavior,
+ * but completely different in appearance. This widget looks like a small
+ * diamond-shaped button with a label to the right.
+ *
+ * To make this work, we subclass the Toggle widget to inherit its behavior
+ * and to inherit the label-drawing function from which Toggle is
+ * subclassed. We then completely replace the Expose, Set, Unset
+ * and Highlight member functions.
+ *
+ * The Set and Unset actions are slightly unorthodox. In Toggle's
+ * ClassInit function, Toggle searches the Command actions list and
+ * "steals" the Set and Unset functions, caching pointers to them in its
+ * class record. It then calls these functions from its own ToggleSet
+ * and Toggle actions.
+ *
+ * We, in turn, override the Set() and Unset() actions in our own ClassRec.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "xdvi-debug.h"
+#include "util.h"
+#include "xaw_bitmaps.h" /* bitmaps for radio/checkbuttons */
+
+#include "xlwradioP.h"
+
+#ifndef MOTIF /* entire file */
+
+#include <stdio.h>
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+/* #include "../src/xmu.h" */
+
+#define BOX_SIZE 16
+#define PIXMAP_OFFSET 2 /* additional space between pixmap and label */
+
+#ifndef UNUSED
+# define UNUSED(x) ((void)(x))
+#endif
+
+#ifndef MAX
+# define MAX(i, j) ( (i) > (j) ? (i) : (j) )
+#endif
+
+
+#define rclass(w) ((RadioWidgetClass)((w)->core.widget_class))
+
+
+#ifdef _ThreeDP_h
+#define swid(rw) ((rw)->threeD.shadow_width)
+#else
+#define swid(rw) ((rw)->core.border_width)
+#endif
+
+#define bsize(rw) (rclass(rw)->radio_class.dsize)
+#define bs(rw) (bsize(rw) + PIXMAP_OFFSET + 2*swid(rw))
+
+/****************************************************************
+ *
+ * Full class record constant
+ *
+ ****************************************************************/
+
+/* The translations table from Toggle do not need to be
+ * overridden by Radio
+ */
+
+
+/* Member functions */
+
+static void RadioInit (Widget, Widget, ArgList, Cardinal *);
+static void RadioExpose (Widget, XEvent *, Region);
+static void RadioResize (Widget);
+static void RadioDestroy (Widget);
+static void RadioClassInit (void);
+static void RadioClassPartInit (WidgetClass);
+static Boolean RadioSetValues (Widget, Widget, Widget, ArgList, Cardinal *);
+static void DrawDiamond (Widget);
+static XtGeometryResult RadioQueryGeometry (Widget, XtWidgetGeometry *,
+ XtWidgetGeometry *);
+
+/* Action procs */
+
+static void RadioHighlight (Widget, XEvent *, String *, Cardinal *);
+static void RadioUnhighlight (Widget, XEvent *, String *, Cardinal *);
+
+/* internal privates */
+
+static void RadioSize (RadioWidget, Dimension *, Dimension *);
+
+/* The actions table from Toggle is almost perfect, but we need
+ * to override Highlight, Set, and Unset.
+ */
+
+static XtActionsRec actionsList[] =
+{
+ {"highlight", RadioHighlight},
+ {"unhighlight", RadioUnhighlight},
+};
+
+#define offset(field) XtOffset(RadioWidget, radio.field)
+
+static XtResource resources[] = {
+ {XtNisRadio, XtCIsRadio, XtRBoolean, sizeof(Boolean),
+ offset(isRadio), XtRImmediate, (XtPointer)True },
+};
+#undef offset
+
+#define SuperClass ((ToggleWidgetClass)&toggleClassRec)
+
+RadioClassRec radioClassRec = {
+ {
+ (WidgetClass) SuperClass, /* superclass */
+ "Radio", /* class_name */
+ sizeof(RadioRec), /* size */
+ RadioClassInit, /* class_initialize */
+ RadioClassPartInit, /* class_part_initialize */
+ FALSE, /* class_inited */
+ RadioInit, /* initialize */
+ NULL, /* initialize_hook */
+ XtInheritRealize, /* realize */
+ actionsList, /* actions */
+ XtNumber(actionsList), /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* resource_count */
+ NULLQUARK, /* xrm_class */
+ TRUE, /* compress_motion */
+ TRUE, /* compress_exposure */
+ TRUE, /* compress_enterleave */
+ FALSE, /* visible_interest */
+ RadioDestroy, /* destroy */
+ RadioResize, /* resize */
+ RadioExpose, /* expose */
+ RadioSetValues, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ XtInheritTranslations, /* tm_table */
+ RadioQueryGeometry, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator */
+ NULL /* extension */
+ }, /* CoreClass fields initialization */
+ {
+ XtInheritChangeSensitive /* change_sensitive */
+#ifndef HAVE_OLD_XAW
+ , NULL
+#endif
+ }, /* SimpleClass fields initialization */
+#ifdef _ThreeDP_h
+ {
+ XtInheritXaw3dShadowDraw /* field not used */
+ }, /* ThreeDClass fields initialization */
+#endif
+ {
+ 0 /* field not used */
+ }, /* LabelClass fields initialization */
+ {
+ 0 /* field not used */
+ }, /* CommandClass fields initialization */
+ {
+ RadioSet, /* Set Procedure. */
+ RadioUnset, /* Unset Procedure. */
+ NULL /* extension. */
+ }, /* ToggleClass fields initialization */
+ {
+ BOX_SIZE,
+ DrawDiamond, /* draw procedure */
+ None, /* selected radiobutton */
+ None, /* unselected radiobutton */
+ None, /* selected menubutton */
+ None, /* unselected menubutton */
+ NULL /* extension. */
+ } /* RadioClass fields initialization */
+};
+
+ /* for public consumption */
+WidgetClass radioWidgetClass = (WidgetClass) &radioClassRec;
+
+
+
+
+
+
+/****************************************************************
+ *
+ * Class Methods
+ *
+ ****************************************************************/
+
+static void
+RadioClassInit (void)
+{
+ XawInitializeWidgetSet();
+}
+
+static void
+RadioClassPartInit (WidgetClass class)
+{
+ RadioWidgetClass c = (RadioWidgetClass) class;
+ RadioWidgetClass super = (RadioWidgetClass)c->core_class.superclass;
+
+ if( c->radio_class.drawDiamond == NULL ||
+ c->radio_class.drawDiamond == XtInheritDrawDiamond )
+ {
+ c->radio_class.drawDiamond = super->radio_class.drawDiamond;
+ }
+
+}
+
+
+
+
+static void
+RadioInit (Widget request,
+ Widget new,
+ ArgList args,
+ Cardinal *num_args)
+{
+ RadioWidget rw = (RadioWidget) new;
+ RadioWidget rw_req = (RadioWidget) request;
+ Dimension w,h;
+
+ UNUSED(args);
+ UNUSED(num_args);
+
+ /* FIXME: should pixmap initialization be here?? */
+
+ /* Select initial size for the widget */
+ if( rw_req->core.width == 0 || rw_req->core.height == 0 ) {
+ RadioSize(rw, &w,&h);
+ if( rw_req->core.width == 0 )
+ rw->core.width = w;
+ if( rw_req->core.height == 0 )
+ rw->core.height = h;
+ rw->core.widget_class->core_class.resize(new);
+ }
+ /*
+ FIXME: access to XtWindow(rw) fails in the init method, so
+ I moved the bitmap creation here -- is there a better way??
+ */
+ /* create pixmaps */
+ rclass(rw)->radio_class.sel_radio
+ = XCreateBitmapFromData(XtDisplay(rw), RootWindowOfScreen(XtScreen(rw)),
+ (char *)button_radio_on_bits, BUTTON_BITMAP_W, BUTTON_BITMAP_H);
+ rclass(rw)->radio_class.unsel_radio
+ = XCreateBitmapFromData(XtDisplay(rw), RootWindowOfScreen(XtScreen(rw)),
+ (char *)button_radio_off_bits, BUTTON_BITMAP_W, BUTTON_BITMAP_H);
+ rclass(rw)->radio_class.sel_menu
+ = XCreateBitmapFromData(XtDisplay(rw), RootWindowOfScreen(XtScreen(rw)),
+ (char *)button_check_on_bits, BUTTON_BITMAP_W, BUTTON_BITMAP_H);
+ rclass(rw)->radio_class.unsel_menu
+ = XCreateBitmapFromData(XtDisplay(rw), RootWindowOfScreen(XtScreen(rw)),
+ (char *)button_check_off_bits, BUTTON_BITMAP_W, BUTTON_BITMAP_H);
+}
+
+/* Function Name: RadioDestroy
+ * Description: Destroy Callback for radio widget.
+ * Arguments: w - the radio widget that is being destroyed.
+ * Returns: none.
+ */
+
+static void
+RadioDestroy (Widget w)
+{
+ RadioWidget rw = (RadioWidget)w;
+ /* de-allocate bitmaps */
+ XFreePixmap(XtDisplay(w), rclass(rw)->radio_class.sel_radio);
+ XFreePixmap(XtDisplay(w), rclass(rw)->radio_class.unsel_radio);
+ XFreePixmap(XtDisplay(w), rclass(rw)->radio_class.sel_menu);
+ XFreePixmap(XtDisplay(w), rclass(rw)->radio_class.unsel_menu);
+}
+
+
+/* React to size change from manager. Label widget will compute some internal
+ * stuff, but we need to override. This code requires knowledge of the
+ * internals of the Label widget.
+ */
+
+static void
+RadioResize (Widget w)
+{
+ RadioWidget rw = (RadioWidget)w;
+
+ /* call parent resize proc */
+ SuperClass->core_class.resize(w);
+
+ /* override label offset */
+
+ switch( rw->label.justify ) {
+ case XtJustifyLeft:
+ rw->label.label_x += (bs(rw) + rw->label.internal_width);
+ break;
+ case XtJustifyRight:
+ break;
+ case XtJustifyCenter:
+ default:
+ rw->label.label_x += (bs(rw) + rw->label.internal_width)/2;
+ break;
+ }
+}
+
+
+/*
+ * Repaint the widget window.
+ */
+
+static void
+RadioExpose (Widget w,
+ XEvent *event,
+ Region region)
+{
+ RadioWidget rw = (RadioWidget) w;
+ Display *dpy = XtDisplay(w);
+ Window win = XtWindow(w);
+ GC gc;
+ Pixmap left_bitmap;
+ extern WidgetClass labelWidgetClass;
+
+ /* Note: the Label widget examines the region to decide if anything
+ * needs to be drawn. I'm not sure that this is worth the effort,
+ * but it bears thinking on.
+ */
+
+ /* Command widget may sometimes override the label GC in order
+ * to draw inverse video. We don't use inverse video, so we need
+ * to restore the label's normal GC.
+ */
+ rw->label.normal_GC = rw->command.normal_GC;
+
+
+ /* Let label widget draw the label. If there was an lbm_x
+ * field, we could let Label draw the bitmap too. But there
+ * isn't, so we need to temporarily remove the bitmap and
+ * draw it ourself later.
+ */
+ left_bitmap = rw->label.left_bitmap;
+ rw->label.left_bitmap = None;
+ labelWidgetClass->core_class.expose(w,event,region);
+ rw->label.left_bitmap = left_bitmap;
+
+ /* now manually draw the left bitmap. TODO: 3-d look, xaw-xpm */
+ gc = XtIsSensitive(w) ? rw->label.normal_GC : rw->label.gray_GC;
+ if( left_bitmap != None && rw->label.lbm_width > 0 )
+ {
+ /* TODO: handle pixmaps */
+ XCopyPlane(dpy, left_bitmap, win, gc,
+ 0,0, rw->label.lbm_width, rw->label.lbm_height,
+ (int) rw->label.internal_width*2 + bs(rw),
+ (int) rw->label.internal_height + rw->label.lbm_y,
+ 1UL);
+ }
+ DrawDiamond(w);
+ /* Finally, the button itself */
+ ((RadioWidgetClass)(w->core.widget_class))->radio_class.drawDiamond(w);
+}
+
+
+
+
+/************************************************************
+ *
+ * Set specified arguments into widget
+ *
+ ***********************************************************/
+
+
+/* ARGSUSED */
+static Boolean
+RadioSetValues (Widget current,
+ Widget request,
+ Widget new,
+ ArgList args,
+ Cardinal *num_args)
+{
+ RadioWidget oldrw = (RadioWidget) current;
+ RadioWidget newrw = (RadioWidget) new;
+
+ UNUSED(request);
+ UNUSED(args);
+ UNUSED(num_args);
+
+ /* Need to find out if the size of the widget changed. Set new size
+ * if it did and resize is permitted. One way to determine of the
+ * widget changed size would be to scan the args list. Another way
+ * is to compare the old and new widgets and see if any of several
+ * size-related fields have been changed. The Label widget chose the
+ * former method, but I choose the latter.
+ */
+
+ if( newrw->label.resize &&
+ ( newrw->core.width != oldrw->core.width ||
+ newrw->core.height != oldrw->core.height ||
+ newrw->core.border_width != oldrw->core.border_width ) )
+ {
+ RadioSize(newrw, &newrw->core.width, &newrw->core.height);
+ }
+
+ /* The label set values routine can resize the widget. We need to
+ * recalculate if this is true.
+ */
+ if (newrw->label.label_x != oldrw->label.label_x)
+ {
+ RadioResize (new);
+ }
+ return FALSE;
+}
+
+static XtGeometryResult
+RadioQueryGeometry (Widget w,
+ XtWidgetGeometry *intended,
+ XtWidgetGeometry *preferred)
+{
+ RadioWidget rw = (RadioWidget) w;
+
+ preferred->request_mode = CWWidth | CWHeight;
+ RadioSize(rw, &preferred->width, &preferred->height);
+
+ if ( ((intended->request_mode & (CWWidth | CWHeight))
+ == (CWWidth | CWHeight)) &&
+ intended->width == preferred->width &&
+ intended->height == preferred->height)
+ return XtGeometryYes;
+ else if (preferred->width == w->core.width &&
+ preferred->height == w->core.height)
+ return XtGeometryNo;
+ else
+ return XtGeometryAlmost;
+}
+
+
+
+
+
+/************************************************************
+ *
+ * Action Procedures
+ *
+ ************************************************************/
+
+/*
+ * Draw the highlight border around the widget. The Command widget
+ * did this by drawing through a mask. We do it by just drawing the
+ * border.
+ */
+
+static void
+DrawHighlight (Widget w,
+ GC gc)
+{
+ RadioWidget rw = (RadioWidget)w;
+ XRectangle rects[4];
+ Dimension ht = rw->command.highlight_thickness;
+
+ if( ht <= 0 ||
+ ht > rw->core.width/2 ||
+ ht > rw->core.height/2 )
+ return;
+
+ if( ! XtIsRealized(w) )
+ return;
+
+ rects[0].x = 0; rects[0].y = 0;
+ rects[0].width = rw->core.width; rects[0].height = ht;
+ rects[1].x = 0; rects[1].y = rw->core.height - ht;
+ rects[1].width = rw->core.width; rects[1].height = ht;
+ rects[2].x = 0; rects[2].y = ht;
+ rects[2].width = ht; rects[2].height = rw->core.height - ht*2;
+ rects[3].x = rw->core.width - ht; rects[3].y = ht;
+ rects[3].width = ht; rects[3].height = rw->core.height - ht*2;
+ XFillRectangles( XtDisplay(w), XtWindow(w), gc, rects, 4);
+}
+
+static void
+RadioHighlight (Widget w,
+ XEvent *event,
+ String *params,
+ Cardinal *num_params)
+{
+ RadioWidget rw = (RadioWidget)w;
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ DrawHighlight(w, rw->command.normal_GC);
+}
+
+
+static void
+RadioUnhighlight (Widget w,
+ XEvent *event,
+ String *params,
+ Cardinal *num_params)
+{
+ RadioWidget rw = (RadioWidget)w;
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ DrawHighlight(w, rw->command.inverse_GC);
+}
+
+
+void
+RadioSet (Widget w,
+ XEvent *event,
+ String *params,
+ Cardinal *num_params)
+{
+ RadioWidget rw = (RadioWidget)w;
+ RadioWidgetClass class = (RadioWidgetClass) w->core.widget_class;
+
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if( rw->command.set )
+ return;
+
+ rw->command.set = TRUE;
+ if( XtIsRealized(w) )
+ class->radio_class.drawDiamond(w);
+}
+
+
+void
+RadioUnset (Widget w,
+ XEvent *event,
+ String *params,
+ Cardinal *num_params)
+{
+ RadioWidget rw = (RadioWidget)w;
+ RadioWidgetClass class = (RadioWidgetClass) w->core.widget_class;
+
+ UNUSED(event);
+ UNUSED(params);
+ UNUSED(num_params);
+
+ if( ! rw->command.set )
+ return;
+
+ rw->command.set = FALSE;
+ if( XtIsRealized(w) )
+ class->radio_class.drawDiamond(w);
+}
+
+
+
+
+/************************************************************
+ *
+ * Internal Procedures
+ *
+ ************************************************************/
+
+
+/* Size of widget. Width is size of box plus width of border around
+ * box plus width of label plus three margins plus the size of the left
+ * bitmap, if any. Height is max(box,bitmap,label) plus two margins.
+ */
+
+static void
+RadioSize (RadioWidget rw,
+ Dimension *w,
+ Dimension *h)
+{
+ *w = rw->label.label_width + bs(rw) + LEFT_OFFSET(rw) +
+ 3 * rw->label.internal_width;
+ *h = MAX( rw->label.label_height, bs(rw) ) +
+ 2 * rw->label.internal_width;
+}
+
+
+static void
+DrawDiamond(Widget w)
+{
+ RadioWidget rw = (RadioWidget) w;
+ Display *dpy = XtDisplay(w);
+ Window win = XtWindow(w);
+
+ Position x = rw->label.internal_width;
+ Position y = rw->core.height/2;
+ GC gc = XtIsSensitive(w) ? rw->command.normal_GC : rw->label.gray_GC;
+ Pixmap selected, unselected;
+
+ if (rw->radio.isRadio) { /* it's a radio button */
+ selected = rclass(rw)->radio_class.sel_radio;
+ unselected = rclass(rw)->radio_class.unsel_radio;
+ }
+ else {
+ selected = rclass(rw)->radio_class.sel_menu;
+ unselected = rclass(rw)->radio_class.unsel_menu;
+ }
+
+ ASSERT(selected != None, "");
+ ASSERT(unselected != None, "");
+
+ if(rw->command.set) {
+ XCopyPlane(dpy, selected, win, gc,
+ 0, 0, BUTTON_BITMAP_H, BUTTON_BITMAP_W,
+ x, y - BUTTON_BITMAP_H / 2, 1L);
+ }
+ else {
+ XCopyPlane(dpy, unselected, win, gc,
+ 0, 0, BUTTON_BITMAP_H, BUTTON_BITMAP_W,
+ x, y - BUTTON_BITMAP_H / 2, 1L);
+ }
+}
+
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/xlwradio.h b/Build/source/texk/xdvik/gui/xlwradio.h
new file mode 100644
index 00000000000..728c97fcbee
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xlwradio.h
@@ -0,0 +1,119 @@
+/* adapted from xlwradio.c in the XEmacs distribution.
+ Changes are Copyright (C) 2002-2004 the xdvik development team
+ Original copyright follows:
+*/
+
+/* Radio Widget for XEmacs.
+ Copyright (C) 1999 Edward A. Falk
+
+This file is part of XEmacs.
+
+XEmacs is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Synched up with: Radio.h 1.1 */
+
+/*
+ * Radio.h - Radio button widget
+ *
+ * Author: Edward A. Falk
+ * falk@falconer.vip.best.com
+ *
+ * Date: June 30, 1997
+ */
+
+#ifndef _XawRadio_h
+#define _XawRadio_h
+
+#include "xdvi-config.h"
+
+#ifndef MOTIF /* entire file */
+
+/***********************************************************************
+ *
+ * Radio Widget
+ *
+ * The Radio widget is identical to the Toggle widget in behavior but
+ * not in appearance. The Radio widget looks like a small diamond
+ * shaped button to the left of the label.
+ * (SU: changed this to use a bitmap instead.)
+ *
+ ***********************************************************************/
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+#include <X11/Xaw/Toggle.h>
+
+/* Resources:
+
+ Name Class RepType Default Value
+ ---- ----- ------- -------------
+ radioGroup RadioGroup Widget NULL
+ radioData RadioData Pointer (XPointer) Widget
+ isRadio IsRadio Booelan True
+ state State Boolean Off
+ background Background Pixel XtDefaultBackground
+ bitmap Pixmap Pixmap None
+ border BorderColor Pixel XtDefaultForeground
+ borderWidth BorderWidth Dimension 1
+ callback Callback Pointer NULL
+ cursor Cursor Cursor None
+ destroyCallback Callback Pointer NULL
+ font Font XFontStructx* XtDefaultFont
+ foreground Foreground Pixel XtDefaultForeground
+ height Height Dimension text height
+ highlightThickness Thickness Dimension 2
+ insensitiveBorder sensitive Pixmap Gray
+ internalHeight Height Dimension 2
+ internalWidth Width Dimension 4
+ justify Justify XtJustify XtJustifyCenter
+ label Label String NULL
+ mappedWhenManaged MappedWhenManaged Boolean True
+ resize Resize Boolean True
+ sensitive Sensitive Boolean True
+ width Width Dimension text width
+ x Position Position 0
+ y Position Position 0
+
+*/
+
+/*
+ * These should be in StringDefs.h but aren't so we will define
+ * them here if they are needed.
+ */
+
+
+extern WidgetClass radioWidgetClass;
+
+typedef struct _RadioClassRec *RadioWidgetClass;
+typedef struct _RadioRec *RadioWidget;
+
+#define XtNisRadio "isRadio"
+#define XtCIsRadio "IsRadio"
+
+/************************************************************
+ *
+ * Public Functions
+ *
+ ************************************************************/
+
+#endif /* MOTIF */
+
+#endif /* _XawRadio_h */
diff --git a/Build/source/texk/xdvik/gui/xlwradioP.h b/Build/source/texk/xdvik/gui/xlwradioP.h
new file mode 100644
index 00000000000..5ce6f654d7f
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xlwradioP.h
@@ -0,0 +1,140 @@
+/* adapted from xlwradio.c in the XEmacs distribution.
+ Changes are Copyright (C) 2002-2004 the xdvik development team
+ Original copyright follows:
+*/
+
+/* Radio Widget for XEmacs.
+ Copyright (C) 1999 Edward A. Falk
+
+This file is part of XEmacs.
+
+XEmacs is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/*
+ * RadioP.h - Private definitions for Radio widget
+ *
+ * Author: Edward A. Falk
+ * falk@falconer.vip.best.com
+ *
+ * Date: June 30, 1997
+ *
+ */
+
+#ifndef _XawRadioP_h
+#define _XawRadioP_h
+
+#include "xdvi-config.h"
+
+#include "xlwradio.h"
+
+#ifndef MOTIF
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xos.h>
+#include <X11/Xaw/Text.h>
+#include <X11/Xaw/AsciiText.h>
+
+#include <X11/Xaw/ToggleP.h>
+
+/***********************************************************************
+ *
+ * Radio Widget Private Data
+ *
+ ***********************************************************************/
+
+typedef void (*XawDiamondProc) (Widget);
+
+void RadioSet (Widget w,
+ XEvent *event,
+ String *params, /* unused */
+ Cardinal *num_params); /* unused */
+
+void RadioUnset (Widget w,
+ XEvent *event,
+ String *params, /* unused */
+ Cardinal *num_params); /* unused */
+
+/************************************
+ *
+ * Class structure
+ *
+ ***********************************/
+
+/* New fields for the Radio widget class record */
+typedef struct _RadioClass {
+ Dimension dsize; /* diamond size */
+ XawDiamondProc drawDiamond;
+ /* pixmaps for the button */
+ Pixmap sel_radio; /* selected state */
+ Pixmap unsel_radio; /* unselected state */
+ Pixmap sel_menu; /* selected state */
+ Pixmap unsel_menu; /* unselected state */
+ /* TODO: 3-d and xaw-xpm features? */
+ XtPointer extension;
+} RadioClassPart;
+
+#define XtInheritDrawDiamond ((XawDiamondProc)_XtInherit)
+
+/* Full class record declaration */
+typedef struct _RadioClassRec {
+ CoreClassPart core_class;
+ SimpleClassPart simple_class;
+#ifdef _ThreeDP_h
+ ThreeDClassPart threeD_class;
+#endif
+ LabelClassPart label_class;
+ CommandClassPart command_class;
+ ToggleClassPart toggle_class;
+ RadioClassPart radio_class;
+} RadioClassRec;
+
+extern RadioClassRec radioClassRec;
+
+/***************************************
+ *
+ * Instance (widget) structure
+ *
+ **************************************/
+
+/* New fields for the Radio widget record */
+typedef struct {
+ /* resources */
+ Boolean isRadio; /* radio if True, checkbox else */
+ /* TODO: 3-d and xaw-xpm features? */
+
+ /* private data */
+ XtPointer extension;
+} RadioPart;
+
+ /* Full widget declaration */
+typedef struct _RadioRec {
+ CorePart core;
+ SimplePart simple;
+#ifdef _ThreeDP_h
+ ThreeDPart threeD;
+#endif
+ LabelPart label;
+ CommandPart command;
+ TogglePart toggle;
+ RadioPart radio;
+} RadioRec;
+
+#endif /* MOTIF */
+
+#endif /* _XawRadioP_h */
diff --git a/Build/source/texk/xdvik/gui/xm_colorsel.c b/Build/source/texk/xdvik/gui/xm_colorsel.c
new file mode 100644
index 00000000000..9b91e2c76fd
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_colorsel.c
@@ -0,0 +1,664 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Color selector window showing a range of colors, and sliders to customize them.
+ * Heavily influenced by color_slide.c from ch. 13 of O'Reilly's Motif Programming Manual 1.2.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "Tip.h"
+#include "x_util.h"
+#include "xm_colorsel.h"
+#include "xm_prefsP.h"
+#include "xm_prefs.h"
+#include "events.h"
+#include "dvi-draw.h"
+#include "util.h"
+#include "topic-window.h"
+#include "search-internal.h"
+
+#ifdef MOTIF /* entire file */
+
+#include <X11/Xatom.h>
+
+#include <Xm/Xm.h>
+#include <Xm/Protocols.h>
+#include <Xm/DialogS.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushB.h>
+#include <Xm/Form.h>
+#include <Xm/PanedW.h>
+#include <Xm/DrawnB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Scale.h>
+#include <Xm/SelectioB.h>
+# include <Xm/AtomMgr.h>
+
+#include <Xm/MwmUtil.h>
+
+#define ROWS 7
+#define COLS 10
+
+/* for passing around information - no global data here ;-) */
+struct color_info {
+ XColor new_color;
+ Widget tooltip;
+ Widget new_sample;
+ Widget r_scale;
+ Widget g_scale;
+ Widget b_scale;
+ struct color_button_info *button_info;
+};
+
+/*
+ * These are the colors of the GTK/Mozilla color picker
+ * (see e.g. http://lxr.mozilla.org/mozilla/source/toolkit/content/widgets/colorpicker.xml)
+ * which has the colors more or less sorted by columns.
+ * It's terminated by NULL just in case the table gets out of sync with
+ * the row/column number.
+ */
+static const char *colors[] = {
+ /* column 1 */
+ "#FFFFFF", "#CCCCCC", "#C0C0C0", "#999999", "#666666", "#333333", "#000000",
+ /* column 2 */
+ "#FFCCCC", "#FF6666", "#FF0000", "#CC0000", "#990000", "#660000", "#330000",
+ /* column 3 */
+ "#FFCC99", "#FF9966", "#FF9900", "#FF6600", "#CC6600", "#993300", "#663300",
+ /* column 4 */
+ "#FFFF99", "#FFFF66", "#FFCC66", "#FFCC33", "#CC9933", "#996633", "#663333",
+ /* column 5 */
+ "#FFFFCC", "#FFFF33", "#FFFF00", "#FFCC00", "#999900", "#666600", "#333300",
+ /* column 6 */
+ "#99FF99", "#66FF99", "#33FF33", "#33CC00", "#009900", "#006600", "#003300",
+ /* column 7 */
+ "#99FFFF", "#33FFFF", "#66CCCC", "#00CCCC", "#339999", "#336666", "#003333",
+ /* column 8 */
+ "#CCFFFF", "#66FFFF", "#33CCFF", "#3366FF", "#3333FF", "#000099", "#000066",
+ /* column 9 */
+ "#CCCCFF", "#9999FF", "#6666CC", "#6633FF", "#6600CC", "#333399", "#330099",
+ /* column 10 */
+ "#FFCCFF", "#FF99FF", "#CC66CC", "#CC33CC", "#993399", "#663366", "#330033",
+ /* safety */
+ NULL
+};
+
+#define MOTIF 1
+
+static void
+popdown_cb(Widget widget, XtPointer client_data, XtPointer call_data)
+{
+ Widget dialog;
+ struct prefs_choice *prefs = (struct prefs_choice *)client_data;
+
+ UNUSED(call_data);
+
+ ASSERT(prefs != NULL, "user_data in popdown_cb musn't be NULL!");
+ if (get_widget_by_name(&dialog, widget, Xdvi_COLOR_DIALOG_NAME, True)) {
+/* fprintf(stderr, "popdown!\n"); */
+ remove_from_deplist(prefs, dialog);
+ XtUnmanageChild(dialog);
+ }
+}
+
+static void
+popdown_apply_cb(Widget widget, XtPointer client_data, XtPointer call_data)
+{
+ struct color_info *cinfo = NULL;
+ static XmDrawnButtonCallbackStruct cbs;
+ struct prefs_choice *prefs = (struct prefs_choice *)client_data;
+
+ UNUSED(call_data);
+ ASSERT(prefs != NULL, "struct prefs_choice * in popdown_apply_cb mustn't be NULL!");
+
+ /* To update button to new color, set its button_info color
+ and call the button's expose callback */
+ XtVaGetValues(widget, XmNuserData, &cinfo, NULL);
+ ASSERT(cinfo != NULL, "XmNuserData in popdown_apply_cb musn't be NULL!");
+ cinfo->button_info->pixel = cinfo->new_color.pixel;
+
+ cbs.reason = XmCR_EXPOSE;
+ XtCallCallbacks(cinfo->button_info->w, XmNexposeCallback, &cbs);
+
+ remove_from_deplist(prefs, widget);
+
+ /* Store the current setting -
+ FIXME: better way of converting color or pixel to string? pixel_to_str() in x_util.c is broken! */
+ store_preference(&(prefs->db), cinfo->button_info->resource_name,
+ "#%.2x%.2x%.2x",
+ cinfo->new_color.red >> 8,
+ cinfo->new_color.green >> 8,
+ cinfo->new_color.blue >> 8);
+
+ /* Update the display to use the new foreground/background.
+ * I don't really understand the entire color interface, but
+ * apparently the following works, and nothing else I tried did ... */
+ if (strcmp(cinfo->button_info->resource_name, "foreground") == 0) {
+ XGCValues values;
+
+ fg_initial.r = cinfo->new_color.red;
+ fg_initial.g = cinfo->new_color.green;
+ fg_initial.b = cinfo->new_color.blue;
+
+ values.foreground = resource.fore_Pixel = resource.rule_pixel = cinfo->new_color.pixel;
+ XChangeGC(DISP, globals.gc.ruler, GCForeground, &values);
+
+ scanned_page = scanned_page_color = scanned_page_reset;
+ globals.ev.flags |= EV_NEWPAGE;
+
+ }
+ else if (strcmp(cinfo->button_info->resource_name, "background") == 0) {
+ bg_initial.r = cinfo->new_color.red;
+ bg_initial.g = cinfo->new_color.green;
+ bg_initial.b = cinfo->new_color.blue;
+
+ resource.back_Pixel = cinfo->new_color.pixel;
+ scanned_page = scanned_page_color = scanned_page_reset;
+ globals.ev.flags |= EV_RELOAD; /* EV_NEWPAGE not sufficient with color code ... */
+ }
+ else if (strcmp(cinfo->button_info->resource_name, "highlight") == 0) {
+ XGCValues values;
+ values.foreground = resource.hl_Pixel = cinfo->new_color.pixel;
+ XChangeGC(DISP, globals.gc.high, GCForeground, &values);
+ /* hack to update match GC: fake change in inverted property, redraw
+ so that GC is cleared, then change inverted property back */
+ resource.match_highlight_inverted = !resource.match_highlight_inverted;
+ search_draw_inverted_regions();
+ resource.match_highlight_inverted = !resource.match_highlight_inverted;
+ /* end of hack to update match GC */
+ globals.ev.flags |= EV_NEWPAGE; /* force redraw */
+ }
+
+ XtUnmanageChild(widget);
+}
+
+static void
+popdown_cancel_cb(Widget widget, XtPointer client_data, XtPointer call_data)
+{
+ struct prefs_choice *prefs = (struct prefs_choice *)client_data;
+
+/* fprintf(stderr, "popdown cancel; call_data: %p!\n", call_data); */
+ if (call_data != NULL) {
+/* fprintf(stderr, "removing from deplist: %p!!!\n", prefs); */
+ remove_from_deplist(prefs, widget);
+ }
+
+ XtUnmanageChild(widget);
+/* XtPopdown(XtParent(widget)); */
+}
+
+static void
+revert_color_cb(Widget widget, XtPointer client_data, XtPointer call_data)
+{
+ struct color_info *cinfo = (struct color_info *)client_data;
+ Pixel pix;
+ unsigned r, g, b;
+
+ UNUSED(call_data);
+
+ /* get color of old_sample button */
+ XtVaGetValues(widget, XmNbackground, &pix, NULL);
+ /* fprintf(stderr, "Color: 0x%.6lx\n", pix); */
+
+ /* use this instead of XtVaSetValues on XmNbackground so that
+ the foreground color gets also changed appropriately. */
+#if XmVersion >= 1002
+ XmChangeColor(cinfo->new_sample, pix);
+#else
+ XtVaSetValues(cinfo->new_sample, XmNbackground, pix, NULL);
+#endif
+
+ /* update sliders */
+ XFreeColors(DISP, G_colormap, &(cinfo->new_color.pixel), 1, 0);
+ pixel_to_color(pix, &(cinfo->new_color), DISP, G_colormap);
+
+ r = cinfo->new_color.red >> 8;
+ g = cinfo->new_color.green >> 8;
+ b = cinfo->new_color.blue >> 8;
+
+/* fprintf(stderr, "Pixel: 0x%.6lx\n", cinfo->new_color.pixel); */
+
+ XtVaSetValues(cinfo->r_scale, XmNvalue, r, NULL);
+ XtVaSetValues(cinfo->g_scale, XmNvalue, g, NULL);
+ XtVaSetValues(cinfo->b_scale, XmNvalue, b, NULL);
+}
+
+static void
+show_color_cb(Widget widget, XtPointer client_data, XtPointer call_data)
+{
+ struct color_info *cinfo = (struct color_info *)client_data;
+ Pixel pix;
+ unsigned r, g, b;
+
+ UNUSED(call_data);
+ XtVaGetValues(widget, XmNbackground, &pix, NULL);
+/* fprintf(stderr, "Color: 0x%.6lx\n", pix); */
+
+ /* use this instead of XtVaSetValues on XmNbackground so that
+ the foreground color gets also changed appropriately. */
+#if XmVersion >= 1002
+ XmChangeColor(cinfo->new_sample, pix);
+#else
+ XtVaSetValues(cinfo->new_sample, XmNbackground, pix, NULL);
+#endif
+
+ /* update sliders */
+ XFreeColors(DISP, G_colormap, &(cinfo->new_color.pixel), 1, 0);
+ pixel_to_color(pix, &(cinfo->new_color), DISP, G_colormap);
+
+ r = cinfo->new_color.red >> 8;
+ g = cinfo->new_color.green >> 8;
+ b = cinfo->new_color.blue >> 8;
+
+/* fprintf(stderr, "Pixel: 0x%.6lx\n", cinfo->new_color.pixel); */
+
+ XtVaSetValues(cinfo->r_scale, XmNvalue, r, NULL);
+ XtVaSetValues(cinfo->g_scale, XmNvalue, g, NULL);
+ XtVaSetValues(cinfo->b_scale, XmNvalue, b, NULL);
+}
+
+static void
+slider_cb(Widget widget, XtPointer client_data, XtPointer call_data)
+{
+ struct color_info *cinfo = (struct color_info *)client_data;
+ XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)call_data;
+
+/* fprintf(stderr, "Pixel1 : 0x%.6lx\n", cinfo->new_color.pixel); */
+ /* reuse cinfo->new_color */
+ XFreeColors(DISP, G_colormap, &(cinfo->new_color.pixel), 1, 0);
+
+ if (widget == cinfo->r_scale) {
+ cinfo->new_color.red = cbs->value << 8; /* << 8 == * 65535 */
+ }
+ else if (widget == cinfo->g_scale) {
+ cinfo->new_color.green = cbs->value << 8;
+ }
+ else if (widget == cinfo->b_scale) {
+ cinfo->new_color.blue = cbs->value << 8;
+ }
+
+ if (!XAllocColor(DISP, G_colormap, &(cinfo->new_color))) {
+ XDVI_ERROR((stderr, "Couldn't XAllocColor\n"));
+ return;
+ }
+/* fprintf(stderr, "Pixel: 0x%.6lx\n", cinfo->new_color.pixel); */
+
+#if XmVersion >= 1002
+ /* if avaliable, use this so that the foreground color also
+ gets updated appropriately: */
+ XmChangeColor(cinfo->new_sample, cinfo->new_color.pixel);
+#else
+ XtVaSetValues(cinfo->new_sample, XmNbackground, cinfo->new_color.pixel, NULL);
+#endif
+}
+
+static void
+h_init_sliders(struct color_info *cinfo)
+{
+ unsigned r, g, b;
+
+ r = cinfo->new_color.red >> 8;
+ g = cinfo->new_color.green >> 8;
+ b = cinfo->new_color.blue >> 8;
+
+ XtVaSetValues(cinfo->r_scale, XmNvalue, r, NULL);
+ XtVaSetValues(cinfo->g_scale, XmNvalue, g, NULL);
+ XtVaSetValues(cinfo->b_scale, XmNvalue, b, NULL);
+}
+
+static Widget
+h_create_color_matrix(Widget parent, Widget top, struct color_info *cinfo)
+{
+ int i, j;
+ const char **color_ptr = colors;
+
+ Widget matrix =
+ XtVaCreateManagedWidget("color_matrix", xmRowColumnWidgetClass,
+ parent,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, top,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNpacking, XmPACK_COLUMN,
+ XmNnumColumns, COLS,
+ XmNorientation, XmVERTICAL,
+ XmNbackground, BlackPixelOfScreen(XtScreen(parent)),
+ XmNspacing, 1,
+ XmNmarginWidth, 1,
+ XmNmarginHeight, 1,
+ NULL);
+
+ for (i = 0; i < ROWS; i++) {
+ for (j = 0; j < COLS; j++) {
+ Pixel pix = BlackPixelOfScreen(XtScreen(parent));
+ Widget button;
+ if (*color_ptr == NULL) /* safety */
+ break;
+ str_to_pixel(top, *color_ptr++, &pix);
+ /* fprintf(stderr, "creating button %d, %d - %s\n", i, j, k % 2 ? "b" : "w"); */
+ button = XtVaCreateManagedWidget("c_button", xmDrawnButtonWidgetClass,
+ matrix,
+ XmNbackground, pix,
+ XmNheight, 19,
+ XmNwidth, 19,
+ XmNmarginWidth, 0,
+ XmNmarginHeight, 0,
+ XmNhighlightThickness, 0,
+ XmNshadowThickness, 0,
+ NULL);
+ XtAddCallback(button, XmNactivateCallback, show_color_cb, cinfo);
+ }
+ }
+ return matrix;
+}
+
+static void
+h_create_sliders(Widget parent, Widget top, struct color_info *cinfo)
+{
+ XmString str;
+ Widget r_label, g_label, b_label;
+ Widget r_scale, g_scale, b_scale;
+ Dimension curr, max;
+
+ Arg scale_args[8];
+ Arg label_args[8];
+ int scale_n = 0;
+
+ XtSetArg(scale_args[scale_n], XmNmaximum, 255); scale_n++;
+ /* True is an older setting of XmNshowValue that should also work with 2.x */
+ XtSetArg(scale_args[scale_n], XmNshowValue, True); scale_n++;
+ XtSetArg(scale_args[scale_n], XmNorientation, XmHORIZONTAL); scale_n++;
+#if XmVersion >= 2000
+ XtSetArg(scale_args[scale_n], XmNshowArrows, XmEACH_SIDE); scale_n++;
+ /* XmVersion < 2000 only had `True' which was the default anyway */
+#endif
+
+ str = XmStringCreateLocalized("Red");
+ XtSetArg(label_args[0], XmNlabelString, str);
+ r_label = XtCreateManagedWidget("r_label", xmLabelGadgetClass, parent, label_args, 1);
+ XmStringFree(str);
+
+ r_scale = XtCreateWidget("r_scale", xmScaleWidgetClass, parent, scale_args, scale_n);
+ cinfo->r_scale = r_scale;
+ XtAddCallback(r_scale, XmNdragCallback, slider_cb, cinfo);
+ XtAddCallback(r_scale, XmNvalueChangedCallback, slider_cb, cinfo);
+
+ str = XmStringCreateLocalized("Green");
+ XtSetArg(label_args[0], XmNlabelString, str);
+ g_label = XtCreateManagedWidget("g_label", xmLabelGadgetClass, parent, label_args, 1);
+ XmStringFree(str);
+
+ g_scale = XtCreateWidget("g_scale", xmScaleWidgetClass, parent, scale_args, scale_n);
+ cinfo->g_scale = g_scale;
+ XtAddCallback(g_scale, XmNdragCallback, slider_cb, cinfo);
+ XtAddCallback(g_scale, XmNvalueChangedCallback, slider_cb, cinfo);
+
+ str = XmStringCreateLocalized("Blue");
+ XtSetArg(label_args[0], XmNlabelString, str);
+ b_label = XtCreateManagedWidget("b_label", xmLabelGadgetClass, parent, label_args, 1);
+ XmStringFree(str);
+
+ b_scale = XtCreateWidget("b_scale", xmScaleWidgetClass, parent, scale_args, scale_n);
+ cinfo->b_scale = b_scale;
+ XtAddCallback(b_scale, XmNdragCallback, slider_cb, cinfo);
+ XtAddCallback(b_scale, XmNvalueChangedCallback, slider_cb, cinfo);
+
+ /* get max width of labels, and adjust scale size to what's left */
+ XtVaGetValues(r_label, XmNwidth, &curr, NULL);
+ XtVaGetValues(g_label, XmNwidth, &max, NULL);
+ if (curr > max)
+ max = curr;
+ XtVaGetValues(b_label, XmNwidth, &curr, NULL);
+ if (curr > max)
+ max = curr;
+ /* we know the width of the color selector is about 200 pixels (10 fields each 20 wide),
+ so we use that as max length */
+ curr = 200 - max - 2; /* some additional offset */
+
+ /* fprintf(stderr, "width of slider: %d\n", curr); */
+ /* fprintf(stderr, "width of string: %d\n", max); */
+
+ /* attach widgets; needs to be done after creating them since r_label
+ attachment references g_label etc. */
+ XtVaSetValues(r_label,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_WIDGET,
+ XmNbottomWidget, g_label,
+ XmNbottomOffset, 20, /* needed to make label visible */
+ NULL);
+ XtVaSetValues(r_scale,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, top,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_WIDGET,
+ XmNbottomWidget, g_label,
+ XmNbottomOffset, 20, /* needed to make label visible */
+ XmNscaleWidth, curr,
+ NULL);
+ XtVaSetValues(g_label,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_WIDGET,
+ XmNbottomWidget, b_label,
+ XmNbottomOffset, 20, /* needed to make label visible */
+ NULL);
+ XtVaSetValues(g_scale,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_WIDGET,
+ XmNbottomWidget, b_label,
+ XmNbottomOffset, 20, /* needed to make label visible */
+ XmNscaleWidth, curr,
+ NULL);
+ XtVaSetValues(b_label,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNbottomOffset, 15,
+ NULL);
+ XtVaSetValues(b_scale,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNbottomOffset, 15,
+ XmNscaleWidth, curr,
+ NULL);
+
+ XtManageChild(r_scale);
+ XtManageChild(g_scale);
+ XtManageChild(b_scale);
+
+ h_init_sliders(cinfo);
+
+}
+
+static Widget
+h_create_shell(Widget parent, struct color_info *cinfo)
+{
+ Widget shell, dialog, form, button_row, color_matrix;
+ Widget old_sample, new_sample;
+ Widget tip_shell;
+ Atom WM_DELETE_WINDOW;
+ Arg args[32];
+ int n;
+
+ XmString str;
+
+ Pixel old_pixel = cinfo->button_info->pixel;
+ /* hack to disable resizing of the shell, since this messes up the color matrix badly */
+ int decoration = MWM_DECOR_ALL | MWM_DECOR_RESIZEH | MWM_DECOR_MENU | MWM_DECOR_MINIMIZE | MWM_DECOR_MAXIMIZE;
+ int functions = MWM_FUNC_ALL | MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE;
+
+ struct color_button_info *binfo = cinfo->button_info;
+ struct topic_info *tinfo = binfo->tinfo;
+ struct prefs_choice *prefs = (struct prefs_choice *)tinfo->data;
+/* struct prefs_choice *prefs; */
+
+ n = 0;
+ XtSetArg(args[n], XmNuserData, cinfo); n++;
+
+/* XtSetArg(args[n], XmNdeleteResponse, XmDO_NOTHING); n++; */
+/* XtSetArg(args[n], XmNnoResize, True); n++; */
+/* XtSetArg(args[n], XmNmwmFunctions, functions); n++; */
+/* XtSetArg(args[n], XmNmwmDecorations, decoration); n++; */
+ XtSetArg(args[n], XtNtitle, "Xdvik: Select Color"); n++;
+
+ dialog = XmCreatePromptDialog(parent, Xdvi_COLOR_DIALOG_NAME, args, n);
+ /* unmanage stuff to get a `scratch' widget */
+ XtUnmanageChild(XtNameToWidget(dialog, "Help"));
+ XtUnmanageChild(XtNameToWidget(dialog, "Text"));
+ XtUnmanageChild(XtNameToWidget(dialog, "Selection"));
+
+ shell = XtParent(dialog);
+
+ XtVaSetValues(shell,
+ XmNdeleteResponse, XmDO_NOTHING,
+ XmNnoResize, True,
+ XmNmwmFunctions, functions,
+ XmNmwmDecorations, decoration,
+ NULL);
+
+ /* cinfo->new_color is a allocated/freed by request; initialize it with old_pixel */
+ XAllocColor(DISP, G_colormap, &(cinfo->new_color));
+ cinfo->new_color.flags = DoRed | DoGreen | DoBlue;
+
+ XFreeColors(DISP, G_colormap, &(cinfo->new_color.pixel), 1, 0);
+ pixel_to_color(old_pixel, &(cinfo->new_color), DISP, G_colormap);
+
+
+ tip_shell = XtVaCreatePopupShell("tipShell", tipWidgetClass,
+ parent, XtNwidth, 1, XtNheight, 1,
+ NULL);
+ cinfo->tooltip = tip_shell;
+
+ form = XtVaCreateWidget("form", xmFormWidgetClass,
+ dialog,
+ XmNhorizontalSpacing, 10,
+ XmNverticalSpacing, 10,
+ XmNallowResize, False,
+ NULL);
+
+ button_row = XtVaCreateManagedWidget("button_row", xmRowColumnWidgetClass,
+ form,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNorientation, XmHORIZONTAL,
+ XmNpacking, XmPACK_COLUMN,
+ XmNspacing, 8,
+ XmNmarginWidth, 1,
+ XmNmarginHeight, 1,
+ NULL);
+
+ str = XmStringCreateLocalized("Old");
+ old_sample = XtVaCreateManagedWidget(Xdvi_COLOR_DIALOG_OLD_SAMPLE_NAME, xmPushButtonWidgetClass,
+ button_row,
+ XmNbackground, old_pixel,
+ XmNlabelString, str,
+ XmNhighlightThickness, 0,
+ XmNshadowThickness, 1,
+ NULL);
+ XtAddCallback(old_sample, XmNactivateCallback, revert_color_cb, cinfo);
+ XmStringFree(str);
+ str = XmStringCreateLocalized("New");
+ new_sample = XtVaCreateManagedWidget("new_sample", xmPushButtonWidgetClass,
+ button_row,
+ XmNbackground, cinfo->new_color.pixel,
+ XmNlabelString, str,
+ XmNhighlightThickness, 0,
+ XmNshadowThickness, 1,
+ NULL);
+ XmStringFree(str);
+ XtInsertEventHandler(new_sample,
+ KeyPressMask | KeyReleaseMask |
+ ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask| PointerMotionHintMask |
+ ButtonMotionMask | FocusChangeMask,
+ True, block_event_callback,
+ (XtPointer)0, 0);
+ cinfo->new_sample = new_sample;
+
+ color_matrix = h_create_color_matrix(form, button_row, cinfo);
+
+ h_create_sliders(form, color_matrix, cinfo);
+
+ XtManageChild(form);
+
+ XtAddCallback(dialog, XmNokCallback, popdown_apply_cb, prefs);
+ XtAddCallback(dialog, XmNcancelCallback, popdown_cancel_cb, prefs);
+
+ XtManageChild(dialog);
+
+ add_to_deplist(prefs, dialog);
+
+/* h_create_commands(shell, color_globals.widgets.paned, "OK", "Cancel", cinfo); */
+
+/* XtManageChild(color_globals.widgets.paned); */
+
+/* XtRealizeWidget(shell); */
+
+ TipAddWidget(tip_shell, old_sample, "Click to revert to old color");
+ /* TipAddWidget(tip_shell, color_matrix, "Select color"); */
+
+ WM_DELETE_WINDOW = XmInternAtom(DISP, "WM_DELETE_WINDOW", False);
+ XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, popdown_cb, prefs);
+
+ return dialog;
+}
+
+void
+popup_color_dialog(Widget parent, struct color_button_info *button_info)
+{
+ static Widget shell;
+ static Boolean first_time = True;
+ /* Must be static so that we can pass its address around */
+ static struct color_info cinfo;
+ struct topic_info *tinfo = button_info->tinfo;
+ struct prefs_choice *prefs = (struct prefs_choice *)tinfo->data;
+
+ cinfo.button_info = button_info;
+
+ if (first_time) {
+ shell = h_create_shell(parent, &cinfo);
+ first_time = False;
+ }
+ else {
+ /* Already created, but we may need to change the colors of old_sample
+ and new_sample. This is done by changing the value of old_sample and
+ invoking its activate callback, which will `revert' new_sample to
+ the same color. */
+ Widget w;
+ if (get_widget_by_name(&w, shell, Xdvi_COLOR_DIALOG_OLD_SAMPLE_NAME, True)) {
+#if XmVersion >= 1002
+ XmChangeColor(w, cinfo.button_info->pixel);
+#else
+ XtVaSetValues(w, XmNbackground, cinfo.button_info->pixel, NULL);
+#endif
+ XtCallCallbacks(w, XmNactivateCallback, &cinfo);
+ }
+ add_to_deplist(prefs, shell);
+ XtManageChild(shell);
+ }
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/xm_colorsel.h b/Build/source/texk/xdvik/gui/xm_colorsel.h
new file mode 100644
index 00000000000..bb4bd38b94a
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_colorsel.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef XM_COLORSEL_H_
+#define XM_COLORSEL_H_
+
+#ifdef MOTIF
+
+struct prefs_choice;
+struct topic_info;
+
+struct color_button_info {
+ Widget w; /* current button */
+ Pixel pixel; /* label color of this button */
+ const char *resource_name; /* resource name to save this color to */
+ struct topic_info *tinfo;
+};
+
+void popup_color_dialog(Widget parent, struct color_button_info *cinfo);
+
+#endif /* MOTIF */
+
+#endif /* XM_COLORSEL_H_ */
diff --git a/Build/source/texk/xdvik/gui/xm_filesel.c b/Build/source/texk/xdvik/gui/xm_filesel.c
new file mode 100644
index 00000000000..e5475f0bbe5
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_filesel.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2001-2004 Marcin Dalecki and others
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Implementation of the File selection dialogue for the Motif GUI.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "sfSelFile.h"
+
+#include "dvi.h"
+#include "string-utils.h"
+#include "util.h"
+#include "events.h"
+#include "message-window.h"
+#include "dvi-init.h" /* for dviErrFlagT */
+
+#if defined(MOTIF) /* entire file */
+
+#include <Xm/FileSB.h>
+
+static Widget dialog = NULL;
+static char *browse_fname = NULL;
+
+/*
+ * Process callback from Dialog cancel actions.
+ */
+static void
+cancel_callback(Widget w,
+ XtPointer client_data,
+ XtPointer call_data)
+{
+ struct filesel_callback *callback = (struct filesel_callback *)client_data;
+
+ UNUSED(w);
+ UNUSED(call_data);
+#if 0
+ /* DON'T reset browse_fname, so that user gets the current
+ value as default next time when he cancels now */
+ if (browse_fname != NULL)
+ {
+ XtFree(browse_fname);
+ browse_fname = NULL;
+ }
+#endif
+
+ XtUnmanageChild(dialog);
+ if (callback->exit_on_cancel) {
+ exit(0);
+ }
+}
+
+/*
+ * Process callback from Dialog actions.
+ */
+
+static void
+accept_callback(Widget w,
+ XtPointer client_data,
+ XtPointer call_data)
+{
+ XmFileSelectionBoxCallbackStruct *fcb;
+ struct filesel_callback *callback;
+
+ UNUSED(w);
+
+ ASSERT(client_data != NULL, "struct filesel_callback pointer expected in client data");
+ callback = (struct filesel_callback *)client_data;
+
+ if (browse_fname != NULL) {
+ XtFree(browse_fname);
+ browse_fname = NULL;
+ }
+ fcb = (XmFileSelectionBoxCallbackStruct *)call_data;
+
+ /* get the filename from the file selection box */
+ XmStringGetLtoR(fcb->value, G_charset, &browse_fname);
+
+ if (callback->must_exist) {
+ FILE *tmp_fp = XFOPEN(browse_fname, "r");
+ dviErrFlagT errflag = NO_ERROR;
+ if (tmp_fp == NULL) {
+ popup_message(XtParent(dialog),
+ MSG_ERR, NULL, "Could not open %s: %s.\n",
+ browse_fname, strerror(errno));
+ /* leave file selection box open */
+ return;
+ }
+ else if (!process_preamble(tmp_fp, &errflag)
+ || !find_postamble(tmp_fp, &errflag)
+ || !read_postamble(tmp_fp, &errflag, True)) {
+ popup_message(XtParent(dialog),
+ MSG_ERR, NULL, "Error opening %s:\n%s.",
+ browse_fname, get_dvi_error(errflag));
+ fclose(tmp_fp);
+ /* leave file selection box open */
+ return;
+ }
+ else { /* file is OK */
+ fclose(tmp_fp);
+ }
+ }
+
+ /* success; close dialog, and call our callback */
+ XtUnmanageChild(dialog);
+ callback->func_ptr(browse_fname, callback->data);
+}
+
+void raise_file_selector(void)
+{
+ /* dummy */
+ return;
+}
+
+void
+XsraSelFile(Widget parent, struct filesel_callback *callback)
+{
+#define ARG_CNT 4
+ XmString filemask = NULL;
+ XmString directory = NULL;
+ Arg args[ARG_CNT];
+ int i = 0;
+
+ if (dialog == NULL) {
+ dialog = XmCreateFileSelectionDialog(parent, "file", NULL, 0);
+ /* Set ret_dialog to the DialogShell parent, not the command widget
+ returned by the Motif routines. We need the DialogShell, otherwise
+ Motif will crash if ret_dialog is used as parent for popup_message()
+ windows!!!
+ */
+ XtVaSetValues(XtParent(dialog), XmNtitle, callback->title, NULL);
+
+ /* my_must_exist = must_exist; */
+ /* XtAddCallback(dialog, XmNokCallback, accept_callback, (XtPointer)&my_must_exist); */
+ XtAddCallback(dialog, XmNokCallback, accept_callback, (XtPointer)callback);
+ XtAddCallback(dialog, XmNcancelCallback, cancel_callback, (XtPointer)callback);
+ /* We have no help in this window, so hide help button */
+ XtUnmanageChild(XmFileSelectionBoxGetChild(dialog, (unsigned char)XmDIALOG_HELP_BUTTON));
+ }
+ else if (XtIsManaged(dialog)) {
+ XBell(DISP, 10);
+ XRaiseWindow(DISP, XtWindow(dialog));
+ return;
+ }
+
+ /* only show files matching our mask */
+ filemask = XmStringCreateLtoR((char *)callback->filemask, G_charset);
+ XtSetArg(args[i], XmNpattern, filemask); i++;
+
+ /* set directory to last directory used */
+ if (browse_fname != NULL) {
+ char *path = xstrdup(browse_fname);
+ char *ptr = strrchr(path, '/');
+ if (ptr != NULL)
+ *ptr = '\0';
+ directory = XmStringCreateLtoR(path, G_charset);
+ XtSetArg(args[i], XmNdirectory, directory); i++;
+ free(path);
+ }
+
+ ASSERT(i < ARG_CNT, "args list too short");
+ XtSetValues(dialog, args, (Cardinal)i);
+
+ free(filemask);
+ free(directory);
+
+ XtManageChild(dialog);
+#undef ARG_CNT
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* defined(MOTIF) */
diff --git a/Build/source/texk/xdvik/gui/xm_menu.c b/Build/source/texk/xdvik/gui/xm_menu.c
new file mode 100644
index 00000000000..51a2bedbd53
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_menu.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2001 Marcin Dalecki and others
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "xm_menu.h"
+#include "xm_toolbar.h"
+#include "my-snprintf.h"
+#include "util.h"
+#include "x_util.h"
+#include "version.h"
+#include "statusline.h"
+#include "pagehist.h"
+#include "dvi-init.h"
+#include "filehist.h"
+#include "c-openmx.h"
+#include "message-window.h"
+
+#ifdef MOTIF /* needed for `make depend' */
+
+#include <Xm/RowColumn.h>
+#include <Xm/Frame.h>
+#include <Xm/PushB.h>
+#include <Xm/PushBG.h>
+#include <Xm/CascadeBG.h>
+#include <Xm/SeparatoG.h>
+#include <Xm/ToggleB.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/Separator.h>
+
+
+/*
+ * There's an apparent bug in Motif related to the interaction between
+ * the menubar menus and the magnifier.
+ *
+ * If you click on a menu on the menubar and then click on the drawing
+ * widget to pop up a magnifier, the keyboard and pointer are still
+ * grabbed, leading to a weird situation in which the magnifier stays
+ * around even after you release the pointer. The ungrab_serial
+ * counter works around this bug by ignoring such pointer events.
+ *
+ * This bug occurs in Motif 1.2 and OpenMotif 2.2.2 (at least). It
+ * does not occur in Lesstif.
+ */
+static unsigned long ungrab_event_num = 0;
+
+void
+popdown_callback(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ UNUSED(w);
+ UNUSED(client_data);
+ /* Lesstif gives call_data == NULL */
+ if (call_data != NULL && *((XtGrabKind *) call_data) != XtGrabNone) {
+ ungrab_event_num = LastKnownRequestProcessed(DISP);
+ }
+}
+
+Boolean
+pulldown_menu_active(unsigned long event_num)
+{
+ return event_num < ungrab_event_num;
+}
+
+
+void
+toggle_menubar(void)
+{
+ if ((resource.expert_mode & XPRT_SHOW_MENUBAR) == 0)
+ XtUnmanageChild(globals.widgets.menu_bar);
+ else
+ XtManageChild(globals.widgets.menu_bar);
+}
+
+static void
+update_menu_labels(Widget menu)
+{
+ WidgetList children;
+ int num_children;
+ int i;
+
+ static char *buf = NULL;
+ static size_t buf_len = 0;
+
+ XtVaGetValues(menu,
+ XmNnumChildren, &num_children,
+ XmNchildren, &children,
+ NULL);
+
+/* for (i = 0; i < num_children; i++) { */
+ for (i = 0; i < (int)file_history_size(); i++) {
+ int dummy_page;
+ char *filename;
+ size_t new_len;
+ XmString str;
+
+ if ((filename = file_history_get_elem(i, &dummy_page)) == NULL) {
+ XDVI_ERROR((stderr, "Error accessing element %d of file history", i));
+ continue;
+ }
+
+ new_len = LENGTH_OF_INT + strlen(filename) + 1;
+ if (new_len > buf_len) {
+ buf = xrealloc(buf, new_len);
+ buf_len = new_len;
+ }
+
+ sprintf(buf, "%d %s", i + 1, filename);
+ str = XmStringCreateLocalized(buf);
+ XtVaSetValues(children[i],
+ XmNlabelString, str,
+ NULL);
+ if (i + 1 < 10) {
+ XtVaSetValues(children[i], XmNmnemonic, buf[0], NULL);
+ }
+ XmStringFree(str);
+ }
+
+ /* if history size < number of menu entries, destroy excess menu entries */
+ for (; i < num_children; i++) {
+ XtDestroyWidget(children[i]);
+ }
+}
+
+static void
+filehist_select_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Widget menu;
+ XmString label;
+ char *label_ptr;
+ int pageno;
+ char *fname;
+ int idx;
+
+/* UNUSED(w); */
+ UNUSED(call_data);
+ UNUSED(client_data);
+
+ XtVaGetValues(w,
+ XmNuserData, &menu,
+ XmNlabelString, &label,
+ NULL);
+
+ XmStringGetLtoR(label, G_charset, &label_ptr);
+ idx = strtol(label_ptr, (char **)NULL, 10) - 1;
+ XtFree(label_ptr);
+
+ ASSERT(menu != NULL, "XmNuserData in filehist_select_cb musn't be NULL!");
+
+ if (idx == 0) { /* user re-selected current file: reload */
+ globals.ev.flags |= EV_RELOAD;
+ return;
+ }
+ if ((fname = file_history_get_elem(idx, &pageno)) == NULL) {
+ statusline_print(STATUS_MEDIUM, "Error accessing file %d of history", idx);
+ return;
+ }
+
+ file_history_open(fname);
+}
+
+void
+filehist_menu_refresh(void)
+{
+ Widget menu;
+ if (get_widget_by_name(&menu, globals.widgets.menu_bar, Xdvi_FILEHIST_MENU, True)) {
+ update_menu_labels(menu);
+ }
+}
+
+void
+filehist_menu_add_entry(const char *filename)
+{
+ Widget menu;
+
+ static char *buf = NULL;
+ static size_t buf_len = 0;
+ size_t new_len = LENGTH_OF_INT + strlen(filename) + 1;
+
+ if (get_widget_by_name(&menu, globals.widgets.menu_bar, Xdvi_FILEHIST_MENU, True)) {
+ int num_children;
+ Widget w;
+
+ if (new_len > buf_len) {
+ buf = xrealloc(buf, new_len);
+ buf_len = new_len;
+ }
+
+ XtVaGetValues(menu, XmNnumChildren, &num_children, NULL);
+
+ sprintf(buf, "%d %s", num_children + 1, filename);
+
+ w = XtVaCreateManagedWidget(buf, xmPushButtonGadgetClass, menu,
+ XmNuserData, menu,
+ NULL);
+ if (num_children + 1 < 10) {
+ XtVaSetValues(w, XmNmnemonic, buf[0], NULL);
+ }
+ XtAddCallback(w, XmNactivateCallback, filehist_select_cb, (XtPointer)(num_children + 1));
+
+ update_menu_labels(menu);
+
+ }
+}
+
+static void
+filehist_submenu(int idx, const char *filename, int pageno, void *data)
+{
+ Widget menu = (Widget)data;
+ Widget w;
+ static char *buf = NULL;
+ static size_t buf_len = 0;
+ size_t new_len = LENGTH_OF_INT + strlen(filename) + 1;
+
+ if (new_len > buf_len) {
+ buf = xrealloc(buf, new_len);
+ buf_len = new_len;
+ }
+
+ UNUSED(pageno);
+
+ sprintf(buf, "%d %s", idx + 1, filename);
+ TRACE_GUI((stderr, "Creating menu `%s'", buf));
+ w = XtVaCreateManagedWidget(buf, xmPushButtonGadgetClass, menu,
+/* XmNmnemonic, buf[0], */
+ XmNuserData, menu,
+ NULL);
+ if (idx + 1 < 10) {
+ XtVaSetValues(w, XmNmnemonic, buf[0], NULL);
+ }
+ XtAddCallback(w, XmNactivateCallback, filehist_select_cb, (XtPointer)idx);
+}
+
+
+
+static Widget
+recent_files_submenu(Widget parent, char *title, char mnemonic)
+{
+ Widget menu = 0, cascade = 0;
+ XmString str;
+
+ menu = XmCreatePulldownMenu(parent, Xdvi_FILEHIST_MENU, NULL, 0);
+ str = XmStringCreateLocalized(title);
+ cascade = XtVaCreateManagedWidget(title, xmCascadeButtonGadgetClass, parent,
+ XmNsubMenuId, menu,
+ XmNlabelString, str,
+ XmNmnemonic, mnemonic,
+ NULL);
+ XmStringFree(str);
+
+ file_history_enumerate(filehist_submenu, menu);
+ return cascade;
+}
+
+Widget
+xm_create_menu(Widget parent, char *title, char mnemonic, struct button_info *item)
+{
+ Widget menu = 0, cascade = 0, w = 0;
+ size_t i;
+ XmString str;
+
+ menu = XmCreatePulldownMenu(parent, "_pulldown", NULL, 0);
+ str = XmStringCreateLocalized(title);
+ cascade = XtVaCreateManagedWidget(title, xmCascadeButtonGadgetClass, parent,
+ XmNsubMenuId, menu,
+ XmNlabelString, str,
+ XmNmnemonic, mnemonic,
+ NULL);
+ XmStringFree(str);
+
+ /* add the menu items */
+ for (i = 0; item != NULL && i < item->size; i++) {
+ item->elems[i].widget = 0;
+ /* if there's a subitem, call this function recursively */
+ if (item->elems[i].submenu != NULL) {
+ w = xm_create_menu(menu, item->elems[i].title,
+ item->elems[i].mnemonic, item->elems[i].submenu);
+ /*
+ workaround for pointer grabbing bug; add additional callback to all menus
+ (they have the same parent)
+ */
+ XtAddCallback(XtParent(menu), XtNpopdownCallback,
+ popdown_callback, (XtPointer) 0);
+ }
+ else if (item->elems[i].action != NULL && item->elems[i].action->proc == Act_recent_files) {
+ /* special case: submenu with recent files */
+ w = recent_files_submenu(menu, item->elems[i].title, item->elems[i].mnemonic);
+ XtAddCallback(XtParent(menu), XtNpopdownCallback,
+ popdown_callback, (XtPointer) 0);
+ }
+ else {
+ switch(item->elems[i].type) {
+ case BT_PUSH:
+ w = XtVaCreateManagedWidget(item->elems[i].title, xmPushButtonGadgetClass, menu,
+ NULL);
+ break;
+ case BT_RADIO:
+ w = XtVaCreateManagedWidget(item->elems[i].title, xmToggleButtonGadgetClass, menu,
+ XmNindicatorType, XmONE_OF_MANY,
+ NULL);
+ break;
+ case BT_CHECK:
+ w = XtVaCreateManagedWidget(item->elems[i].title, xmToggleButtonGadgetClass, menu,
+ XmNindicatorType, XmN_OF_MANY,
+ NULL);
+ break;
+ case BT_SEP:
+ w = XtVaCreateManagedWidget(item->elems[i].title, xmSeparatorGadgetClass, menu,
+ NULL);
+ break;
+ default:
+ XDVI_WARNING((stderr, "unrecognized button type %d in menu %s (skipping this item).\n",
+ item->elems[i].type, item->elems[i].title));
+ break;
+ }
+ item->elems[i].widget = w;
+ }
+
+ if (item->elems[i].mnemonic != 0)
+ XtVaSetValues(w, XmNmnemonic, item->elems[i].mnemonic, NULL);
+
+ if (item->elems[i].accelerator != NULL) {
+ str = XmStringCreateLocalized(item->elems[i].accelerator);
+ XtVaSetValues(w, XmNacceleratorText, str, NULL);
+ XmStringFree(str);
+ }
+
+ if (item->elems[i].action != NULL) {
+ String cb_type;
+ if (XmIsToggleButton(w) || XmIsToggleButtonGadget(w))
+ cb_type = XmNvalueChangedCallback;
+ else
+ cb_type = XmNactivateCallback;
+ XtAddCallback(w, cb_type, handle_command, item->elems[i].action);
+ }
+ }
+ return cascade;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
+
diff --git a/Build/source/texk/xdvik/gui/xm_menu.h b/Build/source/texk/xdvik/gui/xm_menu.h
new file mode 100644
index 00000000000..28dab3a384e
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_menu.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2001 Marcin Dalecki
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef XM_MENU_H_
+#define XM_MENU_H_
+
+#include "menu.h"
+
+#ifdef MOTIF
+
+#define Xdvi_FILEHIST_MENU "filehist_menu"
+
+extern Widget xm_create_menu(Widget parent, char *title, char mnemonic,
+ struct button_info *item);
+
+extern Boolean pulldown_menu_active(unsigned long event_num);
+extern void toggle_menubar(void);
+extern void popdown_callback(Widget w, XtPointer client_data, XtPointer call_data);
+extern void filehist_menu_add_entry(const char *filename);
+extern void filehist_menu_refresh(void);
+
+#endif
+
+#endif /* XM_MENU_H_ */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs.c b/Build/source/texk/xdvik/gui/xm_prefs.c
new file mode 100644
index 00000000000..388ef07ac12
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs.c
@@ -0,0 +1,590 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Preferences dialog for xdvik.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "x_util.h"
+#include "xm_colorsel.h"
+#include "topic-window.h"
+#include "message-window.h"
+#include "util.h"
+#include "events.h"
+
+#include "xm_prefsP.h"
+#include "xm_prefs.h"
+
+#include "xm_prefs_appearance.h"
+#include "xm_prefs_fonts.h"
+#include "xm_prefs_helpers.h"
+#include "xm_prefs_page.h"
+#include "xm_prefs_scroll.h"
+
+/* for reverting preferences, we need access to more prototypes ... */
+#include "dvi-draw.h"
+#include "search-internal.h"
+#include "statusline.h"
+#include "xm_toolbar.h"
+#include "xm_menu.h"
+#include "pagesel.h"
+
+#ifdef MOTIF /* entire file */
+
+#include <X11/Xatom.h>
+
+#include <Xm/Xm.h>
+#include <Xm/Protocols.h>
+#include <Xm/DialogS.h>
+#include <Xm/Form.h>
+
+#define SCROLLING_DONE 0
+
+#define NUM_PREFS_TOPICS 16 /* should be ample ... */
+
+/* hmm, should maybe move these into xm_prefsP.c ... */
+void
+h_attach_below(Widget x, Widget y) {
+ if (y == NULL) {
+ /* no top widget, attach to form - could just pass NULL as XmNtopWidget, but lesstif warns in that case ... */
+ XtVaSetValues(x,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+ }
+ else {
+ XtVaSetValues(x,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, y,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+ }
+}
+
+
+static void
+initialize_items(struct topic_info *info)
+{
+ int i = 0;
+
+ info->items[i].widget = prefs_appearance(info);
+ info->items[i].topic = xstrdup("Appearance");
+ info->items[i].title = xstrdup("Change the appearance of xdvi");
+
+ i++;
+ info->items[i].widget = prefs_fonts_and_colors(info);
+ info->items[i].topic = xstrdup("Fonts and Colors");
+ info->items[i].title = xstrdup("Display of fonts and colors in DVI files");
+
+ i++;
+ info->items[i].widget = prefs_paper(info);
+ info->items[i].topic = xstrdup("Page Size");
+ info->items[i].title = xstrdup("Customize the default window and page size");
+
+#if SCROLLING_DONE /* not finished yet */
+ i++;
+ info->items[i].widget = prefs_scrolling(info);
+ info->items[i].topic = xstrdup("Scrolling");
+ info->items[i].title = xstrdup("Customize the scrolling behaviour when switching pages");
+#endif
+
+ i++;
+ info->items[i].widget = prefs_helpers(info);
+#ifdef LESSTIF_VERSION
+ /* compensate for width computation bug by adding extra whitespace at end */
+ info->items[i].topic = xstrdup("Helper Applications ");
+#else
+ info->items[i].topic = xstrdup("Helper Applications");
+#endif
+ info->items[i].title = xstrdup("External programs used by xdvi");
+
+ /* terminate */
+ i++;
+ info->items[i].widget = 0;
+ info->items[i].topic = info->items[i].title = NULL;
+
+ ASSERT(i < NUM_PREFS_TOPICS, "NUM_PREFS_TOPICS too small!");
+}
+
+void
+remove_from_deplist(struct prefs_choice *prefs, Widget w)
+{
+ size_t i;
+ Boolean found = False;
+
+ /* locate this widget */
+ for (i = 0; i < prefs->depwin_cnt; i++) {
+ if (prefs->depwin[i] == w) {
+ found = True;
+ break;
+ }
+ }
+
+ if (found) {
+ /* move later widgets down */
+ for (; i < prefs->depwin_cnt - 1; i++) {
+ prefs->depwin[i] = prefs->depwin[i + 1];
+ }
+ prefs->depwin_cnt--;
+ }
+
+#if 0
+ fprintf(stderr, "deplist after removal:\n");
+ for (i = 0; i < prefs->depwin_cnt; i++) {
+ fprintf(stderr, "%d: %p\n", i, prefs->depwin[i]);
+ }
+#endif
+}
+
+static void
+update_button(Widget button, Pixel pix)
+{
+ struct color_button_info *cinfo;
+ static XmDrawnButtonCallbackStruct cbs;
+
+ XtVaGetValues(button, XmNuserData, &cinfo, NULL);
+ cinfo->pixel = pix;
+ cbs.reason = XmCR_EXPOSE;
+ XtCallCallbacks(button, XmNexposeCallback, &cbs);
+}
+
+static void
+update_button_by_name(Pixel pix, const char *name)
+{
+ static Widget pref_shell = 0;
+ Widget button;
+
+ if (pref_shell == 0
+ && !get_widget_by_name(&pref_shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, True))
+ return;
+
+ if (get_widget_by_name(&button, pref_shell, name, True)) {
+ update_button(button, pix);
+ }
+}
+
+static Boolean
+revert_colors(Pixel fg, Pixel bg, Pixel hl)
+{
+ XColor color_data[2];
+ Boolean need_redraw = False;
+ Widget button;
+ Pixel visited, unvisited;
+
+ color_data[0].pixel = resource.fore_Pixel;
+ color_data[1].pixel = resource.back_Pixel;
+
+ str_to_pixel(globals.widgets.top_level, resource.visited_link_color, &visited);
+ str_to_pixel(globals.widgets.top_level, resource.link_color, &unvisited);
+
+ XQueryColors(DISP, G_colormap, color_data, 2);
+
+ if (fg != resource.fore_Pixel) {
+ XGCValues values;
+
+ fg_initial.r = color_data[0].red;
+ fg_initial.g = color_data[0].green;
+ fg_initial.b = color_data[0].blue;
+
+ values.foreground = resource.rule_pixel = resource.fore_Pixel;
+ XChangeGC(DISP, globals.gc.ruler, GCForeground, &values);
+
+ scanned_page = scanned_page_color = scanned_page_reset;
+
+ update_button_by_name(resource.fore_Pixel, Xdvi_FG_COLOR_BTN);
+
+ need_redraw = True;
+ }
+ if (bg != resource.back_Pixel) {
+ bg_initial.r = color_data[1].red;
+ bg_initial.g = color_data[1].green;
+ bg_initial.b = color_data[1].blue;
+
+ scanned_page = scanned_page_color = scanned_page_reset;
+
+ update_button_by_name(resource.back_Pixel, Xdvi_BG_COLOR_BTN);
+
+ need_redraw = True;
+ }
+ if (hl != resource.hl_Pixel) {
+ XGCValues values;
+ values.foreground = resource.hl_Pixel;
+ XChangeGC(DISP, globals.gc.high, GCForeground, &values);
+ /* hack to update match GC: fake change in inverted property, redraw
+ so that GC is cleared, then change inverted property back */
+ resource.match_highlight_inverted = !resource.match_highlight_inverted;
+ search_draw_inverted_regions();
+ resource.match_highlight_inverted = !resource.match_highlight_inverted;
+
+ update_button_by_name(resource.hl_Pixel, Xdvi_HL_COLOR_BTN);
+
+ need_redraw = True;
+ }
+ /* NOTE: pixels for hyperlinks are not stored anywhere; just update always: */
+ if (get_widget_by_name(&button, globals.widgets.top_level, Xdvi_VISITED_LINKS_BTN, True)) {
+ update_button(button, visited);
+ h_update_hyperlinks(button, visited); /* this already triggers a redraw */
+ }
+ if (get_widget_by_name(&button, globals.widgets.top_level, Xdvi_UNVISITED_LINKS_BTN, True)) {
+ update_button(button, unvisited);
+ h_update_hyperlinks(button, unvisited); /* this already triggers a redraw */
+ }
+ return need_redraw;
+}
+
+static void
+revert_resources(void)
+{
+ Pixel curr_fg = resource.fore_Pixel;
+ Pixel curr_bg = resource.back_Pixel;
+ Pixel curr_hl = resource.hl_Pixel;
+ Boolean need_redraw = False;
+
+ /* save some old values */
+ int save_shrink = resource.shrinkfactor;
+
+ reload_app_resources();
+
+ /* revert from saved values */
+ resource.use_color = globals.curr_use_color;
+ resource.gamma = globals.curr_gamma;
+ resource.paper = globals.curr_paper;
+ resource.shrinkfactor = save_shrink;
+ do_set_shrinkfactor(resource.shrinkfactor, True);
+
+ update_preferences_darkness();
+
+ /* revert expert mode */
+ if (resource.expert)
+ resource.expert_mode = XPRT_SHOW_NONE;
+ update_expert_mode();
+
+ toggle_statusline();
+#ifndef MOTIF
+ if (!BROKEN_RECONFIG)
+ toggle_scrollbars();
+#else
+ toggle_scrollbars();
+#endif
+
+#ifdef MOTIF
+ toggle_pagelist();
+ toggle_toolbar();
+ toggle_menubar();
+#else
+ toggle_buttons();
+#endif
+
+ /* reset tooltips_wait_period, similar to TipAddWidget() in Tip.c */
+ resource.tooltips_wait_period = resource.tooltips_wait_period_bak;
+ if (resource.tooltips_wait_period < 0) {
+ resource.show_tooltips = False;
+ }
+ else if (!resource.show_tooltips) {
+ if (resource.tooltips_wait_period == 0)
+ resource.tooltips_wait_period = -1;
+ else
+ resource.tooltips_wait_period = -resource.tooltips_wait_period;
+ }
+
+ update_preferences_expert();
+ update_preferences_tooltips();
+ update_preferences_search();
+
+ update_preferences_color();
+ update_preferences_hyperlinks();
+
+ update_preferences_windowsize();
+ update_preferences_shrink();
+ update_preferences_paper();
+
+ update_preferences_helpers();
+
+ need_redraw |= revert_colors(curr_fg, curr_bg, curr_hl);
+
+/* if (need_redraw) */
+ /* just reload it always, there's too many exceptions ...
+ redraw isn't always sufficient if file has colors. */
+ globals.ev.flags |= EV_RELOAD;
+
+}
+
+/* add widget w to list of dependent windows */
+void
+add_to_deplist(struct prefs_choice *prefs, Widget w)
+{
+#if 0
+ size_t i;
+#endif
+ prefs->depwin = xrealloc(prefs->depwin,
+ (prefs->depwin_cnt + 1) * sizeof *(prefs->depwin));
+ prefs->depwin[prefs->depwin_cnt] = w;
+ prefs->depwin_cnt++;
+
+#if 0
+ fprintf(stderr, "deplist after adding:\n");
+ for (i = 0; i < prefs->depwin_cnt; i++) {
+ fprintf(stderr, "%lu: %p\n", (unsigned long)i, prefs->depwin[i]);
+ }
+#endif
+}
+
+static void
+reread_prefs_cb(Window w)
+{
+ if (w != XtWindow(globals.widgets.top_level)) {
+ XChangeProperty(DISP, w,
+ atom_reread_prefs(), atom_reread_prefs(), 8,
+ PropModeReplace,
+ /* dummy values, since all the other instance needs to do is
+ reread the ~/.xdvirc.tmp file */
+ (unsigned char *)"Y", 1);
+ }
+}
+
+static void
+apply_prefs_cb(XtPointer arg)
+{
+ struct topic_info *info = (struct topic_info *)arg;
+ struct prefs_choice *prefs = (struct prefs_choice *)info->data;
+ size_t i;
+ Widget colorsel;
+
+ if (get_widget_by_name(&colorsel, globals.widgets.top_level, Xdvi_COLOR_DIALOG_NAME, False)) {
+ XtPopdown(XtParent(colorsel));
+ }
+
+ /* pop down dependent windows */
+ TRACE_GUI((stderr, "window count: %lu\n", (unsigned long)prefs->depwin_cnt));
+ for (i = 0; i < prefs->depwin_cnt; i++) {
+ TRACE_GUI((stderr, "popping down %lu: %p", (unsigned long)i, (void *)(prefs->depwin[i])));
+ if (XtIsRealized(prefs->depwin[i])) {
+ XtCallCallbacks(prefs->depwin[i], XmNcancelCallback, NULL);
+ XSync(DISP, True); /* wait for server to catch up */
+ if (XtIsRealized(prefs->depwin[i])) {
+ TRACE_GUI((stderr, "calling XmNokCallback of %lu: %p", (unsigned long)i, (void *)(prefs->depwin[i])));
+ XtCallCallbacks(prefs->depwin[i], XmNokCallback, NULL);
+ }
+ }
+ }
+ free(prefs->depwin);
+ prefs->depwin = NULL;
+ prefs->depwin_cnt = 0;
+
+ if (prefs->db == NULL) /* callback invoked multiple times? */
+ return;
+
+ merge_into_user_db(prefs->db); /* this destroys prefs->db */
+ prefs->db = NULL;
+
+ /* remember some current values */
+ free(globals.curr_paper);
+ if (resource.paper != NULL)
+ globals.curr_paper = xstrdup(resource.paper);
+
+ free(globals.curr_editor);
+ if (resource.editor != NULL)
+ globals.curr_editor = xstrdup(resource.editor);
+
+ free(globals.curr_browser);
+ if (resource.browser != NULL)
+ globals.curr_browser = xstrdup(resource.browser);
+
+/* fprintf(stderr, "set curr_browser to: |%s|\n", globals.curr_browser); */
+/* fprintf(stderr, "set curr_editor to: |%s|\n", globals.curr_editor); */
+
+ if (get_xdvi_window_id(False, NULL) && save_user_preferences(False)) {
+ /* if other instances of xdvi are running, make them reread the
+ changed preferences by writing them to ~/.xdvirc.tmp and having
+ them read that file; otherwise they would overwrite the file if
+ user quits them after the current instance.
+ */
+ get_xdvi_window_id(False, reread_prefs_cb);
+ }
+}
+
+static void
+revert_prefs_cb(XtPointer arg)
+{
+ struct topic_info *info = (struct topic_info *)arg;
+ struct prefs_choice *prefs = (struct prefs_choice *)info->data;
+ size_t i;
+
+ /* pop down dependent windows */
+ TRACE_GUI((stderr, "window count: %lu", (unsigned long)prefs->depwin_cnt));
+ for (i = 0; i < prefs->depwin_cnt; i++) {
+ TRACE_GUI((stderr, "popping down %lu: %p", (unsigned long)i, (void *)(prefs->depwin[i])));
+ if (XtIsRealized(prefs->depwin[i])) {
+ XtCallCallbacks(prefs->depwin[i], XmNcancelCallback, NULL);
+ XSync(DISP, True); /* wait for server to catch up */
+ if (XtIsRealized(prefs->depwin[i])) {
+ TRACE_GUI((stderr, "calling XmNokCallback of %lu: %p", (unsigned long)i, (void *)(prefs->depwin[i])));
+ XtCallCallbacks(prefs->depwin[i], XmNokCallback, NULL);
+ }
+ }
+ }
+ free(prefs->depwin);
+ prefs->depwin = NULL;
+ prefs->depwin_cnt = 0;
+
+ if (prefs->db == NULL) { /* callback invoked multiple times, or prefs not changed */
+ return;
+ }
+
+ revert_resources();
+
+ XrmDestroyDatabase(prefs->db);
+ prefs->db = NULL;
+}
+
+static void
+save_prefs_exit(XtPointer arg)
+{
+ struct topic_info *info = (struct topic_info *)arg;
+ apply_prefs_cb(info);
+ XtPopdown(info->shell);
+ XSync(DISP, False);
+ xdvi_exit(EXIT_SUCCESS);
+}
+
+static void
+no_save_prefs_exit(XtPointer arg)
+{
+ struct topic_info *info = (struct topic_info *)arg;
+ revert_prefs_cb(info);
+ XtPopdown(info->shell);
+ XSync(DISP, False);
+ xdvi_exit(EXIT_SUCCESS);
+}
+
+static void
+close_prefs_exit(Widget w, XtPointer arg)
+{
+ struct topic_info *info = (struct topic_info *)arg;
+ struct prefs_choice *prefs = (struct prefs_choice *)info->data;
+/* Widget dialog; */
+/* if (get_widget_by_name(&dialog, w, Xdvi_MESSAGE_DIALOG_NAME, True)) { */
+/* fprintf(stderr, "!!!!!!!!! removing window from deplist!\n"); */
+/* remove_from_deplist(prefs, dialog); */
+/* } */
+
+ remove_from_deplist(prefs, w);
+
+}
+
+Boolean
+preferences_changed(void)
+{
+ Widget prefs_shell = 0, topic_pane = 0;
+
+ if (get_widget_by_name(&prefs_shell, globals.widgets.top_level, "preferences_window", False)
+ && get_widget_by_name(&topic_pane, prefs_shell, "topic_pane", False)) {
+ struct topic_info *info = NULL;
+ struct prefs_choice *prefs = NULL;
+
+ XtVaGetValues(topic_pane, XmNuserData, &info, NULL);
+ if (info == NULL) {
+ return False;
+ }
+ prefs = (struct prefs_choice *)info->data;
+ if (prefs->db != NULL) { /* prefs changed */
+
+ Widget popup = choice3_dialog(prefs_shell,
+ MSG_QUESTION, NULL,
+#ifndef MOTIF
+ NULL,
+#endif
+ close_prefs_exit, info, /* pre_callbacks */
+ "Save and Exit", save_prefs_exit, info,
+ "Exit, don't Save", no_save_prefs_exit, info,
+ "Cancel", NULL, NULL,
+ "Preferences have been changed, but not saved yet. "
+ "Save them now?");
+ add_to_deplist(prefs, popup);
+ return True;
+ }
+ }
+
+ return False;
+}
+
+void
+popup_preferences_dialog(Widget parent, int arg)
+{
+ static Widget preferences_shell = 0;
+ static struct topic_info info;
+ static struct topic_item items[NUM_PREFS_TOPICS];
+ static struct prefs_choice *prefs = NULL;
+
+ if (preferences_shell == 0) { /* called 1st time; create widget */
+ info.ok_callback = apply_prefs_cb;
+ info.cancel_callback = revert_prefs_cb;
+ info.items = items;
+/* info.items_size = NUM_PREFS_TOPICS; */
+
+ prefs = xmalloc(sizeof *prefs);
+ prefs->depwin_cnt = 0;
+ prefs->depwin = NULL;
+/* prefs->orig = orig_prefs; */
+ /* apply_prefs_cb/revert_prefs_cb are responsible for copying
+ the changed preferences into the current preferences as
+ appropriate, and free()ing prefs.changed */
+/* prefs->changed = xmalloc(sizeof *(prefs->changed)); */
+/* copy_resources(orig_prefs, prefs->changed); */
+ prefs->db = NULL; /* XrmGetStringDatabase(""); */
+ info.data = prefs;
+
+ preferences_shell = create_topic_window(parent,
+ "xdvik: Preferences",
+ Xdvi_PREFS_DIALOG_NAME,
+ &info,
+ initialize_items,
+ "OK", "Cancel");
+ info.shell = preferences_shell;
+ center_window(preferences_shell, parent);
+ select_topic(&info, 0);
+ }
+
+ if (arg >= 0)
+ select_topic(&info, arg);
+
+ XtPopup(preferences_shell, XtGrabNone);
+
+ if (resource.no_init_file) {
+ popup_message(preferences_shell,
+ MSG_WARN,
+ NULL,
+ "You specified the resource `noInitFile' or the `-q' command-line option. "
+ "Any preferences that you set in this dialog will be lost when you exit xdvi.");
+ }
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs.h b/Build/source/texk/xdvik/gui/xm_prefs.h
new file mode 100644
index 00000000000..0fb4acee4b8
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef XM_PREFS_H_
+#define XM_PREFS_H_
+
+#ifdef MOTIF
+
+#include "xm_prefsP.h"
+
+extern void popup_preferences_dialog(Widget parent, int arg);
+extern void copy_resources(const struct x_resources *source, struct x_resources *target);
+extern void remove_from_deplist(struct prefs_choice *prefs, Widget w);
+extern void add_to_deplist(struct prefs_choice *prefs, Widget w);
+extern Boolean preferences_changed(void);
+
+#endif
+
+#endif /* XM_PREFS_H_ */
diff --git a/Build/source/texk/xdvik/gui/xm_prefsP.h b/Build/source/texk/xdvik/gui/xm_prefsP.h
new file mode 100644
index 00000000000..3ec65ef9607
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefsP.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * `Private' common header for preferences dialogs.
+ */
+
+#ifndef XM_PREFS_P_H_
+#define XM_PREFS_P_H_
+
+#include "xdvi.h"
+#include "xdvi-config.h"
+
+#ifdef MOTIF
+/*
+ * For consistency when also using the names for XtNameToWidget() in callbacks
+ */
+/* widget names */
+#define Xdvi_PREFS_DIALOG_NAME "preferences_window"
+#define Xdvi_COLOR_DIALOG_NAME "color_dialog"
+#define Xdvi_COLOR_DIALOG_OLD_SAMPLE_NAME "old_sample"
+#define Xdvi_BROWSER_MENU_NAME "browser_menu"
+#define Xdvi_BROWSER_COMBO_NAME "browser_combo"
+#define Xdvi_EDITOR_MENU_NAME "editor_menu"
+#define Xdvi_EDITOR_COMBO_NAME "editor_combo"
+#define Xdvi_EDITOR_POPUP_NAME "editor_prompt"
+#define Xdvi_EDITOR_POPUP "editor_prompt_popup"
+#define Xdvi_BROWSER_POPUP_NAME "browser_prompt"
+#define Xdvi_BROWSER_POPUP "browser_prompt_popup"
+#define Xdvi_TIPS_STATUSLINE "tips_statusline"
+#define Xdvi_TIPS_POPUPS "tips_popups"
+#define Xdvi_TIPS_DELAY_TEXT "tips_delay_text"
+#define Xdvi_TIPS_DELAY_LABEL1 "tips_delay_label1"
+#define Xdvi_TIPS_DELAY_LABEL2 "tips_delay_label2"
+#define Xdvi_HOME_POSITION_X_OFF_TEXT "x_off_text"
+#define Xdvi_HOME_POSITION_Y_OFF_TEXT "y_off_text"
+#define Xdvi_HOME_POSITION_UNITS_MENU "units_menu"
+#define Xdvi_HOME_POSITION_UNITS_PULLDOWN "units_pulldown"
+#define Xdvi_DARKNESS_SPINBOX "darkness_spinbox"
+#define Xdvi_DARKNESS_TEXT "darkness_text"
+#define Xdvi_SHRINK_SPINBOX "shrink_spinbox"
+#define Xdvi_SHRINK_TEXT "shrink_text"
+#define Xdvi_PAPER_CASCADE "papersize_option"
+#define Xdvi_PAPER_MENU "papersize_menu"
+
+/* widget labels that are also used as widget names */
+#define Xdvi_TB_BUTTONS_FLAT_STR "Flat"
+#define Xdvi_TB_BUTTONS_RAISED_STR "Raised"
+#define Xdvi_GUI_STATUSLINE_STR "Show Statusline"
+#define Xdvi_GUI_TOOLBAR_STR "Show Toolbar"
+#define Xdvi_GUI_PAGELIST_STR "Show Pagelist"
+#define Xdvi_GUI_SCROLLBARS_STR "Show Scrollbars"
+#define Xdvi_MATCH_INVERTED_STR "Inverted"
+#define Xdvi_MATCH_BOXED_STR "Boxed with Highlight Color"
+#define Xdvi_FG_COLOR_STR "Text:"
+#define Xdvi_FG_COLOR_BTN "fg_button"
+#define Xdvi_BG_COLOR_STR "Background:"
+#define Xdvi_BG_COLOR_BTN "bg_button"
+#define Xdvi_HL_COLOR_BTN "hl_button"
+#define Xdvi_VISITED_LINKS_STR "Visited Links:"
+#define Xdvi_VISITED_LINKS_BTN "visited_links_button"
+#define Xdvi_UNVISITED_LINKS_STR "Unvisited Links:"
+#define Xdvi_UNVISITED_LINKS_BTN "unvisited_links_button"
+#define Xdvi_DOCUMENT_COLORS_STR "Use Document Colors"
+#define Xdvi_LINKS_UNDERLINED_STR "Underlined"
+#define Xdvi_ADD_COMMAND_STR "Other ..."
+#define Xdvi_SCROLL_KEEP_STR "Keep current position"
+#define Xdvi_SCROLL_UNKEEP_STR "Scroll back to home position of page"
+#define Xdvi_HOME_POSITION_STR "Home position at:"
+#define Xdvi_HOME_POSITION_X_STR "x"
+#define Xdvi_HOME_POSITION_Y_STR "y"
+#define Xdvi_SCROLL_CURRENT_STR "Use current position as home position"
+#define Xdvi_REMEMBER_WINDOWSIZE_STR "Remember current window size"
+#define Xdvi_PAPER_PORTRAIT_STR "Portrait"
+#define Xdvi_PAPER_LANDSCAPE_STR "Landscape"
+#define Xdvi_APPLY_STR "Apply"
+
+#define Xdvi_PREFS_BROWSER_DEFAULTS \
+ "mozilla -remote 'openURL(%s,new-window)'\n" \
+ "netscape -raise -remote 'openURL(%s,new-window)'\n" \
+ "xterm -e lynx %s\n" \
+ Xdvi_ADD_COMMAND_STR
+#define Xdvi_PREFS_EDITOR_DEFAULTS \
+ "gnuclient -q +%l %f\n" \
+ "emacsclient --no-wait +%l %f\n" \
+ "gvim --servername xdvi --remote +%l %f\n" \
+ "nc -noask +%l %f\n" \
+ "xterm -e vi +%l %f\n" \
+ Xdvi_ADD_COMMAND_STR
+
+struct prefs_choice {
+ XrmDatabase db;
+/* struct x_resources *orig; */
+/* struct x_resources *changed; */
+ Widget *depwin;
+ size_t depwin_cnt;
+};
+
+extern void h_attach_below(Widget x, Widget y);
+extern void h_update_hyperlinks(Widget w, Pixel pix); /* implemented in xm_prefs_fonts.c */
+
+#endif /* MOTIF */
+
+#endif /* XM_PREFS_P_H_ */
+
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_appearance.c b/Build/source/texk/xdvik/gui/xm_prefs_appearance.c
new file mode 100644
index 00000000000..b7f966059d5
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_appearance.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Panel 1 (Apperance) for xdvik preferences dialog.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "x_util.h"
+#include "my-snprintf.h"
+#include "xm_colorsel.h"
+#include "topic-window.h"
+#include "message-window.h"
+#include "util.h"
+#include "events.h"
+
+#include "xm_toolbar.h"
+#include "xm_menu.h"
+#include "statusline.h"
+#include "pagesel.h"
+
+#include "xm_prefsP.h"
+#include "xm_prefs_appearance.h"
+
+#ifdef MOTIF /* entire file */
+
+#include <X11/Xatom.h>
+
+#include <Xm/Xm.h>
+#include <Xm/Protocols.h>
+#include <Xm/DialogS.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushB.h>
+#include <Xm/Form.h>
+#include <Xm/Frame.h>
+#include <Xm/PanedW.h>
+#include <Xm/DrawnB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Scale.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+
+/*
+ * Handy defaults
+ */
+static Arg one_of_many = { XmNindicatorType, XmONE_OF_MANY };
+static Arg n_of_many = { XmNindicatorType, XmN_OF_MANY };
+static Arg frame_title = { XmNchildType, XmFRAME_TITLE_CHILD };
+static Arg two_cols[] = {
+ { XmNpacking, XmPACK_TIGHT },
+ { XmNnumColumns, 2 },
+ { XmNorientation, XmHORIZONTAL }
+};
+static Arg two_cols_fixed[] = {
+ { XmNpacking, XmPACK_COLUMN },
+ { XmNnumColumns, 2 }
+};
+
+static void
+match_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+ Widget inverted, boxed;
+
+ UNUSED(w);
+ UNUSED(call_data);
+
+ resource.match_highlight_inverted = !resource.match_highlight_inverted;
+
+ /* force a redraw so that a current match is updated if there was one */
+ globals.ev.flags |= EV_NEWPAGE;
+
+ store_preference(&(prefs->db), "matchInverted", "%s",
+ resource.match_highlight_inverted ? "True" : "False");
+
+ if (get_widget_by_name(&inverted, info->shell, Xdvi_MATCH_INVERTED_STR, True)
+ && get_widget_by_name(&boxed, info->shell, Xdvi_MATCH_BOXED_STR, True)) {
+
+ XmToggleButtonGadgetSetState(inverted, resource.match_highlight_inverted, False);
+ XmToggleButtonGadgetSetState(boxed, !resource.match_highlight_inverted, False);
+ }
+}
+
+static void
+tooltips_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+ const char *w_name = XtName(w);
+
+ UNUSED(call_data);
+
+ if (strcmp(w_name, Xdvi_TIPS_STATUSLINE) == 0) {
+ resource.tooltips_in_statusline = !resource.tooltips_in_statusline;
+ store_preference(&(prefs->db), "tooltipsInStatusline", "%s",
+ resource.tooltips_in_statusline ? "True" : "False");
+ }
+ else if (strcmp(w_name, Xdvi_TIPS_POPUPS) == 0) {
+ Widget label1, text, label2;
+
+ resource.show_tooltips = !resource.show_tooltips;
+
+ if (!resource.show_tooltips && resource.tooltips_wait_period >= 0) {
+ if (resource.tooltips_wait_period == 0)
+ resource.tooltips_wait_period = -1;
+ else
+ resource.tooltips_wait_period = -resource.tooltips_wait_period;
+ }
+ else if (resource.show_tooltips && resource.tooltips_wait_period < 0) {
+ resource.tooltips_wait_period = -resource.tooltips_wait_period;
+ }
+ store_preference(&(prefs->db), "showTooltips", "%s", resource.show_tooltips ? "True" : "False");
+
+ if (get_widget_by_name(&label1, info->shell, Xdvi_TIPS_DELAY_LABEL1, True)
+ && get_widget_by_name(&text, info->shell, Xdvi_TIPS_DELAY_TEXT, True)
+ && get_widget_by_name(&label2, info->shell, Xdvi_TIPS_DELAY_LABEL2, True)) {
+
+ XtSetSensitive(label1, resource.show_tooltips);
+ XtSetSensitive(text, resource.show_tooltips);
+ XtSetSensitive(label2, resource.show_tooltips);
+ }
+ }
+ else if (strcmp(w_name, Xdvi_TIPS_DELAY_TEXT) == 0) {
+ char *buf = XmTextFieldGetString(w);
+ int val = strtol(buf, (char **)NULL, 10);
+ XtFree((char *)buf);
+ TRACE_GUI((stderr, "tooltips_cb wait period2: %d\n", val));
+
+ resource.tooltips_wait_period = val;
+ store_preference(&(prefs->db), "tipShell.waitPeriod", "%d", val);
+
+ }
+ else {
+ XDVI_WARNING((stderr, "unexpected widget name `%s' in tooltips_cb", XtName(w)));
+ }
+
+}
+
+#if 0
+static void
+toolbar_buttons_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct x_resources *res = (struct x_resources *)(info->data);
+ Boolean is_flat = False, is_raised = False;
+
+ Widget flat_b, raised_b;
+
+ UNUSED(call_data);
+
+ if (!get_widget_by_name(&flat_b, XtParent(w), TB_BUTTONS_FLAT_STR, True) ||
+ !get_widget_by_name(&raised_b, XtParent(w), TB_BUTTONS_RAISED_STR, True))
+ return;
+
+ if (w == flat_b) {
+ is_flat = True;
+ }
+ else if (w == raised_b) {
+ is_raised = True;
+ }
+ else {
+ unexpected_widget_in_callback(w, "toolbar_buttons_cb()");
+ return;
+ }
+
+ res->toolbar_buttons_raised = is_raised ? True : False;
+
+ XmToggleButtonGadgetSetState(raised_b, is_raised, False);
+ XmToggleButtonGadgetSetState(flat_b, is_flat, False);
+}
+#endif /* 0 */
+
+void update_preferences_expert(void)
+{
+ Widget shell;
+ Widget statusline_b, toolbar_b, pagelist_b, scrollbars_b;
+
+ /* it's not an error if the prefs dialog doesn't exist yet */
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&statusline_b, shell, Xdvi_GUI_STATUSLINE_STR, True)
+ && get_widget_by_name(&toolbar_b, shell, Xdvi_GUI_TOOLBAR_STR, True)
+ && get_widget_by_name(&pagelist_b, shell, Xdvi_GUI_PAGELIST_STR, True)
+ && get_widget_by_name(&scrollbars_b, shell, Xdvi_GUI_SCROLLBARS_STR, True)) {
+
+ XmToggleButtonGadgetSetState(statusline_b, resource.expert_mode & XPRT_SHOW_STATUSLINE ? True : False, False);
+ XmToggleButtonGadgetSetState(toolbar_b, resource.expert_mode & XPRT_SHOW_TOOLBAR ? True : False, False);
+ XmToggleButtonGadgetSetState(pagelist_b, resource.expert_mode & XPRT_SHOW_PAGELIST ? True : False, False);
+ XmToggleButtonGadgetSetState(scrollbars_b, resource.expert_mode & XPRT_SHOW_SCROLLBARS ? True : False, False);
+ }
+}
+
+void update_preferences_tooltips(void)
+{
+ Widget shell;
+ Widget statusline_b, popup_b, label1, text, label2;
+
+ if (resource.toolbar_unusable)
+ return;
+
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, True)
+ && get_widget_by_name(&statusline_b, shell, Xdvi_TIPS_STATUSLINE, True)
+ && get_widget_by_name(&popup_b, shell, Xdvi_TIPS_POPUPS, True)
+ && get_widget_by_name(&label1, shell, Xdvi_TIPS_DELAY_LABEL1, True)
+ && get_widget_by_name(&text, shell, Xdvi_TIPS_DELAY_TEXT, True)
+ && get_widget_by_name(&label2, shell, Xdvi_TIPS_DELAY_LABEL2, True)) {
+
+ char buf[LENGTH_OF_INT];
+
+ SNPRINTF(buf, LENGTH_OF_INT, "%d", ABS(resource.tooltips_wait_period));
+ XtVaSetValues(text, XmNvalue, buf, NULL);
+
+ XmToggleButtonGadgetSetState(statusline_b, resource.tooltips_in_statusline, False);
+ XmToggleButtonGadgetSetState(popup_b, resource.show_tooltips, False);
+
+ XtSetSensitive(label1, resource.show_tooltips);
+ XtSetSensitive(text, resource.show_tooltips);
+ XtSetSensitive(label2, resource.show_tooltips);
+ }
+}
+
+void update_preferences_search(void)
+{
+ Widget shell;
+ Widget inverted, boxed;
+
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, True)
+ && get_widget_by_name(&inverted, shell, Xdvi_MATCH_INVERTED_STR, True)
+ && get_widget_by_name(&boxed, shell, Xdvi_MATCH_BOXED_STR, True)) {
+
+ XmToggleButtonGadgetSetState(inverted, resource.match_highlight_inverted, False);
+ XmToggleButtonGadgetSetState(boxed, !resource.match_highlight_inverted, False);
+ }
+}
+
+static void
+gui_buttons_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+ char *name = XtName(w);
+
+ UNUSED(call_data);
+
+ if (strcmp(name, Xdvi_GUI_STATUSLINE_STR) == 0) {
+ resource.expert_mode ^= XPRT_SHOW_STATUSLINE;
+ toggle_statusline();
+ update_expert_mode();
+ }
+ else if (strcmp(name, Xdvi_GUI_TOOLBAR_STR) == 0) {
+ resource.expert_mode ^= XPRT_SHOW_TOOLBAR;
+ toggle_toolbar();
+ update_expert_mode();
+ }
+ else if (strcmp(name, Xdvi_GUI_PAGELIST_STR) == 0) {
+ resource.expert_mode ^= XPRT_SHOW_PAGELIST;
+ toggle_pagelist();
+ update_expert_mode();
+ }
+ else if (strcmp(name, Xdvi_GUI_SCROLLBARS_STR) == 0) {
+#if defined(LESSTIF_VERSION)
+ static Boolean warned_about_lesstif = False;
+#endif
+ resource.expert_mode ^= XPRT_SHOW_SCROLLBARS;
+ toggle_scrollbars();
+ update_expert_mode();
+#if defined(LESSTIF_VERSION)
+ if (!warned_about_lesstif) {
+ warned_about_lesstif = True;
+ popup_message(globals.widgets.top_level,
+ MSG_INFO,
+ NULL,
+ "This version has been compiled with LessTif; "
+ "toggling the scrollbars won't work with LessTif.");
+ }
+#endif
+ }
+ else {
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ REPORT_XDVI_BUG_TEMPLATE,
+ "Unexpected label in gui buttons: |%s|!\n", name);
+ }
+ store_preference(&(prefs->db), "expertMode", "%d", resource.expert_mode);
+}
+
+
+#if 0
+static void
+toolbar_buttons_init(struct topic_info *info, Widget raised, Widget flat)
+{
+ Boolean is_flat = False, is_raised = False;
+ struct x_resources *res = (struct x_resources *)(info->data);
+
+ if (res->toolbar_buttons_raised)
+ is_raised = True;
+
+ XmToggleButtonGadgetSetState(raised, is_raised, False);
+ XmToggleButtonGadgetSetState(flat, is_flat, False);
+
+ XtAddCallback(flat, XmNvalueChangedCallback, toolbar_buttons_cb, (XtPointer)info);
+ XtAddCallback(raised, XmNvalueChangedCallback, toolbar_buttons_cb, (XtPointer)info);
+}
+#endif /* 0 */
+
+
+Widget
+prefs_appearance(struct topic_info *info)
+{
+ Widget form;
+ Widget gui_frame, gui_label, gui_rowcol,
+ gui_statusline, gui_toolbar, gui_pagelist, gui_scrollbars;
+ Widget tips_frame, tips_label, tips_form, tips_statusline;
+ Widget tips_popups, tips_delay_text, tips_delay_label1, tips_delay_label2;
+ Widget match_frame, match_label, match_rowcol, match_inverted, match_boxed;
+#if 0
+ Widget tb_buttons_frame, tb_buttons_label, tb_buttons_rowcol,
+ tb_buttons_flat, tb_buttons_raised;
+#endif
+ XmString str;
+ char buf[LENGTH_OF_INT];
+ Arg args[10];
+ int n;
+
+ form = XmCreateForm(info->right_form, "appearance_form", NULL, 0);
+ h_attach_below(form, NULL);
+
+ n = 0;
+ XtSetArg(args[n], XmNmarginWidth, 8); n++;
+ XtSetArg(args[n], XmNmarginHeight, 4); n++;
+ gui_frame = XmCreateFrame(form, "gui_frame", args, n);
+ h_attach_below(gui_frame, NULL);
+
+ gui_label = XmCreateLabelGadget(gui_frame, "Window Configuration", &frame_title, 1);
+ XtManageChild(gui_label);
+
+ gui_rowcol = XmCreateRowColumn(gui_frame, "gui_rowcol", two_cols_fixed, XtNumber(two_cols_fixed));
+ XtManageChild(gui_rowcol);
+
+ gui_statusline = XmCreateToggleButtonGadget(gui_rowcol, Xdvi_GUI_STATUSLINE_STR, &n_of_many, 1);
+ XmToggleButtonGadgetSetState(gui_statusline, resource.expert_mode & XPRT_SHOW_STATUSLINE ? True : False, False);
+ XtManageChild(gui_statusline);
+
+ gui_toolbar = XmCreateToggleButtonGadget(gui_rowcol, Xdvi_GUI_TOOLBAR_STR, &n_of_many, 1);
+ XmToggleButtonGadgetSetState(gui_toolbar, resource.expert_mode & XPRT_SHOW_TOOLBAR ? True : False, False);
+ XtManageChild(gui_toolbar);
+
+ gui_pagelist = XmCreateToggleButtonGadget(gui_rowcol, Xdvi_GUI_PAGELIST_STR, &n_of_many, 1);
+ XmToggleButtonGadgetSetState(gui_pagelist, resource.expert_mode & XPRT_SHOW_PAGELIST ? True : False, False);
+ XtManageChild(gui_pagelist);
+
+ gui_scrollbars = XmCreateToggleButtonGadget(gui_rowcol, Xdvi_GUI_SCROLLBARS_STR, &n_of_many, 1);
+ XmToggleButtonGadgetSetState(gui_scrollbars, resource.expert_mode & XPRT_SHOW_SCROLLBARS ? True : False, False);
+ XtManageChild(gui_scrollbars);
+
+ XtAddCallback(gui_statusline, XmNvalueChangedCallback, gui_buttons_cb, (XtPointer)info);
+ XtAddCallback(gui_toolbar, XmNvalueChangedCallback, gui_buttons_cb, (XtPointer)info);
+ XtAddCallback(gui_pagelist, XmNvalueChangedCallback, gui_buttons_cb, (XtPointer)info);
+ XtAddCallback(gui_scrollbars, XmNvalueChangedCallback, gui_buttons_cb, (XtPointer)info);
+
+ n = 0;
+ XtSetArg(args[n], XmNmarginWidth, 8); n++;
+ XtSetArg(args[n], XmNmarginHeight, 4); n++;
+ XtSetArg(args[n], XmNtopOffset, 10); n++;
+ tips_frame = XmCreateFrame(form, "tips_frame", args, n);
+ h_attach_below(tips_frame, gui_frame);
+
+ tips_label = XmCreateLabelGadget(tips_frame, "Show Tooltips", &frame_title, 1);
+ XtManageChild(tips_label);
+
+ tips_form = XmCreateForm(tips_frame, "tips_form", NULL, 0);
+
+ str = XmStringCreateLocalized("As Text in Statusline");
+ tips_statusline = XtVaCreateManagedWidget(Xdvi_TIPS_STATUSLINE,
+ xmToggleButtonGadgetClass, tips_form,
+ XmNlabelString, str,
+ XmNindicatorType, XmN_OF_MANY,
+ XmNset, True,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+
+ str = XmStringCreateLocalized("As Popups");
+ tips_popups = XtVaCreateManagedWidget(Xdvi_TIPS_POPUPS,
+ xmToggleButtonGadgetClass, tips_form,
+ XmNlabelString, str,
+ XmNindicatorType, XmN_OF_MANY,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tips_statusline,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+
+ str = XmStringCreateLocalized("with");
+ tips_delay_label1 = XtVaCreateManagedWidget(Xdvi_TIPS_DELAY_LABEL1,
+ xmLabelGadgetClass, tips_form,
+ XmNlabelString, tips_form,
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tips_statusline,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, tips_popups,
+ XmNleftOffset, 0, /* no spacing to prev text */
+ NULL);
+ XmStringFree(str);
+
+ SNPRINTF(buf, LENGTH_OF_INT, "%d", ABS(resource.tooltips_wait_period));
+
+ tips_delay_text = XtVaCreateManagedWidget(Xdvi_TIPS_DELAY_TEXT,
+ xmTextFieldWidgetClass, tips_form,
+ XmNcolumns, 4,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tips_statusline,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, tips_delay_label1,
+ XmNvalue, buf,
+ NULL);
+
+ str = XmStringCreateLocalized("milliseconds delay");
+ tips_delay_label2 = XtVaCreateManagedWidget(Xdvi_TIPS_DELAY_LABEL2,
+ xmLabelGadgetClass, tips_form,
+ XmNlabelString, str,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tips_statusline,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, tips_delay_text,
+ NULL);
+
+ adjust_heights(tips_popups, tips_delay_label1, tips_delay_text, tips_delay_label2, NULL);
+
+ XmToggleButtonGadgetSetState(tips_statusline, resource.tooltips_in_statusline, False);
+ XmToggleButtonGadgetSetState(tips_popups, resource.show_tooltips, False);
+
+ if (resource.toolbar_unusable) {
+ XtSetSensitive(tips_frame, False);
+ }
+ else {
+ XtSetSensitive(tips_delay_label1, resource.show_tooltips);
+ XtSetSensitive(tips_delay_text, resource.show_tooltips);
+ XtSetSensitive(tips_delay_label2, resource.show_tooltips);
+
+ XtAddCallback(tips_statusline, XmNvalueChangedCallback, tooltips_cb, (XtPointer)info);
+ XtAddCallback(tips_popups, XmNvalueChangedCallback, tooltips_cb, (XtPointer)info);
+ XtAddCallback(tips_delay_text, XmNvalueChangedCallback, tooltips_cb, (XtPointer)info);
+ }
+
+#if 0
+ tb_buttons_frame = XmCreateFrame(form, "tb_buttons_frame", &v_off, 1);
+ h_attach_below(tb_buttons_frame, tips_frame);
+
+ tb_buttons_label = XmCreateLabelGadget(tb_buttons_frame, "Toolbar Buttons:", &frame_title, 1);
+ XtManageChild(tb_buttons_label);
+
+ tb_buttons_rowcol = XmCreateRowColumn(tb_buttons_frame, "tb_buttons_rowcol", two_cols, XtNumber(two_cols));
+ XtManageChild(tb_buttons_rowcol);
+
+ tb_buttons_raised = XmCreateToggleButtonGadget(tb_buttons_rowcol, "Raised", &one_of_many, 1);
+ XtManageChild(tb_buttons_raised);
+
+ tb_buttons_flat = XmCreateToggleButtonGadget(tb_buttons_rowcol, "Flat", &one_of_many, 1);
+ XtManageChild(tb_buttons_flat);
+ toolbar_buttons_init((XtPointer)info, tb_buttons_raised, tb_buttons_flat);
+#endif /* 0 */
+
+ n = 0;
+ XtSetArg(args[n], XmNmarginWidth, 8); n++;
+ XtSetArg(args[n], XmNmarginHeight, 4); n++;
+ XtSetArg(args[n], XmNtopOffset, 10); n++;
+ match_frame = XmCreateFrame(form, "match_frame", args, n);
+ XtVaSetValues(match_frame,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, tips_frame,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ match_label = XmCreateLabelGadget(match_frame, "String Matches are shown:", &frame_title, 1);
+ XtManageChild(match_label);
+
+ match_rowcol = XmCreateRowColumn(match_frame, "tb_buttons_rowcol", two_cols, XtNumber(two_cols));
+ XtManageChild(match_rowcol);
+
+ match_inverted = XmCreateToggleButtonGadget(match_rowcol, Xdvi_MATCH_INVERTED_STR, &one_of_many, 1);
+ XtManageChild(match_inverted);
+
+ match_boxed = XmCreateToggleButtonGadget(match_rowcol, Xdvi_MATCH_BOXED_STR, &one_of_many, 1);
+ XtManageChild(match_boxed);
+
+ XmToggleButtonGadgetSetState(match_inverted, resource.match_highlight_inverted, False);
+ XmToggleButtonGadgetSetState(match_boxed, !resource.match_highlight_inverted, False);
+
+ XtAddCallback(match_inverted, XmNvalueChangedCallback, match_cb, (XtPointer)info);
+ XtAddCallback(match_boxed, XmNvalueChangedCallback, match_cb, (XtPointer)info);
+
+ /* manage children (order shouldn't matter, since children are already managed, but ...) */
+ XtManageChild(gui_frame);
+
+ XtManageChild(tips_form);
+ XtManageChild(tips_frame);
+
+#if 0
+ XtManageChild(tb_buttons_frame);
+#endif
+
+ XtManageChild(match_frame);
+
+ XtManageChild(form);
+
+ return form;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_appearance.h b/Build/source/texk/xdvik/gui/xm_prefs_appearance.h
new file mode 100644
index 00000000000..1c94a184d3c
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_appearance.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef XM_PREFS_APPEARANCE_
+#define XM_PREFS_APPEARANCE_
+
+#ifdef MOTIF
+
+struct topic_info; /* forward declaration */
+extern Widget prefs_appearance(struct topic_info *info);
+extern void update_preferences_expert(void);
+extern void update_preferences_tooltips(void);
+extern void update_preferences_search(void);
+
+#endif /* MOTIF */
+
+#endif /* XM_PREFS_APPEARANCE_ */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_fonts.c b/Build/source/texk/xdvik/gui/xm_prefs_fonts.c
new file mode 100644
index 00000000000..bf25734bc50
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_fonts.c
@@ -0,0 +1,696 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Panel 2 (Fonts and colors) for xdvik preferences dialog.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "x_util.h"
+#include "xm_colorsel.h"
+#include "topic-window.h"
+#include "util.h"
+#include "events.h"
+#include "hypertex.h"
+#include "my-snprintf.h"
+
+#include "xm_prefsP.h"
+#include "xm_prefs_fonts.h"
+
+#ifdef MOTIF /* entire file */
+
+#include <X11/Xatom.h>
+
+#include <Xm/Xm.h>
+#include <Xm/Protocols.h>
+#include <Xm/DialogS.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushB.h>
+#include <Xm/Form.h>
+#include <Xm/Frame.h>
+#include <Xm/PanedW.h>
+#include <Xm/DrawnB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Scale.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+
+#if XmVersion >= 2000 && !defined(LESSTIF_VERSION)
+/* spinbox only available with Motif 2.0; the lesstif version (as of 0.93) looks like shit */
+#include <Xm/SpinB.h>
+#define USE_SPINBOX 1
+#else
+#define USE_SPINBOX 0
+#endif
+
+/*
+ * Handy defaults
+ */
+static Arg v_off = { XmNtopOffset, 10 };
+static Arg n_of_many = { XmNindicatorType, XmN_OF_MANY };
+static Arg frame_title = { XmNchildType, XmFRAME_TITLE_CHILD };
+
+
+static void
+underline_toggle_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *tinfo = (struct topic_info *)client_data;
+ struct prefs_choice *prefs;
+ Boolean is_set;
+
+ UNUSED(call_data);
+
+ ASSERT(tinfo != NULL, "struct topic_info * in underline_toggle_cb mustn't be NULL!");
+ prefs = (struct prefs_choice *)tinfo->data;
+
+ XtVaGetValues(w, XmNset, &is_set, NULL);
+ if (is_set)
+ resource.link_style |= 1;
+ else
+ resource.link_style &= ~1;
+
+ store_preference(&(prefs->db), "linkStyle", "%d", resource.link_style);
+
+ /* update display */
+ globals.ev.flags |= EV_NEWPAGE;
+ XFlush(DISP);
+}
+
+static void
+colorspecial_toggle_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *tinfo = (struct topic_info *)client_data;
+ struct prefs_choice *prefs;
+
+ UNUSED(w);
+/* UNUSED(client_data); */
+ UNUSED(call_data);
+
+ ASSERT(tinfo != NULL, "struct topic_info * in colorspecial_toggle_cb mustn't be NULL!");
+ prefs = (struct prefs_choice *)tinfo->data;
+
+ do_toggle_color(False);
+ store_preference(&(prefs->db), "color", "%s", resource.use_color ? "True" : "False");
+}
+
+static void
+darkness_text_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ char *text;
+ int val;
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+
+#if USE_SPINBOX
+ /* synchronize internal spinbox value. Apparently this loses the insertion position,
+ so we need to save it and set it again. */
+ XmTextPosition pos = XmTextFieldGetInsertionPosition(w);
+
+ UNUSED(call_data);
+ text = XmTextFieldGetString(w);
+ val = strtol(text, (char **)NULL, 10);
+
+ if (val != 0) {
+ XtVaSetValues(w, XmNposition, val, NULL);
+ XmTextFieldSetInsertionPosition(w, pos);
+ }
+#else
+ Widget text_field;
+ UNUSED(call_data);
+
+ XtVaGetValues(w, XmNuserData, &text_field, NULL);
+ XtVaGetValues(text_field, XmNvalue, &text, NULL);
+ val = strtol(text, (char **)NULL, 10);
+#endif
+ if (XtIsRealized(w)) {
+ do_set_density(val / 100.0, True, False);
+ store_preference(&(prefs->db), "gamma", "%f", val / 100.0);
+ }
+ XtFree(text);
+}
+
+
+#if 0 /* currently unused */
+static void
+darkness_spinbox_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ int val;
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ XtVaGetValues(w, XmNposition, &val, NULL);
+ if (XtIsRealized(w)) {
+ do_set_density(val / 100.0, True, False);
+ /* fprintf(stderr, "storing pref: %d\n", val); */
+ store_preference(&(prefs->db), "gamma", "%f", val / 100.0);
+ }
+
+}
+#endif /* currently unused */
+
+
+void
+h_update_hyperlinks(Widget w, Pixel pix)
+{
+ const char *name = XtName(w);
+ int type = 0;
+
+ if (strcmp(name, Xdvi_UNVISITED_LINKS_BTN) == 0) {
+ type = 1;
+ }
+ else if (strcmp(name, Xdvi_VISITED_LINKS_BTN) == 0) {
+ type = 2;
+ }
+
+ /* fprintf(stderr, "WIDGET: |%s|; type: %d\n", name, type); */
+
+ if (type != 0) {
+ GC new_gc = set_or_make_gc(NULL, GXcopy, pix, resource.back_Pixel);
+ GC old_gc;
+ double r, g, b;
+ double factor = 65535.0;
+ XColor color;
+
+ pixel_to_color(pix, &color, DISP, G_colormap);
+ r = color.red / factor;
+ g = color.green / factor;
+ b = color.blue / factor;
+
+ if (type == 1) {
+ old_gc = globals.gc.linkcolor;
+ sprintf(g_link_color_rgb, "push rgb %.2f %.2f %.2f", r, g, b);
+ }
+ else {
+ old_gc = globals.gc.visited_linkcolor;
+ sprintf(g_visited_link_color_rgb, "push rgb %.2f %.2f %.2f", r, g, b);
+ }
+
+ if (type == 1) {
+ globals.gc.linkcolor = new_gc;
+ XFreeGC(XtDisplay(w), old_gc);
+ }
+ else {
+ globals.gc.visited_linkcolor = new_gc;
+ XFreeGC(XtDisplay(w), old_gc);
+ }
+ /* update display */
+ globals.ev.flags |= EV_NEWPAGE;
+ XFlush(DISP);
+ }
+}
+
+static void
+redraw_or_push_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ XmDrawnButtonCallbackStruct *cbs = (XmDrawnButtonCallbackStruct *)call_data;
+ static GC border_gc = 0;
+ struct color_button_info *cinfo;
+ Pixel pix = (Pixel)client_data;
+
+ if (cbs == NULL) {
+ XDVI_WARNING((stderr, "cinfo mustn't be NULL in redraw_or_push_cb!\n"));
+ return;
+ }
+
+ /* this can also be called via XtCallCallbacks, without call_data */
+ if (cbs->reason == XmCR_EXPOSE) {
+ /* redraw button label */
+ Dimension high_thick, st, wd, ht;
+ Dimension inner_w, inner_h, off_x, off_y;
+ GC label_gc;
+ XGCValues values;
+
+ XtVaGetValues(w,
+ XmNhighlightThickness, &high_thick,
+ XmNshadowThickness, &st,
+ XmNwidth, &wd,
+ XmNheight, &ht,
+ XmNuserData, &cinfo,
+ NULL);
+
+ values.function = GXcopy;
+
+ if (border_gc == 0) {
+ /* create the static GC for drawing the border - Note: never free'd! */
+ values.foreground = BlackPixelOfScreen(XtScreen(w));
+ /* values.line_width = 2; */
+ /* note: never free'd! */
+ border_gc = XCreateGC(XtDisplay(w), XtWindow(w),
+ GCFunction | GCForeground /* | GCLineWidth */, &values);
+ }
+ values.foreground = cinfo->pixel;
+ label_gc = XCreateGC(XtDisplay(w), XtWindow(w),
+ GCFunction | GCForeground, &values);
+
+ off_x = high_thick + st + 4;
+ inner_w = wd - 2 * off_x;
+ off_y = high_thick + st + 4;
+ inner_h = ht - 2 * off_y;
+#if 0
+ fprintf(stderr, "shadow: %d, high: %d\n", st, high_thick);
+ fprintf(stderr, "width: %d, height: %d\n", wd, ht);
+ fprintf(stderr, "inner w: %d, inner h: %d\n", inner_w, inner_h);
+#endif
+
+ XFillRectangle(XtDisplay(w), XtWindow(w), label_gc,
+ off_x, off_y, inner_w, inner_h);
+ XDrawRectangle(XtDisplay(w), XtWindow(w), border_gc,
+ off_x - 1, off_y - 1, inner_w + 1, inner_h + 1);
+ XFreeGC(XtDisplay(w), label_gc);
+
+ if (pix != cinfo->pixel) {
+ h_update_hyperlinks(w, cinfo->pixel);
+ }
+ }
+ else if (cbs->reason == XmCR_ACTIVATE) {
+ /* pushed, open color dialog */
+ XtVaGetValues(w, XmNuserData, &cinfo, NULL);
+ if (cinfo != NULL) {
+ cinfo->w = w;
+ popup_color_dialog(globals.widgets.top_level, cinfo);
+ }
+ else {
+ XDVI_WARNING((stderr, "cinfo mustn't be NULL in redraw_or_push_cb!\n"));
+ return;
+ }
+ }
+ /* else, XmCR_RESIZE - nothing to do */
+}
+
+static Widget
+h_create_colorsample(Widget parent, Widget left,
+ const char *name,
+ const char *resource_name,
+ Pixel pix,
+ struct topic_info *info)
+{
+ struct color_button_info *cinfo = xmalloc(sizeof *cinfo); /* note: never free()d */
+ Widget button;
+
+ UNUSED(left);
+
+ cinfo->pixel = pix;
+ cinfo->tinfo = info;
+ cinfo->resource_name = xstrdup(resource_name); /* note: never free()d */
+
+ button = XtVaCreateManagedWidget(name, xmDrawnButtonWidgetClass, parent,
+ XtNwidth, 42,
+ XtNheight, 28,
+ XmNuserData, cinfo,
+ /* we want the normal button look here to
+ make it obvious that users can press it */
+ XmNshadowType, XmSHADOW_OUT,
+ XmNpushButtonEnabled, True,
+ NULL);
+ XtAddCallback(button, XmNactivateCallback, redraw_or_push_cb, (XtPointer)pix);
+ XtAddCallback(button, XmNexposeCallback, redraw_or_push_cb, (XtPointer)pix);
+ XtAddCallback(button, XmNresizeCallback, redraw_or_push_cb, (XtPointer)pix);
+
+ return button;
+}
+
+
+static Widget
+h_create_fonts_frame(Widget top, struct topic_info *info)
+{
+ Widget darkness_form, darkness_label;
+
+ UNUSED(info);
+
+ darkness_form = XmCreateForm(top, "darkness_form", NULL, 0);
+ XtVaSetValues(darkness_form,
+ XmNverticalSpacing, 10,
+ XmNhorizontalSpacing, 10,
+ NULL);
+
+
+ darkness_label = XmCreateLabelGadget(darkness_form, "Font Darkness: ", NULL, 0);
+ XtVaSetValues(darkness_label,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ XtManageChild(darkness_label);
+ {
+ Widget darkness_text;
+#if USE_SPINBOX
+ Widget darkness_spinbox = XmCreateSpinBox(darkness_form, Xdvi_DARKNESS_SPINBOX, NULL, 0);
+ darkness_text = XmCreateTextField(darkness_spinbox, Xdvi_DARKNESS_TEXT, NULL, 0);
+ XtVaSetValues(darkness_spinbox,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, darkness_label,
+ XmNinitialDelay, 200,
+ XmNrepeatDelay, 50,
+ NULL);
+ XtVaSetValues(darkness_text,
+ XmNspinBoxChildType, XmNUMERIC,
+ XmNminimumValue, 0,
+ XmNmaximumValue, 1000,
+ XmNeditable, True,
+ XmNcolumns, 4,
+ XmNincrementValue, 1,
+ XmNwrap, False, /* too confusing */
+ XmNposition, (int)(resource.gamma * 100.0 + 0.5),
+ NULL);
+ XtAddCallback(darkness_text, XmNactivateCallback, darkness_text_cb, (XtPointer)info);
+ XtAddCallback(darkness_text, XmNvalueChangedCallback, darkness_text_cb, (XtPointer)info);
+
+ adjust_heights(darkness_spinbox, darkness_text, darkness_label, NULL);
+
+ XtManageChild(darkness_text);
+ XtManageChild(darkness_spinbox);
+#else
+ char buf[LENGTH_OF_INT];
+ Widget darkness_button;
+ darkness_text = XmCreateTextField(darkness_form, Xdvi_DARKNESS_TEXT, NULL, 0);
+ SNPRINTF(buf, LENGTH_OF_INT, "%d", (int)(resource.gamma * 100.0 + 0.5));
+ XtVaSetValues(darkness_text,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, darkness_label,
+ XmNcolumns, 4,
+ XmNvalue, buf,
+ XmNuserData, darkness_text,
+ NULL);
+ XtOverrideTranslations(darkness_text, XtParseTranslationTable("<Key>Return:activate()"));
+ XtAddCallback(darkness_text, XmNactivateCallback, darkness_text_cb, (XtPointer)info);
+
+ darkness_button = XmCreatePushButton(darkness_form, Xdvi_APPLY_STR, NULL, 0);
+ XtVaSetValues(darkness_button,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, darkness_text,
+ XmNuserData, darkness_text,
+ NULL);
+ XtAddCallback(darkness_button, XmNactivateCallback, darkness_text_cb, (XtPointer)info);
+
+ adjust_heights(darkness_label, darkness_text, darkness_button, NULL);
+ XtManageChild(darkness_text);
+ XtManageChild(darkness_button);
+#endif
+ }
+
+/* XtManageChild(darkness_form); */
+
+ return darkness_form;
+}
+
+static Widget
+h_create_colors_form(Widget top, struct topic_info *info)
+{
+ Widget text_bg_frame, text_bg_label, text_bg_form;
+ Widget links_frame, links_label, links_form;
+ Widget fg_label, fg_button;
+ Widget bg_label, bg_button;
+ Widget unvisited_label, unvisited_button;
+ Widget visited_label, visited_button;
+ Widget underline_toggle;
+ Widget colorspecials_toggle;
+
+ Widget form = XmCreateForm(top, "colors_form", NULL, 0);
+ Pixel visited_link_pix, link_pix;
+
+ str_to_pixel(top, resource.visited_link_color, &visited_link_pix);
+ str_to_pixel(top, resource.link_color, &link_pix);
+
+ text_bg_frame = XmCreateFrame(form, "text_bg_frame", NULL, 0);
+ XtVaSetValues(text_bg_frame,
+ XmNmarginWidth, 10,
+ XmNmarginHeight, 10,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_POSITION,
+ XmNrightPosition, 50,
+ XmNrightOffset, 10,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ text_bg_label = XmCreateLabelGadget(text_bg_frame, "Text Color", &frame_title, 1);
+ XtManageChild(text_bg_label);
+
+ text_bg_form = XmCreateForm(text_bg_frame, "fg_form", NULL, 0);
+ XtVaSetValues(text_bg_form, XmNverticalSpacing, 2, NULL);
+
+ fg_label = XmCreateLabelGadget(text_bg_form, Xdvi_FG_COLOR_STR, NULL, 0);
+ fg_button = h_create_colorsample(text_bg_form, fg_label,
+ Xdvi_FG_COLOR_BTN, "foreground",
+ resource.fore_Pixel, info);
+ XtVaSetValues(fg_label,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_FORM,
+ NULL);
+ XtVaSetValues(fg_button,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_NONE,
+ NULL);
+ adjust_heights(fg_label, fg_button, NULL);
+ XtManageChild(fg_label);
+ XtManageChild(fg_button);
+
+ bg_label = XmCreateLabelGadget(text_bg_form, Xdvi_BG_COLOR_STR, NULL, 0);
+ bg_button = h_create_colorsample(text_bg_form, bg_label,
+ Xdvi_BG_COLOR_BTN, "background",
+ resource.back_Pixel, info);
+ XtVaSetValues(bg_label,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, fg_label,
+ NULL);
+ XtVaSetValues(bg_button,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_NONE,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, fg_label,
+ NULL);
+ adjust_heights(bg_label, bg_button, NULL);
+ XtManageChild(bg_label);
+ XtManageChild(bg_button);
+
+ colorspecials_toggle = XmCreateToggleButtonGadget(text_bg_form, Xdvi_DOCUMENT_COLORS_STR, &n_of_many, 1);
+ XtVaSetValues(colorspecials_toggle,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, bg_label,
+ NULL);
+ XtManageChild(colorspecials_toggle);
+ XmToggleButtonGadgetSetState(colorspecials_toggle, resource.use_color, False);
+ XtAddCallback(colorspecials_toggle, XmNvalueChangedCallback, colorspecial_toggle_cb, (XtPointer)info);
+
+ links_frame = XmCreateFrame(form, "links_frame", NULL, 0);
+ XtVaSetValues(links_frame,
+ XmNmarginWidth, 10,
+ XmNmarginHeight, 10,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, text_bg_frame,
+ XmNleftOffset, 10,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ links_label = XmCreateLabelGadget(links_frame, "Hyperlinks", &frame_title, 1);
+ XtManageChild(links_label);
+
+ links_form = XmCreateForm(links_frame, "links_form", NULL, 0);
+ XtVaSetValues(links_form,
+ XmNverticalSpacing, 2,
+ NULL);
+
+ unvisited_label = XmCreateLabelGadget(links_form, Xdvi_UNVISITED_LINKS_STR, NULL, 0);
+ unvisited_button = h_create_colorsample(links_form, unvisited_label,
+ Xdvi_UNVISITED_LINKS_BTN, "linkColor",
+ link_pix, info);
+ XtVaSetValues(unvisited_label,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_FORM,
+ NULL);
+ XtVaSetValues(unvisited_button,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_NONE,
+ XmNtopAttachment, XmATTACH_FORM,
+ NULL);
+ adjust_heights(unvisited_label, unvisited_button, NULL);
+ XtManageChild(unvisited_label);
+ XtManageChild(unvisited_button);
+
+ visited_label = XmCreateLabelGadget(links_form, Xdvi_VISITED_LINKS_STR, NULL, 0);
+ visited_button = h_create_colorsample(links_form, visited_label,
+ Xdvi_VISITED_LINKS_BTN, "visitedLinkColor",
+ visited_link_pix, info);
+ XtVaSetValues(visited_label,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, unvisited_label,
+ NULL);
+ XtVaSetValues(visited_button,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_NONE,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, unvisited_label,
+ NULL);
+ adjust_heights(visited_label, visited_button, NULL);
+ XtManageChild(visited_label);
+ XtManageChild(visited_button);
+
+ underline_toggle = XmCreateToggleButtonGadget(links_form, Xdvi_LINKS_UNDERLINED_STR, &n_of_many, 1);
+ XtVaSetValues(underline_toggle,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, visited_label,
+ NULL);
+ XtManageChild(underline_toggle);
+
+/* if (res->link_style & 1) */
+ if (resource.link_style & 1)
+ XmToggleButtonGadgetSetState(underline_toggle, True, False);
+ else
+ XmToggleButtonGadgetSetState(underline_toggle, False, False);
+
+ XtAddCallback(underline_toggle, XmNvalueChangedCallback, underline_toggle_cb, (XtPointer)info);
+
+ XtManageChild(links_frame);
+ XtManageChild(text_bg_frame);
+
+ XtManageChild(text_bg_form);
+ XtManageChild(links_form);
+
+ return form;
+}
+
+void update_preferences_color(void)
+{
+ Widget shell, button;
+
+ /* it's not an error if the prefs dialog doesn't exist yet */
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&button, shell, Xdvi_DOCUMENT_COLORS_STR, True)) {
+ XmToggleButtonGadgetSetState(button, resource.use_color, False);
+ }
+}
+
+void update_preferences_hyperlinks(void)
+{
+ Widget shell, button;
+
+ /* it's not an error if the prefs dialog doesn't exist yet */
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&button, shell, Xdvi_LINKS_UNDERLINED_STR, True)) {
+ XmToggleButtonGadgetSetState(button, resource.link_style & 1 ? True : False, False);
+ }
+}
+
+void update_preferences_darkness(void)
+{
+ Widget shell, text;
+
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&text, shell, Xdvi_DARKNESS_TEXT, True)) {
+
+ char buf[LENGTH_OF_INT];
+ SNPRINTF(buf, LENGTH_OF_INT, "%d", (int)(resource.gamma * 100.0 + 0.5));
+#if USE_SPINBOX
+ XmTextFieldSetString(text, buf);
+ XtVaSetValues(text, XmNposition, (int)(resource.gamma * 100.0 + 0.5), NULL);
+#else
+ XtVaSetValues(text, XmNvalue, buf, NULL);
+#endif
+ }
+}
+
+Widget
+prefs_fonts_and_colors(struct topic_info *info)
+{
+ Widget form;
+ Widget colors_form;
+ Widget other_colors_frame, fonts_frame;
+
+ form = XmCreateForm(info->right_form, "fonts_colors_form", NULL, 0);
+ h_attach_below(form, NULL);
+
+ colors_form = h_create_colors_form(form, info);
+ h_attach_below(colors_form, NULL);
+ XtManageChild(colors_form);
+
+ { /* other colors - currently only highlight color */
+ Widget other_colors_form, other_colors_label;
+ Widget hl_color_text, hl_color_button;
+
+ other_colors_frame = XmCreateFrame(form, "other_colors_frame", &v_off, 1);
+ XtVaSetValues(other_colors_frame,
+ XmNmarginWidth, 10,
+ NULL);
+ h_attach_below(other_colors_frame, colors_form);
+
+ other_colors_label = XmCreateLabelGadget(other_colors_frame, "Highlight Color", &frame_title, 1);
+ other_colors_form = XmCreateForm(other_colors_frame, "other_colors_form", NULL, 0);
+ XtVaSetValues(other_colors_form, XmNverticalSpacing, 2, NULL);
+
+ hl_color_text = XmCreateLabelGadget(other_colors_form,
+#if defined(LESSTIF_VERSION) /* stupid LessTif doesn't wrap Labels at '\n' */
+ "Color of page border, rulers and bounding boxes.",
+#else
+ "Color used for page border, rulers in `ruler mode', and\n"
+ "bounding boxes for forward search and EPS images.",
+#endif
+ NULL, 0);
+ hl_color_button = h_create_colorsample(other_colors_form, hl_color_text,
+ Xdvi_HL_COLOR_BTN, "highlight",
+ resource.hl_Pixel, info);
+ XtVaSetValues(hl_color_text,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNbottomOffset, 10,
+ XmNalignment, XmALIGNMENT_BEGINNING,
+ NULL);
+ XtVaSetValues(hl_color_button,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ NULL);
+
+ XtManageChild(hl_color_text);
+ XtManageChild(hl_color_button);
+ XtManageChild(other_colors_form);
+ XtManageChild(other_colors_label);
+ XtManageChild(other_colors_frame);
+ }
+
+ fonts_frame = h_create_fonts_frame(form, info);
+ h_attach_below(fonts_frame, other_colors_frame);
+ XtManageChild(fonts_frame);
+
+ XtManageChild(form);
+
+ return form;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_fonts.h b/Build/source/texk/xdvik/gui/xm_prefs_fonts.h
new file mode 100644
index 00000000000..b87984cafb2
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_fonts.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef XM_PREFS_FONTS_
+#define XM_PREFS_FONTS_
+
+#ifdef MOTIF
+
+struct topic_info; /* forward declaration */
+extern Widget prefs_fonts_and_colors(struct topic_info *info);
+extern void update_preferences_color(void);
+extern void update_preferences_hyperlinks(void);
+extern void update_preferences_darkness(void);
+
+#endif /* MOTIF */
+
+#endif /* XM_PREFS_FONTS_ */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_helpers.c b/Build/source/texk/xdvik/gui/xm_prefs_helpers.c
new file mode 100644
index 00000000000..493e061827f
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_helpers.c
@@ -0,0 +1,946 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Panel 3 (Helper Applications) for xdvik preferences dialog.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "x_util.h"
+#include "xm_colorsel.h"
+#include "topic-window.h"
+#include "util.h"
+#include "string-utils.h"
+#include "message-window.h"
+#include "events.h"
+#include "xm_menu.h"
+
+#include "xm_prefsP.h"
+#include "xm_prefs.h"
+#include "xm_prefs_helpers.h"
+
+#ifdef MOTIF /* entire file */
+
+#include <X11/Xatom.h>
+
+#include <Xm/Xm.h>
+#include <Xm/Protocols.h>
+#include <Xm/DialogS.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushB.h>
+#include <Xm/Form.h>
+#include <Xm/Frame.h>
+#include <Xm/PanedW.h>
+#include <Xm/DrawnB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Scale.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/PushBG.h>
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+#include <Xm/FileSB.h>
+#include <Xm/SelectioB.h>
+
+struct choice_dialog_info {
+ struct topic_info *tinfo;
+ /* struct prefs_choice *prefs; */
+ Widget combo_box;
+ Widget message_popup;
+};
+
+static char **m_browser_list = NULL;
+static char **m_editor_list = NULL;
+
+/* "mozilla -remote 'openURL(%s,new-window)'", */
+/* "netscape -raise -remote 'openURL(%s,new-window)'", */
+/* "xterm -e lynx %s", */
+/* Xdvi_ADD_COMMAND_STR, */
+/* NULL /\* terminate *\/ */
+/* }; */
+
+/* static const char *editor_list[] = { */
+/* "gnuclient -q +%l %f", */
+/* "emacsclient --no-wait +%l %f", */
+/* "gvim --servername xdvi --remote +%l %f", */
+/* "nc -noask +%l %f", */
+/* "xterm -e vi +%l %f", */
+/* Xdvi_ADD_COMMAND_STR, */
+/* NULL /\* terminate *\/ */
+/* }; */
+
+/* combo box only available with Motif 2.0;
+ * the lesstif version is incomplete
+ */
+#if XmVersion >= 2000 && !defined(LESSTIF_VERSION)
+#include <Xm/ComboBox.h>
+#include <Xm/List.h>
+#define USE_COMBOBOX 1
+#else
+#include <Xm/CascadeBG.h>
+#define USE_COMBOBOX 0
+#endif
+
+static void select_browser_cb(Widget w, XtPointer client_data, XtPointer call_data);
+static void select_editor_cb(Widget w, XtPointer client_data, XtPointer call_data);
+
+/*
+ * Helper functions
+ */
+static char *
+flatten_list(char **list, const char *sep)
+{
+ char *result = xstrdup("");
+ int i;
+
+ for (i = 0; list[i] != NULL; i++) {
+ result = xstrcat(result, list[i]);
+ result = xstrcat(result, sep);
+ }
+ return result;
+}
+
+static char **
+add_to_list(char **list, const char *str)
+{
+ int i, k;
+ /* reallocate with larger capacity */
+ for (i = 0; list[i] != NULL; i++) { ; }
+ i++;
+ list = xrealloc(list, (i + 1) * sizeof *list);
+
+ /* shift old contents down */
+ for (k = i; k > 0; k--) {
+ list[k] = list[k - 1];
+ }
+ /* add new element at beginning */
+ list[0] = xstrdup(str);
+
+ return list;
+}
+
+
+/*
+ * User clicked on `Help' in browser text input prompt
+ */
+static void
+help_browser_dialog_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Widget popup = popup_message(XtParent(w),
+ MSG_HELP,
+ NULL,
+ "The browser is used by xdvi to browse remote documents. "
+ "Please enter the name of the browser (i.e. the executable program) "
+ "you want to use. The browser command may optionally contain a string "
+ "`%%s' which is replaced by the current URL. If no `%%s' is present, "
+ "the URL argument is simply appended to the command.");
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ TRACE_GUI((stderr, "setting user data to %p", (void *)popup));
+ XtVaSetValues(w, XmNuserData, popup, NULL);
+}
+
+/*
+ * User clicked on `Help' in editor text input prompt
+ */
+static void
+help_editor_dialog_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ Widget popup = popup_message(XtParent(w),
+ MSG_HELP,
+ NULL,
+ "The editor is used by reverse search to open the TeX source for a DVI file "
+ "(see `Help' -> `Source Specials' for details)."
+ "Please enter the name of the editor executable you want to use. "
+ "The editor command may optionally contain two format strings: "
+ "`%%l' is replaced by the line number in the TeX file, and `%%f' by the file name. "
+ "(If the format strings are not present, they are appended implicitly.)");
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ TRACE_GUI((stderr, "setting user data to %p", (void *)popup));
+ XtVaSetValues(w, XmNuserData, popup, NULL);
+}
+
+/*
+ * User cancelled browser or editor text input prompt
+ */
+static void
+destroy_dialog_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+/* Widget browser_combo = (Widget)client_data; */
+ struct choice_dialog_info *info = (struct choice_dialog_info *)client_data;
+ Widget browser_combo = NULL;
+ Widget help_popup;
+#if USE_COMBOBOX
+ Widget browser_list_w;
+#endif
+ UNUSED(call_data);
+
+ XtVaGetValues(w, XmNuserData, &help_popup, NULL);
+ TRACE_GUI((stderr, "GOT help_popup: %p", (void *)help_popup));
+
+ if (info != NULL)
+ browser_combo = info->combo_box;
+
+ if (browser_combo != NULL) {
+#if USE_COMBOBOX
+ /* Need to unselect the `Other...' entry from the list; to do this,
+ we select the index from XmNuserData if it's >= 0, or the first item. */
+ int idx;
+ XtVaGetValues(browser_combo,
+ XmNlist, &browser_list_w,
+ XmNuserData, &idx,
+ NULL);
+ if (browser_list_w == 0)
+ XDVI_ERROR((stderr, "couldn't get list component of combo box!\n"));
+ else {
+ if (idx < 0)
+ idx = 0;
+ XmListSelectPos(browser_list_w, idx + 1, True);
+ }
+#else
+ Widget parent;
+ if ((parent = XtParent(w)) != NULL) {
+ Widget rowcol, child;
+ if (strcmp(XtName(parent), Xdvi_BROWSER_POPUP) == 0) {
+ if (get_widget_by_name(&rowcol, globals.widgets.top_level, Xdvi_BROWSER_COMBO_NAME, True)) {
+ XtVaGetValues(rowcol, XmNuserData, &child, NULL);
+ XtVaSetValues(rowcol, XmNmenuHistory, child, NULL);
+ }
+ }
+ else if (strcmp(XtName(parent), Xdvi_EDITOR_POPUP) == 0) {
+ if (get_widget_by_name(&rowcol, globals.widgets.top_level, Xdvi_EDITOR_COMBO_NAME, True)) {
+ XtVaGetValues(rowcol, XmNuserData, &child, NULL);
+ XtVaSetValues(rowcol, XmNmenuHistory, child, NULL);
+ }
+ }
+ else {
+ XDVI_WARNING((stderr, "unexpected widget name `%s' in destroy_dialog_cb", XtName(parent)));
+ }
+ }
+#endif
+ }
+
+ /*
+ * Also popdown dependent help window if it exists before destroying the widget;
+ * otherwise, Motif may even crash in _XmIsFastSubclass() when the help window is moved!
+ *
+ * Since `help_popup' is the top-level xmDialogShellWidget, we need to get its
+ * xmMessageBoxWidget child (by name ...). Don't report an error if it doesn't
+ * exist in case the help window has already been closed.
+ */
+ if (help_popup != NULL) {
+ static Widget message;
+ if (get_widget_by_name(&message, help_popup, Xdvi_MESSAGE_DIALOG_NAME, False))
+ XtCallCallbacks(message, XmNokCallback, NULL);
+ }
+
+ if (info != NULL) {
+ struct prefs_choice *prefs = (struct prefs_choice *)info->tinfo->data;
+ remove_from_deplist(prefs, w);
+ free(info);
+ }
+
+ /* destroy the parent of this dialog (the shell) */
+ XtDestroyWidget(XtParent(w));
+}
+
+static void
+h_get_input_wrapper(const char *listbox_name,
+ Widget w, XtPointer client_data, XtPointer call_data)
+{
+/* Widget combobox = (Widget)client_data; */
+ struct choice_dialog_info *info = (struct choice_dialog_info *)client_data;
+ struct topic_info *tinfo = info->tinfo;
+ struct prefs_choice *prefs = (struct prefs_choice *)tinfo->data;
+ Widget combobox, child;
+ /* following need to be allocated since we want to set resource.xyz to it */
+ static char *browser_choice= NULL, *editor_choice = NULL;
+#if !USE_COMBOBOX
+ XtCallbackProc select_cb = NULL;
+#endif
+ XmSelectionBoxCallbackStruct *cbs = (XmSelectionBoxCallbackStruct *)call_data;
+ static char *ptr = NULL;
+ char *tmp_list;
+
+ if (call_data == NULL) /* widget already being destroyed? */
+ return;
+
+ ASSERT(info != NULL, "client_data in h_get_input_wrapper mustn't be NULL!");
+ combobox = info->combo_box;
+ child = info->message_popup;
+ XtVaGetValues(w, XmNuserData, &child, NULL);
+ TRACE_GUI((stderr, "GOT child: %p", (void *)child));
+
+ if (ptr)
+ XtFree((XtPointer)ptr);
+ ptr = NULL;
+ XmStringGetLtoR(cbs->value, G_charset, &ptr);
+ if (strlen(ptr) == 0 || is_spaces_only(ptr)) {
+ popup_message(XtParent(w),
+ MSG_ERR,
+ NULL,
+ "Empty input string");
+ return;
+ }
+
+ if (strcmp(listbox_name, Xdvi_BROWSER_COMBO_NAME) == 0) {
+#if 0
+ int i;
+#endif
+
+ free(browser_choice);
+ browser_choice = xstrdup(ptr);
+ resource.browser = browser_choice;
+
+#if 0
+ for (i = 0; m_browser_list[i] != NULL; i++) {
+ fprintf(stderr, "list %d: |%s|\n", i, m_browser_list[i]);
+ }
+#endif
+ m_browser_list = add_to_list(m_browser_list, ptr);
+#if 0
+ for (i = 0; m_browser_list[i] != NULL; i++) {
+ fprintf(stderr, "NEW list %d: |%s|\n", i, m_browser_list[i]);
+ }
+#endif
+ tmp_list = flatten_list(m_browser_list, "\n");
+#if 0
+ fprintf(stderr, "TMP LIST: |%s|\n", tmp_list);
+#endif /* 0 */
+ store_preference(&(prefs->db), "prefsBrowserList", "%s", tmp_list);
+ free(tmp_list);
+
+ store_preference(&(prefs->db), "wwwBrowser", "%s", ptr);
+#if !USE_COMBOBOX
+ select_cb = select_browser_cb;
+#endif
+ }
+ else if (strcmp(listbox_name, Xdvi_EDITOR_COMBO_NAME) == 0) {
+ free(editor_choice);
+ editor_choice = xstrdup(ptr);
+ resource.editor = editor_choice;
+
+ m_editor_list = add_to_list(m_editor_list, ptr);
+ tmp_list = flatten_list(m_editor_list, "\n");
+ store_preference(&(prefs->db), "prefsEditorList", "%s", tmp_list);
+ free(tmp_list);
+
+ store_preference(&(prefs->db), "editor", "%s", ptr);
+#if !USE_COMBOBOX
+ select_cb = select_editor_cb;
+#endif
+ }
+ else
+ XDVI_WARNING((stderr, "Unexpected name in h_get_input_wrapper: `%s'", listbox_name));
+
+#if USE_COMBOBOX
+ UNUSED(listbox_name);
+ /* add user input to the combo box list, and make it current */
+ XmComboBoxAddItem(combobox, cbs->value, 1, True);
+ XmComboBoxSelectItem(combobox, cbs->value);
+#else
+ {
+ Widget new_menu, parent, grandparent, rowcol;
+ if ((parent = XtParent(w)) != NULL && (grandparent = XtParent(parent)) != NULL) {
+ /* add new item to front of list ... */
+ new_menu = XtVaCreateManagedWidget(ptr, xmPushButtonGadgetClass, grandparent,
+ XmNpositionIndex, 0,
+ XmNuserData, tinfo,
+ NULL);
+ if (select_cb != NULL) {
+ XtAddCallback(new_menu, XmNactivateCallback, select_cb, grandparent);
+ }
+ /* ... and make it current! */
+ if (get_widget_by_name(&rowcol, globals.widgets.top_level, listbox_name, True)) {
+ XtVaSetValues(rowcol, XmNmenuHistory, new_menu, NULL);
+ }
+ }
+ }
+#endif
+
+ /* as above: popdown help window */
+ if (child != NULL) {
+ Widget message;
+ if (get_widget_by_name(&message, child, Xdvi_MESSAGE_DIALOG_NAME, False))
+ XtCallCallbacks(message, XmNokCallback, NULL);
+ }
+
+ remove_from_deplist(prefs, w);
+ free(info);
+
+ /* destroy the parent of this dialog (the shell) */
+ XtDestroyWidget(XtParent(w));
+}
+
+static void
+h_selector(const char *prompt_name,
+ const char *title_str, const char *label_str,
+ XtCallbackProc ok_cb,
+ XtCallbackProc destroy_cb,
+ XtCallbackProc help_cb,
+ Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *tinfo = NULL;
+ struct prefs_choice *prefs = NULL;
+ struct choice_dialog_info *info = NULL;
+ char *choice;
+ /* following need to be allocated since we want to set resource.xyz to it */
+ static char *browser_choice= NULL, *editor_choice = NULL;
+
+#if USE_COMBOBOX
+ XmComboBoxCallbackStruct *cb;
+#else
+ XmString str;
+ UNUSED(client_data);
+ UNUSED(call_data);
+#endif
+
+#if USE_COMBOBOX
+ tinfo = (struct topic_info *)client_data;
+ prefs = (struct prefs_choice *)tinfo->data;
+#endif
+ info = xmalloc(sizeof *info);
+#if USE_COMBOBOX
+ cb = (XmComboBoxCallbackStruct *)call_data;
+
+ if (cb->event == NULL) /* only browsing, no selection */
+ return;
+
+ choice = (char *)XmStringUnparse(cb->item_or_text, XmFONTLIST_DEFAULT_TAG,
+ XmCHARSET_TEXT, XmCHARSET_TEXT,
+ NULL, 0,
+ XmOUTPUT_ALL);
+#else
+ XtVaGetValues(w, XmNlabelString, &str, NULL);
+ XmStringGetLtoR(str, G_charset, &choice);
+
+ XtVaGetValues(w, XmNuserData, &tinfo, NULL);
+ ASSERT(tinfo != NULL, "XmNuserData in callback musn't be NULL!");
+ prefs = (struct prefs_choice *)tinfo->data;
+#endif
+
+ if (strcmp(choice, Xdvi_ADD_COMMAND_STR) == 0) {
+ Widget prompt_widget;
+ Arg args[8];
+ int n = 0;
+ XmString title = XmStringCreateLocalized((char *)title_str);
+ XmString label = XmStringCreateLocalized((char *)label_str);
+
+ XtSetArg(args[n], XmNselectionLabelString, label); n++;
+ XtSetArg(args[n], XmNautoUnmanage, False); n++;
+ XtSetArg(args[n], XmNdialogTitle, title); n++;
+ XtSetArg(args[n], XmNuserData, NULL); n++;
+ prompt_widget = XmCreatePromptDialog(
+#if USE_COMBOBOX
+ w,
+#else
+ XtParent(w),
+#endif
+ (char *)prompt_name, args, n);
+/* XmStringFree(label); */
+
+ add_to_deplist(prefs, prompt_widget);
+
+ info->tinfo = tinfo;
+ info->combo_box = w;
+ info->message_popup = NULL;
+
+ /* Note: w is the browser_combo widget */
+ XtAddCallback(prompt_widget, XmNokCallback, ok_cb, (XtPointer)info);
+ XtAddCallback(prompt_widget, XmNcancelCallback, destroy_cb, (XtPointer)info);
+ XtAddCallback(prompt_widget, XmNhelpCallback, help_cb, (XtPointer)info);
+
+ XtManageChild(prompt_widget);
+ }
+ else { /* normal item */
+#if USE_COMBOBOX
+ int i;
+#endif
+
+ if (strcmp(prompt_name, Xdvi_BROWSER_POPUP_NAME) == 0) {
+#if !USE_COMBOBOX
+ Widget rowcol;
+ if (get_widget_by_name(&rowcol, globals.widgets.top_level, Xdvi_BROWSER_COMBO_NAME, True)) {
+ XtVaSetValues(rowcol, XmNuserData, w, NULL);
+ }
+#endif
+ free(browser_choice);
+ browser_choice = xstrdup(choice);
+ resource.browser = browser_choice;
+ store_preference(&(prefs->db), "wwwBrowser", "%s", browser_choice);
+ }
+ else if (strcmp(prompt_name, Xdvi_EDITOR_POPUP_NAME) == 0) {
+#if !USE_COMBOBOX
+ Widget rowcol;
+ if (get_widget_by_name(&rowcol, globals.widgets.top_level, Xdvi_EDITOR_COMBO_NAME, True)) {
+ XtVaSetValues(rowcol, XmNuserData, w, NULL);
+ }
+#endif
+ free(editor_choice);
+ editor_choice = xstrdup(choice);
+ resource.editor = editor_choice;
+ store_preference(&(prefs->db), "editor", "%s", editor_choice);
+ }
+ else
+ XDVI_ERROR((stderr, "Unknown category `%s' in h_selector()!", prompt_name));
+
+
+#if USE_COMBOBOX
+ /* update the currently selected value */
+ XtVaGetValues(w, XmNselectedPosition, &i, NULL);
+ XtVaSetValues(w, XmNuserData, i, NULL);
+#endif
+ }
+#if USE_COMBOBOX
+ XtFree(choice);
+#endif
+}
+
+/*
+ * User OK'ed browser text input prompt
+ */
+static void
+get_browser_text_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ if (XtIsRealized(w)) {
+ h_get_input_wrapper(Xdvi_BROWSER_COMBO_NAME, w, client_data, call_data);
+ }
+}
+
+
+/*
+ * User OK'ed editor text input prompt
+ */
+static void
+get_editor_text_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ if (XtIsRealized(w)) {
+ h_get_input_wrapper(Xdvi_EDITOR_COMBO_NAME, w, client_data, call_data);
+ }
+}
+
+
+/*
+ * User selected an item from browser combo box pulldown list
+ */
+static void
+select_browser_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ h_selector(Xdvi_BROWSER_POPUP_NAME,
+ "Xdvi: Add Browser Command",
+ "Browser Command (optional `%s' is replaced by URL): ",
+ get_browser_text_cb, destroy_dialog_cb, help_browser_dialog_cb,
+ w, client_data, call_data);
+}
+
+/*
+ * User selected an item from editor combo box pulldown list
+ */
+static void
+select_editor_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ UNUSED(client_data);
+ h_selector(Xdvi_EDITOR_POPUP_NAME,
+ "Xdvi: Add Editor Command",
+ "Editor Command (optional: `%l' = line number, `%f' = file name): ",
+ get_editor_text_cb, destroy_dialog_cb, help_editor_dialog_cb,
+ w, client_data, call_data);
+}
+
+void
+update_preferences_helpers(void)
+{
+ Widget shell, browser_cascade, editor_cascade;
+
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&browser_cascade, shell, Xdvi_BROWSER_COMBO_NAME, True)
+ && get_widget_by_name(&editor_cascade, shell, Xdvi_EDITOR_COMBO_NAME, True)) {
+
+#if USE_COMBOBOX
+
+ Widget browser_list_w, editor_list_w;
+ XmString str;
+ int i;
+ Boolean found = False;
+
+ XtVaGetValues(browser_cascade, XmNlist, &browser_list_w, NULL);
+ XtVaGetValues(editor_cascade, XmNlist, &editor_list_w, NULL);
+
+ for (i = 0; m_browser_list[i] != NULL; i++) {
+ if (globals.curr_browser != NULL) { /* if this is set, ignore browser setting */
+ if (strcmp(globals.curr_browser, m_browser_list[i]) == 0) {
+ found = True;
+ break;
+ }
+ }
+ else if (resource.browser != NULL) {
+ if (strcmp(resource.browser, m_browser_list[i]) == 0) {
+ found = True;
+ break;
+ }
+ }
+ }
+ if (!found)
+ i = 0;
+ str = XmStringCreateLtoR((char *)m_browser_list[i], "UNMARKED");
+ XmComboBoxSelectItem(browser_cascade, str);
+ XmStringFree(str);
+
+ for (i = 0; m_editor_list[i] != NULL; i++) {
+ if (globals.curr_editor != NULL) { /* if this is set, ignore editor setting */
+ if (strcmp(globals.curr_editor, m_editor_list[i]) == 0) {
+ found = True;
+ break;
+ }
+ }
+ else if (resource.editor != NULL) {
+ if (strcmp(resource.editor, m_editor_list[i]) == 0) {
+ found = True;
+ break;
+ }
+ }
+ }
+ if (!found)
+ i = 0;
+ str = XmStringCreateLtoR((char *)m_editor_list[i], "UNMARKED");
+ XmComboBoxSelectItem(editor_cascade, str);
+ XmStringFree(str);
+ /* XmListSetPos(editor_list_w, i); */
+ /* fprintf(stderr, "setting editor list index %d, %s\n", */
+ /* i, editor_list[i-1]); */
+
+
+ /* if (XmListGetSelectedPos(browser_list_w, &browser_items, &browser_cnt) */
+ /* && XmListGetSelectedPos(editor_list_w, &editor_items, &editor_cnt)) { */
+ /* if (browser_cnt > 0 && editor_cnt > 0) { */
+ /* int browser_idx = browser_items[0] - 1; */
+ /* int editor_idx = editor_items[0] - 1; */
+ /* fprintf(stderr, "selected: %s, %s\n", */
+ /* browser_list[browser_idx], */
+ /* editor_list[editor_idx]); */
+ /* } */
+ /* else { */
+ /* XDVI_WARNING((stderr, "Shouldn't happen: No items selected in browser list?")); */
+ /* return; */
+ /* } */
+ /* XtFree((XtPointer)browser_items); */
+ /* XtFree((XtPointer)editor_items); */
+ /* } */
+#else
+ Widget browser_menu, editor_menu;
+ if (get_widget_by_name(&browser_menu, shell, Xdvi_BROWSER_MENU_NAME, True)
+ && get_widget_by_name(&editor_menu, shell, Xdvi_EDITOR_MENU_NAME, True)) {
+ int i, num_buttons;
+ WidgetList buttons;
+
+ XtVaGetValues(browser_menu,
+ XmNnumChildren, &num_buttons,
+ XmNchildren, &buttons,
+ NULL);
+ for (i = 0; i < num_buttons; i++) {
+ XmString str;
+ char *ptr;
+
+ XtVaGetValues(buttons[i], XmNlabelString, &str, NULL);
+ XmStringGetLtoR(str, G_charset, &ptr);
+/* fprintf(stderr, "kid %d: %s\n", i, ptr); */
+ if (globals.curr_browser != NULL) { /* if this is set, ignore browser setting */
+ if (strcmp(globals.curr_browser, ptr) == 0) {
+ break;
+ }
+ }
+ else if (resource.browser != NULL) {
+ if (strcmp(resource.browser, ptr) == 0) {
+ break;
+ }
+ }
+ }
+ if (i >= num_buttons) /* not found */
+ i = 0;
+ XtVaSetValues(browser_cascade, XmNmenuHistory, buttons[i], NULL);
+
+ /* same for editor */
+ XtVaGetValues(editor_menu,
+ XmNnumChildren, &num_buttons,
+ XmNchildren, &buttons, NULL);
+ for (i = 0; i < num_buttons; i++) {
+ XmString str;
+ char *ptr;
+
+ XtVaGetValues(buttons[i], XmNlabelString, &str, NULL);
+ XmStringGetLtoR(str, G_charset, &ptr);
+/* fprintf(stderr, "kid %d: %s\n", i, ptr); */
+ if (globals.curr_editor != NULL) { /* if this is set, ignore editor setting */
+ if (strcmp(globals.curr_editor, ptr) == 0) {
+ break;
+ }
+ }
+ else if (resource.editor != NULL) {
+ if (strcmp(resource.editor, ptr) == 0) {
+ break;
+ }
+ }
+ }
+ if (i >= num_buttons) /* not found */
+ i = 0;
+ XtVaSetValues(editor_cascade, XmNmenuHistory, buttons[i], NULL);
+
+ }
+#endif
+ /* for browser/editor, try:
+
+ Widget menu;
+ int num_buttons;
+ WidgetList buttons;
+
+ XtVaGetValues( simple_option_widget, XmNsubMenuId, &menu, NULL);
+
+ XtVaGetValues( menu, XmNnumChildren, &num_buttons,
+ XmNchildren, &buttons, NULL ) ;
+
+ */
+ }
+}
+
+static Widget
+h_create_command(const char *name,
+ const char *menu_name,
+ const char *label,
+ const char *curr_value,
+ Widget parent, Widget top,
+ char **command_list,
+ XtCallbackProc select_cb,
+ struct topic_info *tinfo)
+{
+ const char *ptr = NULL;
+ size_t i;
+
+#if USE_COMBOBOX
+ XmStringTable str_list;
+ Widget text_label, combo_box;
+ size_t k, num;
+ int curr_index = -1;
+#else
+ Widget menu, cascade, item;
+ XmString str;
+ Arg args[8];
+ int n;
+#endif
+
+ /* check if we need to add the default resource name */
+ ptr = curr_value;
+
+ /* don't add it if it's already in our list */
+ for (i = 0; ptr != NULL && command_list[i] != NULL; i++) {
+ if (strcmp(command_list[i], ptr) == 0) {
+ ptr = NULL;
+ }
+ }
+#if USE_COMBOBOX
+ UNUSED(menu_name);
+ text_label = XmCreateLabelGadget(parent, (char *)label, NULL, 0);
+ XtVaSetValues(text_label,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, top,
+ XmNleftAttachment, XmATTACH_FORM,
+/* XmNrightAttachment, XmATTACH_FORM, */
+ NULL);
+
+ /* count elements in command_list */
+ for (num = 0; command_list[num] != NULL; num++) { ; }
+
+ if (ptr != NULL)
+ num++;
+
+ str_list = (XmStringTable)XtMalloc(num * sizeof(XmString *));
+
+ i = 0;
+ if (ptr != NULL)
+ str_list[i++] = XmStringCreateLtoR((char *)ptr, "UNMARKED");
+
+ for (k = 0; i < num; i++, k++) {
+ if (curr_value != NULL && strcmp(command_list[k], curr_value) == 0) {
+ curr_index = i;
+ }
+ if (strcmp(command_list[k], Xdvi_ADD_COMMAND_STR) == 0)
+ str_list[i] = XmStringCreateLtoR((char *)command_list[k], "MARKED");
+ else
+ str_list[i] = XmStringCreateLtoR((char *)command_list[k], "UNMARKED");
+ }
+ combo_box = XtVaCreateWidget(name, xmComboBoxWidgetClass,
+ parent,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, top, /* if top == NULL, this used XmATTACH_FORM */
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, text_label,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNcomboBoxType, XmDROP_DOWN_LIST,
+ XmNitems, str_list,
+ XmNitemCount, num,
+ XmNuserData, curr_index,
+ NULL);
+ if (top != NULL) /* FIXME: This assumes we only have 2 items ... */
+ XtVaSetValues(combo_box,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ /* make resource setting current value */
+ if (curr_index >= 0) {
+ XmComboBoxSelectItem(combo_box, str_list[curr_index]);
+ }
+
+ for (i = 0; i < num; i++)
+ XmStringFree(str_list[i]);
+ XtFree((XtPointer)str_list);
+
+ XtAddCallback(combo_box, XmNselectionCallback, select_cb, (XtPointer)tinfo);
+
+ /*
+ * workaround for pointer grabbing bug (see xm_menu.c). We need to use
+ * the popdownCallback of the internal `GrabShell' child of the combo box.
+ */
+ {
+ Widget grab_shell;
+ if (get_widget_by_name(&grab_shell, combo_box, "GrabShell", True))
+ XtAddCallback(grab_shell, XtNpopdownCallback, popdown_callback, NULL);
+ }
+ adjust_heights(text_label, combo_box, NULL);
+
+ XtManageChild(text_label);
+ XtManageChild(combo_box);
+
+ return combo_box;
+#else
+ menu = XmCreatePulldownMenu(parent, (char *)menu_name, NULL, 0);
+/* XtVaSetValues(menu, */
+/* XmNtopAttachment, XmATTACH_WIDGET, */
+/* XmNtopWidget, top, */
+/* XmNleftAttachment, XmATTACH_FORM, */
+/* XmNrightAttachment, XmATTACH_FORM, */
+/* NULL); */
+
+ str = XmStringCreateLocalized((char *)label);
+ n = 0;
+ XtSetArg(args[n], XmNsubMenuId, menu); n++;
+ XtSetArg(args[n], XmNlabelString, str); n++;
+ XtSetArg(args[n], XmNuserData, NULL); n++;
+ cascade = XmCreateOptionMenu(parent, (char *)name, args, n);
+ if (top)
+ XtVaSetValues(cascade,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, top,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ else
+ XtVaSetValues(cascade,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ XmStringFree(str);
+
+ if (ptr != NULL) {
+ item = XtVaCreateManagedWidget(ptr, xmPushButtonGadgetClass, menu,
+ XmNuserData, tinfo,
+ NULL);
+ XtAddCallback(item, XmNactivateCallback, select_cb, menu);
+ }
+
+ for (i = 0; command_list[i] != NULL; i++) {
+ item = XtVaCreateManagedWidget(command_list[i], xmPushButtonGadgetClass, menu,
+ XmNuserData, tinfo,
+ NULL);
+ XtAddCallback(item, XmNactivateCallback, select_cb, menu);
+ }
+ XtManageChild(cascade);
+ return cascade;
+#endif
+}
+
+Widget
+prefs_helpers(struct topic_info *tinfo)
+{
+/* struct prefs_choice *prefs = (struct prefs_choice *)info->data; */
+ Widget form, /* frame, */ form1;
+ Widget browser_command, editor_command;
+
+ form = XmCreateForm(tinfo->right_form, "helpers_form", NULL, 0);
+
+/* frame = XmCreateFrame(form, "commands_frame", NULL, 0); */
+
+ form1 = XtVaCreateWidget("commands_form", xmFormWidgetClass,
+ form,
+ XmNverticalSpacing, 10,
+ XmNhorizontalSpacing, 0,
+ NULL);
+
+ if (m_browser_list == NULL)
+ m_browser_list = get_separated_list(resource.prefs_browser_list, "\n", False);
+
+ if (m_editor_list == NULL)
+ m_editor_list = get_separated_list(resource.prefs_editor_list, "\n", False);
+
+ browser_command = h_create_command(Xdvi_BROWSER_COMBO_NAME,
+ Xdvi_BROWSER_MENU_NAME,
+ "Web Browser: ",
+ resource.browser,
+ form1, NULL,
+ m_browser_list,
+ select_browser_cb, tinfo);
+
+ editor_command = h_create_command(Xdvi_EDITOR_COMBO_NAME,
+ Xdvi_EDITOR_MENU_NAME,
+ "Editor for Source Specials: ",
+ resource.editor,
+ form1, browser_command,
+ m_editor_list,
+ select_editor_cb, tinfo);
+
+/* #if PS_GS */
+/* Widget b2 = XmCreateLabelGadget(rowcol, "[x] Use Ghostscript to interpret PS specials", NULL, 0); */
+
+ /* TODO: don't need this??? Similar: ps2pdf, dvips conversion?? */
+ /* Widget b3 = XmCreateLabelGadget(rowcol, "Path to Ghostscript: ____________", NULL, 0); */
+
+/* #endif */
+/* Widget b4 = XmCreateLabelGadget(rowcol, "Editor for source specials: <pulldown> [Other ...]", NULL, 0); */
+/* XtManageChild(b1); */
+/* XtManageChild(b2); */
+/* XtManageChild(b3); */
+/* XtManageChild(b4); */
+/* XtManageChild(rowcol); */
+
+ XtManageChild(form1);
+/* XtManageChild(frame); */
+
+ return form;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
+
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_helpers.h b/Build/source/texk/xdvik/gui/xm_prefs_helpers.h
new file mode 100644
index 00000000000..07b851186b1
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_helpers.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef XM_PREFS_HELPERS_
+#define XM_PREFS_HELPERS_
+
+#ifdef MOTIF
+
+struct topic_info; /* forward declaration */
+extern Widget prefs_helpers(struct topic_info *info);
+extern void update_preferences_helpers(void);
+
+#endif /* MOTIF */
+
+#endif /* XM_PREFS_HELPERS_ */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_page.c b/Build/source/texk/xdvik/gui/xm_prefs_page.c
new file mode 100644
index 00000000000..b40f1f63132
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_page.c
@@ -0,0 +1,695 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Panel 4 (Paper size) for xdvik preferences dialog.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "x_util.h"
+#include "xm_colorsel.h"
+#include "topic-window.h"
+#include "util.h"
+#include "events.h"
+#include "statusline.h"
+
+#include "xm_prefsP.h"
+#include "xm_prefs_page.h"
+#include "my-snprintf.h"
+
+#ifdef MOTIF /* entire file */
+
+#include <X11/Xatom.h>
+
+#include <Xm/Xm.h>
+#include <Xm/Protocols.h>
+#include <Xm/DialogS.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushB.h>
+#include <Xm/PushBG.h>
+#include <Xm/Form.h>
+#include <Xm/Frame.h>
+#include <Xm/PanedW.h>
+#include <Xm/DrawnB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Scale.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+#include <Xm/CascadeBG.h>
+
+#if XmVersion >= 2000 && !defined(LESSTIF_VERSION)
+/* spinbox only available with Motif 2.0; the lesstif version (as of 0.93) looks like shit */
+#include <Xm/SpinB.h>
+#define USE_SPINBOX 1
+#else
+#define USE_SPINBOX 0
+#endif
+
+/*
+ * Handy defaults
+ */
+static Arg one_of_many = { XmNindicatorType, XmONE_OF_MANY };
+static Arg n_of_many = { XmNindicatorType, XmN_OF_MANY };
+static Arg frame_title = { XmNchildType, XmFRAME_TITLE_CHILD };
+static Arg one_col[] = {
+ { XmNpacking, XmPACK_TIGHT },
+ { XmNnumColumns, 1 },
+ { XmNorientation, XmVERTICAL }
+};
+
+
+/* this is a small selection from the paper types in xdvi.c
+ * (only the more frequenlty used ones)
+ */
+static struct paper_info {
+ const char *format;
+ const char *resource_format;
+ const char *size;
+ const char *landscape_size;
+} papersizes[] = {
+ { "US (Letter)", "us", "8.5x11in", "11x8.5in" },
+ { "Tabloid", "tabloid", "11x17in", "17x11in" }, /* dvips compatibility */
+ { "Legal", "legal", "8.5x14in", "14x8.5in" },
+ { "A0", "a0", "841x1189mm", "1189x841mm" },
+ { "A1", "a1", "594x841mm", "841x594mm" },
+ { "A2", "a2", "420x594mm", "594x420mm" },
+ { "A3", "a3", "297x420mm", "420x297mm" },
+ { "A4", "a4", "210x297mm", "297x210mm" },
+ { "A5", "a5", "148x210mm", "210x148mm" },
+ { "B5", "b5", "176x250mm", "250x176mm" },
+ { "B6", "b6", "125x176mm", "176x125mm" },
+ { "B7", "b7", "88x125mm", "125x88mm" },
+ { NULL, NULL, NULL, NULL } /* terminate */
+};
+
+void update_preferences_windowsize(void)
+{
+ Widget shell, button;
+
+ /* it's not an error if the prefs dialog doesn't exist yet */
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&button, shell, Xdvi_REMEMBER_WINDOWSIZE_STR, True)) {
+ XmToggleButtonGadgetSetState(button, resource.remember_windowsize, False);
+ }
+}
+
+void update_preferences_shrink(void)
+{
+ Widget shell, text;
+
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&text, shell, Xdvi_SHRINK_TEXT, True)) {
+ char buf[LENGTH_OF_INT];
+ SNPRINTF(buf, LENGTH_OF_INT, "%d", resource.shrinkfactor);
+#if USE_SPINBOX
+ XmTextFieldSetString(text, buf);
+ XtVaSetValues(text, XmNposition, resource.shrinkfactor, NULL);
+#else
+ XtVaSetValues(text, XmNvalue, buf, NULL);
+#endif
+ }
+}
+
+static void
+landscape_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *tinfo = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)tinfo->data;
+ Widget portrait_b, landscape_b;
+ Boolean landscape = False, is_set;
+ static char *paper_option = NULL;
+ Boolean match = False;
+ int i;
+
+ UNUSED(call_data);
+
+ for (i = 0; papersizes[i].format != NULL; i++) {
+ /* ignore final `r' when comparing */
+ if (strncmp(resource.paper,
+ papersizes[i].resource_format,
+ strlen(papersizes[i].resource_format)) == 0) {
+ const char *ptr;
+ match = True;
+ if (strcmp(resource.paper, "letter") == 0) /* special case */
+ ptr = "us";
+ else
+ ptr = papersizes[i].resource_format;
+ free(paper_option);
+ paper_option = xstrdup(ptr);
+ break;
+ }
+ }
+
+ if (!match) {
+ XDVI_ERROR((stderr, "paper resource `%s' not found in list!\n", resource.paper));
+ return;
+ }
+
+ if (get_widget_by_name(&portrait_b, tinfo->shell, Xdvi_PAPER_PORTRAIT_STR, True)
+ && get_widget_by_name(&landscape_b, tinfo->shell, Xdvi_PAPER_LANDSCAPE_STR, True)) {
+
+ if (w == portrait_b) {
+ XtVaGetValues(portrait_b, XmNset, &is_set, NULL);
+ landscape = !is_set;
+ }
+ else {
+ XtVaGetValues(landscape_b, XmNset, &is_set, NULL);
+ landscape = is_set;
+ }
+
+/* fprintf(stderr, "++++++++ CALLBACK: setting portrait to %s, landscape to %s\n", */
+/* landscape ? "False" : "True", */
+/* landscape ? "True" : "False"); */
+
+ XmToggleButtonGadgetSetState(portrait_b, !landscape, False);
+ XmToggleButtonGadgetSetState(landscape_b, landscape, False);
+ }
+
+ if (landscape) {
+ paper_option = xstrcat(paper_option, "r");
+ }
+
+ resource.paper = paper_option;
+ store_preference(&(prefs->db), "paper", "%s", paper_option);
+}
+
+static void
+select_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *tinfo = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)tinfo->data;
+
+ XmString str;
+ char *choice;
+ int i;
+ static char *curr_choice= NULL;
+ Boolean landscape = False;
+
+ UNUSED(call_data);
+
+ XtVaGetValues(w, XmNlabelString, &str, NULL);
+ XmStringGetLtoR(str, G_charset, &choice);
+
+ if (strlen(resource.paper) > 0 &&
+ strcmp(resource.paper, "letter") != 0 &&
+ resource.paper[strlen(resource.paper) - 1] == 'r')
+ landscape = True;
+
+ free(curr_choice);
+ curr_choice = NULL;
+ for (i = 0; papersizes[i].format != NULL; i++) {
+ if (strcmp(choice, papersizes[i].format) == 0) {
+ curr_choice = xstrdup(papersizes[i].resource_format);
+ }
+ }
+ if (curr_choice == NULL) {
+ XDVI_ERROR((stderr, "choice`%s' not found in list!\n", choice));
+ return;
+ }
+
+ if (landscape) {
+ curr_choice = xstrcat(curr_choice, "r");
+ }
+
+ resource.paper = curr_choice;
+ store_preference(&(prefs->db), "paper", "%s", curr_choice);
+}
+
+void
+update_preferences_paper(void)
+{
+ Widget shell, portrait_button, landscape_button, sizes_menu, sizes_cascade;
+ Boolean landscape = False;
+
+ /* it's not an error if the prefs dialog doesn't exist yet */
+ if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
+ && get_widget_by_name(&portrait_button, shell, Xdvi_PAPER_PORTRAIT_STR, True)
+ && get_widget_by_name(&landscape_button, shell, Xdvi_PAPER_LANDSCAPE_STR, True)
+ && get_widget_by_name(&sizes_menu, shell, Xdvi_PAPER_MENU, True)
+ && get_widget_by_name(&sizes_cascade, shell, Xdvi_PAPER_CASCADE, True)) {
+
+ int i;
+ Widget sizes_button;
+
+ if (strlen(resource.paper) > 0 &&
+ strcmp(resource.paper, "letter") != 0 &&
+ resource.paper[strlen(resource.paper) - 1] == 'r') {
+
+ landscape = True;
+ }
+
+#if 0
+ XtVaGetValues(portrait_button, XmNset, &test1, NULL);
+ XtVaGetValues(landscape_button, XmNset, &test2, NULL);
+
+ fprintf(stderr, "+++++++ old state of portrait: %d, landscape: %d\n",
+ test1, test2);
+
+ fprintf(stderr, "+++++++ setting portrait to %s, landscape to %s\n",
+ landscape ? "False" : "True",
+ landscape ? "True" : "False");
+#endif /* 0 */
+
+ /*
+ Apparently there's a bug in Motif (OpenMotif 2.1) in that the button
+ is not properly updated in all cases.
+
+ To reproduce:
+
+ Open Preferences dialog, change `landscape' option, click
+ `OK'. Now open the dialog again, change the option again,
+ but click `Cancel'. This correctly reverts the visible
+ state of the buttons, but when opening the dialog again,
+ the button's internal state is not consistent with the
+ visual appearance: when clicking on the unset button, its
+ ValueChanged callback is not invoked, so nothing happens;
+ but after clicking on another(!) button in the preferences
+ dialog, it works again.
+
+ As a workaround, we destroy the buttons and re-create them from scratch - yuck!
+ */
+ {
+ Widget form = XtParent(portrait_button);
+ Widget cascade;
+ struct topic_info *info;
+
+ XtVaGetValues(portrait_button,
+ XmNleftWidget, &cascade,
+ XmNuserData, &info,
+ NULL);
+ XtDestroyWidget(portrait_button);
+ XtDestroyWidget(landscape_button);
+
+ portrait_button = XmCreateToggleButtonGadget(form, Xdvi_PAPER_PORTRAIT_STR, &one_of_many, 1);
+ XmToggleButtonGadgetSetState(portrait_button, !landscape, False);
+ XtVaSetValues(portrait_button,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, cascade,
+ XmNleftOffset, 10,
+ XmNuserData, (XtPointer)info,
+ NULL);
+ landscape_button = XmCreateToggleButtonGadget(form, Xdvi_PAPER_LANDSCAPE_STR, &one_of_many, 1);
+ XmToggleButtonGadgetSetState(landscape_button, landscape, False);
+ XtVaSetValues(landscape_button,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, portrait_button,
+ XmNleftOffset, 10,
+ XmNuserData, (XtPointer)info,
+ NULL);
+ XtManageChild(portrait_button);
+ XtManageChild(landscape_button);
+ XtAddCallback(portrait_button, XmNvalueChangedCallback, landscape_cb, (XtPointer)info);
+ XtAddCallback(landscape_button, XmNvalueChangedCallback, landscape_cb, (XtPointer)info);
+ }
+#if 0
+ XtVaGetValues(portrait_button, XmNset, &test1, NULL);
+ XtVaGetValues(landscape_button, XmNset, &test2, NULL);
+
+ fprintf(stderr, "+++++++ new state of portrait: %d, landscape: %d\n",
+ test1, test2);
+#endif /* 0 */
+
+ for (i = 0; papersizes[i].format != NULL; i++) {
+ if (strncmp(resource.paper,
+ papersizes[i].resource_format,
+ strlen(papersizes[i].resource_format)) == 0
+ && get_widget_by_name(&sizes_button, sizes_menu, papersizes[i].format, True)) {
+
+ XtVaSetValues(sizes_cascade, XmNmenuHistory, sizes_button, NULL);
+ }
+ }
+ }
+}
+
+#if 0 /* currently unused */
+static void
+shrinkfactor_spinbox_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ int val;
+/* static Boolean first_time = True; */
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+ UNUSED(call_data);
+
+ XtVaGetValues(w, XmNposition, &val, NULL);
+
+ /* return if value not changed yet; else the first invocation of the
+ window may actually reset the shrink factor to the default.
+ */
+/* if (val != resource.shrinkfactor) { */
+/* first_time = False; */
+/* } */
+
+ if (XtIsRealized(w)) {
+ /* don't set the resource.shrinkfactor here so that we can revert it from there if needed */
+ do_set_shrinkfactor(val, False);
+ store_preference(&(prefs->db), "shrinkFactor", "%d", val);
+ }
+}
+#endif /* currently unused */
+
+static void
+set_shrinkfactor_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ char *text;
+ int val;
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+
+#if USE_SPINBOX
+ XmTextPosition pos;
+ UNUSED(call_data);
+ text = XmTextFieldGetString(w);
+ val = strtol(text, (char **)NULL, 10);
+#else
+ Widget text_field;
+ UNUSED(call_data);
+ XtVaGetValues(w, XmNuserData, &text_field, NULL);
+ ASSERT(text_field != 0, "Expected text field in XmNuserData, set_shrinkfactor_cb()");
+ XtVaGetValues(text_field, XmNvalue, &text, NULL);
+ val = strtol(text, (char **)NULL, 10);
+/* fprintf(stderr, "spinbox value: |%s|\n", text); */
+#endif
+
+ if (!XtIsRealized(w))
+ return;
+
+ /* verify values in case of direct text input */
+ if (val > 100 || val <= 0) {
+ if (val > 100)
+ statusline_print(STATUS_MEDIUM, "Shrink factor larger than maximum 100");
+ else if (val <= 0)
+ statusline_print(STATUS_MEDIUM, "Shrink factor smaller than minimum 1");
+ return;
+ }
+#if USE_SPINBOX
+ /* synchronize internal spinbox value */
+ pos = XmTextFieldGetInsertionPosition(w);
+ XtVaSetValues(w, XmNposition, val, NULL);
+ XmTextFieldSetInsertionPosition(w, pos);
+#endif
+ /* don't set the resource.shrinkfactor here so that we can revert it from there if needed */
+ do_set_shrinkfactor(val, False);
+ store_preference(&(prefs->db), "shrinkFactor", "%d", val);
+
+ XtFree(text);
+}
+
+static Widget
+h_create_shrink_frame(Widget top, struct topic_info *info)
+{
+ Widget shrink_form, shrink_label;
+
+ UNUSED(info);
+
+ shrink_form = XmCreateForm(top, "shrink_form", NULL, 0);
+ XtVaSetValues(shrink_form,
+/* XmNverticalSpacing, 10, */
+/* XmNhorizontalSpacing, 10, */
+ NULL);
+
+
+ shrink_label = XmCreateLabelGadget(shrink_form, "Default Shrink Factor: ", NULL, 0);
+ XtVaSetValues(shrink_label,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ /* TODO XmNleftOffset, 10, */
+ NULL);
+ XtManageChild(shrink_label);
+ {
+ Widget shrink_text;
+#if USE_SPINBOX
+ Widget shrink_spinbox =
+ XtVaCreateManagedWidget(Xdvi_SHRINK_SPINBOX, xmSpinBoxWidgetClass, shrink_form,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, shrink_label,
+ XmNinitialDelay, 200,
+ XmNrepeatDelay, 50,
+ NULL);
+ shrink_text =
+ XtVaCreateManagedWidget(Xdvi_SHRINK_TEXT, xmTextFieldWidgetClass, shrink_spinbox,
+ XmNspinBoxChildType, XmNUMERIC,
+ XmNminimumValue, 1,
+ XmNmaximumValue, 100,
+ XmNeditable, True,
+ XmNcolumns, 3,
+ XmNincrementValue, 1,
+ XmNwrap, False, /* too confusing */
+ /* NOTE: use resource.shrinkfactor here, not current setting,
+ otherwise the current setting will sneak into ~/.xdvirc */
+ XmNposition, (int)(resource.shrinkfactor),
+ NULL);
+
+ XtAddCallback(shrink_text, XmNactivateCallback, set_shrinkfactor_cb, (XtPointer)info);
+ XtAddCallback(shrink_text, XmNvalueChangedCallback, set_shrinkfactor_cb, (XtPointer)info);
+
+ adjust_heights(shrink_spinbox, shrink_text, shrink_label, NULL);
+
+#else
+ char buf[LENGTH_OF_INT];
+ Widget shrink_button;
+ shrink_text = XmCreateTextField(shrink_form, Xdvi_SHRINK_TEXT, NULL, 0);
+ SNPRINTF(buf, LENGTH_OF_INT, "%d", resource.shrinkfactor);
+ XtVaSetValues(shrink_text,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, shrink_label,
+ XmNcolumns, 4,
+ XmNvalue, buf,
+ XmNuserData, shrink_text,
+ NULL);
+ XtOverrideTranslations(shrink_text, XtParseTranslationTable("<Key>Return:activate()"));
+ XtAddCallback(shrink_text, XmNactivateCallback, set_shrinkfactor_cb, (XtPointer)info);
+
+ shrink_button = XmCreatePushButton(shrink_form, Xdvi_APPLY_STR, NULL, 0);
+ XtVaSetValues(shrink_button,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftOffset, 10,
+ XmNleftWidget, shrink_text,
+ XmNuserData, shrink_text,
+ NULL);
+ XtAddCallback(shrink_button, XmNactivateCallback, set_shrinkfactor_cb, (XtPointer)info);
+
+ adjust_heights(shrink_label, shrink_text, shrink_button, NULL);
+ XtManageChild(shrink_text);
+ XtManageChild(shrink_button);
+#endif
+ }
+
+/* XtManageChild(shrink_form); */
+
+ return shrink_form;
+}
+
+static void
+remember_windowsize_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+
+ UNUSED(w);
+ UNUSED(call_data);
+
+ resource.remember_windowsize = !resource.remember_windowsize;
+
+ store_preference(&(prefs->db), "rememberWindowSize", "%s", resource.remember_windowsize ? "True" : "False");
+}
+
+
+
+static Widget
+h_create_papersize_form(Widget parent, struct topic_info *info)
+{
+ Widget form, menu, cascade, portrait_option, landscape_option;
+ XmString str;
+ Arg args[8];
+ int n;
+ size_t i;
+ Boolean landscape = False;
+
+ form = XmCreateForm(parent, "paper_form", NULL, 0);
+
+ menu = XmCreatePulldownMenu(form, Xdvi_PAPER_MENU, NULL, 0);
+
+ if (strcmp(resource.paper, "letter") != 0 && /* exceptions: these have no landscape format */
+ strcmp(resource.paper, "ledger") != 0 &&
+ strlen(resource.paper) > 0 &&
+ resource.paper[strlen(resource.paper) - 1] == 'r') { /* landscape format */
+ landscape = True;
+ }
+
+ str = XmStringCreateLocalized("Paper Size:");
+
+ n = 0;
+ XtSetArg(args[n], XmNsubMenuId, menu); n++;
+ XtSetArg(args[n], XmNlabelString, str); n++;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+
+ cascade = XmCreateOptionMenu(form, Xdvi_PAPER_CASCADE, args, n);
+ XmStringFree(str);
+
+ portrait_option = XmCreateToggleButtonGadget(form, Xdvi_PAPER_PORTRAIT_STR, &one_of_many, 1);
+ XmToggleButtonGadgetSetState(portrait_option, !landscape, False);
+ XtVaSetValues(portrait_option,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, cascade,
+ XmNleftOffset, 10,
+ XmNuserData, (XtPointer)info,
+ NULL);
+
+ landscape_option = XmCreateToggleButtonGadget(form, Xdvi_PAPER_LANDSCAPE_STR, &one_of_many, 1);
+ XmToggleButtonGadgetSetState(landscape_option, landscape, False);
+ XtVaSetValues(landscape_option,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, portrait_option,
+ XmNleftOffset, 10,
+ XmNuserData, (XtPointer)info,
+ NULL);
+/* adjust_heights(landscape_option, menu, cascade, NULL); */
+ XtAddCallback(portrait_option, XmNvalueChangedCallback, landscape_cb, (XtPointer)info);
+ XtAddCallback(landscape_option, XmNvalueChangedCallback, landscape_cb, (XtPointer)info);
+/* XtAddCallback(portrait_option, XmNarmCallback, test_cb, (XtPointer)info); */
+/* XtAddCallback(landscape_option, XmNarmCallback, test_cb, (XtPointer)info); */
+
+ XtManageChild(portrait_option);
+ XtManageChild(landscape_option);
+
+ for (i = 0; papersizes[i].format != NULL; i++) {
+ Widget w = XtVaCreateManagedWidget(papersizes[i].format, xmPushButtonGadgetClass, menu,
+ XmNuserData, landscape_option,
+ NULL);
+/* fprintf(stderr, "Created button: %p for %s\n", w, papersizes[i].format); */
+
+ /* select default value */
+ if (strncmp(resource.paper,
+ papersizes[i].resource_format,
+ strlen(papersizes[i].resource_format)) == 0) {
+ XtVaSetValues(cascade, XmNmenuHistory, w, NULL);
+ }
+ XtAddCallback(w, XmNactivateCallback, select_cb, (XtPointer)info);
+ }
+ XtManageChild(cascade);
+
+ return form;
+}
+
+Widget
+prefs_paper(struct topic_info *info)
+{
+ Widget form;
+ Widget geometry_frame, geometry_label, geometry_rowcol, shrink_frame, geometry_button;
+ Widget paper_frame, paper_label;
+ Arg args[10];
+ int n = 0;
+ Widget rowcol;
+#if !defined(LESSTIF_VERSION)
+ Widget paper_text;
+#endif
+ Widget paper_size_form;
+
+ form = XtVaCreateWidget("form", xmFormWidgetClass,
+ info->right_form,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ n = 0;
+ XtSetArg(args[n], XmNmarginWidth, 8); n++;
+ XtSetArg(args[n], XmNmarginHeight, 4); n++;
+ geometry_frame = XmCreateFrame(form, "geometry_frame", args, n);
+ h_attach_below(geometry_frame, NULL);
+
+ geometry_label = XmCreateLabelGadget(geometry_frame, "Window Size and Shrink Factor", &frame_title, 1);
+ XtManageChild(geometry_label);
+
+ geometry_rowcol = XmCreateRowColumn(geometry_frame, "geometry_rowcol", one_col, XtNumber(one_col));
+
+ geometry_button = XmCreateToggleButtonGadget(geometry_rowcol, Xdvi_REMEMBER_WINDOWSIZE_STR, &n_of_many, 1);
+ XmToggleButtonGadgetSetState(geometry_button, resource.remember_windowsize, False);
+ XtAddCallback(geometry_button, XmNvalueChangedCallback, remember_windowsize_cb, (XtPointer)info);
+ XtManageChild(geometry_button);
+
+ shrink_frame = h_create_shrink_frame(geometry_rowcol, info);
+ XtManageChild(shrink_frame);
+
+ XtManageChild(geometry_rowcol);
+
+ n = 0;
+ XtSetArg(args[n], XmNmarginWidth, 8); n++;
+ XtSetArg(args[n], XmNmarginHeight, 4); n++;
+ XtSetArg(args[n], XmNtopOffset, 10); n++;
+ paper_frame = XmCreateFrame(form, "paper_frame", args, n);
+ h_attach_below(paper_frame, geometry_frame);
+
+ paper_label = XmCreateLabelGadget(paper_frame, "Default Paper Size", &frame_title, 1);
+ XtManageChild(paper_label);
+
+ rowcol = XmCreateRowColumn(paper_frame, "papersize_rowcol", NULL, 0);
+
+#if !defined(LESSTIF_VERSION) /* stupid LessTif doesn't wrap Labels at '\n' */
+ paper_text = XmCreateLabelGadget(rowcol,
+ "Used if the DVI file does not specify the paper size, e.g. via\n"
+ "\\usepackage[dvips]{geometry}. This setting will only take effect\n"
+ "after restarting xdvi.", NULL, 0);
+ XtVaSetValues(paper_text,
+ XmNalignment, XmALIGNMENT_BEGINNING,
+ NULL);
+ XtManageChild(paper_text);
+#endif
+
+ paper_size_form = h_create_papersize_form(rowcol, info);
+ XtManageChild(paper_size_form);
+
+ XtManageChild(rowcol);
+
+ XtManageChild(geometry_frame);
+ XtManageChild(paper_frame);
+
+ XtManageChild(form);
+
+ return form;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
+
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_page.h b/Build/source/texk/xdvik/gui/xm_prefs_page.h
new file mode 100644
index 00000000000..e333f831507
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_page.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef XM_PREFS_PAGE_
+#define XM_PREFS_PAGE_
+
+#ifdef MOTIF
+
+struct topic_info; /* forward declaration */
+extern Widget prefs_paper(struct topic_info *info);
+extern void update_preferences_windowsize(void);
+extern void restore_preferences_shrink(void);
+extern void update_preferences_shrink(void);
+extern void update_preferences_paper(void);
+
+#endif /* MOTIF */
+
+#endif /* XM_PREFS_PAGE_ */
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_scroll.c b/Build/source/texk/xdvik/gui/xm_prefs_scroll.c
new file mode 100644
index 00000000000..fda08dd33dd
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_scroll.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Panel 5 (Scrolling behaviour) for xdvik preferences dialog.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "x_util.h"
+#include "xm_colorsel.h"
+#include "topic-window.h"
+#include "util.h"
+#include "events.h"
+#include "dvi-init.h"
+#include "statusline.h"
+
+#include "xm_prefsP.h"
+#include "xm_prefs_scroll.h"
+#include "my-snprintf.h"
+
+#ifdef MOTIF /* entire file */
+
+#include <ctype.h>
+
+#include <X11/Xatom.h>
+
+#include <Xm/Xm.h>
+#include <Xm/Protocols.h>
+#include <Xm/DialogS.h>
+#include <Xm/LabelG.h>
+#include <Xm/PushB.h>
+#include <Xm/PushBG.h>
+#include <Xm/Form.h>
+#include <Xm/Frame.h>
+#include <Xm/PanedW.h>
+#include <Xm/DrawnB.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Scale.h>
+#include <Xm/ToggleBG.h>
+#include <Xm/Text.h>
+#include <Xm/TextF.h>
+#include <Xm/CascadeBG.h>
+
+/*
+ * Handy defaults
+ */
+static Arg one_of_many = { XmNindicatorType, XmONE_OF_MANY };
+
+static void
+select_unit_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+
+ Widget pulldown = XtParent(w);
+ Widget form = XtParent(XtParent(pulldown));
+ Widget text_x, text_y;
+
+ const char *w_name = XtName(w);
+
+ UNUSED(call_data);
+
+ fprintf(stderr, "setting name: %s\n", w_name);
+ XtVaSetValues(pulldown, XmNuserData, (XtPointer)w_name, NULL);
+
+ if (get_widget_by_name(&text_x, form, Xdvi_HOME_POSITION_X_OFF_TEXT, True)
+ && get_widget_by_name(&text_y, form, Xdvi_HOME_POSITION_Y_OFF_TEXT, True)) {
+ const char *buf_x = XmTextFieldGetString(text_x);
+ const char *buf_y = XmTextFieldGetString(text_y);
+
+ int val_x = strtol(buf_x, (char **)NULL, 10);
+ int val_y = strtol(buf_y, (char **)NULL, 10);
+
+ static char x_off[LENGTH_OF_INT + 16];
+ static char y_off[LENGTH_OF_INT + 16];
+
+ SNPRINTF(x_off, LENGTH_OF_INT + 16, "%s%s", buf_x, w_name);
+ SNPRINTF(y_off, LENGTH_OF_INT + 16, "%s%s", buf_y, w_name);
+
+ resource.sidemargin = x_off;
+ resource.topmargin = y_off;
+
+ resource.sidemargin_int = val_x;
+ resource.topmargin_int = val_y;
+
+ store_preference(&(prefs->db), "sideMargin", "%s", x_off);
+ store_preference(&(prefs->db), "topMargin", "%s", y_off);
+
+ globals.ev.flags |= EV_NEWPAGE;
+ XFlush(DISP);
+
+ XtFree((char *)buf_x);
+ XtFree((char *)buf_y);
+ }
+}
+
+static void
+set_offset_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+
+ Widget form = XtParent(w);
+ Widget pulldown;
+
+ UNUSED(call_data);
+
+ if (get_widget_by_name(&pulldown, form, Xdvi_HOME_POSITION_UNITS_PULLDOWN, True)) {
+ char *ptr = NULL;
+ const char *w_name = XtName(w);
+
+ XtVaGetValues(pulldown, XmNuserData, &ptr, NULL);
+
+ if (ptr == NULL) {
+ XDVI_WARNING((stderr, "XmNuserData for %s is NULL in set_offset_cb()\n",
+ Xdvi_HOME_POSITION_UNITS_PULLDOWN));
+ return;
+ }
+ fprintf(stderr, "UNIT: |%s|\n", ptr);
+
+ if (strcmp(w_name, Xdvi_HOME_POSITION_X_OFF_TEXT) == 0) {
+ static char x_off[LENGTH_OF_INT + 16];
+ const char *buf = XmTextFieldGetString(w);
+ int val = strtol(buf, (char **)NULL, 10);
+
+ SNPRINTF(x_off, LENGTH_OF_INT + 16, "%s%s", buf, ptr);
+
+ XtFree((char *)buf);
+
+ resource.sidemargin = x_off;
+ resource.sidemargin_int = val;
+ store_preference(&(prefs->db), "sideMargin", "%s", x_off);
+
+ goto_page(current_page, resource.keep_flag ? NULL : home, True);
+ }
+ else if (strcmp(w_name, Xdvi_HOME_POSITION_Y_OFF_TEXT) == 0) {
+ static char y_off[LENGTH_OF_INT + 16];
+ const char *buf = XmTextFieldGetString(w);
+ int val = strtol(buf, (char **)NULL, 10);
+
+ SNPRINTF(y_off, LENGTH_OF_INT + 16, "%s%s", buf, ptr);
+
+ XtFree((char *)buf);
+
+ resource.topmargin = y_off;
+ resource.topmargin_int = val;
+ store_preference(&(prefs->db), "topMargin", "%s", y_off);
+
+ goto_page(current_page, resource.keep_flag ? NULL : home, True);
+ }
+ else {
+ XDVI_WARNING((stderr, "unexpected widget name `%s' in set_offset_cb()", w_name));
+ }
+ }
+}
+
+static void
+home_position_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+
+ Widget parent = XtParent(XtParent(w));
+ Widget toggle_home, toggle_curr, label_x, label_y, text_x, text_y, units_menu;
+
+ UNUSED(call_data);
+
+ resource.use_current_offset = !resource.use_current_offset;
+
+ if (get_widget_by_name(&toggle_home, parent, Xdvi_HOME_POSITION_STR, True)
+ && get_widget_by_name(&toggle_curr, parent, Xdvi_SCROLL_CURRENT_STR, True)
+ && get_widget_by_name(&label_x, parent, Xdvi_HOME_POSITION_X_STR, True)
+ && get_widget_by_name(&label_y, parent, Xdvi_HOME_POSITION_Y_STR, True)
+ && get_widget_by_name(&text_x, parent, Xdvi_HOME_POSITION_X_OFF_TEXT, True)
+ && get_widget_by_name(&text_y, parent, Xdvi_HOME_POSITION_Y_OFF_TEXT, True)
+ && get_widget_by_name(&units_menu, parent, Xdvi_HOME_POSITION_UNITS_MENU, True)) {
+
+ XmToggleButtonGadgetSetState(toggle_home, !resource.use_current_offset, False);
+ XmToggleButtonGadgetSetState(toggle_curr, resource.use_current_offset, False);
+
+ XtSetSensitive(label_x, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(label_y, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(text_x, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(text_y, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(units_menu, !resource.keep_flag && !resource.use_current_offset);
+ }
+
+ store_preference(&(prefs->db), "useCurrentOffset", "%s", resource.use_current_offset ? "True" : "False");
+}
+
+static void
+keep_cb(Widget w, XtPointer client_data, XtPointer call_data)
+{
+ struct topic_info *info = (struct topic_info *)client_data;
+ struct prefs_choice *prefs = (struct prefs_choice *)(info->data);
+
+ Widget parent, keep, unkeep, toggle_home, toggle_curr, label_x, label_y, text_x, text_y, units_menu;
+
+ UNUSED(call_data);
+
+ resource.keep_flag = !resource.keep_flag;
+
+ parent = XtParent(w);
+
+ if (get_widget_by_name(&keep, parent, Xdvi_SCROLL_KEEP_STR, True)
+ && get_widget_by_name(&unkeep, parent, Xdvi_SCROLL_UNKEEP_STR, True)
+ && get_widget_by_name(&toggle_home, parent, Xdvi_HOME_POSITION_STR, True)
+ && get_widget_by_name(&toggle_curr, parent, Xdvi_SCROLL_CURRENT_STR, True)
+ && get_widget_by_name(&label_x, parent, Xdvi_HOME_POSITION_X_STR, True)
+ && get_widget_by_name(&label_y, parent, Xdvi_HOME_POSITION_Y_STR, True)
+ && get_widget_by_name(&text_x, parent, Xdvi_HOME_POSITION_X_OFF_TEXT, True)
+ && get_widget_by_name(&text_y, parent, Xdvi_HOME_POSITION_Y_OFF_TEXT, True)
+ && get_widget_by_name(&units_menu, parent, Xdvi_HOME_POSITION_UNITS_MENU, True)) {
+
+ XmToggleButtonGadgetSetState(keep, resource.keep_flag, False);
+ XmToggleButtonGadgetSetState(unkeep, !resource.keep_flag, False);
+
+ XtSetSensitive(label_x, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(label_y, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(text_x, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(text_y, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(units_menu, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(toggle_home, !resource.keep_flag);
+ XtSetSensitive(toggle_curr, !resource.keep_flag);
+ }
+
+ store_preference(&(prefs->db), "keepPosition", "%s", resource.keep_flag ? "True" : "False");
+
+}
+
+static Widget
+h_create_scrolling(Widget parent, struct topic_info *info)
+{
+ Widget form, form1, form2, size_option, curr_option;
+ Widget x_off_label, x_off_text;
+ Widget y_off_label, y_off_text;
+ Widget off_units_menu, cascade, entry1, entry2, entry3;
+
+ Widget scroll_keep, scroll_unkeep;
+
+ char x_buf[LENGTH_OF_INT + 16];
+ char y_buf[LENGTH_OF_INT + 16];
+ int n;
+ Arg args[8];
+
+ fprintf(stderr, "sidemargin: %s, topmargin: %s\n", resource.sidemargin, resource.topmargin);
+
+ if (resource.sidemargin != NULL) {
+ char *ptr;
+ strcpy(x_buf, resource.sidemargin);
+ ptr = x_buf;
+ if (*ptr == '-')
+ ptr++;
+ while (isdigit((int)*ptr))
+ ptr++;
+ *ptr = '\0';
+ }
+ else
+ strcpy(x_buf, "0");
+
+ if (resource.topmargin != NULL) {
+ char *ptr;
+ strcpy(y_buf, resource.topmargin);
+ ptr = y_buf;
+ if (*ptr == '-')
+ ptr++;
+ while (isdigit((int)*ptr))
+ ptr++;
+ *ptr = '\0';
+ }
+ else
+ strcpy(y_buf, "0");
+
+ form = XmCreateForm(parent, "offsets_form", NULL, 0);
+
+ scroll_keep = XmCreateToggleButtonGadget(form, Xdvi_SCROLL_KEEP_STR, &one_of_many, 1);
+ XtVaSetValues(scroll_keep,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+ scroll_unkeep = XmCreateToggleButtonGadget(form, Xdvi_SCROLL_UNKEEP_STR, &one_of_many, 1);
+ XtVaSetValues(scroll_unkeep,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, scroll_keep,
+ XmNleftAttachment, XmATTACH_FORM,
+ NULL);
+
+ XmToggleButtonGadgetSetState(scroll_keep, resource.keep_flag, False);
+ XmToggleButtonGadgetSetState(scroll_unkeep, !resource.keep_flag, False);
+
+ XtAddCallback(scroll_keep, XmNvalueChangedCallback, keep_cb, (XtPointer)info);
+ XtAddCallback(scroll_unkeep, XmNvalueChangedCallback, keep_cb, (XtPointer)info);
+
+ XtManageChild(scroll_keep);
+ XtManageChild(scroll_unkeep);
+
+ form1 = XmCreateForm(form, "offsets_form1", NULL, 0);
+ XtVaSetValues(form1,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, scroll_unkeep,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 20,
+ NULL);
+
+ size_option = XmCreateToggleButtonGadget(form1, Xdvi_HOME_POSITION_STR, &one_of_many, 1);
+ XtVaSetValues(size_option,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ x_off_label = XmCreateLabelGadget(form1, Xdvi_HOME_POSITION_X_STR, NULL, 0);
+ XtVaSetValues(x_off_label,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, size_option,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ x_off_text = XtVaCreateManagedWidget(Xdvi_HOME_POSITION_X_OFF_TEXT,
+ xmTextFieldWidgetClass, form1,
+ XmNcolumns, 4,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, x_off_label,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNvalue, x_buf,
+/* XmNvalue, buf, */
+ NULL);
+ y_off_label = XmCreateLabelGadget(form1, Xdvi_HOME_POSITION_Y_STR, NULL, 0);
+ XtVaSetValues(y_off_label,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, x_off_text,
+ XmNleftOffset, 10,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ y_off_text = XtVaCreateManagedWidget(Xdvi_HOME_POSITION_Y_OFF_TEXT,
+ xmTextFieldWidgetClass, form1,
+ XmNcolumns, 4,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNleftWidget, y_off_label,
+ XmNbottomAttachment, XmATTACH_FORM,
+ XmNvalue, y_buf,
+ NULL);
+ n = 0;
+ XtSetArg(args[n], XmNuserData, (XtPointer)"in"); n++;
+ off_units_menu = XmCreatePulldownMenu(form1, Xdvi_HOME_POSITION_UNITS_PULLDOWN, args, n);
+
+ n = 0;
+ XtSetArg(args[n], XmNsubMenuId, off_units_menu); n++;
+ XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
+ XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
+ XtSetArg(args[n], XmNleftWidget, y_off_text); n++;
+ XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
+ cascade = XmCreateOptionMenu(form1, Xdvi_HOME_POSITION_UNITS_MENU, args, n);
+ entry1 = XtVaCreateManagedWidget("in", xmPushButtonGadgetClass, off_units_menu,
+ NULL);
+ XtAddCallback(entry1, XmNactivateCallback, select_unit_cb, info);
+ entry2 = XtVaCreateManagedWidget("cm", xmPushButtonGadgetClass, off_units_menu,
+ NULL);
+ XtAddCallback(entry2, XmNactivateCallback, select_unit_cb, info);
+ entry3 = XtVaCreateManagedWidget("Pixel", xmPushButtonGadgetClass, off_units_menu,
+ NULL);
+ XtAddCallback(entry3, XmNactivateCallback, select_unit_cb, info);
+
+ XtAddCallback(x_off_text, XmNvalueChangedCallback, set_offset_cb, (XtPointer)info);
+ XtAddCallback(y_off_text, XmNvalueChangedCallback, set_offset_cb, (XtPointer)info);
+
+ XtManageChild(size_option);
+ XtManageChild(x_off_label);
+ XtManageChild(x_off_text);
+ XtManageChild(y_off_label);
+ XtManageChild(y_off_text);
+ XtManageChild(cascade);
+
+ form2 = XmCreateForm(form, "offsets_form2", NULL, 0);
+ XtVaSetValues(form2,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, form1,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNleftOffset, 20,
+ NULL);
+
+ curr_option = XmCreateToggleButtonGadget(form2, Xdvi_SCROLL_CURRENT_STR, &one_of_many, 1);
+ XtVaSetValues(curr_option,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+ XtManageChild(curr_option);
+
+ XtSetSensitive(x_off_label, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(x_off_text, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(y_off_label, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(y_off_text, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(cascade, !resource.keep_flag && !resource.use_current_offset);
+ XtSetSensitive(size_option, !resource.keep_flag);
+ XtSetSensitive(curr_option, !resource.keep_flag);
+
+ XmToggleButtonGadgetSetState(size_option, !resource.use_current_offset, False);
+ XmToggleButtonGadgetSetState(curr_option, resource.use_current_offset, False);
+
+ XtAddCallback(size_option, XmNvalueChangedCallback, home_position_cb, (XtPointer)info);
+ XtAddCallback(curr_option, XmNvalueChangedCallback, home_position_cb, (XtPointer)info);
+
+ XtManageChild(form1);
+ XtManageChild(form2);
+
+ return form;
+}
+
+Widget
+prefs_scrolling(struct topic_info *info)
+{
+ Widget form;
+ Widget scrolling_form, scrolling_frame;
+
+ form = XtVaCreateWidget("form", xmFormWidgetClass,
+ info->right_form,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ scrolling_frame = XmCreateFrame(form, "scrolling_frame", NULL, 0);
+ h_attach_below(scrolling_frame, NULL);
+
+ scrolling_form = h_create_scrolling(scrolling_frame, info);
+ XtVaSetValues(scrolling_form,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, scrolling_frame,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+
+ XtManageChild(scrolling_form);
+ XtManageChild(scrolling_frame);
+
+ return form;
+}
+
+#else
+/* silence `empty compilation unit' warnings */
+static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
+
diff --git a/Build/source/texk/xdvik/gui/xm_prefs_scroll.h b/Build/source/texk/xdvik/gui/xm_prefs_scroll.h
new file mode 100644
index 00000000000..838a55afdfd
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_prefs_scroll.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2004 Stefan Ulrich
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef XM_PREFS_SCROLL_
+#define XM_PREFS_SCROLL_
+
+#ifdef MOTIF
+
+struct topic_info; /* forward declaration */
+extern Widget prefs_scrolling(struct topic_info *info);
+
+#endif /* MOTIF */
+
+#endif /* XM_PREFS_SCROLL_ */
diff --git a/Build/source/texk/xdvik/gui/xm_toolbar.c b/Build/source/texk/xdvik/gui/xm_toolbar.c
new file mode 100644
index 00000000000..c1bc76286a1
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_toolbar.c
@@ -0,0 +1,860 @@
+/*
+ * Copyright (c) 2001 Marcin Dalecki
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/*
+ * Tool bar implementation for the Motif widget set.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+
+#include "pagesel.h"
+#include "help-window.h"
+#include "message-window.h"
+#include "kpathsea/tex-file.h"
+#include "kpathsea/expand.h"
+#include "statusline.h"
+#include "dvi-init.h"
+#include "events.h"
+#include "dvi-draw.h"
+#include "xm_menu.h"
+#include "xm_toolbar.h"
+#include "util.h"
+#include "x_util.h"
+#include "Tip.h"
+
+#include <stdlib.h>
+
+#include "xdvi-config.h"
+#include "c-openmx.h"
+
+/* default toolbar pixmap file */
+#include "pixmaps/toolbar.xpm"
+
+#ifdef MOTIF
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Shell.h>
+
+#include <Xm/Xm.h>
+#include <Xm/RowColumn.h>
+#include <Xm/Frame.h>
+#include <Xm/PushB.h>
+#include <Xm/Form.h>
+#include <Xm/Separator.h>
+#include <Xm/CascadeB.h>
+#include <Xm/MainW.h>
+#include <Xm/DialogS.h>
+#include <Xm/MessageB.h>
+#include <Xm/Label.h>
+
+#if defined(HAVE_X11_XPM_H)
+# include <X11/xpm.h>
+#elif defined(HAVE_XPM_H)
+# include <xpm.h>
+#elif defined(HAVE_XM_XPMP_H)
+# include <Xm/XpmP.h>
+#endif
+
+#include <sys/stat.h>
+
+/*
+ * The following needs to be keept in sync with the actual pixmap sizes in
+ * tools.xpm. When editing the pixmaps, take care that the symbolic names
+ * are not messed up (e.g. it works with "pixmap" from ftp.x11.org, but
+ * not with xv).
+ */
+
+#define PIXMAP_WIDTH 18
+#define PIXMAP_HEIGHT 18
+/* #define PIXMAP_COUNT 13 */
+
+
+static Widget tool_bar_frame;
+
+#define SEP_CHAR ':' /* character separating entries in translations lines */
+
+void
+toggle_scrollbars(void)
+{
+ Widget x_bar = XtNameToWidget(globals.widgets.main_window, "HorScrollBar");
+ Widget y_bar = XtNameToWidget(globals.widgets.main_window, "VertScrollBar");
+
+ if ((resource.expert_mode & XPRT_SHOW_SCROLLBARS) == 0) {
+ XtUnmanageChild(x_bar);
+ XtUnmanageChild(y_bar);
+ }
+ else {
+ XtManageChild(x_bar);
+ XtManageChild(y_bar);
+ }
+
+ set_menu(&resource.expert_mode, Act_set_expert_mode, check_resource_expert);
+}
+
+void
+toggle_toolbar(void)
+{
+#if !HAVE_XPM
+ statusline_print(STATUS_LONG,
+ "Compiled without XPM support; no toolbar available.");
+#else
+ if (resource.toolbar_unusable) {
+ statusline_print(STATUS_LONG,
+ "Toolbar pixmap file not found; toolbar is disabled.");
+ return;
+ }
+
+ if ((resource.expert_mode & XPRT_SHOW_TOOLBAR) == 0)
+ XtUnmanageChild(tool_bar_frame);
+ else
+ XtManageChild(tool_bar_frame);
+
+ set_menu(&resource.expert_mode, Act_set_expert_mode, check_resource_expert);
+
+#endif /* not HAVE_XPM */
+}
+
+typedef enum { TB_BUTTON, TB_SEPARATOR } toolbarButtonT;
+
+/* global array of button infos */
+static struct toolbar_button_info {
+ Widget button;
+ toolbarButtonT type;
+ char *tip;
+} *toolbar_buttons = NULL;
+
+#if HAVE_XPM /* remainder of file: toolbar is disabled without XPM support */
+
+/* to save current values to */
+static Pixel m_background = 0, m_top_shadow_color = 0, m_bottom_shadow_color = 0;
+
+/* to save resource value of XmNshadowThickness before overriding it if
+ toolbar_buttons_raised is false; it will be used to raise the button on enter:
+*/
+static int m_shadow_thickness;
+extern Boolean get_int_arg(String *param, Cardinal *num_params, int *res);
+
+/* indexes for named colors */
+enum {
+ BACKGROUND,
+ FOREGROUND,
+ BOTTOM_SHADOW,
+ TOP_SHADOW,
+ HIGHLIGHT
+};
+
+/* save info about buttons that need to change state */
+static struct state_buttons_info {
+ Widget back_button; /* insensitive when current page is last page */
+ Widget zoom_in_button; /* insensitive when shrinkfactor is 1 */
+ Widget forward_button; /* insensitive when current page is first page */
+ Widget hyperref_back_button; /* insensitive when at end of href history */
+ Widget hyperref_forward_button; /* insensitive when at begin of href history */
+} m_button_info;
+
+static XtCallbackRec command_call[] = {
+ { handle_command, NULL },
+ { NULL, NULL },
+};
+
+static void
+set_button_sensitivity(Widget w, Boolean sensitive)
+{
+ if (w == NULL) { /* if button hadn't been initialized properly */
+ return;
+ }
+ XtVaSetValues(w, XmNsensitive, sensitive, NULL);
+ /* also remove `raised' property on mouse over */
+ if (!sensitive && !resource.toolbar_buttons_raised) {
+ Dimension x, y, wd, ht;
+ Pixel foreground;
+ static GC backgroundGC = NULL;
+ if (!XtIsRealized(w))
+ return;
+ XtVaGetValues(w,
+ XmNx, &x,
+ XmNy, &y,
+ XmNwidth, &wd,
+ XmNheight, &ht,
+ NULL);
+ if (backgroundGC == NULL) {
+ XtVaGetValues(w, XmNforeground, &foreground, NULL);
+ backgroundGC = set_or_make_gc(NULL, GXcopy, m_background, foreground);
+ }
+ XtVaSetValues(w,
+ XmNtopShadowColor, m_background,
+ XmNbottomShadowColor, m_background,
+ NULL);
+#if 0
+ fprintf(stderr, "drawing on %d,%d\n", x, y);
+ XFillRectangle(XtDisplay(w), XtWindow(w), globals.gc.high, /* backgroundGC, */
+ x, y, wd, ht);
+#endif
+ }
+ XSync(DISP, False);
+}
+
+void
+tb_check_navigation_sensitivity(int pageno)
+{
+ if (!XtIsRealized(globals.widgets.top_level) || (resource.expert_mode & XPRT_SHOW_TOOLBAR) == 0)
+ return;
+
+ set_button_sensitivity(m_button_info.forward_button, pageno == total_pages - 1 ? False : True);
+ set_button_sensitivity(m_button_info.back_button, pageno == 0 ? False : True);
+}
+
+void
+tb_set_htex_back_sensitivity(Boolean sensitive)
+{
+ if (!XtIsRealized(globals.widgets.top_level) || (resource.expert_mode & XPRT_SHOW_TOOLBAR) == 0)
+ return;
+ set_button_sensitivity(m_button_info.hyperref_back_button, sensitive);
+}
+
+void
+tb_set_htex_forward_sensitivity(Boolean sensitive)
+{
+ if (!XtIsRealized(globals.widgets.top_level) || (resource.expert_mode & XPRT_SHOW_TOOLBAR) == 0)
+ return;
+
+ set_button_sensitivity(m_button_info.hyperref_forward_button, sensitive);
+}
+
+void
+tb_set_pagehist_back_sensitivity(Boolean sensitive)
+{
+ if (!XtIsRealized(globals.widgets.top_level) || (resource.expert_mode & XPRT_SHOW_TOOLBAR) == 0)
+ return;
+ set_button_sensitivity(m_button_info.hyperref_back_button, sensitive);
+}
+
+void
+tb_set_pagehist_forward_sensitivity(Boolean sensitive)
+{
+ if (!XtIsRealized(globals.widgets.top_level) || (resource.expert_mode & XPRT_SHOW_TOOLBAR) == 0)
+ return;
+
+ set_button_sensitivity(m_button_info.hyperref_forward_button, sensitive);
+}
+
+void
+tb_set_zoom_sensitivity(Boolean sensitive)
+{
+ if (!XtIsRealized(globals.widgets.top_level) || (resource.expert_mode & XPRT_SHOW_TOOLBAR) == 0)
+ return;
+
+ set_button_sensitivity(m_button_info.zoom_in_button, sensitive);
+}
+
+#if 0
+static void
+search_callback(Widget w,
+ XtPointer client_data,
+ XmAnyCallbackStruct *call_data)
+{
+ UNUSED(w);
+ UNUSED(client_data);
+ UNUSED(call_data);
+
+ popup_message(globals.widgets.top_level,
+ MSG_ERR, NULL, "Sorry, not yet implemented");
+}
+#endif /* 0 */
+
+
+
+/*
+ * If successful, this extracts a square pixmap from resource.toolbar_pixmap_file
+ * and returns True.
+ * In this case, the pixmap `sen' will contain the actual
+ * pixmap and `insen' will contain a drawn pixmap for the insensitive state of
+ * the button. We are emulating a shaded state derived from the monochrome 'm'
+ * color attributes of the XPM.
+ *
+ * If unsuccessful, it returns False, and the Pixmap pointers are undefined.
+ */
+
+static Boolean
+create_pixmap(Widget parent, int iconidx, Pixmap *sen, Pixmap *insen)
+{
+ static Boolean first_time = True;
+ static Window rootWindow;
+ static XpmColorSymbol color[5] = {
+ {"none", "none", 0},
+ {"iconColor1", NULL, 0},
+ {"bottomShadowColor", NULL, 0},
+ {"topShadowColor", NULL, 0},
+ {"selectColor", NULL, 0}
+ };
+ static int screenNum;
+ static Pixmap tools_map;
+ static Pixmap tools_mask;
+ static Pixmap shade_map;
+ static Pixmap shade_mask;
+
+ int status = 0;
+ XpmAttributes attr;
+ Pixmap map;
+ Pixmap mask;
+ static String pixmap_file_path = NULL; /* note: never free()d */
+
+ ASSERT(iconidx >= 0, "index must be positive");
+
+ if (first_time) {
+ /* FIXME: We use a dummy window here to get the correct depth/visual for the
+ pixmap creation (cant use globals.widgets.top_level since it's not realized
+ yet and realizing it now would result in wrong dimensions) ... */
+ Widget dummy = XtVaAppCreateShell("xdvi", "Xdvi",
+ transientShellWidgetClass, DISP,
+ XtNdepth, G_depth,
+ XtNvisual, G_visual,
+ XtNcolormap, G_colormap,
+ XtNmappedWhenManaged, False,
+ NULL);
+ XtRealizeWidget(dummy); /* note: doesn't pop it up */
+ rootWindow = XtWindow(dummy);
+ screenNum = DefaultScreen(XtDisplay(globals.widgets.top_level));
+ ASSERT(rootWindow != 0, "");
+ XtVaGetValues(parent,
+ XmNbackground, &color[BACKGROUND].pixel,
+ XmNforeground, &color[FOREGROUND].pixel,
+ XmNbottomShadowColor, &color[BOTTOM_SHADOW].pixel,
+ XmNtopShadowColor, &color[TOP_SHADOW].pixel,
+ XmNhighlightColor, &color[HIGHLIGHT].pixel,
+ NULL);
+ /* try to locate the XPM file with the toolbar pixmaps */
+ pixmap_file_path = XtResolvePathname(DISP,
+ "pixmaps",
+ resource.toolbar_pixmap_file,
+ (String)NULL, /* suffix */
+ (String)NULL, /* use default path */
+ (Substitution)NULL, /* substitutions */
+ 0, /* number of substitutions */
+ (XtFilePredicate)NULL); /* return True iff file exists */
+
+ TRACE_GUI((stderr, "pixmap file search via XtResolvePathname: %s => %s",
+ resource.toolbar_pixmap_file, pixmap_file_path ? (char*)pixmap_file_path : "<NULL>"));
+ if (pixmap_file_path == NULL) {
+ pixmap_file_path = (String)kpse_find_file(resource.toolbar_pixmap_file,
+ kpse_program_text_format,
+ 0);
+ TRACE_GUI((stderr,
+ "pixmap file search via kpse_find_file: %s => %s",
+ resource.toolbar_pixmap_file,
+ pixmap_file_path ? (char*)pixmap_file_path : "<NULL>"));
+ if (pixmap_file_path == NULL) {
+ TRACE_GUI((stderr, "No installed toolbar pixmap found, using built-in pixmap."));
+ }
+ }
+ }
+
+ /* Setup the color subsititution table */
+ attr.valuemask = XpmColorSymbols | XpmCloseness | XpmColormap | XpmDepth | XpmVisual;
+ attr.closeness = 65535; /* accuracy isn't crucial */
+ attr.colorsymbols = color;
+ attr.numsymbols = XtNumber(color);
+ attr.visual = G_visual;
+ attr.colormap = G_colormap;
+ attr.depth = G_depth;
+
+ /* Create the "sensitive" pixmap */
+ if (!tools_map) {
+ if (pixmap_file_path != NULL) {
+ status = XpmReadFileToPixmap(XtDisplay(globals.widgets.top_level), rootWindow,
+ pixmap_file_path, &tools_map, &tools_mask, &attr);
+ }
+ else {
+ status = XpmCreatePixmapFromData(XtDisplay(globals.widgets.top_level), rootWindow,
+ (char **)toolbar_xpm, &tools_map, &tools_mask, &attr);
+ }
+ }
+ else
+ status = XpmSuccess;
+
+ map = tools_map;
+ mask = tools_mask;
+
+ if (status == XpmSuccess) {
+ static Pixmap tmp_mask;
+ static GC gc;
+
+ if (first_time) {
+ tmp_mask = XCreatePixmap(XtDisplay(globals.widgets.top_level), rootWindow, PIXMAP_WIDTH, PIXMAP_HEIGHT, 1);
+ gc = XCreateGC(XtDisplay(globals.widgets.top_level), tmp_mask, 0, NULL);
+ }
+ XCopyArea(XtDisplay(globals.widgets.top_level),
+ mask, tmp_mask, gc, iconidx * PIXMAP_WIDTH, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT, 0, 0);
+
+ mask = tmp_mask;
+ }
+ else { /* something went wrong */
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ "Something's wrong with your XPM file - "
+ "try to load it into an image editor and fix the problem.",
+ "Xpm error: %s - switching toolbar off.",
+ XpmGetErrorString(status));
+ sen = insen = NULL;
+ resource.expert_mode ^= XPRT_SHOW_TOOLBAR;
+ return False;
+ }
+
+ XpmFreeAttributes(&attr);
+
+ if (map != 0) {
+ static GC back_gc, bots_gc;
+
+ if (first_time) {
+ XGCValues gcvalues;
+
+ gcvalues.foreground = color[BACKGROUND].pixel;
+ back_gc = XCreateGC(XtDisplay(globals.widgets.top_level), rootWindow, GCForeground, &gcvalues);
+
+ gcvalues.foreground = color[BOTTOM_SHADOW].pixel;
+ bots_gc = XCreateGC(XtDisplay(globals.widgets.top_level), rootWindow, GCForeground, &gcvalues);
+ }
+
+ /* Need to create new Pixmaps with the mask applied. */
+ XSetClipMask(XtDisplay(globals.widgets.top_level), bots_gc, mask);
+
+ /* Create the "sensitive" pixmap. */
+ *sen = XCreatePixmap(XtDisplay(globals.widgets.top_level), rootWindow, PIXMAP_WIDTH, PIXMAP_HEIGHT,
+ G_depth);
+ XFillRectangle(XtDisplay(globals.widgets.top_level), *sen, back_gc, 0, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT);
+ if (iconidx != -1)
+ XCopyArea(XtDisplay(globals.widgets.top_level), map, *sen, bots_gc,
+ iconidx * PIXMAP_WIDTH, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT, 0, 0);
+ else
+ XCopyArea(XtDisplay(globals.widgets.top_level), map, *sen, bots_gc,
+ 0, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT, 0, 0);
+
+ if (iconidx == -1)
+ XFreePixmap(XtDisplay(globals.widgets.top_level), map);
+
+ /* Create the "insensitive" pixmap. */
+ if (insen != NULL) {
+ Pixmap map;
+ Pixmap mask;
+
+ attr.valuemask = XpmColorSymbols | XpmCloseness | XpmColorKey | XpmColormap | XpmDepth | XpmVisual;
+ attr.closeness = 65535; /* accuracy isn't crucial */
+ attr.colorsymbols = color;
+ attr.numsymbols = XtNumber(color);
+ attr.color_key = XPM_MONO;
+ attr.visual = G_visual;
+ attr.colormap = G_colormap;
+ attr.depth = G_depth;
+
+
+ if (!shade_map) {
+ if (pixmap_file_path != NULL) {
+ status = XpmReadFileToPixmap(XtDisplay(globals.widgets.top_level), rootWindow,
+ pixmap_file_path, &shade_map, &shade_mask, &attr);
+ }
+ else {
+ status = XpmCreatePixmapFromData(XtDisplay(globals.widgets.top_level), rootWindow,
+ (char **)toolbar_xpm, &shade_map, &shade_mask, &attr);
+ }
+ }
+ else
+ status = XpmSuccess;
+
+ map = shade_map;
+ mask = shade_mask;
+
+ if (status == XpmSuccess) {
+ static Pixmap tmp_mask;
+ static GC gc;
+
+ if (first_time) {
+ tmp_mask = XCreatePixmap(XtDisplay(globals.widgets.top_level), rootWindow,
+ PIXMAP_WIDTH, PIXMAP_HEIGHT, 1);
+ gc = XCreateGC(XtDisplay(globals.widgets.top_level), tmp_mask, 0, NULL);
+ }
+
+ XCopyArea(XtDisplay(globals.widgets.top_level), mask, tmp_mask, gc,
+ iconidx * PIXMAP_WIDTH, 0,
+ PIXMAP_WIDTH, PIXMAP_HEIGHT,
+ 0, 0);
+
+ mask = tmp_mask;
+ }
+ else { /* something went wrong */
+ popup_message(globals.widgets.top_level,
+ MSG_ERR,
+ "Something's wrong with your XPM file - "
+ "try to load it into an image editor and fix the problem.",
+ "Xpm error: %s - switching toolbar off.",
+ XpmGetErrorString(status));
+ sen = insen = NULL;
+ resource.expert_mode ^= XPRT_SHOW_TOOLBAR;
+ return False;
+ }
+
+ if (mask != 0) {
+ static GC tops_gc;
+
+ if (first_time) {
+ XGCValues gcvalues;
+
+ gcvalues.foreground = color[TOP_SHADOW].pixel;
+ tops_gc = XCreateGC(XtDisplay(globals.widgets.top_level), rootWindow, GCForeground, &gcvalues);
+ }
+
+ /* Need to create new Pixmaps with the mask applied. */
+ XSetClipMask(XtDisplay(globals.widgets.top_level), bots_gc, mask);
+ XSetClipMask(XtDisplay(globals.widgets.top_level), tops_gc, mask);
+ XSetClipOrigin(XtDisplay(globals.widgets.top_level), tops_gc, 1, 1);
+
+ *insen = XCreatePixmap(XtDisplay(globals.widgets.top_level), rootWindow, PIXMAP_WIDTH, PIXMAP_HEIGHT,
+ G_depth);
+
+ XFillRectangle(XtDisplay(globals.widgets.top_level), *insen, back_gc, 0, 0,
+ PIXMAP_WIDTH, PIXMAP_HEIGHT);
+ XFillRectangle(XtDisplay(globals.widgets.top_level), *insen, tops_gc, 1, 1,
+ PIXMAP_WIDTH - 1, PIXMAP_HEIGHT - 1);
+ XFillRectangle(XtDisplay(globals.widgets.top_level), *insen, bots_gc, 0, 0, PIXMAP_WIDTH, PIXMAP_HEIGHT);
+
+ if (iconidx == -1)
+ XFreePixmap(XtDisplay(globals.widgets.top_level), map);
+ }
+
+ XpmFreeAttributes(&attr);
+ }
+ }
+
+ first_time = False;
+ return True;
+}
+
+/*
+ * If successful, this returns True, and sets *button to a button with
+ * a square pixmap on it (which is cut out form `index' position in
+ * resource.toolbar_pixmap_file). If unsuccessful, it returns false,
+ * and *button is undefined.
+ */
+static Boolean
+create_toolbar_button(Widget parent, Widget *button,
+ const Pixmap *image_sens, const Pixmap *image_insens)
+{
+ Boolean sensitive = True; /* dummy */
+ *button = XtVaCreateManagedWidget("button", xmPushButtonWidgetClass, parent,
+ XmNhighlightOnEnter, True,
+ XmNlabelPixmap, *image_sens,
+ XmNlabelInsensitivePixmap, *image_insens,
+ XmNsensitive, sensitive,
+ XmNlabelType, XmPIXMAP,
+ NULL);
+ XtVaGetValues(*button, XmNshadowThickness, &m_shadow_thickness, NULL);
+ if (!resource.toolbar_buttons_raised) {
+ if (m_background == 0) { /* initialize values */
+ XtVaGetValues(*button,
+ /* should we rather get background of parent widget? */
+ XmNbackground, &m_background,
+ XmNtopShadowColor, &m_top_shadow_color,
+ XmNbottomShadowColor, &m_bottom_shadow_color,
+ NULL);
+ }
+ /* remove shadows, setting them later when mouse enters button */
+ XtVaSetValues(*button,
+ XmNtopShadowColor, m_background,
+ XmNbottomShadowColor, m_background,
+ NULL);
+ }
+ return True;
+}
+
+static void
+create_toolbar_separator(Widget parent, Widget *separator, int width)
+{
+ *separator = XtVaCreateManagedWidget("toolbarSeparator",
+ xmSeparatorWidgetClass, parent,
+ XmNseparatorType, XmNO_LINE,
+ XmNminWidth, width,
+ XmNwidth, width,
+ XmNorientation, XmVERTICAL,
+ XmNleftAttachment, XmATTACH_WIDGET,
+ XmNrightAttachment, XmATTACH_WIDGET,
+ XmNtopAttachment, XmATTACH_FORM,
+ XmNbottomAttachment, XmATTACH_FORM,
+ NULL);
+}
+
+/* taken from shadow_trick in WlToolBar.c, mgv-3.1.5:
+ Get a raised behaviour for armed buttons, by explicitly setting
+ a shadow on entry and removing it on leave.
+*/
+static void
+enter_leave(Widget w, XtPointer closure, XEvent *event, Boolean *cont)
+{
+ char *tooltip = (char *)closure;
+ XCrossingEvent *ev = (XCrossingEvent *)event;
+ static Boolean entered = False; /* to skip double leaves */
+
+ UNUSED(cont);
+
+ if (ev->type == EnterNotify) {
+ if (!resource.toolbar_buttons_raised) {
+ /* draw shadows */
+ XtVaSetValues(w,
+ XmNtopShadowColor, m_top_shadow_color,
+ XmNbottomShadowColor, m_bottom_shadow_color,
+ NULL);
+ }
+ entered = True;
+ if (resource.tooltips_in_statusline) {
+ statusline_print(STATUS_SHORT, tooltip);
+ }
+ }
+ else if (ev->type == LeaveNotify && !resource.toolbar_buttons_raised) {
+ /* remove shadows */
+ if (!entered)
+ return;
+
+ XtVaSetValues(w,
+ XmNtopShadowColor, m_background,
+ XmNbottomShadowColor, m_background,
+ NULL);
+ entered = False;
+ }
+}
+
+/*
+ save info about special buttons in m_button_info
+ (see definition of that for details)
+*/
+static void
+button_info_save(struct xdvi_action *action, Widget w)
+{
+ if (action->proc == Act_back_page && strcmp(action->param, "1") == 0) {
+ m_button_info.back_button = w;
+ }
+ else if (action->proc == Act_forward_page && strcmp(action->param, "1") == 0) {
+ m_button_info.forward_button = w;
+ }
+ else if (action->proc == Act_pagehistory_back) {
+ set_button_sensitivity(w, False);
+ m_button_info.hyperref_back_button = w;
+ }
+ else if (action->proc == Act_pagehistory_forward) {
+ set_button_sensitivity(w, False);
+ m_button_info.hyperref_forward_button = w;
+ }
+ else if (action->proc == Act_set_shrink_factor && action->param[0] == '+') {
+ m_button_info.zoom_in_button = w;
+ }
+}
+
+#endif /* HAVE_XPM */
+
+/*
+ * Create a toolbar with buttons, return toolbar widget.
+ */
+Widget
+create_toolbar(Widget parent, Widget menu_bar)
+{
+#if HAVE_XPM
+ size_t alloc_len = 0, n;
+ size_t alloc_step = 16;
+ const char *c_ptr, *e_ptr;
+#endif /* HAVE_XPM */
+ Widget tool_bar;
+ resource.toolbar_unusable = False;
+
+ tool_bar_frame = XtVaCreateWidget("toolBarFrame",
+ xmFrameWidgetClass, parent,
+ XmNshadowType, XmSHADOW_OUT,
+ XmNleftAttachment, XmATTACH_FORM,
+ XmNrightAttachment, XmATTACH_FORM,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, menu_bar,
+ NULL);
+
+ tool_bar = XtVaCreateManagedWidget("toolBar",
+ xmRowColumnWidgetClass, tool_bar_frame,
+ XmNchildType, XmFRAME_WORKAREA_CHILD,
+ XmNrowColumnType, XmWORK_AREA,
+ XmNorientation, XmHORIZONTAL,
+ XmNtraversalOn, False,
+ XmNisHomogeneous, False,
+ XmNpacking, XmPACK_TIGHT,
+ XmNspacing, 0, /* override to use SEPARATOR(n) instead */
+ XmNadjustLast, True,
+ NULL);
+
+#if HAVE_XPM
+ /* parse toolbar_translations, create the widgets and assign the actions */
+ for (n = 0, c_ptr = resource.toolbar_translations;
+ c_ptr != NULL && *c_ptr != '\0';
+ c_ptr = e_ptr, n++) {
+ char **line_items = NULL;
+ int extra_space;
+ size_t len, curr, item_count = 0;
+
+ if ((e_ptr = strchr(c_ptr, '\n')) == NULL
+ /* ... and in case last line doesn't end with \n ... */
+ && (e_ptr = strchr(c_ptr, '\0')) == NULL) {
+ break;
+ }
+
+ if (e_ptr == c_ptr) {
+ XDVI_WARNING((stderr, "Skipping empty line in toolbarTranslations resource."));
+ e_ptr++;
+ continue;
+ }
+ len = e_ptr - c_ptr;
+ TRACE_GUI((stderr, "LEN %lu: |%.*s|", (unsigned long)len, (int)len, c_ptr));
+
+ line_items = split_line(c_ptr, SEP_CHAR, 0, len, &item_count);
+
+ if (globals.debug & DBG_GUI) {
+ int k;
+ for (k = 0; line_items[k] != NULL; k++) {
+ fprintf(stderr, "ITEM %d of %lu: |%s|\n", k, (unsigned long)item_count, line_items[k]);
+ }
+ }
+ while (alloc_len <= n + 1) {
+ alloc_len += alloc_step;
+ toolbar_buttons = xrealloc(toolbar_buttons, alloc_len * sizeof *toolbar_buttons);
+ }
+
+ if (item_count == 1 && sscanf(line_items[0], "SPACER(%d)", &extra_space) == 1) {
+ TRACE_GUI((stderr, "creating spacer of witdh %d at %lu", extra_space, (unsigned long)n));
+ create_toolbar_separator(tool_bar, &(toolbar_buttons[n].button), extra_space);
+ toolbar_buttons[n].type = TB_SEPARATOR;
+ }
+ else if (item_count == 4) {
+ Pixmap sens, insens;
+ int idx = strtoul(line_items[0], (char **)NULL, 10);
+ struct xdvi_action *action;
+
+ TRACE_GUI((stderr, "creating pixmap at %d", idx));
+ if (!create_pixmap(tool_bar, idx, &sens, &insens)) {
+ free(toolbar_buttons);
+ toolbar_buttons = NULL;
+ break;
+ }
+ TRACE_GUI((stderr, "creating button %ld", (unsigned long)n));
+ if (!create_toolbar_button(tool_bar, &(toolbar_buttons[n].button), &sens, &insens)) {
+ free(toolbar_buttons);
+ toolbar_buttons = NULL;
+ break;
+ }
+ toolbar_buttons[n].type = TB_BUTTON;
+
+ if ((action = compile_action(line_items[3])) != NULL) {
+ char *long_tooltip = xstrdup(line_items[1]);
+ toolbar_buttons[n].tip = xstrdup(line_items[2]);
+ /* char *short_tooltip = xstrdup(line_items[2]); */
+ command_call[0].closure = (XtPointer) action;
+
+ /*
+ eventually save this widget in list of `special' buttons
+ that need to toggle between sensitive/insensitive
+ */
+ button_info_save(action, toolbar_buttons[n].button);
+
+ XtVaSetValues(toolbar_buttons[n].button, XmNactivateCallback, (XtArgVal)command_call, NULL);
+ XtAddEventHandler(toolbar_buttons[n].button,
+ EnterWindowMask | LeaveWindowMask,
+ False,
+ enter_leave,
+ long_tooltip);
+ }
+ else {
+ XDVI_WARNING((stderr, "Invalid action \"%s\" in toolbarTranslations resource:\n\"%.*s\"",
+ line_items[3], (int)len, c_ptr));
+ }
+ }
+ else {
+ XDVI_WARNING((stderr, "Skipping malformed line \"%.*s\" in toolbarTranslations resource "
+ "(%lu instead of 4 items).",
+ (int)len, c_ptr, (unsigned long)item_count));
+ toolbar_buttons[n].button = 0;
+ }
+
+ for (curr = 0; curr < item_count; curr++) {
+ free(line_items[curr]);
+ }
+ free(line_items);
+ line_items = NULL;
+
+ if (*e_ptr != '\0')
+ e_ptr++;
+ }
+#else
+ if ((resource.expert_mode & XPRT_SHOW_SCROLLBARS) != 0) {
+ XDVI_WARNING((stderr, "This version has been compiled without XPM support. "
+ "Disabling the toolbar, which needs XPM."));
+ }
+#endif /* HAVE_XPM */
+
+ if (toolbar_buttons == NULL) {
+ resource.toolbar_unusable = True;
+ resource.expert_mode ^= XPRT_SHOW_TOOLBAR;
+ }
+ else {
+#if HAVE_XPM
+ toolbar_buttons[n].button = 0; /* terminate info */
+#endif
+ }
+ return tool_bar;
+}
+
+/*
+ * Add the tips to the toolbar. This has to be done after the toolbar has been
+ * realized.
+ */
+void
+create_tips(Widget toplevel)
+{
+#if HAVE_XPM
+ Widget tip_shell;
+
+ int i;
+
+ if (resource.toolbar_unusable) /* don't create tips in this case */
+ return;
+
+ tip_shell = XtVaCreatePopupShell("tipShell", tipWidgetClass,
+ toplevel, XtNwidth, 1, XtNheight, 1,
+ NULL);
+
+ for (i = 0; toolbar_buttons[i].button != 0; i++) {
+ if (toolbar_buttons[i].type == TB_BUTTON) {
+ TipAddWidget(tip_shell, toolbar_buttons[i].button, toolbar_buttons[i].tip);
+ }
+ }
+#else
+ UNUSED(toplevel);
+#endif /* HAVE_XPM */
+}
+
+
+#else /* MOTIF */
+/* silence "empty compilation unit" and "`toolbar_xpm' defined but not used" warnings */
+static void bar(void); static void foo() { UNUSED(toolbar_xpm); bar(); } static void bar(void) { foo(); }
+#endif /* MOTIF */
diff --git a/Build/source/texk/xdvik/gui/xm_toolbar.h b/Build/source/texk/xdvik/gui/xm_toolbar.h
new file mode 100644
index 00000000000..7afd1012d59
--- /dev/null
+++ b/Build/source/texk/xdvik/gui/xm_toolbar.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2001 Marcin Dalecki
+ * Copyright (c) 2002-2004 the xdvik development team
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+
+ */
+
+#ifndef XM_TOOLBAR_H_
+#define XM_TOOLBAR_H_
+
+#ifdef MOTIF
+
+extern Widget create_toolbar(Widget parent, Widget menu_bar);
+
+extern Boolean toolbar_visible, scrollbars_visible, pagelist_visible;
+extern void create_tips(Widget parent);
+
+#if HAVE_XPM
+extern void tb_check_navigation_sensitivity(int pageno);
+extern void tb_check_navigation_sensitivity(int pageno);
+extern void tb_set_htex_forward_sensitivity(Boolean sensitive);
+extern void tb_set_htex_back_sensitivity(Boolean sensitive);
+extern void tb_set_pagehist_forward_sensitivity(Boolean sensitive);
+extern void tb_set_pagehist_back_sensitivity(Boolean sensitive);
+extern void tb_set_zoom_sensitivity(Boolean sensitive);
+#endif /* HAVE_XPM */
+
+extern void toggle_toolbar(void);
+extern void toggle_scrollbars(void);
+
+#endif /* MOTIF */
+
+#endif /* XM_TOOLBAR_H_ */