7139 lines
158 KiB
C
7139 lines
158 KiB
C
/****************************************************************************
|
|
* 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 "../config.h"
|
|
#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>
|
|
|
|
#include "../libnut/system.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 FreeBodyImages();
|
|
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();
|
|
extern void traversal_back(); /* these are in HTMLwidgets.c */
|
|
extern void traversal_forward();
|
|
extern void traversal_end();
|
|
extern void traversal_current();
|
|
|
|
void DebugHook();
|
|
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 Boolean html_accept_focus();
|
|
|
|
#ifdef _NO_PROTO
|
|
static void _HTMLInput() ;
|
|
#ifndef MOTIF
|
|
static void _HTMLpwdInput() ;
|
|
#endif
|
|
static void Initialize() ;
|
|
static void Redisplay() ;
|
|
static void Resize() ;
|
|
static Boolean SetValues() ;
|
|
static XtGeometryResult GeometryManager() ;
|
|
static void RecolorInternalHRefs() ;
|
|
static Dimension VbarWidth();
|
|
static Dimension HbarHeight();
|
|
static void ViewRedisplay();
|
|
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 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);
|
|
void ViewClearAndRefresh(HTMLWidget hw);
|
|
static void CallLinkCallbacks(HTMLWidget hw);
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
char CurrentURL[8096]; /*if url bigger than this...too bad*/
|
|
|
|
#ifndef DISABLE_TRACE
|
|
int htmlwTrace;
|
|
#endif
|
|
|
|
/* for selective image loading */
|
|
extern Boolean currently_delaying_images;
|
|
|
|
/*
|
|
* Default translations
|
|
* Selection of text, and activate anchors.
|
|
* If motif, add manager translations.
|
|
* 4/5/96 TPR added traversal_current to make sure if user presses
|
|
* button in view the hotkeys get control.
|
|
*/
|
|
#ifdef MOTIF
|
|
static char defaultTranslations[] =
|
|
" \
|
|
<Btn1Down>: select-start() ManagerGadgetArm()\n\
|
|
<Btn1Motion>: extend-adjust() ManagerGadgetButtonMotion()\n\
|
|
<Btn1Up>: extend-end(PRIMARY, CUT_BUFFER0) ManagerGadgetActivate() traversal_current()\n\
|
|
<Btn2Down>: select-start()\n\
|
|
<Btn2Motion>: extend-adjust()\n\
|
|
<Btn2Up>: extend-end(PRIMARY, CUT_BUFFER0)\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) traversal_current()\n\
|
|
<Btn2Down>: select-start() \n\
|
|
<Btn2Motion>: extend-adjust() \n\
|
|
<Btn2Up>: extend-end(PRIMARY, CUT_BUFFER0) \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 },
|
|
{ "HTMLInput", (XtActionProc) _HTMLInput },
|
|
{ "traversal_back", (XtActionProc) traversal_back },
|
|
{ "traversal_forward", (XtActionProc) traversal_forward },
|
|
{ "traversal_end", (XtActionProc) traversal_end },
|
|
{ "traversal_current", (XtActionProc) traversal_current },
|
|
#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 },
|
|
{ "HTMLInput", (XtActionProc) _HTMLInput },
|
|
{ "traversal_back", (XtActionProc) traversal_back },
|
|
{ "traversal_forward", (XtActionProc) traversal_forward },
|
|
{ "traversal_end", (XtActionProc) traversal_end },
|
|
{ "traversal_current", (XtActionProc) traversal_current },
|
|
#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
|
|
|
|
{ WbNbodyColors,
|
|
WbCBodyColors, XtRBoolean, sizeof (Boolean),
|
|
XtOffset (HTMLWidget, html.body_colors),
|
|
XtRString, "True"
|
|
},
|
|
|
|
{ WbNbodyImages,
|
|
WbCBodyImages, XtRBoolean, sizeof (Boolean),
|
|
XtOffset (HTMLWidget, html.body_images),
|
|
XtRString, "True"
|
|
},
|
|
|
|
{ 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-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNmeterFont,
|
|
WbCMeterFont, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.meter_font),
|
|
XtRString, "-adobe-courier-bold-r-normal-*-14-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNtoolbarFont,
|
|
WbCToolbarFont, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.toolbar_font),
|
|
XtRString, "-adobe-times-bold-r-normal-*-12-*-*-*-*-*-iso8859-1"
|
|
},
|
|
|
|
{ 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-*-*-*-*-*-*-*"
|
|
},
|
|
/* amb */
|
|
{ WbNsupSubFont,
|
|
WbCSupSubFont, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.supsub_font),
|
|
XtRString, "-adobe-courier-medium-r-normal-*-10-*-*-*-*-*-*-*"
|
|
},
|
|
/* end amb */
|
|
{ WbNpreviouslyVisitedTestFunction,
|
|
WbCPreviouslyVisitedTestFunction, XtRPointer,
|
|
sizeof (XtPointer),
|
|
XtOffset (HTMLWidget, html.previously_visited_test),
|
|
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
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
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 */
|
|
XtInheritRealize, /* 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 */
|
|
(XtAcceptFocusProc) html_accept_focus, /* 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 */
|
|
}
|
|
};
|
|
|
|
|
|
extern int hacked_width;
|
|
extern int hacked_height;
|
|
extern int hacked_x;
|
|
extern int hacked_y;
|
|
|
|
|
|
WidgetClass htmlWidgetClass = (WidgetClass)&htmlClassRec;
|
|
|
|
static Cursor in_anchor_cursor = (Cursor)NULL;
|
|
static char *mailToKludgeSubject = NULL;
|
|
static char *mailToKludgeURL = NULL;
|
|
|
|
char *cattrs[]={"text","bgcolor","alink","vlink","link",NULL};
|
|
|
|
int installed_colormap=0;
|
|
Colormap installed_cmap;
|
|
|
|
int NoBodyColors(Widget w) {
|
|
|
|
HTMLWidget hw = (HTMLWidget) w;
|
|
|
|
if (hw->html.body_colors) {
|
|
return(0);
|
|
}
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
int InitBody(Widget w) {
|
|
|
|
HTMLWidget hw = (HTMLWidget) w;
|
|
unsigned long valuemask;
|
|
XGCValues values;
|
|
|
|
hw->html.bg_image=0;
|
|
hw->html.bgmap_SAVE=None;
|
|
hw->html.bgclip_SAVE=None;
|
|
|
|
if (NoBodyImages(hw)) {
|
|
return;
|
|
}
|
|
|
|
/* ??? Why is this here? */
|
|
hw->html.view->core.background_pixel = hw->html.background_SAVE ;
|
|
|
|
return;
|
|
}
|
|
|
|
int NoBodyImages(Widget w) {
|
|
|
|
HTMLWidget hw = (HTMLWidget) w;
|
|
|
|
if (hw->html.body_images) {
|
|
return(0);
|
|
}
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
hw_do_bg(Widget w, char *bgname) {
|
|
|
|
ImageInfo *pic_data;
|
|
HTMLWidget hw=(HTMLWidget) w;
|
|
unsigned long valuemask;
|
|
XGCValues values;
|
|
|
|
if (!bgname || !*bgname || !(hw->html.drawGC)) {
|
|
return;
|
|
}
|
|
|
|
if (hw->html.delay_images==True || currently_delaying_images==1) {
|
|
pic_data = (*(resolveImageProc)(hw->html.resolveImage)
|
|
)(hw, bgname, 1, NULL, NULL);
|
|
if (pic_data!=NULL) { /*it was cached*/
|
|
/* Plop the background image here */
|
|
pic_data->image=InfoToImage(hw,pic_data,0);
|
|
pic_data->transparent=0;
|
|
pic_data->clip=None;
|
|
hw->html.bg_image=1;
|
|
hw->html.bg_height=pic_data->height;
|
|
hw->html.bg_width=pic_data->width;
|
|
hw->html.bgmap_SAVE=pic_data->image;
|
|
hw->html.bgclip_SAVE=pic_data->clip;
|
|
}
|
|
else { /*not cached*/
|
|
hw->html.bg_image=0;
|
|
hw->html.bgmap_SAVE=None;
|
|
hw->html.bgclip_SAVE=None;
|
|
}
|
|
}
|
|
else { /*loading images*/
|
|
pic_data = (*(resolveImageProc)(hw->html.resolveImage)
|
|
)(hw, bgname, 0, NULL, NULL);
|
|
if (pic_data!=NULL) { /*it was cached or downloaded*/
|
|
/* Plop the background image here */
|
|
pic_data->image=InfoToImage(hw,pic_data,0);
|
|
pic_data->transparent=0;
|
|
pic_data->clip=None;
|
|
hw->html.bg_image=1;
|
|
hw->html.bg_height=pic_data->height;
|
|
hw->html.bg_width=pic_data->width;
|
|
hw->html.bgmap_SAVE=pic_data->image;
|
|
hw->html.bgclip_SAVE=pic_data->clip;
|
|
}
|
|
else { /*bad image*/
|
|
hw->html.bg_image=0;
|
|
hw->html.bgmap_SAVE=None;
|
|
hw->html.bgclip_SAVE=None;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
hw_do_color(Widget w, char *att, char *cname)
|
|
{
|
|
int r,g,b;
|
|
XColor ecol,col;
|
|
XColor fg,sel,ts,bs;
|
|
XmColorProc calc;
|
|
Colormap cmap;
|
|
HTMLWidget hw = (HTMLWidget) w;
|
|
char *p,*val,*ptr;
|
|
char t[3];
|
|
int allocated=0;
|
|
int i;
|
|
|
|
if (!att || !*att || !cname || !*cname) {
|
|
return;
|
|
}
|
|
|
|
cmap = hw->core.colormap;
|
|
|
|
val=cname;
|
|
if (*val!='#') {
|
|
if (XAllocNamedColor(XtDisplay(w),cmap,cname,&col,&ecol)) {
|
|
allocated=1;
|
|
}
|
|
}
|
|
|
|
if(!allocated){
|
|
if(*val=='#') val++;
|
|
if (!*val) {
|
|
return;
|
|
}
|
|
|
|
if (strlen(val)>=6) {
|
|
/* Must be valid hex */
|
|
for (i=0; i<6; i++) {
|
|
if (!strchr("0123456789AaBbCcDdEeFf",val[i])) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
t[2]=0;
|
|
t[0]=val[0];
|
|
t[1]=val[1];
|
|
sscanf(t,"%x",&r);
|
|
t[0]=val[2];
|
|
t[1]=val[3];
|
|
sscanf(t,"%x",&g);
|
|
t[0]=val[4];
|
|
t[1]=val[5];
|
|
sscanf(t,"%x",&b);
|
|
|
|
col.red = ((unsigned) r) << 8;
|
|
col.green = ((unsigned) g) << 8;
|
|
col.blue = ((unsigned) b) << 8;
|
|
col.flags = DoRed | DoGreen | DoBlue;
|
|
|
|
if (!XAllocColor(XtDisplay(w),cmap,&col)) {
|
|
return;
|
|
}
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (!my_strcasecmp(att,"text")) {
|
|
hw->manager.foreground = col.pixel;
|
|
}
|
|
if (!my_strcasecmp(att,"bgcolor")){
|
|
/* calculate shadow colors */
|
|
calc = XmGetColorCalculation();
|
|
calc(&col, &fg, &sel, &ts, &bs);
|
|
if (XAllocColor(XtDisplay(w),cmap,&ts))
|
|
hw->manager.top_shadow_color = ts.pixel;
|
|
if (XAllocColor(XtDisplay(w),cmap,&bs))
|
|
hw->manager.bottom_shadow_color = bs.pixel;
|
|
|
|
hw->core.background_pixel = col.pixel;
|
|
hw->html.view->core.background_pixel = col.pixel ;
|
|
hw->html.activeAnchor_bg = col.pixel;
|
|
}
|
|
if (!my_strcasecmp(att,"link")) {
|
|
hw->html.anchor_fg = col.pixel;
|
|
}
|
|
if (!my_strcasecmp(att,"vlink")) {
|
|
hw->html.visitedAnchor_fg = col.pixel;
|
|
}
|
|
if (!my_strcasecmp(att,"alink")) {
|
|
hw->html.activeAnchor_fg = col.pixel;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
CreateOrNotGC(hw)
|
|
HTMLWidget hw;
|
|
{
|
|
|
|
unsigned long valuemask;
|
|
XGCValues values;
|
|
|
|
if (hw->html.drawGC==NULL) {
|
|
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;
|
|
|
|
values.fill_style = FillSolid;
|
|
|
|
valuemask = GCFunction|GCPlaneMask|GCForeground|GCBackground|
|
|
GCFillStyle;
|
|
|
|
hw->html.drawGC = XCreateGC(XtDisplay(hw),
|
|
XtWindow(hw->html.view),
|
|
valuemask,
|
|
&values);
|
|
}
|
|
}
|
|
|
|
|
|
#define MAX_Y_EXP_DIFF 10 /*pixels between exposes to make one expose area*/
|
|
|
|
/*
|
|
* 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;
|
|
{
|
|
|
|
XEvent NewEvent;
|
|
HTMLWidget hw = (HTMLWidget)data;
|
|
int x, y, x1, y1;
|
|
int width, height;
|
|
int nx, ny, nwidth, nheight;
|
|
Display *dsp;
|
|
Window win;
|
|
int changed=0;
|
|
|
|
if (!(event->xany.type==Expose ||
|
|
/*
|
|
(hw->html.obscured && event->xany.type==GraphicsExpose) ||
|
|
*/
|
|
(event->xany.type==GraphicsExpose) ||
|
|
event->xany.type==VisibilityNotify)) {
|
|
return;
|
|
}
|
|
|
|
if (event->xany.type==VisibilityNotify) {
|
|
if (event->xvisibility.state==VisibilityUnobscured) {
|
|
hw->html.obscured=0;
|
|
}
|
|
else {
|
|
hw->html.obscured=1;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Make sure we have a valid GC to draw with.
|
|
*/
|
|
CreateOrNotGC(hw);
|
|
|
|
if (event->xany.type==Expose) {
|
|
x = event->xexpose.x;
|
|
y = event->xexpose.y;
|
|
width = event->xexpose.width;
|
|
height = event->xexpose.height;
|
|
}
|
|
else {
|
|
x = event->xgraphicsexpose.x;
|
|
y = event->xgraphicsexpose.y;
|
|
width = event->xgraphicsexpose.width;
|
|
height = event->xgraphicsexpose.height;
|
|
}
|
|
|
|
/*
|
|
goto single_expose;
|
|
*/
|
|
|
|
/*
|
|
* Get rid of any extra expose events.
|
|
* Be sure to get the entire area of exposure.
|
|
*/
|
|
|
|
dsp=XtDisplay(w);
|
|
win=XtWindow(w);
|
|
|
|
while (((XCheckWindowEvent(dsp, win,
|
|
ExposureMask|VisibilityChangeMask,
|
|
&NewEvent) == True))) {
|
|
if (NewEvent.xany.type==Expose ||
|
|
/*
|
|
(hw->html.obscured && NewEvent.xany.type==GraphicsExpose) ||
|
|
*/
|
|
(NewEvent.xany.type==GraphicsExpose) ||
|
|
NewEvent.xany.type==VisibilityNotify) {
|
|
|
|
if (NewEvent.xany.type==VisibilityNotify) {
|
|
if (NewEvent.xvisibility.state==VisibilityUnobscured) {
|
|
hw->html.obscured=0;
|
|
}
|
|
else {
|
|
hw->html.obscured=1;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (NewEvent.xany.type==Expose) {
|
|
nx = NewEvent.xexpose.x;
|
|
ny = NewEvent.xexpose.y;
|
|
nwidth = NewEvent.xexpose.width;
|
|
nheight = NewEvent.xexpose.height;
|
|
}
|
|
else {
|
|
nx = NewEvent.xgraphicsexpose.x;
|
|
ny = NewEvent.xgraphicsexpose.y;
|
|
nwidth = NewEvent.xgraphicsexpose.width;
|
|
nheight = NewEvent.xgraphicsexpose.height;
|
|
}
|
|
|
|
if (width==(-666) && height==(-666)) {
|
|
x = nx;
|
|
y = ny;
|
|
width = nwidth;
|
|
height = nheight;
|
|
|
|
continue;
|
|
}
|
|
|
|
x1 = x + width;
|
|
y1 = y + height;
|
|
|
|
/* The following block makes sure the exposure area is not
|
|
incredibly HUGE...like one widget at the top and another
|
|
at the bottom causing the whole page to be drawn over and
|
|
over. --SWP */
|
|
if ((y>(ny+nheight) &&
|
|
(y-(ny+nheight))>MAX_Y_EXP_DIFF) ||
|
|
(y1<ny &&
|
|
(ny-y1)>MAX_Y_EXP_DIFF)) {
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
DebugHook(x, y, width, height);
|
|
}
|
|
#endif
|
|
|
|
ViewRedisplay(hw, x, y, width, height);
|
|
width=height=(-666);
|
|
|
|
continue;
|
|
}
|
|
|
|
if (x > nx) {
|
|
x = nx;
|
|
changed=1;
|
|
}
|
|
|
|
if (y > ny) {
|
|
y = ny;
|
|
changed=1;
|
|
}
|
|
|
|
if (x1 < (nx + nwidth)) {
|
|
x1 = nx + nwidth;
|
|
changed=1;
|
|
}
|
|
|
|
if (y1 < (ny + nheight)) {
|
|
y1 = ny + nheight;
|
|
changed=1;
|
|
}
|
|
|
|
/* The following is to create a clip_mask for the gc which
|
|
will insure that nothing is drawn that does not need to
|
|
be drawn. Also changes appear in ViewRedisplay. --SWP */
|
|
if (changed) {
|
|
width = x1 - x;
|
|
height = y1 - y;
|
|
changed=0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
single_expose:
|
|
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
DebugHook(x, y, width, height);
|
|
}
|
|
#endif
|
|
|
|
/* Let's actually do the draw... --SWP */
|
|
ViewRedisplay(hw, x, y, width, height);
|
|
}
|
|
|
|
|
|
void ResetWidgetsOnResize(hw)
|
|
HTMLWidget hw;
|
|
{
|
|
WidgetInfo *wptr;
|
|
int xval, yval;
|
|
|
|
wptr = hw->html.widget_list;
|
|
while (wptr != NULL)
|
|
{
|
|
if (wptr->w != NULL)
|
|
{
|
|
wptr->seeable=1;
|
|
}
|
|
wptr = wptr->next;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
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-xval;
|
|
y = wptr->y-yval;
|
|
|
|
/*
|
|
* lower_right on screen?
|
|
* lower_left on screen?
|
|
* upper_right on screen?
|
|
* upper_left on screen?
|
|
*
|
|
* if any of the above, move the widget, otherwise
|
|
* it is not "seeable". Incredible speed for many
|
|
* widget pages.
|
|
*
|
|
* SWP and TPR
|
|
*/
|
|
|
|
if (((y>0 &&
|
|
y<=hw->html.view_height) ||
|
|
((y+wptr->height)>0 &&
|
|
(y+wptr->height)<=hw->html.view_height)) &&
|
|
((x>0 &&
|
|
x<=hw->html.view_width) ||
|
|
((x+wptr->width)>0 &&
|
|
(x+wptr->width)<=hw->html.view_width))) {
|
|
wptr->seeable=1;
|
|
XtMoveWidget(w, x, y);
|
|
}
|
|
else if (wptr->seeable) {
|
|
wptr->seeable=0;
|
|
XtMoveWidget(w, x, y);
|
|
}
|
|
}
|
|
wptr = wptr->next;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
#ifndef MOTIF
|
|
/*
|
|
* Set the Athena Scrollbar's thumb position properly.
|
|
*/
|
|
static void
|
|
setScrollBar(sb, topPosition, totalLength, currentLength)
|
|
Widget sb;
|
|
Position topPosition;
|
|
Dimension totalLength, currentLength;
|
|
{
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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;
|
|
Dimension totalLength, currentLength;
|
|
|
|
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|VisibilityChangeMask, True,
|
|
(XtEventHandler)DrawExpose, (caddr_t)hw);
|
|
hw->html.obscured=0;
|
|
|
|
/*
|
|
* 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
|
|
{
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
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;
|
|
}
|
|
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
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,
|
|
hw->html.view_height);
|
|
#endif /* MOTIF */
|
|
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
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,
|
|
hw->html.view_width);
|
|
#endif /* MOTIF */
|
|
}
|
|
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
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
|
|
*/
|
|
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
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,new);
|
|
CallLinkCallbacks(new);
|
|
new->html.html_header_objects =
|
|
HTMLParse(NULL, request->html.header_text,new);
|
|
new->html.html_footer_objects =
|
|
HTMLParse(NULL, request->html.footer_text,new);
|
|
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;
|
|
|
|
new->html.top_color_SAVE = new->manager.top_shadow_color;
|
|
new->html.bottom_color_SAVE = new->manager.bottom_shadow_color;
|
|
new->html.foreground_SAVE = new->manager.foreground;
|
|
new->html.anchor_fg_SAVE = new->html.anchor_fg;
|
|
new->html.visitedAnchor_fg_SAVE = new->html.visitedAnchor_fg;
|
|
new->html.activeAnchor_fg_SAVE = new->html.activeAnchor_fg;
|
|
new->html.activeAnchor_bg_SAVE = new->html.activeAnchor_bg;
|
|
new->html.background_SAVE = new->core.background_pixel;
|
|
new->html.bgmap_SAVE = None;
|
|
new->html.bgclip_SAVE = None;
|
|
new->html.bg_image=0;
|
|
new->html.focus_follows_mouse=0;
|
|
|
|
/* Initialize cursor used when pointer is inside anchor. */
|
|
if (in_anchor_cursor == (Cursor)NULL)
|
|
in_anchor_cursor = XCreateFontCursor (XtDisplay (new), XC_hand2);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
DebugHook(x, y, width, height)
|
|
int x, y, width, height;
|
|
{
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
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;
|
|
|
|
if(hw->html.bg_image) {
|
|
HTMLDrawBackgroundImage((Widget)hw,
|
|
x,
|
|
y,
|
|
width,
|
|
height);
|
|
}
|
|
|
|
/*
|
|
* 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
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
#ifdef _NO_PROTO
|
|
ViewClearAndRefresh (hw)
|
|
HTMLWidget hw;
|
|
#else
|
|
ViewClearAndRefresh(
|
|
HTMLWidget hw)
|
|
#endif
|
|
{
|
|
int r,b;
|
|
|
|
/*
|
|
* Only refresh if we have a window already.
|
|
* (if we have a GC we have a window)
|
|
*/
|
|
if (hw->html.drawGC != NULL)
|
|
{
|
|
|
|
/* minor trickery to insure that the update happens...*/
|
|
hw->html.view->core.background_pixel =
|
|
hw->core.background_pixel?0:1;
|
|
|
|
r = hw->manager.top_shadow_color;
|
|
b = hw->manager.bottom_shadow_color;
|
|
|
|
hw->manager.top_shadow_color =
|
|
hw->manager.top_shadow_color ? 0 : 1;
|
|
hw->manager.bottom_shadow_color =
|
|
hw->manager.bottom_shadow_color ? 0 : 1;
|
|
|
|
XtVaSetValues(hw->html.view,
|
|
XmNbackground, hw->core.background_pixel,
|
|
XmNtopShadowColor, r,
|
|
XmNbottomShadowColor, b,
|
|
NULL);
|
|
|
|
XtVaSetValues((Widget)hw,
|
|
XmNbackground, hw->core.background_pixel,
|
|
XmNtopShadowColor, r,
|
|
XmNbottomShadowColor, b,
|
|
NULL);
|
|
|
|
XClearArea(XtDisplay(hw), 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->html.view),
|
|
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->html.view),
|
|
*/
|
|
_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;
|
|
|
|
/* Make sure all widgets in HTMLw are moved and redrawn */
|
|
ResetWidgetsOnResize(hw);
|
|
|
|
/*
|
|
* 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);
|
|
}
|
|
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
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);
|
|
}
|
|
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
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), XtWindow(hw->html.view));
|
|
#endif
|
|
XUndefineCursor(XtDisplay(hw), XtWindow(hw->html.view));
|
|
|
|
/*
|
|
* 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)
|
|
{
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
fprintf(stderr, "cannot allocate atom list\n");
|
|
}
|
|
#endif
|
|
|
|
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, ""); \
|
|
XUndefineCursor (XtDisplay (hw), XtWindow (hw->html.view));
|
|
|
|
/* 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((Widget) hw) != 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, eptr->anchorHRef);
|
|
XDefineCursor (XtDisplay (hw), XtWindow (hw->html.view), 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;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We're adding a subject attribute to the anchor tag
|
|
of course this subject attribute is dependent on that the HREF attribute
|
|
is set to a mailto URL. I think this is a kludge. libwww is not set up
|
|
for this, so to minimize modifications, this routine exists for
|
|
libwww:HTSendMaitlTo() to call to get the subject for the mailto URL.
|
|
The static globals mailToKludgeSubject, etc are set in HTMLInput when
|
|
an anchor is clicked.
|
|
*/
|
|
GetMailtoKludgeInfo(url,subject)
|
|
char **url;
|
|
char **subject;
|
|
{
|
|
*url = mailToKludgeURL;
|
|
*subject = mailToKludgeSubject;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* 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;
|
|
|
|
HTMLSetAppInsensitive((Widget) hw);
|
|
|
|
/*
|
|
* 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
|
|
mailToKludgeSubject = eptr->anchorSubject;
|
|
mailToKludgeURL = eptr->anchorHRef;
|
|
|
|
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);
|
|
}
|
|
mailToKludgeSubject = NULL;
|
|
mailToKludgeURL = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
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(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);
|
|
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
fprintf(stderr,"modified passwd <%s>\n", wptr->password);
|
|
}
|
|
#endif
|
|
|
|
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);
|
|
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
fprintf(stderr,"modified passwd <%s>\n", wptr->password);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
#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),
|
|
(installed_colormap ?
|
|
installed_cmap :
|
|
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,new);
|
|
CallLinkCallbacks(new);
|
|
new->html.html_header_objects =
|
|
HTMLParse(current->html.html_header_objects,
|
|
request->html.header_text,new);
|
|
new->html.html_footer_objects =
|
|
HTMLParse(current->html.html_footer_objects,
|
|
request->html.footer_text,new);
|
|
|
|
/*
|
|
* 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;*/
|
|
}
|
|
|
|
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);
|
|
*/
|
|
memcpy((char*)targetP, (char*)std_targets,
|
|
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);
|
|
*/
|
|
memcpy( (char*)*value, ((char*)&temp)+sizeof(long)-4, 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);
|
|
*/
|
|
memcpy( (char*)*value, ((char*)&temp)+sizeof(long)-4, 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, url, time_str)
|
|
Widget w;
|
|
int pretty;
|
|
char *url;
|
|
char *time_str;
|
|
#else
|
|
HTMLGetText(Widget w, int pretty, char *url, char *time_str)
|
|
#endif
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
char *text;
|
|
char *tptr, *buf;
|
|
struct ele_rec *start;
|
|
struct ele_rec *end;
|
|
|
|
if (url && *url) {
|
|
strcpy(CurrentURL,url);
|
|
}
|
|
else {
|
|
sprintf(CurrentURL,"UNKNOWN");
|
|
}
|
|
|
|
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, url, time_str);
|
|
}
|
|
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.
|
|
*/
|
|
/*
|
|
* "correction" is either -1, 0, or 1. These values determine if we are
|
|
* to set the pointer a 1/2 page in the negative or positive direction...or
|
|
* simply leave it alone.
|
|
* --SWP
|
|
*/
|
|
void
|
|
#ifdef _NO_PROTO
|
|
HTMLGotoId(w, element_id, correction)
|
|
Widget w;
|
|
int element_id;
|
|
int correction;
|
|
#else
|
|
HTMLGotoId(Widget w, int element_id, int correction)
|
|
#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
|
|
{
|
|
if (!correction) {
|
|
newy = eptr->y - 2;
|
|
}
|
|
else if (correction<0) { /*"up" a 1/2 page*/
|
|
newy = eptr->y - 2 - ((int)(hw->html.view_height)/2);
|
|
}
|
|
else { /*"down" a 1/2 page*/
|
|
newy = eptr->y - 2 + ((int)(hw->html.view_height)/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,
|
|
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)&&
|
|
(strcmp(start->anchorName, name) == 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);
|
|
}
|
|
}
|
|
else /****** temporary until figure support */
|
|
if (mptr->type == M_FIGURE)
|
|
{
|
|
tptr = ParseMarkTag(mptr->start, MT_FIGURE, "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++;
|
|
}
|
|
}
|
|
else /****** temporary until figure support */
|
|
if (mptr->type == M_FIGURE)
|
|
{
|
|
tptr =ParseMarkTag(mptr->start,MT_FIGURE,"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),
|
|
(installed_colormap ?
|
|
installed_cmap :
|
|
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)
|
|
Widget w;
|
|
visitTestProc testFunc;
|
|
#else
|
|
HTMLRetestAnchors(Widget w, visitTestProc testFunc)
|
|
#endif
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
struct ele_rec *start;
|
|
|
|
if (testFunc == NULL)
|
|
{
|
|
testFunc = (visitTestProc)hw->html.previously_visited_test;
|
|
}
|
|
|
|
/*
|
|
* 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 ((*testFunc)(hw, 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
|
|
*/
|
|
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)
|
|
{
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
fprintf(stderr, "cannot allocate atom list\n");
|
|
}
|
|
#endif
|
|
|
|
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)
|
|
{
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
fprintf(stderr, "No space for return string\n");
|
|
}
|
|
#endif
|
|
|
|
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;
|
|
|
|
/* init the body stuff...just in case they have no body tag */
|
|
InitBody((Widget)hw);
|
|
|
|
/* restore default colors as required */
|
|
|
|
if(hw->manager.foreground != hw->html.foreground_SAVE) {
|
|
XFreeColors(XtDisplay(hw),hw->core.colormap,
|
|
&hw->manager.foreground,1,0);
|
|
hw->manager.foreground = hw->html.foreground_SAVE;
|
|
}
|
|
if(hw->html.anchor_fg != hw->html.anchor_fg_SAVE) {
|
|
XFreeColors(XtDisplay(hw),hw->core.colormap,
|
|
&hw->html.anchor_fg,1,0);
|
|
hw->html.anchor_fg = hw->html.anchor_fg_SAVE;
|
|
}
|
|
if(hw->html.visitedAnchor_fg != hw->html.visitedAnchor_fg_SAVE){
|
|
XFreeColors(XtDisplay(hw),hw->core.colormap,
|
|
&hw->html.visitedAnchor_fg,1,0);
|
|
hw->html.visitedAnchor_fg = hw->html.visitedAnchor_fg_SAVE;
|
|
}
|
|
if(hw->html.activeAnchor_fg != hw->html.activeAnchor_fg_SAVE){
|
|
XFreeColors(XtDisplay(hw),hw->core.colormap,
|
|
&hw->html.activeAnchor_fg,1,0);
|
|
hw->html.activeAnchor_fg = hw->html.activeAnchor_fg_SAVE;
|
|
}
|
|
if(hw->html.top_color_SAVE != hw->manager.top_shadow_color){
|
|
XFreeColors(XtDisplay(hw),hw->core.colormap,
|
|
&hw->manager.top_shadow_color,1,0);
|
|
hw->manager.top_shadow_color = hw->html.top_color_SAVE;
|
|
}
|
|
if(hw->html.bottom_color_SAVE != hw->manager.bottom_shadow_color){
|
|
XFreeColors(XtDisplay(hw),hw->core.colormap,
|
|
&hw->manager.bottom_shadow_color,1,0);
|
|
hw->manager.bottom_shadow_color = hw->html.bottom_color_SAVE;
|
|
}
|
|
if(hw->core.background_pixel != hw->html.background_SAVE){
|
|
XFreeColors(XtDisplay(hw),hw->core.colormap,
|
|
&hw->core.background_pixel,1,0);
|
|
hw->html.activeAnchor_bg = hw->html.activeAnchor_bg_SAVE;
|
|
hw->core.background_pixel = hw->html.background_SAVE;
|
|
hw->html.view->core.background_pixel = hw->html.background_SAVE ;
|
|
}
|
|
/*
|
|
* 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),
|
|
(installed_colormap ?
|
|
installed_cmap :
|
|
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,hw);
|
|
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,hw);
|
|
}
|
|
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,hw);
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
#ifndef DISABLE_TRACE
|
|
if (htmlwTrace) {
|
|
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 unsigned char map_table[];
|
|
#define TOLOWER(x) (map_table[x])
|
|
#endif /* NOT_ASCII */
|
|
|
|
|
|
/*
|
|
* Allows us to jump to the bottom of a document (or very close).
|
|
*/
|
|
int
|
|
#ifdef _NO_PROTO
|
|
HTMLLastId(w)
|
|
Widget w;
|
|
#else
|
|
HTMLLastId(Widget w)
|
|
#endif
|
|
{
|
|
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
struct ele_rec *eptr;
|
|
int Id;
|
|
|
|
if (!w) {
|
|
return(0);
|
|
}
|
|
|
|
eptr=hw->html.formatted_elements;
|
|
Id=eptr->ele_id;
|
|
while (eptr->next != NULL) {
|
|
Id=eptr->ele_id;
|
|
eptr=eptr->next;
|
|
}
|
|
|
|
return(Id);
|
|
}
|
|
|
|
|
|
/*
|
|
* News hack of searching function for HTML widget...only looks for an edata
|
|
* of ">>>" as it will be by itself because the one we are looking for
|
|
* will be enclosed in a <b></b>. This will have to be rewritten when we
|
|
* start using the new parser! --SWP
|
|
*/
|
|
int
|
|
#ifdef _NO_PROTO
|
|
HTMLSearchNews(w, m_start, m_end)
|
|
Widget w;
|
|
ElementRef *m_start;
|
|
ElementRef *m_end;
|
|
#else
|
|
HTMLSearchNews(Widget w, ElementRef *m_start, ElementRef *m_end)
|
|
#endif
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
struct ele_rec *eptr;
|
|
|
|
/*
|
|
* If bad parameters are passed, just fail the search
|
|
*/
|
|
if ((m_start == NULL)||(m_end == NULL)) {
|
|
return(-1);
|
|
}
|
|
|
|
eptr = hw->html.formatted_elements;
|
|
|
|
while (eptr != NULL) {
|
|
if (eptr->internal!=True && eptr->type==E_TEXT) {
|
|
if (eptr->edata && !strcmp(eptr->edata,">>>")) {
|
|
m_start->id = eptr->ele_id;
|
|
m_start->pos = 0;
|
|
m_end->id = eptr->ele_id;
|
|
m_end->pos = 3;
|
|
|
|
return(1);
|
|
}
|
|
}
|
|
eptr=eptr->next;
|
|
}
|
|
|
|
return(-1);
|
|
}
|
|
|
|
|
|
/*
|
|
* 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)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
/* the following is a hack to make the html widget not acknowledge
|
|
any button events while it is busy so that the rbm will not grab the
|
|
server. Hopefully this will be removed when the application is re-written
|
|
to pay more attention to the event loop - TPR 2/9/96 */
|
|
|
|
Window sens_win = (Window)NULL;
|
|
|
|
void HTMLSetAppInsensitive(Widget hw)
|
|
{
|
|
int x, y, width, height;
|
|
|
|
x = hw->core.x;
|
|
y = hw->core.y;
|
|
width = hw->core.width;
|
|
height = hw->core.height;
|
|
|
|
/* ???? Should this be cast to a HTMLWidget and XtWindow changed to html.view*/
|
|
sens_win = XCreateWindow(XtDisplay((Widget) hw), XtWindow(hw), x,
|
|
y, width, height, 0,CopyFromParent, InputOnly,
|
|
CopyFromParent, 0, NULL);
|
|
XMapRaised(XtDisplay((Widget) hw), sens_win);
|
|
}
|
|
|
|
void HTMLSetAppSensitive(Widget hw)
|
|
{
|
|
if(sens_win)
|
|
XDestroyWindow(XtDisplay((Widget) hw), sens_win);
|
|
sens_win = (Window)NULL;
|
|
}
|
|
|
|
/*
|
|
* Original hack by TPR...
|
|
*
|
|
* Fixed up and rewritten by SWP...
|
|
*/
|
|
void HTMLDrawBackgroundImage(Widget wid, int x, int y, int width,
|
|
int height) {
|
|
|
|
int w_whole=0, h_whole=0,
|
|
start_width=0, start_height=0,
|
|
w_start_offset=0, h_start_offset=0,
|
|
w_whole_tiles=0, h_whole_tiles=0,
|
|
end_width=0, end_height=0,
|
|
w, h,
|
|
destx=0, desty=0;
|
|
HTMLWidget hw = (HTMLWidget) wid;
|
|
|
|
if(!hw || (x<0) || (y<0) || width<=0 || height<=0 ||
|
|
!hw->html.bg_width ||
|
|
!hw->html.bg_height || !hw->html.bgmap_SAVE ||
|
|
!hw->html.bg_image) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (width > hw->html.view_width) {
|
|
width=hw->html.view_width-x;
|
|
}
|
|
if (height > hw->html.view_height) {
|
|
height=hw->html.view_height-y;
|
|
}
|
|
|
|
/*
|
|
* Figure out the width offset into the bg image.
|
|
* Figure out the width of the area to draw.
|
|
* If there is a width offset, index the number of width tiles.
|
|
* Figure out the height offset into the bg image.
|
|
* Figure out the height of the area to draw.
|
|
* If there is a height offset, index the number of height tiles.
|
|
*/
|
|
w_start_offset = (x+hw->html.scroll_x) % hw->html.bg_width;
|
|
if (w_start_offset || (!w_start_offset && width<hw->html.bg_width)) {
|
|
w_whole++;
|
|
start_width=hw->html.bg_width-w_start_offset;
|
|
if (start_width>width) {
|
|
start_width=width;
|
|
}
|
|
}
|
|
h_start_offset = (y+hw->html.scroll_y) % hw->html.bg_height;
|
|
if (h_start_offset || (!h_start_offset && height<hw->html.bg_height)) {
|
|
h_whole++;
|
|
start_height=hw->html.bg_height-h_start_offset;
|
|
if (start_height>height) {
|
|
start_height=height;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Now that we know the width and height of the first area to draw,
|
|
* we can compute how many "whole" tiles to draw for entire width
|
|
* and the entire height.
|
|
* We do not bother setting w_whole_tiles or h_whole_tiles to zero
|
|
* if the if fails because they are inited to zero.
|
|
*/
|
|
if (width-start_width) {
|
|
w_whole_tiles=(width-start_width)/hw->html.bg_width;
|
|
w_whole+=w_whole_tiles;
|
|
}
|
|
if (height-start_height) {
|
|
h_whole_tiles=(height-start_height)/hw->html.bg_height;
|
|
h_whole+=h_whole_tiles;
|
|
}
|
|
|
|
/*
|
|
* Now we have the numbers to compute the amount of the last tile to
|
|
* draw.
|
|
* If there is something to draw, index the "whole" variable.
|
|
*/
|
|
end_width=width-(start_width+(w_whole_tiles*hw->html.bg_width));
|
|
if (end_width) {
|
|
w_whole++;
|
|
}
|
|
end_height=height-(start_height+(h_whole_tiles*hw->html.bg_height));
|
|
if (end_height) {
|
|
h_whole++;
|
|
}
|
|
|
|
/*
|
|
printf("x:%d y:%d width:%d height:%d\n",x,y,width,height);
|
|
printf("w_start_offset:%d h_start_offset:%d\n",w_start_offset,h_start_offset);
|
|
printf("start_width:%d start_height:%d\n",start_width,start_height);
|
|
printf("end_width:%d end_height:%d\n",end_width,end_height);
|
|
printf("w_whole_tiles:%d h_whole_tiles:%d\n",w_whole_tiles,h_whole_tiles);
|
|
printf("w_whole:%d h_whole:%d\n\n",w_whole,h_whole);
|
|
*/
|
|
|
|
/*
|
|
* Now it's time to draw...yippeeeee.
|
|
*
|
|
* This could probably stand to be optimized, but I wanted something
|
|
* that worked first.
|
|
*/
|
|
desty=y;
|
|
/*
|
|
if (hw->html.bgclip_SAVE!=None) {
|
|
XSetClipMask(XtDisplay(hw),
|
|
hw->html.drawGC,
|
|
hw->html.bgclip_SAVE);
|
|
}
|
|
*/
|
|
for (h=0; h<h_whole; h++) {
|
|
destx=x;
|
|
for (w=0; w<w_whole; w++) {
|
|
/*
|
|
if (hw->html.bgclip_SAVE!=None) {
|
|
XSetClipOrigin(XtDisplay(hw),
|
|
hw->html.drawGC,
|
|
(destx-(w_start_offset*(!w))),
|
|
(desty-(h_start_offset*(!h))));
|
|
}
|
|
*/
|
|
XCopyArea(XtDisplay(wid),
|
|
hw->html.bgmap_SAVE,
|
|
XtWindowOfObject(hw->html.view),
|
|
hw->html.drawGC,
|
|
w_start_offset*(!w),
|
|
h_start_offset*(!h),
|
|
(!w ?
|
|
(start_width ?
|
|
start_width :
|
|
hw->html.bg_width) :
|
|
((w+1)==w_whole ?
|
|
(end_width ?
|
|
end_width :
|
|
hw->html.bg_width) :
|
|
hw->html.bg_width)),
|
|
(!h ?
|
|
(start_height ?
|
|
start_height :
|
|
hw->html.bg_height) :
|
|
((h+1)==h_whole ?
|
|
(end_height ?
|
|
end_height :
|
|
hw->html.bg_height) :
|
|
hw->html.bg_height)),
|
|
destx,
|
|
desty);
|
|
destx+=(!w ?
|
|
(start_width ?
|
|
start_width :
|
|
hw->html.bg_width) :
|
|
hw->html.bg_width);
|
|
}
|
|
desty+=(!h ?
|
|
(start_height ?
|
|
start_height :
|
|
hw->html.bg_height) :
|
|
hw->html.bg_height);
|
|
}
|
|
|
|
/*
|
|
if (hw->html.bgclip_SAVE!=None) {
|
|
XSetClipMask(XtDisplay(hw),
|
|
hw->html.drawGC,
|
|
None);
|
|
XSetClipOrigin(XtDisplay(hw),
|
|
hw->html.drawGC,
|
|
0,
|
|
0);
|
|
}
|
|
*/
|
|
|
|
return;
|
|
}
|
|
|
|
static Boolean html_accept_focus(Widget w, Time *t)
|
|
{
|
|
return True;
|
|
}
|
|
|
|
/* this allows the client to set the focus policy for all the widgets
|
|
created as children of the html widget */
|
|
void HTMLSetFocusPolicy(Widget w, int to)
|
|
{
|
|
HTMLWidget hw = (HTMLWidget) w;
|
|
|
|
if(hw->html.focus_follows_mouse == to)
|
|
return;
|
|
else
|
|
{
|
|
Widget shell = w;
|
|
|
|
while(!XtIsTopLevelShell(shell))
|
|
shell = XtParent(shell);
|
|
|
|
hw->html.focus_follows_mouse = to;
|
|
if(to)
|
|
{
|
|
XtVaSetValues(shell, XmNkeyboardFocusPolicy, XmPOINTER, NULL);
|
|
}
|
|
else
|
|
{
|
|
XtVaSetValues(shell, XmNkeyboardFocusPolicy, XmEXPLICIT, NULL);
|
|
/* when we have preference dialog this will have to
|
|
undo all the translations that are currently installed
|
|
in the widgets and set the keyboardFocus policy of the
|
|
toplevel shell to pointer */
|
|
}
|
|
}
|
|
}
|