mirror of
https://github.com/NishiOwO/chimera.git
synced 2025-04-22 00:54:39 +00:00
5959 lines
129 KiB
C
5959 lines
129 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "HTMLP.h"
|
|
#include "DrawingArea.h"
|
|
#include <X11/Xaw/Scrollbar.h>
|
|
#include <X11/cursorfont.h>
|
|
|
|
#define MARGIN_DEFAULT 20
|
|
#define CLICK_TIME 500
|
|
#define SELECT_THRESHOLD 3
|
|
#define MAX_UNDERLINES 3
|
|
#define DEFAULT_INCREMENT 18
|
|
|
|
#ifndef ABS
|
|
#define ABS(x) (((x) > 0) ? (x) : ((x) * -1))
|
|
#endif
|
|
|
|
#define W_TEXTFIELD 0
|
|
#define W_CHECKBOX 1
|
|
#define W_RADIOBOX 2
|
|
#define W_PUSHBUTTON 3
|
|
#define W_PASSWORD 4
|
|
#define W_OPTIONMENU 5
|
|
|
|
|
|
extern int FormatAll();
|
|
extern int DocumentWidth();
|
|
extern void PlaceLine();
|
|
extern void TextRefresh();
|
|
extern void ImageRefresh();
|
|
extern void LinefeedRefresh();
|
|
extern void RefreshTextRange();
|
|
extern void FreeColors();
|
|
extern void FreeImages();
|
|
extern void HideWidgets();
|
|
extern void MapWidgets();
|
|
extern int SwapElements();
|
|
extern int ElementLessThan();
|
|
extern int IsDelayedHRef();
|
|
extern int IsIsMapForm();
|
|
extern int AnchoredHeight();
|
|
extern char *ParseMarkTag();
|
|
extern char *ParseTextToString();
|
|
extern char *ParseTextToPrettyString();
|
|
extern char *ParseTextToPSString();
|
|
extern struct mark_up *HTMLParse();
|
|
extern struct ele_rec *LocateElement();
|
|
extern struct ele_rec **MakeLineList();
|
|
extern void FreeHRefs();
|
|
extern struct ref_rec *AddHRef();
|
|
extern void FreeDelayedImages();
|
|
extern struct delay_rec *AddDelayedImage();
|
|
extern ImageInfo *NoImageData();
|
|
extern void ImageSubmitForm();
|
|
|
|
|
|
static void SelectStart();
|
|
static void ExtendStart();
|
|
static void ExtendAdjust();
|
|
static void ExtendEnd();
|
|
static void TrackMotion();
|
|
static Boolean ConvertSelection();
|
|
static void LoseSelection();
|
|
static void SelectionDone();
|
|
static void ScrollUp();
|
|
static void ScrollDown();
|
|
|
|
|
|
#ifdef _NO_PROTO
|
|
|
|
static void _HTMLInput() ;
|
|
static void _HTMLpwdInput() ;
|
|
static void Initialize() ;
|
|
static void Redisplay() ;
|
|
static void Resize() ;
|
|
static Boolean SetValues() ;
|
|
static XtGeometryResult GeometryManager() ;
|
|
static Dimension VbarWidth();
|
|
static Dimension HbarHeight();
|
|
static void ViewRedisplay();
|
|
static void ViewClearAndRefresh();
|
|
static void CallLinkCallbacks();
|
|
|
|
#else /* _NO_PROTO */
|
|
|
|
static void _HTMLInput(Widget w, XEvent *event,
|
|
String *params, Cardinal *num_params);
|
|
static void _HTMLpwdInput(Widget w, XEvent *event,
|
|
String *params, Cardinal *num_params);
|
|
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 Dimension VbarWidth(HTMLWidget hw);
|
|
static Dimension HbarHeight(HTMLWidget hw);
|
|
static void ViewRedisplay(HTMLWidget hw, int x, int y,
|
|
int width, int height);
|
|
static void ViewClearAndRefresh(HTMLWidget hw);
|
|
static void CallLinkCallbacks(HTMLWidget hw);
|
|
#endif /* _NO_PROTO */
|
|
|
|
|
|
/*
|
|
* Default translations
|
|
* Selection of text, and activate anchors.
|
|
* If motif, add manager translations.
|
|
*/
|
|
static char defaultTranslations[] =
|
|
" \
|
|
<Btn1Down>: select-start() \n\
|
|
<Btn1Motion>: extend-adjust() \n\
|
|
<Btn1Up>: extend-end(PRIMARY, CUT_BUFFER0) \n\
|
|
<Btn2Down>: select-start() \n\
|
|
<Btn2Motion>: extend-adjust() \n\
|
|
<Btn2Up>: extend-end(PRIMARY, CUT_BUFFER0) \n\
|
|
<Btn3Down>: extend-start()\n\
|
|
<Btn3Motion>: extend-adjust()\n\
|
|
<Btn3Up>: extend-end(PRIMARY, CUT_BUFFER0) \n\
|
|
<Motion>: track-motion()\n\
|
|
<Leave>: track-motion()\n\
|
|
<FocusOut>: track-motion()\n\
|
|
<Expose>: track-motion()\n\
|
|
<Key>space: scroll-up(\"Halfscreen\")\n\
|
|
<Key>b: scroll-down(\"Halfscreen\")\n\
|
|
<Key>j: scroll-up(\"Oneline\")\n\
|
|
<Key>k: scroll-down(\"Oneline\")\n\
|
|
<Key>Down: scroll-up(\"Oneline\")\n\
|
|
<Key>Up: scroll-down(\"Oneline\")\n\
|
|
";
|
|
/*
|
|
* Changes above by Satoshi ASAMI <asami@cory.EECS.Berkeley.EDU>
|
|
*/
|
|
|
|
|
|
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 },
|
|
{ "HTMLpwdInput", (XtActionProc) _HTMLpwdInput },
|
|
{ "scroll-up", (XtActionProc) ScrollUp },
|
|
{ "scroll-down", (XtActionProc) ScrollDown },
|
|
};
|
|
|
|
/*
|
|
* 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 },
|
|
{ "HTMLpwdInput", (XtActionProc) _HTMLpwdInput },
|
|
{ "scroll-up", (XtActionProc) ScrollUp },
|
|
{ "scroll-down", (XtActionProc) ScrollDown },
|
|
};
|
|
|
|
|
|
/*
|
|
* Resource definitions for HTML widget
|
|
*/
|
|
|
|
static XtResource resources[] =
|
|
{
|
|
{ XtNborderWidth,
|
|
XtCBorderWidth, XtRDimension, sizeof (Dimension),
|
|
XtOffset (HTMLWidget, core.border_width),
|
|
XtRImmediate, (XtPointer) 0
|
|
},
|
|
{ WbNverticalScrollBarPos,
|
|
WbCVerticalScrollBarPos, XtRInt, sizeof (int),
|
|
XtOffset (HTMLWidget, html.scroll_y),
|
|
XtRInt, 0
|
|
},
|
|
|
|
{ WbNhorizontalScrollBarPos,
|
|
WbCHorizontalScrollBarPos, XtRInt, sizeof (int),
|
|
XtOffset (HTMLWidget, html.scroll_x),
|
|
XtRInt, 0
|
|
},
|
|
|
|
{ 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
|
|
},
|
|
{ XtNforeground,
|
|
XtCForeground, XtRPixel, sizeof (Pixel),
|
|
XtOffset (HTMLWidget, html.foreground),
|
|
XtRString, "Black"
|
|
},
|
|
|
|
{ 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, "False"
|
|
},
|
|
|
|
{ WbNhorizontalScrollOnTop,
|
|
WbCHorizontalScrollOnTop, XtRBoolean, sizeof (Boolean),
|
|
XtOffset (HTMLWidget, html.hbar_top),
|
|
XtRString, "False"
|
|
},
|
|
|
|
{ XtNfont,
|
|
XtCFont, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.font),
|
|
XtRString, "-adobe-times-medium-r-normal-*-14-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNitalicFont,
|
|
WbCItalicFont, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.italic_font),
|
|
XtRString, "-adobe-times-medium-i-normal-*-14-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNboldFont,
|
|
WbCBoldFont, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.bold_font),
|
|
XtRString, "-adobe-times-bold-r-normal-*-14-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNfixedFont,
|
|
WbCFixedFont, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.fixed_font),
|
|
XtRString, "-adobe-courier-medium-r-normal-*-14-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNfixedboldFont,
|
|
WbCFixedboldFont, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.fixedbold_font),
|
|
XtRString, "-adobe-courier-bold-r-normal-*-14-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNfixeditalicFont,
|
|
WbCFixeditalicFont, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.fixeditalic_font),
|
|
XtRString, "-adobe-courier-medium-o-normal-*-14-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNheader1Font,
|
|
WbCHeader1Font, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.header1_font),
|
|
XtRString, "-adobe-times-bold-r-normal-*-24-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNheader2Font,
|
|
WbCHeader2Font, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.header2_font),
|
|
XtRString, "-adobe-times-bold-r-normal-*-18-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNheader3Font,
|
|
WbCHeader3Font, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.header3_font),
|
|
XtRString, "-adobe-times-bold-r-normal-*-17-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNheader4Font,
|
|
WbCHeader4Font, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.header4_font),
|
|
XtRString, "-adobe-times-bold-r-normal-*-14-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNheader5Font,
|
|
WbCHeader5Font, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.header5_font),
|
|
XtRString, "-adobe-times-bold-r-normal-*-12-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNheader6Font,
|
|
WbCHeader6Font, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.header6_font),
|
|
XtRString, "-adobe-times-bold-r-normal-*-10-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNaddressFont,
|
|
WbCAddressFont, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.address_font),
|
|
XtRString, "-adobe-times-medium-i-normal-*-14-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNplainFont,
|
|
WbCPlainFont, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.plain_font),
|
|
XtRString, "-adobe-courier-medium-r-normal-*-14-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNplainboldFont,
|
|
WbCPlainboldFont, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.plainbold_font),
|
|
XtRString, "-adobe-courier-bold-r-normal-*-14-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNplainitalicFont,
|
|
WbCPlainitalicFont, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.plainitalic_font),
|
|
XtRString, "-adobe-courier-medium-o-normal-*-14-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNlistingFont,
|
|
WbCListingFont, XtRFontStruct, sizeof (XFontStruct *),
|
|
XtOffset (HTMLWidget, html.listing_font),
|
|
XtRString, "-adobe-courier-medium-r-normal-*-12-*-*-*-*-*-*-*"
|
|
},
|
|
|
|
{ WbNpreviouslyVisitedTestFunction,
|
|
WbCPreviouslyVisitedTestFunction, XtRPointer,
|
|
sizeof (XtPointer),
|
|
XtOffset (HTMLWidget, html.previously_visited_test),
|
|
XtRImmediate, (caddr_t) NULL
|
|
},
|
|
|
|
{ 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 */
|
|
(WidgetClass) &constraintClassRec, /* superclass */
|
|
"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 */
|
|
NULL, /* accept_focus */
|
|
XtVersion, /* version */
|
|
NULL, /* callback_private */
|
|
defaultTranslations, /* tm_table */
|
|
XtInheritQueryGeometry, /* query_geometry */
|
|
XtInheritDisplayAccelerator, /* display_accelerator*/
|
|
NULL, /* extension */
|
|
},
|
|
|
|
{ /* composite_class fields */
|
|
(XtGeometryHandler) GeometryManager, /* geometry_manager */
|
|
NULL, /* change_managed */
|
|
XtInheritInsertChild, /* insert_child */
|
|
XtInheritDeleteChild, /* delete_child */
|
|
NULL, /* extension */
|
|
},
|
|
|
|
{ /* constraint_class fields */
|
|
NULL, /* resource list */
|
|
0, /* num resources */
|
|
0, /* constraint size */
|
|
NULL, /* init proc */
|
|
NULL, /* destroy proc */
|
|
NULL, /* set values proc */
|
|
NULL, /* extension */
|
|
},
|
|
|
|
{ /* html_class fields */
|
|
0 /* none */
|
|
}
|
|
};
|
|
|
|
WidgetClass htmlWidgetClass = (WidgetClass)&htmlClassRec;
|
|
|
|
static Cursor in_anchor_cursor = (Cursor)NULL;
|
|
|
|
|
|
/*
|
|
* Process an expose event in the View (or drawing area). This
|
|
* Can be a regular expose event, or perhaps a GraphicsExpose Event.
|
|
*/
|
|
static void
|
|
DrawExpose(w, data, event)
|
|
Widget w;
|
|
caddr_t data;
|
|
XEvent *event;
|
|
{
|
|
XExposeEvent *ExEvent = (XExposeEvent *)event;
|
|
HTMLWidget hw = (HTMLWidget)data;
|
|
int x, y;
|
|
int width, height;
|
|
|
|
if ((event->xany.type != Expose)&&(event->xany.type != GraphicsExpose))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Make sure we have a valid GC to draw with.
|
|
*/
|
|
if (hw->html.drawGC == NULL)
|
|
{
|
|
unsigned long valuemask;
|
|
XGCValues values;
|
|
|
|
values.function = GXcopy;
|
|
values.plane_mask = AllPlanes;
|
|
values.foreground = hw->html.foreground;
|
|
values.background = hw->core.background_pixel;
|
|
|
|
valuemask = GCFunction|GCPlaneMask|GCForeground|GCBackground;
|
|
|
|
hw->html.drawGC = XCreateGC(XtDisplay(hw), XtWindow(hw),
|
|
valuemask, &values);
|
|
}
|
|
|
|
x = ExEvent->x;
|
|
y = ExEvent->y;
|
|
width = (int)ExEvent->width;
|
|
height = (int)ExEvent->height;
|
|
|
|
#ifdef DEBUG
|
|
DebugHook(x, y, width, height);
|
|
#endif
|
|
|
|
ViewRedisplay(hw, x, y, width, height);
|
|
}
|
|
|
|
|
|
void
|
|
ScrollWidgets(hw)
|
|
HTMLWidget hw;
|
|
{
|
|
WidgetInfo *wptr;
|
|
int xval, yval;
|
|
|
|
xval = hw->html.scroll_x;
|
|
yval = hw->html.scroll_y;
|
|
wptr = hw->html.widget_list;
|
|
while (wptr != NULL)
|
|
{
|
|
if (wptr->w != NULL)
|
|
{
|
|
Widget w;
|
|
int x, y;
|
|
|
|
w = wptr->w;
|
|
x = wptr->x;
|
|
y = wptr->y;
|
|
XtMoveWidget(w, (x - xval), (y - yval));
|
|
}
|
|
wptr = wptr->next;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* 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);
|
|
|
|
#if !defined(ultrix)
|
|
#if defined(XRELEASE)
|
|
#if XRELEASE > 4
|
|
XawScrollbarSetThumb(sb, top, shown);
|
|
#endif
|
|
#endif
|
|
#else
|
|
XawScrollbarSetThumb(sb, top, shown);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* Either the vertical or hortizontal scrollbar has been moved
|
|
*/
|
|
void
|
|
ScrollToPos(w, hw, value)
|
|
Widget w;
|
|
HTMLWidget hw;
|
|
int value;
|
|
{
|
|
/*
|
|
* Special code incase the scrollbar is "moved" before we have a window
|
|
* (if we have a GC we have a window)
|
|
*/
|
|
if (hw->html.drawGC == NULL)
|
|
{
|
|
if (w == hw->html.vbar)
|
|
{
|
|
hw->html.scroll_y = value;
|
|
}
|
|
else if (w == hw->html.hbar)
|
|
{
|
|
hw->html.scroll_x = value;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* get our widgets out of the way (No Expose events)
|
|
HideWidgets(hw);
|
|
*/
|
|
|
|
/*
|
|
* If we've moved the vertical scrollbar
|
|
*/
|
|
if (w == hw->html.vbar)
|
|
{
|
|
/*
|
|
* We've scrolled down. Copy up the untouched part of the
|
|
* window. Then Clear and redraw the new area
|
|
* exposed.
|
|
*/
|
|
if (value > hw->html.scroll_y)
|
|
{
|
|
int dy;
|
|
|
|
dy = value - hw->html.scroll_y;
|
|
if (dy > hw->html.view_height)
|
|
{
|
|
hw->html.scroll_y = value;
|
|
XClearArea(XtDisplay(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
0, 0,
|
|
hw->html.view_width,
|
|
hw->html.view_height, False);
|
|
ViewRedisplay(hw,
|
|
0, 0,
|
|
hw->html.view_width,
|
|
hw->html.view_height);
|
|
}
|
|
else
|
|
{
|
|
XCopyArea(XtDisplay(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
hw->html.drawGC, 0, dy,
|
|
hw->html.view_width,
|
|
hw->html.view_height - dy,
|
|
0, 0);
|
|
hw->html.scroll_y = value;
|
|
XClearArea(XtDisplay(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
0, (int)hw->html.view_height - dy,
|
|
hw->html.view_width, dy, False);
|
|
ViewRedisplay(hw,
|
|
0, (int)hw->html.view_height - dy,
|
|
hw->html.view_width, dy);
|
|
}
|
|
}
|
|
/*
|
|
* We've scrolled up. Copy down the untouched part of the
|
|
* window. Then Clear and redraw the new area
|
|
* exposed.
|
|
*/
|
|
else if (value < hw->html.scroll_y)
|
|
{
|
|
int dy;
|
|
|
|
dy = hw->html.scroll_y - value;
|
|
if (dy > hw->html.view_height)
|
|
{
|
|
hw->html.scroll_y = value;
|
|
XClearArea(XtDisplay(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
0, 0,
|
|
hw->html.view_width,
|
|
hw->html.view_height, False);
|
|
ViewRedisplay(hw,
|
|
0, 0,
|
|
hw->html.view_width,
|
|
hw->html.view_height);
|
|
}
|
|
else
|
|
{
|
|
XCopyArea(XtDisplay(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
hw->html.drawGC, 0, 0,
|
|
hw->html.view_width,
|
|
hw->html.view_height - dy,
|
|
0, dy);
|
|
hw->html.scroll_y = value;
|
|
XClearArea(XtDisplay(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
0, 0,
|
|
hw->html.view_width, dy, False);
|
|
ViewRedisplay(hw,
|
|
0, 0,
|
|
hw->html.view_width, dy);
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Else we've moved the horizontal scrollbar
|
|
*/
|
|
else if (w == hw->html.hbar)
|
|
{
|
|
/*
|
|
* We've scrolled right. Copy left the untouched part of the
|
|
* window. Then Clear and redraw the new area
|
|
* exposed.
|
|
*/
|
|
if (value > hw->html.scroll_x)
|
|
{
|
|
int dx;
|
|
|
|
dx = value - hw->html.scroll_x;
|
|
if (dx > hw->html.view_width)
|
|
{
|
|
hw->html.scroll_x = value;
|
|
XClearArea(XtDisplay(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
0, 0,
|
|
hw->html.view_width,
|
|
hw->html.view_height, False);
|
|
ViewRedisplay(hw,
|
|
0, 0,
|
|
hw->html.view_width,
|
|
hw->html.view_height);
|
|
}
|
|
else
|
|
{
|
|
XCopyArea(XtDisplay(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
hw->html.drawGC, dx, 0,
|
|
hw->html.view_width - dx,
|
|
hw->html.view_height,
|
|
0, 0);
|
|
hw->html.scroll_x = value;
|
|
XClearArea(XtDisplay(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
(int)hw->html.view_width - dx, 0,
|
|
dx, hw->html.view_height, False);
|
|
ViewRedisplay(hw,
|
|
(int)hw->html.view_width - dx, 0,
|
|
dx, hw->html.view_height);
|
|
}
|
|
}
|
|
/*
|
|
* We've scrolled left. Copy right the untouched part of the
|
|
* window. Then Clear and redraw the new area
|
|
* exposed.
|
|
*/
|
|
else if (value < hw->html.scroll_x)
|
|
{
|
|
int dx;
|
|
|
|
dx = hw->html.scroll_x - value;
|
|
if (dx > hw->html.view_width)
|
|
{
|
|
hw->html.scroll_x = value;
|
|
XClearArea(XtDisplay(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
0, 0,
|
|
hw->html.view_width,
|
|
hw->html.view_height, False);
|
|
ViewRedisplay(hw,
|
|
0, 0,
|
|
hw->html.view_width,
|
|
hw->html.view_height);
|
|
}
|
|
else
|
|
{
|
|
XCopyArea(XtDisplay(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
hw->html.drawGC, 0, 0,
|
|
hw->html.view_width - dx,
|
|
hw->html.view_height,
|
|
dx, 0);
|
|
hw->html.scroll_x = value;
|
|
XClearArea(XtDisplay(hw->html.view),
|
|
XtWindow(hw->html.view),
|
|
0, 0,
|
|
dx, hw->html.view_height, False);
|
|
ViewRedisplay(hw,
|
|
0, 0,
|
|
dx, hw->html.view_height);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Move the now hidden widgets
|
|
* Flush any Copyed or Cleared text first.
|
|
XFlush(XtDisplay(hw));
|
|
*/
|
|
ScrollWidgets(hw);
|
|
|
|
/*
|
|
* Remap the widgets to their new location
|
|
MapWidgets(hw);
|
|
*/
|
|
}
|
|
|
|
|
|
/*
|
|
* Either the vertical or hortizontal scrollbar has been moved
|
|
*/
|
|
void
|
|
ScrollMove(w, client_data, call_data)
|
|
Widget w;
|
|
caddr_t client_data;
|
|
caddr_t call_data;
|
|
{
|
|
float scrollDir = (int)call_data < 0 ? -0.3 : 0.3;
|
|
HTMLWidget hw = (HTMLWidget)client_data;
|
|
int value, maxv;
|
|
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; */
|
|
/*
|
|
* patch by Satoshi Asami <asami@cs.berkeley.edu>
|
|
*/
|
|
if ((int)call_data == 1 || (int)call_data == -1)
|
|
value = hw->html.scroll_y + scrollDir * currentLength;
|
|
else
|
|
value = hw->html.scroll_y + (int)call_data;
|
|
}
|
|
else
|
|
{
|
|
totalLength = hw->html.doc_width;
|
|
currentLength = hw->html.view_width;
|
|
value = hw->html.scroll_x + scrollDir * currentLength;
|
|
}
|
|
|
|
/*
|
|
* If resizing of the document has made the scroll value
|
|
* greater than the max, we want to hold it at the max.
|
|
*
|
|
* Moved this from someplace else in the code to keep the scrollbar
|
|
* from going too far. john.
|
|
*/
|
|
maxv = totalLength - currentLength;
|
|
if (value > maxv) value = maxv;
|
|
if (value < 0) value = 0;
|
|
|
|
setScrollBar(w, value, totalLength, currentLength);
|
|
ScrollToPos(w, hw, value);
|
|
}
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
/*
|
|
* 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",
|
|
drawingAreaWidgetClass,
|
|
(Widget)hw, arg, argcnt);
|
|
XtManageChild(hw->html.view);
|
|
}
|
|
|
|
/*
|
|
* For the view widget catch all Expose and GraphicsExpose
|
|
* events. Replace its translations with ours, and make
|
|
* sure all the actions are in order.
|
|
*/
|
|
XtAddEventHandler((Widget)hw->html.view, ExposureMask, True,
|
|
(XtEventHandler)DrawExpose, (caddr_t)hw);
|
|
/*
|
|
* As described previoisly, for some reason with Motif1.2/X11R5
|
|
* the list actionsList is corrupted when we get here,
|
|
* so we have to use the special copy SpareActionsList
|
|
*/
|
|
XtAppAddActions(XtWidgetToApplicationContext(hw->html.view),
|
|
SpareActionsList, XtNumber(SpareActionsList));
|
|
trans = XtParseTranslationTable(defaultTranslations);
|
|
argcnt = 0;
|
|
XtSetArg(arg[argcnt], XtNtranslations, trans); argcnt++;
|
|
XtSetValues(hw->html.view, arg, argcnt);
|
|
|
|
/*
|
|
* If the user hasn't provided a vertical scrollbar (which they
|
|
* should not most of the time) make one.
|
|
*/
|
|
if (hw->html.vbar == NULL)
|
|
{
|
|
argcnt = 0;
|
|
XtSetArg(arg[argcnt],XtNorientation,XtorientVertical); argcnt++;
|
|
hw->html.vbar = XtCreateWidget("Vbar", scrollbarWidgetClass,
|
|
(Widget)hw, arg, argcnt);
|
|
XtManageChild(hw->html.vbar);
|
|
}
|
|
|
|
/*
|
|
* Add callbacks to catch scrollbar changes
|
|
*/
|
|
XtAddCallback(hw->html.vbar, XtNjumpProc,
|
|
(XtCallbackProc)JumpMove, (caddr_t)hw);
|
|
XtAddCallback(hw->html.vbar, XtNscrollProc,
|
|
(XtCallbackProc)ScrollMove, (caddr_t)hw);
|
|
|
|
/*
|
|
* 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;
|
|
XtSetArg(arg[argcnt], XtNorientation, XtorientHorizontal);
|
|
argcnt++;
|
|
hw->html.hbar = XtCreateWidget("Hbar", scrollbarWidgetClass,
|
|
(Widget)hw, arg, argcnt);
|
|
XtManageChild(hw->html.hbar);
|
|
}
|
|
|
|
/*
|
|
* Add callbacks to catch scrollbar changes
|
|
*/
|
|
XtAddCallback(hw->html.hbar, XtNjumpProc,
|
|
(XtCallbackProc)JumpMove, (caddr_t)hw);
|
|
XtAddCallback(hw->html.hbar, XtNscrollProc,
|
|
(XtCallbackProc)ScrollMove, (caddr_t)hw);
|
|
}
|
|
|
|
|
|
/*
|
|
* 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
|
|
{
|
|
int vx, vy;
|
|
|
|
/*
|
|
* Move and size the viewing area
|
|
*/
|
|
vx = vy = 0;
|
|
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 * 0),
|
|
hw->html.vbar->core.border_width);
|
|
|
|
/*
|
|
* Set the slider size to be the percentage of the
|
|
* viewing area that the viewing area is of the
|
|
* document area. Or set it to 1 if that isn't possible.
|
|
*/
|
|
if (hw->html.doc_height == 0)
|
|
{
|
|
ss = 1;
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf (stderr, "view_height %d, doc_height %d\n",
|
|
hw->html.view_height, hw->html.doc_height);
|
|
#endif
|
|
#ifdef NOT_RIGHT
|
|
/* Eric -- your previous equation wasn't doing it.
|
|
This isn't either... */
|
|
ss =
|
|
(int)((float)hw->html.view_height *
|
|
((float)hw->html.view_height /
|
|
(float)(hw->html.doc_height - (int)hw->html.view_height)));
|
|
if (ss > hw->html.view_height)
|
|
{
|
|
ss = hw->html.view_height;
|
|
}
|
|
#endif
|
|
/* Added by marca: this produces results *very* close (~1 pixel)
|
|
to the original scrolled window behavior. */
|
|
ss = hw->html.view_height;
|
|
}
|
|
if (ss < 1)
|
|
{
|
|
ss = 1;
|
|
}
|
|
#ifdef DEBUG
|
|
fprintf (stderr, "computed ss to be %d\n", ss);
|
|
#endif
|
|
|
|
/*
|
|
* If resizing of the document has made scroll_y
|
|
* greater than the max, we want to hold it at the max.
|
|
*/
|
|
maxv = hw->html.doc_height - (int)hw->html.view_height;
|
|
if (maxv < 0)
|
|
{
|
|
maxv = 0;
|
|
}
|
|
if (hw->html.scroll_y > maxv)
|
|
{
|
|
hw->html.scroll_y = maxv;
|
|
}
|
|
|
|
/*
|
|
* Prevent the Motif max value and slider size
|
|
* from going to zero, which is illegal
|
|
*/
|
|
maxv = maxv + ss;
|
|
if (maxv < 1)
|
|
{
|
|
maxv = 1;
|
|
}
|
|
|
|
/*
|
|
* Motif will not allow the actual value to be equal to
|
|
* its max value. Adjust accordingly.
|
|
* Since we might decrease scroll_y, cap it at zero.
|
|
*/
|
|
if (hw->html.scroll_y >= maxv)
|
|
{
|
|
hw->html.scroll_y = maxv - 1;
|
|
}
|
|
if (hw->html.scroll_y < 0)
|
|
{
|
|
hw->html.scroll_y = 0;
|
|
}
|
|
|
|
setScrollBar(hw->html.vbar,
|
|
hw->html.scroll_y,
|
|
hw->html.doc_height,
|
|
hw->html.view_height);
|
|
|
|
#ifdef DEBUG
|
|
XtVaGetValues(hw->html.vbar, XmNsliderSize, &ss, NULL);
|
|
fprintf (stderr, "real slider size %d\n", ss);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Set up horizontal scrollbar
|
|
*/
|
|
if (hw->html.use_hbar == True)
|
|
{
|
|
int maxv;
|
|
int ss;
|
|
|
|
/*
|
|
* Size the horizontal scrollbar to the width of
|
|
* the viewing area
|
|
*/
|
|
XtResizeWidget(hw->html.hbar,
|
|
hw->html.view_width,
|
|
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;
|
|
}
|
|
|
|
setScrollBar(hw->html.hbar,
|
|
hw->html.scroll_x,
|
|
hw->html.doc_width,
|
|
hw->html.view_width);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
int ss;
|
|
XtVaGetValues(hw->html.vbar, XmNsliderSize, &ss, NULL);
|
|
fprintf (stderr, "real slider size %d\n", ss);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* Reformat the window and scrollbars.
|
|
* May be called because of a changed document, or because of a changed
|
|
* window size.
|
|
*/
|
|
static void
|
|
#ifdef _NO_PROTO
|
|
ReformatWindow (hw)
|
|
HTMLWidget hw ;
|
|
#else
|
|
ReformatWindow(
|
|
HTMLWidget hw)
|
|
#endif
|
|
{
|
|
int temp;
|
|
int new_width;
|
|
Dimension swidth, sheight;
|
|
Dimension st;
|
|
|
|
/*
|
|
* Find the current scrollbar sizes, and shadow thickness and format
|
|
* the document to the current window width
|
|
* (assume a vertical scrollbar)
|
|
*/
|
|
swidth = VbarWidth(hw);
|
|
sheight = HbarHeight(hw);
|
|
st = 0;
|
|
if (hw->core.width <= swidth)
|
|
{
|
|
hw->core.width = swidth + 10;
|
|
}
|
|
new_width = hw->core.width - swidth - (2 * st);
|
|
temp = FormatAll(hw, &new_width);
|
|
|
|
/*
|
|
* If we need the vertical scrollbar, place and manage it,
|
|
* and store the current viewing area width.
|
|
*/
|
|
if (temp > hw->core.height - sheight)
|
|
{
|
|
hw->html.use_vbar = True;
|
|
if (hw->html.vbar_right == True)
|
|
{
|
|
XtMoveWidget(hw->html.vbar,
|
|
(hw->core.width - swidth), 0);
|
|
}
|
|
else
|
|
{
|
|
XtMoveWidget(hw->html.vbar, 0, 0);
|
|
}
|
|
XtManageChild(hw->html.vbar);
|
|
hw->html.view_width = hw->core.width - swidth - (2 * st);
|
|
}
|
|
/*
|
|
* Else we were wrong to assume a vertical scrollbar.
|
|
* Remove it, and reformat the document to the wider width.
|
|
* Save the as the current viewing are width.
|
|
*/
|
|
else
|
|
{
|
|
hw->html.use_vbar = False;
|
|
XtUnmanageChild(hw->html.vbar);
|
|
hw->html.scroll_y = 0;
|
|
new_width = hw->core.width - (2 * st);
|
|
temp = FormatAll(hw, &new_width);
|
|
hw->html.view_width = hw->core.width - (2 * st);
|
|
/* fake out later horizontal scrollbars */
|
|
swidth = 0;
|
|
}
|
|
|
|
/*
|
|
* Calculate the actual max width and height of the complete
|
|
* formatted document.
|
|
* The max width may exceed the preformatted width due to special
|
|
* factors in the formatting of the widget.
|
|
* Use the max of the 2 here, but leave max_pre_width unchanged
|
|
* for future formatting calls.
|
|
*/
|
|
/*
|
|
* new_width includes the margins, and hw->html.max_pre_width
|
|
* does not, fix that here.
|
|
*/
|
|
new_width = new_width - (2 * hw->html.margin_width);
|
|
if (hw->html.max_pre_width > new_width)
|
|
{
|
|
new_width = hw->html.max_pre_width;
|
|
}
|
|
/*
|
|
* If the maximum width derives from a formatted, as opposed to
|
|
* unformatted piece of text, allow a 20% of margin width slop
|
|
* over into the margin to cover up a minor glick with terminaing
|
|
* punctuation after anchors at the end of the line.
|
|
*/
|
|
else
|
|
{
|
|
new_width = new_width - (20 * hw->html.margin_width / 100);
|
|
}
|
|
|
|
hw->html.doc_height = temp;
|
|
hw->html.doc_width = new_width + (2 * hw->html.margin_width);
|
|
if (hw->html.view_width > hw->html.doc_width)
|
|
{
|
|
hw->html.doc_width = hw->html.view_width;
|
|
}
|
|
|
|
/*
|
|
* If we need a horizontal scrollbar
|
|
* Place it and manage it. Save the height of the current
|
|
* viewing area.
|
|
*/
|
|
if (hw->html.doc_width > hw->html.view_width)
|
|
{
|
|
hw->html.use_hbar = True;
|
|
if (hw->html.hbar_top == True)
|
|
{
|
|
if (hw->html.use_vbar == True)
|
|
{
|
|
XtMoveWidget(hw->html.vbar,
|
|
hw->html.vbar->core.x, sheight);
|
|
}
|
|
|
|
if (hw->html.vbar_right == True)
|
|
{
|
|
XtMoveWidget(hw->html.hbar, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
XtMoveWidget(hw->html.hbar, swidth, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (hw->html.vbar_right == True)
|
|
{
|
|
XtMoveWidget(hw->html.hbar, 0,
|
|
(hw->core.height - sheight));
|
|
}
|
|
else
|
|
{
|
|
XtMoveWidget(hw->html.hbar, swidth,
|
|
(hw->core.height - sheight));
|
|
}
|
|
}
|
|
XtManageChild(hw->html.hbar);
|
|
hw->html.view_height = hw->core.height - sheight - (2 * st);
|
|
}
|
|
/*
|
|
* Else we don't need a horizontal scrollbar.
|
|
* Remove it and save the current viewing area height.
|
|
*/
|
|
else
|
|
{
|
|
hw->html.use_hbar = False;
|
|
XtUnmanageChild(hw->html.hbar);
|
|
hw->html.scroll_x = 0;
|
|
hw->html.view_height = hw->core.height - (2 * st);
|
|
}
|
|
|
|
/*
|
|
* Configure the scrollbar min, max, and slider sizes
|
|
*/
|
|
#ifdef DEBUG
|
|
fprintf (stderr, "calling in ReformatWindow\n");
|
|
#endif
|
|
ConfigScrollBars(hw);
|
|
}
|
|
|
|
|
|
/*
|
|
* We're a happy widget. We let any child move or resize themselves
|
|
* however they want, we don't care.
|
|
*/
|
|
static XtGeometryResult
|
|
#ifdef _NO_PROTO
|
|
GeometryManager (w, request, reply)
|
|
Widget w;
|
|
XtWidgetGeometry * request;
|
|
XtWidgetGeometry * reply;
|
|
#else
|
|
GeometryManager (
|
|
Widget w,
|
|
XtWidgetGeometry * request,
|
|
XtWidgetGeometry * reply)
|
|
#endif
|
|
{
|
|
reply->x = request->x;
|
|
reply->y = request->y;
|
|
reply->width = request->width;
|
|
reply->height = request->height;
|
|
reply->border_width = request->border_width;
|
|
reply->request_mode = request->request_mode;
|
|
return (XtGeometryYes);
|
|
}
|
|
|
|
|
|
/*
|
|
* Initialize is called when the widget is first initialized.
|
|
* Check to see that all the starting resources are valid.
|
|
*/
|
|
static void
|
|
#ifdef _NO_PROTO
|
|
Initialize (request, new)
|
|
HTMLWidget request ;
|
|
HTMLWidget new ;
|
|
#else
|
|
Initialize(
|
|
HTMLWidget request,
|
|
HTMLWidget new)
|
|
#endif
|
|
{
|
|
/*
|
|
* Make sure height and width are not zero.
|
|
*/
|
|
if (new->core.width == 0)
|
|
{
|
|
new->core.width = new->html.margin_width << 1 ;
|
|
}
|
|
if (new->core.width == 0)
|
|
{
|
|
new->core.width = 10 ;
|
|
}
|
|
if (new->core.height == 0)
|
|
{
|
|
new->core.height = new->html.margin_height << 1 ;
|
|
}
|
|
if (new->core.height == 0)
|
|
{
|
|
new->core.height = 10 ;
|
|
}
|
|
|
|
/*
|
|
* Make sure the underline numbers are within bounds.
|
|
*/
|
|
if (new->html.num_anchor_underlines < 0)
|
|
{
|
|
new->html.num_anchor_underlines = 0;
|
|
}
|
|
if (new->html.num_anchor_underlines > MAX_UNDERLINES)
|
|
{
|
|
new->html.num_anchor_underlines = MAX_UNDERLINES;
|
|
}
|
|
if (new->html.num_visitedAnchor_underlines < 0)
|
|
{
|
|
new->html.num_visitedAnchor_underlines = 0;
|
|
}
|
|
if (new->html.num_visitedAnchor_underlines > MAX_UNDERLINES)
|
|
{
|
|
new->html.num_visitedAnchor_underlines = MAX_UNDERLINES;
|
|
}
|
|
|
|
/*
|
|
* Parse the raw text with the HTML parser. And set the formatted
|
|
* element list to NULL.
|
|
*/
|
|
new->html.html_objects = HTMLParse(NULL, request->html.raw_text);
|
|
CallLinkCallbacks(new);
|
|
new->html.html_header_objects =
|
|
HTMLParse(NULL, request->html.header_text);
|
|
new->html.html_footer_objects =
|
|
HTMLParse(NULL, request->html.footer_text);
|
|
new->html.formatted_elements = NULL;
|
|
new->html.my_visited_hrefs = NULL;
|
|
new->html.my_delayed_images = NULL;
|
|
new->html.widget_list = NULL;
|
|
new->html.form_list = NULL;
|
|
|
|
/*
|
|
* Blank document
|
|
*/
|
|
new->html.line_array = NULL;
|
|
new->html.line_count = 0;
|
|
|
|
/*
|
|
* Find the max width of a preformatted
|
|
* line in this document.
|
|
*/
|
|
new->html.max_pre_width = DocumentWidth(new, new->html.html_objects);
|
|
|
|
/*
|
|
* Create the scrollbars.
|
|
* Find their dimensions and then decide which scrollbars you
|
|
* will need, and what the dimensions of the viewing area are.
|
|
* Start assuming a vertical scrollbar and a horizontal one.
|
|
* The remove vertical if short enough, and remove horizontal
|
|
* if narrow enough.
|
|
*/
|
|
CreateScrollbars(new);
|
|
new->html.scroll_x = 0;
|
|
new->html.scroll_y = 0;
|
|
ReformatWindow(new);
|
|
|
|
/*
|
|
* Initialize private widget resources
|
|
*/
|
|
new->html.drawGC = NULL;
|
|
new->html.select_start = NULL;
|
|
new->html.select_end = NULL;
|
|
new->html.sel_start_pos = 0;
|
|
new->html.sel_end_pos = 0;
|
|
new->html.new_start = NULL;
|
|
new->html.new_end = NULL;
|
|
new->html.new_start_pos = 0;
|
|
new->html.new_end_pos = 0;
|
|
new->html.active_anchor = NULL;
|
|
new->html.press_x = 0;
|
|
new->html.press_y = 0;
|
|
|
|
new->html.cached_tracked_ele = NULL;
|
|
|
|
/* Initialize cursor used when pointer is inside anchor. */
|
|
if (in_anchor_cursor == (Cursor)NULL)
|
|
in_anchor_cursor = XCreateFontCursor (XtDisplay (new), XC_hand2);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
void
|
|
DebugHook(x, y, width, height)
|
|
int x, y, width, height;
|
|
{
|
|
fprintf(stderr, "Redrawing (%d,%d) %dx%d\n", x, y, width, height);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* This is called by redisplay. It is passed a rectangle
|
|
* in the viewing area, and it redisplays that portion of the
|
|
* underlying document area.
|
|
*/
|
|
static void
|
|
#ifdef _NO_PROTO
|
|
ViewRedisplay (hw, x, y, width, height)
|
|
HTMLWidget hw;
|
|
int x, y;
|
|
int width, height;
|
|
#else
|
|
ViewRedisplay(
|
|
HTMLWidget hw,
|
|
int x,
|
|
int y,
|
|
int width,
|
|
int height)
|
|
#endif
|
|
{
|
|
int sx, sy;
|
|
int doc_x, doc_y;
|
|
int i, start, end, guess;
|
|
|
|
/*
|
|
* Use scrollbar values to map from view space to document space.
|
|
*/
|
|
sx = sy = 0;
|
|
if (hw->html.use_vbar == True)
|
|
{
|
|
sy += hw->html.scroll_y;
|
|
}
|
|
if (hw->html.use_hbar == True)
|
|
{
|
|
sx += hw->html.scroll_x;
|
|
}
|
|
|
|
doc_x = x + sx;
|
|
doc_y = y + sy;
|
|
|
|
/*
|
|
* Find the lines that overlap the exposed area.
|
|
*/
|
|
start = 0;
|
|
end = hw->html.line_count - 1;
|
|
|
|
/*
|
|
* Heuristic to speed up redraws by guessing at the starting line.
|
|
*/
|
|
guess = doc_y / (hw->html.font->max_bounds.ascent +
|
|
hw->html.font->max_bounds.descent);
|
|
if (guess > end)
|
|
{
|
|
guess = end;
|
|
}
|
|
while (guess > 0)
|
|
{
|
|
if ((hw->html.line_array[guess] != NULL)&&
|
|
(hw->html.line_array[guess]->y < doc_y))
|
|
{
|
|
break;
|
|
}
|
|
guess--;
|
|
}
|
|
if (guess < start)
|
|
{
|
|
guess = start;
|
|
}
|
|
|
|
for (i=guess; i<hw->html.line_count; i++)
|
|
{
|
|
if (hw->html.line_array[i] == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (hw->html.line_array[i]->y < doc_y)
|
|
{
|
|
start = i;
|
|
}
|
|
if (hw->html.line_array[i]->y > (doc_y + height))
|
|
{
|
|
end = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we have a GC draw the lines that overlap the exposed area.
|
|
*/
|
|
if (hw->html.drawGC != NULL)
|
|
{
|
|
for (i=start; i<=end; i++)
|
|
{
|
|
PlaceLine(hw, i);
|
|
}
|
|
#ifdef EXTRA_FLUSH
|
|
XFlush(XtDisplay(hw));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
#ifdef _NO_PROTO
|
|
ViewClearAndRefresh (hw)
|
|
HTMLWidget hw;
|
|
#else
|
|
ViewClearAndRefresh(
|
|
HTMLWidget hw)
|
|
#endif
|
|
{
|
|
#ifdef FAKE_EXPOSE
|
|
/*
|
|
* This is some scary shit. The first argument in DrawExpose is
|
|
* not used so 0 is OK but I am still getting queasy. The reason
|
|
* this is being done is because there are problems on some machines
|
|
* with refreshes. This may be bad because at this point there
|
|
* may not be a window. This seemed to be the easiest way to solve it
|
|
* but I will try to figure out a better way. john.
|
|
*/
|
|
if (hw->html.drawGC == NULL)
|
|
{
|
|
XEvent xe;
|
|
|
|
xe.xany.type = Expose;
|
|
|
|
DrawExpose(0, (caddr_t)hw, &xe);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Only refresh if we have a window already.
|
|
* (if we have a GC we have a window)
|
|
*/
|
|
if (hw->html.drawGC != NULL)
|
|
{
|
|
XClearArea(XtDisplay(hw->html.view), XtWindow(hw->html.view),
|
|
0, 0, 0, 0, False);
|
|
ViewRedisplay(hw, 0, 0,
|
|
hw->html.view_width, hw->html.view_height);
|
|
/*
|
|
* This is a fake deal to make an Expose event tocall Redisplay
|
|
* to redraw the shadow around the view area
|
|
*/
|
|
XClearArea(XtDisplay(hw), XtWindow(hw),
|
|
0, 0, 1, 1, True);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* The Redisplay function is what you do with an expose event.
|
|
* Right now we call user callbacks, and then call the CompositeWidget's
|
|
* Redisplay routine.
|
|
*/
|
|
static void
|
|
#ifdef _NO_PROTO
|
|
Redisplay (hw, event, region)
|
|
HTMLWidget hw;
|
|
XEvent * event;
|
|
Region region;
|
|
#else
|
|
Redisplay(
|
|
HTMLWidget hw,
|
|
XEvent * event,
|
|
Region region)
|
|
#endif
|
|
{
|
|
int dx, dy;
|
|
|
|
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);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* Resize is called when the widget changes size.
|
|
* Mostly any resize causes a reformat, except for the special case
|
|
* where the width doesn't change, and the height doesn't change
|
|
* enought to affect the vertical scrollbar.
|
|
* It is too complex to guess exactly what needs to be redrawn, so refresh the
|
|
* whole window on any resize.
|
|
*/
|
|
static void
|
|
#ifdef _NO_PROTO
|
|
Resize (hw)
|
|
HTMLWidget hw;
|
|
#else
|
|
Resize(
|
|
HTMLWidget hw)
|
|
#endif
|
|
{
|
|
int tempw;
|
|
Dimension swidth, sheight;
|
|
Dimension st;
|
|
|
|
/*
|
|
* Find the new widht of the viewing area.
|
|
*/
|
|
swidth = VbarWidth(hw);
|
|
sheight = HbarHeight(hw);
|
|
st = 0;
|
|
if (hw->core.width <= swidth)
|
|
{
|
|
hw->core.width = swidth + 10 ;
|
|
}
|
|
|
|
if (hw->html.use_vbar == True)
|
|
{
|
|
tempw = hw->core.width - swidth - (2 * st);
|
|
}
|
|
else
|
|
{
|
|
tempw = hw->core.width - (2 * st);
|
|
/* fool positioning of horz scrollbar later */
|
|
swidth = 0;
|
|
}
|
|
|
|
/*
|
|
* Special case where we don't have to reformat to a new width.
|
|
* The width has not changed, and the height has not changed
|
|
* significantly to change the state of the vertical scrollbar.
|
|
*/
|
|
if ((tempw == hw->html.view_width)&&
|
|
(((hw->html.use_vbar == True)&&
|
|
((hw->core.height - sheight - (2 * st)) < hw->html.doc_height))||
|
|
((hw->html.use_vbar == False)&&
|
|
((hw->core.height - sheight - (2 * st)) >= hw->html.doc_height))))
|
|
{
|
|
/*
|
|
* Super special case where the size of the window hasn't
|
|
* changed at ALL!
|
|
*/
|
|
if (((hw->html.use_hbar == True)&&(hw->html.view_height ==
|
|
(hw->core.height - sheight - (2 * st))))||
|
|
((hw->html.use_hbar == False)&&(hw->html.view_height ==
|
|
(hw->core.height - (2 * st)))))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (hw->html.use_hbar == True)
|
|
{
|
|
if (hw->html.hbar_top == True)
|
|
{
|
|
if (hw->html.vbar_right == True)
|
|
{
|
|
XtMoveWidget(hw->html.hbar, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
XtMoveWidget(hw->html.hbar, swidth, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (hw->html.vbar_right == True)
|
|
{
|
|
XtMoveWidget(hw->html.hbar, 0,
|
|
(hw->core.height - sheight));
|
|
}
|
|
else
|
|
{
|
|
XtMoveWidget(hw->html.hbar, swidth,
|
|
(hw->core.height - sheight));
|
|
}
|
|
}
|
|
hw->html.view_height = hw->core.height - sheight -
|
|
(2 * st);
|
|
}
|
|
else
|
|
{
|
|
hw->html.view_height = hw->core.height - (2 * st);
|
|
}
|
|
#ifdef DEBUG
|
|
fprintf (stderr, "calling in Resize\n");
|
|
#endif
|
|
ConfigScrollBars(hw);
|
|
ScrollWidgets(hw);
|
|
ViewClearAndRefresh(hw);
|
|
}
|
|
/*
|
|
* Otherwise we have to do a full reformat on every resize.
|
|
*/
|
|
else
|
|
{
|
|
ReformatWindow(hw);
|
|
ScrollWidgets(hw);
|
|
ViewClearAndRefresh(hw);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
int ss;
|
|
XtVaGetValues(hw->html.vbar, XmNsliderSize, &ss, NULL);
|
|
fprintf (stderr, "leaving; slider size %d\n", ss);
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* Find the complete text for this the anchor that aptr is a part of
|
|
* and set it into the selection.
|
|
*/
|
|
static void
|
|
FindSelectAnchor(hw, aptr)
|
|
HTMLWidget hw;
|
|
struct ele_rec *aptr;
|
|
{
|
|
struct ele_rec *eptr;
|
|
|
|
eptr = aptr;
|
|
while ((eptr->prev != NULL)&&
|
|
(eptr->prev->anchorHRef != NULL)&&
|
|
(strcmp(eptr->prev->anchorHRef, eptr->anchorHRef) == 0))
|
|
{
|
|
eptr = eptr->prev;
|
|
}
|
|
hw->html.select_start = eptr;
|
|
hw->html.sel_start_pos = 0;
|
|
|
|
eptr = aptr;
|
|
while ((eptr->next != NULL)&&
|
|
(eptr->next->anchorHRef != NULL)&&
|
|
(strcmp(eptr->next->anchorHRef, eptr->anchorHRef) == 0))
|
|
{
|
|
eptr = eptr->next;
|
|
}
|
|
hw->html.select_end = eptr;
|
|
hw->html.sel_end_pos = eptr->edata_len - 2;
|
|
}
|
|
|
|
|
|
/*
|
|
* Set as active all elements in the widget that are part of the anchor
|
|
* in the widget's start ptr.
|
|
*/
|
|
static void
|
|
SetAnchor(hw)
|
|
HTMLWidget hw;
|
|
{
|
|
struct ele_rec *eptr;
|
|
struct ele_rec *start;
|
|
struct ele_rec *end;
|
|
unsigned long fg, bg;
|
|
unsigned long old_fg, old_bg;
|
|
|
|
eptr = hw->html.active_anchor;
|
|
if ((eptr == NULL)||(eptr->anchorHRef == NULL))
|
|
{
|
|
return;
|
|
}
|
|
fg = hw->html.activeAnchor_fg;
|
|
bg = hw->html.activeAnchor_bg;
|
|
|
|
FindSelectAnchor(hw, eptr);
|
|
|
|
start = hw->html.select_start;
|
|
end = hw->html.select_end;
|
|
|
|
eptr = start;
|
|
while ((eptr != NULL)&&(eptr != end))
|
|
{
|
|
if (eptr->type == E_TEXT)
|
|
{
|
|
old_fg = eptr->fg;
|
|
old_bg = eptr->bg;
|
|
eptr->fg = fg;
|
|
eptr->bg = bg;
|
|
TextRefresh(hw, eptr,
|
|
0, (eptr->edata_len - 2));
|
|
eptr->fg = old_fg;
|
|
eptr->bg = old_bg;
|
|
}
|
|
else if (eptr->type == E_IMAGE)
|
|
{
|
|
old_fg = eptr->fg;
|
|
old_bg = eptr->bg;
|
|
eptr->fg = fg;
|
|
eptr->bg = bg;
|
|
ImageRefresh(hw, eptr);
|
|
eptr->fg = old_fg;
|
|
eptr->bg = old_bg;
|
|
}
|
|
/*
|
|
* Linefeeds in anchor spanning multiple lines should NOT
|
|
* be highlighted!
|
|
else if (eptr->type == E_LINEFEED)
|
|
{
|
|
old_fg = eptr->fg;
|
|
old_bg = eptr->bg;
|
|
eptr->fg = fg;
|
|
eptr->bg = bg;
|
|
LinefeedRefresh(hw, eptr);
|
|
eptr->fg = old_fg;
|
|
eptr->bg = old_bg;
|
|
}
|
|
*/
|
|
eptr = eptr->next;
|
|
}
|
|
if (eptr != NULL)
|
|
{
|
|
if (eptr->type == E_TEXT)
|
|
{
|
|
old_fg = eptr->fg;
|
|
old_bg = eptr->bg;
|
|
eptr->fg = fg;
|
|
eptr->bg = bg;
|
|
TextRefresh(hw, eptr,
|
|
0, (eptr->edata_len - 2));
|
|
eptr->fg = old_fg;
|
|
eptr->bg = old_bg;
|
|
}
|
|
else if (eptr->type == E_IMAGE)
|
|
{
|
|
old_fg = eptr->fg;
|
|
old_bg = eptr->bg;
|
|
eptr->fg = fg;
|
|
eptr->bg = bg;
|
|
ImageRefresh(hw, eptr);
|
|
eptr->fg = old_fg;
|
|
eptr->bg = old_bg;
|
|
}
|
|
/*
|
|
* Linefeeds in anchor spanning multiple lines should NOT
|
|
* be highlighted!
|
|
else if (eptr->type == E_LINEFEED)
|
|
{
|
|
old_fg = eptr->fg;
|
|
old_bg = eptr->bg;
|
|
eptr->fg = fg;
|
|
eptr->bg = bg;
|
|
LinefeedRefresh(hw, eptr);
|
|
eptr->fg = old_fg;
|
|
eptr->bg = old_bg;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Draw selection for all elements in the widget
|
|
* from start to end.
|
|
*/
|
|
static void
|
|
DrawSelection(hw, start, end, start_pos, end_pos)
|
|
HTMLWidget hw;
|
|
struct ele_rec *start;
|
|
struct ele_rec *end;
|
|
int start_pos, end_pos;
|
|
{
|
|
struct ele_rec *eptr;
|
|
int epos;
|
|
|
|
if ((start == NULL)||(end == NULL))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Keep positions within bounds (allows us to be sloppy elsewhere)
|
|
*/
|
|
if (start_pos < 0)
|
|
{
|
|
start_pos = 0;
|
|
}
|
|
if (start_pos >= start->edata_len - 1)
|
|
{
|
|
start_pos = start->edata_len - 2;
|
|
}
|
|
if (end_pos < 0)
|
|
{
|
|
end_pos = 0;
|
|
}
|
|
if (end_pos >= end->edata_len - 1)
|
|
{
|
|
end_pos = end->edata_len - 2;
|
|
}
|
|
|
|
if (SwapElements(start, end, start_pos, end_pos))
|
|
{
|
|
eptr = start;
|
|
start = end;
|
|
end = eptr;
|
|
epos = start_pos;
|
|
start_pos = end_pos;
|
|
end_pos = epos;
|
|
}
|
|
|
|
eptr = start;
|
|
while ((eptr != NULL)&&(eptr != end))
|
|
{
|
|
int p1, p2;
|
|
|
|
if (eptr == start)
|
|
{
|
|
p1 = start_pos;
|
|
}
|
|
else
|
|
{
|
|
p1 = 0;
|
|
}
|
|
p2 = eptr->edata_len - 2;
|
|
|
|
if (eptr->type == E_TEXT)
|
|
{
|
|
eptr->selected = True;
|
|
eptr->start_pos = p1;
|
|
eptr->end_pos = p2;
|
|
TextRefresh(hw, eptr, p1, p2);
|
|
}
|
|
else if (eptr->type == E_LINEFEED)
|
|
{
|
|
eptr->selected = True;
|
|
LinefeedRefresh(hw, eptr);
|
|
}
|
|
eptr = eptr->next;
|
|
}
|
|
if (eptr != NULL)
|
|
{
|
|
int p1, p2;
|
|
|
|
if (eptr == start)
|
|
{
|
|
p1 = start_pos;
|
|
}
|
|
else
|
|
{
|
|
p1 = 0;
|
|
}
|
|
|
|
if (eptr == end)
|
|
{
|
|
p2 = end_pos;
|
|
}
|
|
else
|
|
{
|
|
p2 = eptr->edata_len - 2;
|
|
}
|
|
|
|
if (eptr->type == E_TEXT)
|
|
{
|
|
eptr->selected = True;
|
|
eptr->start_pos = p1;
|
|
eptr->end_pos = p2;
|
|
TextRefresh(hw, eptr, p1, p2);
|
|
}
|
|
else if (eptr->type == E_LINEFEED)
|
|
{
|
|
eptr->selected = True;
|
|
LinefeedRefresh(hw, eptr);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Set selection for all elements in the widget's
|
|
* start to end list.
|
|
*/
|
|
static void
|
|
SetSelection(hw)
|
|
HTMLWidget hw;
|
|
{
|
|
struct ele_rec *start;
|
|
struct ele_rec *end;
|
|
int start_pos, end_pos;
|
|
|
|
start = hw->html.select_start;
|
|
end = hw->html.select_end;
|
|
start_pos = hw->html.sel_start_pos;
|
|
end_pos = hw->html.sel_end_pos;
|
|
DrawSelection(hw, start, end, start_pos, end_pos);
|
|
}
|
|
|
|
|
|
/*
|
|
* Erase the selection from start to end
|
|
*/
|
|
static void
|
|
EraseSelection(hw, start, end, start_pos, end_pos)
|
|
HTMLWidget hw;
|
|
struct ele_rec *start;
|
|
struct ele_rec *end;
|
|
int start_pos, end_pos;
|
|
{
|
|
struct ele_rec *eptr;
|
|
int epos;
|
|
|
|
if ((start == NULL)||(end == NULL))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Keep positoins within bounds (allows us to be sloppy elsewhere)
|
|
*/
|
|
if (start_pos < 0)
|
|
{
|
|
start_pos = 0;
|
|
}
|
|
if (start_pos >= start->edata_len - 1)
|
|
{
|
|
start_pos = start->edata_len - 2;
|
|
}
|
|
if (end_pos < 0)
|
|
{
|
|
end_pos = 0;
|
|
}
|
|
if (end_pos >= end->edata_len - 1)
|
|
{
|
|
end_pos = end->edata_len - 2;
|
|
}
|
|
|
|
if (SwapElements(start, end, start_pos, end_pos))
|
|
{
|
|
eptr = start;
|
|
start = end;
|
|
end = eptr;
|
|
epos = start_pos;
|
|
start_pos = end_pos;
|
|
end_pos = epos;
|
|
}
|
|
|
|
eptr = start;
|
|
while ((eptr != NULL)&&(eptr != end))
|
|
{
|
|
int p1, p2;
|
|
|
|
if (eptr == start)
|
|
{
|
|
p1 = start_pos;
|
|
}
|
|
else
|
|
{
|
|
p1 = 0;
|
|
}
|
|
p2 = eptr->edata_len - 2;
|
|
|
|
if (eptr->type == E_TEXT)
|
|
{
|
|
eptr->selected = False;
|
|
TextRefresh(hw, eptr, p1, p2);
|
|
}
|
|
else if (eptr->type == E_LINEFEED)
|
|
{
|
|
eptr->selected = False;
|
|
LinefeedRefresh(hw, eptr);
|
|
}
|
|
eptr = eptr->next;
|
|
}
|
|
if (eptr != NULL)
|
|
{
|
|
int p1, p2;
|
|
|
|
if (eptr == start)
|
|
{
|
|
p1 = start_pos;
|
|
}
|
|
else
|
|
{
|
|
p1 = 0;
|
|
}
|
|
|
|
if (eptr == end)
|
|
{
|
|
p2 = end_pos;
|
|
}
|
|
else
|
|
{
|
|
p2 = eptr->edata_len - 2;
|
|
}
|
|
|
|
if (eptr->type == E_TEXT)
|
|
{
|
|
eptr->selected = False;
|
|
TextRefresh(hw, eptr, p1, p2);
|
|
}
|
|
else if (eptr->type == E_LINEFEED)
|
|
{
|
|
eptr->selected = False;
|
|
LinefeedRefresh(hw, eptr);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Clear the current selection (if there is one)
|
|
*/
|
|
static void
|
|
ClearSelection(hw)
|
|
HTMLWidget hw;
|
|
{
|
|
struct ele_rec *start;
|
|
struct ele_rec *end;
|
|
int start_pos, end_pos;
|
|
|
|
start = hw->html.select_start;
|
|
end = hw->html.select_end;
|
|
start_pos = hw->html.sel_start_pos;
|
|
end_pos = hw->html.sel_end_pos;
|
|
EraseSelection(hw, start, end, start_pos, end_pos);
|
|
|
|
if ((start == NULL)||(end == NULL))
|
|
{
|
|
hw->html.select_start = NULL;
|
|
hw->html.select_end = NULL;
|
|
hw->html.sel_start_pos = 0;
|
|
hw->html.sel_end_pos = 0;
|
|
hw->html.active_anchor = NULL;
|
|
return;
|
|
}
|
|
|
|
hw->html.select_start = NULL;
|
|
hw->html.select_end = NULL;
|
|
hw->html.sel_start_pos = 0;
|
|
hw->html.sel_end_pos = 0;
|
|
hw->html.active_anchor = NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* clear from active all elements in the widget that are part of the anchor.
|
|
* (These have already been previously set into the start and end of the
|
|
* selection.
|
|
*/
|
|
static void
|
|
UnsetAnchor(hw)
|
|
HTMLWidget hw;
|
|
{
|
|
struct ele_rec *eptr;
|
|
|
|
/*
|
|
* Clear any activated images
|
|
*/
|
|
eptr = hw->html.select_start;
|
|
while ((eptr != NULL)&&(eptr != hw->html.select_end))
|
|
{
|
|
if (eptr->type == E_IMAGE)
|
|
{
|
|
ImageRefresh(hw, eptr);
|
|
}
|
|
eptr = eptr->next;
|
|
}
|
|
if ((eptr != NULL)&&(eptr->type == E_IMAGE))
|
|
{
|
|
ImageRefresh(hw, eptr);
|
|
}
|
|
|
|
/*
|
|
* Clear the activated anchor
|
|
*/
|
|
ClearSelection(hw);
|
|
}
|
|
|
|
|
|
/*
|
|
* Erase the old selection, and draw the new one in such a way
|
|
* that advantage is taken of overlap, and there is no obnoxious
|
|
* flashing.
|
|
*/
|
|
static void
|
|
ChangeSelection(hw, start, end, start_pos, end_pos)
|
|
HTMLWidget hw;
|
|
struct ele_rec *start;
|
|
struct ele_rec *end;
|
|
int start_pos, end_pos;
|
|
{
|
|
struct ele_rec *old_start;
|
|
struct ele_rec *old_end;
|
|
struct ele_rec *new_start;
|
|
struct ele_rec *new_end;
|
|
struct ele_rec *eptr;
|
|
int epos;
|
|
int new_start_pos, new_end_pos;
|
|
int old_start_pos, old_end_pos;
|
|
|
|
old_start = hw->html.new_start;
|
|
old_end = hw->html.new_end;
|
|
old_start_pos = hw->html.new_start_pos;
|
|
old_end_pos = hw->html.new_end_pos;
|
|
new_start = start;
|
|
new_end = end;
|
|
new_start_pos = start_pos;
|
|
new_end_pos = end_pos;
|
|
|
|
if ((new_start == NULL)||(new_end == NULL))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((old_start == NULL)||(old_end == NULL))
|
|
{
|
|
DrawSelection(hw, new_start, new_end,
|
|
new_start_pos, new_end_pos);
|
|
return;
|
|
}
|
|
|
|
if (SwapElements(old_start, old_end, old_start_pos, old_end_pos))
|
|
{
|
|
eptr = old_start;
|
|
old_start = old_end;
|
|
old_end = eptr;
|
|
epos = old_start_pos;
|
|
old_start_pos = old_end_pos;
|
|
old_end_pos = epos;
|
|
}
|
|
|
|
if (SwapElements(new_start, new_end, new_start_pos, new_end_pos))
|
|
{
|
|
eptr = new_start;
|
|
new_start = new_end;
|
|
new_end = eptr;
|
|
epos = new_start_pos;
|
|
new_start_pos = new_end_pos;
|
|
new_end_pos = epos;
|
|
}
|
|
|
|
/*
|
|
* Deal with all possible intersections of the 2 selection sets.
|
|
*
|
|
********************************************************
|
|
* * *
|
|
* |-- * |-- *
|
|
* old--| * new--| *
|
|
* |-- * |-- *
|
|
* * *
|
|
* |-- * |-- *
|
|
* new--| * old--| *
|
|
* |-- * |-- *
|
|
* * *
|
|
********************************************************
|
|
* * *
|
|
* |---- * |-- *
|
|
* old--| * new--| *
|
|
* | |-- * | *
|
|
* |-+-- * |-+-- *
|
|
* | * | |-- *
|
|
* new--| * old--| *
|
|
* |-- * |---- *
|
|
* * *
|
|
********************************************************
|
|
* * *
|
|
* |--------- * |--------- *
|
|
* | * | *
|
|
* | |-- * | |-- *
|
|
* new--| old--| * old--| new--| *
|
|
* | |-- * | |-- *
|
|
* | * | *
|
|
* |--------- * |--------- *
|
|
* * *
|
|
********************************************************
|
|
*
|
|
*/
|
|
if ((ElementLessThan(old_end, new_start, old_end_pos, new_start_pos))||
|
|
(ElementLessThan(new_end, old_start, new_end_pos, old_start_pos)))
|
|
{
|
|
EraseSelection(hw, old_start, old_end,
|
|
old_start_pos, old_end_pos);
|
|
DrawSelection(hw, new_start, new_end,
|
|
new_start_pos, new_end_pos);
|
|
}
|
|
else if ((ElementLessThan(old_start, new_start,
|
|
old_start_pos, new_start_pos))&&
|
|
(ElementLessThan(old_end, new_end, old_end_pos, new_end_pos)))
|
|
{
|
|
if (new_start_pos != 0)
|
|
{
|
|
EraseSelection(hw, old_start, new_start,
|
|
old_start_pos, new_start_pos - 1);
|
|
}
|
|
else
|
|
{
|
|
EraseSelection(hw, old_start, new_start->prev,
|
|
old_start_pos, new_start->prev->edata_len - 2);
|
|
}
|
|
if (old_end_pos < (old_end->edata_len - 2))
|
|
{
|
|
DrawSelection(hw, old_end, new_end,
|
|
old_end_pos + 1, new_end_pos);
|
|
}
|
|
else
|
|
{
|
|
DrawSelection(hw, old_end->next, new_end,
|
|
0, new_end_pos);
|
|
}
|
|
}
|
|
else if ((ElementLessThan(new_start, old_start,
|
|
new_start_pos, old_start_pos))&&
|
|
(ElementLessThan(new_end, old_end, new_end_pos, old_end_pos)))
|
|
{
|
|
if (old_start_pos != 0)
|
|
{
|
|
DrawSelection(hw, new_start, old_start,
|
|
new_start_pos, old_start_pos - 1);
|
|
}
|
|
else
|
|
{
|
|
DrawSelection(hw, new_start, old_start->prev,
|
|
new_start_pos, old_start->prev->edata_len - 2);
|
|
}
|
|
if (new_end_pos < (new_end->edata_len - 2))
|
|
{
|
|
EraseSelection(hw, new_end, old_end,
|
|
new_end_pos + 1, old_end_pos);
|
|
}
|
|
else
|
|
{
|
|
EraseSelection(hw, new_end->next, old_end,
|
|
0, old_end_pos);
|
|
}
|
|
}
|
|
else if ((ElementLessThan(new_start, old_start,
|
|
new_start_pos, old_start_pos))||
|
|
(ElementLessThan(old_end, new_end, old_end_pos, new_end_pos)))
|
|
{
|
|
if ((new_start != old_start)||(new_start_pos != old_start_pos))
|
|
{
|
|
if (old_start_pos != 0)
|
|
{
|
|
DrawSelection(hw, new_start, old_start,
|
|
new_start_pos, old_start_pos - 1);
|
|
}
|
|
else
|
|
{
|
|
DrawSelection(hw, new_start, old_start->prev,
|
|
new_start_pos,
|
|
old_start->prev->edata_len - 2);
|
|
}
|
|
}
|
|
if ((old_end != new_end)||(old_end_pos != new_end_pos))
|
|
{
|
|
if (old_end_pos < (old_end->edata_len - 2))
|
|
{
|
|
DrawSelection(hw, old_end, new_end,
|
|
old_end_pos + 1, new_end_pos);
|
|
}
|
|
else
|
|
{
|
|
DrawSelection(hw, old_end->next, new_end,
|
|
0, new_end_pos);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((old_start != new_start)||(old_start_pos != new_start_pos))
|
|
{
|
|
if (new_start_pos != 0)
|
|
{
|
|
EraseSelection(hw, old_start, new_start,
|
|
old_start_pos, new_start_pos - 1);
|
|
}
|
|
else
|
|
{
|
|
EraseSelection(hw, old_start, new_start->prev,
|
|
old_start_pos,
|
|
new_start->prev->edata_len - 2);
|
|
}
|
|
}
|
|
if ((new_end != old_end)||(new_end_pos != old_end_pos))
|
|
{
|
|
if (new_end_pos < (new_end->edata_len - 2))
|
|
{
|
|
EraseSelection(hw, new_end, old_end,
|
|
new_end_pos + 1, old_end_pos);
|
|
}
|
|
else
|
|
{
|
|
EraseSelection(hw, new_end->next, old_end,
|
|
0, old_end_pos);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
SelectStart(w, event, params, num_params)
|
|
Widget w;
|
|
XEvent *event;
|
|
String *params; /* unused */
|
|
Cardinal *num_params; /* unused */
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)XtParent(w);
|
|
XButtonPressedEvent *BuEvent = (XButtonPressedEvent *)event;
|
|
struct ele_rec *eptr;
|
|
int epos;
|
|
|
|
if (XtClass(XtParent(w)) != htmlWidgetClass)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#ifdef NOT_RIGHT
|
|
XUndefineCursor(XtDisplay(hw->html.view), XtWindow(hw->html.view));
|
|
#endif
|
|
XUndefineCursor(XtDisplay(hw), XtWindow(hw));
|
|
|
|
/*
|
|
* Because X sucks, we can get the button pressed in the window, but
|
|
* released out of the window. This will highlight some text, but
|
|
* never complete the selection. Now on the next button press we
|
|
* have to clean up this mess.
|
|
*/
|
|
EraseSelection(hw, hw->html.new_start, hw->html.new_end,
|
|
hw->html.new_start_pos, hw->html.new_end_pos);
|
|
|
|
/*
|
|
* We want to erase the currently selected text, but still save the
|
|
* selection internally in case we don't create a new one.
|
|
*/
|
|
EraseSelection(hw, hw->html.select_start, hw->html.select_end,
|
|
hw->html.sel_start_pos, hw->html.sel_end_pos);
|
|
hw->html.new_start = hw->html.select_start;
|
|
hw->html.new_end = NULL;
|
|
hw->html.new_start_pos = hw->html.sel_start_pos;
|
|
hw->html.new_end_pos = 0;
|
|
|
|
eptr = LocateElement(hw, BuEvent->x, BuEvent->y, &epos);
|
|
if (eptr != NULL)
|
|
{
|
|
/*
|
|
* If this is an anchor assume for now we are activating it
|
|
* and not selecting it.
|
|
*/
|
|
if (eptr->anchorHRef != NULL)
|
|
{
|
|
hw->html.active_anchor = eptr;
|
|
hw->html.press_x = BuEvent->x;
|
|
hw->html.press_y = BuEvent->y;
|
|
SetAnchor(hw);
|
|
}
|
|
/*
|
|
* Else if we are on an image we can't select text so
|
|
* pretend we got eptr==NULL, and exit here.
|
|
*/
|
|
else if (eptr->type == E_IMAGE)
|
|
{
|
|
hw->html.new_start = NULL;
|
|
hw->html.new_end = NULL;
|
|
hw->html.new_start_pos = 0;
|
|
hw->html.new_end_pos = 0;
|
|
hw->html.press_x = BuEvent->x;
|
|
hw->html.press_y = BuEvent->y;
|
|
hw->html.but_press_time = BuEvent->time;
|
|
return;
|
|
}
|
|
/*
|
|
* Else if we used button2, we can't select text, so exit
|
|
* here.
|
|
*/
|
|
else if (BuEvent->button == Button2)
|
|
{
|
|
hw->html.press_x = BuEvent->x;
|
|
hw->html.press_y = BuEvent->y;
|
|
hw->html.but_press_time = BuEvent->time;
|
|
return;
|
|
}
|
|
/*
|
|
* Else a single click will not select a new object
|
|
* but it will prime that selection on the next mouse
|
|
* move.
|
|
* Ignore special internal text
|
|
*/
|
|
else if (eptr->internal == False)
|
|
{
|
|
hw->html.new_start = eptr;
|
|
hw->html.new_start_pos = epos;
|
|
hw->html.new_end = NULL;
|
|
hw->html.new_end_pos = 0;
|
|
hw->html.press_x = BuEvent->x;
|
|
hw->html.press_y = BuEvent->y;
|
|
}
|
|
else
|
|
{
|
|
hw->html.new_start = NULL;
|
|
hw->html.new_end = NULL;
|
|
hw->html.new_start_pos = 0;
|
|
hw->html.new_end_pos = 0;
|
|
hw->html.press_x = BuEvent->x;
|
|
hw->html.press_y = BuEvent->y;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hw->html.new_start = NULL;
|
|
hw->html.new_end = NULL;
|
|
hw->html.new_start_pos = 0;
|
|
hw->html.new_end_pos = 0;
|
|
hw->html.press_x = BuEvent->x;
|
|
hw->html.press_y = BuEvent->y;
|
|
}
|
|
hw->html.but_press_time = BuEvent->time;
|
|
}
|
|
|
|
|
|
static void
|
|
ExtendStart(w, event, params, num_params)
|
|
Widget w;
|
|
XEvent *event;
|
|
String *params; /* unused */
|
|
Cardinal *num_params; /* unused */
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)XtParent(w);
|
|
XButtonPressedEvent *BuEvent = (XButtonPressedEvent *)event;
|
|
struct ele_rec *eptr;
|
|
struct ele_rec *start, *end;
|
|
struct ele_rec *old_start, *old_end;
|
|
int old_start_pos, old_end_pos;
|
|
int start_pos, end_pos;
|
|
int epos;
|
|
|
|
if (XtClass(XtParent(w)) != htmlWidgetClass)
|
|
{
|
|
return;
|
|
}
|
|
|
|
eptr = LocateElement(hw, BuEvent->x, BuEvent->y, &epos);
|
|
|
|
/*
|
|
* Ignore IMAGE elements.
|
|
*/
|
|
if ((eptr != NULL)&&(eptr->type == E_IMAGE))
|
|
{
|
|
eptr = NULL;
|
|
}
|
|
|
|
/*
|
|
* Ignore NULL elements.
|
|
* Ignore special internal text
|
|
* documents.
|
|
*/
|
|
if ((eptr != NULL)&&(eptr->internal == False))
|
|
{
|
|
old_start = hw->html.new_start;
|
|
old_start_pos = hw->html.new_start_pos;
|
|
old_end = hw->html.new_end;
|
|
old_end_pos = hw->html.new_end_pos;
|
|
if (hw->html.new_start == NULL)
|
|
{
|
|
hw->html.new_start = hw->html.select_start;
|
|
hw->html.new_start_pos = hw->html.sel_start_pos;
|
|
hw->html.new_end = hw->html.select_end;
|
|
hw->html.new_end_pos = hw->html.sel_end_pos;
|
|
}
|
|
else
|
|
{
|
|
hw->html.new_end = eptr;
|
|
hw->html.new_end_pos = epos;
|
|
}
|
|
|
|
if (SwapElements(hw->html.new_start, hw->html.new_end,
|
|
hw->html.new_start_pos, hw->html.new_end_pos))
|
|
{
|
|
if (SwapElements(eptr, hw->html.new_end,
|
|
epos, hw->html.new_end_pos))
|
|
{
|
|
start = hw->html.new_end;
|
|
start_pos = hw->html.new_end_pos;
|
|
end = eptr;
|
|
end_pos = epos;
|
|
}
|
|
else
|
|
{
|
|
start = hw->html.new_start;
|
|
start_pos = hw->html.new_start_pos;
|
|
end = eptr;
|
|
end_pos = epos;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (SwapElements(eptr, hw->html.new_start,
|
|
epos, hw->html.new_start_pos))
|
|
{
|
|
start = hw->html.new_start;
|
|
start_pos = hw->html.new_start_pos;
|
|
end = eptr;
|
|
end_pos = epos;
|
|
}
|
|
else
|
|
{
|
|
start = hw->html.new_end;
|
|
start_pos = hw->html.new_end_pos;
|
|
end = eptr;
|
|
end_pos = epos;
|
|
}
|
|
}
|
|
|
|
if (start == NULL)
|
|
{
|
|
start = eptr;
|
|
start_pos = epos;
|
|
}
|
|
|
|
if (old_start == NULL)
|
|
{
|
|
hw->html.new_start = hw->html.select_start;
|
|
hw->html.new_end = hw->html.select_end;
|
|
hw->html.new_start_pos = hw->html.sel_start_pos;
|
|
hw->html.new_end_pos = hw->html.sel_end_pos;
|
|
}
|
|
else
|
|
{
|
|
hw->html.new_start = old_start;
|
|
hw->html.new_end = old_end;
|
|
hw->html.new_start_pos = old_start_pos;
|
|
hw->html.new_end_pos = old_end_pos;
|
|
}
|
|
ChangeSelection(hw, start, end, start_pos, end_pos);
|
|
hw->html.new_start = start;
|
|
hw->html.new_end = end;
|
|
hw->html.new_start_pos = start_pos;
|
|
hw->html.new_end_pos = end_pos;
|
|
}
|
|
else
|
|
{
|
|
if (hw->html.new_start == NULL)
|
|
{
|
|
hw->html.new_start = hw->html.select_start;
|
|
hw->html.new_start_pos = hw->html.sel_start_pos;
|
|
hw->html.new_end = hw->html.select_end;
|
|
hw->html.new_end_pos = hw->html.sel_end_pos;
|
|
}
|
|
}
|
|
hw->html.press_x = BuEvent->x;
|
|
hw->html.press_y = BuEvent->y;
|
|
}
|
|
|
|
|
|
static void
|
|
ExtendAdjust(w, event, params, num_params)
|
|
Widget w;
|
|
XEvent *event;
|
|
String *params; /* unused */
|
|
Cardinal *num_params; /* unused */
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)XtParent(w);
|
|
XPointerMovedEvent *MoEvent = (XPointerMovedEvent *)event;
|
|
struct ele_rec *eptr;
|
|
struct ele_rec *start, *end;
|
|
int start_pos, end_pos;
|
|
int epos;
|
|
|
|
if (XtClass(XtParent(w)) != htmlWidgetClass)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Very small mouse motion immediately after button press
|
|
* is ignored.
|
|
*/
|
|
if ((ABS((hw->html.press_x - MoEvent->x)) <= SELECT_THRESHOLD)&&
|
|
(ABS((hw->html.press_y - MoEvent->y)) <= SELECT_THRESHOLD))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* If we have an active anchor and we got here, we have moved the
|
|
* mouse too far. Deactivate anchor, and prime a selection.
|
|
* If the anchor is internal text, don't
|
|
* prime a selection.
|
|
*/
|
|
if (hw->html.active_anchor != NULL)
|
|
{
|
|
eptr = hw->html.active_anchor;
|
|
UnsetAnchor(hw);
|
|
if (eptr->internal == False)
|
|
{
|
|
hw->html.new_start = NULL;
|
|
hw->html.new_start_pos = 0;
|
|
hw->html.new_end = NULL;
|
|
hw->html.new_end_pos = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we used button2, we can't select text, so
|
|
* clear selection and exit here.
|
|
*/
|
|
if ((MoEvent->state & Button1Mask) == 0)
|
|
{
|
|
hw->html.select_start = NULL;
|
|
hw->html.select_end = NULL;
|
|
hw->html.sel_start_pos = 0;
|
|
hw->html.sel_end_pos = 0;
|
|
hw->html.new_start = NULL;
|
|
hw->html.new_end = NULL;
|
|
hw->html.new_start_pos = 0;
|
|
hw->html.new_end_pos = 0;
|
|
return;
|
|
}
|
|
|
|
eptr = LocateElement(hw, MoEvent->x, MoEvent->y, &epos);
|
|
|
|
/*
|
|
* If we are on an image pretend we are nowhere
|
|
* and just return;
|
|
*/
|
|
if ((eptr != NULL)&&(eptr->type == E_IMAGE))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Ignore NULL items.
|
|
* Ignore if the same as last selected item and position.
|
|
* Ignore special internal text
|
|
*/
|
|
if ((eptr != NULL)&&
|
|
((eptr != hw->html.new_end)||(epos != hw->html.new_end_pos))&&
|
|
(eptr->internal == False))
|
|
{
|
|
start = hw->html.new_start;
|
|
start_pos = hw->html.new_start_pos;
|
|
end = eptr;
|
|
end_pos = epos;
|
|
if (start == NULL)
|
|
{
|
|
start = eptr;
|
|
start_pos = epos;
|
|
}
|
|
|
|
ChangeSelection(hw, start, end, start_pos, end_pos);
|
|
hw->html.new_start = start;
|
|
hw->html.new_end = end;
|
|
hw->html.new_start_pos = start_pos;
|
|
hw->html.new_end_pos = end_pos;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
ExtendEnd(w, event, params, num_params)
|
|
Widget w;
|
|
XEvent *event;
|
|
String *params;
|
|
Cardinal *num_params;
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)XtParent(w);
|
|
XButtonReleasedEvent *BuEvent = (XButtonReleasedEvent *)event;
|
|
struct ele_rec *eptr;
|
|
struct ele_rec *start, *end;
|
|
Atom *atoms;
|
|
int i, buffer;
|
|
int start_pos, end_pos;
|
|
int epos;
|
|
char *text;
|
|
|
|
if (XtClass(XtParent(w)) != htmlWidgetClass)
|
|
{
|
|
return;
|
|
}
|
|
|
|
eptr = LocateElement(hw, BuEvent->x, BuEvent->y, &epos);
|
|
|
|
/*
|
|
* If we just released button one or two, and we are on an object,
|
|
* and we have an active anchor, and we are on the active anchor,
|
|
* and if we havn't waited too long. Activate that anchor.
|
|
*/
|
|
if (((BuEvent->button == Button1)||(BuEvent->button == Button2))&&
|
|
(eptr != NULL)&&
|
|
(hw->html.active_anchor != NULL)&&
|
|
(eptr == hw->html.active_anchor)&&
|
|
((BuEvent->time - hw->html.but_press_time) < CLICK_TIME))
|
|
{
|
|
_HTMLInput(w, event, params, num_params);
|
|
return;
|
|
}
|
|
else if (hw->html.active_anchor != NULL)
|
|
{
|
|
start = hw->html.active_anchor;
|
|
UnsetAnchor(hw);
|
|
if (start->internal == False)
|
|
{
|
|
hw->html.new_start = eptr;
|
|
hw->html.new_start_pos = epos;
|
|
hw->html.new_end = NULL;
|
|
hw->html.new_end_pos = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we used button2, we can't select text, so clear
|
|
* selection and exit here.
|
|
*/
|
|
if (BuEvent->button == Button2)
|
|
{
|
|
hw->html.new_start = hw->html.select_start;
|
|
hw->html.new_end = NULL;
|
|
hw->html.new_start_pos = hw->html.sel_start_pos;
|
|
hw->html.new_end_pos = 0;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* If we are on an image, pretend we are nowhere
|
|
* and NULL out the eptr
|
|
*/
|
|
if ((eptr != NULL)&&(eptr->type == E_IMAGE))
|
|
{
|
|
eptr = NULL;
|
|
}
|
|
|
|
/*
|
|
* If button released on a NULL item, take the last non-NULL
|
|
* item that we highlighted.
|
|
*/
|
|
if ((eptr == NULL)&&(hw->html.new_end != NULL))
|
|
{
|
|
eptr = hw->html.new_end;
|
|
epos = hw->html.new_end_pos;
|
|
}
|
|
|
|
if ((eptr != NULL)&&(eptr->internal == False)&&
|
|
(hw->html.new_end != NULL))
|
|
{
|
|
start = hw->html.new_start;
|
|
start_pos = hw->html.new_start_pos;
|
|
end = eptr;
|
|
end_pos = epos;
|
|
if (start == NULL)
|
|
{
|
|
start = eptr;
|
|
start_pos = epos;
|
|
}
|
|
ChangeSelection(hw, start, end, start_pos, end_pos);
|
|
hw->html.select_start = start;
|
|
hw->html.sel_start_pos = start_pos;
|
|
hw->html.select_end = end;
|
|
hw->html.sel_end_pos = end_pos;
|
|
SetSelection(hw);
|
|
hw->html.new_start = NULL;
|
|
hw->html.new_end = NULL;
|
|
hw->html.new_start_pos = 0;
|
|
hw->html.new_end_pos = 0;
|
|
|
|
atoms = (Atom *)malloc(*num_params * sizeof(Atom));
|
|
if (atoms == NULL)
|
|
{
|
|
fprintf(stderr, "cannot allocate atom list\n");
|
|
return;
|
|
}
|
|
XmuInternStrings(XtDisplay((Widget)hw), params, *num_params, atoms);
|
|
hw->html.selection_time = BuEvent->time;
|
|
for (i=0; i< *num_params; i++)
|
|
{
|
|
switch (atoms[i])
|
|
{
|
|
case XA_CUT_BUFFER0: buffer = 0; break;
|
|
case XA_CUT_BUFFER1: buffer = 1; break;
|
|
case XA_CUT_BUFFER2: buffer = 2; break;
|
|
case XA_CUT_BUFFER3: buffer = 3; break;
|
|
case XA_CUT_BUFFER4: buffer = 4; break;
|
|
case XA_CUT_BUFFER5: buffer = 5; break;
|
|
case XA_CUT_BUFFER6: buffer = 6; break;
|
|
case XA_CUT_BUFFER7: buffer = 7; break;
|
|
default: buffer = -1; break;
|
|
}
|
|
if (buffer >= 0)
|
|
{
|
|
if (hw->html.fancy_selections == True)
|
|
{
|
|
text = ParseTextToPrettyString(hw,
|
|
hw->html.formatted_elements,
|
|
hw->html.select_start,
|
|
hw->html.select_end,
|
|
hw->html.sel_start_pos,
|
|
hw->html.sel_end_pos,
|
|
hw->html.font->max_bounds.width,
|
|
hw->html.margin_width);
|
|
}
|
|
else
|
|
{
|
|
text = ParseTextToString(
|
|
hw->html.formatted_elements,
|
|
hw->html.select_start,
|
|
hw->html.select_end,
|
|
hw->html.sel_start_pos,
|
|
hw->html.sel_end_pos,
|
|
hw->html.font->max_bounds.width,
|
|
hw->html.margin_width);
|
|
}
|
|
XStoreBuffer(XtDisplay((Widget)hw),
|
|
text, strlen(text), buffer);
|
|
if (text != NULL)
|
|
{
|
|
free(text);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XtOwnSelection((Widget)hw, atoms[i],
|
|
BuEvent->time,
|
|
(XtConvertSelectionProc )ConvertSelection,
|
|
(XtLoseSelectionProc )LoseSelection,
|
|
(XtSelectionDoneProc )SelectionDone);
|
|
}
|
|
}
|
|
free((char *)atoms);
|
|
}
|
|
else if (eptr == NULL)
|
|
{
|
|
hw->html.select_start = NULL;
|
|
hw->html.sel_start_pos = 0;
|
|
hw->html.select_end = NULL;
|
|
hw->html.sel_end_pos = 0;
|
|
hw->html.new_start = NULL;
|
|
hw->html.new_start_pos = 0;
|
|
hw->html.new_end = NULL;
|
|
hw->html.new_end_pos = 0;
|
|
}
|
|
}
|
|
|
|
|
|
#define LEAVING_ANCHOR(hw) \
|
|
hw->html.cached_tracked_ele = NULL; \
|
|
(*(pointerTrackProc) \
|
|
(hw->html.pointer_motion_callback))(hw, ""); \
|
|
XUndefineCursor (XtDisplay (hw), XtWindow (hw));
|
|
|
|
/* KNOWN PROBLEM: We never get LeaveNotify or FocusOut events,
|
|
despite the fact we've requested them. Bummer. */
|
|
static void
|
|
TrackMotion(w, event, params, num_params)
|
|
Widget w;
|
|
XEvent *event;
|
|
String *params; /* unused */
|
|
Cardinal *num_params; /* unused */
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)XtParent(w);
|
|
struct ele_rec *eptr;
|
|
int epos, x, y;
|
|
|
|
if (XtClass(XtParent(w)) != htmlWidgetClass)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!hw->html.pointer_motion_callback)
|
|
return;
|
|
|
|
if (event->type == MotionNotify)
|
|
{
|
|
x = ((XMotionEvent *)event)->x;
|
|
y = ((XMotionEvent *)event)->y;
|
|
}
|
|
else if (event->type == LeaveNotify || event->type == FocusOut ||
|
|
event->type == Expose)
|
|
{
|
|
/* Wipe out. */
|
|
if (hw->html.cached_tracked_ele)
|
|
{
|
|
LEAVING_ANCHOR (hw);
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
eptr = LocateElement(hw, x, y, &epos);
|
|
|
|
/* We're hitting a new anchor if eptr exists and
|
|
eptr != cached tracked element and anchorHRef != NULL. */
|
|
if (eptr != NULL && eptr != hw->html.cached_tracked_ele &&
|
|
eptr->anchorHRef != NULL)
|
|
{
|
|
hw->html.cached_tracked_ele = eptr;
|
|
(*(pointerTrackProc)
|
|
(hw->html.pointer_motion_callback))(hw, eptr->anchorHRef);
|
|
XDefineCursor (XtDisplay (hw), XtWindow (hw), in_anchor_cursor);
|
|
}
|
|
/* We're leaving an anchor if eptr exists and
|
|
a cached ele exists and we're not entering a new anchor. */
|
|
else if (eptr != NULL && hw->html.cached_tracked_ele != NULL &&
|
|
eptr->anchorHRef == NULL)
|
|
{
|
|
LEAVING_ANCHOR (hw);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void
|
|
ScrollUp(w, event, params, num_params)
|
|
Widget w;
|
|
XEvent *event;
|
|
String *params; /* unused */
|
|
Cardinal *num_params; /* unused */
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)XtParent(w);
|
|
|
|
if (XtClass(XtParent(w)) == htmlWidgetClass)
|
|
{
|
|
/*
|
|
* Added by Satoshi ASAMI <asami@cory.EECS.Berkeley.EDU>
|
|
*/
|
|
if (*num_params == 1)
|
|
{
|
|
if (strcmp(params[0], "Oneline") == 0)
|
|
ScrollMove(hw->html.vbar, (caddr_t)hw, DEFAULT_INCREMENT);
|
|
else
|
|
ScrollMove(hw->html.vbar, (caddr_t)hw, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
ScrollDown(w, event, params, num_params)
|
|
Widget w;
|
|
XEvent *event;
|
|
String *params; /* unused */
|
|
Cardinal *num_params; /* unused */
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)XtParent(w);
|
|
|
|
if (XtClass(XtParent(w)) == htmlWidgetClass)
|
|
{
|
|
/*
|
|
* Added by Satoshi ASAMI <asami@cory.EECS.Berkeley.EDU>
|
|
*/
|
|
if (*num_params == 1)
|
|
{
|
|
if (strcmp(params[0], "Oneline") == 0)
|
|
ScrollMove(hw->html.vbar, (caddr_t)hw, -DEFAULT_INCREMENT);
|
|
else
|
|
ScrollMove(hw->html.vbar, (caddr_t)hw, -1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
|
|
if (XtClass(XtParent(w)) != htmlWidgetClass)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (event->type == ButtonRelease)
|
|
{
|
|
eptr = LocateElement(hw, event->xbutton.x, event->xbutton.y,
|
|
&epos);
|
|
if (eptr != NULL)
|
|
{
|
|
if (eptr->anchorHRef != NULL)
|
|
{
|
|
char *tptr, *ptr;
|
|
|
|
/*
|
|
* Save the anchor text, replace newlines with
|
|
* spaces.
|
|
*/
|
|
tptr = ParseTextToString(hw->html.select_start,
|
|
hw->html.select_start, hw->html.select_end,
|
|
hw->html.sel_start_pos, hw->html.sel_end_pos,
|
|
hw->html.font->max_bounds.width,
|
|
hw->html.margin_width);
|
|
ptr = tptr;
|
|
while ((ptr != NULL)&&(*ptr != '\0'))
|
|
{
|
|
if (*ptr == '\n')
|
|
{
|
|
*ptr = ' ';
|
|
}
|
|
ptr++;
|
|
}
|
|
|
|
/*
|
|
* Clear the activated anchor
|
|
*/
|
|
UnsetAnchor(hw);
|
|
#ifdef EXTRA_FLUSH
|
|
XFlush(XtDisplay(hw));
|
|
#endif
|
|
|
|
if ((IsDelayedHRef(hw, eptr->anchorHRef))&&
|
|
(hw->html.resolveDelayedImage != NULL))
|
|
{
|
|
eptr->pic_data = (*(resolveImageProc)
|
|
(hw->html.resolveDelayedImage))(hw, eptr->edata);
|
|
|
|
if (eptr->pic_data == NULL)
|
|
{
|
|
eptr->pic_data = NoImageData(hw);
|
|
eptr->pic_data->delayed = 0;
|
|
eptr->pic_data->internal = 0;
|
|
}
|
|
else
|
|
{
|
|
eptr->pic_data->delayed = 0;
|
|
/*
|
|
* Mark images we have sucessfully
|
|
* loaded at least once
|
|
*/
|
|
if (eptr->pic_data->image_data != NULL)
|
|
{
|
|
eptr->pic_data->fetched = 1;
|
|
}
|
|
/*
|
|
* See if this is a special
|
|
* internal image
|
|
*/
|
|
if ((eptr->edata != NULL)&&
|
|
(strncmp(eptr->edata,
|
|
INTERNAL_IMAGE,
|
|
strlen(INTERNAL_IMAGE)) == 0))
|
|
{
|
|
eptr->pic_data->internal = 1;
|
|
}
|
|
else
|
|
{
|
|
eptr->pic_data->internal = 0;
|
|
}
|
|
}
|
|
|
|
ReformatWindow(hw);
|
|
ScrollWidgets(hw);
|
|
ViewClearAndRefresh(hw);
|
|
}
|
|
else if ((eptr->pic_data != NULL)&&
|
|
(eptr->pic_data->delayed)&&
|
|
(eptr->anchorHRef != NULL)&&
|
|
(IsIsMapForm(hw, eptr->anchorHRef)))
|
|
{
|
|
eptr->pic_data = (*(resolveImageProc)
|
|
(hw->html.resolveDelayedImage))(hw, eptr->edata);
|
|
|
|
if (eptr->pic_data == NULL)
|
|
{
|
|
eptr->pic_data = NoImageData(hw);
|
|
eptr->pic_data->delayed = 0;
|
|
eptr->pic_data->internal = 0;
|
|
}
|
|
else
|
|
{
|
|
eptr->pic_data->delayed = 0;
|
|
/*
|
|
* Mark images we have sucessfully
|
|
* loaded at least once
|
|
*/
|
|
if (eptr->pic_data->image_data != NULL)
|
|
{
|
|
eptr->pic_data->fetched = 1;
|
|
}
|
|
/*
|
|
* See if this is a special
|
|
* internal image
|
|
*/
|
|
if ((eptr->edata != NULL)&&
|
|
(strncmp(eptr->edata,
|
|
INTERNAL_IMAGE,
|
|
strlen(INTERNAL_IMAGE)) == 0))
|
|
{
|
|
eptr->pic_data->internal = 1;
|
|
}
|
|
else
|
|
{
|
|
eptr->pic_data->internal = 0;
|
|
}
|
|
}
|
|
|
|
ReformatWindow(hw);
|
|
ScrollWidgets(hw);
|
|
ViewClearAndRefresh(hw);
|
|
}
|
|
else if ((eptr->pic_data != NULL)&&
|
|
(eptr->pic_data->delayed)&&
|
|
(eptr->anchorHRef != NULL)&&
|
|
(!IsDelayedHRef(hw, eptr->anchorHRef))&&
|
|
(!IsIsMapForm(hw, eptr->anchorHRef))&&
|
|
(((event->xbutton.y + hw->html.scroll_y) -
|
|
(eptr->y + eptr->y_offset)) >
|
|
AnchoredHeight(hw)))
|
|
{
|
|
eptr->pic_data = (*(resolveImageProc)
|
|
(hw->html.resolveDelayedImage))(hw, eptr->edata);
|
|
|
|
if (eptr->pic_data == NULL)
|
|
{
|
|
eptr->pic_data = NoImageData(hw);
|
|
eptr->pic_data->delayed = 0;
|
|
eptr->pic_data->internal = 0;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Mark images we have sucessfully
|
|
* loaded at least once
|
|
*/
|
|
if (eptr->pic_data->image_data != NULL)
|
|
{
|
|
eptr->pic_data->fetched = 1;
|
|
}
|
|
/*
|
|
* See if this is a special
|
|
* internal image
|
|
*/
|
|
if ((eptr->edata != NULL)&&
|
|
(strncmp(eptr->edata,
|
|
INTERNAL_IMAGE,
|
|
strlen(INTERNAL_IMAGE)) == 0))
|
|
{
|
|
eptr->pic_data->internal = 1;
|
|
}
|
|
else
|
|
{
|
|
eptr->pic_data->internal = 0;
|
|
}
|
|
}
|
|
eptr->pic_data->delayed = 0;
|
|
|
|
ReformatWindow(hw);
|
|
ScrollWidgets(hw);
|
|
ViewClearAndRefresh(hw);
|
|
}
|
|
else if ((eptr->pic_data != NULL)&&
|
|
(eptr->pic_data->ismap)&&
|
|
(eptr->anchorHRef != NULL)&&
|
|
(IsIsMapForm(hw, eptr->anchorHRef)))
|
|
{
|
|
int form_x, form_y;
|
|
|
|
form_x = event->xbutton.x + hw->html.scroll_x -
|
|
eptr->x;
|
|
form_y = event->xbutton.y + hw->html.scroll_y -
|
|
eptr->y;
|
|
ImageSubmitForm(eptr->pic_data->fptr, event,
|
|
eptr->pic_data->text,
|
|
form_x, form_y);
|
|
}
|
|
else
|
|
{
|
|
/* The following is a hack to send the
|
|
* selection location along with the HRef
|
|
* for images. This allows you to
|
|
* point at a location on a map and have
|
|
* the server send you the related document.
|
|
* Tony Sanders, April 1993 <sanders@bsdi.com>
|
|
*/
|
|
int alloced = 0;
|
|
char *buf = eptr->anchorHRef;
|
|
if (eptr->type == E_IMAGE && eptr->pic_data
|
|
&& eptr->pic_data->ismap) {
|
|
buf = (char *)
|
|
malloc(strlen(eptr->anchorHRef) + 256);
|
|
alloced = 1;
|
|
sprintf(buf, "%s?%d,%d",
|
|
eptr->anchorHRef,
|
|
event->xbutton.x + hw->html.scroll_x - eptr->x,
|
|
event->xbutton.y + hw->html.scroll_y - eptr->y);
|
|
}
|
|
/*
|
|
* XXX: should call a media dependent
|
|
* function that decides how to munge the
|
|
* HRef. For example mpeg data will want
|
|
* to know on what frame the event occured.
|
|
*
|
|
* cddata.href = *(eptr->eventf)(eptr, event);
|
|
*/
|
|
cbdata.event = event;
|
|
cbdata.element_id = eptr->ele_id;
|
|
cbdata.href = buf;
|
|
/* cbdata.href = eptr->anchorHRef; */
|
|
cbdata.text = tptr;
|
|
XtCallCallbackList ((Widget)hw,
|
|
hw->html.anchor_callback,
|
|
(XtPointer)&cbdata);
|
|
if (alloced) free(buf);
|
|
if (tptr != NULL) free(tptr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
#include <X11/Xaw/AsciiText.h>
|
|
/*
|
|
* Process key input passwd widgets
|
|
*/
|
|
static void
|
|
#ifdef _NO_PROTO
|
|
_HTMLpwdInput( w, event, params, num_params)
|
|
Widget w ;
|
|
XEvent *event ;
|
|
String *params; /* unused */
|
|
Cardinal *num_params; /* unused */
|
|
#else
|
|
_HTMLpwdInput(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params, /* unused */
|
|
Cardinal *num_params) /* unused */
|
|
#endif
|
|
{
|
|
char buffer[50];
|
|
KeySym ks;
|
|
char *keySymString;
|
|
char *star = "*";
|
|
int length, passwdLength, i, insertPos, maxLength;
|
|
Boolean stringInPlace;
|
|
|
|
if (event->type == KeyPress)
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)XtParent(XtParent(w));
|
|
WidgetInfo *wptr;
|
|
|
|
if (XtClass((Widget)hw) != htmlWidgetClass)
|
|
return; /* it was not for us */
|
|
|
|
/*
|
|
* find the structure for this widget
|
|
*/
|
|
wptr = hw->html.widget_list;
|
|
while (wptr != NULL)
|
|
{
|
|
if (wptr->w == w)
|
|
break;
|
|
wptr = wptr->next;
|
|
}
|
|
if (wptr == NULL)
|
|
return;
|
|
|
|
passwdLength = wptr->password ? strlen(wptr->password) : 0;
|
|
|
|
length = XLookupString((XKeyEvent *)event,
|
|
buffer, 50, &ks, NULL);
|
|
keySymString = XKeysymToString(ks);
|
|
XtVaGetValues(w,
|
|
XtNinsertPosition,&insertPos,
|
|
XtNuseStringInPlace, &stringInPlace,
|
|
XtNlength, &maxLength,
|
|
NULL);
|
|
|
|
if (maxLength<1) maxLength = 1000000;
|
|
|
|
if (!strcmp("Left",keySymString))
|
|
{
|
|
if (insertPos > 0)
|
|
XtVaSetValues(w,XtNinsertPosition,--insertPos,NULL);
|
|
return;
|
|
}
|
|
else if (!strcmp("Right",keySymString))
|
|
{
|
|
if (insertPos < passwdLength)
|
|
XtVaSetValues(w,XtNinsertPosition,++insertPos,NULL);
|
|
return;
|
|
}
|
|
|
|
if ((!strcmp("BackSpace",keySymString))
|
|
|| (!strcmp("Backspace",keySymString))
|
|
|| (!strcmp("Delete",keySymString)) )
|
|
{
|
|
insertPos --;
|
|
|
|
if (passwdLength>0)
|
|
{
|
|
char *pwd = &(wptr->password[insertPos]);
|
|
|
|
for (i = passwdLength - insertPos; i>0; i--,pwd++)
|
|
*pwd = *(pwd+1);
|
|
|
|
/* fprintf(stderr,"modified passwd <%s>\n", wptr->password);*/
|
|
XtCallActionProc(w,
|
|
insertPos>-1 ? "delete-previous-character" :
|
|
"delete-next-character",
|
|
event, NULL,0);
|
|
}
|
|
/* else nothing to erase */
|
|
return;
|
|
}
|
|
|
|
if (length == 1)
|
|
{
|
|
buffer[1] = '\0';
|
|
|
|
if (passwdLength>0)
|
|
{
|
|
|
|
if (passwdLength < maxLength)
|
|
{
|
|
char *pwd = wptr->password =
|
|
(char *)realloc(wptr->password,
|
|
sizeof(char)*(passwdLength+2));
|
|
for (i=passwdLength+1; i>insertPos; i--)
|
|
pwd[i] = pwd[i-1];
|
|
|
|
pwd[insertPos] = buffer[0];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (wptr->password == NULL)
|
|
wptr->password = (char *)malloc(sizeof(char)*2);
|
|
|
|
wptr->password[0] = buffer[0];
|
|
wptr->password[1] = '\0';
|
|
}
|
|
|
|
if (stringInPlace && passwdLength<maxLength)
|
|
{
|
|
char *txt;
|
|
/* insert string dumps core when string in place is true */
|
|
|
|
XtVaGetValues(w,XtNstring,&txt,NULL);
|
|
txt[passwdLength] = star[0];
|
|
txt[passwdLength+1] = '\0';
|
|
|
|
/* the combined set values command does not work */
|
|
XtVaSetValues(w, XtNstring,txt, NULL);
|
|
XtVaSetValues(w, XtNinsertPosition,insertPos+1, NULL);
|
|
}
|
|
else
|
|
XtCallActionProc(w, "insert-string", event, &star, 1);
|
|
/* fprintf(stderr,"modified passwd <%s>\n", wptr->password); */
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* SetValues is called when XtSetValues is used to change resources in this
|
|
* widget.
|
|
*/
|
|
static Boolean
|
|
#ifdef _NO_PROTO
|
|
SetValues (current, request, new)
|
|
HTMLWidget current ;
|
|
HTMLWidget request ;
|
|
HTMLWidget new ;
|
|
#else
|
|
SetValues(
|
|
HTMLWidget current,
|
|
HTMLWidget request,
|
|
HTMLWidget new)
|
|
#endif
|
|
{
|
|
int reformatted;
|
|
|
|
/*
|
|
* Make sure the underline numbers are within bounds.
|
|
*/
|
|
if (request->html.num_anchor_underlines < 0)
|
|
{
|
|
new->html.num_anchor_underlines = 0;
|
|
}
|
|
if (request->html.num_anchor_underlines > MAX_UNDERLINES)
|
|
{
|
|
new->html.num_anchor_underlines = MAX_UNDERLINES;
|
|
}
|
|
if (request->html.num_visitedAnchor_underlines < 0)
|
|
{
|
|
new->html.num_visitedAnchor_underlines = 0;
|
|
}
|
|
if (request->html.num_visitedAnchor_underlines > MAX_UNDERLINES)
|
|
{
|
|
new->html.num_visitedAnchor_underlines = MAX_UNDERLINES;
|
|
}
|
|
|
|
reformatted = 0;
|
|
if ((request->html.raw_text != current->html.raw_text)||
|
|
(request->html.header_text != current->html.header_text)||
|
|
(request->html.footer_text != current->html.footer_text))
|
|
{
|
|
/*
|
|
* Free up the old visited href list.
|
|
*/
|
|
FreeHRefs(current->html.my_visited_hrefs);
|
|
new->html.my_visited_hrefs = NULL;
|
|
|
|
/*
|
|
* Free up the old visited delayed images list.
|
|
*/
|
|
FreeDelayedImages(current->html.my_delayed_images);
|
|
new->html.my_delayed_images = NULL;
|
|
|
|
/*
|
|
* Free any old colors and pixmaps
|
|
*/
|
|
FreeColors(XtDisplay(current), DefaultColormapOfScreen(XtScreen(current)));
|
|
FreeImages(current);
|
|
|
|
/*
|
|
* Hide any old widgets
|
|
*/
|
|
HideWidgets(current);
|
|
new->html.widget_list = NULL;
|
|
new->html.form_list = NULL;
|
|
|
|
/*
|
|
* Parse the raw text with the HTML parser
|
|
*/
|
|
new->html.html_objects = HTMLParse(current->html.html_objects,
|
|
request->html.raw_text);
|
|
CallLinkCallbacks(new);
|
|
new->html.html_header_objects =
|
|
HTMLParse(current->html.html_header_objects,
|
|
request->html.header_text);
|
|
new->html.html_footer_objects =
|
|
HTMLParse(current->html.html_footer_objects,
|
|
request->html.footer_text);
|
|
|
|
/*
|
|
* Redisplay for the changed data.
|
|
*/
|
|
{
|
|
new->html.scroll_x = 0;
|
|
new->html.scroll_y = 0;
|
|
new->html.max_pre_width = DocumentWidth(new,
|
|
new->html.html_objects);
|
|
ReformatWindow(new);
|
|
ViewClearAndRefresh(new);
|
|
reformatted = 1;
|
|
}
|
|
|
|
/*
|
|
* Clear any previous selection
|
|
*/
|
|
new->html.select_start = NULL;
|
|
new->html.select_end = NULL;
|
|
new->html.sel_start_pos = 0;
|
|
new->html.sel_end_pos = 0;
|
|
new->html.new_start = NULL;
|
|
new->html.new_end = NULL;
|
|
new->html.new_start_pos = 0;
|
|
new->html.new_end_pos = 0;
|
|
new->html.active_anchor = NULL;
|
|
}
|
|
else if ((request->html.font != current->html.font)||
|
|
(request->html.italic_font != current->html.italic_font)||
|
|
(request->html.bold_font != current->html.bold_font)||
|
|
(request->html.fixed_font != current->html.fixed_font)||
|
|
(request->html.fixedbold_font != current->html.fixedbold_font)||
|
|
(request->html.fixeditalic_font != current->html.fixeditalic_font)||
|
|
(request->html.header1_font != current->html.header1_font)||
|
|
(request->html.header2_font != current->html.header2_font)||
|
|
(request->html.header3_font != current->html.header3_font)||
|
|
(request->html.header4_font != current->html.header4_font)||
|
|
(request->html.header5_font != current->html.header5_font)||
|
|
(request->html.header6_font != current->html.header6_font)||
|
|
(request->html.address_font != current->html.address_font)||
|
|
(request->html.plain_font != current->html.plain_font)||
|
|
(request->html.plainbold_font != current->html.plainbold_font)||
|
|
(request->html.plainitalic_font != current->html.plainitalic_font)||
|
|
(request->html.listing_font != current->html.listing_font)||
|
|
(request->html.activeAnchor_fg != current->html.activeAnchor_fg)||
|
|
(request->html.activeAnchor_bg != current->html.activeAnchor_bg)||
|
|
(request->html.anchor_fg != current->html.anchor_fg)||
|
|
(request->html.visitedAnchor_fg != current->html.visitedAnchor_fg)||
|
|
(request->html.dashed_anchor_lines != current->html.dashed_anchor_lines)||
|
|
(request->html.dashed_visitedAnchor_lines != current->html.dashed_visitedAnchor_lines)||
|
|
(request->html.num_anchor_underlines != current->html.num_anchor_underlines)||
|
|
(request->html.num_visitedAnchor_underlines != current->html.num_visitedAnchor_underlines))
|
|
{
|
|
if ((request->html.plain_font != current->html.plain_font)||
|
|
(request->html.listing_font != current->html.listing_font))
|
|
{
|
|
new->html.max_pre_width = DocumentWidth(new,
|
|
new->html.html_objects);
|
|
}
|
|
|
|
ReformatWindow(new);
|
|
ScrollWidgets(new);
|
|
ViewClearAndRefresh(new);
|
|
reformatted = 1;
|
|
}
|
|
|
|
/*
|
|
* image borders have been changed
|
|
*/
|
|
if (request->html.border_images != current->html.border_images)
|
|
{
|
|
ReformatWindow(new);
|
|
ScrollWidgets(new);
|
|
ViewClearAndRefresh(new);
|
|
reformatted = 1;
|
|
}
|
|
|
|
/*
|
|
* vertical space has been changed
|
|
*/
|
|
if(request->html.percent_vert_space != current->html.percent_vert_space)
|
|
{
|
|
ReformatWindow(new);
|
|
ScrollWidgets(new);
|
|
ViewClearAndRefresh(new);
|
|
reformatted = 1;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
static Boolean
|
|
ConvertSelection(w, selection, target, type, value, length, format)
|
|
Widget w;
|
|
Atom *selection, *target, *type;
|
|
caddr_t *value;
|
|
unsigned long *length;
|
|
int *format;
|
|
{
|
|
Display *d = XtDisplay(w);
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
char *text;
|
|
|
|
if (hw->html.select_start == NULL)
|
|
{
|
|
return False;
|
|
}
|
|
|
|
if (*target == XA_TARGETS(d))
|
|
{
|
|
Atom *targetP;
|
|
Atom *std_targets;
|
|
unsigned long std_length;
|
|
XmuConvertStandardSelection( w, hw->html.selection_time,
|
|
selection, target, type, (caddr_t*)&std_targets,
|
|
&std_length, format);
|
|
|
|
*length = std_length + 5;
|
|
*value = (caddr_t)XtMalloc(sizeof(Atom)*(*length));
|
|
targetP = *(Atom**)value;
|
|
*targetP++ = XA_STRING;
|
|
*targetP++ = XA_TEXT(d);
|
|
*targetP++ = XA_COMPOUND_TEXT(d);
|
|
*targetP++ = XA_LENGTH(d);
|
|
*targetP++ = XA_LIST_LENGTH(d);
|
|
|
|
bcopy((char*)std_targets, (char*)targetP,
|
|
sizeof(Atom)*std_length);
|
|
XtFree((char*)std_targets);
|
|
*type = XA_ATOM;
|
|
*format = 32;
|
|
return True;
|
|
}
|
|
|
|
if (*target == XA_STRING || *target == XA_TEXT(d) ||
|
|
*target == XA_COMPOUND_TEXT(d))
|
|
{
|
|
if (*target == XA_COMPOUND_TEXT(d))
|
|
{
|
|
*type = *target;
|
|
}
|
|
else
|
|
{
|
|
*type = XA_STRING;
|
|
}
|
|
if (hw->html.fancy_selections == True)
|
|
{
|
|
text = ParseTextToPrettyString(hw,
|
|
hw->html.formatted_elements,
|
|
hw->html.select_start, hw->html.select_end,
|
|
hw->html.sel_start_pos, hw->html.sel_end_pos,
|
|
hw->html.font->max_bounds.width,
|
|
hw->html.margin_width);
|
|
}
|
|
else
|
|
{
|
|
text = ParseTextToString(hw->html.formatted_elements,
|
|
hw->html.select_start, hw->html.select_end,
|
|
hw->html.sel_start_pos, hw->html.sel_end_pos,
|
|
hw->html.font->max_bounds.width,
|
|
hw->html.margin_width);
|
|
}
|
|
*value = text;
|
|
*length = strlen(*value);
|
|
*format = 8;
|
|
return True;
|
|
}
|
|
|
|
if (*target == XA_LIST_LENGTH(d))
|
|
{
|
|
*value = XtMalloc(4);
|
|
if (sizeof(long) == 4)
|
|
{
|
|
*(long*)*value = 1;
|
|
}
|
|
else
|
|
{
|
|
long temp = 1;
|
|
bcopy( ((char*)&temp)+sizeof(long)-4, (char*)*value, 4);
|
|
}
|
|
*type = XA_INTEGER;
|
|
*length = 1;
|
|
*format = 32;
|
|
return True;
|
|
}
|
|
|
|
if (*target == XA_LENGTH(d))
|
|
{
|
|
if (hw->html.fancy_selections == True)
|
|
{
|
|
text = ParseTextToPrettyString(hw,
|
|
hw->html.formatted_elements,
|
|
hw->html.select_start, hw->html.select_end,
|
|
hw->html.sel_start_pos, hw->html.sel_end_pos,
|
|
hw->html.font->max_bounds.width,
|
|
hw->html.margin_width);
|
|
}
|
|
else
|
|
{
|
|
text = ParseTextToString(hw->html.formatted_elements,
|
|
hw->html.select_start, hw->html.select_end,
|
|
hw->html.sel_start_pos, hw->html.sel_end_pos,
|
|
hw->html.font->max_bounds.width,
|
|
hw->html.margin_width);
|
|
}
|
|
*value = XtMalloc(4);
|
|
if (sizeof(long) == 4)
|
|
{
|
|
*(long*)*value = strlen(text);
|
|
}
|
|
else
|
|
{
|
|
long temp = strlen(text);
|
|
bcopy( ((char*)&temp)+sizeof(long)-4, (char*)*value, 4);
|
|
}
|
|
free(text);
|
|
*type = XA_INTEGER;
|
|
*length = 1;
|
|
*format = 32;
|
|
return True;
|
|
}
|
|
|
|
if (XmuConvertStandardSelection(w, hw->html.selection_time, selection,
|
|
target, type, value, length, format))
|
|
{
|
|
return True;
|
|
}
|
|
|
|
return False;
|
|
}
|
|
|
|
|
|
static void
|
|
LoseSelection(w, selection)
|
|
Widget w;
|
|
Atom *selection;
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
|
|
ClearSelection(hw);
|
|
}
|
|
|
|
|
|
static void
|
|
SelectionDone(w, selection, target)
|
|
Widget w;
|
|
Atom *selection, *target;
|
|
{
|
|
/* empty proc so Intrinsics know we want to keep storage */
|
|
}
|
|
|
|
|
|
/*
|
|
*************************************************************************
|
|
******************************* PUBLIC FUNCTIONS ************************
|
|
*************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
* Convenience function to return the text of the HTML document as a plain
|
|
* ascii text string.
|
|
* This function allocates memory for the returned string, that it is up
|
|
* to the user to free.
|
|
* Extra option flags "pretty" text to be returned.
|
|
* when pretty is two or larger, Postscript is returned. The font used is
|
|
* encoded in the pretty parameter:
|
|
* pretty = 2: Times
|
|
* pretty = 3: Helvetica
|
|
* pretty = 4: New century schoolbook
|
|
* pretty = 5: Lucida Bright
|
|
*/
|
|
char *
|
|
#ifdef _NO_PROTO
|
|
HTMLGetText (w, pretty)
|
|
Widget w;
|
|
int pretty;
|
|
#else
|
|
HTMLGetText(Widget w, int pretty)
|
|
#endif
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
char *text;
|
|
char *tptr, *buf;
|
|
struct ele_rec *start;
|
|
struct ele_rec *end;
|
|
|
|
text = NULL;
|
|
start = hw->html.formatted_elements;
|
|
end = start;
|
|
while (end != NULL)
|
|
{
|
|
end = end->next;
|
|
}
|
|
|
|
if (pretty >= 2)
|
|
{
|
|
tptr = ParseTextToPSString(hw, start, start, end,
|
|
0, 0,
|
|
hw->html.font->max_bounds.width,
|
|
hw->html.margin_width , pretty-2);
|
|
}
|
|
else if (pretty)
|
|
{
|
|
tptr = ParseTextToPrettyString(hw, start, start, end,
|
|
0, 0,
|
|
hw->html.font->max_bounds.width,
|
|
hw->html.margin_width);
|
|
}
|
|
else
|
|
{
|
|
tptr = ParseTextToString(start, start, end,
|
|
0, 0,
|
|
hw->html.font->max_bounds.width,
|
|
hw->html.margin_width);
|
|
}
|
|
if (tptr != NULL)
|
|
{
|
|
if (text == NULL)
|
|
{
|
|
text = tptr;
|
|
}
|
|
else
|
|
{
|
|
buf = (char *)malloc(strlen(text) +
|
|
strlen(tptr) + 1);
|
|
strcpy(buf, text);
|
|
strcat(buf, tptr);
|
|
free(text);
|
|
free(tptr);
|
|
text = buf;
|
|
}
|
|
}
|
|
return(text);
|
|
}
|
|
|
|
|
|
/*
|
|
* Convenience function to return the element id of the element
|
|
* nearest to the x,y coordinates passed in.
|
|
* If there is no element there, return the first element in the
|
|
* line we are on. If there we are on no line, either return the
|
|
* beginning, or the end of the document.
|
|
*/
|
|
int
|
|
#ifdef _NO_PROTO
|
|
HTMLPositionToId(w, x, y)
|
|
Widget w;
|
|
int x, y;
|
|
#else
|
|
HTMLPositionToId(Widget w, int x, int y)
|
|
#endif
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
int i;
|
|
int epos;
|
|
struct ele_rec *eptr;
|
|
|
|
eptr = LocateElement(hw, x, y, &epos);
|
|
if (eptr == NULL)
|
|
{
|
|
x = x + hw->html.scroll_x;
|
|
y = y + hw->html.scroll_y;
|
|
eptr = hw->html.line_array[0];
|
|
for (i=0; i<hw->html.line_count; i++)
|
|
{
|
|
if (hw->html.line_array[i] == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
else if (hw->html.line_array[i]->y <= y)
|
|
{
|
|
eptr = hw->html.line_array[i];
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 0 means the very top of the document. We put you there for
|
|
* unfound elements.
|
|
* We also special case for when the scrollbar is at the
|
|
* absolute top.
|
|
*/
|
|
if ((eptr == NULL)||(hw->html.scroll_y == 0))
|
|
{
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
return(eptr->ele_id);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Convenience function to return the position of the element
|
|
* based on the element id passed in.
|
|
* Function returns 1 on success and fills in x,y pixel values.
|
|
* If there is no such element, x=0, y=0 and -1 is returned.
|
|
*/
|
|
int
|
|
#ifdef _NO_PROTO
|
|
HTMLIdToPosition(w, element_id, x, y)
|
|
Widget w;
|
|
int element_id;
|
|
int *x, *y;
|
|
#else
|
|
HTMLIdToPosition(Widget w, int element_id, int *x, int *y)
|
|
#endif
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
struct ele_rec *start;
|
|
struct ele_rec *eptr;
|
|
|
|
eptr = NULL;
|
|
start = hw->html.formatted_elements;
|
|
while (start != NULL)
|
|
{
|
|
if (start->ele_id == element_id)
|
|
{
|
|
eptr = start;
|
|
break;
|
|
}
|
|
start = start->next;
|
|
}
|
|
|
|
if (eptr == NULL)
|
|
{
|
|
*x = 0;
|
|
*y = 0;
|
|
return(-1);
|
|
}
|
|
else
|
|
{
|
|
*x = eptr->x;
|
|
*y = eptr->y;
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Convenience function to position the element
|
|
* based on the element id passed at the top of the viewing area.
|
|
* A passed in id of 0 means goto the top.
|
|
*/
|
|
void
|
|
#ifdef _NO_PROTO
|
|
HTMLGotoId(w, element_id)
|
|
Widget w;
|
|
int element_id;
|
|
#else
|
|
HTMLGotoId(Widget w, int element_id)
|
|
#endif
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
struct ele_rec *start;
|
|
struct ele_rec *eptr;
|
|
int newy;
|
|
|
|
/*
|
|
* If we have no scrollbar, just return.
|
|
*/
|
|
if (hw->html.use_vbar == False)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Find the element corrsponding to the id passed in.
|
|
*/
|
|
eptr = NULL;
|
|
start = hw->html.formatted_elements;
|
|
while (start != NULL)
|
|
{
|
|
if (start->ele_id == element_id)
|
|
{
|
|
eptr = start;
|
|
break;
|
|
}
|
|
start = start->next;
|
|
}
|
|
|
|
/*
|
|
* No such element, do nothing.
|
|
*/
|
|
if ((element_id != 0)&&(eptr == NULL))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (element_id == 0)
|
|
{
|
|
newy = 0;
|
|
}
|
|
else
|
|
{
|
|
newy = eptr->y - (int)hw->html.view_height / 2;
|
|
}
|
|
if (newy < 0)
|
|
{
|
|
newy = 0;
|
|
}
|
|
if (newy > (hw->html.doc_height - (int)hw->html.view_height / 2))
|
|
{
|
|
newy = hw->html.doc_height - (int)hw->html.view_height / 2;
|
|
}
|
|
if (newy < 0)
|
|
{
|
|
newy = 0;
|
|
}
|
|
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);
|
|
}
|
|
|
|
|
|
/*
|
|
* 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);
|
|
}
|
|
}
|
|
mptr = mptr->next;
|
|
}
|
|
|
|
if (cnt == 0)
|
|
{
|
|
*num_srcs = 0;
|
|
return(NULL);
|
|
}
|
|
else
|
|
{
|
|
*num_srcs = cnt;
|
|
harray = (char **)malloc(sizeof(char *) * cnt);
|
|
mptr = hw->html.html_objects;
|
|
cnt = 0;
|
|
while (mptr != NULL)
|
|
{
|
|
if (mptr->type == M_IMAGE)
|
|
{
|
|
tptr = ParseMarkTag(mptr->start,MT_IMAGE,"SRC");
|
|
if ((tptr != NULL)&&(*tptr != '\0'))
|
|
{
|
|
harray[cnt] = tptr;
|
|
cnt++;
|
|
}
|
|
}
|
|
mptr = mptr->next;
|
|
}
|
|
return(harray);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Convenience function to return the link information
|
|
* for all the <LINK> tags in the document.
|
|
* Function returns an array of LinkInfo structures and fills
|
|
* num_links passed.
|
|
* If there are no LINKs NULL returned.
|
|
*/
|
|
LinkInfo *
|
|
#ifdef _NO_PROTO
|
|
HTMLGetLinks(w, num_links)
|
|
Widget w;
|
|
int *num_links;
|
|
#else
|
|
HTMLGetLinks(Widget w, int *num_links)
|
|
#endif
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
struct mark_up *mptr;
|
|
int cnt;
|
|
char *tptr;
|
|
LinkInfo *larray;
|
|
|
|
cnt = 0;
|
|
mptr = hw->html.html_objects;
|
|
while (mptr != NULL)
|
|
{
|
|
if (mptr->type == M_BASE)
|
|
{
|
|
cnt++;
|
|
}
|
|
mptr = mptr->next;
|
|
}
|
|
|
|
if (cnt == 0)
|
|
{
|
|
*num_links = 0;
|
|
return(NULL);
|
|
}
|
|
else
|
|
{
|
|
*num_links = cnt;
|
|
larray = (LinkInfo *)malloc(sizeof(LinkInfo) * cnt);
|
|
mptr = hw->html.html_objects;
|
|
cnt = 0;
|
|
while (mptr != NULL)
|
|
{
|
|
if (mptr->type == M_BASE)
|
|
{
|
|
tptr = ParseMarkTag(mptr->start,
|
|
MT_BASE, "HREF");
|
|
larray[cnt].href = tptr;
|
|
tptr = ParseMarkTag(mptr->start,
|
|
MT_BASE, "ROLE");
|
|
larray[cnt].role = tptr;
|
|
cnt++;
|
|
}
|
|
mptr = mptr->next;
|
|
}
|
|
return(larray);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
#ifdef _NO_PROTO
|
|
HTMLGetWidgetInfo(w)
|
|
Widget w;
|
|
#else
|
|
HTMLGetWidgetInfo(Widget w)
|
|
#endif
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
|
|
return((void *)hw->html.widget_list);
|
|
}
|
|
|
|
|
|
void
|
|
#ifdef _NO_PROTO
|
|
HTMLFreeImageInfo(w)
|
|
Widget w;
|
|
#else
|
|
HTMLFreeImageInfo(Widget w)
|
|
#endif
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
|
|
FreeColors(XtDisplay(w), DefaultColormapOfScreen(XtScreen(w)));
|
|
FreeImages(hw);
|
|
}
|
|
|
|
|
|
void
|
|
#ifdef _NO_PROTO
|
|
HTMLFreeWidgetInfo(ptr)
|
|
void *ptr;
|
|
#else
|
|
HTMLFreeWidgetInfo(void *ptr)
|
|
#endif
|
|
{
|
|
WidgetInfo *wptr = (WidgetInfo *)ptr;
|
|
WidgetInfo *tptr;
|
|
|
|
while (wptr != NULL)
|
|
{
|
|
tptr = wptr;
|
|
wptr = wptr->next;
|
|
if (tptr->w != NULL)
|
|
{
|
|
/*
|
|
* This is REALLY DUMB, but X generates an expose event
|
|
* for the destruction of the Widgte, even if it isn't
|
|
* mapped at the time it is destroyed.
|
|
* So I move the invisible widget to -1000,-1000
|
|
* before destroying it, to avoid a visible flash.
|
|
*/
|
|
XtMoveWidget(tptr->w, -1000, -1000);
|
|
XtDestroyWidget(tptr->w);
|
|
}
|
|
if (tptr->name != NULL)
|
|
{
|
|
free(tptr->name);
|
|
}
|
|
if ((tptr->value != NULL)&&(tptr->type != W_OPTIONMENU))
|
|
{
|
|
free(tptr->value);
|
|
}
|
|
free((char *)tptr);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Convenience function to redraw all active anchors in the
|
|
* document.
|
|
* Can also pass a new predicate function to check visited
|
|
* anchors. If NULL passed for function, uses default predicate
|
|
* function.
|
|
*/
|
|
void
|
|
#ifdef _NO_PROTO
|
|
HTMLRetestAnchors(w, testFunc)
|
|
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)
|
|
{
|
|
fprintf(stderr, "cannot allocate atom list\n");
|
|
return;
|
|
}
|
|
XmuInternStrings(XtDisplay((Widget)hw), params, 2, atoms);
|
|
hw->html.selection_time = CurrentTime;
|
|
for (i=0; i< 2; i++)
|
|
{
|
|
switch (atoms[i])
|
|
{
|
|
case XA_CUT_BUFFER0: buffer = 0; break;
|
|
case XA_CUT_BUFFER1: buffer = 1; break;
|
|
case XA_CUT_BUFFER2: buffer = 2; break;
|
|
case XA_CUT_BUFFER3: buffer = 3; break;
|
|
case XA_CUT_BUFFER4: buffer = 4; break;
|
|
case XA_CUT_BUFFER5: buffer = 5; break;
|
|
case XA_CUT_BUFFER6: buffer = 6; break;
|
|
case XA_CUT_BUFFER7: buffer = 7; break;
|
|
default: buffer = -1; break;
|
|
}
|
|
if (buffer >= 0)
|
|
{
|
|
if (hw->html.fancy_selections == True)
|
|
{
|
|
text = ParseTextToPrettyString(hw,
|
|
hw->html.formatted_elements,
|
|
hw->html.select_start,
|
|
hw->html.select_end,
|
|
hw->html.sel_start_pos,
|
|
hw->html.sel_end_pos,
|
|
hw->html.font->max_bounds.width,
|
|
hw->html.margin_width);
|
|
}
|
|
else
|
|
{
|
|
text = ParseTextToString(
|
|
hw->html.formatted_elements,
|
|
hw->html.select_start,
|
|
hw->html.select_end,
|
|
hw->html.sel_start_pos,
|
|
hw->html.sel_end_pos,
|
|
hw->html.font->max_bounds.width,
|
|
hw->html.margin_width);
|
|
}
|
|
XStoreBuffer(XtDisplay((Widget)hw),
|
|
text, strlen(text), buffer);
|
|
free(text);
|
|
}
|
|
else
|
|
{
|
|
XtOwnSelection((Widget)hw, atoms[i], CurrentTime,
|
|
(XtConvertSelectionProc )ConvertSelection,
|
|
(XtLoseSelectionProc )LoseSelection,
|
|
(XtSelectionDoneProc )SelectionDone);
|
|
}
|
|
}
|
|
free((char *)atoms);
|
|
}
|
|
|
|
|
|
/*
|
|
* Convenience function to return the text of the HTML document as a single
|
|
* white space separated string, with pointers to the various start and
|
|
* end points of selections.
|
|
* This function allocates memory for the returned string, that it is up
|
|
* to the user to free.
|
|
*/
|
|
char *
|
|
#ifdef _NO_PROTO
|
|
HTMLGetTextAndSelection (w, startp, endp, insertp)
|
|
Widget w;
|
|
char **startp;
|
|
char **endp;
|
|
char **insertp;
|
|
#else
|
|
HTMLGetTextAndSelection(Widget w, char **startp, char **endp, char **insertp)
|
|
#endif
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
int length;
|
|
char *text;
|
|
char *tptr;
|
|
struct ele_rec *eptr;
|
|
struct ele_rec *sel_start;
|
|
struct ele_rec *sel_end;
|
|
struct ele_rec *insert_start;
|
|
int start_pos, end_pos, insert_pos;
|
|
|
|
if (SwapElements(hw->html.select_start, hw->html.select_end,
|
|
hw->html.sel_start_pos, hw->html.sel_end_pos))
|
|
{
|
|
sel_end = hw->html.select_start;
|
|
end_pos = hw->html.sel_start_pos;
|
|
sel_start = hw->html.select_end;
|
|
start_pos = hw->html.sel_end_pos;
|
|
}
|
|
else
|
|
{
|
|
sel_start = hw->html.select_start;
|
|
start_pos = hw->html.sel_start_pos;
|
|
sel_end = hw->html.select_end;
|
|
end_pos = hw->html.sel_end_pos;
|
|
}
|
|
|
|
insert_start = hw->html.new_start;
|
|
insert_pos = hw->html.new_start_pos;
|
|
*startp = NULL;
|
|
*endp = NULL;
|
|
*insertp = NULL;
|
|
|
|
length = 0;
|
|
|
|
eptr = hw->html.formatted_elements;
|
|
while (eptr != NULL)
|
|
{
|
|
/*
|
|
* Skip the special internal text
|
|
*/
|
|
if (eptr->internal == True)
|
|
{
|
|
eptr = eptr->next;
|
|
continue;
|
|
}
|
|
|
|
if (eptr->type == E_TEXT)
|
|
{
|
|
length = length + eptr->edata_len - 1;
|
|
}
|
|
else if (eptr->type == E_LINEFEED)
|
|
{
|
|
length = length + 1;
|
|
}
|
|
eptr = eptr->next;
|
|
}
|
|
|
|
text = (char *)malloc(length + 1);
|
|
if (text == NULL)
|
|
{
|
|
fprintf(stderr, "No space for return string\n");
|
|
return(NULL);
|
|
}
|
|
strcpy(text, "");
|
|
|
|
tptr = text;
|
|
|
|
eptr = hw->html.formatted_elements;
|
|
while (eptr != NULL)
|
|
{
|
|
/*
|
|
* Skip the special internal text
|
|
*/
|
|
if (eptr->internal == True)
|
|
{
|
|
eptr = eptr->next;
|
|
continue;
|
|
}
|
|
|
|
if (eptr->type == E_TEXT)
|
|
{
|
|
if (eptr == sel_start)
|
|
{
|
|
*startp = (char *)(tptr + start_pos);
|
|
}
|
|
|
|
if (eptr == sel_end)
|
|
{
|
|
*endp = (char *)(tptr + end_pos);
|
|
}
|
|
|
|
if (eptr == insert_start)
|
|
{
|
|
*insertp = (char *)(tptr + insert_pos);
|
|
}
|
|
|
|
strcat(text, (char *)eptr->edata);
|
|
tptr = tptr + eptr->edata_len - 1;
|
|
}
|
|
else if (eptr->type == E_LINEFEED)
|
|
{
|
|
if (eptr == sel_start)
|
|
{
|
|
*startp = tptr;
|
|
}
|
|
|
|
if (eptr == sel_end)
|
|
{
|
|
*endp = tptr;
|
|
}
|
|
|
|
if (eptr == insert_start)
|
|
{
|
|
*insertp = tptr;
|
|
}
|
|
|
|
strcat(text, " ");
|
|
tptr = tptr + 1;
|
|
}
|
|
eptr = eptr->next;
|
|
}
|
|
return(text);
|
|
}
|
|
|
|
|
|
/*
|
|
* Convenience function to set the raw text into the widget.
|
|
* Forces a reparse and a reformat.
|
|
* If any pointer is passed in as NULL that text is unchanged,
|
|
* if a pointer points to an empty string, that text is set to NULL;
|
|
* Also pass an element ID to set the view area to that section of the new
|
|
* text. Finally pass an anchor NAME to set position of the new text
|
|
* to that anchor.
|
|
*/
|
|
void
|
|
#ifdef _NO_PROTO
|
|
HTMLSetText (w, text, header_text, footer_text, element_id, target_anchor, ptr)
|
|
Widget w;
|
|
char *text;
|
|
char *header_text;
|
|
char *footer_text;
|
|
int element_id;
|
|
char *target_anchor;
|
|
void *ptr;
|
|
#else
|
|
HTMLSetText(Widget w, char *text, char *header_text, char *footer_text, int element_id, char *target_anchor, void *ptr)
|
|
#endif
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
WidgetInfo *wptr = (WidgetInfo *)ptr;
|
|
struct ele_rec *start;
|
|
struct ele_rec *eptr;
|
|
|
|
if ((text == NULL)&&(header_text == NULL)&&(footer_text == NULL))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Free up the old visited href list.
|
|
*/
|
|
FreeHRefs(hw->html.my_visited_hrefs);
|
|
hw->html.my_visited_hrefs = NULL;
|
|
|
|
/*
|
|
* Free up the old visited delayed images list.
|
|
*/
|
|
FreeDelayedImages(hw->html.my_delayed_images);
|
|
hw->html.my_delayed_images = NULL;
|
|
|
|
/*
|
|
* Hide any old widgets
|
|
*/
|
|
HideWidgets(hw);
|
|
hw->html.widget_list = wptr;
|
|
hw->html.form_list = NULL;
|
|
|
|
if (text != NULL)
|
|
{
|
|
if (*text == '\0')
|
|
{
|
|
text = NULL;
|
|
}
|
|
hw->html.raw_text = text;
|
|
|
|
/*
|
|
* Free any old colors and pixmaps
|
|
*/
|
|
FreeColors(XtDisplay(hw),DefaultColormapOfScreen(XtScreen(hw)));
|
|
FreeImages(hw);
|
|
|
|
/*
|
|
* Parse the raw text with the HTML parser
|
|
*/
|
|
hw->html.html_objects = HTMLParse(hw->html.html_objects,
|
|
hw->html.raw_text);
|
|
CallLinkCallbacks(hw);
|
|
}
|
|
if (header_text != NULL)
|
|
{
|
|
if (*header_text == '\0')
|
|
{
|
|
header_text = NULL;
|
|
}
|
|
hw->html.header_text = header_text;
|
|
|
|
/*
|
|
* Parse the header text with the HTML parser
|
|
*/
|
|
hw->html.html_header_objects =
|
|
HTMLParse(hw->html.html_header_objects,
|
|
hw->html.header_text);
|
|
}
|
|
if (footer_text != NULL)
|
|
{
|
|
if (*footer_text == '\0')
|
|
{
|
|
footer_text = NULL;
|
|
}
|
|
hw->html.footer_text = footer_text;
|
|
|
|
/*
|
|
* Parse the footer text with the HTML parser
|
|
*/
|
|
hw->html.html_footer_objects =
|
|
HTMLParse(hw->html.html_footer_objects,
|
|
hw->html.footer_text);
|
|
}
|
|
|
|
/*
|
|
* Reformat the new text
|
|
*/
|
|
hw->html.max_pre_width = DocumentWidth(hw, hw->html.html_objects);
|
|
ReformatWindow(hw);
|
|
|
|
/*
|
|
* If a target anchor is passed, override the element id
|
|
* with the id of that anchor.
|
|
*/
|
|
if (target_anchor != NULL)
|
|
{
|
|
int id;
|
|
|
|
id = HTMLAnchorToId(w, target_anchor);
|
|
if (id != 0)
|
|
{
|
|
element_id = id;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Position text at id specified, or at top if no position
|
|
* specified.
|
|
* Find the element corrsponding to the id passed in.
|
|
*/
|
|
eptr = NULL;
|
|
if (element_id != 0)
|
|
{
|
|
start = hw->html.formatted_elements;
|
|
while (start != NULL)
|
|
{
|
|
if (start->ele_id == element_id)
|
|
{
|
|
eptr = start;
|
|
break;
|
|
}
|
|
start = start->next;
|
|
}
|
|
}
|
|
/*
|
|
* Took this out because it screwed up the scrollbar positioning which
|
|
* I hacked on. It sucks but seems to work. john.
|
|
*/
|
|
/*
|
|
if (eptr == NULL)
|
|
{
|
|
newy = 0;
|
|
}
|
|
else
|
|
{
|
|
newy = eptr->y - 2;
|
|
}
|
|
if (newy < 0)
|
|
{
|
|
newy = 0;
|
|
}
|
|
if (newy > (hw->html.doc_height - (int)hw->html.view_height))
|
|
{
|
|
newy = hw->html.doc_height - (int)hw->html.view_height;
|
|
}
|
|
if (newy < 0)
|
|
{
|
|
newy = 0;
|
|
}
|
|
hw->html.scroll_x = 0;
|
|
hw->html.scroll_y = newy;
|
|
*/
|
|
#ifdef DEBUG
|
|
fprintf (stderr, "calling in HTMLSetText\n");
|
|
#endif
|
|
ConfigScrollBars(hw);
|
|
ScrollWidgets(hw);
|
|
|
|
/*
|
|
* Display the new text
|
|
*/
|
|
ViewClearAndRefresh(hw);
|
|
|
|
/*
|
|
* Clear any previous selection
|
|
*/
|
|
hw->html.select_start = NULL;
|
|
hw->html.select_end = NULL;
|
|
hw->html.sel_start_pos = 0;
|
|
hw->html.sel_end_pos = 0;
|
|
hw->html.new_start = NULL;
|
|
hw->html.new_end = NULL;
|
|
hw->html.new_start_pos = 0;
|
|
hw->html.new_end_pos = 0;
|
|
hw->html.active_anchor = NULL;
|
|
|
|
hw->html.cached_tracked_ele = NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* To use faster TOLOWER as set up in HTMLparse.c
|
|
*/
|
|
#ifdef NOT_ASCII
|
|
#define TOLOWER(x) (tolower(x))
|
|
#else
|
|
extern char map_table[];
|
|
#define TOLOWER(x) (map_table[x])
|
|
#endif /* NOT_ASCII */
|
|
|
|
|
|
/*
|
|
* Convenience function to search the text of the HTML document as a single
|
|
* white space separated string. Linefeeds are converted into spaces.
|
|
*
|
|
* Takes a pattern, pointers to the start and end blocks to store the
|
|
* start and end of the match into. Start is also used as the location to
|
|
* start the search from for incremental searching. If start is an invalid
|
|
* position (id = 0). Default start is the beginning of the document for
|
|
* forward searching, and the end of the document for backwards searching.
|
|
* The backward and caseless parameters I hope are self-explanatory.
|
|
*
|
|
* returns 1 on success
|
|
* (and the start and end positions of the match).
|
|
* returns -1 otherwise (and start and end are unchanged).
|
|
*/
|
|
int
|
|
#ifdef _NO_PROTO
|
|
HTMLSearchText (w, pattern, m_start, m_end, backward, caseless)
|
|
Widget w;
|
|
char *pattern;
|
|
ElementRef *m_start;
|
|
ElementRef *m_end;
|
|
int backward;
|
|
int caseless;
|
|
#else
|
|
HTMLSearchText (Widget w, char *pattern, ElementRef *m_start, ElementRef *m_end,
|
|
int backward, int caseless)
|
|
#endif
|
|
{
|
|
HTMLWidget hw = (HTMLWidget)w;
|
|
int found, equal;
|
|
char *match;
|
|
char *tptr;
|
|
char *mptr;
|
|
char cval;
|
|
struct ele_rec *eptr;
|
|
int s_pos;
|
|
struct ele_rec *s_eptr;
|
|
ElementRef s_ref, e_ref;
|
|
ElementRef *start, *end;
|
|
|
|
/*
|
|
* If bad parameters are passed, just fail the search
|
|
*/
|
|
if ((pattern == NULL)||(*pattern == '\0')||
|
|
(m_start == NULL)||(m_end == NULL))
|
|
{
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* If we are caseless, make a lower case copy of the pattern to
|
|
* match to use in compares.
|
|
*
|
|
* remember to free this before returning
|
|
*/
|
|
if (caseless)
|
|
{
|
|
match = (char *)malloc(strlen(pattern) + 1);
|
|
tptr = pattern;
|
|
mptr = match;
|
|
while (*tptr != '\0')
|
|
{
|
|
*mptr = (char)TOLOWER((int)*tptr);
|
|
mptr++;
|
|
tptr++;
|
|
}
|
|
*mptr = '\0';
|
|
}
|
|
else
|
|
{
|
|
match = pattern;
|
|
}
|
|
|
|
/*
|
|
* Slimy coding. I later decided I didn't want to change start and
|
|
* end if the search failed. Rather than changing all the code,
|
|
* I just copy it into locals here, and copy it out again if a match
|
|
* is found.
|
|
*/
|
|
start = &s_ref;
|
|
end = &e_ref;
|
|
start->id = m_start->id;
|
|
start->pos = m_start->pos;
|
|
end->id = m_end->id;
|
|
end->pos = m_end->pos;
|
|
|
|
/*
|
|
* Find the user specified start position.
|
|
*/
|
|
if (start->id > 0)
|
|
{
|
|
found = 0;
|
|
eptr = hw->html.formatted_elements;
|
|
|
|
while (eptr != NULL)
|
|
{
|
|
if (eptr->ele_id == start->id)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|