aboutsummaryrefslogtreecommitdiff
path: root/vendor/x11iraf/obm/ObmW/HTML.c
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /vendor/x11iraf/obm/ObmW/HTML.c
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'vendor/x11iraf/obm/ObmW/HTML.c')
-rw-r--r--vendor/x11iraf/obm/ObmW/HTML.c6177
1 files changed, 6177 insertions, 0 deletions
diff --git a/vendor/x11iraf/obm/ObmW/HTML.c b/vendor/x11iraf/obm/ObmW/HTML.c
new file mode 100644
index 00000000..546bfbc0
--- /dev/null
+++ b/vendor/x11iraf/obm/ObmW/HTML.c
@@ -0,0 +1,6177 @@
+/****************************************************************************
+ * NCSA Mosaic for the X Window System *
+ * Software Development Group *
+ * National Center for Supercomputing Applications *
+ * University of Illinois at Urbana-Champaign *
+ * 605 E. Springfield, Champaign IL 61820 *
+ * mosaic@ncsa.uiuc.edu *
+ * *
+ * Copyright (C) 1993, Board of Trustees of the University of Illinois *
+ * *
+ * NCSA Mosaic software, both binary and source (hereafter, Software) is *
+ * copyrighted by The Board of Trustees of the University of Illinois *
+ * (UI), and ownership remains with the UI. *
+ * *
+ * The UI grants you (hereafter, Licensee) a license to use the Software *
+ * for academic, research and internal business purposes only, without a *
+ * fee. Licensee may distribute the binary and source code (if released) *
+ * to third parties provided that the copyright notice and this statement *
+ * appears on all copies and that no charge is associated with such *
+ * copies. *
+ * *
+ * Licensee may make derivative works. However, if Licensee distributes *
+ * any derivative work based on or derived from the Software, then *
+ * Licensee will (1) notify NCSA regarding its distribution of the *
+ * derivative work, and (2) clearly notify users that such derivative *
+ * work is a modified version and not the original NCSA Mosaic *
+ * distributed by the UI. *
+ * *
+ * Any Licensee wishing to make commercial use of the Software should *
+ * contact the UI, c/o NCSA, to negotiate an appropriate license for such *
+ * commercial use. Commercial use includes (1) integration of all or *
+ * part of the source code into a product for sale or license by or on *
+ * behalf of Licensee to third parties, or (2) distribution of the binary *
+ * code or source code to third parties that need it to utilize a *
+ * commercial product sold or licensed by or on behalf of Licensee. *
+ * *
+ * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR *
+ * ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
+ * WARRANTY. THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
+ * USERS OF THIS SOFTWARE. *
+ * *
+ * By using or copying this Software, Licensee agrees to abide by the *
+ * copyright law and all other applicable laws of the U.S. including, but *
+ * not limited to, export control laws, and the terms of this license. *
+ * UI shall have the right to terminate this license immediately by *
+ * written notice upon Licensee's breach of, or non-compliance with, any *
+ * of its terms. Licensee may be held legally responsible for any *
+ * copyright infringement that is caused or encouraged by Licensee's *
+ * failure to abide by the terms of this license. *
+ * *
+ * Comments and questions are welcome and can be sent to *
+ * mosaic-x@ncsa.uiuc.edu. *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include "HTMLP.h"
+#ifdef MOTIF
+#include <Xm/DrawingA.h>
+#include <Xm/ScrollBar.h>
+#else
+#include "DrawingArea.h"
+#include <X11/Xaw/Scrollbar.h>
+#endif
+#include <X11/cursorfont.h>
+
+
+#define MARGIN_DEFAULT 20
+#define CLICK_TIME 500
+#define SELECT_THRESHOLD 3
+#define MAX_UNDERLINES 3
+#define DEFAULT_INCREMENT 18
+
+#ifndef ABS
+#define ABS(x) (((x) > 0) ? (x) : ((x) * -1))
+#endif
+
+#define W_TEXTFIELD 0
+#define W_CHECKBOX 1
+#define W_RADIOBOX 2
+#define W_PUSHBUTTON 3
+#define W_PASSWORD 4
+#define W_OPTIONMENU 5
+
+
+extern int FormatAll();
+extern int DocumentWidth();
+extern void PlaceLine();
+extern void TextRefresh();
+extern void ImageRefresh();
+extern void LinefeedRefresh();
+extern void RefreshTextRange();
+extern void FreeColors();
+extern void FreeImages();
+extern void HideWidgets();
+extern void MapWidgets();
+extern int SwapElements();
+extern int ElementLessThan();
+extern int IsDelayedHRef();
+extern int IsIsMapForm();
+extern int AnchoredHeight();
+extern char *ParseMarkTag();
+extern char *ParseTextToString();
+extern char *ParseTextToPrettyString();
+extern char *ParseTextToPSString();
+extern struct mark_up *HTMLParse();
+extern struct ele_rec *LocateElement();
+extern struct ele_rec **MakeLineList();
+extern void FreeHRefs();
+extern struct ref_rec *AddHRef();
+extern void FreeDelayedImages();
+extern struct delay_rec *AddDelayedImage();
+extern ImageInfo *NoImageData();
+extern void ImageSubmitForm();
+
+
+static void SelectStart();
+static void ExtendStart();
+static void ExtendAdjust();
+static void ExtendEnd();
+static void TrackMotion();
+static Boolean ConvertSelection();
+static void LoseSelection();
+static void SelectionDone();
+static void Scroll();
+
+
+#ifdef _NO_PROTO
+
+static void _HTMLInput() ;
+#ifndef MOTIF
+static void _HTMLpwdInput() ;
+#endif
+static void Initialize() ;
+static void Realize() ;
+static void Redisplay() ;
+static void Resize() ;
+static Boolean SetValues() ;
+static XtGeometryResult GeometryManager() ;
+static void RecolorInternalHRefs() ;
+static Dimension VbarWidth();
+static Dimension HbarHeight();
+static void ViewRedisplay();
+static void ViewClearAndRefresh();
+static void CallLinkCallbacks();
+
+#else /* _NO_PROTO */
+
+static void _HTMLInput(Widget w, XEvent *event,
+ String *params, Cardinal *num_params);
+#ifndef MOTIF
+static void _HTMLpwdInput(Widget w, XEvent *event,
+ String *params, Cardinal *num_params);
+#endif
+static void Initialize(HTMLWidget request, HTMLWidget new);
+static void Realize(HTMLWidget hw, Mask *valueMask,
+ XSetWindowAttributes *attributes);
+static void Redisplay(HTMLWidget hw, XEvent *event, Region region);
+static void Resize(HTMLWidget hw);
+static Boolean SetValues(HTMLWidget current, HTMLWidget request,
+ HTMLWidget new);
+static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *request,
+ XtWidgetGeometry *reply);
+static void RecolorInternalHRefs(HTMLWidget hw, char *href);
+static Dimension VbarWidth(HTMLWidget hw);
+static Dimension HbarHeight(HTMLWidget hw);
+static void ViewRedisplay(HTMLWidget hw, int x, int y,
+ int width, int height);
+static void ViewClearAndRefresh(HTMLWidget hw);
+static void CallLinkCallbacks(HTMLWidget hw);
+#endif /* _NO_PROTO */
+
+
+/*
+ * Default translations
+ * Selection of text, and activate anchors.
+ * If motif, add manager translations.
+ */
+#ifdef MOTIF
+static char defaultTranslations[] =
+" \
+<Btn1Down>: select-start() ManagerGadgetArm()\n\
+<Btn1Motion>: extend-adjust() ManagerGadgetButtonMotion()\n\
+<Btn1Up>: extend-end(PRIMARY, CUT_BUFFER0) ManagerGadgetActivate()\n\
+<Btn2Down>: select-start()\n\
+<Btn2Motion>: extend-adjust()\n\
+<Btn2Up>: extend-end(PRIMARY, CUT_BUFFER0)\n\
+<Btn3Down>: extend-start()\n\
+<Btn3Motion>: extend-adjust()\n\
+<Btn3Up>: extend-end(PRIMARY, CUT_BUFFER0) \n\
+<Key>f: scroll(1)\n\
+<Key>b: scroll(-1)\n\
+<Key>Prior: scroll(-1)\n\
+<Key>Next: scroll(1)\n\
+<Key>u: scroll(-0.5)\n\
+<Key>d: scroll(0.5)\n\
+<Key>Up: scroll(-0.5)\n\
+<Key>Down: scroll(0.5)\n\
+<Key>j: scroll(1ch)\n\
+<Key>k: scroll(-1ch)\n\
+<Motion>: track-motion()\n\
+<Leave>: track-motion()\n\
+<FocusOut>: track-motion()\n\
+<Expose>: track-motion()\
+";
+#else
+static char defaultTranslations[] =
+" \
+<Btn1Down>: select-start() \n\
+<Btn1Motion>: extend-adjust() \n\
+<Btn1Up>: extend-end(PRIMARY, CUT_BUFFER0) \n\
+<Btn2Down>: select-start() \n\
+<Btn2Motion>: extend-adjust() \n\
+<Btn2Up>: extend-end(PRIMARY, CUT_BUFFER0) \n\
+<Btn3Down>: extend-start()\n\
+<Btn3Motion>: extend-adjust()\n\
+<Btn3Up>: extend-end(PRIMARY, CUT_BUFFER0) \n\
+<Key>f: scroll(1)\n\
+<Key>b: scroll(-1)\n\
+<Key>Prior: scroll(-1)\n\
+<Key>Next: scroll(1)\n\
+<Key>u: scroll(-0.5)\n\
+<Key>d: scroll(0.5)\n\
+<Key>Up: scroll(-0.5)\n\
+<Key>Down: scroll(0.5)\n\
+<Key>j: scroll(1ch)\n\
+<Key>k: scroll(-1ch)\n\
+<Motion>: track-motion()\n\
+<Leave>: track-motion()\n\
+<FocusOut>: track-motion()\n\
+<Expose>: track-motion()\
+";
+#endif /* MOTIF */
+
+
+static XtActionsRec actionsList[] =
+{
+ { "select-start", (XtActionProc) SelectStart },
+ { "extend-start", (XtActionProc) ExtendStart },
+ { "extend-adjust", (XtActionProc) ExtendAdjust },
+ { "extend-end", (XtActionProc) ExtendEnd },
+ { "track-motion", (XtActionProc) TrackMotion },
+ { "scroll", (XtActionProc) Scroll },
+ { "HTMLInput", (XtActionProc) _HTMLInput },
+#ifndef MOTIF
+ { "HTMLpwdInput", (XtActionProc) _HTMLpwdInput },
+#endif
+
+#ifdef MOTIF
+#ifndef MOTIF1_2
+ { "Arm", (XtActionProc) _XmGadgetArm }, /* Motif 1.0 */
+ { "Activate", (XtActionProc) _XmGadgetActivate }, /* Motif 1.0 */
+ { "Enter", (XtActionProc) _XmManagerEnter }, /* Motif 1.0 */
+ { "FocusIn", (XtActionProc) _XmManagerFocusIn }, /* Motif 1.0 */
+ { "Help", (XtActionProc) _XmManagerHelp }, /* Motif 1.0 */
+#endif /* not MOTIF1_2 */
+#endif /* MOTIF */
+};
+
+/*
+ * For some reason, in Motif1.2/X11R5 the actionsList above gets corrupted
+ * When the parent HTML widget is created. This means we can't use
+ * it later with XtAppAddActions to add to the viewing area.
+ * So, we make a spare copy here to use with XtAppAddActions.
+ */
+static XtActionsRec SpareActionsList[] =
+{
+ { "select-start", (XtActionProc) SelectStart },
+ { "extend-start", (XtActionProc) ExtendStart },
+ { "extend-adjust", (XtActionProc) ExtendAdjust },
+ { "extend-end", (XtActionProc) ExtendEnd },
+ { "track-motion", (XtActionProc) TrackMotion },
+ { "scroll", (XtActionProc) Scroll },
+ { "HTMLInput", (XtActionProc) _HTMLInput },
+#ifndef MOTIF
+ { "HTMLpwdInput", (XtActionProc) _HTMLpwdInput },
+#endif
+};
+
+
+
+/*
+ * Resource definitions for HTML widget
+ */
+
+static XtResource resources[] =
+{
+ /* Without Motif we need to override the borderWidth to 0 (from 1). */
+#ifndef MOTIF
+ { XtNborderWidth,
+ XtCBorderWidth, XtRDimension, sizeof (Dimension),
+ XtOffset (HTMLWidget, core.border_width),
+ XtRImmediate, (XtPointer) 0
+ },
+#endif
+
+ { WbNmarginWidth,
+ WbCMarginWidth, XtRDimension, sizeof (Dimension),
+ XtOffset (HTMLWidget, html.margin_width),
+ XtRImmediate, (caddr_t) MARGIN_DEFAULT
+ },
+
+ { WbNmarginHeight,
+ WbCMarginHeight, XtRDimension, sizeof (Dimension),
+ XtOffset (HTMLWidget, html.margin_height),
+ XtRImmediate, (caddr_t) MARGIN_DEFAULT
+ },
+
+ { WbNanchorCallback,
+ XtCCallback, XtRCallback, sizeof (XtCallbackList),
+ XtOffset (HTMLWidget, html.anchor_callback),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ { WbNlinkCallback,
+ XtCCallback, XtRCallback, sizeof (XtCallbackList),
+ XtOffset (HTMLWidget, html.link_callback),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ { WbNsubmitFormCallback,
+ XtCCallback, XtRCallback, sizeof (XtCallbackList),
+ XtOffset (HTMLWidget, html.form_callback),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ { WbNtext,
+ WbCText, XtRString, sizeof (char *),
+ XtOffset (HTMLWidget, html.raw_text),
+ XtRString, (char *) NULL
+ },
+
+ { WbNheaderText,
+ WbCHeaderText, XtRString, sizeof (char *),
+ XtOffset (HTMLWidget, html.header_text),
+ XtRString, (char *) NULL
+ },
+
+ { WbNfooterText,
+ WbCFooterText, XtRString, sizeof (char *),
+ XtOffset (HTMLWidget, html.footer_text),
+ XtRString, (char *) NULL
+ },
+
+ { WbNtitleText,
+ WbCTitleText, XtRString, sizeof (char *),
+ XtOffset (HTMLWidget, html.title),
+ XtRString, (char *) NULL
+ },
+
+/*
+ * Without motif we need our own foreground resource instead of
+ * using the manager's
+ */
+#ifndef MOTIF
+ { XtNforeground,
+ XtCForeground, XtRPixel, sizeof (Pixel),
+ XtOffset (HTMLWidget, html.foreground),
+ XtRString, "Black"
+ },
+#endif
+
+ { WbNanchorUnderlines,
+ WbCAnchorUnderlines, XtRInt, sizeof (int),
+ XtOffset (HTMLWidget, html.num_anchor_underlines),
+ XtRString, "0"
+ },
+
+ { WbNvisitedAnchorUnderlines,
+ WbCVisitedAnchorUnderlines, XtRInt, sizeof (int),
+ XtOffset (HTMLWidget, html.num_visitedAnchor_underlines),
+ XtRString, "0"
+ },
+
+ { WbNdashedAnchorUnderlines,
+ WbCDashedAnchorUnderlines, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.dashed_anchor_lines),
+ XtRString, "False"
+ },
+
+ { WbNdashedVisitedAnchorUnderlines,
+ WbCDashedVisitedAnchorUnderlines, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.dashed_visitedAnchor_lines),
+ XtRString, "False"
+ },
+
+ { WbNanchorColor,
+ XtCForeground, XtRPixel, sizeof (Pixel),
+ XtOffset (HTMLWidget, html.anchor_fg),
+ XtRString, "blue2"
+ },
+
+ { WbNvisitedAnchorColor,
+ XtCForeground, XtRPixel, sizeof (Pixel),
+ XtOffset (HTMLWidget, html.visitedAnchor_fg),
+ XtRString, "purple4"
+ },
+
+ { WbNactiveAnchorFG,
+ XtCBackground, XtRPixel, sizeof (Pixel),
+ XtOffset (HTMLWidget, html.activeAnchor_fg),
+ XtRString, "Red"
+ },
+
+ { WbNactiveAnchorBG,
+ XtCForeground, XtRPixel, sizeof (Pixel),
+ XtOffset (HTMLWidget, html.activeAnchor_bg),
+ XtRString, "White"
+ },
+
+ { WbNpercentVerticalSpace,
+ WbCPercentVerticalSpace, XtRInt, sizeof (int),
+ XtOffset (HTMLWidget, html.percent_vert_space),
+ XtRString, "90"
+ },
+
+ { WbNimageBorders,
+ WbCImageBorders, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.border_images),
+ XtRString, "False"
+ },
+
+ { WbNdelayImageLoads,
+ WbCDelayImageLoads, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.delay_images),
+ XtRString, "False"
+ },
+
+ { WbNfancySelections,
+ WbCFancySelections, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.fancy_selections),
+ XtRString, "False"
+ },
+
+ { WbNisIndex,
+ WbCIsIndex, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.is_index),
+ XtRString, "False"
+ },
+
+ { WbNview,
+ WbCView, XtRWidget, sizeof (Widget),
+ XtOffset (HTMLWidget, html.view),
+ XtRImmediate, NULL
+ },
+
+ { WbNverticalScrollBar,
+ WbCVerticalScrollBar, XtRWidget, sizeof (Widget),
+ XtOffset (HTMLWidget, html.vbar),
+ XtRImmediate, NULL
+ },
+
+ { WbNhorizontalScrollBar,
+ WbCHorizontalScrollBar, XtRWidget, sizeof (Widget),
+ XtOffset (HTMLWidget, html.hbar),
+ XtRImmediate, NULL
+ },
+
+ { WbNverticalScrollOnRight,
+ WbCVerticalScrollOnRight, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.vbar_right),
+ XtRString, "True"
+ },
+
+ { WbNhorizontalScrollOnTop,
+ WbCHorizontalScrollOnTop, XtRBoolean, sizeof (Boolean),
+ XtOffset (HTMLWidget, html.hbar_top),
+ XtRString, "False"
+ },
+
+ { XtNfont,
+ XtCFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.font),
+ XtRString, "-adobe-times-medium-r-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNitalicFont,
+ WbCItalicFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.italic_font),
+ XtRString, "-adobe-times-medium-i-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNboldFont,
+ WbCBoldFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.bold_font),
+ XtRString, "-adobe-times-bold-r-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNfixedFont,
+ WbCFixedFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.fixed_font),
+ XtRString, "-adobe-courier-medium-r-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNfixedboldFont,
+ WbCFixedboldFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.fixedbold_font),
+ XtRString, "-adobe-courier-bold-r-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNfixeditalicFont,
+ WbCFixeditalicFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.fixeditalic_font),
+ XtRString, "-adobe-courier-medium-o-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNheader1Font,
+ WbCHeader1Font, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.header1_font),
+ XtRString, "-adobe-times-bold-r-normal-*-24-*-*-*-*-*-*-*"
+ },
+
+ { WbNheader2Font,
+ WbCHeader2Font, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.header2_font),
+ XtRString, "-adobe-times-bold-r-normal-*-18-*-*-*-*-*-*-*"
+ },
+
+ { WbNheader3Font,
+ WbCHeader3Font, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.header3_font),
+ XtRString, "-adobe-times-bold-r-normal-*-17-*-*-*-*-*-*-*"
+ },
+
+ { WbNheader4Font,
+ WbCHeader4Font, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.header4_font),
+ XtRString, "-adobe-times-bold-r-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNheader5Font,
+ WbCHeader5Font, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.header5_font),
+ XtRString, "-adobe-times-bold-r-normal-*-12-*-*-*-*-*-*-*"
+ },
+
+ { WbNheader6Font,
+ WbCHeader6Font, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.header6_font),
+ XtRString, "-adobe-times-bold-r-normal-*-10-*-*-*-*-*-*-*"
+ },
+
+ { WbNaddressFont,
+ WbCAddressFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.address_font),
+ XtRString, "-adobe-times-medium-i-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNplainFont,
+ WbCPlainFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.plain_font),
+ XtRString, "-adobe-courier-medium-r-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNplainboldFont,
+ WbCPlainboldFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.plainbold_font),
+ XtRString, "-adobe-courier-bold-r-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNplainitalicFont,
+ WbCPlainitalicFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.plainitalic_font),
+ XtRString, "-adobe-courier-medium-o-normal-*-14-*-*-*-*-*-*-*"
+ },
+
+ { WbNlistingFont,
+ WbCListingFont, XtRFontStruct, sizeof (XFontStruct *),
+ XtOffset (HTMLWidget, html.listing_font),
+ XtRString, "-adobe-courier-medium-r-normal-*-12-*-*-*-*-*-*-*"
+ },
+
+ { WbNpreviouslyVisitedTestFunction,
+ WbCPreviouslyVisitedTestFunction, XtRPointer,
+ sizeof (XtPointer),
+ XtOffset (HTMLWidget, html.previously_visited_test),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ { WbNpreviouslyVisitedTestData,
+ WbCPreviouslyVisitedTestData, XtRPointer,
+ sizeof (XtPointer),
+ XtOffset (HTMLWidget, html.vt_client_data),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ { WbNresolveImageFunction,
+ WbCResolveImageFunction, XtRPointer,
+ sizeof (XtPointer),
+ XtOffset (HTMLWidget, html.resolveImage),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ { WbNresolveDelayedImage,
+ WbCResolveDelayedImage, XtRPointer,
+ sizeof (XtPointer),
+ XtOffset (HTMLWidget, html.resolveDelayedImage),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ {
+ WbNpointerMotionCallback,
+ WbCPointerMotionCallback, XtRPointer,
+ sizeof (XtPointer),
+ XtOffset (HTMLWidget, html.pointer_motion_callback),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+ { WbNpointerMotionData,
+ WbCPointerMotionData, XtRPointer,
+ sizeof (XtPointer),
+ XtOffset (HTMLWidget, html.pm_client_data),
+ XtRImmediate, (caddr_t) NULL
+ },
+
+};
+
+
+
+HTMLClassRec htmlClassRec = {
+ { /* core class fields */
+#ifdef MOTIF
+ (WidgetClass) &xmManagerClassRec, /* superclass */
+#else
+ (WidgetClass) &constraintClassRec, /* superclass */
+#endif /* MOTIF */
+ "HTML", /* class_name */
+ sizeof(HTMLRec), /* widget_size */
+ NULL, /* class_initialize */
+ NULL, /* class_part_init */
+ FALSE, /* class_inited */
+ (XtInitProc) Initialize, /* initialize */
+ NULL, /* initialize_hook */
+ (XtRealizeProc) Realize, /* realize */
+ actionsList, /* actions */
+ XtNumber(actionsList), /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* num_resources */
+ NULLQUARK, /* xrm_class */
+ TRUE, /* compress_motion */
+ FALSE, /* compress_exposure */
+ TRUE, /* compress_enterlv */
+ FALSE, /* visible_interest */
+ NULL, /* destroy */
+ (XtWidgetProc) Resize, /* resize */
+ (XtExposeProc) Redisplay, /* expose */
+ (XtSetValuesFunc) SetValues, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ defaultTranslations, /* tm_table */
+ XtInheritQueryGeometry, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator*/
+ NULL, /* extension */
+ },
+
+ { /* composite_class fields */
+ (XtGeometryHandler) GeometryManager, /* geometry_manager */
+ NULL, /* change_managed */
+ XtInheritInsertChild, /* insert_child */
+ XtInheritDeleteChild, /* delete_child */
+ NULL, /* extension */
+ },
+
+ { /* constraint_class fields */
+ NULL, /* resource list */
+ 0, /* num resources */
+ 0, /* constraint size */
+ NULL, /* init proc */
+ NULL, /* destroy proc */
+ NULL, /* set values proc */
+ NULL, /* extension */
+ },
+
+#ifdef MOTIF
+ { /* manager_class fields */
+ XtInheritTranslations, /* translations */
+ NULL, /* syn_resources */
+ 0, /* num_syn_resources */
+ NULL, /* syn_cont_resources */
+ 0, /* num_syn_cont_resources */
+ XmInheritParentProcess, /* parent_process */
+ NULL, /* extension */
+ },
+#endif /* MOTIF */
+
+ { /* html_class fields */
+ 0 /* none */
+ }
+};
+
+WidgetClass htmlWidgetClass = (WidgetClass)&htmlClassRec;
+
+/*static Cursor in_anchor_cursor = (Cursor)NULL;*/ /* MF021 */
+Cursor in_anchor_cursor = (Cursor)NULL;
+
+
+/*
+ * Process an expose event in the View (or drawing area). This
+ * Can be a regular expose event, or perhaps a GraphicsExpose Event.
+ */
+static void
+DrawExpose(w, data, event)
+ Widget w;
+ caddr_t data;
+ XEvent *event;
+{
+ XExposeEvent *ExEvent = (XExposeEvent *)event;
+ HTMLWidget hw = (HTMLWidget)data;
+ int x, y;
+ int width, height;
+
+ if ((event->xany.type != Expose)&&(event->xany.type != GraphicsExpose))
+ {
+ return;
+ }
+
+ /*
+ * Make sure we have a valid GC to draw with.
+ */
+ if (hw->html.drawGC == NULL)
+ {
+ unsigned long valuemask;
+ XGCValues values;
+
+ values.function = GXcopy;
+ values.plane_mask = AllPlanes;
+/*
+ * Without motif we use our own foreground resource instead of
+ * using the manager's
+ */
+#ifdef MOTIF
+ values.foreground = hw->manager.foreground;
+#else
+ values.foreground = hw->html.foreground;
+#endif /* MOTIF */
+ values.background = hw->core.background_pixel;
+
+ valuemask = GCFunction|GCPlaneMask|GCForeground|GCBackground;
+
+ hw->html.drawGC = XCreateGC(XtDisplay(hw), XtWindow(hw),
+ valuemask, &values);
+ }
+
+ x = ExEvent->x;
+ y = ExEvent->y;
+ width = (int)ExEvent->width;
+ height = (int)ExEvent->height;
+
+#ifdef DEBUG
+DebugHook(x, y, width, height);
+#endif
+
+ ViewRedisplay(hw, x, y, width, height);
+}
+
+
+void
+ScrollWidgets(hw)
+ HTMLWidget hw;
+{
+ WidgetInfo *wptr;
+ int xval, yval;
+
+ xval = hw->html.scroll_x;
+ yval = hw->html.scroll_y;
+ wptr = hw->html.widget_list;
+ while (wptr != NULL)
+ {
+ if (wptr->w != NULL)
+ {
+ Widget w;
+ int x, y;
+
+ w = wptr->w;
+ x = wptr->x;
+ y = wptr->y;
+ XtMoveWidget(w, (x - xval), (y - yval));
+ }
+ wptr = wptr->next;
+ }
+}
+
+
+#ifndef MOTIF
+/*
+ * Set the Athena Scrollbar's thumb position properly.
+ */
+static void
+setScrollBar(sb, topPosition, totalLength, currentLength)
+ Widget sb;
+ int topPosition; /* MF026 */
+ int totalLength, currentLength; /* MF026 */
+{
+ float top = (float)topPosition /(float)(totalLength);
+ float shown = (float)currentLength/(float)(totalLength);
+
+ XawScrollbarSetThumb(sb, top, shown);
+}
+#endif
+
+
+/*
+ * Either the vertical or hortizontal scrollbar has been moved
+ */
+void
+ScrollToPos(w, hw, value)
+ Widget w;
+ HTMLWidget hw;
+ int value;
+{
+ /*
+ * Special code incase the scrollbar is "moved" before we have a window
+ * (if we have a GC we have a window)
+ */
+ if (hw->html.drawGC == NULL)
+ {
+ if (w == hw->html.vbar)
+ {
+ hw->html.scroll_y = value;
+ }
+ else if (w == hw->html.hbar)
+ {
+ hw->html.scroll_x = value;
+ }
+ return;
+ }
+
+ /*
+ * get our widgets out of the way (No Expose events)
+ HideWidgets(hw);
+ */
+
+ /*
+ * If we've moved the vertical scrollbar
+ */
+ if (w == hw->html.vbar)
+ {
+ /*
+ * We've scrolled down. Copy up the untouched part of the
+ * window. Then Clear and redraw the new area
+ * exposed.
+ */
+ if (value > hw->html.scroll_y)
+ {
+ int dy;
+
+ dy = value - hw->html.scroll_y;
+ if (dy > hw->html.view_height)
+ {
+ hw->html.scroll_y = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height, False);
+ ViewRedisplay(hw,
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height);
+ }
+ else
+ {
+ XCopyArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ XtWindow(hw->html.view),
+ hw->html.drawGC, 0, dy,
+ hw->html.view_width,
+ hw->html.view_height - dy,
+ 0, 0);
+ hw->html.scroll_y = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ 0, (int)hw->html.view_height - dy,
+ hw->html.view_width, dy, False);
+ ViewRedisplay(hw,
+ 0, (int)hw->html.view_height - dy,
+ hw->html.view_width, dy);
+ }
+ }
+ /*
+ * We've scrolled up. Copy down the untouched part of the
+ * window. Then Clear and redraw the new area
+ * exposed.
+ */
+ else if (value < hw->html.scroll_y)
+ {
+ int dy;
+
+ dy = hw->html.scroll_y - value;
+ if (dy > hw->html.view_height)
+ {
+ hw->html.scroll_y = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height, False);
+ ViewRedisplay(hw,
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height);
+ }
+ else
+ {
+ XCopyArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ XtWindow(hw->html.view),
+ hw->html.drawGC, 0, 0,
+ hw->html.view_width,
+ hw->html.view_height - dy,
+ 0, dy);
+ hw->html.scroll_y = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ 0, 0,
+ hw->html.view_width, dy, False);
+ ViewRedisplay(hw,
+ 0, 0,
+ hw->html.view_width, dy);
+ }
+ }
+ }
+ /*
+ * Else we've moved the horizontal scrollbar
+ */
+ else if (w == hw->html.hbar)
+ {
+ /*
+ * We've scrolled right. Copy left the untouched part of the
+ * window. Then Clear and redraw the new area
+ * exposed.
+ */
+ if (value > hw->html.scroll_x)
+ {
+ int dx;
+
+ dx = value - hw->html.scroll_x;
+ if (dx > hw->html.view_width)
+ {
+ hw->html.scroll_x = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height, False);
+ ViewRedisplay(hw,
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height);
+ }
+ else
+ {
+ XCopyArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ XtWindow(hw->html.view),
+ hw->html.drawGC, dx, 0,
+ hw->html.view_width - dx,
+ hw->html.view_height,
+ 0, 0);
+ hw->html.scroll_x = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ (int)hw->html.view_width - dx, 0,
+ dx, hw->html.view_height, False);
+ ViewRedisplay(hw,
+ (int)hw->html.view_width - dx, 0,
+ dx, hw->html.view_height);
+ }
+ }
+ /*
+ * We've scrolled left. Copy right the untouched part of the
+ * window. Then Clear and redraw the new area
+ * exposed.
+ */
+ else if (value < hw->html.scroll_x)
+ {
+ int dx;
+
+ dx = hw->html.scroll_x - value;
+ if (dx > hw->html.view_width)
+ {
+ hw->html.scroll_x = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height, False);
+ ViewRedisplay(hw,
+ 0, 0,
+ hw->html.view_width,
+ hw->html.view_height);
+ }
+ else
+ {
+ XCopyArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ XtWindow(hw->html.view),
+ hw->html.drawGC, 0, 0,
+ hw->html.view_width - dx,
+ hw->html.view_height,
+ dx, 0);
+ hw->html.scroll_x = value;
+ XClearArea(XtDisplay(hw->html.view),
+ XtWindow(hw->html.view),
+ 0, 0,
+ dx, hw->html.view_height, False);
+ ViewRedisplay(hw,
+ 0, 0,
+ dx, hw->html.view_height);
+ }
+ }
+ }
+
+ /*
+ * Move the now hidden widgets
+ * Flush any Copyed or Cleared text first.
+ XFlush(XtDisplay(hw));
+ */
+ ScrollWidgets(hw);
+
+ /*
+ * Remap the widgets to their new location
+ MapWidgets(hw);
+ */
+}
+
+
+/*
+ * Either the vertical or hortizontal scrollbar has been moved
+ */
+void
+ScrollMove(w, client_data, call_data)
+ Widget w;
+ caddr_t client_data;
+ caddr_t call_data;
+{
+#ifdef MOTIF
+ XmScrollBarCallbackStruct *sc = (XmScrollBarCallbackStruct *)call_data;
+
+ ScrollToPos(w, (HTMLWidget)client_data, sc->value);
+#else
+ float scrollDir = (int)call_data < 0 ? -0.3 : 0.3;
+ HTMLWidget hw = (HTMLWidget)client_data;
+ int value;
+ int totalLength, currentLength; /* MF026 */
+
+ if (w == hw->html.vbar)
+ {
+ totalLength = hw->html.doc_height;
+ currentLength = hw->html.view_height;
+ value = hw->html.scroll_y + scrollDir * currentLength;
+ }
+ else
+ {
+ totalLength = hw->html.doc_width;
+ currentLength = hw->html.view_width;
+ value = hw->html.scroll_x + scrollDir * currentLength;
+ }
+
+ if (value > (int)totalLength) value = totalLength;
+ if (value < 0) value = 0;
+
+ setScrollBar(w, value, totalLength, currentLength);
+ ScrollToPos(w, hw, value);
+#endif
+}
+
+
+#ifndef MOTIF
+void
+JumpMove(w, client_data, call_data)
+ Widget w;
+ caddr_t client_data;
+ caddr_t call_data;
+{
+ HTMLWidget hw = (HTMLWidget)client_data;
+ int value = (int)(*(float *)call_data *
+ (w == hw->html.vbar ?
+ hw->html.doc_height :
+ hw->html.doc_width));
+ ScrollToPos(w, hw, value);
+}
+#endif
+
+
+/*
+ * Create the horizontal and vertical scroll bars.
+ * Size them later.
+ */
+static void
+#ifdef _NO_PROTO
+CreateScrollbars (hw)
+ HTMLWidget hw ;
+#else
+CreateScrollbars(
+ HTMLWidget hw)
+#endif
+{
+ Arg arg[20];
+ Cardinal argcnt;
+ XtTranslations trans;
+
+ /*
+ * If the user hasn't provided a viewing area Widget (which they
+ * should not most of the time) make a drawing are to use.
+ */
+ if (hw->html.view == NULL)
+ {
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XxNwidth, 10); argcnt++;
+ XtSetArg(arg[argcnt], XxNheight, 10); argcnt++;
+ hw->html.view = XtCreateWidget("View",
+#ifdef MOTIF
+ xmDrawingAreaWidgetClass,
+#else
+ drawingAreaWidgetClass,
+#endif
+ (Widget)hw, arg, argcnt);
+ XtManageChild(hw->html.view);
+ }
+
+ /*
+ * For the view widget catch all Expose and GraphicsExpose
+ * events. Replace its translations with ours, and make
+ * sure all the actions are in order.
+ */
+ XtAddEventHandler((Widget)hw->html.view, ExposureMask, True,
+ (XtEventHandler)DrawExpose, (caddr_t)hw);
+ /*
+ * As described previoisly, for some reason with Motif1.2/X11R5
+ * the list actionsList is corrupted when we get here,
+ * so we have to use the special copy SpareActionsList
+ */
+ XtAppAddActions(XtWidgetToApplicationContext(hw->html.view),
+ SpareActionsList, XtNumber(SpareActionsList));
+ trans = XtParseTranslationTable(defaultTranslations);
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XtNtranslations, trans); argcnt++;
+ XtSetValues(hw->html.view, arg, argcnt);
+
+ /*
+ * If the user hasn't provided a vertical scrollbar (which they
+ * should not most of the time) make one.
+ */
+ if (hw->html.vbar == NULL)
+ {
+ argcnt = 0;
+#ifdef MOTIF
+ XtSetArg(arg[argcnt], XmNorientation, XmVERTICAL); argcnt++;
+ hw->html.vbar = XtCreateWidget("Vbar", xmScrollBarWidgetClass,
+ (Widget)hw, arg, argcnt);
+#else
+ XtSetArg(arg[argcnt],XtNorientation,XtorientVertical); argcnt++;
+ hw->html.vbar = XtCreateWidget("Vbar", scrollbarWidgetClass,
+ (Widget)hw, arg, argcnt);
+#endif
+ XtManageChild(hw->html.vbar);
+ }
+
+ /*
+ * Add callbacks to catch scrollbar changes
+ */
+#ifdef MOTIF
+ XtAddCallback(hw->html.vbar, XmNvalueChangedCallback,
+ (XtCallbackProc)ScrollMove, (caddr_t)hw);
+ XtAddCallback(hw->html.vbar, XmNdragCallback,
+ (XtCallbackProc)ScrollMove, (caddr_t)hw);
+#else
+ XtAddCallback(hw->html.vbar, XtNjumpProc,
+ (XtCallbackProc)JumpMove, (caddr_t)hw);
+ XtAddCallback(hw->html.vbar, XtNscrollProc,
+ (XtCallbackProc)ScrollMove, (caddr_t)hw);
+#endif
+
+ /*
+ * If the user hasn't provided a horizontal scrollbar (which they
+ * should not most of the time) make one.
+ */
+ if (hw->html.hbar == NULL)
+ {
+ argcnt = 0;
+#ifdef MOTIF
+ XtSetArg(arg[argcnt], XmNorientation, XmHORIZONTAL); argcnt++;
+ hw->html.hbar = XtCreateWidget("Hbar", xmScrollBarWidgetClass,
+ (Widget)hw, arg, argcnt);
+#else
+ XtSetArg(arg[argcnt], XtNorientation, XtorientHorizontal);
+ argcnt++;
+ hw->html.hbar = XtCreateWidget("Hbar", scrollbarWidgetClass,
+ (Widget)hw, arg, argcnt);
+#endif
+ XtManageChild(hw->html.hbar);
+ }
+
+ /*
+ * Add callbacks to catch scrollbar changes
+ */
+#ifdef MOTIF
+ XtAddCallback(hw->html.hbar, XmNvalueChangedCallback,
+ (XtCallbackProc)ScrollMove, (caddr_t)hw);
+ XtAddCallback(hw->html.hbar, XmNdragCallback,
+ (XtCallbackProc)ScrollMove, (caddr_t)hw);
+#else
+ XtAddCallback(hw->html.hbar, XtNjumpProc,
+ (XtCallbackProc)JumpMove, (caddr_t)hw);
+ XtAddCallback(hw->html.hbar, XtNscrollProc,
+ (XtCallbackProc)ScrollMove, (caddr_t)hw);
+#endif
+}
+
+
+/*
+ * Return the width of the vertical scrollbar
+ */
+static Dimension
+#ifdef _NO_PROTO
+VbarWidth (hw)
+ HTMLWidget hw ;
+#else
+VbarWidth(
+ HTMLWidget hw)
+#endif
+{
+ Arg arg[4];
+ Cardinal argcnt;
+ Dimension width;
+
+ width = 0;
+ if (hw->html.vbar != NULL)
+ {
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XxNwidth, &width); argcnt++;
+ XtGetValues(hw->html.vbar, arg, argcnt);
+ }
+
+ return(width);
+}
+
+
+/*
+ * Return the height of the horizontal scrollbar
+ */
+static Dimension
+#ifdef _NO_PROTO
+HbarHeight (hw)
+ HTMLWidget hw ;
+#else
+HbarHeight(
+ HTMLWidget hw)
+#endif
+{
+ Arg arg[4];
+ Cardinal argcnt;
+ Dimension height;
+
+ height = 0;
+ if (hw->html.hbar != NULL)
+ {
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XxNheight, &height); argcnt++;
+ XtGetValues(hw->html.hbar, arg, argcnt);
+ }
+
+ return(height);
+}
+
+
+/*
+ * Resize and set the min and max values of the scrollbars. Position viewing
+ * area based on scrollbar locations.
+ */
+static void
+#ifdef _NO_PROTO
+ConfigScrollBars (hw)
+ HTMLWidget hw ;
+#else
+ConfigScrollBars(
+ HTMLWidget hw)
+#endif
+{
+#ifdef MOTIF
+ Arg arg[20];
+ Cardinal argcnt;
+#endif
+ int vx, vy;
+
+ /*
+ * Move and size the viewing area
+ */
+#ifdef MOTIF
+ vx = hw->manager.shadow_thickness;
+ vy = hw->manager.shadow_thickness;
+#else
+ vx = vy = 0;
+#endif
+ if ((hw->html.use_vbar == True)&&(hw->html.vbar_right == False))
+ {
+ vx += VbarWidth(hw);
+ }
+ if ((hw->html.use_hbar == True)&&(hw->html.hbar_top == True))
+ {
+ vy += HbarHeight(hw);
+ }
+ XtMoveWidget(hw->html.view, vx, vy);
+ XtResizeWidget(hw->html.view, hw->html.view_width, hw->html.view_height,
+ hw->html.view->core.border_width);
+
+ /*
+ * Set up vertical scrollbar
+ */
+ if (hw->html.use_vbar == True)
+ {
+ int maxv;
+ int ss;
+
+ /*
+ * Size the vertical scrollbar to the height of
+ * the viewing area
+ */
+ XtResizeWidget(hw->html.vbar, hw->html.vbar->core.width,
+ hw->html.view_height + (2 *
+#ifdef MOTIF
+ hw->manager.shadow_thickness
+#else
+ 0
+#endif
+ ),
+ hw->html.vbar->core.border_width);
+
+ /*
+ * Set the slider size to be the percentage of the
+ * viewing area that the viewing area is of the
+ * document area. Or set it to 1 if that isn't possible.
+ */
+ if (hw->html.doc_height == 0)
+ {
+ ss = 1;
+ }
+ else
+ {
+#ifdef DEBUG
+fprintf (stderr, "view_height %d, doc_height %d\n",
+hw->html.view_height, hw->html.doc_height);
+#endif
+#ifdef NOT_RIGHT
+ /* Eric -- your previous equation wasn't doing it.
+ This isn't either... */
+ ss =
+ (int)((float)hw->html.view_height *
+ ((float)hw->html.view_height /
+ (float)(hw->html.doc_height - (int)hw->html.view_height)));
+ if (ss > hw->html.view_height)
+ {
+ ss = hw->html.view_height;
+ }
+#endif
+ /* Added by marca: this produces results *very* close (~1 pixel)
+ to the original scrolled window behavior. */
+ ss = hw->html.view_height;
+ }
+ if (ss < 1)
+ {
+ ss = 1;
+ }
+#ifdef DEBUG
+fprintf (stderr, "computed ss to be %d\n", ss);
+#endif
+
+ /*
+ * If resizing of the document has made scroll_y
+ * greater than the max, we want to hold it at the max.
+ */
+ maxv = hw->html.doc_height - (int)hw->html.view_height;
+ if (maxv < 0)
+ {
+ maxv = 0;
+ }
+ if (hw->html.scroll_y > maxv)
+ {
+ hw->html.scroll_y = maxv;
+ }
+
+ /*
+ * Prevent the Motif max value and slider size
+ * from going to zero, which is illegal
+ */
+ maxv = maxv + ss;
+ if (maxv < 1)
+ {
+ maxv = 1;
+ }
+
+ /*
+ * Motif will not allow the actual value to be equal to
+ * its max value. Adjust accordingly.
+ * Since we might decrease scroll_y, cap it at zero.
+ */
+ if (hw->html.scroll_y >= maxv)
+ {
+ hw->html.scroll_y = maxv - 1;
+ }
+ if (hw->html.scroll_y < 0)
+ {
+ hw->html.scroll_y = 0;
+ }
+
+#ifdef MOTIF
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNminimum, 0); argcnt++;
+ XtSetArg(arg[argcnt], XmNmaximum, maxv); argcnt++;
+ XtSetArg(arg[argcnt], XmNvalue, hw->html.scroll_y); argcnt++;
+ XtSetArg(arg[argcnt], XmNsliderSize, ss); argcnt++;
+ XtSetArg(arg[argcnt], XmNincrement, DEFAULT_INCREMENT); argcnt++;
+ XtSetArg(arg[argcnt], XmNpageIncrement,
+ hw->html.view_height > DEFAULT_INCREMENT ?
+ hw->html.view_height - DEFAULT_INCREMENT : 1); argcnt++;
+ XtSetValues(hw->html.vbar, arg, argcnt);
+#else
+ setScrollBar(hw->html.vbar,
+ hw->html.scroll_y,
+ hw->html.doc_height,
+ (int)hw->html.view_height);
+#endif /* MOTIF */
+
+#ifdef DEBUG
+XtVaGetValues(hw->html.vbar, XmNsliderSize, &ss, NULL);
+fprintf (stderr, "real slider size %d\n", ss);
+#endif
+ }
+
+ /*
+ * Set up horizontal scrollbar
+ */
+ if (hw->html.use_hbar == True)
+ {
+ int maxv;
+ int ss;
+
+ /*
+ * Size the horizontal scrollbar to the width of
+ * the viewing area
+ */
+ XtResizeWidget(hw->html.hbar,
+ hw->html.view_width + (2 *
+#ifdef MOTIF
+ hw->manager.shadow_thickness
+#else
+ 0
+#endif /* MOTIF */
+ ),
+ hw->html.hbar->core.height,
+ hw->html.hbar->core.border_width);
+
+ /*
+ * Set the slider size to be the percentage of the
+ * viewing area that the viewing area is of the
+ * document area. Or set it to 1 if that isn't possible.
+ */
+ if (hw->html.doc_width == 0)
+ {
+ ss = 1;
+ }
+ else
+ {
+#ifdef NOT_RIGHT
+ ss = hw->html.view_width *
+ hw->html.view_width / hw->html.doc_width;
+ if (ss > hw->html.view_width)
+ {
+ ss = hw->html.view_width;
+ }
+#endif
+ /* Added by marca: this produces results *very* close (~1 pixel)
+ to the original scrolled window behavior. */
+ ss = hw->html.view_width;
+ }
+ if (ss < 1)
+ {
+ ss = 1;
+ }
+
+ /*
+ * If resizing of the document has made scroll_x
+ * greater than the max, we want to hold it at the max.
+ */
+ maxv = hw->html.doc_width - (int)hw->html.view_width;
+ if (maxv < 0)
+ {
+ maxv = 0;
+ }
+ if (hw->html.scroll_x > maxv)
+ {
+ hw->html.scroll_x = maxv;
+ }
+
+ /*
+ * Prevent the Motif max value and slider size
+ * from going to zero, which is illegal
+ */
+ maxv = maxv + ss;
+ if (maxv < 1)
+ {
+ maxv = 1;
+ }
+
+ /*
+ * Motif will not allow the actual value to be equal to
+ * its max value. Adjust accordingly.
+ * Since we might decrease scroll_x, cap it at zero.
+ */
+ if (hw->html.scroll_x >= maxv)
+ {
+ hw->html.scroll_x = maxv - 1;
+ }
+ if (hw->html.scroll_x < 0)
+ {
+ hw->html.scroll_x = 0;
+ }
+
+#ifdef MOTIF
+ argcnt = 0;
+ XtSetArg(arg[argcnt], XmNminimum, 0); argcnt++;
+ XtSetArg(arg[argcnt], XmNmaximum, maxv); argcnt++;
+ XtSetArg(arg[argcnt], XmNvalue, hw->html.scroll_x); argcnt++;
+ XtSetArg(arg[argcnt], XmNsliderSize, ss); argcnt++;
+ XtSetArg(arg[argcnt], XmNincrement, DEFAULT_INCREMENT); argcnt++;
+ XtSetArg(arg[argcnt], XmNpageIncrement,
+ hw->html.view_width > DEFAULT_INCREMENT ?
+ hw->html.view_width - DEFAULT_INCREMENT : 1); argcnt++;
+ XtSetValues(hw->html.hbar, arg, argcnt);
+#else
+ setScrollBar(hw->html.hbar,
+ hw->html.scroll_x,
+ hw->html.doc_width,
+ (int)hw->html.view_width);
+#endif /* MOTIF */
+ }
+
+#ifdef DEBUG
+ {
+ int ss;
+XtVaGetValues(hw->html.vbar, XmNsliderSize, &ss, NULL);
+fprintf (stderr, "real slider size %d\n", ss);
+ }
+#endif
+}
+
+
+/*
+ * Reformat the window and scrollbars.
+ * May be called because of a changed document, or because of a changed
+ * window size.
+ */
+static void
+#ifdef _NO_PROTO
+ReformatWindow (hw)
+ HTMLWidget hw ;
+#else
+ReformatWindow(
+ HTMLWidget hw)
+#endif
+{
+ int temp;
+ int new_width;
+ Dimension swidth, sheight;
+ Dimension st;
+
+ /*
+ * Find the current scrollbar sizes, and shadow thickness and format
+ * the document to the current window width
+ * (assume a vertical scrollbar)
+ */
+ swidth = VbarWidth(hw);
+ sheight = HbarHeight(hw);
+#ifdef MOTIF
+ st = hw->manager.shadow_thickness;
+#else
+ st = 0;
+#endif /* MOTIF */
+ if (hw->core.width <= swidth)
+ {
+ hw->core.width = swidth + 10;
+ }
+ new_width = hw->core.width - swidth - (2 * st);
+ temp = FormatAll(hw, &new_width);
+
+ /*
+ * If we need the vertical scrollbar, place and manage it,
+ * and store the current viewing area width.
+ */
+ if (temp > hw->core.height - sheight)
+ {
+ hw->html.use_vbar = True;
+ if (hw->html.vbar_right == True)
+ {
+ XtMoveWidget(hw->html.vbar,
+ (hw->core.width - swidth), 0);
+ }
+ else
+ {
+ XtMoveWidget(hw->html.vbar, 0, 0);
+ }
+ XtManageChild(hw->html.vbar);
+ hw->html.view_width = hw->core.width - swidth - (2 * st);
+ }
+ /*
+ * Else we were wrong to assume a vertical scrollbar.
+ * Remove it, and reformat the document to the wider width.
+ * Save the as the current viewing are width.
+ */
+ else
+ {
+ hw->html.use_vbar = False;
+ XtUnmanageChild(hw->html.vbar);
+ hw->html.scroll_y = 0;
+ new_width = hw->core.width - (2 * st);
+ temp = FormatAll(hw, &new_width);
+ hw->html.view_width = hw->core.width - (2 * st);
+ /* fake out later horizontal scrollbars */
+ swidth = 0;
+ }
+
+ /*
+ * Calculate the actual max width and height of the complete
+ * formatted document.
+ * The max width may exceed the preformatted width due to special
+ * factors in the formatting of the widget.
+ * Use the max of the 2 here, but leave max_pre_width unchanged
+ * for future formatting calls.
+ */
+ /*
+ * new_width includes the margins, and hw->html.max_pre_width
+ * does not, fix that here.
+ */
+ new_width = new_width - (2 * hw->html.margin_width);
+ if (hw->html.max_pre_width > new_width)
+ {
+ new_width = hw->html.max_pre_width;
+ }
+ /*
+ * If the maximum width derives from a formatted, as opposed to
+ * unformatted piece of text, allow a 20% of margin width slop
+ * over into the margin to cover up a minor glick with terminaing
+ * punctuation after anchors at the end of the line.
+ */
+ else
+ {
+ new_width = new_width - (20 * hw->html.margin_width / 100);
+ }
+
+ hw->html.doc_height = temp;
+ hw->html.doc_width = new_width + (2 * hw->html.margin_width);
+ if (hw->html.view_width > hw->html.doc_width)
+ {
+ hw->html.doc_width = hw->html.view_width;
+ }
+
+ /*
+ * If we need a horizontal scrollbar
+ * Place it and manage it. Save the height of the current
+ * viewing area.
+ */
+ if (hw->html.doc_width > hw->html.view_width)
+ {
+ hw->html.use_hbar = True;
+ if (hw->html.hbar_top == True)
+ {
+ if (hw->html.use_vbar == True)
+ {
+ XtMoveWidget(hw->html.vbar,
+ hw->html.vbar->core.x, sheight);
+ }
+
+ if (hw->html.vbar_right == True)
+ {
+ XtMoveWidget(hw->html.hbar, 0, 0);
+ }
+ else
+ {
+ XtMoveWidget(hw->html.hbar, swidth, 0);
+ }
+ }
+ else
+ {
+ if (hw->html.vbar_right == True)
+ {
+ XtMoveWidget(hw->html.hbar, 0,
+ (hw->core.height - sheight));
+ }
+ else
+ {
+ XtMoveWidget(hw->html.hbar, swidth,
+ (hw->core.height - sheight));
+ }
+ }
+ XtManageChild(hw->html.hbar);
+ hw->html.view_height = hw->core.height - sheight - (2 * st);
+ }
+ /*
+ * Else we don't need a horizontal scrollbar.
+ * Remove it and save the current viewing area height.
+ */
+ else
+ {
+ hw->html.use_hbar = False;
+ XtUnmanageChild(hw->html.hbar);
+ hw->html.scroll_x = 0;
+ hw->html.view_height = hw->core.height - (2 * st);
+ }
+
+ /*
+ * Configure the scrollbar min, max, and slider sizes
+ */
+#ifdef DEBUG
+fprintf (stderr, "calling in ReformatWindow\n");
+#endif
+ ConfigScrollBars(hw);
+}
+
+
+/*
+ * We're a happy widget. We let any child move or resize themselves
+ * however they want, we don't care.
+ */
+static XtGeometryResult
+#ifdef _NO_PROTO
+GeometryManager (w, request, reply)
+ Widget w;
+ XtWidgetGeometry * request;
+ XtWidgetGeometry * reply;
+#else
+GeometryManager (
+ Widget w,
+ XtWidgetGeometry * request,
+ XtWidgetGeometry * reply)
+#endif
+{
+ reply->x = request->x;
+ reply->y = request->y;
+ reply->width = request->width;
+ reply->height = request->height;
+ reply->border_width = request->border_width;
+ reply->request_mode = request->request_mode;
+ return (XtGeometryYes);
+}
+
+
+/*
+ * Initialize is called when the widget is first initialized.
+ * Check to see that all the starting resources are valid.
+ */
+static void
+#ifdef _NO_PROTO
+Initialize (request, new)
+ HTMLWidget request ;
+ HTMLWidget new ;
+#else
+Initialize(
+ HTMLWidget request,
+ HTMLWidget new)
+#endif
+{
+ /*
+ * Make sure height and width are not zero.
+ */
+ if (new->core.width == 0)
+ {
+ new->core.width = new->html.margin_width << 1 ;
+ }
+ if (new->core.width == 0)
+ {
+ new->core.width = 10 ;
+ }
+ if (new->core.height == 0)
+ {
+ new->core.height = new->html.margin_height << 1 ;
+ }
+ if (new->core.height == 0)
+ {
+ new->core.height = 10 ;
+ }
+
+ /*
+ * Make sure the underline numbers are within bounds.
+ */
+ if (new->html.num_anchor_underlines < 0)
+ {
+ new->html.num_anchor_underlines = 0;
+ }
+ if (new->html.num_anchor_underlines > MAX_UNDERLINES)
+ {
+ new->html.num_anchor_underlines = MAX_UNDERLINES;
+ }
+ if (new->html.num_visitedAnchor_underlines < 0)
+ {
+ new->html.num_visitedAnchor_underlines = 0;
+ }
+ if (new->html.num_visitedAnchor_underlines > MAX_UNDERLINES)
+ {
+ new->html.num_visitedAnchor_underlines = MAX_UNDERLINES;
+ }
+
+ /*
+ * Parse the raw text with the HTML parser. And set the formatted
+ * element list to NULL.
+ */
+ new->html.html_objects = HTMLParse(NULL, request->html.raw_text);
+ CallLinkCallbacks(new);
+ new->html.html_header_objects =
+ HTMLParse(NULL, request->html.header_text);
+ new->html.html_footer_objects =
+ HTMLParse(NULL, request->html.footer_text);
+ new->html.formatted_elements = NULL;
+ new->html.my_visited_hrefs = NULL;
+ new->html.my_delayed_images = NULL;
+ new->html.widget_list = NULL;
+ new->html.form_list = NULL;
+
+ /*
+ * Blank document
+ */
+ new->html.line_array = NULL;
+ new->html.line_count = 0;
+
+ /*
+ * Find the max width of a preformatted
+ * line in this document.
+ */
+ new->html.max_pre_width = DocumentWidth(new, new->html.html_objects);
+
+ /*
+ * Create the scrollbars.
+ * Find their dimensions and then decide which scrollbars you
+ * will need, and what the dimensions of the viewing area are.
+ * Start assuming a vertical scrollbar and a horizontal one.
+ * The remove vertical if short enough, and remove horizontal
+ * if narrow enough.
+ */
+ CreateScrollbars(new);
+ new->html.scroll_x = 0;
+ new->html.scroll_y = 0;
+ ReformatWindow(new);
+
+ /*
+ * Initialize private widget resources
+ */
+ new->html.drawGC = NULL;
+ new->html.select_start = NULL;
+ new->html.select_end = NULL;
+ new->html.sel_start_pos = 0;
+ new->html.sel_end_pos = 0;
+ new->html.new_start = NULL;
+ new->html.new_end = NULL;
+ new->html.new_start_pos = 0;
+ new->html.new_end_pos = 0;
+ new->html.active_anchor = NULL;
+ new->html.press_x = 0;
+ new->html.press_y = 0;
+
+ new->html.cached_tracked_ele = NULL;
+
+ /* Initialize cursor used when pointer is inside anchor.
+ if (in_anchor_cursor == (Cursor)NULL) */
+ in_anchor_cursor = XCreateFontCursor (XtDisplay (new), XC_hand2);
+
+ return;
+}
+
+/*
+ * Realize is called when the widget is realized to create its window.
+ * We call the Realize method of our superclass and then create the drawGC
+ * to be used by the HTML widget. (This was added at NOAO, the NCSA
+ * version does not use a custom Realize method, and the drawGC is not
+ * created until the first Expose event occurs. This causes the widget to
+ * crash if a drawing routine is called before the application becomes idle
+ * and processes the queued input from the display server.)
+ */
+static void
+#ifdef _NO_PROTO
+Realize (hw, valueMask, attributes)
+ HTMLWidget hw ;
+ Mask *valueMask ;
+ XSetWindowAttributes *attributes ;
+#else
+Realize (
+ HTMLWidget hw ,
+ Mask *valueMask ,
+ XSetWindowAttributes *attributes )
+#endif
+{
+ unsigned long valuemask;
+ XGCValues values;
+
+ /* Call the Realize method of the superclass to create the window. */
+ (*htmlWidgetClass->core_class.superclass->core_class.realize)
+ ((Widget)hw, valueMask, attributes);
+
+ /* Create the drawGC for the HTML window (copied from Expose). */
+ values.function = GXcopy;
+ values.plane_mask = AllPlanes;
+/*
+ * Without motif we use our own foreground resource instead of
+ * using the manager's
+ */
+#ifdef MOTIF
+ values.foreground = hw->manager.foreground;
+#else
+ values.foreground = hw->html.foreground;
+#endif /* MOTIF */
+ values.background = hw->core.background_pixel;
+
+ valuemask = GCFunction|GCPlaneMask|GCForeground|GCBackground;
+
+ hw->html.drawGC = XCreateGC(XtDisplay(hw), XtWindow(hw),
+ valuemask, &values);
+}
+
+
+#ifdef DEBUG
+void
+DebugHook(x, y, width, height)
+ int x, y, width, height;
+{
+fprintf(stderr, "Redrawing (%d,%d) %dx%d\n", x, y, width, height);
+}
+#endif
+
+
+/*
+ * This is called by redisplay. It is passed a rectangle
+ * in the viewing area, and it redisplays that portion of the
+ * underlying document area.
+ */
+static void
+#ifdef _NO_PROTO
+ViewRedisplay (hw, x, y, width, height)
+ HTMLWidget hw;
+ int x, y;
+ int width, height;
+#else
+ViewRedisplay(
+ HTMLWidget hw,
+ int x,
+ int y,
+ int width,
+ int height)
+#endif
+{
+ int sx, sy;
+ int doc_x, doc_y;
+ int i, start, end, guess;
+
+ /*
+ * Use scrollbar values to map from view space to document space.
+ */
+ sx = sy = 0;
+ if (hw->html.use_vbar == True)
+ {
+ sy += hw->html.scroll_y;
+ }
+ if (hw->html.use_hbar == True)
+ {
+ sx += hw->html.scroll_x;
+ }
+
+ doc_x = x + sx;
+ doc_y = y + sy;
+
+ /*
+ * Find the lines that overlap the exposed area.
+ */
+ start = 0;
+ end = hw->html.line_count - 1;
+
+ /*
+ * Heuristic to speed up redraws by guessing at the starting line.
+ */
+ guess = doc_y / (hw->html.font->max_bounds.ascent +
+ hw->html.font->max_bounds.descent);
+ if (guess > end)
+ {
+ guess = end;
+ }
+ while (guess > 0)
+ {
+ if ((hw->html.line_array[guess] != NULL)&&
+ (hw->html.line_array[guess]->y < doc_y))
+ {
+ break;
+ }
+ guess--;
+ }
+ if (guess < start)
+ {
+ guess = start;
+ }
+
+ for (i=guess; i<hw->html.line_count; i++)
+ {
+ if (hw->html.line_array[i] == NULL)
+ {
+ continue;
+ }
+
+ if (hw->html.line_array[i]->y < doc_y)
+ {
+ start = i;
+ }
+ if (hw->html.line_array[i]->y > (doc_y + height))
+ {
+ end = i;
+ break;
+ }
+ }
+
+ /*
+ * If we have a GC draw the lines that overlap the exposed area.
+ */
+ if (hw->html.drawGC != NULL)
+ {
+ for (i=start; i<=end; i++)
+ {
+ PlaceLine(hw, i);
+ }
+#ifdef EXTRA_FLUSH
+ XFlush(XtDisplay(hw));
+#endif
+ }
+}
+
+
+static void
+#ifdef _NO_PROTO
+ViewClearAndRefresh (hw)
+ HTMLWidget hw;
+#else
+ViewClearAndRefresh(
+ HTMLWidget hw)
+#endif
+{
+ /*
+ * Only refresh if we have a window already.
+ * (if we have a GC we have a window)
+ */
+ if (hw->html.drawGC != NULL)
+ {
+ XClearArea(XtDisplay(hw->html.view), XtWindow(hw->html.view),
+ 0, 0, 0, 0, False);
+ ViewRedisplay(hw, 0, 0,
+ hw->html.view_width, hw->html.view_height);
+ /*
+ * This is a fake deal to make an Expose event tocall Redisplay
+ * to redraw the shadow around the view area
+ */
+ XClearArea(XtDisplay(hw), XtWindow(hw),
+ 0, 0, 1, 1, True);
+ }
+}
+
+
+/*
+ * The Redisplay function is what you do with an expose event.
+ * Right now we call user callbacks, and then call the CompositeWidget's
+ * Redisplay routine.
+ */
+static void
+#ifdef _NO_PROTO
+Redisplay (hw, event, region)
+ HTMLWidget hw;
+ XEvent * event;
+ Region region;
+#else
+Redisplay(
+ HTMLWidget hw,
+ XEvent * event,
+ Region region)
+#endif
+{
+ XExposeEvent *ExEvent = (XExposeEvent *)event;
+ int dx, dy;
+
+#ifdef MOTIF
+ /*
+ * find out where the shadow is based on scrollbars
+ */
+
+ Dimension st = hw->manager.shadow_thickness;
+#endif /* MOTIF */
+
+ dx = dy = 0;
+ if ((hw->html.use_vbar == True)&&(hw->html.vbar_right == False))
+ {
+ dx += VbarWidth(hw);
+ }
+ if ((hw->html.use_hbar == True)&&(hw->html.hbar_top == True))
+ {
+ dy += HbarHeight(hw);
+ }
+
+#ifdef MOTIF
+ /*
+ * Redraw the shadow around the scrolling area which may have been
+ * messed up.
+ */
+ _XmDrawShadow(XtDisplay(hw), XtWindow(hw),
+ hw->manager.bottom_shadow_GC, hw->manager.top_shadow_GC,
+ hw->manager.shadow_thickness, dx, dy,
+ hw->html.view_width + (2 * st),hw->html.view_height + (2 * st));
+#endif /* MOTIF */
+
+#ifdef MOTIF
+#ifdef MOTIF1_2
+ _XmRedisplayGadgets ((Widget)hw, (XEvent*)event, region);
+#else
+ _XmRedisplayGadgets ((CompositeWidget)hw, (XExposeEvent*)event, region);
+#endif /* MOTIF1_2 */
+#endif /* MOTIF */
+
+ return;
+}
+
+
+/*
+ * Resize is called when the widget changes size.
+ * Mostly any resize causes a reformat, except for the special case
+ * where the width doesn't change, and the height doesn't change
+ * enought to affect the vertical scrollbar.
+ * It is too complex to guess exactly what needs to be redrawn, so refresh the
+ * whole window on any resize.
+ */
+static void
+#ifdef _NO_PROTO
+Resize (hw)
+ HTMLWidget hw;
+#else
+Resize(
+ HTMLWidget hw)
+#endif
+{
+ int tempw;
+ Dimension swidth, sheight;
+ Dimension st;
+
+ /*
+ * Find the new widht of the viewing area.
+ */
+ swidth = VbarWidth(hw);
+ sheight = HbarHeight(hw);
+#ifdef MOTIF
+ st = hw->manager.shadow_thickness;
+#else
+ st = 0;
+#endif /* MOTIF */
+ if (hw->core.width <= swidth)
+ {
+ hw->core.width = swidth + 10 ;
+ }
+
+ if (hw->html.use_vbar == True)
+ {
+ tempw = hw->core.width - swidth - (2 * st);
+ }
+ else
+ {
+ tempw = hw->core.width - (2 * st);
+ /* fool positioning of horz scrollbar later */
+ swidth = 0;
+ }
+
+ /*
+ * Special case where we don't have to reformat to a new width.
+ * The width has not changed, and the height has not changed
+ * significantly to change the state of the vertical scrollbar.
+ */
+ if ((tempw == hw->html.view_width)&&
+ (((hw->html.use_vbar == True)&&
+ ((hw->core.height - sheight - (2 * st)) < hw->html.doc_height))||
+ ((hw->html.use_vbar == False)&&
+ ((hw->core.height - sheight - (2 * st)) >= hw->html.doc_height))))
+ {
+ /*
+ * Super special case where the size of the window hasn't
+ * changed at ALL!
+ */
+ if (((hw->html.use_hbar == True)&&(hw->html.view_height ==
+ (hw->core.height - sheight - (2 * st))))||
+ ((hw->html.use_hbar == False)&&(hw->html.view_height ==
+ (hw->core.height - (2 * st)))))
+ {
+ return;
+ }
+
+ if (hw->html.use_hbar == True)
+ {
+ if (hw->html.hbar_top == True)
+ {
+ if (hw->html.vbar_right == True)
+ {
+ XtMoveWidget(hw->html.hbar, 0, 0);
+ }
+ else
+ {
+ XtMoveWidget(hw->html.hbar, swidth, 0);
+ }
+ }
+ else
+ {
+ if (hw->html.vbar_right == True)
+ {
+ XtMoveWidget(hw->html.hbar, 0,
+ (hw->core.height - sheight));
+ }
+ else
+ {
+ XtMoveWidget(hw->html.hbar, swidth,
+ (hw->core.height - sheight));
+ }
+ }
+ hw->html.view_height = hw->core.height - sheight -
+ (2 * st);
+ }
+ else
+ {
+ hw->html.view_height = hw->core.height - (2 * st);
+ }
+#ifdef DEBUG
+fprintf (stderr, "calling in Resize\n");
+#endif
+ ConfigScrollBars(hw);
+ ScrollWidgets(hw);
+ ViewClearAndRefresh(hw);
+ }
+ /*
+ * Otherwise we have to do a full reformat on every resize.
+ */
+ else
+ {
+ ReformatWindow(hw);
+ ScrollWidgets(hw);
+ ViewClearAndRefresh(hw);
+ }
+
+#ifdef DEBUG
+ {
+ int ss;
+XtVaGetValues(hw->html.vbar, XmNsliderSize, &ss, NULL);
+fprintf (stderr, "leaving; slider size %d\n", ss);
+ }
+#endif
+
+ return;
+}
+
+
+/*
+ * Find the complete text for this the anchor that aptr is a part of
+ * and set it into the selection.
+ */
+static void
+FindSelectAnchor(hw, aptr)
+ HTMLWidget hw;
+ struct ele_rec *aptr;
+{
+ struct ele_rec *eptr;
+
+ eptr = aptr;
+ while ((eptr->prev != NULL)&&
+ (eptr->prev->anchorHRef != NULL)&&
+ (strcmp(eptr->prev->anchorHRef, eptr->anchorHRef) == 0))
+ {
+ eptr = eptr->prev;
+ }
+ hw->html.select_start = eptr;
+ hw->html.sel_start_pos = 0;
+
+ eptr = aptr;
+ while ((eptr->next != NULL)&&
+ (eptr->next->anchorHRef != NULL)&&
+ (strcmp(eptr->next->anchorHRef, eptr->anchorHRef) == 0))
+ {
+ eptr = eptr->next;
+ }
+ hw->html.select_end = eptr;
+ hw->html.sel_end_pos = eptr->edata_len - 2;
+}
+
+
+/*
+ * Set as active all elements in the widget that are part of the anchor
+ * in the widget's start ptr.
+ */
+static void
+SetAnchor(hw)
+ HTMLWidget hw;
+{
+ struct ele_rec *eptr;
+ struct ele_rec *start;
+ struct ele_rec *end;
+ unsigned long fg, bg;
+ unsigned long old_fg, old_bg;
+
+ eptr = hw->html.active_anchor;
+ if ((eptr == NULL)||(eptr->anchorHRef == NULL))
+ {
+ return;
+ }
+ fg = hw->html.activeAnchor_fg;
+ bg = hw->html.activeAnchor_bg;
+
+ FindSelectAnchor(hw, eptr);
+
+ start = hw->html.select_start;
+ end = hw->html.select_end;
+
+ eptr = start;
+ while ((eptr != NULL)&&(eptr != end))
+ {
+ if (eptr->type == E_TEXT)
+ {
+ old_fg = eptr->fg;
+ old_bg = eptr->bg;
+ eptr->fg = fg;
+ eptr->bg = bg;
+ TextRefresh(hw, eptr,
+ 0, (eptr->edata_len - 2));
+ eptr->fg = old_fg;
+ eptr->bg = old_bg;
+ }
+ else if (eptr->type == E_IMAGE)
+ {
+ old_fg = eptr->fg;
+ old_bg = eptr->bg;
+ eptr->fg = fg;
+ eptr->bg = bg;
+ ImageRefresh(hw, eptr);
+ eptr->fg = old_fg;
+ eptr->bg = old_bg;
+ }
+ /*
+ * Linefeeds in anchor spanning multiple lines should NOT
+ * be highlighted!
+ else if (eptr->type == E_LINEFEED)
+ {
+ old_fg = eptr->fg;
+ old_bg = eptr->bg;
+ eptr->fg = fg;
+ eptr->bg = bg;
+ LinefeedRefresh(hw, eptr);
+ eptr->fg = old_fg;
+ eptr->bg = old_bg;
+ }
+ */
+ eptr = eptr->next;
+ }
+ if (eptr != NULL)
+ {
+ if (eptr->type == E_TEXT)
+ {
+ old_fg = eptr->fg;
+ old_bg = eptr->bg;
+ eptr->fg = fg;
+ eptr->bg = bg;
+ TextRefresh(hw, eptr,
+ 0, (eptr->edata_len - 2));
+ eptr->fg = old_fg;
+ eptr->bg = old_bg;
+ }
+ else if (eptr->type == E_IMAGE)
+ {
+ old_fg = eptr->fg;
+ old_bg = eptr->bg;
+ eptr->fg = fg;
+ eptr->bg = bg;
+ ImageRefresh(hw, eptr);
+ eptr->fg = old_fg;
+ eptr->bg = old_bg;
+ }
+ /*
+ * Linefeeds in anchor spanning multiple lines should NOT
+ * be highlighted!
+ else if (eptr->type == E_LINEFEED)
+ {
+ old_fg = eptr->fg;
+ old_bg = eptr->bg;
+ eptr->fg = fg;
+ eptr->bg = bg;
+ LinefeedRefresh(hw, eptr);
+ eptr->fg = old_fg;
+ eptr->bg = old_bg;
+ }
+ */
+ }
+}
+
+
+/*
+ * Draw selection for all elements in the widget
+ * from start to end.
+ */
+static void
+DrawSelection(hw, start, end, start_pos, end_pos)
+ HTMLWidget hw;
+ struct ele_rec *start;
+ struct ele_rec *end;
+ int start_pos, end_pos;
+{
+ struct ele_rec *eptr;
+ int epos;
+
+ if ((start == NULL)||(end == NULL))
+ {
+ return;
+ }
+
+ /*
+ * Keep positions within bounds (allows us to be sloppy elsewhere)
+ */
+ if (start_pos < 0)
+ {
+ start_pos = 0;
+ }
+ if (start_pos >= start->edata_len - 1)
+ {
+ start_pos = start->edata_len - 2;
+ }
+ if (end_pos < 0)
+ {
+ end_pos = 0;
+ }
+ if (end_pos >= end->edata_len - 1)
+ {
+ end_pos = end->edata_len - 2;
+ }
+
+ if (SwapElements(start, end, start_pos, end_pos))
+ {
+ eptr = start;
+ start = end;
+ end = eptr;
+ epos = start_pos;
+ start_pos = end_pos;
+ end_pos = epos;
+ }
+
+ eptr = start;
+ while ((eptr != NULL)&&(eptr != end))
+ {
+ int p1, p2;
+
+ if (eptr == start)
+ {
+ p1 = start_pos;
+ }
+ else
+ {
+ p1 = 0;
+ }
+ p2 = eptr->edata_len - 2;
+
+ if (eptr->type == E_TEXT)
+ {
+ eptr->selected = True;
+ eptr->start_pos = p1;
+ eptr->end_pos = p2;
+ TextRefresh(hw, eptr, p1, p2);
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ eptr->selected = True;
+ LinefeedRefresh(hw, eptr);
+ }
+ eptr = eptr->next;
+ }
+ if (eptr != NULL)
+ {
+ int p1, p2;
+
+ if (eptr == start)
+ {
+ p1 = start_pos;
+ }
+ else
+ {
+ p1 = 0;
+ }
+
+ if (eptr == end)
+ {
+ p2 = end_pos;
+ }
+ else
+ {
+ p2 = eptr->edata_len - 2;
+ }
+
+ if (eptr->type == E_TEXT)
+ {
+ eptr->selected = True;
+ eptr->start_pos = p1;
+ eptr->end_pos = p2;
+ TextRefresh(hw, eptr, p1, p2);
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ eptr->selected = True;
+ LinefeedRefresh(hw, eptr);
+ }
+ }
+}
+
+
+/*
+ * Set selection for all elements in the widget's
+ * start to end list.
+ */
+static void
+SetSelection(hw)
+ HTMLWidget hw;
+{
+ struct ele_rec *start;
+ struct ele_rec *end;
+ int start_pos, end_pos;
+
+ start = hw->html.select_start;
+ end = hw->html.select_end;
+ start_pos = hw->html.sel_start_pos;
+ end_pos = hw->html.sel_end_pos;
+ DrawSelection(hw, start, end, start_pos, end_pos);
+}
+
+
+/*
+ * Erase the selection from start to end
+ */
+static void
+EraseSelection(hw, start, end, start_pos, end_pos)
+ HTMLWidget hw;
+ struct ele_rec *start;
+ struct ele_rec *end;
+ int start_pos, end_pos;
+{
+ struct ele_rec *eptr;
+ int epos;
+
+ if ((start == NULL)||(end == NULL))
+ {
+ return;
+ }
+
+ /*
+ * Keep positoins within bounds (allows us to be sloppy elsewhere)
+ */
+ if (start_pos < 0)
+ {
+ start_pos = 0;
+ }
+ if (start_pos >= start->edata_len - 1)
+ {
+ start_pos = start->edata_len - 2;
+ }
+ if (end_pos < 0)
+ {
+ end_pos = 0;
+ }
+ if (end_pos >= end->edata_len - 1)
+ {
+ end_pos = end->edata_len - 2;
+ }
+
+ if (SwapElements(start, end, start_pos, end_pos))
+ {
+ eptr = start;
+ start = end;
+ end = eptr;
+ epos = start_pos;
+ start_pos = end_pos;
+ end_pos = epos;
+ }
+
+ eptr = start;
+ while ((eptr != NULL)&&(eptr != end))
+ {
+ int p1, p2;
+
+ if (eptr == start)
+ {
+ p1 = start_pos;
+ }
+ else
+ {
+ p1 = 0;
+ }
+ p2 = eptr->edata_len - 2;
+
+ if (eptr->type == E_TEXT)
+ {
+ eptr->selected = False;
+ TextRefresh(hw, eptr, p1, p2);
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ eptr->selected = False;
+ LinefeedRefresh(hw, eptr);
+ }
+ eptr = eptr->next;
+ }
+ if (eptr != NULL)
+ {
+ int p1, p2;
+
+ if (eptr == start)
+ {
+ p1 = start_pos;
+ }
+ else
+ {
+ p1 = 0;
+ }
+
+ if (eptr == end)
+ {
+ p2 = end_pos;
+ }
+ else
+ {
+ p2 = eptr->edata_len - 2;
+ }
+
+ if (eptr->type == E_TEXT)
+ {
+ eptr->selected = False;
+ TextRefresh(hw, eptr, p1, p2);
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ eptr->selected = False;
+ LinefeedRefresh(hw, eptr);
+ }
+ }
+}
+
+
+/*
+ * Clear the current selection (if there is one)
+ */
+static void
+ClearSelection(hw)
+ HTMLWidget hw;
+{
+ struct ele_rec *start;
+ struct ele_rec *end;
+ int start_pos, end_pos;
+
+ start = hw->html.select_start;
+ end = hw->html.select_end;
+ start_pos = hw->html.sel_start_pos;
+ end_pos = hw->html.sel_end_pos;
+ EraseSelection(hw, start, end, start_pos, end_pos);
+
+ if ((start == NULL)||(end == NULL))
+ {
+ hw->html.select_start = NULL;
+ hw->html.select_end = NULL;
+ hw->html.sel_start_pos = 0;
+ hw->html.sel_end_pos = 0;
+ hw->html.active_anchor = NULL;
+ return;
+ }
+
+ hw->html.select_start = NULL;
+ hw->html.select_end = NULL;
+ hw->html.sel_start_pos = 0;
+ hw->html.sel_end_pos = 0;
+ hw->html.active_anchor = NULL;
+}
+
+
+/*
+ * clear from active all elements in the widget that are part of the anchor.
+ * (These have already been previously set into the start and end of the
+ * selection.
+ */
+static void
+UnsetAnchor(hw)
+ HTMLWidget hw;
+{
+ struct ele_rec *eptr;
+
+ /*
+ * Clear any activated images
+ */
+ eptr = hw->html.select_start;
+ while ((eptr != NULL)&&(eptr != hw->html.select_end))
+ {
+ if (eptr->type == E_IMAGE)
+ {
+ ImageRefresh(hw, eptr);
+ }
+ eptr = eptr->next;
+ }
+ if ((eptr != NULL)&&(eptr->type == E_IMAGE))
+ {
+ ImageRefresh(hw, eptr);
+ }
+
+ /*
+ * Clear the activated anchor
+ */
+ ClearSelection(hw);
+}
+
+
+/*
+ * Erase the old selection, and draw the new one in such a way
+ * that advantage is taken of overlap, and there is no obnoxious
+ * flashing.
+ */
+static void
+ChangeSelection(hw, start, end, start_pos, end_pos)
+ HTMLWidget hw;
+ struct ele_rec *start;
+ struct ele_rec *end;
+ int start_pos, end_pos;
+{
+ struct ele_rec *old_start;
+ struct ele_rec *old_end;
+ struct ele_rec *new_start;
+ struct ele_rec *new_end;
+ struct ele_rec *eptr;
+ int epos;
+ int new_start_pos, new_end_pos;
+ int old_start_pos, old_end_pos;
+
+ old_start = hw->html.new_start;
+ old_end = hw->html.new_end;
+ old_start_pos = hw->html.new_start_pos;
+ old_end_pos = hw->html.new_end_pos;
+ new_start = start;
+ new_end = end;
+ new_start_pos = start_pos;
+ new_end_pos = end_pos;
+
+ if ((new_start == NULL)||(new_end == NULL))
+ {
+ return;
+ }
+
+ if ((old_start == NULL)||(old_end == NULL))
+ {
+ DrawSelection(hw, new_start, new_end,
+ new_start_pos, new_end_pos);
+ return;
+ }
+
+ if (SwapElements(old_start, old_end, old_start_pos, old_end_pos))
+ {
+ eptr = old_start;
+ old_start = old_end;
+ old_end = eptr;
+ epos = old_start_pos;
+ old_start_pos = old_end_pos;
+ old_end_pos = epos;
+ }
+
+ if (SwapElements(new_start, new_end, new_start_pos, new_end_pos))
+ {
+ eptr = new_start;
+ new_start = new_end;
+ new_end = eptr;
+ epos = new_start_pos;
+ new_start_pos = new_end_pos;
+ new_end_pos = epos;
+ }
+
+ /*
+ * Deal with all possible intersections of the 2 selection sets.
+ *
+ ********************************************************
+ * * *
+ * |-- * |-- *
+ * old--| * new--| *
+ * |-- * |-- *
+ * * *
+ * |-- * |-- *
+ * new--| * old--| *
+ * |-- * |-- *
+ * * *
+ ********************************************************
+ * * *
+ * |---- * |-- *
+ * old--| * new--| *
+ * | |-- * | *
+ * |-+-- * |-+-- *
+ * | * | |-- *
+ * new--| * old--| *
+ * |-- * |---- *
+ * * *
+ ********************************************************
+ * * *
+ * |--------- * |--------- *
+ * | * | *
+ * | |-- * | |-- *
+ * new--| old--| * old--| new--| *
+ * | |-- * | |-- *
+ * | * | *
+ * |--------- * |--------- *
+ * * *
+ ********************************************************
+ *
+ */
+ if ((ElementLessThan(old_end, new_start, old_end_pos, new_start_pos))||
+ (ElementLessThan(new_end, old_start, new_end_pos, old_start_pos)))
+ {
+ EraseSelection(hw, old_start, old_end,
+ old_start_pos, old_end_pos);
+ DrawSelection(hw, new_start, new_end,
+ new_start_pos, new_end_pos);
+ }
+ else if ((ElementLessThan(old_start, new_start,
+ old_start_pos, new_start_pos))&&
+ (ElementLessThan(old_end, new_end, old_end_pos, new_end_pos)))
+ {
+ if (new_start_pos != 0)
+ {
+ EraseSelection(hw, old_start, new_start,
+ old_start_pos, new_start_pos - 1);
+ }
+ else
+ {
+ EraseSelection(hw, old_start, new_start->prev,
+ old_start_pos, new_start->prev->edata_len - 2);
+ }
+ if (old_end_pos < (old_end->edata_len - 2))
+ {
+ DrawSelection(hw, old_end, new_end,
+ old_end_pos + 1, new_end_pos);
+ }
+ else
+ {
+ DrawSelection(hw, old_end->next, new_end,
+ 0, new_end_pos);
+ }
+ }
+ else if ((ElementLessThan(new_start, old_start,
+ new_start_pos, old_start_pos))&&
+ (ElementLessThan(new_end, old_end, new_end_pos, old_end_pos)))
+ {
+ if (old_start_pos != 0)
+ {
+ DrawSelection(hw, new_start, old_start,
+ new_start_pos, old_start_pos - 1);
+ }
+ else
+ {
+ DrawSelection(hw, new_start, old_start->prev,
+ new_start_pos, old_start->prev->edata_len - 2);
+ }
+ if (new_end_pos < (new_end->edata_len - 2))
+ {
+ EraseSelection(hw, new_end, old_end,
+ new_end_pos + 1, old_end_pos);
+ }
+ else
+ {
+ EraseSelection(hw, new_end->next, old_end,
+ 0, old_end_pos);
+ }
+ }
+ else if ((ElementLessThan(new_start, old_start,
+ new_start_pos, old_start_pos))||
+ (ElementLessThan(old_end, new_end, old_end_pos, new_end_pos)))
+ {
+ if ((new_start != old_start)||(new_start_pos != old_start_pos))
+ {
+ if (old_start_pos != 0)
+ {
+ DrawSelection(hw, new_start, old_start,
+ new_start_pos, old_start_pos - 1);
+ }
+ else
+ {
+ DrawSelection(hw, new_start, old_start->prev,
+ new_start_pos,
+ old_start->prev->edata_len - 2);
+ }
+ }
+ if ((old_end != new_end)||(old_end_pos != new_end_pos))
+ {
+ if (old_end_pos < (old_end->edata_len - 2))
+ {
+ DrawSelection(hw, old_end, new_end,
+ old_end_pos + 1, new_end_pos);
+ }
+ else
+ {
+ DrawSelection(hw, old_end->next, new_end,
+ 0, new_end_pos);
+ }
+ }
+ }
+ else
+ {
+ if ((old_start != new_start)||(old_start_pos != new_start_pos))
+ {
+ if (new_start_pos != 0)
+ {
+ EraseSelection(hw, old_start, new_start,
+ old_start_pos, new_start_pos - 1);
+ }
+ else
+ {
+ EraseSelection(hw, old_start, new_start->prev,
+ old_start_pos,
+ new_start->prev->edata_len - 2);
+ }
+ }
+ if ((new_end != old_end)||(new_end_pos != old_end_pos))
+ {
+ if (new_end_pos < (new_end->edata_len - 2))
+ {
+ EraseSelection(hw, new_end, old_end,
+ new_end_pos + 1, old_end_pos);
+ }
+ else
+ {
+ EraseSelection(hw, new_end->next, old_end,
+ 0, old_end_pos);
+ }
+ }
+ }
+}
+
+
+static void
+SelectStart(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params; /* unused */
+{
+ HTMLWidget hw = (HTMLWidget)XtParent(w);
+ XButtonPressedEvent *BuEvent = (XButtonPressedEvent *)event;
+ struct ele_rec *eptr;
+ int epos;
+
+ if (XtClass(XtParent(w)) != htmlWidgetClass)
+ {
+ return;
+ }
+
+#ifdef NOT_RIGHT
+ XUndefineCursor(XtDisplay(hw->html.view), XtWindow(hw->html.view));
+#endif
+ XUndefineCursor(XtDisplay(hw), XtWindow(hw));
+
+ /*
+ * Because X sucks, we can get the button pressed in the window, but
+ * released out of the window. This will highlight some text, but
+ * never complete the selection. Now on the next button press we
+ * have to clean up this mess.
+ */
+ EraseSelection(hw, hw->html.new_start, hw->html.new_end,
+ hw->html.new_start_pos, hw->html.new_end_pos);
+
+ /*
+ * We want to erase the currently selected text, but still save the
+ * selection internally in case we don't create a new one.
+ */
+ EraseSelection(hw, hw->html.select_start, hw->html.select_end,
+ hw->html.sel_start_pos, hw->html.sel_end_pos);
+ hw->html.new_start = hw->html.select_start;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = hw->html.sel_start_pos;
+ hw->html.new_end_pos = 0;
+
+ eptr = LocateElement(hw, BuEvent->x, BuEvent->y, &epos);
+ if (eptr != NULL)
+ {
+ /*
+ * If this is an anchor assume for now we are activating it
+ * and not selecting it.
+ */
+ if (eptr->anchorHRef != NULL)
+ {
+ hw->html.active_anchor = eptr;
+ hw->html.press_x = BuEvent->x;
+ hw->html.press_y = BuEvent->y;
+ SetAnchor(hw);
+ }
+ /*
+ * Else if we are on an image we can't select text so
+ * pretend we got eptr==NULL, and exit here.
+ */
+ else if (eptr->type == E_IMAGE)
+ {
+ hw->html.new_start = NULL;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end_pos = 0;
+ hw->html.press_x = BuEvent->x;
+ hw->html.press_y = BuEvent->y;
+ hw->html.but_press_time = BuEvent->time;
+ return;
+ }
+ /*
+ * Else if we used button2, we can't select text, so exit
+ * here.
+ */
+ else if (BuEvent->button == Button2)
+ {
+ hw->html.press_x = BuEvent->x;
+ hw->html.press_y = BuEvent->y;
+ hw->html.but_press_time = BuEvent->time;
+ return;
+ }
+ /*
+ * Else a single click will not select a new object
+ * but it will prime that selection on the next mouse
+ * move.
+ * Ignore special internal text
+ */
+ else if (eptr->internal == False)
+ {
+ hw->html.new_start = eptr;
+ hw->html.new_start_pos = epos;
+ hw->html.new_end = NULL;
+ hw->html.new_end_pos = 0;
+ hw->html.press_x = BuEvent->x;
+ hw->html.press_y = BuEvent->y;
+ }
+ else
+ {
+ hw->html.new_start = NULL;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end_pos = 0;
+ hw->html.press_x = BuEvent->x;
+ hw->html.press_y = BuEvent->y;
+ }
+ }
+ else
+ {
+ hw->html.new_start = NULL;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end_pos = 0;
+ hw->html.press_x = BuEvent->x;
+ hw->html.press_y = BuEvent->y;
+ }
+ hw->html.but_press_time = BuEvent->time;
+}
+
+
+static void
+ExtendStart(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params; /* unused */
+{
+ HTMLWidget hw = (HTMLWidget)XtParent(w);
+ XButtonPressedEvent *BuEvent = (XButtonPressedEvent *)event;
+ struct ele_rec *eptr;
+ struct ele_rec *start, *end;
+ struct ele_rec *old_start, *old_end;
+ int old_start_pos, old_end_pos;
+ int start_pos, end_pos;
+ int epos;
+
+ if (XtClass(XtParent(w)) != htmlWidgetClass)
+ {
+ return;
+ }
+
+ eptr = LocateElement(hw, BuEvent->x, BuEvent->y, &epos);
+
+ /*
+ * Ignore IMAGE elements.
+ */
+ if ((eptr != NULL)&&(eptr->type == E_IMAGE))
+ {
+ eptr = NULL;
+ }
+
+ /*
+ * Ignore NULL elements.
+ * Ignore special internal text
+ * documents.
+ */
+ if ((eptr != NULL)&&(eptr->internal == False))
+ {
+ old_start = hw->html.new_start;
+ old_start_pos = hw->html.new_start_pos;
+ old_end = hw->html.new_end;
+ old_end_pos = hw->html.new_end_pos;
+ if (hw->html.new_start == NULL)
+ {
+ hw->html.new_start = hw->html.select_start;
+ hw->html.new_start_pos = hw->html.sel_start_pos;
+ hw->html.new_end = hw->html.select_end;
+ hw->html.new_end_pos = hw->html.sel_end_pos;
+ }
+ else
+ {
+ hw->html.new_end = eptr;
+ hw->html.new_end_pos = epos;
+ }
+
+ if (SwapElements(hw->html.new_start, hw->html.new_end,
+ hw->html.new_start_pos, hw->html.new_end_pos))
+ {
+ if (SwapElements(eptr, hw->html.new_end,
+ epos, hw->html.new_end_pos))
+ {
+ start = hw->html.new_end;
+ start_pos = hw->html.new_end_pos;
+ end = eptr;
+ end_pos = epos;
+ }
+ else
+ {
+ start = hw->html.new_start;
+ start_pos = hw->html.new_start_pos;
+ end = eptr;
+ end_pos = epos;
+ }
+ }
+ else
+ {
+ if (SwapElements(eptr, hw->html.new_start,
+ epos, hw->html.new_start_pos))
+ {
+ start = hw->html.new_start;
+ start_pos = hw->html.new_start_pos;
+ end = eptr;
+ end_pos = epos;
+ }
+ else
+ {
+ start = hw->html.new_end;
+ start_pos = hw->html.new_end_pos;
+ end = eptr;
+ end_pos = epos;
+ }
+ }
+
+ if (start == NULL)
+ {
+ start = eptr;
+ start_pos = epos;
+ }
+
+ if (old_start == NULL)
+ {
+ hw->html.new_start = hw->html.select_start;
+ hw->html.new_end = hw->html.select_end;
+ hw->html.new_start_pos = hw->html.sel_start_pos;
+ hw->html.new_end_pos = hw->html.sel_end_pos;
+ }
+ else
+ {
+ hw->html.new_start = old_start;
+ hw->html.new_end = old_end;
+ hw->html.new_start_pos = old_start_pos;
+ hw->html.new_end_pos = old_end_pos;
+ }
+ ChangeSelection(hw, start, end, start_pos, end_pos);
+ hw->html.new_start = start;
+ hw->html.new_end = end;
+ hw->html.new_start_pos = start_pos;
+ hw->html.new_end_pos = end_pos;
+ }
+ else
+ {
+ if (hw->html.new_start == NULL)
+ {
+ hw->html.new_start = hw->html.select_start;
+ hw->html.new_start_pos = hw->html.sel_start_pos;
+ hw->html.new_end = hw->html.select_end;
+ hw->html.new_end_pos = hw->html.sel_end_pos;
+ }
+ }
+ hw->html.press_x = BuEvent->x;
+ hw->html.press_y = BuEvent->y;
+}
+
+
+static void
+ExtendAdjust(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params; /* unused */
+{
+ HTMLWidget hw = (HTMLWidget)XtParent(w);
+ XPointerMovedEvent *MoEvent = (XPointerMovedEvent *)event;
+ struct ele_rec *eptr;
+ struct ele_rec *start, *end;
+ int start_pos, end_pos;
+ int epos;
+
+ if (XtClass(XtParent(w)) != htmlWidgetClass)
+ {
+ return;
+ }
+
+ /*
+ * Very small mouse motion immediately after button press
+ * is ignored.
+ */
+ if ((ABS((hw->html.press_x - MoEvent->x)) <= SELECT_THRESHOLD)&&
+ (ABS((hw->html.press_y - MoEvent->y)) <= SELECT_THRESHOLD))
+ {
+ return;
+ }
+
+ /*
+ * If we have an active anchor and we got here, we have moved the
+ * mouse too far. Deactivate anchor, and prime a selection.
+ * If the anchor is internal text, don't
+ * prime a selection.
+ */
+ if (hw->html.active_anchor != NULL)
+ {
+ eptr = hw->html.active_anchor;
+ UnsetAnchor(hw);
+ if (eptr->internal == False)
+ {
+ hw->html.new_start = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end = NULL;
+ hw->html.new_end_pos = 0;
+ }
+ }
+
+ /*
+ * If we used button2, we can't select text, so
+ * clear selection and exit here.
+ */
+ if ((MoEvent->state & Button2Mask) != 0)
+ {
+ hw->html.select_start = NULL;
+ hw->html.select_end = NULL;
+ hw->html.sel_start_pos = 0;
+ hw->html.sel_end_pos = 0;
+ hw->html.new_start = NULL;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end_pos = 0;
+ return;
+ }
+
+ eptr = LocateElement(hw, MoEvent->x, MoEvent->y, &epos);
+
+ /*
+ * If we are on an image pretend we are nowhere
+ * and just return;
+ */
+ if ((eptr != NULL)&&(eptr->type == E_IMAGE))
+ {
+ return;
+ }
+
+ /*
+ * Ignore NULL items.
+ * Ignore if the same as last selected item and position.
+ * Ignore special internal text
+ */
+ if ((eptr != NULL)&&
+ ((eptr != hw->html.new_end)||(epos != hw->html.new_end_pos))&&
+ (eptr->internal == False))
+ {
+ start = hw->html.new_start;
+ start_pos = hw->html.new_start_pos;
+ end = eptr;
+ end_pos = epos;
+ if (start == NULL)
+ {
+ start = eptr;
+ start_pos = epos;
+ }
+
+ ChangeSelection(hw, start, end, start_pos, end_pos);
+ hw->html.new_start = start;
+ hw->html.new_end = end;
+ hw->html.new_start_pos = start_pos;
+ hw->html.new_end_pos = end_pos;
+ }
+}
+
+
+static void
+ExtendEnd(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ HTMLWidget hw = (HTMLWidget)XtParent(w);
+ XButtonReleasedEvent *BuEvent = (XButtonReleasedEvent *)event;
+ struct ele_rec *eptr;
+ struct ele_rec *start, *end;
+ Atom *atoms;
+ int i, buffer;
+ int start_pos, end_pos;
+ int epos;
+ char *text;
+
+ if (XtClass(XtParent(w)) != htmlWidgetClass)
+ {
+ return;
+ }
+
+ eptr = LocateElement(hw, BuEvent->x, BuEvent->y, &epos);
+
+ /*
+ * If we just released button one or two, and we are on an object,
+ * and we have an active anchor, and we are on the active anchor,
+ * and if we havn't waited too long. Activate that anchor.
+ */
+ if (((BuEvent->button == Button1)||(BuEvent->button == Button2))&&
+ (eptr != NULL)&&
+ (hw->html.active_anchor != NULL)&&
+ (eptr == hw->html.active_anchor)&&
+ ((BuEvent->time - hw->html.but_press_time) < CLICK_TIME))
+ {
+ _HTMLInput(w, event, params, num_params);
+ return;
+ }
+ else if (hw->html.active_anchor != NULL)
+ {
+ start = hw->html.active_anchor;
+ UnsetAnchor(hw);
+ if (start->internal == False)
+ {
+ hw->html.new_start = eptr;
+ hw->html.new_start_pos = epos;
+ hw->html.new_end = NULL;
+ hw->html.new_end_pos = 0;
+ }
+ }
+
+ /*
+ * If we used button2, we can't select text, so clear
+ * selection and exit here.
+ */
+ if (BuEvent->button == Button2)
+ {
+ hw->html.new_start = hw->html.select_start;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = hw->html.sel_start_pos;
+ hw->html.new_end_pos = 0;
+ return;
+ }
+
+ /*
+ * If we are on an image, pretend we are nowhere
+ * and NULL out the eptr
+ */
+ if ((eptr != NULL)&&(eptr->type == E_IMAGE))
+ {
+ eptr = NULL;
+ }
+
+ /*
+ * If button released on a NULL item, take the last non-NULL
+ * item that we highlighted.
+ */
+ if ((eptr == NULL)&&(hw->html.new_end != NULL))
+ {
+ eptr = hw->html.new_end;
+ epos = hw->html.new_end_pos;
+ }
+
+ if ((eptr != NULL)&&(eptr->internal == False)&&
+ (hw->html.new_end != NULL))
+ {
+ start = hw->html.new_start;
+ start_pos = hw->html.new_start_pos;
+ end = eptr;
+ end_pos = epos;
+ if (start == NULL)
+ {
+ start = eptr;
+ start_pos = epos;
+ }
+ ChangeSelection(hw, start, end, start_pos, end_pos);
+ hw->html.select_start = start;
+ hw->html.sel_start_pos = start_pos;
+ hw->html.select_end = end;
+ hw->html.sel_end_pos = end_pos;
+ SetSelection(hw);
+ hw->html.new_start = NULL;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end_pos = 0;
+
+ atoms = (Atom *)malloc(*num_params * sizeof(Atom));
+ if (atoms == NULL)
+ {
+ fprintf(stderr, "cannot allocate atom list\n");
+ return;
+ }
+ XmuInternStrings(XtDisplay((Widget)hw), params, *num_params, atoms);
+ hw->html.selection_time = BuEvent->time;
+ for (i=0; i< *num_params; i++)
+ {
+ switch (atoms[i])
+ {
+ case XA_CUT_BUFFER0: buffer = 0; break;
+ case XA_CUT_BUFFER1: buffer = 1; break;
+ case XA_CUT_BUFFER2: buffer = 2; break;
+ case XA_CUT_BUFFER3: buffer = 3; break;
+ case XA_CUT_BUFFER4: buffer = 4; break;
+ case XA_CUT_BUFFER5: buffer = 5; break;
+ case XA_CUT_BUFFER6: buffer = 6; break;
+ case XA_CUT_BUFFER7: buffer = 7; break;
+ default: buffer = -1; break;
+ }
+ if (buffer >= 0)
+ {
+ if (hw->html.fancy_selections == True)
+ {
+ text = ParseTextToPrettyString(hw,
+ hw->html.formatted_elements,
+ hw->html.select_start,
+ hw->html.select_end,
+ hw->html.sel_start_pos,
+ hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ else
+ {
+ text = ParseTextToString(
+ hw->html.formatted_elements,
+ hw->html.select_start,
+ hw->html.select_end,
+ hw->html.sel_start_pos,
+ hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ XStoreBuffer(XtDisplay((Widget)hw),
+ text, strlen(text), buffer);
+ if (text != NULL)
+ {
+ free(text);
+ }
+ }
+ else
+ {
+ XtOwnSelection((Widget)hw, atoms[i],
+ BuEvent->time,
+ (XtConvertSelectionProc )ConvertSelection,
+ (XtLoseSelectionProc )LoseSelection,
+ (XtSelectionDoneProc )SelectionDone);
+ }
+ }
+ free((char *)atoms);
+ }
+ else if (eptr == NULL)
+ {
+ hw->html.select_start = NULL;
+ hw->html.sel_start_pos = 0;
+ hw->html.select_end = NULL;
+ hw->html.sel_end_pos = 0;
+ hw->html.new_start = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end = NULL;
+ hw->html.new_end_pos = 0;
+ }
+}
+
+
+#define LEAVING_ANCHOR(hw) \
+ hw->html.cached_tracked_ele = NULL; \
+ (*(pointerTrackProc) \
+ (hw->html.pointer_motion_callback))(hw, hw->html.pm_client_data, ""); \
+ XUndefineCursor (XtDisplay (hw), XtWindow (hw));
+
+/* KNOWN PROBLEM: We never get LeaveNotify or FocusOut events,
+ despite the fact we've requested them. Bummer. */
+static void
+TrackMotion(w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params; /* unused */
+ Cardinal *num_params; /* unused */
+{
+ HTMLWidget hw = (HTMLWidget)XtParent(w);
+ struct ele_rec *eptr;
+ int epos, x, y;
+
+ if (XtClass(XtParent(w)) != htmlWidgetClass)
+ {
+ return;
+ }
+
+ if (!hw->html.pointer_motion_callback)
+ return;
+
+ if (event->type == MotionNotify)
+ {
+ x = ((XMotionEvent *)event)->x;
+ y = ((XMotionEvent *)event)->y;
+ }
+ else if (event->type == LeaveNotify || event->type == FocusOut ||
+ event->type == Expose)
+ {
+ /* Wipe out. */
+ if (hw->html.cached_tracked_ele)
+ {
+ LEAVING_ANCHOR (hw);
+ }
+ return;
+ }
+ else
+ {
+ return;
+ }
+
+ eptr = LocateElement(hw, x, y, &epos);
+
+ /* We're hitting a new anchor if eptr exists and
+ eptr != cached tracked element and anchorHRef != NULL. */
+ if (eptr != NULL && eptr != hw->html.cached_tracked_ele &&
+ eptr->anchorHRef != NULL)
+ {
+ hw->html.cached_tracked_ele = eptr;
+ (*(pointerTrackProc)
+ (hw->html.pointer_motion_callback))
+ (hw, hw->html.pm_client_data, eptr->anchorHRef);
+ XDefineCursor (XtDisplay (hw), XtWindow (hw), in_anchor_cursor);
+ }
+ /* We're leaving an anchor if eptr exists and
+ a cached ele exists and we're not entering a new anchor. */
+ else if (eptr != NULL && hw->html.cached_tracked_ele != NULL &&
+ eptr->anchorHRef == NULL)
+ {
+ LEAVING_ANCHOR (hw);
+ }
+
+ return;
+}
+
+
+/*
+ * Scroll display vertically.
+ */
+static void
+Scroll (w, event, params, num_params)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *num_params;
+{
+ register HTMLWidget hw = (HTMLWidget)XtParent(w);
+#ifdef MOTIF
+ int val, size, inc, pageinc;
+#endif
+ int offset, newy;
+
+ if (XtClass(XtParent(w)) != htmlWidgetClass)
+ return;
+
+ if (*num_params > 0) {
+ char *s = params[0];
+ double fraction;
+ double atof();
+ int ch;
+
+ if (strcmp (s + strlen(s) - 2, "ch") == 0) {
+ fraction = atof (s);
+ ch = (hw->html.font->max_bounds.ascent +
+ hw->html.font->max_bounds.descent);
+ offset = fraction * ch;
+ } else
+ offset = (int)hw->html.view_height * atof(s);
+
+ } else
+ offset = (int)hw->html.view_height / 10;
+
+ newy = hw->html.scroll_y + offset;
+ if (newy < 0)
+ newy = 0;
+ if (newy > (hw->html.doc_height - (int)hw->html.view_height))
+ newy = hw->html.doc_height - (int)hw->html.view_height;
+ if (newy < 0)
+ newy = 0;
+
+#ifdef MOTIF
+ XmScrollBarGetValues(hw->html.vbar, &val, &size, &inc, &pageinc);
+ XmScrollBarSetValues(hw->html.vbar, newy, size, inc, pageinc, True);
+ XmScrollBarGetValues(hw->html.hbar, &val, &size, &inc, &pageinc);
+ XmScrollBarSetValues(hw->html.hbar, 0, size, inc, pageinc, True);
+#else
+ ScrollToPos(hw->html.vbar, hw, newy);
+ ScrollToPos(hw->html.hbar, hw, 0);
+ setScrollBar(hw->html.vbar, newy,
+ hw->html.doc_height,
+ (int)hw->html.view_height);
+#endif
+}
+
+
+/*
+ * Process mouse input to the HTML widget
+ * Currently only processes an anchor-activate when Button1
+ * is pressed
+ */
+static void
+#ifdef _NO_PROTO
+_HTMLInput( w, event, params, num_params)
+ Widget w ;
+ XEvent *event ;
+ String *params; /* unused */
+ Cardinal *num_params; /* unused */
+#else
+_HTMLInput(
+ Widget w,
+ XEvent *event,
+ String *params, /* unused */
+ Cardinal *num_params) /* unused */
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)XtParent(w);
+ struct ele_rec *eptr;
+ WbAnchorCallbackData cbdata;
+ int epos;
+#ifdef MOTIF
+ Boolean on_gadget;
+#endif /* MOTIF */
+
+ if (XtClass(XtParent(w)) != htmlWidgetClass)
+ {
+ return;
+ }
+
+#ifdef MOTIF
+ /*
+ * If motif is defined, we don't want to process this button press
+ * if it is on a gadget
+ */
+#ifdef MOTIF1_2
+ on_gadget = (_XmInputForGadget((Widget)hw,
+#else
+ on_gadget = (_XmInputForGadget((CompositeWidget)hw,
+#endif /* MOTIF1_2 */
+ event->xbutton.x, event->xbutton.y) != NULL);
+
+ if (on_gadget)
+ {
+ return;
+ }
+#endif /* MOTIF */
+
+ if (event->type == ButtonRelease)
+ {
+ eptr = LocateElement(hw, event->xbutton.x, event->xbutton.y,
+ &epos);
+ if (eptr != NULL)
+ {
+ if (eptr->anchorHRef != NULL)
+ {
+ char *tptr, *ptr;
+
+ /*
+ * Save the anchor text, replace newlines with
+ * spaces.
+ */
+ tptr = ParseTextToString(hw->html.select_start,
+ hw->html.select_start, hw->html.select_end,
+ hw->html.sel_start_pos, hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ ptr = tptr;
+ while ((ptr != NULL)&&(*ptr != '\0'))
+ {
+ if (*ptr == '\n')
+ {
+ *ptr = ' ';
+ }
+ ptr++;
+ }
+
+ /*
+ * Clear the activated anchor
+ */
+ UnsetAnchor(hw);
+#ifdef EXTRA_FLUSH
+ XFlush(XtDisplay(hw));
+#endif
+
+ if ((IsDelayedHRef(hw, eptr->anchorHRef))&&
+ (hw->html.resolveDelayedImage != NULL))
+ {
+ eptr->pic_data = (*(resolveImageProc)
+ (hw->html.resolveDelayedImage))(hw, eptr->edata);
+
+ if (eptr->pic_data == NULL)
+ {
+ eptr->pic_data = NoImageData(hw);
+ eptr->pic_data->delayed = 0;
+ eptr->pic_data->internal = 0;
+ }
+ else
+ {
+ eptr->pic_data->delayed = 0;
+ /*
+ * Mark images we have sucessfully
+ * loaded at least once
+ */
+ if (eptr->pic_data->image_data != NULL)
+ {
+ eptr->pic_data->fetched = 1;
+ }
+ /*
+ * See if this is a special
+ * internal image
+ */
+ if ((eptr->edata != NULL)&&
+ (strncmp(eptr->edata,
+ INTERNAL_IMAGE,
+ strlen(INTERNAL_IMAGE)) == 0))
+ {
+ eptr->pic_data->internal = 1;
+ }
+ else
+ {
+ eptr->pic_data->internal = 0;
+ }
+ }
+
+ ReformatWindow(hw);
+ ScrollWidgets(hw);
+ ViewClearAndRefresh(hw);
+ }
+ else if ((eptr->pic_data != NULL)&&
+ (eptr->pic_data->delayed)&&
+ (eptr->anchorHRef != NULL)&&
+ (IsIsMapForm(hw, eptr->anchorHRef)))
+ {
+ eptr->pic_data = (*(resolveImageProc)
+ (hw->html.resolveDelayedImage))(hw, eptr->edata);
+
+ if (eptr->pic_data == NULL)
+ {
+ eptr->pic_data = NoImageData(hw);
+ eptr->pic_data->delayed = 0;
+ eptr->pic_data->internal = 0;
+ }
+ else
+ {
+ eptr->pic_data->delayed = 0;
+ /*
+ * Mark images we have sucessfully
+ * loaded at least once
+ */
+ if (eptr->pic_data->image_data != NULL)
+ {
+ eptr->pic_data->fetched = 1;
+ }
+ /*
+ * See if this is a special
+ * internal image
+ */
+ if ((eptr->edata != NULL)&&
+ (strncmp(eptr->edata,
+ INTERNAL_IMAGE,
+ strlen(INTERNAL_IMAGE)) == 0))
+ {
+ eptr->pic_data->internal = 1;
+ }
+ else
+ {
+ eptr->pic_data->internal = 0;
+ }
+ }
+
+ ReformatWindow(hw);
+ ScrollWidgets(hw);
+ ViewClearAndRefresh(hw);
+ }
+ else if ((eptr->pic_data != NULL)&&
+ (eptr->pic_data->delayed)&&
+ (eptr->anchorHRef != NULL)&&
+ (!IsDelayedHRef(hw, eptr->anchorHRef))&&
+ (!IsIsMapForm(hw, eptr->anchorHRef))&&
+ (((event->xbutton.y + hw->html.scroll_y) -
+ (eptr->y + eptr->y_offset)) >
+ AnchoredHeight(hw)))
+ {
+ eptr->pic_data = (*(resolveImageProc)
+ (hw->html.resolveDelayedImage))(hw, eptr->edata);
+
+ if (eptr->pic_data == NULL)
+ {
+ eptr->pic_data = NoImageData(hw);
+ eptr->pic_data->delayed = 0;
+ eptr->pic_data->internal = 0;
+ }
+ else
+ {
+ /*
+ * Mark images we have sucessfully
+ * loaded at least once
+ */
+ if (eptr->pic_data->image_data != NULL)
+ {
+ eptr->pic_data->fetched = 1;
+ }
+ /*
+ * See if this is a special
+ * internal image
+ */
+ if ((eptr->edata != NULL)&&
+ (strncmp(eptr->edata,
+ INTERNAL_IMAGE,
+ strlen(INTERNAL_IMAGE)) == 0))
+ {
+ eptr->pic_data->internal = 1;
+ }
+ else
+ {
+ eptr->pic_data->internal = 0;
+ }
+ }
+ eptr->pic_data->delayed = 0;
+
+ ReformatWindow(hw);
+ ScrollWidgets(hw);
+ ViewClearAndRefresh(hw);
+ }
+ else if ((eptr->pic_data != NULL)&&
+ (eptr->pic_data->ismap)&&
+ (eptr->anchorHRef != NULL)&&
+ (IsIsMapForm(hw, eptr->anchorHRef)))
+ {
+ int form_x, form_y;
+
+ form_x = event->xbutton.x + hw->html.scroll_x -
+ eptr->x;
+ form_y = event->xbutton.y + hw->html.scroll_y -
+ eptr->y;
+ ImageSubmitForm(eptr->pic_data->fptr, event,
+ eptr->pic_data->text, form_x, form_y);
+ }
+ else
+ {
+ /* The following is a hack to send the
+ * selection location along with the HRef
+ * for images. This allows you to
+ * point at a location on a map and have
+ * the server send you the related document.
+ * Tony Sanders, April 1993 <sanders@bsdi.com>
+ */
+ int alloced = 0;
+ char *buf = eptr->anchorHRef;
+ if (eptr->type == E_IMAGE && eptr->pic_data
+ && eptr->pic_data->ismap) {
+ buf = (char *)
+ malloc(strlen(eptr->anchorHRef) + 256);
+ alloced = 1;
+ sprintf(buf, "%s?%d,%d",
+ eptr->anchorHRef,
+ event->xbutton.x + hw->html.scroll_x - eptr->x,
+ event->xbutton.y + hw->html.scroll_y - eptr->y);
+ }
+ /*
+ * XXX: should call a media dependent
+ * function that decides how to munge the
+ * HRef. For example mpeg data will want
+ * to know on what frame the event occured.
+ *
+ * cddata.href = *(eptr->eventf)(eptr, event);
+ */
+ cbdata.event = event;
+ cbdata.element_id = eptr->ele_id;
+ cbdata.href = buf;
+ /* cbdata.href = eptr->anchorHRef; */
+ cbdata.text = tptr;
+ XtCallCallbackList ((Widget)hw,
+ hw->html.anchor_callback,
+ (XtPointer)&cbdata);
+ if (alloced) free(buf);
+ if (tptr != NULL) free(tptr);
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+
+#ifndef MOTIF
+#include <X11/Xaw/AsciiText.h>
+/*
+ * Process key input passwd widgets
+ */
+static void
+#ifdef _NO_PROTO
+_HTMLpwdInput( w, event, params, num_params)
+ Widget w ;
+ XEvent *event ;
+ String *params; /* unused */
+ Cardinal *num_params; /* unused */
+#else
+_HTMLpwdInput(
+ Widget w,
+ XEvent *event,
+ String *params, /* unused */
+ Cardinal *num_params) /* unused */
+#endif
+ {
+ char buffer[50];
+ KeySym ks;
+ char *keySymString;
+ char *star = "*";
+ int length, passwdLength, i, insertPos, maxLength;
+ Boolean stringInPlace;
+
+ if (event->type == KeyPress)
+ {
+ HTMLWidget hw = (HTMLWidget)XtParent(XtParent(w));
+ WidgetInfo *wptr;
+
+ if (XtClass((Widget)hw) != htmlWidgetClass)
+ return; /* it was not for us */
+
+ /*
+ * find the structure for this widget
+ */
+ wptr = hw->html.widget_list;
+ while (wptr != NULL)
+ {
+ if (wptr->w == w)
+ break;
+ wptr = wptr->next;
+ }
+ if (wptr == NULL)
+ return;
+
+ passwdLength = wptr->password ? strlen(wptr->password) : 0;
+
+ length = XLookupString((XKeyEvent *)event,
+ buffer, 50, &ks, NULL);
+ keySymString = XKeysymToString(ks);
+ XtVaGetValues(w,
+ XtNinsertPosition,&insertPos,
+ XtNuseStringInPlace, &stringInPlace,
+ XtNlength, &maxLength,
+ NULL);
+
+ if (maxLength<1) maxLength = 1000000;
+
+ if (!strcmp("Left",keySymString))
+ {
+ if (insertPos > 0)
+ XtVaSetValues(w,XtNinsertPosition,--insertPos,NULL);
+ return;
+ }
+ else if (!strcmp("Right",keySymString))
+ {
+ if (insertPos < passwdLength)
+ XtVaSetValues(w,XtNinsertPosition,++insertPos,NULL);
+ return;
+ }
+
+ if ((!strcmp("BackSpace",keySymString))
+ || (!strcmp("Backspace",keySymString))
+ || (!strcmp("Delete",keySymString)) )
+ {
+ insertPos --;
+
+ if (passwdLength>0)
+ {
+ char *pwd = &(wptr->password[insertPos]);
+
+ for (i = passwdLength - insertPos; i>0; i--,pwd++)
+ *pwd = *(pwd+1);
+
+/* fprintf(stderr,"modified passwd <%s>\n", wptr->password);*/
+ XtCallActionProc(w,
+ insertPos>-1 ? "delete-previous-character" :
+ "delete-next-character",
+ event, NULL,0);
+ }
+ /* else nothing to erase */
+ return;
+ }
+
+ if (length == 1)
+ {
+ buffer[1] = '\0';
+
+ if (passwdLength>0)
+ {
+
+ if (passwdLength < maxLength)
+ {
+ char *pwd = wptr->password =
+ (char *)realloc(wptr->password,
+ sizeof(char)*(passwdLength+2));
+ for (i=passwdLength+1; i>insertPos; i--)
+ pwd[i] = pwd[i-1];
+
+ pwd[insertPos] = buffer[0];
+ }
+ }
+ else
+ {
+ if (wptr->password == NULL)
+ wptr->password = (char *)malloc(sizeof(char)*2);
+
+ wptr->password[0] = buffer[0];
+ wptr->password[1] = '\0';
+ }
+
+ if (stringInPlace && passwdLength<maxLength)
+ {
+ char *txt;
+ /* insert string dumps core when string in place is true */
+
+ XtVaGetValues(w,XtNstring,&txt,NULL);
+ txt[passwdLength] = star[0];
+ txt[passwdLength+1] = '\0';
+
+ /* the combined set values command does not work */
+ XtVaSetValues(w, XtNstring,txt, NULL);
+ XtVaSetValues(w, XtNinsertPosition,insertPos+1, NULL);
+ }
+ else
+ XtCallActionProc(w, "insert-string", event, &star, 1);
+/* fprintf(stderr,"modified passwd <%s>\n", wptr->password); */
+ }
+ }
+ }
+#endif /* not MOTIF */
+
+
+/*
+ * SetValues is called when XtSetValues is used to change resources in this
+ * widget.
+ */
+static Boolean
+#ifdef _NO_PROTO
+SetValues (current, request, new)
+ HTMLWidget current ;
+ HTMLWidget request ;
+ HTMLWidget new ;
+#else
+SetValues(
+ HTMLWidget current,
+ HTMLWidget request,
+ HTMLWidget new)
+#endif
+{
+ int reformatted;
+
+ /*
+ * Make sure the underline numbers are within bounds.
+ */
+ if (request->html.num_anchor_underlines < 0)
+ {
+ new->html.num_anchor_underlines = 0;
+ }
+ if (request->html.num_anchor_underlines > MAX_UNDERLINES)
+ {
+ new->html.num_anchor_underlines = MAX_UNDERLINES;
+ }
+ if (request->html.num_visitedAnchor_underlines < 0)
+ {
+ new->html.num_visitedAnchor_underlines = 0;
+ }
+ if (request->html.num_visitedAnchor_underlines > MAX_UNDERLINES)
+ {
+ new->html.num_visitedAnchor_underlines = MAX_UNDERLINES;
+ }
+
+ reformatted = 0;
+ if ((request->html.raw_text != current->html.raw_text)||
+ (request->html.header_text != current->html.header_text)||
+ (request->html.footer_text != current->html.footer_text))
+ {
+ /*
+ * Free up the old visited href list.
+ */
+ FreeHRefs(current->html.my_visited_hrefs);
+ new->html.my_visited_hrefs = NULL;
+
+ /*
+ * Free up the old visited delayed images list.
+ */
+ FreeDelayedImages(current->html.my_delayed_images);
+ new->html.my_delayed_images = NULL;
+
+ /*
+ * Free any old colors and pixmaps
+ */
+ FreeColors(XtDisplay(current), DefaultColormapOfScreen(XtScreen(current)));
+ FreeImages(current);
+
+ /*
+ * Hide any old widgets
+ */
+ HideWidgets(current);
+ new->html.widget_list = NULL;
+ new->html.form_list = NULL;
+
+ /*
+ * Parse the raw text with the HTML parser
+ */
+ new->html.html_objects = HTMLParse(current->html.html_objects,
+ request->html.raw_text);
+ CallLinkCallbacks(new);
+ new->html.html_header_objects =
+ HTMLParse(current->html.html_header_objects,
+ request->html.header_text);
+ new->html.html_footer_objects =
+ HTMLParse(current->html.html_footer_objects,
+ request->html.footer_text);
+
+ /*
+ * Redisplay for the changed data.
+ */
+ {
+ new->html.scroll_x = 0;
+ new->html.scroll_y = 0;
+ new->html.max_pre_width = DocumentWidth(new,
+ new->html.html_objects);
+ ReformatWindow(new);
+ ViewClearAndRefresh(new);
+ reformatted = 1;
+ }
+
+ /*
+ * Clear any previous selection
+ */
+ new->html.select_start = NULL;
+ new->html.select_end = NULL;
+ new->html.sel_start_pos = 0;
+ new->html.sel_end_pos = 0;
+ new->html.new_start = NULL;
+ new->html.new_end = NULL;
+ new->html.new_start_pos = 0;
+ new->html.new_end_pos = 0;
+ new->html.active_anchor = NULL;
+ }
+ else if ((request->html.font != current->html.font)||
+ (request->html.italic_font != current->html.italic_font)||
+ (request->html.bold_font != current->html.bold_font)||
+ (request->html.fixed_font != current->html.fixed_font)||
+ (request->html.fixedbold_font != current->html.fixedbold_font)||
+ (request->html.fixeditalic_font != current->html.fixeditalic_font)||
+ (request->html.header1_font != current->html.header1_font)||
+ (request->html.header2_font != current->html.header2_font)||
+ (request->html.header3_font != current->html.header3_font)||
+ (request->html.header4_font != current->html.header4_font)||
+ (request->html.header5_font != current->html.header5_font)||
+ (request->html.header6_font != current->html.header6_font)||
+ (request->html.address_font != current->html.address_font)||
+ (request->html.plain_font != current->html.plain_font)||
+ (request->html.plainbold_font != current->html.plainbold_font)||
+ (request->html.plainitalic_font != current->html.plainitalic_font)||
+ (request->html.listing_font != current->html.listing_font)||
+ (request->html.activeAnchor_fg != current->html.activeAnchor_fg)||
+ (request->html.activeAnchor_bg != current->html.activeAnchor_bg)||
+ (request->html.anchor_fg != current->html.anchor_fg)||
+ (request->html.visitedAnchor_fg != current->html.visitedAnchor_fg)||
+ (request->html.dashed_anchor_lines != current->html.dashed_anchor_lines)||
+ (request->html.dashed_visitedAnchor_lines != current->html.dashed_visitedAnchor_lines)||
+ (request->html.num_anchor_underlines != current->html.num_anchor_underlines)||
+ (request->html.num_visitedAnchor_underlines != current->html.num_visitedAnchor_underlines))
+ {
+ if ((request->html.plain_font != current->html.plain_font)||
+ (request->html.listing_font != current->html.listing_font))
+ {
+ new->html.max_pre_width = DocumentWidth(new,
+ new->html.html_objects);
+ }
+
+ ReformatWindow(new);
+ ScrollWidgets(new);
+ ViewClearAndRefresh(new);
+ reformatted = 1;
+ }
+
+ /*
+ * image borders have been changed
+ */
+ if (request->html.border_images != current->html.border_images)
+ {
+ ReformatWindow(new);
+ ScrollWidgets(new);
+ ViewClearAndRefresh(new);
+ reformatted = 1;
+ }
+
+ /*
+ * vertical space has been changed
+ */
+ if(request->html.percent_vert_space != current->html.percent_vert_space)
+ {
+ ReformatWindow(new);
+ ScrollWidgets(new);
+ ViewClearAndRefresh(new);
+ reformatted = 1;
+ }
+
+ /*
+ * Set client data for retest anchors callback.
+ */
+ if(request->html.vt_client_data != current->html.vt_client_data)
+ {
+ new->html.vt_client_data = request->html.vt_client_data;
+ }
+
+ /*
+ * Set client data for pointer motion callback.
+ */
+ if(request->html.pm_client_data != current->html.pm_client_data)
+ {
+ new->html.pm_client_data = request->html.pm_client_data;
+ }
+
+ return(False);
+}
+
+
+/*
+ * Go through the parsed marks and for all the <LINK> tags in the document
+ * call the LinkCallback.
+ */
+static void
+#ifdef _NO_PROTO
+CallLinkCallbacks(hw)
+ HTMLWidget hw;
+#else
+CallLinkCallbacks(HTMLWidget hw)
+#endif
+{
+ struct mark_up *mptr;
+ LinkInfo l_info;
+
+ mptr = hw->html.html_objects;
+ while (mptr != NULL)
+ {
+ if (mptr->type == M_BASE)
+ {
+ l_info.href = ParseMarkTag(mptr->start, MT_BASE,
+ "HREF");
+ l_info.role = ParseMarkTag(mptr->start, MT_BASE,
+ "ROLE");
+ XtCallCallbackList ((Widget)hw, hw->html.link_callback,
+ (XtPointer)&l_info);
+ if (l_info.href != NULL)
+ {
+ free(l_info.href);
+ }
+ if (l_info.role != NULL)
+ {
+ free(l_info.role);
+ }
+ }
+ mptr = mptr->next;
+ }
+}
+
+
+/*
+ * Search through the whole document, and recolor the internal elements with
+ * the passed HREF.
+ */
+static void
+#ifdef _NO_PROTO
+RecolorInternalHRefs(hw, href)
+ HTMLWidget hw;
+ char *href;
+#else
+RecolorInternalHRefs(HTMLWidget hw, char *href)
+#endif
+{
+ struct ele_rec *start;
+ unsigned long fg;
+
+ fg = hw->html.visitedAnchor_fg;
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ /*
+ * This one is internal
+ * This one has an href
+ * This is the href we want
+ */
+ if ((start->internal == True)&&
+ (start->anchorHRef != NULL)&&
+ (strcmp(start->anchorHRef, href) == 0))
+ {
+ start->fg = fg;
+ start->underline_number =
+ hw->html.num_visitedAnchor_underlines;
+ start->dashed_underline =
+ hw->html.dashed_visitedAnchor_lines;
+ }
+ start = start->next;
+ }
+}
+
+
+static Boolean
+ConvertSelection(w, selection, target, type, value, length, format)
+ Widget w;
+ Atom *selection, *target, *type;
+ caddr_t *value;
+ unsigned long *length;
+ int *format;
+{
+ Display *d = XtDisplay(w);
+ HTMLWidget hw = (HTMLWidget)w;
+ char *text;
+
+ if (hw->html.select_start == NULL)
+ {
+ return False;
+ }
+
+ if (*target == XA_TARGETS(d))
+ {
+ Atom *targetP;
+ Atom *std_targets;
+ unsigned long std_length;
+ XmuConvertStandardSelection( w, hw->html.selection_time,
+ selection, target, type, (caddr_t*)&std_targets,
+ &std_length, format);
+
+ *length = std_length + 5;
+ *value = (caddr_t)XtMalloc(sizeof(Atom)*(*length));
+ targetP = *(Atom**)value;
+ *targetP++ = XA_STRING;
+ *targetP++ = XA_TEXT(d);
+ *targetP++ = XA_COMPOUND_TEXT(d);
+ *targetP++ = XA_LENGTH(d);
+ *targetP++ = XA_LIST_LENGTH(d);
+
+ bcopy((char*)std_targets, (char*)targetP,
+ sizeof(Atom)*std_length);
+ XtFree((char*)std_targets);
+ *type = XA_ATOM;
+ *format = 32;
+ return True;
+ }
+
+ if (*target == XA_STRING || *target == XA_TEXT(d) ||
+ *target == XA_COMPOUND_TEXT(d))
+ {
+ if (*target == XA_COMPOUND_TEXT(d))
+ {
+ *type = *target;
+ }
+ else
+ {
+ *type = XA_STRING;
+ }
+ if (hw->html.fancy_selections == True)
+ {
+ text = ParseTextToPrettyString(hw,
+ hw->html.formatted_elements,
+ hw->html.select_start, hw->html.select_end,
+ hw->html.sel_start_pos, hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ else
+ {
+ text = ParseTextToString(hw->html.formatted_elements,
+ hw->html.select_start, hw->html.select_end,
+ hw->html.sel_start_pos, hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ *value = text;
+ *length = strlen(*value);
+ *format = 8;
+ return True;
+ }
+
+ if (*target == XA_LIST_LENGTH(d))
+ {
+ *value = XtMalloc(4);
+ if (sizeof(long) == 4)
+ {
+ *(long*)*value = 1;
+ }
+ else
+ {
+ long temp = 1;
+ bcopy( ((char*)&temp)+sizeof(long)-4, (char*)*value, 4);
+ }
+ *type = XA_INTEGER;
+ *length = 1;
+ *format = 32;
+ return True;
+ }
+
+ if (*target == XA_LENGTH(d))
+ {
+ if (hw->html.fancy_selections == True)
+ {
+ text = ParseTextToPrettyString(hw,
+ hw->html.formatted_elements,
+ hw->html.select_start, hw->html.select_end,
+ hw->html.sel_start_pos, hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ else
+ {
+ text = ParseTextToString(hw->html.formatted_elements,
+ hw->html.select_start, hw->html.select_end,
+ hw->html.sel_start_pos, hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ *value = XtMalloc(4);
+ if (sizeof(long) == 4)
+ {
+ *(long*)*value = strlen(text);
+ }
+ else
+ {
+ long temp = strlen(text);
+ bcopy( ((char*)&temp)+sizeof(long)-4, (char*)*value, 4);
+ }
+ free(text);
+ *type = XA_INTEGER;
+ *length = 1;
+ *format = 32;
+ return True;
+ }
+
+ if (XmuConvertStandardSelection(w, hw->html.selection_time, selection,
+ target, type, value, length, format))
+ {
+ return True;
+ }
+
+ return False;
+}
+
+
+static void
+LoseSelection(w, selection)
+ Widget w;
+ Atom *selection;
+{
+ HTMLWidget hw = (HTMLWidget)w;
+
+ ClearSelection(hw);
+}
+
+
+static void
+SelectionDone(w, selection, target)
+ Widget w;
+ Atom *selection, *target;
+{
+ /* empty proc so Intrinsics know we want to keep storage */
+}
+
+
+/*
+ *************************************************************************
+ ******************************* PUBLIC FUNCTIONS ************************
+ *************************************************************************
+ */
+
+
+/*
+ * Convenience function to return the text of the HTML document as a plain
+ * ascii text string.
+ * This function allocates memory for the returned string, that it is up
+ * to the user to free.
+ * Extra option flags "pretty" text to be returned.
+ * when pretty is two or larger, Postscript is returned. The font used is
+ * encoded in the pretty parameter:
+ * pretty = 2: Times
+ * pretty = 3: Helvetica
+ * pretty = 4: New century schoolbook
+ * pretty = 5: Lucida Bright
+ */
+char *
+#ifdef _NO_PROTO
+HTMLGetText (w, pretty)
+ Widget w;
+ int pretty;
+#else
+HTMLGetText(Widget w, int pretty)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ char *text;
+ char *tptr, *buf;
+ struct ele_rec *start;
+ struct ele_rec *end;
+
+ text = NULL;
+ start = hw->html.formatted_elements;
+ end = start;
+ while (end != NULL)
+ {
+ end = end->next;
+ }
+
+ if (pretty >= 2)
+ {
+ tptr = ParseTextToPSString(hw, start, start, end,
+ 0, 0,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width , pretty-2);
+ }
+ else if (pretty)
+ {
+ tptr = ParseTextToPrettyString(hw, start, start, end,
+ 0, 0,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ else
+ {
+ tptr = ParseTextToString(start, start, end,
+ 0, 0,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ if (tptr != NULL)
+ {
+ if (text == NULL)
+ {
+ text = tptr;
+ }
+ else
+ {
+ buf = (char *)malloc(strlen(text) +
+ strlen(tptr) + 1);
+ strcpy(buf, text);
+ strcat(buf, tptr);
+ free(text);
+ free(tptr);
+ text = buf;
+ }
+ }
+ return(text);
+}
+
+
+/*
+ * Convenience function to return the element id of the element
+ * nearest to the x,y coordinates passed in.
+ * If there is no element there, return the first element in the
+ * line we are on. If there we are on no line, either return the
+ * beginning, or the end of the document.
+ */
+int
+#ifdef _NO_PROTO
+HTMLPositionToId(w, x, y)
+ Widget w;
+ int x, y;
+#else
+HTMLPositionToId(Widget w, int x, int y)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ int i;
+ int epos;
+ struct ele_rec *eptr;
+
+ eptr = LocateElement(hw, x, y, &epos);
+ if (eptr == NULL)
+ {
+ x = x + hw->html.scroll_x;
+ y = y + hw->html.scroll_y;
+ eptr = hw->html.line_array[0];
+ for (i=0; i<hw->html.line_count; i++)
+ {
+ if (hw->html.line_array[i] == NULL)
+ {
+ continue;
+ }
+ else if (hw->html.line_array[i]->y <= y)
+ {
+ eptr = hw->html.line_array[i];
+ continue;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ /*
+ * 0 means the very top of the document. We put you there for
+ * unfound elements.
+ * We also special case for when the scrollbar is at the
+ * absolute top.
+ */
+ if ((eptr == NULL)||(hw->html.scroll_y == 0))
+ {
+ return(0);
+ }
+ else
+ {
+ return(eptr->ele_id);
+ }
+}
+
+
+/*
+ * Convenience function to return the position of the element
+ * based on the element id passed in.
+ * Function returns 1 on success and fills in x,y pixel values.
+ * If there is no such element, x=0, y=0 and -1 is returned.
+ */
+int
+#ifdef _NO_PROTO
+HTMLIdToPosition(w, element_id, x, y)
+ Widget w;
+ int element_id;
+ int *x, *y;
+#else
+HTMLIdToPosition(Widget w, int element_id, int *x, int *y)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ struct ele_rec *start;
+ struct ele_rec *eptr;
+
+ eptr = NULL;
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ if (start->ele_id == element_id)
+ {
+ eptr = start;
+ break;
+ }
+ start = start->next;
+ }
+
+ if (eptr == NULL)
+ {
+ *x = 0;
+ *y = 0;
+ return(-1);
+ }
+ else
+ {
+ *x = eptr->x;
+ *y = eptr->y;
+ return(1);
+ }
+}
+
+
+/*
+ * Convenience function to position the element
+ * based on the element id passed at the top of the viewing area.
+ * A passed in id of 0 means goto the top.
+ */
+void
+#ifdef _NO_PROTO
+HTMLGotoId(w, element_id)
+ Widget w;
+ int element_id;
+#else
+HTMLGotoId(Widget w, int element_id)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ struct ele_rec *start;
+ struct ele_rec *eptr;
+ int newy;
+#ifdef MOTIF
+ int val, size, inc, pageinc;
+#endif
+
+ /*
+ * If we have no scrollbar, just return.
+ */
+ if (hw->html.use_vbar == False)
+ {
+ return;
+ }
+
+ /*
+ * Find the element corrsponding to the id passed in.
+ */
+ eptr = NULL;
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ if (start->ele_id == element_id)
+ {
+ eptr = start;
+ break;
+ }
+ start = start->next;
+ }
+
+ /*
+ * No such element, do nothing.
+ */
+ if ((element_id != 0)&&(eptr == NULL))
+ {
+ return;
+ }
+
+ if (element_id == 0)
+ {
+ newy = 0;
+ }
+ else
+ {
+ newy = eptr->y - 2;
+ }
+ if (newy < 0)
+ {
+ newy = 0;
+ }
+ if (newy > (hw->html.doc_height - (int)hw->html.view_height))
+ {
+ newy = hw->html.doc_height - (int)hw->html.view_height;
+ }
+ if (newy < 0)
+ {
+ newy = 0;
+ }
+#ifdef MOTIF
+ XmScrollBarGetValues(hw->html.vbar, &val, &size, &inc, &pageinc);
+ XmScrollBarSetValues(hw->html.vbar, newy, size, inc, pageinc, True);
+ XmScrollBarGetValues(hw->html.hbar, &val, &size, &inc, &pageinc);
+ XmScrollBarSetValues(hw->html.hbar, 0, size, inc, pageinc, True);
+#else
+ ScrollToPos(hw->html.vbar, hw, newy);
+ ScrollToPos(hw->html.hbar, hw, 0);
+ setScrollBar(hw->html.vbar, newy,
+ hw->html.doc_height,
+ (int)hw->html.view_height);
+#endif
+}
+
+
+/*
+ * Convenience function to return the position of the anchor
+ * based on the anchor NAME passed.
+ * Function returns 1 on success and fills in x,y pixel values.
+ * If there is no such element, x=0, y=0 and -1 is returned.
+ */
+int
+#ifdef _NO_PROTO
+HTMLAnchorToPosition(w, name, x, y)
+ Widget w;
+ char *name;
+ int *x, *y;
+#else
+HTMLAnchorToPosition(Widget w, char *name, int *x, int *y)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ struct ele_rec *start;
+ struct ele_rec *eptr;
+
+ eptr = NULL;
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ if ((start->anchorName)&&
+ (strcmp(start->anchorName, name) == 0))
+ {
+ eptr = start;
+ break;
+ }
+ start = start->next;
+ }
+
+ if (eptr == NULL)
+ {
+ *x = 0;
+ *y = 0;
+ return(-1);
+ }
+ else
+ {
+ *x = eptr->x;
+ *y = eptr->y;
+ return(1);
+ }
+}
+
+
+/*
+ * Convenience function to return the element id of the anchor
+ * based on the anchor NAME passed.
+ * Function returns id on success.
+ * If there is no such element, 0 is returned.
+ */
+int
+#ifdef _NO_PROTO
+HTMLAnchorToId(w, name)
+ Widget w;
+ char *name;
+#else
+HTMLAnchorToId(Widget w, char *name)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ struct ele_rec *start;
+ struct ele_rec *eptr;
+
+ /*
+ * Find the passed anchor name
+ */
+ eptr = NULL;
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ if ((start->anchorName)&& /* MF023 */
+ ((strcmp(start->anchorName, name) == 0) ||
+ (*name == '#' && strcmp(start->anchorName, &(name[1])) == 0)) ) {
+ eptr = start;
+ break;
+ }
+ start = start->next;
+ }
+
+ if (eptr == NULL)
+ {
+ return(0);
+ }
+ else
+ {
+ return(eptr->ele_id);
+ }
+}
+
+
+/*
+ * Convenience function to return the HREFs of all active anchors in the
+ * document.
+ * Function returns an array of strings and fills num_hrefs passed.
+ * If there are no HREFs NULL returned.
+ */
+char **
+#ifdef _NO_PROTO
+HTMLGetHRefs(w, num_hrefs)
+ Widget w;
+ int *num_hrefs;
+#else
+HTMLGetHRefs(Widget w, int *num_hrefs)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ int cnt;
+ struct ele_rec *start;
+ struct ele_rec *list;
+ struct ele_rec *eptr;
+ char **harray;
+
+ list = NULL;
+ cnt = 0;
+ /*
+ * Construct a linked list of all the diffeent hrefs, counting
+ * then as we go.
+ */
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ /*
+ * This one has an HREF
+ */
+ if (start->anchorHRef != NULL)
+ {
+ /*
+ * Check to see if we already have
+ * this HREF in our list.
+ */
+ eptr = list;
+ while (eptr != NULL)
+ {
+ if (strcmp(eptr->anchorHRef,
+ start->anchorHRef) == 0)
+ {
+ break;
+ }
+ eptr = eptr->next;
+ }
+ /*
+ * This HREF is not, in our list. Add it.
+ * That is, if it's not an internal reference.
+ */
+ if ((eptr == NULL)&&(start->internal == False))
+ {
+ eptr = (struct ele_rec *)
+ malloc(sizeof(struct ele_rec));
+ eptr->anchorHRef = start->anchorHRef;
+ eptr->next = list;
+ list = eptr;
+ cnt++;
+ }
+ }
+ start = start->next;
+ }
+
+ if (cnt == 0)
+ {
+ *num_hrefs = 0;
+ return(NULL);
+ }
+ else
+ {
+ *num_hrefs = cnt;
+ harray = (char **)malloc(sizeof(char *) * cnt);
+ eptr = list;
+ cnt--;
+ while (eptr != NULL)
+ {
+ harray[cnt] = (char *)
+ malloc(strlen(eptr->anchorHRef) + 1);
+ strcpy(harray[cnt], eptr->anchorHRef);
+ start = eptr;
+ eptr = eptr->next;
+ free((char *)start);
+ cnt--;
+ }
+ return(harray);
+ }
+}
+
+
+/*
+ * Convenience function to return the SRCs of all images in the
+ * document.
+ * Function returns an array of strings and fills num_srcs passed.
+ * If there are no SRCs NULL returned.
+ */
+char **
+#ifdef _NO_PROTO
+HTMLGetImageSrcs(w, num_srcs)
+ Widget w;
+ int *num_srcs;
+#else
+HTMLGetImageSrcs(Widget w, int *num_srcs)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ struct mark_up *mptr;
+ int cnt;
+ char *tptr;
+ char **harray;
+
+ cnt = 0;
+ mptr = hw->html.html_objects;
+ while (mptr != NULL)
+ {
+ if (mptr->type == M_IMAGE)
+ {
+ tptr = ParseMarkTag(mptr->start, MT_IMAGE, "SRC");
+ if ((tptr != NULL)&&(*tptr != '\0'))
+ {
+ cnt++;
+ free(tptr);
+ }
+ }
+ mptr = mptr->next;
+ }
+
+ if (cnt == 0)
+ {
+ *num_srcs = 0;
+ return(NULL);
+ }
+ else
+ {
+ *num_srcs = cnt;
+ harray = (char **)malloc(sizeof(char *) * cnt);
+ mptr = hw->html.html_objects;
+ cnt = 0;
+ while (mptr != NULL)
+ {
+ if (mptr->type == M_IMAGE)
+ {
+ tptr = ParseMarkTag(mptr->start,MT_IMAGE,"SRC");
+ if ((tptr != NULL)&&(*tptr != '\0'))
+ {
+ harray[cnt] = tptr;
+ cnt++;
+ }
+ }
+ mptr = mptr->next;
+ }
+ return(harray);
+ }
+}
+
+
+/*
+ * Convenience function to return the link information
+ * for all the <LINK> tags in the document.
+ * Function returns an array of LinkInfo structures and fills
+ * num_links passed.
+ * If there are no LINKs NULL returned.
+ */
+LinkInfo *
+#ifdef _NO_PROTO
+HTMLGetLinks(w, num_links)
+ Widget w;
+ int *num_links;
+#else
+HTMLGetLinks(Widget w, int *num_links)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ struct mark_up *mptr;
+ int cnt;
+ char *tptr;
+ LinkInfo *larray;
+
+ cnt = 0;
+ mptr = hw->html.html_objects;
+ while (mptr != NULL)
+ {
+ if (mptr->type == M_BASE)
+ {
+ cnt++;
+ }
+ mptr = mptr->next;
+ }
+
+ if (cnt == 0)
+ {
+ *num_links = 0;
+ return(NULL);
+ }
+ else
+ {
+ *num_links = cnt;
+ larray = (LinkInfo *)malloc(sizeof(LinkInfo) * cnt);
+ mptr = hw->html.html_objects;
+ cnt = 0;
+ while (mptr != NULL)
+ {
+ if (mptr->type == M_BASE)
+ {
+ tptr = ParseMarkTag(mptr->start,
+ MT_BASE, "HREF");
+ larray[cnt].href = tptr;
+ tptr = ParseMarkTag(mptr->start,
+ MT_BASE, "ROLE");
+ larray[cnt].role = tptr;
+ cnt++;
+ }
+ mptr = mptr->next;
+ }
+ return(larray);
+ }
+}
+
+
+
+void *
+#ifdef _NO_PROTO
+HTMLGetWidgetInfo(w)
+ Widget w;
+#else
+HTMLGetWidgetInfo(Widget w)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+
+ return((void *)hw->html.widget_list);
+}
+
+
+void
+#ifdef _NO_PROTO
+HTMLFreeImageInfo(w)
+ Widget w;
+#else
+HTMLFreeImageInfo(Widget w)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+
+ FreeColors(XtDisplay(w), DefaultColormapOfScreen(XtScreen(w)));
+ FreeImages(hw);
+}
+
+
+void
+#ifdef _NO_PROTO
+HTMLFreeWidgetInfo(ptr)
+ void *ptr;
+#else
+HTMLFreeWidgetInfo(void *ptr)
+#endif
+{
+ WidgetInfo *wptr = (WidgetInfo *)ptr;
+ WidgetInfo *tptr;
+
+ while (wptr != NULL)
+ {
+ tptr = wptr;
+ wptr = wptr->next;
+ if (tptr->w != NULL)
+ {
+ /*
+ * This is REALLY DUMB, but X generates an expose event
+ * for the destruction of the Widgte, even if it isn't
+ * mapped at the time it is destroyed.
+ * So I move the invisible widget to -1000,-1000
+ * before destroying it, to avoid a visible flash.
+ */
+ XtMoveWidget(tptr->w, -1000, -1000);
+ XtDestroyWidget(tptr->w);
+ }
+ if (tptr->name != NULL)
+ {
+ free(tptr->name);
+ }
+ if ((tptr->value != NULL)&&(tptr->type != W_OPTIONMENU))
+ {
+ free(tptr->value);
+ }
+ free((char *)tptr);
+ }
+}
+
+
+/*
+ * Convenience function to redraw all active anchors in the
+ * document.
+ * Can also pass a new predicate function to check visited
+ * anchors. If NULL passed for function, uses default predicate
+ * function.
+ */
+void
+#ifdef _NO_PROTO
+HTMLRetestAnchors(w, testFunc, client_data)
+ Widget w;
+ visitTestProc testFunc;
+ XtPointer client_data;
+#else
+HTMLRetestAnchors(Widget w, visitTestProc testFunc, XtPointer client_data)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ struct ele_rec *start;
+ int stat = 0;
+
+ if (testFunc == NULL)
+ {
+ testFunc = (visitTestProc)hw->html.previously_visited_test;
+ client_data = hw->html.vt_client_data;
+ }
+
+ /*
+ * Search all elements
+ */
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ if ((start->internal == True)||
+ (start->anchorHRef == NULL))
+ {
+ start = start->next;
+ continue;
+ }
+
+ if (testFunc != NULL)
+ {
+ if ((stat=(*testFunc)(hw, client_data, start->anchorHRef)))
+ {
+ start->fg = hw->html.visitedAnchor_fg;
+ start->underline_number =
+ hw->html.num_visitedAnchor_underlines;
+ start->dashed_underline =
+ hw->html.dashed_visitedAnchor_lines;
+ }
+ else
+ {
+ start->fg = hw->html.anchor_fg;
+ start->underline_number =
+ hw->html.num_anchor_underlines;
+ start->dashed_underline =
+ hw->html.dashed_anchor_lines;
+ }
+ }
+ else
+ {
+ start->fg = hw->html.anchor_fg;
+ start->underline_number =
+ hw->html.num_anchor_underlines;
+ start->dashed_underline =
+ hw->html.dashed_anchor_lines;
+ }
+
+ /*
+ * Since the element may have changed, redraw it
+ */
+ if (stat) {
+ switch(start->type)
+ {
+ case E_TEXT:
+ TextRefresh(hw, start,
+ 0, (start->edata_len - 2));
+ break;
+ case E_IMAGE:
+ ImageRefresh(hw, start);
+ break;
+ case E_BULLET:
+ BulletRefresh(hw, start);
+ break;
+ case E_LINEFEED:
+ LinefeedRefresh(hw, start);
+ break;
+ }
+ }
+
+ start = start->next;
+ }
+}
+
+
+void
+#ifdef _NO_PROTO
+HTMLClearSelection (w)
+ Widget w;
+#else
+HTMLClearSelection(Widget w)
+#endif
+{
+ LoseSelection (w, NULL);
+}
+
+
+/*
+ * Set the current selection based on the ElementRefs passed in.
+ * Both refs must be valid.
+ */
+void
+#ifdef _NO_PROTO
+HTMLSetSelection (w, start, end)
+ Widget w;
+ ElementRef *start;
+ ElementRef *end;
+#else
+HTMLSetSelection(Widget w, ElementRef *start, ElementRef *end)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ int found;
+ struct ele_rec *eptr;
+ struct ele_rec *e_start;
+ struct ele_rec *e_end;
+ int start_pos, end_pos;
+ Atom *atoms;
+ int i, buffer;
+ char *text;
+ char *params[2];
+
+ /*
+ * If the starting position is not valid, fail the selection
+ */
+ if ((start->id > 0)&&(start->pos >= 0))
+ {
+ found = 0;
+ eptr = hw->html.formatted_elements;
+
+ while (eptr != NULL)
+ {
+ if (eptr->ele_id == start->id)
+ {
+ e_start = eptr;
+ start_pos = start->pos;
+ found = 1;
+ break;
+ }
+ eptr = eptr->next;
+ }
+ if (!found)
+ {
+ return;
+ }
+ }
+
+ /*
+ * If the ending position is not valid, fail the selection
+ */
+ if ((end->id > 0)&&(end->pos >= 0))
+ {
+ found = 0;
+ eptr = hw->html.formatted_elements;
+
+ while (eptr != NULL)
+ {
+ if (eptr->ele_id == end->id)
+ {
+ e_end = eptr;
+ end_pos = end->pos;
+ found = 1;
+ break;
+ }
+ eptr = eptr->next;
+ }
+ if (!found)
+ {
+ return;
+ }
+ }
+
+ LoseSelection (w, NULL);
+
+ /*
+ * We expect the ElementRefs came from HTMLSearchText, so we know
+ * that the end_pos is one past what we want to select.
+ */
+ end_pos = end_pos - 1;
+
+ /*
+ * Sanify the position data
+ */
+ if ((start_pos > 0)&&(start_pos >= e_start->edata_len - 1))
+ {
+ start_pos = e_start->edata_len - 2;
+ }
+ if ((end_pos > 0)&&(end_pos >= e_end->edata_len - 1))
+ {
+ end_pos = e_end->edata_len - 2;
+ }
+
+ hw->html.select_start = e_start;
+ hw->html.sel_start_pos = start_pos;
+ hw->html.select_end = e_end;
+ hw->html.sel_end_pos = end_pos;
+ SetSelection(hw);
+ hw->html.new_start = NULL;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end_pos = 0;
+
+ /*
+ * Do all the gunk from the end of the ExtendEnd function
+ */
+ params[0] = "PRIMARY";
+ params[1] = "CUT_BUFFER0";
+ atoms = (Atom *)malloc(2 * sizeof(Atom));
+ if (atoms == NULL)
+ {
+ fprintf(stderr, "cannot allocate atom list\n");
+ return;
+ }
+ XmuInternStrings(XtDisplay((Widget)hw), params, 2, atoms);
+ hw->html.selection_time = CurrentTime;
+ for (i=0; i< 2; i++)
+ {
+ switch (atoms[i])
+ {
+ case XA_CUT_BUFFER0: buffer = 0; break;
+ case XA_CUT_BUFFER1: buffer = 1; break;
+ case XA_CUT_BUFFER2: buffer = 2; break;
+ case XA_CUT_BUFFER3: buffer = 3; break;
+ case XA_CUT_BUFFER4: buffer = 4; break;
+ case XA_CUT_BUFFER5: buffer = 5; break;
+ case XA_CUT_BUFFER6: buffer = 6; break;
+ case XA_CUT_BUFFER7: buffer = 7; break;
+ default: buffer = -1; break;
+ }
+ if (buffer >= 0)
+ {
+ if (hw->html.fancy_selections == True)
+ {
+ text = ParseTextToPrettyString(hw,
+ hw->html.formatted_elements,
+ hw->html.select_start,
+ hw->html.select_end,
+ hw->html.sel_start_pos,
+ hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ else
+ {
+ text = ParseTextToString(
+ hw->html.formatted_elements,
+ hw->html.select_start,
+ hw->html.select_end,
+ hw->html.sel_start_pos,
+ hw->html.sel_end_pos,
+ hw->html.font->max_bounds.width,
+ hw->html.margin_width);
+ }
+ XStoreBuffer(XtDisplay((Widget)hw),
+ text, strlen(text), buffer);
+ free(text);
+ }
+ else
+ {
+ XtOwnSelection((Widget)hw, atoms[i], CurrentTime,
+ (XtConvertSelectionProc )ConvertSelection,
+ (XtLoseSelectionProc )LoseSelection,
+ (XtSelectionDoneProc )SelectionDone);
+ }
+ }
+ free((char *)atoms);
+}
+
+
+/*
+ * Convenience function to return the text of the HTML document as a single
+ * white space separated string, with pointers to the various start and
+ * end points of selections.
+ * This function allocates memory for the returned string, that it is up
+ * to the user to free.
+ */
+char *
+#ifdef _NO_PROTO
+HTMLGetTextAndSelection (w, startp, endp, insertp)
+ Widget w;
+ char **startp;
+ char **endp;
+ char **insertp;
+#else
+HTMLGetTextAndSelection(Widget w, char **startp, char **endp, char **insertp)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ int length;
+ char *text;
+ char *tptr;
+ struct ele_rec *eptr;
+ struct ele_rec *sel_start;
+ struct ele_rec *sel_end;
+ struct ele_rec *insert_start;
+ int start_pos, end_pos, insert_pos;
+
+ if (SwapElements(hw->html.select_start, hw->html.select_end,
+ hw->html.sel_start_pos, hw->html.sel_end_pos))
+ {
+ sel_end = hw->html.select_start;
+ end_pos = hw->html.sel_start_pos;
+ sel_start = hw->html.select_end;
+ start_pos = hw->html.sel_end_pos;
+ }
+ else
+ {
+ sel_start = hw->html.select_start;
+ start_pos = hw->html.sel_start_pos;
+ sel_end = hw->html.select_end;
+ end_pos = hw->html.sel_end_pos;
+ }
+
+ insert_start = hw->html.new_start;
+ insert_pos = hw->html.new_start_pos;
+ *startp = NULL;
+ *endp = NULL;
+ *insertp = NULL;
+
+ length = 0;
+
+ eptr = hw->html.formatted_elements;
+ while (eptr != NULL)
+ {
+ /*
+ * Skip the special internal text
+ */
+ if (eptr->internal == True)
+ {
+ eptr = eptr->next;
+ continue;
+ }
+
+ if (eptr->type == E_TEXT)
+ {
+ length = length + eptr->edata_len - 1;
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ length = length + 1;
+ }
+ eptr = eptr->next;
+ }
+
+ text = (char *)malloc(length + 1);
+ if (text == NULL)
+ {
+ fprintf(stderr, "No space for return string\n");
+ return(NULL);
+ }
+ strcpy(text, "");
+
+ tptr = text;
+
+ eptr = hw->html.formatted_elements;
+ while (eptr != NULL)
+ {
+ /*
+ * Skip the special internal text
+ */
+ if (eptr->internal == True)
+ {
+ eptr = eptr->next;
+ continue;
+ }
+
+ if (eptr->type == E_TEXT)
+ {
+ if (eptr == sel_start)
+ {
+ *startp = (char *)(tptr + start_pos);
+ }
+
+ if (eptr == sel_end)
+ {
+ *endp = (char *)(tptr + end_pos);
+ }
+
+ if (eptr == insert_start)
+ {
+ *insertp = (char *)(tptr + insert_pos);
+ }
+
+ strcat(text, (char *)eptr->edata);
+ tptr = tptr + eptr->edata_len - 1;
+ }
+ else if (eptr->type == E_LINEFEED)
+ {
+ if (eptr == sel_start)
+ {
+ *startp = tptr;
+ }
+
+ if (eptr == sel_end)
+ {
+ *endp = tptr;
+ }
+
+ if (eptr == insert_start)
+ {
+ *insertp = tptr;
+ }
+
+ strcat(text, " ");
+ tptr = tptr + 1;
+ }
+ eptr = eptr->next;
+ }
+ return(text);
+}
+
+
+/*
+ * Convenience function to set the raw text into the widget.
+ * Forces a reparse and a reformat.
+ * If any pointer is passed in as NULL that text is unchanged,
+ * if a pointer points to an empty string, that text is set to NULL;
+ * Also pass an element ID to set the view area to that section of the new
+ * text. Finally pass an anchor NAME to set position of the new text
+ * to that anchor.
+ */
+void
+#ifdef _NO_PROTO
+HTMLSetText (w, text, header_text, footer_text, element_id, target_anchor, ptr)
+ Widget w;
+ char *text;
+ char *header_text;
+ char *footer_text;
+ int element_id;
+ char *target_anchor;
+ void *ptr;
+#else
+HTMLSetText(Widget w, char *text, char *header_text, char *footer_text, int element_id, char *target_anchor, void *ptr)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ WidgetInfo *wptr = (WidgetInfo *)ptr;
+ struct ele_rec *start;
+ struct ele_rec *eptr;
+ int newy;
+
+ if ((text == NULL)&&(header_text == NULL)&&(footer_text == NULL))
+ {
+ return;
+ }
+
+ /*
+ * Free up the old visited href list.
+ */
+ FreeHRefs(hw->html.my_visited_hrefs);
+ hw->html.my_visited_hrefs = NULL;
+
+ /*
+ * Free up the old visited delayed images list.
+ */
+ FreeDelayedImages(hw->html.my_delayed_images);
+ hw->html.my_delayed_images = NULL;
+
+ /*
+ * Hide any old widgets
+ */
+ HideWidgets(hw);
+ hw->html.widget_list = wptr;
+ hw->html.form_list = NULL;
+
+ if (text != NULL)
+ {
+ if (*text == '\0')
+ {
+ text = NULL;
+ }
+ hw->html.raw_text = text;
+
+ /*
+ * Free any old colors and pixmaps
+ */
+ FreeColors(XtDisplay(hw),DefaultColormapOfScreen(XtScreen(hw)));
+ FreeImages(hw);
+
+ /*
+ * Parse the raw text with the HTML parser
+ */
+ hw->html.html_objects = HTMLParse(hw->html.html_objects,
+ hw->html.raw_text);
+ CallLinkCallbacks(hw);
+ }
+ if (header_text != NULL)
+ {
+ if (*header_text == '\0')
+ {
+ header_text = NULL;
+ }
+ hw->html.header_text = header_text;
+
+ /*
+ * Parse the header text with the HTML parser
+ */
+ hw->html.html_header_objects =
+ HTMLParse(hw->html.html_header_objects,
+ hw->html.header_text);
+ }
+ if (footer_text != NULL)
+ {
+ if (*footer_text == '\0')
+ {
+ footer_text = NULL;
+ }
+ hw->html.footer_text = footer_text;
+
+ /*
+ * Parse the footer text with the HTML parser
+ */
+ hw->html.html_footer_objects =
+ HTMLParse(hw->html.html_footer_objects,
+ hw->html.footer_text);
+ }
+
+ /*
+ * Reformat the new text
+ */
+ hw->html.max_pre_width = DocumentWidth(hw, hw->html.html_objects);
+ ReformatWindow(hw);
+
+ /*
+ * If a target anchor is passed, override the element id
+ * with the id of that anchor.
+ */
+ if (target_anchor != NULL)
+ {
+ int id;
+
+ id = HTMLAnchorToId(w, target_anchor);
+ if (id != 0)
+ {
+ element_id = id;
+ }
+ }
+
+ /*
+ * Position text at id specified, or at top if no position
+ * specified.
+ * Find the element corrsponding to the id passed in.
+ */
+ eptr = NULL;
+ if (element_id != 0)
+ {
+ start = hw->html.formatted_elements;
+ while (start != NULL)
+ {
+ if (start->ele_id == element_id)
+ {
+ eptr = start;
+ break;
+ }
+ start = start->next;
+ }
+ }
+ if (eptr == NULL)
+ {
+ newy = 0;
+ }
+ else
+ {
+ newy = eptr->y - 2;
+ }
+ if (newy < 0)
+ {
+ newy = 0;
+ }
+ if (newy > (hw->html.doc_height - (int)hw->html.view_height))
+ {
+ newy = hw->html.doc_height - (int)hw->html.view_height;
+ }
+ if (newy < 0)
+ {
+ newy = 0;
+ }
+ hw->html.scroll_x = 0;
+ hw->html.scroll_y = newy;
+#ifdef DEBUG
+fprintf (stderr, "calling in HTMLSetText\n");
+#endif
+ ConfigScrollBars(hw);
+ ScrollWidgets(hw);
+
+ /*
+ * Display the new text
+ */
+ ViewClearAndRefresh(hw);
+
+ /*
+ * Clear any previous selection
+ */
+ hw->html.select_start = NULL;
+ hw->html.select_end = NULL;
+ hw->html.sel_start_pos = 0;
+ hw->html.sel_end_pos = 0;
+ hw->html.new_start = NULL;
+ hw->html.new_end = NULL;
+ hw->html.new_start_pos = 0;
+ hw->html.new_end_pos = 0;
+ hw->html.active_anchor = NULL;
+
+ hw->html.cached_tracked_ele = NULL;
+}
+
+
+/*
+ * To use faster TOLOWER as set up in HTMLparse.c
+ */
+#ifdef NOT_ASCII
+#define TOLOWER(x) (tolower(x))
+#else
+extern char map_table[];
+#define TOLOWER(x) (map_table[x])
+#endif /* NOT_ASCII */
+
+
+/*
+ * Convenience function to search the text of the HTML document as a single
+ * white space separated string. Linefeeds are converted into spaces.
+ *
+ * Takes a pattern, pointers to the start and end blocks to store the
+ * start and end of the match into. Start is also used as the location to
+ * start the search from for incremental searching. If start is an invalid
+ * position (id = 0). Default start is the beginning of the document for
+ * forward searching, and the end of the document for backwards searching.
+ * The backward and caseless parameters I hope are self-explanatory.
+ *
+ * returns 1 on success
+ * (and the start and end positions of the match).
+ * returns -1 otherwise (and start and end are unchanged).
+ */
+int
+#ifdef _NO_PROTO
+HTMLSearchText (w, pattern, m_start, m_end, backward, caseless)
+ Widget w;
+ char *pattern;
+ ElementRef *m_start;
+ ElementRef *m_end;
+ int backward;
+ int caseless;
+#else
+HTMLSearchText (Widget w, char *pattern, ElementRef *m_start, ElementRef *m_end,
+ int backward, int caseless)
+#endif
+{
+ HTMLWidget hw = (HTMLWidget)w;
+ int found, equal;
+ char *match;
+ char *tptr;
+ char *mptr;
+ char cval;
+ struct ele_rec *eptr;
+ int s_pos;
+ struct ele_rec *s_eptr;
+ ElementRef s_ref, e_ref;
+ ElementRef *start, *end;
+
+ /*
+ * If bad parameters are passed, just fail the search
+ */
+ if ((pattern == NULL)||(*pattern == '\0')||
+ (m_start == NULL)||(m_end == NULL)) {
+ return(-1);
+ }
+
+ /*
+ * If we are caseless, make a lower case copy of the pattern to
+ * match to use in compares.
+ *
+ * remember to free this before returning
+ */
+ if (caseless) {
+ match = (char *)malloc(strlen(pattern) + 1);
+ tptr = pattern;
+ mptr = match;
+ while (*tptr != '\0') {
+ *mptr = (char)TOLOWER((int)*tptr);
+ mptr++;
+ tptr++;
+ }
+ *mptr = '\0';
+ } else {
+ match = pattern;
+ }
+
+ /*
+ * Slimy coding. I later decided I didn't want to change start and
+ * end if the search failed. Rather than changing all the code,
+ * I just copy it into locals here, and copy it out again if a match
+ * is found.
+ */
+ start = &s_ref;
+ end = &e_ref;
+ start->id = m_start->id;
+ start->pos = m_start->pos;
+ end->id = m_end->id;
+ end->pos = m_end->pos;
+
+ /*
+ * Find the user specified start position.
+ */
+ if (start->id > 0) {
+ found = 0;
+ eptr = hw->html.formatted_elements;
+
+ while (eptr != NULL) {
+/* if (eptr->ele_id > start->id) {*/ /* MF031 */
+ if ((!backward && eptr->ele_id > start->id) ||
+ ( backward && eptr->ele_id == start->id)) {
+ s_eptr = eptr;
+ found = 1;
+ break;
+ }
+ eptr = eptr->next;
+ }
+ /*
+ * Bad start position, fail them out.
+ */
+ if (!found) {
+ if (caseless) {
+ free(match);
+ }
+ return(-1);
+ }
+ /*
+ * Sanify the start position
+ */
+ s_pos = start->pos;
+ if (s_pos >= s_eptr->edata_len - 1) {
+ s_pos = s_eptr->edata_len - 2;
+ }
+ if (s_pos < 0) {
+ s_pos = 0;
+ }
+
+ } else {
+ /*
+ * Default search starts at end for backward, and
+ * beginning for forwards.
+ */
+ if (backward) {
+ s_eptr = hw->html.formatted_elements;
+ while (s_eptr->next != NULL) {
+ s_eptr = s_eptr->next;
+ }
+ s_pos = s_eptr->edata_len - 2;
+ } else {
+ s_eptr = hw->html.formatted_elements;
+ s_pos = 0;
+ }
+ }
+
+ if (backward) {
+ char *mend;
+
+ /*
+ * Save the end of match here for easy end to start searching
+ */
+ mend = match;
+ while (*mend != '\0') {
+ mend++;
+ }
+ if (mend > match) {
+ mend--;
+ }
+ found = 0;
+ equal = 0;
+ mptr = mend;
+
+ if (s_eptr != NULL) {
+ eptr = s_eptr;
+ } else {
+ eptr = hw->html.formatted_elements;
+ while (eptr->next != NULL) {
+ eptr = eptr->next;
+ }
+ }
+
+ while (eptr != NULL) {
+ /*
+ * Skip the special internal text
+ */
+ if (eptr->internal == True) {
+ eptr = eptr->prev;
+ continue;
+ }
+
+ if (eptr->type == E_TEXT) {
+ tptr = (char *)(eptr->edata + eptr->edata_len - 2);
+ if (eptr == s_eptr) {
+ tptr = (char *)(eptr->edata + s_pos);
+ }
+ while (tptr >= eptr->edata) {
+ if (equal) {
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ while ((mptr >= match)&&
+ (tptr >= eptr->edata)&&
+ (cval == *mptr))
+ {
+ tptr--;
+ mptr--;
+ if (tptr >= eptr->edata) {
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ }
+ }
+ if (mptr < match) {
+ found = 1;
+ start->id = eptr->ele_id;
+ start->pos = (int)
+ (tptr - eptr->edata + 1);
+ break;
+ } else if (tptr < eptr->edata) {
+ break;
+ } else {
+ equal = 0;
+ }
+ } else {
+ mptr = mend;
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ while ((tptr >= eptr->edata)&&
+ (cval != *mptr))
+ {
+ tptr--;
+ if (tptr >= eptr->edata) {
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ }
+ }
+ if ((tptr >= eptr->edata)&&
+ (cval == *mptr))
+ {
+ equal = 1;
+ end->id = eptr->ele_id;
+ end->pos = (int)
+ (tptr - eptr->edata + 1);
+ }
+ }
+ }
+ }
+ /*
+ * Linefeeds match to single space characters.
+ */
+ else if (eptr->type == E_LINEFEED) {
+ if (equal) {
+ if (*mptr == ' ') {
+ mptr--;
+ if (mptr < match) {
+ found = 1;
+ start->id =eptr->ele_id;
+ start->pos = 0;
+ }
+ } else {
+ equal = 0;
+ }
+ } else {
+ mptr = mend;
+ if (*mptr == ' ') {
+ equal = 1;
+ end->id = eptr->ele_id;
+ end->pos = 0;
+ mptr--;
+ if (mptr < match) {
+ found = 1;
+ start->id =eptr->ele_id;
+ start->pos = 0;
+ }
+ }
+ }
+ }
+ if (found) {
+ break;
+ }
+ eptr = eptr->prev;
+ }
+ }
+ else /* forward */
+ {
+ found = 0;
+ equal = 0;
+ mptr = match;
+
+ if (s_eptr != NULL) {
+ eptr = s_eptr;
+ } else {
+ eptr = hw->html.formatted_elements;
+ }
+
+ while (eptr != NULL) {
+ /*
+ * Skip the special internal text
+ */
+ if (eptr->internal == True) {
+ eptr = eptr->next;
+ continue;
+ }
+
+ if (eptr->type == E_TEXT) {
+ tptr = eptr->edata;
+ if (eptr == s_eptr) {
+ tptr = (char *)(tptr + s_pos);
+ }
+ while (*tptr != '\0') {
+ if (equal) {
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ while ((*mptr != '\0')&&
+ (cval == *mptr))
+ {
+ tptr++;
+ mptr++;
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ }
+ if (*mptr == '\0') {
+ found = 1;
+ end->id = eptr->ele_id;
+ end->pos = (int)
+ (tptr - eptr->edata);
+ break;
+ } else if (*tptr == '\0') {
+ break;
+ } else {
+ equal = 0;
+ }
+ } else {
+ mptr = match;
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ while ((*tptr != '\0')&&
+ (cval != *mptr))
+ {
+ tptr++;
+ if (caseless) {
+ cval =(char)TOLOWER((int)*tptr);
+ } else {
+ cval = *tptr;
+ }
+ }
+ if (cval == *mptr) {
+ equal = 1;
+ start->id = eptr->ele_id;
+ start->pos = (int)
+ (tptr - eptr->edata);
+ }
+ }
+ }
+ }
+ else if (eptr->type == E_LINEFEED) {
+ if (equal) {
+ if (*mptr == ' ') {
+ mptr++;
+ if (*mptr == '\0') {
+ found = 1;
+ end->id = eptr->ele_id;
+ end->pos = 0;
+ }
+ } else {
+ equal = 0;
+ }
+ } else {
+ mptr = match;
+ if (*mptr == ' ') {
+ equal = 1;
+ start->id = eptr->ele_id;
+ start->pos = 0;
+ mptr++;
+ if (*mptr == '\0') {
+ found = 1;
+ end->id = eptr->ele_id;
+ end->pos = 0;
+ }
+ }
+ }
+ }
+ if (found) {
+ break;
+ }
+ eptr = eptr->next;
+ }
+ }
+
+ if (found) {
+ m_start->id = start->id;
+ m_start->pos = start->pos;
+ m_end->id = end->id;
+ m_end->pos = end->pos;
+ }
+
+ if (caseless) {
+ free(match);
+ }
+
+ if (found) {
+ return(1);
+ } else {
+ return(-1);
+ }
+}