1 /****************************************************************************
2  * NCSA Mosaic for the X Window System                                      *
3  * Software Development Group                                               *
4  * National Center for Supercomputing Applications                          *
5  * University of Illinois at Urbana-Champaign                               *
6  * 605 E. Springfield, Champaign IL 61820                                   *
7  * mosaic@ncsa.uiuc.edu                                                     *
8  *                                                                          *
9  * Copyright (C) 1993, Board of Trustees of the University of Illinois      *
10  *                                                                          *
11  * NCSA Mosaic software, both binary and source (hereafter, Software) is    *
12  * copyrighted by The Board of Trustees of the University of Illinois       *
13  * (UI), and ownership remains with the UI.                                 *
14  *                                                                          *
15  * The UI grants you (hereafter, Licensee) a license to use the Software    *
16  * for academic, research and internal business purposes only, without a    *
17  * fee.  Licensee may distribute the binary and source code (if released)   *
18  * to third parties provided that the copyright notice and this statement   *
19  * appears on all copies and that no charge is associated with such         *
20  * copies.                                                                  *
21  *                                                                          *
22  * Licensee may make derivative works.  However, if Licensee distributes    *
23  * any derivative work based on or derived from the Software, then          *
24  * Licensee will (1) notify NCSA regarding its distribution of the          *
25  * derivative work, and (2) clearly notify users that such derivative       *
26  * work is a modified version and not the original NCSA Mosaic              *
27  * distributed by the UI.                                                   *
28  *                                                                          *
29  * Any Licensee wishing to make commercial use of the Software should       *
30  * contact the UI, c/o NCSA, to negotiate an appropriate license for such   *
31  * commercial use.  Commercial use includes (1) integration of all or       *
32  * part of the source code into a product for sale or license by or on      *
33  * behalf of Licensee to third parties, or (2) distribution of the binary   *
34  * code or source code to third parties that need it to utilize a           *
35  * commercial product sold or licensed by or on behalf of Licensee.         *
36  *                                                                          *
37  * UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR   *
38  * ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED          *
39  * WARRANTY.  THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE    *
40  * USERS OF THIS SOFTWARE.                                                  *
41  *                                                                          *
42  * By using or copying this Software, Licensee agrees to abide by the       *
43  * copyright law and all other applicable laws of the U.S. including, but   *
44  * not limited to, export control laws, and the terms of this license.      *
45  * UI shall have the right to terminate this license immediately by         *
46  * written notice upon Licensee's breach of, or non-compliance with, any    *
47  * of its terms.  Licensee may be held legally responsible for any          *
48  * copyright infringement that is caused or encouraged by Licensee's        *
49  * failure to abide by the terms of this license.                           *
50  *                                                                          *
51  * Comments and questions are welcome and can be sent to                    *
52  * mosaic-x@ncsa.uiuc.edu.                                                  *
53  ****************************************************************************/
54 
55 #include <stdio.h>
56 #include "HTMLP.h"
57 #ifdef MOTIF
58 #include <Xm/DrawingA.h>
59 #include <Xm/ScrollBar.h>
60 #else
61 #include "DrawingArea.h"
62 #include <X11/Xaw/Scrollbar.h>
63 #endif
64 #include <X11/cursorfont.h>
65 
66 
67 #define	MARGIN_DEFAULT		20
68 #define	CLICK_TIME		500
69 #define	SELECT_THRESHOLD	3
70 #define	MAX_UNDERLINES		3
71 #define DEFAULT_INCREMENT       18
72 
73 #ifndef ABS
74 #define ABS(x)  (((x) > 0) ? (x) : ((x) * -1))
75 #endif
76 
77 #define	W_TEXTFIELD	0
78 #define	W_CHECKBOX	1
79 #define	W_RADIOBOX	2
80 #define	W_PUSHBUTTON	3
81 #define	W_PASSWORD	4
82 #define	W_OPTIONMENU	5
83 
84 
85 extern int FormatAll();
86 extern int DocumentWidth();
87 extern void PlaceLine();
88 extern void TextRefresh();
89 extern void ImageRefresh();
90 extern void LinefeedRefresh();
91 extern void RefreshTextRange();
92 extern void FreeColors();
93 extern void FreeImages();
94 extern void HideWidgets();
95 extern void MapWidgets();
96 extern int SwapElements();
97 extern int ElementLessThan();
98 extern int IsDelayedHRef();
99 extern int IsIsMapForm();
100 extern int AnchoredHeight();
101 extern char *ParseMarkTag();
102 extern char *ParseTextToString();
103 extern char *ParseTextToPrettyString();
104 extern char *ParseTextToPSString();
105 extern struct mark_up *HTMLParse();
106 extern struct ele_rec *LocateElement();
107 extern struct ele_rec **MakeLineList();
108 extern void FreeHRefs();
109 extern struct ref_rec *AddHRef();
110 extern void FreeDelayedImages();
111 extern struct delay_rec *AddDelayedImage();
112 extern ImageInfo *NoImageData();
113 extern void ImageSubmitForm();
114 
115 
116 static void		SelectStart();
117 static void		ExtendStart();
118 static void		ExtendAdjust();
119 static void		ExtendEnd();
120 static void             TrackMotion();
121 static Boolean		ConvertSelection();
122 static void		LoseSelection();
123 static void		SelectionDone();
124 
125 
126 #ifdef _NO_PROTO
127 
128 static void		_HTMLInput() ;
129 #ifndef MOTIF
130 static void		_HTMLpwdInput() ;
131 #endif
132 static void             Initialize() ;
133 static void             Redisplay() ;
134 static void             Resize() ;
135 static Boolean          SetValues() ;
136 static XtGeometryResult	GeometryManager() ;
137 static void		RecolorInternalHRefs() ;
138 static Dimension	VbarWidth();
139 static Dimension	HbarHeight();
140 static void		ViewRedisplay();
141 static void		ViewClearAndRefresh();
142 static void		CallLinkCallbacks();
143 
144 #else /* _NO_PROTO */
145 
146 static void		_HTMLInput(Widget w, XEvent *event,
147 				String *params, Cardinal *num_params);
148 #ifndef MOTIF
149 static void		_HTMLpwdInput(Widget w, XEvent *event,
150 				String *params, Cardinal *num_params);
151 #endif
152 static void             Initialize(HTMLWidget request, HTMLWidget new);
153 static void             Redisplay(HTMLWidget hw, XEvent *event, Region region);
154 static void             Resize(HTMLWidget hw);
155 static Boolean          SetValues(HTMLWidget current, HTMLWidget request,
156 				HTMLWidget new);
157 static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *request,
158 				XtWidgetGeometry *reply);
159 static void		RecolorInternalHRefs(HTMLWidget hw, char *href);
160 static Dimension        VbarWidth(HTMLWidget hw);
161 static Dimension        HbarHeight(HTMLWidget hw);
162 static void		ViewRedisplay(HTMLWidget hw, int x, int y,
163 				int width, int height);
164 static void             ViewClearAndRefresh(HTMLWidget hw);
165 static void             CallLinkCallbacks(HTMLWidget hw);
166 #endif /* _NO_PROTO */
167 
168 
169 /*
170  * Default translations
171  * Selection of text, and activate anchors.
172  * If motif, add manager translations.
173  */
174 #ifdef MOTIF
175 static char defaultTranslations[] =
176 " \
177 <Btn1Down>:	select-start() ManagerGadgetArm()\n\
178 <Btn1Motion>:	extend-adjust() ManagerGadgetButtonMotion()\n\
179 <Btn1Up>:	extend-end(PRIMARY, CUT_BUFFER0) ManagerGadgetActivate()\n\
180 <Btn2Down>:	select-start()\n\
181 <Btn2Motion>:	extend-adjust()\n\
182 <Btn2Up>:	extend-end(PRIMARY, CUT_BUFFER0)\n\
183 <Btn3Down>:	extend-start()\n\
184 <Btn3Motion>:	extend-adjust()\n\
185 <Btn3Up>:	extend-end(PRIMARY, CUT_BUFFER0) \n\
186 <Motion>:       track-motion()\n\
187 <Leave>:        track-motion()\n\
188 <FocusOut>:     track-motion()\n\
189 <Expose>:       track-motion()\
190 ";
191 #else
192 static char defaultTranslations[] =
193 " \
194 <Btn1Down>:	select-start() \n\
195 <Btn1Motion>:	extend-adjust() \n\
196 <Btn1Up>:	extend-end(PRIMARY, CUT_BUFFER0) \n\
197 <Btn2Down>:	select-start() \n\
198 <Btn2Motion>:	extend-adjust() \n\
199 <Btn2Up>:	extend-end(PRIMARY, CUT_BUFFER0) \n\
200 <Btn3Down>:	extend-start()\n\
201 <Btn3Motion>:	extend-adjust()\n\
202 <Btn3Up>:	extend-end(PRIMARY, CUT_BUFFER0) \n\
203 <Motion>:       track-motion()\n\
204 <Leave>:        track-motion()\n\
205 <FocusOut>:     track-motion()\n\
206 <Expose>:       track-motion()\
207 ";
208 #endif /* MOTIF */
209 
210 
211 static XtActionsRec actionsList[] =
212 {
213    { "select-start",    (XtActionProc) SelectStart },
214    { "extend-start",    (XtActionProc) ExtendStart },
215    { "extend-adjust",   (XtActionProc) ExtendAdjust },
216    { "extend-end",      (XtActionProc) ExtendEnd },
217    { "track-motion",    (XtActionProc) TrackMotion },
218    { "HTMLInput",	(XtActionProc) _HTMLInput },
219 #ifndef MOTIF
220    { "HTMLpwdInput",	(XtActionProc) _HTMLpwdInput },
221 #endif
222 
223 #ifdef MOTIF
224 #ifndef MOTIF1_2
225    { "Arm",      (XtActionProc) _XmGadgetArm },         /* Motif 1.0 */
226    { "Activate", (XtActionProc) _XmGadgetActivate },    /* Motif 1.0 */
227    { "Enter",    (XtActionProc) _XmManagerEnter },      /* Motif 1.0 */
228    { "FocusIn",  (XtActionProc) _XmManagerFocusIn },    /* Motif 1.0 */
229    { "Help",     (XtActionProc) _XmManagerHelp },       /* Motif 1.0 */
230 #endif /* not MOTIF1_2 */
231 #endif /* MOTIF */
232 };
233 
234 /*
235  * For some reason, in Motif1.2/X11R5 the actionsList above gets corrupted
236  * When the parent HTML widget is created.  This means we can't use
237  * it later with XtAppAddActions to add to the viewing area.
238  * So, we make a spare copy here to use with XtAppAddActions.
239  */
240 static XtActionsRec SpareActionsList[] =
241 {
242    { "select-start",    (XtActionProc) SelectStart },
243    { "extend-start",    (XtActionProc) ExtendStart },
244    { "extend-adjust",   (XtActionProc) ExtendAdjust },
245    { "extend-end",      (XtActionProc) ExtendEnd },
246    { "track-motion",    (XtActionProc) TrackMotion },
247    { "HTMLInput",	(XtActionProc) _HTMLInput },
248 #ifndef MOTIF
249    { "HTMLpwdInput",	(XtActionProc) _HTMLpwdInput },
250 #endif
251 };
252 
253 
254 
255 /*
256  *  Resource definitions for HTML widget
257  */
258 
259 static XtResource resources[] =
260 {
261   /* Without Motif we need to override the borderWidth to 0 (from 1). */
262 #ifndef MOTIF
263         {       XtNborderWidth,
264                 XtCBorderWidth, XtRDimension, sizeof (Dimension),
265                 XtOffset (HTMLWidget, core.border_width),
266                 XtRImmediate, (XtPointer) 0
267         },
268 #endif
269 
270 	{	WbNmarginWidth,
271 		WbCMarginWidth, XtRDimension, sizeof (Dimension),
272 		XtOffset (HTMLWidget, html.margin_width),
273 		XtRImmediate, (caddr_t) MARGIN_DEFAULT
274 	},
275 
276 	{	WbNmarginHeight,
277 		WbCMarginHeight, XtRDimension, sizeof (Dimension),
278 		XtOffset (HTMLWidget, html.margin_height),
279 		XtRImmediate, (caddr_t) MARGIN_DEFAULT
280 	},
281 
282 	{	WbNanchorCallback,
283 		XtCCallback, XtRCallback, sizeof (XtCallbackList),
284 		XtOffset (HTMLWidget, html.anchor_callback),
285 		XtRImmediate, (caddr_t) NULL
286 	},
287 
288 	{	WbNlinkCallback,
289 		XtCCallback, XtRCallback, sizeof (XtCallbackList),
290 		XtOffset (HTMLWidget, html.link_callback),
291 		XtRImmediate, (caddr_t) NULL
292 	},
293 
294 	{	WbNsubmitFormCallback,
295 		XtCCallback, XtRCallback, sizeof (XtCallbackList),
296 		XtOffset (HTMLWidget, html.form_callback),
297 		XtRImmediate, (caddr_t) NULL
298 	},
299 
300 	{	WbNtext,
301 		WbCText, XtRString, sizeof (char *),
302 		XtOffset (HTMLWidget, html.raw_text),
303 		XtRString, (char *) NULL
304 	},
305 
306 	{	WbNheaderText,
307 		WbCHeaderText, XtRString, sizeof (char *),
308 		XtOffset (HTMLWidget, html.header_text),
309 		XtRString, (char *) NULL
310 	},
311 
312 	{	WbNfooterText,
313 		WbCFooterText, XtRString, sizeof (char *),
314 		XtOffset (HTMLWidget, html.footer_text),
315 		XtRString, (char *) NULL
316 	},
317 
318 	{	WbNtitleText,
319 		WbCTitleText, XtRString, sizeof (char *),
320 		XtOffset (HTMLWidget, html.title),
321 		XtRString, (char *) NULL
322 	},
323 
324 /*
325  * Without motif we need our own foreground resource instead of
326  * using the manager's
327  */
328 #ifndef MOTIF
329 	{	XtNforeground,
330 		XtCForeground, XtRPixel, sizeof (Pixel),
331 		XtOffset (HTMLWidget, html.foreground),
332 		XtRString, "Black"
333 	},
334 #endif
335 
336 	{	WbNanchorUnderlines,
337 		WbCAnchorUnderlines, XtRInt, sizeof (int),
338 		XtOffset (HTMLWidget, html.num_anchor_underlines),
339 		XtRString, "0"
340 	},
341 
342 	{	WbNvisitedAnchorUnderlines,
343 		WbCVisitedAnchorUnderlines, XtRInt, sizeof (int),
344 		XtOffset (HTMLWidget, html.num_visitedAnchor_underlines),
345 		XtRString, "0"
346 	},
347 
348 	{	WbNdashedAnchorUnderlines,
349 		WbCDashedAnchorUnderlines, XtRBoolean, sizeof (Boolean),
350 		XtOffset (HTMLWidget, html.dashed_anchor_lines),
351 		XtRString, "False"
352 	},
353 
354 	{	WbNdashedVisitedAnchorUnderlines,
355 		WbCDashedVisitedAnchorUnderlines, XtRBoolean, sizeof (Boolean),
356 		XtOffset (HTMLWidget, html.dashed_visitedAnchor_lines),
357 		XtRString, "False"
358 	},
359 
360 	{	WbNanchorColor,
361 		XtCForeground, XtRPixel, sizeof (Pixel),
362 		XtOffset (HTMLWidget, html.anchor_fg),
363 		XtRString, "blue2"
364 	},
365 
366 	{	WbNvisitedAnchorColor,
367 		XtCForeground, XtRPixel, sizeof (Pixel),
368 		XtOffset (HTMLWidget, html.visitedAnchor_fg),
369 		XtRString, "purple4"
370 	},
371 
372 	{	WbNactiveAnchorFG,
373 		XtCBackground, XtRPixel, sizeof (Pixel),
374 		XtOffset (HTMLWidget, html.activeAnchor_fg),
375 		XtRString, "Red"
376 	},
377 
378 	{	WbNactiveAnchorBG,
379 		XtCForeground, XtRPixel, sizeof (Pixel),
380 		XtOffset (HTMLWidget, html.activeAnchor_bg),
381 		XtRString, "White"
382 	},
383 
384 	{	WbNpercentVerticalSpace,
385 		WbCPercentVerticalSpace, XtRInt, sizeof (int),
386 		XtOffset (HTMLWidget, html.percent_vert_space),
387 		XtRString, "90"
388 	},
389 
390 	{	WbNimageBorders,
391 		WbCImageBorders, XtRBoolean, sizeof (Boolean),
392 		XtOffset (HTMLWidget, html.border_images),
393 		XtRString, "False"
394 	},
395 
396 	{	WbNdelayImageLoads,
397 		WbCDelayImageLoads, XtRBoolean, sizeof (Boolean),
398 		XtOffset (HTMLWidget, html.delay_images),
399 		XtRString, "False"
400 	},
401 
402 	{	WbNfancySelections,
403 		WbCFancySelections, XtRBoolean, sizeof (Boolean),
404 		XtOffset (HTMLWidget, html.fancy_selections),
405 		XtRString, "False"
406 	},
407 
408 	{	WbNisIndex,
409 		WbCIsIndex, XtRBoolean, sizeof (Boolean),
410 		XtOffset (HTMLWidget, html.is_index),
411 		XtRString, "False"
412 	},
413 
414 	{	WbNview,
415 		WbCView, XtRWidget, sizeof (Widget),
416 		XtOffset (HTMLWidget, html.view),
417 		XtRImmediate, NULL
418 	},
419 
420 	{	WbNverticalScrollBar,
421 		WbCVerticalScrollBar, XtRWidget, sizeof (Widget),
422 		XtOffset (HTMLWidget, html.vbar),
423 		XtRImmediate, NULL
424 	},
425 
426 	{	WbNhorizontalScrollBar,
427 		WbCHorizontalScrollBar, XtRWidget, sizeof (Widget),
428 		XtOffset (HTMLWidget, html.hbar),
429 		XtRImmediate, NULL
430 	},
431 
432 	{	WbNverticalScrollOnRight,
433 		WbCVerticalScrollOnRight, XtRBoolean, sizeof (Boolean),
434 		XtOffset (HTMLWidget, html.vbar_right),
435 		XtRString, "True"
436 	},
437 
438 	{	WbNhorizontalScrollOnTop,
439 		WbCHorizontalScrollOnTop, XtRBoolean, sizeof (Boolean),
440 		XtOffset (HTMLWidget, html.hbar_top),
441 		XtRString, "False"
442 	},
443 
444 	{	XtNfont,
445 		XtCFont, XtRFontStruct, sizeof (XFontStruct *),
446 		XtOffset (HTMLWidget, html.font),
447 		XtRString, "-adobe-times-medium-r-normal-*-14-*-*-*-*-*-*-*"
448 	},
449 
450 	{	WbNitalicFont,
451 		WbCItalicFont, XtRFontStruct, sizeof (XFontStruct *),
452 		XtOffset (HTMLWidget, html.italic_font),
453 		XtRString, "-adobe-times-medium-i-normal-*-14-*-*-*-*-*-*-*"
454 	},
455 
456 	{	WbNboldFont,
457 		WbCBoldFont, XtRFontStruct, sizeof (XFontStruct *),
458 		XtOffset (HTMLWidget, html.bold_font),
459 		XtRString, "-adobe-times-bold-r-normal-*-14-*-*-*-*-*-*-*"
460 	},
461 
462 	{	WbNfixedFont,
463 		WbCFixedFont, XtRFontStruct, sizeof (XFontStruct *),
464 		XtOffset (HTMLWidget, html.fixed_font),
465 		XtRString, "-adobe-courier-medium-r-normal-*-14-*-*-*-*-*-*-*"
466 	},
467 
468 	{	WbNfixedboldFont,
469 		WbCFixedboldFont, XtRFontStruct, sizeof (XFontStruct *),
470 		XtOffset (HTMLWidget, html.fixedbold_font),
471 		XtRString, "-adobe-courier-bold-r-normal-*-14-*-*-*-*-*-*-*"
472 	},
473 
474 	{	WbNfixeditalicFont,
475 		WbCFixeditalicFont, XtRFontStruct, sizeof (XFontStruct *),
476 		XtOffset (HTMLWidget, html.fixeditalic_font),
477 		XtRString, "-adobe-courier-medium-o-normal-*-14-*-*-*-*-*-*-*"
478 	},
479 
480 	{	WbNheader1Font,
481 		WbCHeader1Font, XtRFontStruct, sizeof (XFontStruct *),
482 		XtOffset (HTMLWidget, html.header1_font),
483 		XtRString, "-adobe-times-bold-r-normal-*-24-*-*-*-*-*-*-*"
484 	},
485 
486 	{	WbNheader2Font,
487 		WbCHeader2Font, XtRFontStruct, sizeof (XFontStruct *),
488 		XtOffset (HTMLWidget, html.header2_font),
489 		XtRString, "-adobe-times-bold-r-normal-*-18-*-*-*-*-*-*-*"
490 	},
491 
492 	{	WbNheader3Font,
493 		WbCHeader3Font, XtRFontStruct, sizeof (XFontStruct *),
494 		XtOffset (HTMLWidget, html.header3_font),
495 		XtRString, "-adobe-times-bold-r-normal-*-17-*-*-*-*-*-*-*"
496 	},
497 
498 	{	WbNheader4Font,
499 		WbCHeader4Font, XtRFontStruct, sizeof (XFontStruct *),
500 		XtOffset (HTMLWidget, html.header4_font),
501 		XtRString, "-adobe-times-bold-r-normal-*-14-*-*-*-*-*-*-*"
502 	},
503 
504 	{	WbNheader5Font,
505 		WbCHeader5Font, XtRFontStruct, sizeof (XFontStruct *),
506 		XtOffset (HTMLWidget, html.header5_font),
507 		XtRString, "-adobe-times-bold-r-normal-*-12-*-*-*-*-*-*-*"
508 	},
509 
510 	{	WbNheader6Font,
511 		WbCHeader6Font, XtRFontStruct, sizeof (XFontStruct *),
512 		XtOffset (HTMLWidget, html.header6_font),
513 		XtRString, "-adobe-times-bold-r-normal-*-10-*-*-*-*-*-*-*"
514 	},
515 
516 	{	WbNaddressFont,
517 		WbCAddressFont, XtRFontStruct, sizeof (XFontStruct *),
518 		XtOffset (HTMLWidget, html.address_font),
519 		XtRString, "-adobe-times-medium-i-normal-*-14-*-*-*-*-*-*-*"
520 	},
521 
522 	{	WbNplainFont,
523 		WbCPlainFont, XtRFontStruct, sizeof (XFontStruct *),
524 		XtOffset (HTMLWidget, html.plain_font),
525 		XtRString, "-adobe-courier-medium-r-normal-*-14-*-*-*-*-*-*-*"
526 	},
527 
528 	{	WbNplainboldFont,
529 		WbCPlainboldFont, XtRFontStruct, sizeof (XFontStruct *),
530 		XtOffset (HTMLWidget, html.plainbold_font),
531 		XtRString, "-adobe-courier-bold-r-normal-*-14-*-*-*-*-*-*-*"
532 	},
533 
534 	{	WbNplainitalicFont,
535 		WbCPlainitalicFont, XtRFontStruct, sizeof (XFontStruct *),
536 		XtOffset (HTMLWidget, html.plainitalic_font),
537 		XtRString, "-adobe-courier-medium-o-normal-*-14-*-*-*-*-*-*-*"
538 	},
539 
540 	{	WbNlistingFont,
541 		WbCListingFont, XtRFontStruct, sizeof (XFontStruct *),
542 		XtOffset (HTMLWidget, html.listing_font),
543 		XtRString, "-adobe-courier-medium-r-normal-*-12-*-*-*-*-*-*-*"
544 	},
545 /* amb */
546         {       WbNsupSubFont,
547                 WbCSupSubFont, XtRFontStruct, sizeof (XFontStruct *),
548                 XtOffset (HTMLWidget, html.supsub_font),
549                 XtRString, "-adobe-courier-medium-r-normal-*-10-*-*-*-*-*-*-*"
550         },
551 /* end amb */
552         {       WbNpreviouslyVisitedTestFunction,
553                 WbCPreviouslyVisitedTestFunction, XtRPointer,
554                 sizeof (XtPointer),
555                 XtOffset (HTMLWidget, html.previously_visited_test),
556                 XtRImmediate, (caddr_t) NULL
557         },
558 
559         {       WbNresolveImageFunction,
560                 WbCResolveImageFunction, XtRPointer,
561                 sizeof (XtPointer),
562                 XtOffset (HTMLWidget, html.resolveImage),
563                 XtRImmediate, (caddr_t) NULL
564         },
565 
566         {       WbNresolveDelayedImage,
567                 WbCResolveDelayedImage, XtRPointer,
568                 sizeof (XtPointer),
569                 XtOffset (HTMLWidget, html.resolveDelayedImage),
570                 XtRImmediate, (caddr_t) NULL
571         },
572 
573         {
574                 WbNpointerMotionCallback,
575                 WbCPointerMotionCallback, XtRPointer,
576                 sizeof (XtPointer),
577                 XtOffset (HTMLWidget, html.pointer_motion_callback),
578                 XtRImmediate, (caddr_t) NULL
579         },
580 
581 };
582 
583 
584 
585 HTMLClassRec htmlClassRec = {
586    {						/* core class fields  */
587 #ifdef MOTIF
588       (WidgetClass) &xmManagerClassRec,		/* superclass         */
589 #else
590       (WidgetClass) &constraintClassRec,	/* superclass         */
591 #endif /* MOTIF */
592       "HTML",					/* class_name         */
593       sizeof(HTMLRec),				/* widget_size        */
594       NULL,					/* class_initialize   */
595       NULL,					/* class_part_init    */
596       FALSE,					/* class_inited       */
597       (XtInitProc) Initialize,			/* initialize         */
598       NULL,					/* initialize_hook    */
599       XtInheritRealize,				/* realize            */
600       actionsList,				/* actions	      */
601       XtNumber(actionsList),			/* num_actions	      */
602       resources,				/* resources          */
603       XtNumber(resources),			/* num_resources      */
604       NULLQUARK,				/* xrm_class          */
605       TRUE,					/* compress_motion    */
606       FALSE,					/* compress_exposure  */
607       TRUE,					/* compress_enterlv   */
608       FALSE,					/* visible_interest   */
609       NULL,			                /* destroy            */
610       (XtWidgetProc) Resize,			/* resize             */
611       (XtExposeProc) Redisplay,			/* expose             */
612       (XtSetValuesFunc) SetValues,		/* set_values         */
613       NULL,					/* set_values_hook    */
614       XtInheritSetValuesAlmost,			/* set_values_almost  */
615       NULL,					/* get_values_hook    */
616       NULL,					/* accept_focus       */
617       XtVersion,				/* version            */
618       NULL,					/* callback_private   */
619       defaultTranslations,			/* tm_table           */
620       XtInheritQueryGeometry,			/* query_geometry     */
621       XtInheritDisplayAccelerator,              /* display_accelerator*/
622       NULL,		                        /* extension          */
623    },
624 
625    {		/* composite_class fields */
626       (XtGeometryHandler) GeometryManager,   	/* geometry_manager   */
627       NULL,					/* change_managed     */
628       XtInheritInsertChild,			/* insert_child       */
629       XtInheritDeleteChild,			/* delete_child       */
630       NULL,                                     /* extension          */
631    },
632 
633    {		/* constraint_class fields */
634       NULL,					/* resource list        */
635       0,					/* num resources        */
636       0,					/* constraint size      */
637       NULL,					/* init proc            */
638       NULL,					/* destroy proc         */
639       NULL,					/* set values proc      */
640       NULL,                                     /* extension            */
641    },
642 
643 #ifdef MOTIF
644    {		/* manager_class fields */
645       XtInheritTranslations,			/* translations           */
646       NULL,					/* syn_resources      	  */
647       0,					/* num_syn_resources 	  */
648       NULL,					/* syn_cont_resources     */
649       0,					/* num_syn_cont_resources */
650       XmInheritParentProcess,                   /* parent_process         */
651       NULL,					/* extension 	          */
652    },
653 #endif /* MOTIF */
654 
655    {		/* html_class fields */
656       0						/* none			  */
657    }
658 };
659 
660 WidgetClass htmlWidgetClass = (WidgetClass)&htmlClassRec;
661 
662 static Cursor in_anchor_cursor = (Cursor)NULL;
663 
664 
665 /*
666  * Process an expose event in the View (or drawing area).  This
667  * Can be a regular expose event, or perhaps a GraphicsExpose Event.
668  */
669 static void
DrawExpose(w,data,event)670 DrawExpose(w, data, event)
671 	Widget w;
672 	caddr_t data;
673 	XEvent *event;
674 {
675 	XExposeEvent *ExEvent = (XExposeEvent *)event;
676 	HTMLWidget hw = (HTMLWidget)data;
677 	int x, y;
678 	int width, height;
679 
680 	if ((event->xany.type != Expose)&&(event->xany.type != GraphicsExpose))
681 	{
682 		return;
683 	}
684 
685 	/*
686 	 * Make sure we have a valid GC to draw with.
687 	 */
688 	if (hw->html.drawGC == NULL)
689 	{
690 		unsigned long valuemask;
691 		XGCValues values;
692 
693 		values.function = GXcopy;
694 		values.plane_mask = AllPlanes;
695 /*
696  * Without motif we use our own foreground resource instead of
697  * using the manager's
698  */
699 #ifdef MOTIF
700 		values.foreground = hw->manager.foreground;
701 #else
702 		values.foreground = hw->html.foreground;
703 #endif /* MOTIF */
704 		values.background = hw->core.background_pixel;
705 
706 		valuemask = GCFunction|GCPlaneMask|GCForeground|GCBackground;
707 
708 		hw->html.drawGC = XCreateGC(XtDisplay(hw), XtWindow(hw),
709 			valuemask, &values);
710 	}
711 
712 	x = ExEvent->x;
713 	y = ExEvent->y;
714 	width = (int)ExEvent->width;
715 	height = (int)ExEvent->height;
716 
717 #ifdef DEBUG
718 DebugHook(x, y, width, height);
719 #endif
720 
721 	ViewRedisplay(hw, x, y, width, height);
722 }
723 
724 
725 void
ScrollWidgets(hw)726 ScrollWidgets(hw)
727 	HTMLWidget hw;
728 {
729 	WidgetInfo *wptr;
730 	int xval, yval;
731 
732 	xval = hw->html.scroll_x;
733 	yval = hw->html.scroll_y;
734 	wptr = hw->html.widget_list;
735 	while (wptr != NULL)
736 	{
737 		if (wptr->w != NULL)
738 		{
739 			Widget w;
740 			int x, y;
741 
742 			w = wptr->w;
743 			x = wptr->x;
744 			y = wptr->y;
745 			XtMoveWidget(w, (x - xval), (y - yval));
746 		}
747 		wptr = wptr->next;
748 	}
749 }
750 
751 
752 #ifndef MOTIF
753 /*
754  * Set the Athena Scrollbar's thumb position properly.
755  */
756 static void
setScrollBar(sb,topPosition,totalLength,currentLength)757 setScrollBar(sb, topPosition, totalLength, currentLength)
758 	Widget sb;
759 	Position topPosition;
760 	Dimension totalLength, currentLength;
761 {
762 	float top   = (float)topPosition  /(float)(totalLength);
763 	float shown = (float)currentLength/(float)(totalLength);
764 
765 	XawScrollbarSetThumb(sb, top, shown);
766 }
767 #endif
768 
769 
770 /*
771  * Either the vertical or hortizontal scrollbar has been moved
772  */
773 void
ScrollToPos(w,hw,value)774 ScrollToPos(w, hw, value)
775 	Widget w;
776 	HTMLWidget hw;
777 	int value;
778 {
779 	/*
780 	 * Special code incase the scrollbar is "moved" before we have a window
781 	 * (if we have a GC we have a window)
782 	 */
783 	if (hw->html.drawGC == NULL)
784 	{
785 		if (w == hw->html.vbar)
786 		{
787 			hw->html.scroll_y = value;
788 		}
789 		else if (w == hw->html.hbar)
790 		{
791 			hw->html.scroll_x = value;
792 		}
793 		return;
794 	}
795 
796 	/*
797 	 * get our widgets out of the way (No Expose events)
798 	HideWidgets(hw);
799 	 */
800 
801 	/*
802 	 * If we've moved the vertical scrollbar
803 	 */
804 	if (w == hw->html.vbar)
805 	{
806 		/*
807 		 * We've scrolled down. Copy up the untouched part of the
808 		 * window.  Then Clear and redraw the new area
809 		 * exposed.
810 		 */
811 		if (value > hw->html.scroll_y)
812 		{
813 			int dy;
814 
815 			dy = value - hw->html.scroll_y;
816 			if (dy > hw->html.view_height)
817 			{
818 				hw->html.scroll_y = value;
819 				XClearArea(XtDisplay(hw->html.view),
820 					XtWindow(hw->html.view),
821 					0, 0,
822 					hw->html.view_width,
823 					hw->html.view_height, False);
824 				ViewRedisplay(hw,
825 					0, 0,
826 					hw->html.view_width,
827 					hw->html.view_height);
828 			}
829 			else
830 			{
831 				XCopyArea(XtDisplay(hw->html.view),
832 					XtWindow(hw->html.view),
833 					XtWindow(hw->html.view),
834 					hw->html.drawGC, 0, dy,
835 					hw->html.view_width,
836 					hw->html.view_height - dy,
837 					0, 0);
838 				hw->html.scroll_y = value;
839 				XClearArea(XtDisplay(hw->html.view),
840 					XtWindow(hw->html.view),
841 					0, (int)hw->html.view_height - dy,
842 					hw->html.view_width, dy, False);
843 				ViewRedisplay(hw,
844 					0, (int)hw->html.view_height - dy,
845 					hw->html.view_width, dy);
846 			}
847 		}
848 		/*
849 		 * We've scrolled up. Copy down the untouched part of the
850 		 * window.  Then Clear and redraw the new area
851 		 * exposed.
852 		 */
853 		else if (value < hw->html.scroll_y)
854 		{
855 			int dy;
856 
857 			dy = hw->html.scroll_y - value;
858 			if (dy > hw->html.view_height)
859 			{
860 				hw->html.scroll_y = value;
861 				XClearArea(XtDisplay(hw->html.view),
862 					XtWindow(hw->html.view),
863 					0, 0,
864 					hw->html.view_width,
865 					hw->html.view_height, False);
866 				ViewRedisplay(hw,
867 					0, 0,
868 					hw->html.view_width,
869 					hw->html.view_height);
870 			}
871 			else
872 			{
873 				XCopyArea(XtDisplay(hw->html.view),
874 					XtWindow(hw->html.view),
875 					XtWindow(hw->html.view),
876 					hw->html.drawGC, 0, 0,
877 					hw->html.view_width,
878 					hw->html.view_height - dy,
879 					0, dy);
880 				hw->html.scroll_y = value;
881 				XClearArea(XtDisplay(hw->html.view),
882 					XtWindow(hw->html.view),
883 					0, 0,
884 					hw->html.view_width, dy, False);
885 				ViewRedisplay(hw,
886 					0, 0,
887 					hw->html.view_width, dy);
888 			}
889 		}
890 	}
891 	/*
892 	 * Else we've moved the horizontal scrollbar
893 	 */
894 	else if (w == hw->html.hbar)
895 	{
896 		/*
897 		 * We've scrolled right. Copy left the untouched part of the
898 		 * window.  Then Clear and redraw the new area
899 		 * exposed.
900 		 */
901 		if (value > hw->html.scroll_x)
902 		{
903 			int dx;
904 
905 			dx = value - hw->html.scroll_x;
906 			if (dx > hw->html.view_width)
907 			{
908 				hw->html.scroll_x = value;
909 				XClearArea(XtDisplay(hw->html.view),
910 					XtWindow(hw->html.view),
911 					0, 0,
912 					hw->html.view_width,
913 					hw->html.view_height, False);
914 				ViewRedisplay(hw,
915 					0, 0,
916 					hw->html.view_width,
917 					hw->html.view_height);
918 			}
919 			else
920 			{
921 				XCopyArea(XtDisplay(hw->html.view),
922 					XtWindow(hw->html.view),
923 					XtWindow(hw->html.view),
924 					hw->html.drawGC, dx, 0,
925 					hw->html.view_width - dx,
926 					hw->html.view_height,
927 					0, 0);
928 				hw->html.scroll_x = value;
929 				XClearArea(XtDisplay(hw->html.view),
930 					XtWindow(hw->html.view),
931 					(int)hw->html.view_width - dx, 0,
932 					dx, hw->html.view_height, False);
933 				ViewRedisplay(hw,
934 					(int)hw->html.view_width - dx, 0,
935 					dx, hw->html.view_height);
936 			}
937 		}
938 		/*
939 		 * We've scrolled left. Copy right the untouched part of the
940 		 * window.  Then Clear and redraw the new area
941 		 * exposed.
942 		 */
943 		else if (value < hw->html.scroll_x)
944 		{
945 			int dx;
946 
947 			dx = hw->html.scroll_x - value;
948 			if (dx > hw->html.view_width)
949 			{
950 				hw->html.scroll_x = value;
951 				XClearArea(XtDisplay(hw->html.view),
952 					XtWindow(hw->html.view),
953 					0, 0,
954 					hw->html.view_width,
955 					hw->html.view_height, False);
956 				ViewRedisplay(hw,
957 					0, 0,
958 					hw->html.view_width,
959 					hw->html.view_height);
960 			}
961 			else
962 			{
963 				XCopyArea(XtDisplay(hw->html.view),
964 					XtWindow(hw->html.view),
965 					XtWindow(hw->html.view),
966 					hw->html.drawGC, 0, 0,
967 					hw->html.view_width - dx,
968 					hw->html.view_height,
969 					dx, 0);
970 				hw->html.scroll_x = value;
971 				XClearArea(XtDisplay(hw->html.view),
972 					XtWindow(hw->html.view),
973 					0, 0,
974 					dx, hw->html.view_height, False);
975 				ViewRedisplay(hw,
976 					0, 0,
977 					dx, hw->html.view_height);
978 			}
979 		}
980 	}
981 
982 	/*
983 	 * Move the now hidden widgets
984 	 * Flush any Copyed or Cleared text first.
985 	XFlush(XtDisplay(hw));
986 	 */
987 	ScrollWidgets(hw);
988 
989 	/*
990 	 * Remap the widgets to their new location
991 	MapWidgets(hw);
992 	 */
993 }
994 
995 
996 /*
997  * Either the vertical or hortizontal scrollbar has been moved
998  */
999 void
ScrollMove(w,client_data,call_data)1000 ScrollMove(w, client_data, call_data)
1001 	Widget w;
1002 	caddr_t client_data;
1003 	caddr_t call_data;
1004 {
1005 #ifdef MOTIF
1006 	XmScrollBarCallbackStruct *sc = (XmScrollBarCallbackStruct *)call_data;
1007 
1008 	ScrollToPos(w, (HTMLWidget)client_data, sc->value);
1009 #else
1010 	float scrollDir = (int)call_data < 0 ? -0.3 : 0.3;
1011 	HTMLWidget hw = (HTMLWidget)client_data;
1012 	int value;
1013 	Dimension totalLength, currentLength;
1014 
1015 	if (w == hw->html.vbar)
1016 	{
1017 		totalLength = hw->html.doc_height;
1018 		currentLength = hw->html.view_height;
1019 		value = hw->html.scroll_y + scrollDir * currentLength;
1020 	}
1021 	else
1022 	{
1023 		totalLength = hw->html.doc_width;
1024 		currentLength = hw->html.view_width;
1025 		value = hw->html.scroll_x + scrollDir * currentLength;
1026 	}
1027 
1028 	if (value > (int)totalLength) value = totalLength;
1029 	if (value < 0) value = 0;
1030 
1031 	setScrollBar(w, value, totalLength, currentLength);
1032 	ScrollToPos(w, hw, value);
1033 #endif
1034 }
1035 
1036 
1037 #ifndef MOTIF
1038 void
JumpMove(w,client_data,call_data)1039 JumpMove(w, client_data, call_data)
1040 	Widget w;
1041 	caddr_t client_data;
1042 	caddr_t call_data;
1043 {
1044 	HTMLWidget hw = (HTMLWidget)client_data;
1045 	int value = (int)(*(float *)call_data *
1046 			(w == hw->html.vbar ?
1047 			hw->html.doc_height :
1048 			hw->html.doc_width));
1049 	ScrollToPos(w, hw, value);
1050 }
1051 #endif
1052 
1053 
1054 /*
1055  * Create the horizontal and vertical scroll bars.
1056  * Size them later.
1057  */
1058 static void
1059 #ifdef _NO_PROTO
CreateScrollbars(hw)1060 CreateScrollbars (hw)
1061             HTMLWidget hw ;
1062 #else
1063 CreateScrollbars(
1064             HTMLWidget hw)
1065 #endif
1066 {
1067 	Arg arg[20];
1068 	Cardinal argcnt;
1069 	XtTranslations trans;
1070 
1071 	/*
1072 	 * If the user hasn't provided a viewing area Widget (which they
1073 	 * should not most of the time) make a drawing are to use.
1074 	 */
1075 	if (hw->html.view == NULL)
1076 	{
1077 		argcnt = 0;
1078 		XtSetArg(arg[argcnt], XxNwidth, 10); argcnt++;
1079 		XtSetArg(arg[argcnt], XxNheight, 10); argcnt++;
1080 		hw->html.view = XtCreateWidget("View",
1081 #ifdef MOTIF
1082 			xmDrawingAreaWidgetClass,
1083 #else
1084 			drawingAreaWidgetClass,
1085 #endif
1086 			(Widget)hw, arg, argcnt);
1087 		XtManageChild(hw->html.view);
1088 	}
1089 
1090 	/*
1091 	 * For the view widget catch all Expose and GraphicsExpose
1092 	 * events.  Replace its translations with ours, and make
1093 	 * sure all the actions are in order.
1094 	 */
1095 	XtAddEventHandler((Widget)hw->html.view, ExposureMask, True,
1096 		(XtEventHandler)DrawExpose, (caddr_t)hw);
1097 	/*
1098 	 * As described previoisly, for some reason with Motif1.2/X11R5
1099 	 * the list actionsList is corrupted when we get here,
1100 	 * so we have to use the special copy SpareActionsList
1101 	 */
1102 	XtAppAddActions(XtWidgetToApplicationContext(hw->html.view),
1103 		SpareActionsList, XtNumber(SpareActionsList));
1104 	trans = XtParseTranslationTable(defaultTranslations);
1105 	argcnt = 0;
1106 	XtSetArg(arg[argcnt], XtNtranslations, trans); argcnt++;
1107 	XtSetValues(hw->html.view, arg, argcnt);
1108 
1109 	/*
1110 	 * If the user hasn't provided a vertical scrollbar (which they
1111 	 * should not most of the time) make one.
1112 	 */
1113 	if (hw->html.vbar == NULL)
1114 	{
1115 		argcnt = 0;
1116 #ifdef MOTIF
1117 		XtSetArg(arg[argcnt], XmNorientation, XmVERTICAL); argcnt++;
1118 		hw->html.vbar = XtCreateWidget("Vbar", xmScrollBarWidgetClass,
1119 			(Widget)hw, arg, argcnt);
1120 #else
1121 		XtSetArg(arg[argcnt],XtNorientation,XtorientVertical); argcnt++;
1122 		hw->html.vbar = XtCreateWidget("Vbar", scrollbarWidgetClass,
1123 			(Widget)hw, arg, argcnt);
1124 #endif
1125 		XtManageChild(hw->html.vbar);
1126 	}
1127 
1128 	/*
1129 	 * Add callbacks to catch scrollbar changes
1130 	 */
1131 #ifdef MOTIF
1132 	XtAddCallback(hw->html.vbar, XmNvalueChangedCallback,
1133 		(XtCallbackProc)ScrollMove, (caddr_t)hw);
1134 	XtAddCallback(hw->html.vbar, XmNdragCallback,
1135 		(XtCallbackProc)ScrollMove, (caddr_t)hw);
1136 #else
1137 	XtAddCallback(hw->html.vbar, XtNjumpProc,
1138 		(XtCallbackProc)JumpMove, (caddr_t)hw);
1139 	XtAddCallback(hw->html.vbar, XtNscrollProc,
1140 		(XtCallbackProc)ScrollMove, (caddr_t)hw);
1141 #endif
1142 
1143 	/*
1144 	 * If the user hasn't provided a horizontal scrollbar (which they
1145 	 * should not most of the time) make one.
1146 	 */
1147 	if (hw->html.hbar == NULL)
1148 	{
1149 		argcnt = 0;
1150 #ifdef MOTIF
1151 		XtSetArg(arg[argcnt], XmNorientation, XmHORIZONTAL); argcnt++;
1152 		hw->html.hbar = XtCreateWidget("Hbar", xmScrollBarWidgetClass,
1153 			(Widget)hw, arg, argcnt);
1154 #else
1155 		XtSetArg(arg[argcnt], XtNorientation, XtorientHorizontal);
1156 		argcnt++;
1157 		hw->html.hbar = XtCreateWidget("Hbar", scrollbarWidgetClass,
1158 			(Widget)hw, arg, argcnt);
1159 #endif
1160 		XtManageChild(hw->html.hbar);
1161 	}
1162 
1163 	/*
1164 	 * Add callbacks to catch scrollbar changes
1165 	 */
1166 #ifdef MOTIF
1167 	XtAddCallback(hw->html.hbar, XmNvalueChangedCallback,
1168 		(XtCallbackProc)ScrollMove, (caddr_t)hw);
1169 	XtAddCallback(hw->html.hbar, XmNdragCallback,
1170 		(XtCallbackProc)ScrollMove, (caddr_t)hw);
1171 #else
1172 	XtAddCallback(hw->html.hbar, XtNjumpProc,
1173 		(XtCallbackProc)JumpMove, (caddr_t)hw);
1174 	XtAddCallback(hw->html.hbar, XtNscrollProc,
1175 		(XtCallbackProc)ScrollMove, (caddr_t)hw);
1176 #endif
1177 }
1178 
1179 
1180 /*
1181  * Return the width of the vertical scrollbar
1182  */
1183 static Dimension
1184 #ifdef _NO_PROTO
VbarWidth(hw)1185 VbarWidth (hw)
1186             HTMLWidget hw ;
1187 #else
1188 VbarWidth(
1189             HTMLWidget hw)
1190 #endif
1191 {
1192 	Arg arg[4];
1193 	Cardinal argcnt;
1194 	Dimension width;
1195 
1196 	width = 0;
1197 	if (hw->html.vbar != NULL)
1198 	{
1199 		argcnt = 0;
1200 		XtSetArg(arg[argcnt], XxNwidth, &width); argcnt++;
1201 		XtGetValues(hw->html.vbar, arg, argcnt);
1202 	}
1203 
1204 	return(width);
1205 }
1206 
1207 
1208 /*
1209  * Return the height of the horizontal scrollbar
1210  */
1211 static Dimension
1212 #ifdef _NO_PROTO
HbarHeight(hw)1213 HbarHeight (hw)
1214             HTMLWidget hw ;
1215 #else
1216 HbarHeight(
1217             HTMLWidget hw)
1218 #endif
1219 {
1220 	Arg arg[4];
1221 	Cardinal argcnt;
1222 	Dimension height;
1223 
1224 	height = 0;
1225 	if (hw->html.hbar != NULL)
1226 	{
1227 		argcnt = 0;
1228 		XtSetArg(arg[argcnt], XxNheight, &height); argcnt++;
1229 		XtGetValues(hw->html.hbar, arg, argcnt);
1230 	}
1231 
1232 	return(height);
1233 }
1234 
1235 
1236 /*
1237  * Resize and set the min and max values of the scrollbars.  Position viewing
1238  * area based on scrollbar locations.
1239  */
1240 static void
1241 #ifdef _NO_PROTO
ConfigScrollBars(hw)1242 ConfigScrollBars (hw)
1243             HTMLWidget hw ;
1244 #else
1245 ConfigScrollBars(
1246             HTMLWidget hw)
1247 #endif
1248 {
1249 #ifdef MOTIF
1250 	Arg arg[20];
1251 	Cardinal argcnt;
1252 #endif
1253 	int vx, vy;
1254 
1255 	/*
1256 	 * Move and size the viewing area
1257 	 */
1258 #ifdef MOTIF
1259 	vx = hw->manager.shadow_thickness;
1260 	vy = hw->manager.shadow_thickness;
1261 #else
1262 	vx = vy = 0;
1263 #endif
1264 	if ((hw->html.use_vbar == True)&&(hw->html.vbar_right == False))
1265 	{
1266 		vx += VbarWidth(hw);
1267 	}
1268 	if ((hw->html.use_hbar == True)&&(hw->html.hbar_top == True))
1269 	{
1270 		vy += HbarHeight(hw);
1271 	}
1272 	XtMoveWidget(hw->html.view, vx, vy);
1273 	XtResizeWidget(hw->html.view, hw->html.view_width, hw->html.view_height,
1274 		hw->html.view->core.border_width);
1275 
1276 	/*
1277 	 * Set up vertical scrollbar
1278 	 */
1279 	if (hw->html.use_vbar == True)
1280 	{
1281 		int maxv;
1282 		int ss;
1283 
1284 		/*
1285 		 * Size the vertical scrollbar to the height of
1286 		 * the viewing area
1287 		 */
1288 		XtResizeWidget(hw->html.vbar, hw->html.vbar->core.width,
1289 		    hw->html.view_height + (2 *
1290 #ifdef MOTIF
1291 					    hw->manager.shadow_thickness
1292 #else
1293 					    0
1294 #endif
1295 					    ),
1296 		    hw->html.vbar->core.border_width);
1297 
1298 		/*
1299 		 * Set the slider size to be the percentage of the
1300 		 * viewing area that the viewing area is of the
1301 		 * document area.  Or set it to 1 if that isn't possible.
1302 		 */
1303 		if (hw->html.doc_height == 0)
1304 		{
1305 			ss = 1;
1306 		}
1307 		else
1308 		{
1309 #ifdef DEBUG
1310 fprintf (stderr, "view_height %d, doc_height %d\n",
1311 hw->html.view_height, hw->html.doc_height);
1312 #endif
1313 #ifdef NOT_RIGHT
1314                         /* Eric -- your previous equation wasn't doing it.
1315                            This isn't either... */
1316 			ss =
1317                           (int)((float)hw->html.view_height *
1318                                 ((float)hw->html.view_height /
1319                                  (float)(hw->html.doc_height - (int)hw->html.view_height)));
1320 			if (ss > hw->html.view_height)
1321 			{
1322 				ss = hw->html.view_height;
1323 			}
1324 #endif
1325                         /* Added by marca: this produces results *very* close (~1 pixel)
1326                            to the original scrolled window behavior. */
1327                         ss = hw->html.view_height;
1328 		}
1329 		if (ss < 1)
1330 		{
1331 			ss = 1;
1332 		}
1333 #ifdef DEBUG
1334 fprintf (stderr, "computed ss to be %d\n", ss);
1335 #endif
1336 
1337 		/*
1338 		 * If resizing of the document has made scroll_y
1339 		 * greater than the max, we want to hold it at the max.
1340 		 */
1341 		maxv = hw->html.doc_height - (int)hw->html.view_height;
1342 		if (maxv < 0)
1343 		{
1344 			maxv = 0;
1345 		}
1346 		if (hw->html.scroll_y > maxv)
1347 		{
1348 			hw->html.scroll_y = maxv;
1349 		}
1350 
1351 		/*
1352 		 * Prevent the Motif max value and slider size
1353 		 * from going to zero, which is illegal
1354 		 */
1355 		maxv = maxv + ss;
1356 		if (maxv < 1)
1357 		{
1358 			maxv = 1;
1359 		}
1360 
1361 		/*
1362 		 * Motif will not allow the actual value to be equal to
1363 		 * its max value.  Adjust accordingly.
1364 		 * Since we might decrease scroll_y, cap it at zero.
1365 		 */
1366 		if (hw->html.scroll_y >= maxv)
1367 		{
1368 			hw->html.scroll_y = maxv - 1;
1369 		}
1370 		if (hw->html.scroll_y < 0)
1371 		{
1372 			hw->html.scroll_y = 0;
1373 		}
1374 
1375 #ifdef MOTIF
1376 		argcnt = 0;
1377 		XtSetArg(arg[argcnt], XmNminimum, 0); argcnt++;
1378 		XtSetArg(arg[argcnt], XmNmaximum, maxv); argcnt++;
1379 		XtSetArg(arg[argcnt], XmNvalue, hw->html.scroll_y); argcnt++;
1380 		XtSetArg(arg[argcnt], XmNsliderSize, ss); argcnt++;
1381                 XtSetArg(arg[argcnt], XmNincrement, DEFAULT_INCREMENT); argcnt++;
1382                 XtSetArg(arg[argcnt], XmNpageIncrement,
1383                          hw->html.view_height > DEFAULT_INCREMENT ?
1384                            hw->html.view_height - DEFAULT_INCREMENT : 1); argcnt++;
1385 		XtSetValues(hw->html.vbar, arg, argcnt);
1386 #else
1387 		setScrollBar(hw->html.vbar,
1388 			     hw->html.scroll_y,
1389 			     hw->html.doc_height,
1390 			     hw->html.view_height);
1391 #endif /* MOTIF */
1392 
1393 #ifdef DEBUG
1394 XtVaGetValues(hw->html.vbar, XmNsliderSize, &ss, NULL);
1395 fprintf (stderr, "real slider size %d\n", ss);
1396 #endif
1397 	}
1398 
1399 	/*
1400 	 * Set up horizontal scrollbar
1401 	 */
1402 	if (hw->html.use_hbar == True)
1403 	{
1404 		int maxv;
1405 		int ss;
1406 
1407 		/*
1408 		 * Size the horizontal scrollbar to the width of
1409 		 * the viewing area
1410 		 */
1411 		XtResizeWidget(hw->html.hbar,
1412 		    hw->html.view_width + (2 *
1413 #ifdef MOTIF
1414 					   hw->manager.shadow_thickness
1415 #else
1416 					   0
1417 #endif /* MOTIF */
1418 					   ),
1419 		    hw->html.hbar->core.height,
1420 		    hw->html.hbar->core.border_width);
1421 
1422 		/*
1423 		 * Set the slider size to be the percentage of the
1424 		 * viewing area that the viewing area is of the
1425 		 * document area.  Or set it to 1 if that isn't possible.
1426 		 */
1427 		if (hw->html.doc_width == 0)
1428 		{
1429 			ss = 1;
1430 		}
1431 		else
1432 		{
1433 #ifdef NOT_RIGHT
1434 			ss = hw->html.view_width *
1435 				hw->html.view_width / hw->html.doc_width;
1436 			if (ss > hw->html.view_width)
1437 			{
1438 				ss = hw->html.view_width;
1439 			}
1440 #endif
1441                         /* Added by marca: this produces results *very* close (~1 pixel)
1442                            to the original scrolled window behavior. */
1443                         ss = hw->html.view_width;
1444 		}
1445 		if (ss < 1)
1446 		{
1447 			ss = 1;
1448 		}
1449 
1450 		/*
1451 		 * If resizing of the document has made scroll_x
1452 		 * greater than the max, we want to hold it at the max.
1453 		 */
1454 		maxv = hw->html.doc_width - (int)hw->html.view_width;
1455 		if (maxv < 0)
1456 		{
1457 			maxv = 0;
1458 		}
1459 		if (hw->html.scroll_x > maxv)
1460 		{
1461 			hw->html.scroll_x = maxv;
1462 		}
1463 
1464 		/*
1465 		 * Prevent the Motif max value and slider size
1466 		 * from going to zero, which is illegal
1467 		 */
1468 		maxv = maxv + ss;
1469 		if (maxv < 1)
1470 		{
1471 			maxv = 1;
1472 		}
1473 
1474 		/*
1475 		 * Motif will not allow the actual value to be equal to
1476 		 * its max value.  Adjust accordingly.
1477 		 * Since we might decrease scroll_x, cap it at zero.
1478 		 */
1479 		if (hw->html.scroll_x >= maxv)
1480 		{
1481 			hw->html.scroll_x = maxv - 1;
1482 		}
1483 		if (hw->html.scroll_x < 0)
1484 		{
1485 			hw->html.scroll_x = 0;
1486 		}
1487 
1488 #ifdef MOTIF
1489 		argcnt = 0;
1490 		XtSetArg(arg[argcnt], XmNminimum, 0); argcnt++;
1491 		XtSetArg(arg[argcnt], XmNmaximum, maxv); argcnt++;
1492 		XtSetArg(arg[argcnt], XmNvalue, hw->html.scroll_x); argcnt++;
1493 		XtSetArg(arg[argcnt], XmNsliderSize, ss); argcnt++;
1494                 XtSetArg(arg[argcnt], XmNincrement, DEFAULT_INCREMENT); argcnt++;
1495                 XtSetArg(arg[argcnt], XmNpageIncrement,
1496                          hw->html.view_width > DEFAULT_INCREMENT ?
1497                          hw->html.view_width - DEFAULT_INCREMENT : 1); argcnt++;
1498 		XtSetValues(hw->html.hbar, arg, argcnt);
1499 #else
1500 		setScrollBar(hw->html.hbar,
1501 			     hw->html.scroll_x,
1502 			     hw->html.doc_width,
1503 			     hw->html.view_width);
1504 #endif /* MOTIF */
1505 	}
1506 
1507 #ifdef DEBUG
1508         {
1509           int ss;
1510 XtVaGetValues(hw->html.vbar, XmNsliderSize, &ss, NULL);
1511 fprintf (stderr, "real slider size %d\n", ss);
1512         }
1513 #endif
1514 }
1515 
1516 
1517 /*
1518  * Reformat the window and scrollbars.
1519  * May be called because of a changed document, or because of a changed
1520  * window size.
1521  */
1522 static void
1523 #ifdef _NO_PROTO
ReformatWindow(hw)1524 ReformatWindow (hw)
1525             HTMLWidget hw ;
1526 #else
1527 ReformatWindow(
1528             HTMLWidget hw)
1529 #endif
1530 {
1531 	int temp;
1532 	int new_width;
1533 	Dimension swidth, sheight;
1534 	Dimension st;
1535 
1536 	/*
1537 	 * Find the current scrollbar sizes, and shadow thickness and format
1538 	 * the document to the current window width
1539 	 * (assume a vertical scrollbar)
1540 	 */
1541 	swidth = VbarWidth(hw);
1542 	sheight = HbarHeight(hw);
1543 #ifdef MOTIF
1544 	st = hw->manager.shadow_thickness;
1545 #else
1546 	st = 0;
1547 #endif /* MOTIF */
1548 	if (hw->core.width <= swidth)
1549 	{
1550 		hw->core.width = swidth + 10;
1551 	}
1552 	new_width = hw->core.width - swidth - (2 * st);
1553 	temp = FormatAll(hw, &new_width);
1554 
1555 	/*
1556 	 * If we need the vertical scrollbar, place and manage it,
1557 	 * and store the current viewing area width.
1558 	 */
1559 	if (temp > hw->core.height - sheight)
1560 	{
1561 		hw->html.use_vbar = True;
1562 		if (hw->html.vbar_right == True)
1563 		{
1564 			XtMoveWidget(hw->html.vbar,
1565 				(hw->core.width - swidth), 0);
1566 		}
1567 		else
1568 		{
1569 			XtMoveWidget(hw->html.vbar, 0, 0);
1570 		}
1571 		XtManageChild(hw->html.vbar);
1572 		hw->html.view_width = hw->core.width - swidth - (2 * st);
1573 	}
1574 	/*
1575 	 * Else we were wrong to assume a vertical scrollbar.
1576 	 * Remove it, and reformat the document to the wider width.
1577 	 * Save the as the current viewing are width.
1578 	 */
1579 	else
1580 	{
1581 		hw->html.use_vbar = False;
1582 		XtUnmanageChild(hw->html.vbar);
1583 		hw->html.scroll_y = 0;
1584 		new_width = hw->core.width - (2 * st);
1585 		temp = FormatAll(hw, &new_width);
1586 		hw->html.view_width = hw->core.width - (2 * st);
1587 		/* fake out later horizontal scrollbars */
1588 		swidth = 0;
1589 	}
1590 
1591 	/*
1592 	 * Calculate the actual max width and height of the complete
1593 	 * formatted document.
1594 	 * The max width may exceed the preformatted width due to special
1595 	 * factors in the formatting of the widget.
1596 	 * Use the max of the 2 here, but leave max_pre_width unchanged
1597 	 * for future formatting calls.
1598 	 */
1599 	/*
1600 	 * new_width includes the margins, and hw->html.max_pre_width
1601 	 * does not, fix that here.
1602 	 */
1603 	new_width = new_width - (2 * hw->html.margin_width);
1604 	if (hw->html.max_pre_width > new_width)
1605 	{
1606 		new_width = hw->html.max_pre_width;
1607 	}
1608 	/*
1609 	 * If the maximum width derives from a formatted, as opposed to
1610 	 * unformatted piece of text, allow a 20% of margin width slop
1611 	 * over into the margin to cover up a minor glick with terminaing
1612 	 * punctuation after anchors at the end of the line.
1613 	 */
1614 	else
1615 	{
1616 		new_width = new_width - (20 * hw->html.margin_width / 100);
1617 	}
1618 
1619 	hw->html.doc_height = temp;
1620 	hw->html.doc_width = new_width + (2 * hw->html.margin_width);
1621 	if (hw->html.view_width > hw->html.doc_width)
1622 	{
1623 		hw->html.doc_width = hw->html.view_width;
1624 	}
1625 
1626 	/*
1627 	 * If we need a horizontal scrollbar
1628 	 * Place it and manage it.  Save the height of the current
1629 	 * viewing area.
1630 	 */
1631 	if (hw->html.doc_width > hw->html.view_width)
1632 	{
1633 		hw->html.use_hbar = True;
1634 		if (hw->html.hbar_top == True)
1635 		{
1636 			if (hw->html.use_vbar == True)
1637 			{
1638 				XtMoveWidget(hw->html.vbar,
1639 					hw->html.vbar->core.x, sheight);
1640 			}
1641 
1642 			if (hw->html.vbar_right == True)
1643 			{
1644 				XtMoveWidget(hw->html.hbar, 0, 0);
1645 			}
1646 			else
1647 			{
1648 				XtMoveWidget(hw->html.hbar, swidth, 0);
1649 			}
1650 		}
1651 		else
1652 		{
1653 			if (hw->html.vbar_right == True)
1654 			{
1655 				XtMoveWidget(hw->html.hbar, 0,
1656 					(hw->core.height - sheight));
1657 			}
1658 			else
1659 			{
1660 				XtMoveWidget(hw->html.hbar, swidth,
1661 					(hw->core.height - sheight));
1662 			}
1663 		}
1664 		XtManageChild(hw->html.hbar);
1665 		hw->html.view_height = hw->core.height - sheight - (2 * st);
1666 	}
1667 	/*
1668 	 * Else we don't need a horizontal scrollbar.
1669 	 * Remove it and save the current viewing area height.
1670 	 */
1671 	else
1672 	{
1673 		hw->html.use_hbar = False;
1674 		XtUnmanageChild(hw->html.hbar);
1675 		hw->html.scroll_x = 0;
1676 		hw->html.view_height = hw->core.height - (2 * st);
1677 	}
1678 
1679 	/*
1680 	 * Configure the scrollbar min, max, and slider sizes
1681 	 */
1682 #ifdef DEBUG
1683 fprintf (stderr, "calling in ReformatWindow\n");
1684 #endif
1685 	ConfigScrollBars(hw);
1686 }
1687 
1688 
1689 /*
1690  * We're a happy widget.  We let any child move or resize themselves
1691  * however they want, we don't care.
1692  */
1693 static XtGeometryResult
1694 #ifdef _NO_PROTO
GeometryManager(w,request,reply)1695 GeometryManager (w, request, reply)
1696 	Widget w;
1697 	XtWidgetGeometry * request;
1698 	XtWidgetGeometry * reply;
1699 #else
1700 GeometryManager (
1701 	Widget w,
1702 	XtWidgetGeometry * request,
1703 	XtWidgetGeometry * reply)
1704 #endif
1705 {
1706 	reply->x = request->x;
1707 	reply->y = request->y;
1708 	reply->width = request->width;
1709 	reply->height = request->height;
1710 	reply->border_width = request->border_width;
1711 	reply->request_mode = request->request_mode;
1712 	return (XtGeometryYes);
1713 }
1714 
1715 
1716 /*
1717  * Initialize is called when the widget is first initialized.
1718  * Check to see that all the starting resources are valid.
1719  */
1720 static void
1721 #ifdef _NO_PROTO
Initialize(request,new)1722 Initialize (request, new)
1723             HTMLWidget request ;
1724             HTMLWidget new ;
1725 #else
1726 Initialize(
1727             HTMLWidget request,
1728             HTMLWidget new)
1729 #endif
1730 {
1731 	/*
1732 	 *	Make sure height and width are not zero.
1733 	 */
1734 	if (new->core.width == 0)
1735 	{
1736 		new->core.width = new->html.margin_width << 1 ;
1737 	}
1738 	if (new->core.width == 0)
1739 	{
1740 		new->core.width = 10 ;
1741 	}
1742 	if (new->core.height == 0)
1743 	{
1744 		new->core.height = new->html.margin_height << 1 ;
1745 	}
1746 	if (new->core.height == 0)
1747 	{
1748 		new->core.height = 10 ;
1749 	}
1750 
1751 	/*
1752 	 *	Make sure the underline numbers are within bounds.
1753 	 */
1754 	if (new->html.num_anchor_underlines < 0)
1755 	{
1756 		new->html.num_anchor_underlines = 0;
1757 	}
1758 	if (new->html.num_anchor_underlines > MAX_UNDERLINES)
1759 	{
1760 		new->html.num_anchor_underlines = MAX_UNDERLINES;
1761 	}
1762 	if (new->html.num_visitedAnchor_underlines < 0)
1763 	{
1764 		new->html.num_visitedAnchor_underlines = 0;
1765 	}
1766 	if (new->html.num_visitedAnchor_underlines > MAX_UNDERLINES)
1767 	{
1768 		new->html.num_visitedAnchor_underlines = MAX_UNDERLINES;
1769 	}
1770 
1771 	/*
1772 	 * Parse the raw text with the HTML parser.  And set the formatted
1773 	 * element list to NULL.
1774 	 */
1775 	new->html.html_objects = HTMLParse(NULL, request->html.raw_text);
1776 	CallLinkCallbacks(new);
1777 	new->html.html_header_objects =
1778 		HTMLParse(NULL, request->html.header_text);
1779 	new->html.html_footer_objects =
1780 		HTMLParse(NULL, request->html.footer_text);
1781 	new->html.formatted_elements = NULL;
1782 	new->html.my_visited_hrefs = NULL;
1783 	new->html.my_delayed_images = NULL;
1784 	new->html.widget_list = NULL;
1785 	new->html.form_list = NULL;
1786 
1787 	/*
1788 	 * Blank document
1789 	 */
1790 	new->html.line_array = NULL;
1791 	new->html.line_count = 0;
1792 
1793 	/*
1794 	 * Find the max width of a preformatted
1795 	 * line in this document.
1796 	 */
1797 	new->html.max_pre_width = DocumentWidth(new, new->html.html_objects);
1798 
1799 	/*
1800 	 * Create the scrollbars.
1801 	 * Find their dimensions and then decide which scrollbars you
1802 	 * will need, and what the dimensions of the viewing area are.
1803 	 * Start assuming a vertical scrollbar and a horizontal one.
1804 	 * The remove vertical if short enough, and remove horizontal
1805 	 * if narrow enough.
1806 	 */
1807 	CreateScrollbars(new);
1808 	new->html.scroll_x = 0;
1809 	new->html.scroll_y = 0;
1810 	ReformatWindow(new);
1811 
1812 	/*
1813 	 * Initialize private widget resources
1814 	 */
1815 	new->html.drawGC = NULL;
1816 	new->html.select_start = NULL;
1817 	new->html.select_end = NULL;
1818 	new->html.sel_start_pos = 0;
1819 	new->html.sel_end_pos = 0;
1820 	new->html.new_start = NULL;
1821 	new->html.new_end = NULL;
1822 	new->html.new_start_pos = 0;
1823 	new->html.new_end_pos = 0;
1824 	new->html.active_anchor = NULL;
1825 	new->html.press_x = 0;
1826 	new->html.press_y = 0;
1827 
1828         new->html.cached_tracked_ele = NULL;
1829 
1830         /* Initialize cursor used when pointer is inside anchor. */
1831         if (in_anchor_cursor == (Cursor)NULL)
1832           in_anchor_cursor = XCreateFontCursor (XtDisplay (new), XC_hand2);
1833 
1834         return;
1835 }
1836 
1837 
1838 #ifdef DEBUG
1839 void
DebugHook(x,y,width,height)1840 DebugHook(x, y, width, height)
1841 	int x, y, width, height;
1842 {
1843 /*
1844 fprintf(stderr, "Redrawing (%d,%d) %dx%d\n", x, y, width, height);
1845 */
1846 }
1847 #endif
1848 
1849 
1850 /*
1851  * This is called by redisplay.  It is passed a rectangle
1852  * in the viewing area, and it redisplays that portion of the
1853  * underlying document area.
1854  */
1855 static void
1856 #ifdef _NO_PROTO
ViewRedisplay(hw,x,y,width,height)1857 ViewRedisplay (hw, x, y, width, height)
1858             HTMLWidget hw;
1859 	    int x, y;
1860 	    int width, height;
1861 #else
1862 ViewRedisplay(
1863             HTMLWidget hw,
1864             int x,
1865             int y,
1866             int width,
1867             int height)
1868 #endif
1869 {
1870 	int sx, sy;
1871 	int doc_x, doc_y;
1872 	int i, start, end, guess;
1873 
1874 	/*
1875 	 * Use scrollbar values to map from view space to document space.
1876 	 */
1877 	sx = sy = 0;
1878 	if (hw->html.use_vbar == True)
1879 	{
1880 		sy += hw->html.scroll_y;
1881 	}
1882 	if (hw->html.use_hbar == True)
1883 	{
1884 		sx += hw->html.scroll_x;
1885 	}
1886 
1887 	doc_x = x + sx;
1888 	doc_y = y + sy;
1889 
1890 	/*
1891 	 * Find the lines that overlap the exposed area.
1892 	 */
1893 	start = 0;
1894 	end = hw->html.line_count - 1;
1895 
1896 	/*
1897 	 * Heuristic to speed up redraws by guessing at the starting line.
1898 	 */
1899 	guess = doc_y / (hw->html.font->max_bounds.ascent +
1900 		hw->html.font->max_bounds.descent);
1901 	if (guess > end)
1902 	{
1903 		guess = end;
1904 	}
1905 	while (guess > 0)
1906 	{
1907 		if ((hw->html.line_array[guess] != NULL)&&
1908 			(hw->html.line_array[guess]->y < doc_y))
1909 		{
1910 			break;
1911 		}
1912 		guess--;
1913 	}
1914 	if (guess < start)
1915 	{
1916 		guess = start;
1917 	}
1918 
1919 	for (i=guess; i<hw->html.line_count; i++)
1920 	{
1921 		if (hw->html.line_array[i] == NULL)
1922 		{
1923 			continue;
1924 		}
1925 
1926 		if (hw->html.line_array[i]->y < doc_y)
1927 		{
1928 			start = i;
1929 		}
1930 		if (hw->html.line_array[i]->y > (doc_y + height))
1931 		{
1932 			end = i;
1933 			break;
1934 		}
1935 	}
1936 
1937 	/*
1938 	 * If we have a GC draw the lines that overlap the exposed area.
1939 	 */
1940 	if (hw->html.drawGC != NULL)
1941 	{
1942 		for (i=start; i<=end; i++)
1943 		{
1944 			PlaceLine(hw, i);
1945 		}
1946 #ifdef EXTRA_FLUSH
1947 		XFlush(XtDisplay(hw));
1948 #endif
1949 	}
1950 }
1951 
1952 
1953 static void
1954 #ifdef _NO_PROTO
ViewClearAndRefresh(hw)1955 ViewClearAndRefresh (hw)
1956             HTMLWidget hw;
1957 #else
1958 ViewClearAndRefresh(
1959             HTMLWidget hw)
1960 #endif
1961 {
1962 	/*
1963 	 * Only refresh if we have a window already.
1964 	 * (if we have a GC we have a window)
1965 	 */
1966 	if (hw->html.drawGC != NULL)
1967 	{
1968 		XClearArea(XtDisplay(hw->html.view), XtWindow(hw->html.view),
1969 			0, 0, 0, 0, False);
1970 		ViewRedisplay(hw, 0, 0,
1971 			hw->html.view_width, hw->html.view_height);
1972 		/*
1973 		 * This is a fake deal to make an Expose event tocall Redisplay
1974 		 * to redraw the shadow around the view area
1975 		 */
1976 		XClearArea(XtDisplay(hw), XtWindow(hw),
1977 			0, 0, 1, 1, True);
1978 	}
1979 }
1980 
1981 
1982 /*
1983  * The Redisplay function is what you do with an expose event.
1984  * Right now we call user callbacks, and then call the CompositeWidget's
1985  * Redisplay routine.
1986  */
1987 static void
1988 #ifdef _NO_PROTO
Redisplay(hw,event,region)1989 Redisplay (hw, event, region)
1990             HTMLWidget hw;
1991             XEvent * event;
1992             Region region;
1993 #else
1994 Redisplay(
1995             HTMLWidget hw,
1996             XEvent * event,
1997             Region region)
1998 #endif
1999 {
2000 	XExposeEvent *ExEvent = (XExposeEvent *)event;
2001 	int dx, dy;
2002 
2003 #ifdef MOTIF
2004 	/*
2005 	 * find out where the shadow is based on scrollbars
2006 	 */
2007 
2008 	Dimension st = hw->manager.shadow_thickness;
2009 #endif /* MOTIF */
2010 
2011 	dx = dy = 0;
2012 	if ((hw->html.use_vbar == True)&&(hw->html.vbar_right == False))
2013 	{
2014 		dx += VbarWidth(hw);
2015 	}
2016 	if ((hw->html.use_hbar == True)&&(hw->html.hbar_top == True))
2017 	{
2018 		dy += HbarHeight(hw);
2019 	}
2020 
2021 #ifdef MOTIF
2022 	/*
2023 	 * Redraw the shadow around the scrolling area which may have been
2024 	 * messed up.
2025 	 */
2026 	_XmDrawShadow(XtDisplay(hw), XtWindow(hw),
2027 		hw->manager.bottom_shadow_GC, hw->manager.top_shadow_GC,
2028 		hw->manager.shadow_thickness, dx, dy,
2029 		hw->html.view_width + (2 * st),hw->html.view_height + (2 * st));
2030 #endif /* MOTIF */
2031 
2032 #ifdef MOTIF
2033 #ifdef MOTIF1_2
2034 	_XmRedisplayGadgets ((Widget)hw, (XEvent*)event, region);
2035 #else
2036 	_XmRedisplayGadgets ((CompositeWidget)hw, (XExposeEvent*)event, region);
2037 #endif /* MOTIF1_2 */
2038 #endif /* MOTIF */
2039 
2040 	return;
2041 }
2042 
2043 
2044 /*
2045  * Resize is called when the widget changes size.
2046  * Mostly any resize causes a reformat, except for the special case
2047  * where the width doesn't change, and the height doesn't change
2048  * enought to affect the vertical scrollbar.
2049  * It is too complex to guess exactly what needs to be redrawn, so refresh the
2050  * whole window on any resize.
2051  */
2052 static void
2053 #ifdef _NO_PROTO
Resize(hw)2054 Resize (hw)
2055             HTMLWidget hw;
2056 #else
2057 Resize(
2058             HTMLWidget hw)
2059 #endif
2060 {
2061 	int tempw;
2062 	Dimension swidth, sheight;
2063 	Dimension st;
2064 
2065 	/*
2066 	 * Find the new widht of the viewing area.
2067 	 */
2068 	swidth = VbarWidth(hw);
2069 	sheight = HbarHeight(hw);
2070 #ifdef MOTIF
2071 	st = hw->manager.shadow_thickness;
2072 #else
2073 	st = 0;
2074 #endif /* MOTIF */
2075 	if (hw->core.width <= swidth)
2076 	{
2077 		hw->core.width = swidth + 10 ;
2078 	}
2079 
2080 	if (hw->html.use_vbar == True)
2081 	{
2082 		tempw = hw->core.width - swidth - (2 * st);
2083 	}
2084 	else
2085 	{
2086 		tempw = hw->core.width - (2 * st);
2087 		/* fool positioning of horz scrollbar later */
2088 		swidth = 0;
2089 	}
2090 
2091 	/*
2092 	 * Special case where we don't have to reformat to a new width.
2093 	 * The width has not changed, and the height has not changed
2094 	 * significantly to change the state of the vertical scrollbar.
2095 	 */
2096 	if ((tempw == hw->html.view_width)&&
2097 	    (((hw->html.use_vbar == True)&&
2098 	      ((hw->core.height - sheight - (2 * st)) < hw->html.doc_height))||
2099 	     ((hw->html.use_vbar == False)&&
2100 	      ((hw->core.height - sheight - (2 * st)) >= hw->html.doc_height))))
2101 	{
2102 		/*
2103 		 * Super special case where the size of the window hasn't
2104 		 * changed at ALL!
2105 		 */
2106 		if (((hw->html.use_hbar == True)&&(hw->html.view_height ==
2107 			(hw->core.height - sheight - (2 * st))))||
2108 			((hw->html.use_hbar == False)&&(hw->html.view_height ==
2109 			(hw->core.height - (2 * st)))))
2110 		{
2111 			return;
2112 		}
2113 
2114 		if (hw->html.use_hbar == True)
2115 		{
2116 			if (hw->html.hbar_top == True)
2117 			{
2118 				if (hw->html.vbar_right == True)
2119 				{
2120 					XtMoveWidget(hw->html.hbar, 0, 0);
2121 				}
2122 				else
2123 				{
2124 					XtMoveWidget(hw->html.hbar, swidth, 0);
2125 				}
2126 			}
2127 			else
2128 			{
2129 				if (hw->html.vbar_right == True)
2130 				{
2131 					XtMoveWidget(hw->html.hbar, 0,
2132 						(hw->core.height - sheight));
2133 				}
2134 				else
2135 				{
2136 					XtMoveWidget(hw->html.hbar, swidth,
2137 						(hw->core.height - sheight));
2138 				}
2139 			}
2140 			hw->html.view_height = hw->core.height - sheight -
2141 				(2 * st);
2142 		}
2143 		else
2144 		{
2145 			hw->html.view_height = hw->core.height - (2 * st);
2146 		}
2147 #ifdef DEBUG
2148 fprintf (stderr, "calling in Resize\n");
2149 #endif
2150 		ConfigScrollBars(hw);
2151 		ScrollWidgets(hw);
2152 		ViewClearAndRefresh(hw);
2153 	}
2154 	/*
2155 	 * Otherwise we have to do a full reformat on every resize.
2156 	 */
2157 	else
2158 	{
2159 		ReformatWindow(hw);
2160 		ScrollWidgets(hw);
2161 		ViewClearAndRefresh(hw);
2162 	}
2163 
2164 #ifdef DEBUG
2165         {
2166           int ss;
2167 XtVaGetValues(hw->html.vbar, XmNsliderSize, &ss, NULL);
2168 fprintf (stderr, "leaving; slider size %d\n", ss);
2169         }
2170 #endif
2171 
2172 	return;
2173 }
2174 
2175 
2176 /*
2177  * Find the complete text for this the anchor that aptr is a part of
2178  * and set it into the selection.
2179  */
2180 static void
FindSelectAnchor(hw,aptr)2181 FindSelectAnchor(hw, aptr)
2182 	HTMLWidget hw;
2183 	struct ele_rec *aptr;
2184 {
2185 	struct ele_rec *eptr;
2186 
2187 	eptr = aptr;
2188 	while ((eptr->prev != NULL)&&
2189 		(eptr->prev->anchorHRef != NULL)&&
2190 		(strcmp(eptr->prev->anchorHRef, eptr->anchorHRef) == 0))
2191 	{
2192 		eptr = eptr->prev;
2193 	}
2194 	hw->html.select_start = eptr;
2195 	hw->html.sel_start_pos = 0;
2196 
2197 	eptr = aptr;
2198 	while ((eptr->next != NULL)&&
2199 		(eptr->next->anchorHRef != NULL)&&
2200 		(strcmp(eptr->next->anchorHRef, eptr->anchorHRef) == 0))
2201 	{
2202 		eptr = eptr->next;
2203 	}
2204 	hw->html.select_end = eptr;
2205 	hw->html.sel_end_pos = eptr->edata_len - 2;
2206 }
2207 
2208 
2209 /*
2210  * Set as active all elements in the widget that are part of the anchor
2211  * in the widget's start ptr.
2212  */
2213 static void
SetAnchor(hw)2214 SetAnchor(hw)
2215 	HTMLWidget hw;
2216 {
2217 	struct ele_rec *eptr;
2218 	struct ele_rec *start;
2219 	struct ele_rec *end;
2220 	unsigned long fg, bg;
2221 	unsigned long old_fg, old_bg;
2222 
2223 	eptr = hw->html.active_anchor;
2224 	if ((eptr == NULL)||(eptr->anchorHRef == NULL))
2225 	{
2226 		return;
2227 	}
2228 	fg = hw->html.activeAnchor_fg;
2229 	bg = hw->html.activeAnchor_bg;
2230 
2231 	FindSelectAnchor(hw, eptr);
2232 
2233 	start = hw->html.select_start;
2234 	end = hw->html.select_end;
2235 
2236 	eptr = start;
2237 	while ((eptr != NULL)&&(eptr != end))
2238 	{
2239 		if (eptr->type == E_TEXT)
2240 		{
2241 			old_fg = eptr->fg;
2242 			old_bg = eptr->bg;
2243 			eptr->fg = fg;
2244 			eptr->bg = bg;
2245 			TextRefresh(hw, eptr,
2246 				0, (eptr->edata_len - 2));
2247 			eptr->fg = old_fg;
2248 			eptr->bg = old_bg;
2249 		}
2250 		else if (eptr->type == E_IMAGE)
2251 		{
2252 			old_fg = eptr->fg;
2253 			old_bg = eptr->bg;
2254 			eptr->fg = fg;
2255 			eptr->bg = bg;
2256 			ImageRefresh(hw, eptr);
2257 			eptr->fg = old_fg;
2258 			eptr->bg = old_bg;
2259 		}
2260 	/*
2261 	 * Linefeeds in anchor spanning multiple lines should NOT
2262 	 * be highlighted!
2263 		else if (eptr->type == E_LINEFEED)
2264 		{
2265 			old_fg = eptr->fg;
2266 			old_bg = eptr->bg;
2267 			eptr->fg = fg;
2268 			eptr->bg = bg;
2269 			LinefeedRefresh(hw, eptr);
2270 			eptr->fg = old_fg;
2271 			eptr->bg = old_bg;
2272 		}
2273 	*/
2274 		eptr = eptr->next;
2275 	}
2276 	if (eptr != NULL)
2277 	{
2278 		if (eptr->type == E_TEXT)
2279 		{
2280 			old_fg = eptr->fg;
2281 			old_bg = eptr->bg;
2282 			eptr->fg = fg;
2283 			eptr->bg = bg;
2284 			TextRefresh(hw, eptr,
2285 				0, (eptr->edata_len - 2));
2286 			eptr->fg = old_fg;
2287 			eptr->bg = old_bg;
2288 		}
2289 		else if (eptr->type == E_IMAGE)
2290 		{
2291 			old_fg = eptr->fg;
2292 			old_bg = eptr->bg;
2293 			eptr->fg = fg;
2294 			eptr->bg = bg;
2295 			ImageRefresh(hw, eptr);
2296 			eptr->fg = old_fg;
2297 			eptr->bg = old_bg;
2298 		}
2299 	/*
2300 	 * Linefeeds in anchor spanning multiple lines should NOT
2301 	 * be highlighted!
2302 		else if (eptr->type == E_LINEFEED)
2303 		{
2304 			old_fg = eptr->fg;
2305 			old_bg = eptr->bg;
2306 			eptr->fg = fg;
2307 			eptr->bg = bg;
2308 			LinefeedRefresh(hw, eptr);
2309 			eptr->fg = old_fg;
2310 			eptr->bg = old_bg;
2311 		}
2312 	*/
2313 	}
2314 }
2315 
2316 
2317 /*
2318  * Draw selection for all elements in the widget
2319  * from start to end.
2320  */
2321 static void
DrawSelection(hw,start,end,start_pos,end_pos)2322 DrawSelection(hw, start, end, start_pos, end_pos)
2323 	HTMLWidget hw;
2324 	struct ele_rec *start;
2325 	struct ele_rec *end;
2326 	int start_pos, end_pos;
2327 {
2328 	struct ele_rec *eptr;
2329 	int epos;
2330 
2331 	if ((start == NULL)||(end == NULL))
2332 	{
2333 		return;
2334 	}
2335 
2336 	/*
2337 	 * Keep positions within bounds (allows us to be sloppy elsewhere)
2338 	 */
2339 	if (start_pos < 0)
2340 	{
2341 		start_pos = 0;
2342 	}
2343 	if (start_pos >= start->edata_len - 1)
2344 	{
2345 		start_pos = start->edata_len - 2;
2346 	}
2347 	if (end_pos < 0)
2348 	{
2349 		end_pos = 0;
2350 	}
2351 	if (end_pos >= end->edata_len - 1)
2352 	{
2353 		end_pos = end->edata_len - 2;
2354 	}
2355 
2356 	if (SwapElements(start, end, start_pos, end_pos))
2357 	{
2358 		eptr = start;
2359 		start = end;
2360 		end = eptr;
2361 		epos = start_pos;
2362 		start_pos = end_pos;
2363 		end_pos = epos;
2364 	}
2365 
2366 	eptr = start;
2367 	while ((eptr != NULL)&&(eptr != end))
2368 	{
2369 		int p1, p2;
2370 
2371 		if (eptr == start)
2372 		{
2373 			p1 = start_pos;
2374 		}
2375 		else
2376 		{
2377 			p1 = 0;
2378 		}
2379 		p2 = eptr->edata_len - 2;
2380 
2381 		if (eptr->type == E_TEXT)
2382 		{
2383 			eptr->selected = True;
2384 			eptr->start_pos = p1;
2385 			eptr->end_pos = p2;
2386 			TextRefresh(hw, eptr, p1, p2);
2387 		}
2388 		else if (eptr->type == E_LINEFEED)
2389 		{
2390 			eptr->selected = True;
2391 			LinefeedRefresh(hw, eptr);
2392 		}
2393 		eptr = eptr->next;
2394 	}
2395 	if (eptr != NULL)
2396 	{
2397 		int p1, p2;
2398 
2399 		if (eptr == start)
2400 		{
2401 			p1 = start_pos;
2402 		}
2403 		else
2404 		{
2405 			p1 = 0;
2406 		}
2407 
2408 		if (eptr == end)
2409 		{
2410 			p2 = end_pos;
2411 		}
2412 		else
2413 		{
2414 			p2 = eptr->edata_len - 2;
2415 		}
2416 
2417 		if (eptr->type == E_TEXT)
2418 		{
2419 			eptr->selected = True;
2420 			eptr->start_pos = p1;
2421 			eptr->end_pos = p2;
2422 			TextRefresh(hw, eptr, p1, p2);
2423 		}
2424 		else if (eptr->type == E_LINEFEED)
2425 		{
2426 			eptr->selected = True;
2427 			LinefeedRefresh(hw, eptr);
2428 		}
2429 	}
2430 }
2431 
2432 
2433 /*
2434  * Set selection for all elements in the widget's
2435  * start to end list.
2436  */
2437 static void
SetSelection(hw)2438 SetSelection(hw)
2439 	HTMLWidget hw;
2440 {
2441 	struct ele_rec *start;
2442 	struct ele_rec *end;
2443 	int start_pos, end_pos;
2444 
2445 	start = hw->html.select_start;
2446 	end = hw->html.select_end;
2447 	start_pos = hw->html.sel_start_pos;
2448 	end_pos = hw->html.sel_end_pos;
2449 	DrawSelection(hw, start, end, start_pos, end_pos);
2450 }
2451 
2452 
2453 /*
2454  * Erase the selection from start to end
2455  */
2456 static void
EraseSelection(hw,start,end,start_pos,end_pos)2457 EraseSelection(hw, start, end, start_pos, end_pos)
2458 	HTMLWidget hw;
2459 	struct ele_rec *start;
2460 	struct ele_rec *end;
2461 	int start_pos, end_pos;
2462 {
2463 	struct ele_rec *eptr;
2464 	int epos;
2465 
2466 	if ((start == NULL)||(end == NULL))
2467 	{
2468 		return;
2469 	}
2470 
2471 	/*
2472 	 * Keep positoins within bounds (allows us to be sloppy elsewhere)
2473 	 */
2474 	if (start_pos < 0)
2475 	{
2476 		start_pos = 0;
2477 	}
2478 	if (start_pos >= start->edata_len - 1)
2479 	{
2480 		start_pos = start->edata_len - 2;
2481 	}
2482 	if (end_pos < 0)
2483 	{
2484 		end_pos = 0;
2485 	}
2486 	if (end_pos >= end->edata_len - 1)
2487 	{
2488 		end_pos = end->edata_len - 2;
2489 	}
2490 
2491 	if (SwapElements(start, end, start_pos, end_pos))
2492 	{
2493 		eptr = start;
2494 		start = end;
2495 		end = eptr;
2496 		epos = start_pos;
2497 		start_pos = end_pos;
2498 		end_pos = epos;
2499 	}
2500 
2501 	eptr = start;
2502 	while ((eptr != NULL)&&(eptr != end))
2503 	{
2504 		int p1, p2;
2505 
2506 		if (eptr == start)
2507 		{
2508 			p1 = start_pos;
2509 		}
2510 		else
2511 		{
2512 			p1 = 0;
2513 		}
2514 		p2 = eptr->edata_len - 2;
2515 
2516 		if (eptr->type == E_TEXT)
2517 		{
2518 			eptr->selected = False;
2519 			TextRefresh(hw, eptr, p1, p2);
2520 		}
2521 		else if (eptr->type == E_LINEFEED)
2522 		{
2523 			eptr->selected = False;
2524 			LinefeedRefresh(hw, eptr);
2525 		}
2526 		eptr = eptr->next;
2527 	}
2528 	if (eptr != NULL)
2529 	{
2530 		int p1, p2;
2531 
2532 		if (eptr == start)
2533 		{
2534 			p1 = start_pos;
2535 		}
2536 		else
2537 		{
2538 			p1 = 0;
2539 		}
2540 
2541 		if (eptr == end)
2542 		{
2543 			p2 = end_pos;
2544 		}
2545 		else
2546 		{
2547 			p2 = eptr->edata_len - 2;
2548 		}
2549 
2550 		if (eptr->type == E_TEXT)
2551 		{
2552 			eptr->selected = False;
2553 			TextRefresh(hw, eptr, p1, p2);
2554 		}
2555 		else if (eptr->type == E_LINEFEED)
2556 		{
2557 			eptr->selected = False;
2558 			LinefeedRefresh(hw, eptr);
2559 		}
2560 	}
2561 }
2562 
2563 
2564 /*
2565  * Clear the current selection (if there is one)
2566  */
2567 static void
ClearSelection(hw)2568 ClearSelection(hw)
2569 	HTMLWidget hw;
2570 {
2571 	struct ele_rec *start;
2572 	struct ele_rec *end;
2573 	int start_pos, end_pos;
2574 
2575 	start = hw->html.select_start;
2576 	end = hw->html.select_end;
2577 	start_pos = hw->html.sel_start_pos;
2578 	end_pos = hw->html.sel_end_pos;
2579 	EraseSelection(hw, start, end, start_pos, end_pos);
2580 
2581 	if ((start == NULL)||(end == NULL))
2582 	{
2583 		hw->html.select_start = NULL;
2584 		hw->html.select_end = NULL;
2585 		hw->html.sel_start_pos = 0;
2586 		hw->html.sel_end_pos = 0;
2587 		hw->html.active_anchor = NULL;
2588 		return;
2589 	}
2590 
2591 	hw->html.select_start = NULL;
2592 	hw->html.select_end = NULL;
2593 	hw->html.sel_start_pos = 0;
2594 	hw->html.sel_end_pos = 0;
2595 	hw->html.active_anchor = NULL;
2596 }
2597 
2598 
2599 /*
2600  * clear from active all elements in the widget that are part of the anchor.
2601  * (These have already been previously set into the start and end of the
2602  * selection.
2603  */
2604 static void
UnsetAnchor(hw)2605 UnsetAnchor(hw)
2606 	HTMLWidget hw;
2607 {
2608 	struct ele_rec *eptr;
2609 
2610 	/*
2611 	 * Clear any activated images
2612 	 */
2613 	eptr = hw->html.select_start;
2614 	while ((eptr != NULL)&&(eptr != hw->html.select_end))
2615 	{
2616 		if (eptr->type == E_IMAGE)
2617 		{
2618 			ImageRefresh(hw, eptr);
2619 		}
2620 		eptr = eptr->next;
2621 	}
2622 	if ((eptr != NULL)&&(eptr->type == E_IMAGE))
2623 	{
2624 		ImageRefresh(hw, eptr);
2625 	}
2626 
2627 	/*
2628 	 * Clear the activated anchor
2629 	 */
2630 	ClearSelection(hw);
2631 }
2632 
2633 
2634 /*
2635  * Erase the old selection, and draw the new one in such a way
2636  * that advantage is taken of overlap, and there is no obnoxious
2637  * flashing.
2638  */
2639 static void
ChangeSelection(hw,start,end,start_pos,end_pos)2640 ChangeSelection(hw, start, end, start_pos, end_pos)
2641 	HTMLWidget hw;
2642 	struct ele_rec *start;
2643 	struct ele_rec *end;
2644 	int start_pos, end_pos;
2645 {
2646 	struct ele_rec *old_start;
2647 	struct ele_rec *old_end;
2648 	struct ele_rec *new_start;
2649 	struct ele_rec *new_end;
2650 	struct ele_rec *eptr;
2651 	int epos;
2652 	int new_start_pos, new_end_pos;
2653 	int old_start_pos, old_end_pos;
2654 
2655 	old_start = hw->html.new_start;
2656 	old_end = hw->html.new_end;
2657 	old_start_pos = hw->html.new_start_pos;
2658 	old_end_pos = hw->html.new_end_pos;
2659 	new_start = start;
2660 	new_end = end;
2661 	new_start_pos = start_pos;
2662 	new_end_pos = end_pos;
2663 
2664 	if ((new_start == NULL)||(new_end == NULL))
2665 	{
2666 		return;
2667 	}
2668 
2669 	if ((old_start == NULL)||(old_end == NULL))
2670 	{
2671 		DrawSelection(hw, new_start, new_end,
2672 			new_start_pos, new_end_pos);
2673 		return;
2674 	}
2675 
2676 	if (SwapElements(old_start, old_end, old_start_pos, old_end_pos))
2677 	{
2678 		eptr = old_start;
2679 		old_start = old_end;
2680 		old_end = eptr;
2681 		epos = old_start_pos;
2682 		old_start_pos = old_end_pos;
2683 		old_end_pos = epos;
2684 	}
2685 
2686 	if (SwapElements(new_start, new_end, new_start_pos, new_end_pos))
2687 	{
2688 		eptr = new_start;
2689 		new_start = new_end;
2690 		new_end = eptr;
2691 		epos = new_start_pos;
2692 		new_start_pos = new_end_pos;
2693 		new_end_pos = epos;
2694 	}
2695 
2696 	/*
2697 	 * Deal with all possible intersections of the 2 selection sets.
2698 	 *
2699 	 ********************************************************
2700 	 *			*				*
2701 	 *      |--		*	     |--		*
2702 	 * old--|		*	new--|			*
2703 	 *      |--		*	     |--		*
2704 	 *			*				*
2705 	 *      |--		*	     |--		*
2706 	 * new--|		*	old--|			*
2707 	 *      |--		*	     |--		*
2708 	 *			*				*
2709 	 ********************************************************
2710 	 *			*				*
2711 	 *      |----		*	       |--		*
2712 	 * old--|		*	  new--|		*
2713 	 *      | |--		*	       |		*
2714 	 *      |-+--		*	     |-+--		*
2715 	 *        |		*	     | |--		*
2716 	 *   new--|		*	old--|			*
2717 	 *        |--		*	     |----		*
2718 	 *			*				*
2719 	 ********************************************************
2720 	 *			*				*
2721 	 *      |---------	*	     |---------		*
2722 	 *      |		*	     |			*
2723 	 *      |      |--	*	     |      |--		*
2724 	 * new--| old--|	*	old--| new--|		*
2725 	 *      |      |--	*	     |      |--		*
2726 	 *      |		*	     |			*
2727 	 *      |---------	*	     |---------		*
2728 	 *			*				*
2729 	 ********************************************************
2730 	 *
2731 	 */
2732 	if ((ElementLessThan(old_end, new_start, old_end_pos, new_start_pos))||
2733 	    (ElementLessThan(new_end, old_start, new_end_pos, old_start_pos)))
2734 	{
2735 		EraseSelection(hw, old_start, old_end,
2736 			old_start_pos, old_end_pos);
2737 		DrawSelection(hw, new_start, new_end,
2738 			new_start_pos, new_end_pos);
2739 	}
2740 	else if ((ElementLessThan(old_start, new_start,
2741 			old_start_pos, new_start_pos))&&
2742 		 (ElementLessThan(old_end, new_end, old_end_pos, new_end_pos)))
2743 	{
2744 		if (new_start_pos != 0)
2745 		{
2746 			EraseSelection(hw, old_start, new_start,
2747 				old_start_pos, new_start_pos - 1);
2748 		}
2749 		else
2750 		{
2751 			EraseSelection(hw, old_start, new_start->prev,
2752 				old_start_pos, new_start->prev->edata_len - 2);
2753 		}
2754 		if (old_end_pos < (old_end->edata_len - 2))
2755 		{
2756 			DrawSelection(hw, old_end, new_end,
2757 				old_end_pos + 1, new_end_pos);
2758 		}
2759 		else
2760 		{
2761 			DrawSelection(hw, old_end->next, new_end,
2762 				0, new_end_pos);
2763 		}
2764 	}
2765 	else if ((ElementLessThan(new_start, old_start,
2766 			new_start_pos, old_start_pos))&&
2767 		 (ElementLessThan(new_end, old_end, new_end_pos, old_end_pos)))
2768 	{
2769 		if (old_start_pos != 0)
2770 		{
2771 			DrawSelection(hw, new_start, old_start,
2772 				new_start_pos, old_start_pos - 1);
2773 		}
2774 		else
2775 		{
2776 			DrawSelection(hw, new_start, old_start->prev,
2777 				new_start_pos, old_start->prev->edata_len - 2);
2778 		}
2779 		if (new_end_pos < (new_end->edata_len - 2))
2780 		{
2781 			EraseSelection(hw, new_end, old_end,
2782 				new_end_pos + 1, old_end_pos);
2783 		}
2784 		else
2785 		{
2786 			EraseSelection(hw, new_end->next, old_end,
2787 				0, old_end_pos);
2788 		}
2789 	}
2790 	else if ((ElementLessThan(new_start, old_start,
2791 			new_start_pos, old_start_pos))||
2792 		 (ElementLessThan(old_end, new_end, old_end_pos, new_end_pos)))
2793 	{
2794 		if ((new_start != old_start)||(new_start_pos != old_start_pos))
2795 		{
2796 			if (old_start_pos != 0)
2797 			{
2798 				DrawSelection(hw, new_start, old_start,
2799 					new_start_pos, old_start_pos - 1);
2800 			}
2801 			else
2802 			{
2803 				DrawSelection(hw, new_start, old_start->prev,
2804 					new_start_pos,
2805 					old_start->prev->edata_len - 2);
2806 			}
2807 		}
2808 		if ((old_end != new_end)||(old_end_pos != new_end_pos))
2809 		{
2810 			if (old_end_pos < (old_end->edata_len - 2))
2811 			{
2812 				DrawSelection(hw, old_end, new_end,
2813 					old_end_pos + 1, new_end_pos);
2814 			}
2815 			else
2816 			{
2817 				DrawSelection(hw, old_end->next, new_end,
2818 					0, new_end_pos);
2819 			}
2820 		}
2821 	}
2822 	else
2823 	{
2824 		if ((old_start != new_start)||(old_start_pos != new_start_pos))
2825 		{
2826 			if (new_start_pos != 0)
2827 			{
2828 				EraseSelection(hw, old_start, new_start,
2829 					old_start_pos, new_start_pos - 1);
2830 			}
2831 			else
2832 			{
2833 				EraseSelection(hw, old_start, new_start->prev,
2834 					old_start_pos,
2835 					new_start->prev->edata_len - 2);
2836 			}
2837 		}
2838 		if ((new_end != old_end)||(new_end_pos != old_end_pos))
2839 		{
2840 			if (new_end_pos < (new_end->edata_len - 2))
2841 			{
2842 				EraseSelection(hw, new_end, old_end,
2843 					new_end_pos + 1, old_end_pos);
2844 			}
2845 			else
2846 			{
2847 				EraseSelection(hw, new_end->next, old_end,
2848 					0, old_end_pos);
2849 			}
2850 		}
2851 	}
2852 }
2853 
2854 
2855 static void
SelectStart(w,event,params,num_params)2856 SelectStart(w, event, params, num_params)
2857 	Widget w;
2858 	XEvent *event;
2859 	String *params;         /* unused */
2860 	Cardinal *num_params;   /* unused */
2861 {
2862 	HTMLWidget hw = (HTMLWidget)XtParent(w);
2863 	XButtonPressedEvent *BuEvent = (XButtonPressedEvent *)event;
2864 	struct ele_rec *eptr;
2865 	int epos;
2866 
2867 	if (XtClass(XtParent(w)) != htmlWidgetClass)
2868 	{
2869 		return;
2870 	}
2871 
2872 #ifdef NOT_RIGHT
2873         XUndefineCursor(XtDisplay(hw->html.view), XtWindow(hw->html.view));
2874 #endif
2875         XUndefineCursor(XtDisplay(hw), XtWindow(hw));
2876 
2877 	/*
2878 	 * Because X sucks, we can get the button pressed in the window, but
2879 	 * released out of the window.  This will highlight some text, but
2880 	 * never complete the selection.  Now on the next button press we
2881 	 * have to clean up this mess.
2882 	 */
2883 	EraseSelection(hw, hw->html.new_start, hw->html.new_end,
2884 		hw->html.new_start_pos, hw->html.new_end_pos);
2885 
2886 	/*
2887 	 * We want to erase the currently selected text, but still save the
2888 	 * selection internally in case we don't create a new one.
2889 	 */
2890 	EraseSelection(hw, hw->html.select_start, hw->html.select_end,
2891 		hw->html.sel_start_pos, hw->html.sel_end_pos);
2892 	hw->html.new_start = hw->html.select_start;
2893 	hw->html.new_end = NULL;
2894 	hw->html.new_start_pos = hw->html.sel_start_pos;
2895 	hw->html.new_end_pos = 0;
2896 
2897 	eptr = LocateElement(hw, BuEvent->x, BuEvent->y, &epos);
2898 	if (eptr != NULL)
2899 	{
2900 		/*
2901 		 * If this is an anchor assume for now we are activating it
2902 		 * and not selecting it.
2903 		 */
2904 		if (eptr->anchorHRef != NULL)
2905 		{
2906 			hw->html.active_anchor = eptr;
2907 			hw->html.press_x = BuEvent->x;
2908 			hw->html.press_y = BuEvent->y;
2909 			SetAnchor(hw);
2910 		}
2911 		/*
2912 		 * Else if we are on an image we can't select text so
2913 		 * pretend we got eptr==NULL, and exit here.
2914 		 */
2915 		else if (eptr->type == E_IMAGE)
2916 		{
2917 			hw->html.new_start = NULL;
2918 			hw->html.new_end = NULL;
2919 			hw->html.new_start_pos = 0;
2920 			hw->html.new_end_pos = 0;
2921 			hw->html.press_x = BuEvent->x;
2922 			hw->html.press_y = BuEvent->y;
2923 			hw->html.but_press_time = BuEvent->time;
2924 			return;
2925 		}
2926 		/*
2927 		 * Else if we used button2, we can't select text, so exit
2928 		 * here.
2929 		 */
2930 		else if (BuEvent->button == Button2)
2931 		{
2932 			hw->html.press_x = BuEvent->x;
2933 			hw->html.press_y = BuEvent->y;
2934 			hw->html.but_press_time = BuEvent->time;
2935 			return;
2936 		}
2937 		/*
2938 		 * Else a single click will not select a new object
2939 		 * but it will prime that selection on the next mouse
2940 		 * move.
2941 		 * Ignore special internal text
2942 		 */
2943 		else if (eptr->internal == False)
2944 		{
2945 			hw->html.new_start = eptr;
2946 			hw->html.new_start_pos = epos;
2947 			hw->html.new_end = NULL;
2948 			hw->html.new_end_pos = 0;
2949 			hw->html.press_x = BuEvent->x;
2950 			hw->html.press_y = BuEvent->y;
2951 		}
2952 		else
2953 		{
2954 			hw->html.new_start = NULL;
2955 			hw->html.new_end = NULL;
2956 			hw->html.new_start_pos = 0;
2957 			hw->html.new_end_pos = 0;
2958 			hw->html.press_x = BuEvent->x;
2959 			hw->html.press_y = BuEvent->y;
2960 		}
2961 	}
2962 	else
2963 	{
2964 		hw->html.new_start = NULL;
2965 		hw->html.new_end = NULL;
2966 		hw->html.new_start_pos = 0;
2967 		hw->html.new_end_pos = 0;
2968 		hw->html.press_x = BuEvent->x;
2969 		hw->html.press_y = BuEvent->y;
2970 	}
2971 	hw->html.but_press_time = BuEvent->time;
2972 }
2973 
2974 
2975 static void
ExtendStart(w,event,params,num_params)2976 ExtendStart(w, event, params, num_params)
2977 	Widget w;
2978 	XEvent *event;
2979 	String *params;         /* unused */
2980 	Cardinal *num_params;   /* unused */
2981 {
2982 	HTMLWidget hw = (HTMLWidget)XtParent(w);
2983 	XButtonPressedEvent *BuEvent = (XButtonPressedEvent *)event;
2984 	struct ele_rec *eptr;
2985 	struct ele_rec *start, *end;
2986 	struct ele_rec *old_start, *old_end;
2987 	int old_start_pos, old_end_pos;
2988 	int start_pos, end_pos;
2989 	int epos;
2990 
2991 	if (XtClass(XtParent(w)) != htmlWidgetClass)
2992 	{
2993 		return;
2994 	}
2995 
2996 	eptr = LocateElement(hw, BuEvent->x, BuEvent->y, &epos);
2997 
2998 	/*
2999 	 * Ignore IMAGE elements.
3000 	 */
3001 	if ((eptr != NULL)&&(eptr->type == E_IMAGE))
3002 	{
3003 		eptr = NULL;
3004 	}
3005 
3006 	/*
3007 	 * Ignore NULL elements.
3008 	 * Ignore special internal text
3009 	 * documents.
3010 	 */
3011 	if ((eptr != NULL)&&(eptr->internal == False))
3012 	{
3013 		old_start = hw->html.new_start;
3014 		old_start_pos = hw->html.new_start_pos;
3015 		old_end = hw->html.new_end;
3016 		old_end_pos = hw->html.new_end_pos;
3017 		if (hw->html.new_start == NULL)
3018 		{
3019 			hw->html.new_start = hw->html.select_start;
3020 			hw->html.new_start_pos = hw->html.sel_start_pos;
3021 			hw->html.new_end = hw->html.select_end;
3022 			hw->html.new_end_pos = hw->html.sel_end_pos;
3023 		}
3024 		else
3025 		{
3026 			hw->html.new_end = eptr;
3027 			hw->html.new_end_pos = epos;
3028 		}
3029 
3030 		if (SwapElements(hw->html.new_start, hw->html.new_end,
3031 			hw->html.new_start_pos, hw->html.new_end_pos))
3032 		{
3033 			if (SwapElements(eptr, hw->html.new_end,
3034 				epos, hw->html.new_end_pos))
3035 			{
3036 				start = hw->html.new_end;
3037 				start_pos = hw->html.new_end_pos;
3038 				end = eptr;
3039 				end_pos = epos;
3040 			}
3041 			else
3042 			{
3043 				start = hw->html.new_start;
3044 				start_pos = hw->html.new_start_pos;
3045 				end = eptr;
3046 				end_pos = epos;
3047 			}
3048 		}
3049 		else
3050 		{
3051 			if (SwapElements(eptr, hw->html.new_start,
3052 				epos, hw->html.new_start_pos))
3053 			{
3054 				start = hw->html.new_start;
3055 				start_pos = hw->html.new_start_pos;
3056 				end = eptr;
3057 				end_pos = epos;
3058 			}
3059 			else
3060 			{
3061 				start = hw->html.new_end;
3062 				start_pos = hw->html.new_end_pos;
3063 				end = eptr;
3064 				end_pos = epos;
3065 			}
3066 		}
3067 
3068 		if (start == NULL)
3069 		{
3070 			start = eptr;
3071 			start_pos = epos;
3072 		}
3073 
3074 		if (old_start == NULL)
3075 		{
3076 			hw->html.new_start = hw->html.select_start;
3077 			hw->html.new_end = hw->html.select_end;
3078 			hw->html.new_start_pos = hw->html.sel_start_pos;
3079 			hw->html.new_end_pos = hw->html.sel_end_pos;
3080 		}
3081 		else
3082 		{
3083 			hw->html.new_start = old_start;
3084 			hw->html.new_end = old_end;
3085 			hw->html.new_start_pos = old_start_pos;
3086 			hw->html.new_end_pos = old_end_pos;
3087 		}
3088 		ChangeSelection(hw, start, end, start_pos, end_pos);
3089 		hw->html.new_start = start;
3090 		hw->html.new_end = end;
3091 		hw->html.new_start_pos = start_pos;
3092 		hw->html.new_end_pos = end_pos;
3093 	}
3094 	else
3095 	{
3096 		if (hw->html.new_start == NULL)
3097 		{
3098 			hw->html.new_start = hw->html.select_start;
3099 			hw->html.new_start_pos = hw->html.sel_start_pos;
3100 			hw->html.new_end = hw->html.select_end;
3101 			hw->html.new_end_pos = hw->html.sel_end_pos;
3102 		}
3103 	}
3104 	hw->html.press_x = BuEvent->x;
3105 	hw->html.press_y = BuEvent->y;
3106 }
3107 
3108 
3109 static void
ExtendAdjust(w,event,params,num_params)3110 ExtendAdjust(w, event, params, num_params)
3111 	Widget w;
3112 	XEvent *event;
3113 	String *params;         /* unused */
3114 	Cardinal *num_params;   /* unused */
3115 {
3116 	HTMLWidget hw = (HTMLWidget)XtParent(w);
3117 	XPointerMovedEvent *MoEvent = (XPointerMovedEvent *)event;
3118 	struct ele_rec *eptr;
3119 	struct ele_rec *start, *end;
3120 	int start_pos, end_pos;
3121 	int epos;
3122 
3123 	if (XtClass(XtParent(w)) != htmlWidgetClass)
3124 	{
3125 		return;
3126 	}
3127 
3128 	/*
3129 	 * Very small mouse motion immediately after button press
3130 	 * is ignored.
3131 	 */
3132 	if ((ABS((hw->html.press_x - MoEvent->x)) <= SELECT_THRESHOLD)&&
3133 	    (ABS((hw->html.press_y - MoEvent->y)) <= SELECT_THRESHOLD))
3134 	{
3135 		return;
3136 	}
3137 
3138 	/*
3139 	 * If we have an active anchor and we got here, we have moved the
3140 	 * mouse too far.  Deactivate anchor, and prime a selection.
3141 	 * If the anchor is internal text, don't
3142 	 * prime a selection.
3143 	 */
3144 	if (hw->html.active_anchor != NULL)
3145 	{
3146 		eptr = hw->html.active_anchor;
3147 		UnsetAnchor(hw);
3148 		if (eptr->internal == False)
3149 		{
3150 			hw->html.new_start = NULL;
3151 			hw->html.new_start_pos = 0;
3152 			hw->html.new_end = NULL;
3153 			hw->html.new_end_pos = 0;
3154 		}
3155 	}
3156 
3157 	/*
3158 	 * If we used button2, we can't select text, so
3159 	 * clear selection and exit here.
3160 	 */
3161 	if ((MoEvent->state & Button2Mask) != 0)
3162 	{
3163 		hw->html.select_start = NULL;
3164 		hw->html.select_end = NULL;
3165 		hw->html.sel_start_pos = 0;
3166 		hw->html.sel_end_pos = 0;
3167 		hw->html.new_start = NULL;
3168 		hw->html.new_end = NULL;
3169 		hw->html.new_start_pos = 0;
3170 		hw->html.new_end_pos = 0;
3171 		return;
3172 	}
3173 
3174 	eptr = LocateElement(hw, MoEvent->x, MoEvent->y, &epos);
3175 
3176 	/*
3177 	 * If we are on an image pretend we are nowhere
3178 	 * and just return;
3179 	 */
3180 	if ((eptr != NULL)&&(eptr->type == E_IMAGE))
3181 	{
3182 		return;
3183 	}
3184 
3185 	/*
3186 	 * Ignore NULL items.
3187 	 * Ignore if the same as last selected item and position.
3188 	 * Ignore special internal text
3189 	 */
3190 	if ((eptr != NULL)&&
3191 	    ((eptr != hw->html.new_end)||(epos != hw->html.new_end_pos))&&
3192 	    (eptr->internal == False))
3193 	{
3194 		start = hw->html.new_start;
3195 		start_pos = hw->html.new_start_pos;
3196 		end = eptr;
3197 		end_pos = epos;
3198 		if (start == NULL)
3199 		{
3200 			start = eptr;
3201 			start_pos = epos;
3202 		}
3203 
3204 		ChangeSelection(hw, start, end, start_pos, end_pos);
3205 		hw->html.new_start = start;
3206 		hw->html.new_end = end;
3207 		hw->html.new_start_pos = start_pos;
3208 		hw->html.new_end_pos = end_pos;
3209 	}
3210 }
3211 
3212 
3213 static void
ExtendEnd(w,event,params,num_params)3214 ExtendEnd(w, event, params, num_params)
3215 	Widget w;
3216 	XEvent *event;
3217 	String *params;
3218 	Cardinal *num_params;
3219 {
3220 	HTMLWidget hw = (HTMLWidget)XtParent(w);
3221 	XButtonReleasedEvent *BuEvent = (XButtonReleasedEvent *)event;
3222 	struct ele_rec *eptr;
3223 	struct ele_rec *start, *end;
3224 	Atom *atoms;
3225 	int i, buffer;
3226 	int start_pos, end_pos;
3227 	int epos;
3228 	char *text;
3229 
3230 	if (XtClass(XtParent(w)) != htmlWidgetClass)
3231 	{
3232 		return;
3233 	}
3234 
3235 	eptr = LocateElement(hw, BuEvent->x, BuEvent->y, &epos);
3236 
3237 	/*
3238 	 * If we just released button one or two, and we are on an object,
3239 	 * and we have an active anchor, and we are on the active anchor,
3240 	 * and if we havn't waited too long.  Activate that anchor.
3241 	 */
3242 	if (((BuEvent->button == Button1)||(BuEvent->button == Button2))&&
3243 		(eptr != NULL)&&
3244 		(hw->html.active_anchor != NULL)&&
3245 		(eptr == hw->html.active_anchor)&&
3246 		((BuEvent->time - hw->html.but_press_time) < CLICK_TIME))
3247 	{
3248 		_HTMLInput(w, event, params, num_params);
3249 		return;
3250 	}
3251 	else if (hw->html.active_anchor != NULL)
3252 	{
3253 		start = hw->html.active_anchor;
3254 		UnsetAnchor(hw);
3255 		if (start->internal == False)
3256 		{
3257 			hw->html.new_start = eptr;
3258 			hw->html.new_start_pos = epos;
3259 			hw->html.new_end = NULL;
3260 			hw->html.new_end_pos = 0;
3261 		}
3262 	}
3263 
3264 	/*
3265 	 * If we used button2, we can't select text, so clear
3266 	 * selection and exit here.
3267 	 */
3268 	if (BuEvent->button == Button2)
3269 	{
3270 		hw->html.new_start = hw->html.select_start;
3271 		hw->html.new_end = NULL;
3272 		hw->html.new_start_pos = hw->html.sel_start_pos;
3273 		hw->html.new_end_pos = 0;
3274 		return;
3275 	}
3276 
3277 	/*
3278 	 * If we are on an image, pretend we are nowhere
3279 	 * and NULL out the eptr
3280 	 */
3281 	if ((eptr != NULL)&&(eptr->type == E_IMAGE))
3282 	{
3283 		eptr = NULL;
3284 	}
3285 
3286 	/*
3287 	 * If button released on a NULL item, take the last non-NULL
3288 	 * item that we highlighted.
3289 	 */
3290 	if ((eptr == NULL)&&(hw->html.new_end != NULL))
3291 	{
3292 		eptr = hw->html.new_end;
3293 		epos = hw->html.new_end_pos;
3294 	}
3295 
3296 	if ((eptr != NULL)&&(eptr->internal == False)&&
3297 		(hw->html.new_end != NULL))
3298 	{
3299 		start = hw->html.new_start;
3300 		start_pos = hw->html.new_start_pos;
3301 		end = eptr;
3302 		end_pos = epos;
3303 		if (start == NULL)
3304 		{
3305 			start = eptr;
3306 			start_pos = epos;
3307 		}
3308 		ChangeSelection(hw, start, end, start_pos, end_pos);
3309 		hw->html.select_start = start;
3310 		hw->html.sel_start_pos = start_pos;
3311 		hw->html.select_end = end;
3312 		hw->html.sel_end_pos = end_pos;
3313 		SetSelection(hw);
3314 		hw->html.new_start = NULL;
3315 		hw->html.new_end = NULL;
3316 		hw->html.new_start_pos = 0;
3317 		hw->html.new_end_pos = 0;
3318 
3319 		atoms = (Atom *)malloc(*num_params * sizeof(Atom));
3320 		if (atoms == NULL)
3321 		{
3322 			fprintf(stderr, "cannot allocate atom list\n");
3323 			return;
3324 		}
3325 		XmuInternStrings(XtDisplay((Widget)hw), params, *num_params, atoms);
3326 		hw->html.selection_time = BuEvent->time;
3327 		for (i=0; i< *num_params; i++)
3328 		{
3329 			switch (atoms[i])
3330 			{
3331 				case XA_CUT_BUFFER0: buffer = 0; break;
3332 				case XA_CUT_BUFFER1: buffer = 1; break;
3333 				case XA_CUT_BUFFER2: buffer = 2; break;
3334 				case XA_CUT_BUFFER3: buffer = 3; break;
3335 				case XA_CUT_BUFFER4: buffer = 4; break;
3336 				case XA_CUT_BUFFER5: buffer = 5; break;
3337 				case XA_CUT_BUFFER6: buffer = 6; break;
3338 				case XA_CUT_BUFFER7: buffer = 7; break;
3339 				default: buffer = -1; break;
3340 			}
3341 			if (buffer >= 0)
3342 			{
3343 				if (hw->html.fancy_selections == True)
3344 				{
3345 				    text = ParseTextToPrettyString(hw,
3346 					hw->html.formatted_elements,
3347 					hw->html.select_start,
3348 					hw->html.select_end,
3349 					hw->html.sel_start_pos,
3350 					hw->html.sel_end_pos,
3351 					hw->html.font->max_bounds.width,
3352 					hw->html.margin_width);
3353 				}
3354 				else
3355 				{
3356 				    text = ParseTextToString(
3357 					hw->html.formatted_elements,
3358 					hw->html.select_start,
3359 					hw->html.select_end,
3360 					hw->html.sel_start_pos,
3361 					hw->html.sel_end_pos,
3362 					hw->html.font->max_bounds.width,
3363 					hw->html.margin_width);
3364 				}
3365 				XStoreBuffer(XtDisplay((Widget)hw),
3366 					text, strlen(text), buffer);
3367 				if (text != NULL)
3368 				{
3369 					free(text);
3370 				}
3371 			}
3372 			else
3373 			{
3374 				XtOwnSelection((Widget)hw, atoms[i],
3375 					       BuEvent->time,
3376 					       (XtConvertSelectionProc )ConvertSelection,
3377 					       (XtLoseSelectionProc )LoseSelection,
3378 					       (XtSelectionDoneProc )SelectionDone);
3379 			}
3380 		}
3381 		free((char *)atoms);
3382 	}
3383 	else if (eptr == NULL)
3384 	{
3385 		hw->html.select_start = NULL;
3386 		hw->html.sel_start_pos = 0;
3387 		hw->html.select_end = NULL;
3388 		hw->html.sel_end_pos = 0;
3389 		hw->html.new_start = NULL;
3390 		hw->html.new_start_pos = 0;
3391 		hw->html.new_end = NULL;
3392 		hw->html.new_end_pos = 0;
3393 	}
3394 }
3395 
3396 
3397 #define LEAVING_ANCHOR(hw) \
3398   hw->html.cached_tracked_ele = NULL; \
3399   (*(pointerTrackProc) \
3400     (hw->html.pointer_motion_callback))(hw, ""); \
3401   XUndefineCursor (XtDisplay (hw), XtWindow (hw));
3402 
3403 /* KNOWN PROBLEM: We never get LeaveNotify or FocusOut events,
3404    despite the fact we've requested them.  Bummer. */
3405 static void
TrackMotion(w,event,params,num_params)3406 TrackMotion(w, event, params, num_params)
3407 	Widget w;
3408 	XEvent *event;
3409 	String *params;         /* unused */
3410 	Cardinal *num_params;   /* unused */
3411 {
3412 	HTMLWidget hw = (HTMLWidget)XtParent(w);
3413 	struct ele_rec *eptr;
3414 	int epos, x, y;
3415 
3416 	if (XtClass(XtParent(w)) != htmlWidgetClass)
3417 	{
3418 		return;
3419 	}
3420 
3421         if (!hw->html.pointer_motion_callback)
3422           return;
3423 
3424         if (event->type == MotionNotify)
3425           {
3426             x = ((XMotionEvent *)event)->x;
3427             y = ((XMotionEvent *)event)->y;
3428           }
3429         else if (event->type == LeaveNotify || event->type == FocusOut ||
3430                  event->type == Expose)
3431           {
3432             /* Wipe out. */
3433             if (hw->html.cached_tracked_ele)
3434               {
3435                 LEAVING_ANCHOR (hw);
3436               }
3437             return;
3438           }
3439         else
3440           {
3441             return;
3442           }
3443 
3444 	eptr = LocateElement(hw, x, y, &epos);
3445 
3446         /* We're hitting a new anchor if eptr exists and
3447            eptr != cached tracked element and anchorHRef != NULL. */
3448 	if (eptr != NULL && eptr != hw->html.cached_tracked_ele &&
3449             eptr->anchorHRef != NULL)
3450           {
3451             hw->html.cached_tracked_ele = eptr;
3452 	    (*(pointerTrackProc)
3453              (hw->html.pointer_motion_callback))(hw, eptr->anchorHRef);
3454             XDefineCursor (XtDisplay (hw), XtWindow (hw), in_anchor_cursor);
3455           }
3456         /* We're leaving an anchor if eptr exists and
3457            a cached ele exists and we're not entering a new anchor. */
3458         else if (eptr != NULL && hw->html.cached_tracked_ele != NULL &&
3459                  eptr->anchorHRef == NULL)
3460           {
3461             LEAVING_ANCHOR (hw);
3462           }
3463 
3464         return;
3465 }
3466 
3467 
3468 /*
3469  * Process mouse input to the HTML widget
3470  * Currently only processes an anchor-activate when Button1
3471  * is pressed
3472  */
3473 static void
3474 #ifdef _NO_PROTO
_HTMLInput(w,event,params,num_params)3475 _HTMLInput( w, event, params, num_params)
3476 	Widget w ;
3477 	XEvent *event ;
3478 	String *params;		/* unused */
3479 	Cardinal *num_params;	/* unused */
3480 #else
3481 _HTMLInput(
3482 	Widget w,
3483 	XEvent *event,
3484 	String *params,		/* unused */
3485 	Cardinal *num_params)	/* unused */
3486 #endif
3487 {
3488 	HTMLWidget hw = (HTMLWidget)XtParent(w);
3489 	struct ele_rec *eptr;
3490 	WbAnchorCallbackData cbdata;
3491 	int epos;
3492 #ifdef MOTIF
3493 	Boolean on_gadget;
3494 #endif /* MOTIF */
3495 
3496 	if (XtClass(XtParent(w)) != htmlWidgetClass)
3497 	{
3498 		return;
3499 	}
3500 
3501 #ifdef MOTIF
3502 	/*
3503 	 * If motif is defined, we don't want to process this button press
3504 	 * if it is on a gadget
3505 	 */
3506 #ifdef MOTIF1_2
3507 	on_gadget = (_XmInputForGadget((Widget)hw,
3508 #else
3509 	on_gadget = (_XmInputForGadget((CompositeWidget)hw,
3510 #endif /* MOTIF1_2 */
3511 				event->xbutton.x, event->xbutton.y) != NULL);
3512 
3513 	if (on_gadget)
3514 	{
3515 		return;
3516 	}
3517 #endif /* MOTIF */
3518 
3519 	if (event->type == ButtonRelease)
3520 	{
3521 		eptr = LocateElement(hw, event->xbutton.x, event->xbutton.y,
3522 				&epos);
3523 		if (eptr != NULL)
3524 		{
3525 			if (eptr->anchorHRef != NULL)
3526 			{
3527 			    char *tptr, *ptr;
3528 
3529 			   /*
3530 			    * Save the anchor text, replace newlines with
3531 			    * spaces.
3532 			    */
3533 			    tptr = ParseTextToString(hw->html.select_start,
3534 				hw->html.select_start, hw->html.select_end,
3535 				hw->html.sel_start_pos, hw->html.sel_end_pos,
3536 				hw->html.font->max_bounds.width,
3537 				hw->html.margin_width);
3538 			    ptr = tptr;
3539 			    while ((ptr != NULL)&&(*ptr != '\0'))
3540 			    {
3541 				if (*ptr == '\n')
3542 				{
3543 					*ptr = ' ';
3544 				}
3545 				ptr++;
3546 			    }
3547 
3548 			   /*
3549 			    * Clear the activated anchor
3550 			    */
3551 			    UnsetAnchor(hw);
3552 #ifdef EXTRA_FLUSH
3553 			    XFlush(XtDisplay(hw));
3554 #endif
3555 
3556 			    if ((IsDelayedHRef(hw, eptr->anchorHRef))&&
3557 				(hw->html.resolveDelayedImage != NULL))
3558 			    {
3559 				eptr->pic_data = (*(resolveImageProc)
3560 				    (hw->html.resolveDelayedImage))(hw, eptr->edata);
3561 
3562 				if (eptr->pic_data == NULL)
3563 				{
3564 					eptr->pic_data = NoImageData(hw);
3565 					eptr->pic_data->delayed = 0;
3566 					eptr->pic_data->internal = 0;
3567 				}
3568 				else
3569 				{
3570 					eptr->pic_data->delayed = 0;
3571 					/*
3572 					 * Mark images we have sucessfully
3573 					 * loaded at least once
3574 					 */
3575 					if (eptr->pic_data->image_data != NULL)
3576 					{
3577 					    eptr->pic_data->fetched = 1;
3578 					}
3579 					/*
3580 					 * See if this is a special
3581 					 * internal image
3582 					 */
3583 					if ((eptr->edata != NULL)&&
3584 						(strncmp(eptr->edata,
3585 						INTERNAL_IMAGE,
3586 						strlen(INTERNAL_IMAGE)) == 0))
3587 					{
3588 					    eptr->pic_data->internal = 1;
3589 					}
3590 					else
3591 					{
3592 					    eptr->pic_data->internal = 0;
3593 					}
3594 				}
3595 
3596 				ReformatWindow(hw);
3597 				ScrollWidgets(hw);
3598 				ViewClearAndRefresh(hw);
3599 			    }
3600 			    else if ((eptr->pic_data != NULL)&&
3601 				(eptr->pic_data->delayed)&&
3602 				(eptr->anchorHRef != NULL)&&
3603 				(IsIsMapForm(hw, eptr->anchorHRef)))
3604 			    {
3605 				eptr->pic_data = (*(resolveImageProc)
3606 				    (hw->html.resolveDelayedImage))(hw, eptr->edata);
3607 
3608 				if (eptr->pic_data == NULL)
3609 				{
3610 					eptr->pic_data = NoImageData(hw);
3611 					eptr->pic_data->delayed = 0;
3612 					eptr->pic_data->internal = 0;
3613 				}
3614 				else
3615 				{
3616 					eptr->pic_data->delayed = 0;
3617 					/*
3618 					 * Mark images we have sucessfully
3619 					 * loaded at least once
3620 					 */
3621 					if (eptr->pic_data->image_data != NULL)
3622 					{
3623 					    eptr->pic_data->fetched = 1;
3624 					}
3625 					/*
3626 					 * See if this is a special
3627 					 * internal image
3628 					 */
3629 					if ((eptr->edata != NULL)&&
3630 						(strncmp(eptr->edata,
3631 						INTERNAL_IMAGE,
3632 						strlen(INTERNAL_IMAGE)) == 0))
3633 					{
3634 					    eptr->pic_data->internal = 1;
3635 					}
3636 					else
3637 					{
3638 					    eptr->pic_data->internal = 0;
3639 					}
3640 				}
3641 
3642 				ReformatWindow(hw);
3643 				ScrollWidgets(hw);
3644 				ViewClearAndRefresh(hw);
3645 			    }
3646 			    else if ((eptr->pic_data != NULL)&&
3647 				(eptr->pic_data->delayed)&&
3648 				(eptr->anchorHRef != NULL)&&
3649 				(!IsDelayedHRef(hw, eptr->anchorHRef))&&
3650 				(!IsIsMapForm(hw, eptr->anchorHRef))&&
3651 				(((event->xbutton.y + hw->html.scroll_y) -
3652 				  (eptr->y + eptr->y_offset)) >
3653 				  AnchoredHeight(hw)))
3654 			    {
3655 				eptr->pic_data = (*(resolveImageProc)
3656 				    (hw->html.resolveDelayedImage))(hw, eptr->edata);
3657 
3658 				if (eptr->pic_data == NULL)
3659 				{
3660 					eptr->pic_data = NoImageData(hw);
3661 					eptr->pic_data->delayed = 0;
3662 					eptr->pic_data->internal = 0;
3663 				}
3664 				else
3665 				{
3666 					/*
3667 					 * Mark images we have sucessfully
3668 					 * loaded at least once
3669 					 */
3670 					if (eptr->pic_data->image_data != NULL)
3671 					{
3672 					    eptr->pic_data->fetched = 1;
3673 					}
3674 					/*
3675 					 * See if this is a special
3676 					 * internal image
3677 					 */
3678 					if ((eptr->edata != NULL)&&
3679 						(strncmp(eptr->edata,
3680 						INTERNAL_IMAGE,
3681 						strlen(INTERNAL_IMAGE)) == 0))
3682 					{
3683 					    eptr->pic_data->internal = 1;
3684 					}
3685 					else
3686 					{
3687 					    eptr->pic_data->internal = 0;
3688 					}
3689 				}
3690 				eptr->pic_data->delayed = 0;
3691 
3692 				ReformatWindow(hw);
3693 				ScrollWidgets(hw);
3694 				ViewClearAndRefresh(hw);
3695 			    }
3696 			    else if ((eptr->pic_data != NULL)&&
3697 				(eptr->pic_data->ismap)&&
3698 				(eptr->anchorHRef != NULL)&&
3699 				(IsIsMapForm(hw, eptr->anchorHRef)))
3700 			    {
3701 				int form_x, form_y;
3702 
3703 				form_x = event->xbutton.x + hw->html.scroll_x -
3704 					eptr->x;
3705 				form_y = event->xbutton.y + hw->html.scroll_y -
3706 					eptr->y;
3707 				ImageSubmitForm(eptr->pic_data->fptr, event,
3708 					eptr->pic_data->text, form_x, form_y);
3709 			    }
3710 			    else
3711 			    {
3712 			     	/* The following is a hack to send the
3713 			     	 * selection location along with the HRef
3714 			     	 * for images.  This allows you to
3715 			     	 * point at a location on a map and have
3716 			     	 * the server send you the related document.
3717 			     	 * Tony Sanders, April 1993 <sanders@bsdi.com>
3718 			     	 */
3719 			     	int alloced = 0;
3720 			     	char *buf = eptr->anchorHRef;
3721 				if (eptr->type == E_IMAGE && eptr->pic_data
3722 				        && eptr->pic_data->ismap) {
3723 				    buf = (char *)
3724 				        malloc(strlen(eptr->anchorHRef) + 256);
3725 				    alloced = 1;
3726 				    sprintf(buf, "%s?%d,%d",
3727 					eptr->anchorHRef,
3728 					event->xbutton.x + hw->html.scroll_x - eptr->x,
3729 					event->xbutton.y + hw->html.scroll_y - eptr->y);
3730 			        }
3731 				/*
3732 				 * XXX: should call a media dependent
3733 				 * function that decides how to munge the
3734 				 * HRef.  For example mpeg data will want
3735 				 * to know on what frame the event occured.
3736 				 *
3737 				 * cddata.href = *(eptr->eventf)(eptr, event);
3738 			         */
3739 				cbdata.event = event;
3740 				cbdata.element_id = eptr->ele_id;
3741 				cbdata.href = buf;
3742 				/* cbdata.href = eptr->anchorHRef; */
3743 				cbdata.text = tptr;
3744 				XtCallCallbackList ((Widget)hw,
3745 					hw->html.anchor_callback,
3746 					(XtPointer)&cbdata);
3747 			        if (alloced) free(buf);
3748 			        if (tptr != NULL) free(tptr);
3749 			    }
3750 			}
3751 		}
3752 	}
3753 
3754 	return;
3755 }
3756 
3757 
3758 #ifndef MOTIF
3759 #include <X11/Xaw/AsciiText.h>
3760 /*
3761  * Process key input passwd widgets
3762  */
3763 static void
3764 #ifdef _NO_PROTO
_HTMLpwdInput(w,event,params,num_params)3765 _HTMLpwdInput( w, event, params, num_params)
3766 	Widget w ;
3767 	XEvent *event ;
3768 	String *params;		/* unused */
3769 	Cardinal *num_params;	/* unused */
3770 #else
3771 _HTMLpwdInput(
3772 	Widget w,
3773 	XEvent *event,
3774 	String *params,		/* unused */
3775 	Cardinal *num_params)	/* unused */
3776 #endif
3777      {
3778      char buffer[50];
3779      KeySym ks;
3780      char *keySymString;
3781      char *star = "*";
3782      int length, passwdLength, i, insertPos, maxLength;
3783      Boolean stringInPlace;
3784 
3785      if (event->type == KeyPress)
3786 	 {
3787 	 HTMLWidget hw = (HTMLWidget)XtParent(XtParent(w));
3788 	 WidgetInfo *wptr;
3789 
3790 	 if (XtClass((Widget)hw) != htmlWidgetClass)
3791 	     return;   /* it was not for us */
3792 
3793 	/*
3794 	 * find the structure for this widget
3795 	 */
3796 	wptr = hw->html.widget_list;
3797 	while (wptr != NULL)
3798 	    {
3799 	    if (wptr->w == w)
3800 		break;
3801 	    wptr = wptr->next;
3802 	    }
3803 	 if (wptr == NULL)
3804 	     return;
3805 
3806 	 passwdLength = wptr->password ? strlen(wptr->password) : 0;
3807 
3808 	 length = XLookupString((XKeyEvent *)event,
3809 				buffer, 50, &ks, NULL);
3810 	 keySymString = XKeysymToString(ks);
3811 	 XtVaGetValues(w,
3812 		       XtNinsertPosition,&insertPos,
3813 		       XtNuseStringInPlace, &stringInPlace,
3814 		       XtNlength, &maxLength,
3815 		       NULL);
3816 
3817          if (maxLength<1) maxLength = 1000000;
3818 
3819 	 if (!strcmp("Left",keySymString))
3820 	     {
3821 	     if (insertPos > 0)
3822 		 XtVaSetValues(w,XtNinsertPosition,--insertPos,NULL);
3823 	     return;
3824 	     }
3825 	 else if (!strcmp("Right",keySymString))
3826 	     {
3827 	     if (insertPos < passwdLength)
3828 		 XtVaSetValues(w,XtNinsertPosition,++insertPos,NULL);
3829 	     return;
3830 	     }
3831 
3832 	 if ((!strcmp("BackSpace",keySymString))
3833 	     || (!strcmp("Backspace",keySymString))
3834 	     || (!strcmp("Delete",keySymString)) )
3835 	     {
3836 	     insertPos --;
3837 
3838 	     if (passwdLength>0)
3839 		 {
3840 		 char *pwd = &(wptr->password[insertPos]);
3841 
3842 		 for (i = passwdLength - insertPos; i>0; i--,pwd++)
3843 		     *pwd = *(pwd+1);
3844 
3845 /*		 fprintf(stderr,"modified passwd <%s>\n", wptr->password);*/
3846 		 XtCallActionProc(w,
3847 				  insertPos>-1 ? "delete-previous-character" :
3848 				  "delete-next-character",
3849 				  event, NULL,0);
3850 		 }
3851 	     /* else nothing to erase */
3852 	     return;
3853 	     }
3854 
3855 	 if (length == 1)
3856 	     {
3857 	     buffer[1] = '\0';
3858 
3859 	     if (passwdLength>0)
3860 		 {
3861 
3862 		 if (passwdLength < maxLength)
3863 		     {
3864 		     char *pwd = wptr->password =
3865 			 (char *)realloc(wptr->password,
3866 				 sizeof(char)*(passwdLength+2));
3867 		     for (i=passwdLength+1; i>insertPos; i--)
3868 			 pwd[i] = pwd[i-1];
3869 
3870 		     pwd[insertPos] = buffer[0];
3871 		     }
3872 		 }
3873 	     else
3874 		 {
3875 		 if (wptr->password == NULL)
3876 		     wptr->password = (char *)malloc(sizeof(char)*2);
3877 
3878 		 wptr->password[0] = buffer[0];
3879 		 wptr->password[1] = '\0';
3880 		 }
3881 
3882 	     if (stringInPlace && passwdLength<maxLength)
3883 		 {
3884 		 char *txt;
3885 		 /* insert string dumps core when  string in place is true */
3886 
3887 		 XtVaGetValues(w,XtNstring,&txt,NULL);
3888 		 txt[passwdLength] = star[0];
3889 		 txt[passwdLength+1] = '\0';
3890 
3891 		 /* the combined set values command does not work */
3892 		 XtVaSetValues(w, XtNstring,txt, NULL);
3893 		 XtVaSetValues(w, XtNinsertPosition,insertPos+1, NULL);
3894 		 }
3895 	     else
3896 		 XtCallActionProc(w, "insert-string", event, &star, 1);
3897 /*	     fprintf(stderr,"modified passwd <%s>\n",  wptr->password); */
3898 	     }
3899 	 }
3900      }
3901 #endif /* not MOTIF */
3902 
3903 
3904 /*
3905  * SetValues is called when XtSetValues is used to change resources in this
3906  * widget.
3907  */
3908 static Boolean
3909 #ifdef _NO_PROTO
SetValues(current,request,new)3910 SetValues (current, request, new)
3911             HTMLWidget current ;
3912             HTMLWidget request ;
3913             HTMLWidget new ;
3914 #else
3915 SetValues(
3916             HTMLWidget current,
3917             HTMLWidget request,
3918             HTMLWidget new)
3919 #endif
3920 {
3921 	int reformatted;
3922 
3923 	/*
3924 	 *	Make sure the underline numbers are within bounds.
3925 	 */
3926 	if (request->html.num_anchor_underlines < 0)
3927 	{
3928 		new->html.num_anchor_underlines = 0;
3929 	}
3930 	if (request->html.num_anchor_underlines > MAX_UNDERLINES)
3931 	{
3932 		new->html.num_anchor_underlines = MAX_UNDERLINES;
3933 	}
3934 	if (request->html.num_visitedAnchor_underlines < 0)
3935 	{
3936 		new->html.num_visitedAnchor_underlines = 0;
3937 	}
3938 	if (request->html.num_visitedAnchor_underlines > MAX_UNDERLINES)
3939 	{
3940 		new->html.num_visitedAnchor_underlines = MAX_UNDERLINES;
3941 	}
3942 
3943 	reformatted = 0;
3944 	if ((request->html.raw_text != current->html.raw_text)||
3945 	    (request->html.header_text != current->html.header_text)||
3946 	    (request->html.footer_text != current->html.footer_text))
3947 	{
3948 		/*
3949 		 * Free up the old visited href list.
3950 		 */
3951 		FreeHRefs(current->html.my_visited_hrefs);
3952 		new->html.my_visited_hrefs = NULL;
3953 
3954 		/*
3955 		 * Free up the old visited delayed images list.
3956 		 */
3957 		FreeDelayedImages(current->html.my_delayed_images);
3958 		new->html.my_delayed_images = NULL;
3959 
3960 		/*
3961 		 * Free any old colors and pixmaps
3962 		 */
3963 		FreeColors(XtDisplay(current), DefaultColormapOfScreen(XtScreen(current)));
3964 		FreeImages(current);
3965 
3966 		/*
3967 		 * Hide any old widgets
3968 		 */
3969 		HideWidgets(current);
3970 		new->html.widget_list = NULL;
3971 		new->html.form_list = NULL;
3972 
3973 		/*
3974 		 * Parse the raw text with the HTML parser
3975 		 */
3976 		new->html.html_objects = HTMLParse(current->html.html_objects,
3977 			request->html.raw_text);
3978 		CallLinkCallbacks(new);
3979 		new->html.html_header_objects =
3980 			HTMLParse(current->html.html_header_objects,
3981 			request->html.header_text);
3982 		new->html.html_footer_objects =
3983 			HTMLParse(current->html.html_footer_objects,
3984 			request->html.footer_text);
3985 
3986 		/*
3987 		 * Redisplay for the changed data.
3988 		 */
3989 		{
3990 			new->html.scroll_x = 0;
3991 			new->html.scroll_y = 0;
3992 			new->html.max_pre_width = DocumentWidth(new,
3993 				new->html.html_objects);
3994 			ReformatWindow(new);
3995 			ViewClearAndRefresh(new);
3996 			reformatted = 1;
3997 		}
3998 
3999 		/*
4000 		 * Clear any previous selection
4001 		 */
4002 		new->html.select_start = NULL;
4003 		new->html.select_end = NULL;
4004 		new->html.sel_start_pos = 0;
4005 		new->html.sel_end_pos = 0;
4006 		new->html.new_start = NULL;
4007 		new->html.new_end = NULL;
4008 		new->html.new_start_pos = 0;
4009 		new->html.new_end_pos = 0;
4010 		new->html.active_anchor = NULL;
4011 	}
4012 	else if ((request->html.font != current->html.font)||
4013 	         (request->html.italic_font != current->html.italic_font)||
4014 	         (request->html.bold_font != current->html.bold_font)||
4015 	         (request->html.fixed_font != current->html.fixed_font)||
4016 	         (request->html.fixedbold_font != current->html.fixedbold_font)||
4017 	         (request->html.fixeditalic_font != current->html.fixeditalic_font)||
4018 	         (request->html.header1_font != current->html.header1_font)||
4019 	         (request->html.header2_font != current->html.header2_font)||
4020 	         (request->html.header3_font != current->html.header3_font)||
4021 	         (request->html.header4_font != current->html.header4_font)||
4022 	         (request->html.header5_font != current->html.header5_font)||
4023 	         (request->html.header6_font != current->html.header6_font)||
4024 	         (request->html.address_font != current->html.address_font)||
4025 	         (request->html.plain_font != current->html.plain_font)||
4026 	         (request->html.plainbold_font != current->html.plainbold_font)||
4027 	         (request->html.plainitalic_font != current->html.plainitalic_font)||
4028 	         (request->html.listing_font != current->html.listing_font)||
4029 	         (request->html.activeAnchor_fg != current->html.activeAnchor_fg)||
4030 	         (request->html.activeAnchor_bg != current->html.activeAnchor_bg)||
4031 	         (request->html.anchor_fg != current->html.anchor_fg)||
4032 	         (request->html.visitedAnchor_fg != current->html.visitedAnchor_fg)||
4033 	         (request->html.dashed_anchor_lines != current->html.dashed_anchor_lines)||
4034 	         (request->html.dashed_visitedAnchor_lines != current->html.dashed_visitedAnchor_lines)||
4035 	         (request->html.num_anchor_underlines != current->html.num_anchor_underlines)||
4036 	         (request->html.num_visitedAnchor_underlines != current->html.num_visitedAnchor_underlines))
4037 	{
4038 		if ((request->html.plain_font != current->html.plain_font)||
4039 		    (request->html.listing_font != current->html.listing_font))
4040 		{
4041 			new->html.max_pre_width = DocumentWidth(new,
4042 				new->html.html_objects);
4043 		}
4044 
4045 		ReformatWindow(new);
4046 		ScrollWidgets(new);
4047 		ViewClearAndRefresh(new);
4048 		reformatted = 1;
4049 	}
4050 
4051 	/*
4052 	 * image borders have been changed
4053 	 */
4054 	if (request->html.border_images != current->html.border_images)
4055 	{
4056 		ReformatWindow(new);
4057 		ScrollWidgets(new);
4058 		ViewClearAndRefresh(new);
4059 		reformatted = 1;
4060 	}
4061 
4062 	/*
4063 	 * vertical space has been changed
4064 	 */
4065 	if(request->html.percent_vert_space != current->html.percent_vert_space)
4066 	{
4067 		ReformatWindow(new);
4068 		ScrollWidgets(new);
4069 		ViewClearAndRefresh(new);
4070 		reformatted = 1;
4071 	}
4072 
4073 	return(False);
4074 }
4075 
4076 
4077 /*
4078  * Go through the parsed marks and for all the <LINK> tags in the document
4079  * call the LinkCallback.
4080  */
4081 static void
4082 #ifdef _NO_PROTO
CallLinkCallbacks(hw)4083 CallLinkCallbacks(hw)
4084 	HTMLWidget hw;
4085 #else
4086 CallLinkCallbacks(HTMLWidget hw)
4087 #endif
4088 {
4089 	struct mark_up *mptr;
4090 	LinkInfo l_info;
4091 
4092 	mptr = hw->html.html_objects;
4093 	while (mptr != NULL)
4094 	{
4095 		if (mptr->type == M_BASE)
4096 		{
4097 			l_info.href = ParseMarkTag(mptr->start, MT_BASE,
4098 				"HREF");
4099 			l_info.role = ParseMarkTag(mptr->start, MT_BASE,
4100 				"ROLE");
4101 			XtCallCallbackList ((Widget)hw, hw->html.link_callback,
4102 				(XtPointer)&l_info);
4103 			if (l_info.href != NULL)
4104 			{
4105 				free(l_info.href);
4106 			}
4107 			if (l_info.role != NULL)
4108 			{
4109 				free(l_info.role);
4110 			}
4111 		}
4112 		mptr = mptr->next;
4113 	}
4114 }
4115 
4116 
4117 /*
4118  * Search through the whole document, and recolor the internal elements with
4119  * the passed HREF.
4120  */
4121 static void
4122 #ifdef _NO_PROTO
RecolorInternalHRefs(hw,href)4123 RecolorInternalHRefs(hw, href)
4124 	HTMLWidget hw;
4125 	char *href;
4126 #else
4127 RecolorInternalHRefs(HTMLWidget hw, char *href)
4128 #endif
4129 {
4130 	struct ele_rec *start;
4131 	unsigned long fg;
4132 
4133 	fg = hw->html.visitedAnchor_fg;
4134 	start = hw->html.formatted_elements;
4135 	while (start != NULL)
4136 	{
4137 		/*
4138 		 * This one is internal
4139 		 * This one has an href
4140 		 * This is the href we want
4141 		 */
4142 		if ((start->internal == True)&&
4143 		    (start->anchorHRef != NULL)&&
4144 		    (strcmp(start->anchorHRef, href) == 0))
4145 		{
4146 			start->fg = fg;
4147 			start->underline_number =
4148 				hw->html.num_visitedAnchor_underlines;
4149 			start->dashed_underline =
4150 				hw->html.dashed_visitedAnchor_lines;
4151 		}
4152 		start = start->next;
4153 	}
4154 }
4155 
4156 
4157 static Boolean
ConvertSelection(w,selection,target,type,value,length,format)4158 ConvertSelection(w, selection, target, type, value, length, format)
4159 	Widget w;
4160 	Atom *selection, *target, *type;
4161 	caddr_t *value;
4162 	unsigned long *length;
4163 	int *format;
4164 {
4165 	Display *d = XtDisplay(w);
4166 	HTMLWidget hw = (HTMLWidget)w;
4167 	char *text;
4168 
4169 	if (hw->html.select_start == NULL)
4170 	{
4171 		return False;
4172 	}
4173 
4174 	if (*target == XA_TARGETS(d))
4175 	{
4176 		Atom *targetP;
4177 		Atom *std_targets;
4178 		unsigned long std_length;
4179 		XmuConvertStandardSelection( w, hw->html.selection_time,
4180 			selection, target, type, (caddr_t*)&std_targets,
4181 			&std_length, format);
4182 
4183 		*length = std_length + 5;
4184 		*value = (caddr_t)XtMalloc(sizeof(Atom)*(*length));
4185 		targetP = *(Atom**)value;
4186 		*targetP++ = XA_STRING;
4187 		*targetP++ = XA_TEXT(d);
4188 		*targetP++ = XA_COMPOUND_TEXT(d);
4189 		*targetP++ = XA_LENGTH(d);
4190 		*targetP++ = XA_LIST_LENGTH(d);
4191 
4192 		bcopy((char*)std_targets, (char*)targetP,
4193 			sizeof(Atom)*std_length);
4194 		XtFree((char*)std_targets);
4195 		*type = XA_ATOM;
4196 		*format = 32;
4197 		return True;
4198 	}
4199 
4200 	if (*target == XA_STRING || *target == XA_TEXT(d) ||
4201 		*target == XA_COMPOUND_TEXT(d))
4202 	{
4203 		if (*target == XA_COMPOUND_TEXT(d))
4204 		{
4205 			*type = *target;
4206 		}
4207 		else
4208 		{
4209 			*type = XA_STRING;
4210 		}
4211 		if (hw->html.fancy_selections == True)
4212 		{
4213 			text = ParseTextToPrettyString(hw,
4214 				hw->html.formatted_elements,
4215 				hw->html.select_start, hw->html.select_end,
4216 				hw->html.sel_start_pos, hw->html.sel_end_pos,
4217 				hw->html.font->max_bounds.width,
4218 				hw->html.margin_width);
4219 		}
4220 		else
4221 		{
4222 			text = ParseTextToString(hw->html.formatted_elements,
4223 				hw->html.select_start, hw->html.select_end,
4224 				hw->html.sel_start_pos, hw->html.sel_end_pos,
4225 				hw->html.font->max_bounds.width,
4226 				hw->html.margin_width);
4227 		}
4228 		*value = text;
4229 		*length = strlen(*value);
4230 		*format = 8;
4231 		return True;
4232 	}
4233 
4234 	if (*target == XA_LIST_LENGTH(d))
4235 	{
4236 		*value = XtMalloc(4);
4237 		if (sizeof(long) == 4)
4238 		{
4239 			*(long*)*value = 1;
4240 		}
4241 		else
4242 		{
4243 			long temp = 1;
4244 			bcopy( ((char*)&temp)+sizeof(long)-4, (char*)*value, 4);
4245 		}
4246 		*type = XA_INTEGER;
4247 		*length = 1;
4248 		*format = 32;
4249 		return True;
4250 	}
4251 
4252 	if (*target == XA_LENGTH(d))
4253 	{
4254 		if (hw->html.fancy_selections == True)
4255 		{
4256 			text = ParseTextToPrettyString(hw,
4257 				hw->html.formatted_elements,
4258 				hw->html.select_start, hw->html.select_end,
4259 				hw->html.sel_start_pos, hw->html.sel_end_pos,
4260 				hw->html.font->max_bounds.width,
4261 				hw->html.margin_width);
4262 		}
4263 		else
4264 		{
4265 			text = ParseTextToString(hw->html.formatted_elements,
4266 				hw->html.select_start, hw->html.select_end,
4267 				hw->html.sel_start_pos, hw->html.sel_end_pos,
4268 				hw->html.font->max_bounds.width,
4269 				hw->html.margin_width);
4270 		}
4271 		*value = XtMalloc(4);
4272 		if (sizeof(long) == 4)
4273 		{
4274 			*(long*)*value = strlen(text);
4275 		}
4276 		else
4277 		{
4278 			long temp = strlen(text);
4279 			bcopy( ((char*)&temp)+sizeof(long)-4, (char*)*value, 4);
4280 		}
4281 		free(text);
4282 		*type = XA_INTEGER;
4283 		*length = 1;
4284 		*format = 32;
4285 		return True;
4286 	}
4287 
4288 	if (XmuConvertStandardSelection(w, hw->html.selection_time, selection,
4289 				    target, type, value, length, format))
4290 	{
4291 		return True;
4292 	}
4293 
4294 	return False;
4295 }
4296 
4297 
4298 static void
LoseSelection(w,selection)4299 LoseSelection(w, selection)
4300 	Widget w;
4301 	Atom *selection;
4302 {
4303 	HTMLWidget hw = (HTMLWidget)w;
4304 
4305 	ClearSelection(hw);
4306 }
4307 
4308 
4309 static void
SelectionDone(w,selection,target)4310 SelectionDone(w, selection, target)
4311 	Widget w;
4312 	Atom *selection, *target;
4313 {
4314 	/* empty proc so Intrinsics know we want to keep storage */
4315 }
4316 
4317 
4318 /*
4319  *************************************************************************
4320  ******************************* PUBLIC FUNCTIONS ************************
4321  *************************************************************************
4322  */
4323 
4324 
4325 /*
4326  * Convenience function to return the text of the HTML document as a plain
4327  * ascii text string.
4328  * This function allocates memory for the returned string, that it is up
4329  * to the user to free.
4330  * Extra option flags "pretty" text to be returned.
4331  * when pretty is two or larger, Postscript is returned. The font used is
4332  * encoded in the pretty parameter:
4333  * pretty = 2: Times
4334  * pretty = 3: Helvetica
4335  * pretty = 4: New century schoolbook
4336  * pretty = 5: Lucida Bright
4337  */
4338 char *
4339 #ifdef _NO_PROTO
HTMLGetText(w,pretty)4340 HTMLGetText (w, pretty)
4341 	Widget w;
4342 	int pretty;
4343 #else
4344 HTMLGetText(Widget w, int pretty)
4345 #endif
4346 {
4347 	HTMLWidget hw = (HTMLWidget)w;
4348 	char *text;
4349 	char *tptr, *buf;
4350 	struct ele_rec *start;
4351 	struct ele_rec *end;
4352 
4353 	text = NULL;
4354 	start = hw->html.formatted_elements;
4355 	end = start;
4356 	while (end != NULL)
4357 	{
4358 		end = end->next;
4359 	}
4360 
4361 	if (pretty >= 2)
4362 	{
4363 		tptr = ParseTextToPSString(hw, start, start, end,
4364 				0, 0,
4365 				hw->html.font->max_bounds.width,
4366 				hw->html.margin_width , pretty-2);
4367 	}
4368 	else if (pretty)
4369 	{
4370 		tptr = ParseTextToPrettyString(hw, start, start, end,
4371 				0, 0,
4372 				hw->html.font->max_bounds.width,
4373 				hw->html.margin_width);
4374 	}
4375 	else
4376 	{
4377 		tptr = ParseTextToString(start, start, end,
4378 				0, 0,
4379 				hw->html.font->max_bounds.width,
4380 				hw->html.margin_width);
4381 	}
4382 	if (tptr != NULL)
4383 	{
4384 		if (text == NULL)
4385 		{
4386 			text = tptr;
4387 		}
4388 		else
4389 		{
4390 			buf = (char *)malloc(strlen(text) +
4391 				strlen(tptr) + 1);
4392 			strcpy(buf, text);
4393 			strcat(buf, tptr);
4394 			free(text);
4395 			free(tptr);
4396 			text = buf;
4397 		}
4398 	}
4399 	return(text);
4400 }
4401 
4402 
4403 /*
4404  * Convenience function to return the element id of the element
4405  * nearest to the x,y coordinates passed in.
4406  * If there is no element there, return the first element in the
4407  * line we are on.  If there we are on no line, either return the
4408  * beginning, or the end of the document.
4409  */
4410 int
4411 #ifdef _NO_PROTO
HTMLPositionToId(w,x,y)4412 HTMLPositionToId(w, x, y)
4413 	Widget w;
4414 	int x, y;
4415 #else
4416 HTMLPositionToId(Widget w, int x, int y)
4417 #endif
4418 {
4419 	HTMLWidget hw = (HTMLWidget)w;
4420 	int i;
4421 	int epos;
4422 	struct ele_rec *eptr;
4423 
4424 	eptr = LocateElement(hw, x, y, &epos);
4425 	if (eptr == NULL)
4426 	{
4427 		x = x + hw->html.scroll_x;
4428 		y = y + hw->html.scroll_y;
4429 		eptr = hw->html.line_array[0];
4430 		for (i=0; i<hw->html.line_count; i++)
4431 		{
4432 			if (hw->html.line_array[i] == NULL)
4433 			{
4434 				continue;
4435 			}
4436 			else if (hw->html.line_array[i]->y <= y)
4437 			{
4438 				eptr = hw->html.line_array[i];
4439 				continue;
4440 			}
4441 			else
4442 			{
4443 				break;
4444 			}
4445 		}
4446 	}
4447 
4448 	/*
4449 	 * 0 means the very top of the document.  We put you there for
4450 	 * unfound elements.
4451 	 * We also special case for when the scrollbar is at the
4452 	 * absolute top.
4453 	 */
4454 	if ((eptr == NULL)||(hw->html.scroll_y == 0))
4455 	{
4456 		return(0);
4457 	}
4458 	else
4459 	{
4460 		return(eptr->ele_id);
4461 	}
4462 }
4463 
4464 
4465 /*
4466  * Convenience function to return the position of the element
4467  * based on the element id passed in.
4468  * Function returns 1 on success and fills in x,y pixel values.
4469  * If there is no such element, x=0, y=0 and -1 is returned.
4470  */
4471 int
4472 #ifdef _NO_PROTO
HTMLIdToPosition(w,element_id,x,y)4473 HTMLIdToPosition(w, element_id, x, y)
4474 	Widget w;
4475 	int element_id;
4476 	int *x, *y;
4477 #else
4478 HTMLIdToPosition(Widget w, int element_id, int *x, int *y)
4479 #endif
4480 {
4481 	HTMLWidget hw = (HTMLWidget)w;
4482 	struct ele_rec *start;
4483 	struct ele_rec *eptr;
4484 
4485 	eptr = NULL;
4486 	start = hw->html.formatted_elements;
4487 	while (start != NULL)
4488 	{
4489 		if (start->ele_id == element_id)
4490 		{
4491 			eptr = start;
4492 			break;
4493 		}
4494 		start = start->next;
4495 	}
4496 
4497 	if (eptr == NULL)
4498 	{
4499 		*x = 0;
4500 		*y = 0;
4501 		return(-1);
4502 	}
4503 	else
4504 	{
4505 		*x = eptr->x;
4506 		*y = eptr->y;
4507 		return(1);
4508 	}
4509 }
4510 
4511 
4512 /*
4513  * Convenience function to position the element
4514  * based on the element id passed at the top of the viewing area.
4515  * A passed in id of 0 means goto the top.
4516  */
4517 void
4518 #ifdef _NO_PROTO
HTMLGotoId(w,element_id)4519 HTMLGotoId(w, element_id)
4520 	Widget w;
4521 	int element_id;
4522 #else
4523 HTMLGotoId(Widget w, int element_id)
4524 #endif
4525 {
4526 	HTMLWidget hw = (HTMLWidget)w;
4527 	struct ele_rec *start;
4528 	struct ele_rec *eptr;
4529 	int newy;
4530 #ifdef MOTIF
4531 	int val, size, inc, pageinc;
4532 #endif
4533 
4534 	/*
4535 	 * If we have no scrollbar, just return.
4536 	 */
4537 	if (hw->html.use_vbar == False)
4538 	{
4539 		return;
4540 	}
4541 
4542 	/*
4543 	 * Find the element corrsponding to the id passed in.
4544 	 */
4545 	eptr = NULL;
4546 	start = hw->html.formatted_elements;
4547 	while (start != NULL)
4548 	{
4549 		if (start->ele_id == element_id)
4550 		{
4551 			eptr = start;
4552 			break;
4553 		}
4554 		start = start->next;
4555 	}
4556 
4557 	/*
4558 	 * No such element, do nothing.
4559 	 */
4560 	if ((element_id != 0)&&(eptr == NULL))
4561 	{
4562 		return;
4563 	}
4564 
4565 	if (element_id == 0)
4566 	{
4567 		newy = 0;
4568 	}
4569 	else
4570 	{
4571 		newy = eptr->y - 2;
4572 	}
4573 	if (newy < 0)
4574 	{
4575 		newy = 0;
4576 	}
4577 	if (newy > (hw->html.doc_height - (int)hw->html.view_height))
4578 	{
4579 		newy = hw->html.doc_height - (int)hw->html.view_height;
4580 	}
4581 	if (newy < 0)
4582 	{
4583 		newy = 0;
4584 	}
4585 #ifdef MOTIF
4586 	XmScrollBarGetValues(hw->html.vbar, &val, &size, &inc, &pageinc);
4587 	XmScrollBarSetValues(hw->html.vbar, newy, size, inc, pageinc, True);
4588 	XmScrollBarGetValues(hw->html.hbar, &val, &size, &inc, &pageinc);
4589 	XmScrollBarSetValues(hw->html.hbar, 0, size, inc, pageinc, True);
4590 #else
4591 	ScrollToPos(hw->html.vbar, hw, newy);
4592 	ScrollToPos(hw->html.hbar, hw, 0);
4593 	setScrollBar(hw->html.vbar, newy,
4594 		     hw->html.doc_height,
4595 		     hw->html.view_height);
4596 #endif
4597 }
4598 
4599 
4600 /*
4601  * Convenience function to return the position of the anchor
4602  * based on the anchor NAME passed.
4603  * Function returns 1 on success and fills in x,y pixel values.
4604  * If there is no such element, x=0, y=0 and -1 is returned.
4605  */
4606 int
4607 #ifdef _NO_PROTO
HTMLAnchorToPosition(w,name,x,y)4608 HTMLAnchorToPosition(w, name, x, y)
4609 	Widget w;
4610 	char *name;
4611 	int *x, *y;
4612 #else
4613 HTMLAnchorToPosition(Widget w, char *name, int *x, int *y)
4614 #endif
4615 {
4616 	HTMLWidget hw = (HTMLWidget)w;
4617 	struct ele_rec *start;
4618 	struct ele_rec *eptr;
4619 
4620 	eptr = NULL;
4621 	start = hw->html.formatted_elements;
4622 	while (start != NULL)
4623 	{
4624 		if ((start->anchorName)&&
4625 		    (strcmp(start->anchorName, name) == 0))
4626 		{
4627 			eptr = start;
4628 			break;
4629 		}
4630 		start = start->next;
4631 	}
4632 
4633 	if (eptr == NULL)
4634 	{
4635 		*x = 0;
4636 		*y = 0;
4637 		return(-1);
4638 	}
4639 	else
4640 	{
4641 		*x = eptr->x;
4642 		*y = eptr->y;
4643 		return(1);
4644 	}
4645 }
4646 
4647 
4648 /*
4649  * Convenience function to return the element id of the anchor
4650  * based on the anchor NAME passed.
4651  * Function returns id on success.
4652  * If there is no such element, 0 is returned.
4653  */
4654 int
4655 #ifdef _NO_PROTO
HTMLAnchorToId(w,name)4656 HTMLAnchorToId(w, name)
4657 	Widget w;
4658 	char *name;
4659 #else
4660 HTMLAnchorToId(Widget w, char *name)
4661 #endif
4662 {
4663 	HTMLWidget hw = (HTMLWidget)w;
4664 	struct ele_rec *start;
4665 	struct ele_rec *eptr;
4666 
4667 	/*
4668 	 * Find the passed anchor name
4669 	 */
4670 	eptr = NULL;
4671 	start = hw->html.formatted_elements;
4672 	while (start != NULL)
4673 	{
4674 		if ((start->anchorName)&&
4675 		    (strcmp(start->anchorName, name) == 0))
4676 		{
4677 			eptr = start;
4678 			break;
4679 		}
4680 		start = start->next;
4681 	}
4682 
4683 	if (eptr == NULL)
4684 	{
4685 		return(0);
4686 	}
4687 	else
4688 	{
4689 		return(eptr->ele_id);
4690 	}
4691 }
4692 
4693 
4694 /*
4695  * Convenience function to return the HREFs of all active anchors in the
4696  * document.
4697  * Function returns an array of strings and fills num_hrefs passed.
4698  * If there are no HREFs NULL returned.
4699  */
4700 char **
4701 #ifdef _NO_PROTO
HTMLGetHRefs(w,num_hrefs)4702 HTMLGetHRefs(w, num_hrefs)
4703 	Widget w;
4704 	int *num_hrefs;
4705 #else
4706 HTMLGetHRefs(Widget w, int *num_hrefs)
4707 #endif
4708 {
4709 	HTMLWidget hw = (HTMLWidget)w;
4710 	int cnt;
4711 	struct ele_rec *start;
4712 	struct ele_rec *list;
4713 	struct ele_rec *eptr;
4714 	char **harray;
4715 
4716 	list = NULL;
4717 	cnt = 0;
4718 	/*
4719 	 * Construct a linked list of all the diffeent hrefs, counting
4720 	 * then as we go.
4721 	 */
4722 	start = hw->html.formatted_elements;
4723 	while (start != NULL)
4724 	{
4725 		/*
4726 		 * This one has an HREF
4727 		 */
4728 		if (start->anchorHRef != NULL)
4729 		{
4730 			/*
4731 			 * Check to see if we already have
4732 			 * this HREF in our list.
4733 			 */
4734 			eptr = list;
4735 			while (eptr != NULL)
4736 			{
4737 				if (strcmp(eptr->anchorHRef,
4738 					start->anchorHRef) == 0)
4739 				{
4740 					break;
4741 				}
4742 				eptr = eptr->next;
4743 			}
4744 			/*
4745 			 * This HREF is not, in our list.  Add it.
4746 			 * That is, if it's not an internal reference.
4747 			 */
4748 			if ((eptr == NULL)&&(start->internal == False))
4749 			{
4750 				eptr = (struct ele_rec *)
4751 					malloc(sizeof(struct ele_rec));
4752 				eptr->anchorHRef = start->anchorHRef;
4753 				eptr->next = list;
4754 				list = eptr;
4755 				cnt++;
4756 			}
4757 		}
4758 		start = start->next;
4759 	}
4760 
4761 	if (cnt == 0)
4762 	{
4763 		*num_hrefs = 0;
4764 		return(NULL);
4765 	}
4766 	else
4767 	{
4768 		*num_hrefs = cnt;
4769 		harray = (char **)malloc(sizeof(char *) * cnt);
4770 		eptr = list;
4771 		cnt--;
4772 		while (eptr != NULL)
4773 		{
4774 			harray[cnt] = (char *)
4775 				malloc(strlen(eptr->anchorHRef) + 1);
4776 			strcpy(harray[cnt], eptr->anchorHRef);
4777 			start = eptr;
4778 			eptr = eptr->next;
4779 			free((char *)start);
4780 			cnt--;
4781 		}
4782 		return(harray);
4783 	}
4784 }
4785 
4786 
4787 /*
4788  * Convenience function to return the SRCs of all images in the
4789  * document.
4790  * Function returns an array of strings and fills num_srcs passed.
4791  * If there are no SRCs NULL returned.
4792  */
4793 char **
4794 #ifdef _NO_PROTO
HTMLGetImageSrcs(w,num_srcs)4795 HTMLGetImageSrcs(w, num_srcs)
4796 	Widget w;
4797 	int *num_srcs;
4798 #else
4799 HTMLGetImageSrcs(Widget w, int *num_srcs)
4800 #endif
4801 {
4802 	HTMLWidget hw = (HTMLWidget)w;
4803 	struct mark_up *mptr;
4804 	int cnt;
4805 	char *tptr;
4806 	char **harray;
4807 
4808 	cnt = 0;
4809 	mptr = hw->html.html_objects;
4810 	while (mptr != NULL)
4811 	{
4812 		if (mptr->type == M_IMAGE)
4813 		{
4814 			tptr = ParseMarkTag(mptr->start, MT_IMAGE, "SRC");
4815 			if ((tptr != NULL)&&(*tptr != '\0'))
4816 			{
4817 				cnt++;
4818 				free(tptr);
4819 			}
4820 		}
4821 		else /****** temporary until figure support */
4822 		if (mptr->type == M_FIGURE)
4823 		{
4824 			tptr = ParseMarkTag(mptr->start, MT_FIGURE, "SRC");
4825 			if ((tptr != NULL)&&(*tptr != '\0'))
4826 			{
4827 				cnt++;
4828 				free(tptr);
4829 			}
4830 		}
4831 		/*********************************************/
4832 		mptr = mptr->next;
4833 	}
4834 
4835 	if (cnt == 0)
4836 	{
4837 		*num_srcs = 0;
4838 		return(NULL);
4839 	}
4840 	else
4841 	{
4842 		*num_srcs = cnt;
4843 		harray = (char **)malloc(sizeof(char *) * cnt);
4844 		mptr = hw->html.html_objects;
4845 		cnt = 0;
4846 		while (mptr != NULL)
4847 		{
4848 			if (mptr->type == M_IMAGE)
4849 			{
4850 				tptr = ParseMarkTag(mptr->start,MT_IMAGE,"SRC");
4851 				if ((tptr != NULL)&&(*tptr != '\0'))
4852 				{
4853 					harray[cnt] = tptr;
4854 					cnt++;
4855 				}
4856 			}
4857 			else /****** temporary until figure support */
4858 			if (mptr->type == M_FIGURE)
4859 			{
4860 				tptr =ParseMarkTag(mptr->start,MT_FIGURE,"SRC");
4861 				if ((tptr != NULL)&&(*tptr != '\0'))
4862 				{
4863 					harray[cnt] = tptr;
4864 					cnt++;
4865 				}
4866 			}
4867 			/*********************************************/
4868 			mptr = mptr->next;
4869 		}
4870 		return(harray);
4871 	}
4872 }
4873 
4874 
4875 /*
4876  * Convenience function to return the link information
4877  * for all the <LINK> tags in the document.
4878  * Function returns an array of LinkInfo structures and fills
4879  * num_links passed.
4880  * If there are no LINKs NULL returned.
4881  */
4882 LinkInfo *
4883 #ifdef _NO_PROTO
HTMLGetLinks(w,num_links)4884 HTMLGetLinks(w, num_links)
4885 	Widget w;
4886 	int *num_links;
4887 #else
4888 HTMLGetLinks(Widget w, int *num_links)
4889 #endif
4890 {
4891 	HTMLWidget hw = (HTMLWidget)w;
4892 	struct mark_up *mptr;
4893 	int cnt;
4894 	char *tptr;
4895 	LinkInfo *larray;
4896 
4897 	cnt = 0;
4898 	mptr = hw->html.html_objects;
4899 	while (mptr != NULL)
4900 	{
4901 		if (mptr->type == M_BASE)
4902 		{
4903 			cnt++;
4904 		}
4905 		mptr = mptr->next;
4906 	}
4907 
4908 	if (cnt == 0)
4909 	{
4910 		*num_links = 0;
4911 		return(NULL);
4912 	}
4913 	else
4914 	{
4915 		*num_links = cnt;
4916 		larray = (LinkInfo *)malloc(sizeof(LinkInfo) * cnt);
4917 		mptr = hw->html.html_objects;
4918 		cnt = 0;
4919 		while (mptr != NULL)
4920 		{
4921 			if (mptr->type == M_BASE)
4922 			{
4923 				tptr = ParseMarkTag(mptr->start,
4924 					MT_BASE, "HREF");
4925 				larray[cnt].href = tptr;
4926 				tptr = ParseMarkTag(mptr->start,
4927 					MT_BASE, "ROLE");
4928 				larray[cnt].role = tptr;
4929 				cnt++;
4930 			}
4931 			mptr = mptr->next;
4932 		}
4933 		return(larray);
4934 	}
4935 }
4936 
4937 
4938 
4939 void *
4940 #ifdef _NO_PROTO
HTMLGetWidgetInfo(w)4941 HTMLGetWidgetInfo(w)
4942 	Widget w;
4943 #else
4944 HTMLGetWidgetInfo(Widget w)
4945 #endif
4946 {
4947 	HTMLWidget hw = (HTMLWidget)w;
4948 
4949 	return((void *)hw->html.widget_list);
4950 }
4951 
4952 
4953 void
4954 #ifdef _NO_PROTO
HTMLFreeImageInfo(w)4955 HTMLFreeImageInfo(w)
4956 	Widget w;
4957 #else
4958 HTMLFreeImageInfo(Widget w)
4959 #endif
4960 {
4961 	HTMLWidget hw = (HTMLWidget)w;
4962 
4963 	FreeColors(XtDisplay(w), DefaultColormapOfScreen(XtScreen(w)));
4964 	FreeImages(hw);
4965 }
4966 
4967 
4968 void
4969 #ifdef _NO_PROTO
HTMLFreeWidgetInfo(ptr)4970 HTMLFreeWidgetInfo(ptr)
4971 	void *ptr;
4972 #else
4973 HTMLFreeWidgetInfo(void *ptr)
4974 #endif
4975 {
4976 	WidgetInfo *wptr = (WidgetInfo *)ptr;
4977 	WidgetInfo *tptr;
4978 
4979 	while (wptr != NULL)
4980 	{
4981 		tptr = wptr;
4982 		wptr = wptr->next;
4983 		if (tptr->w != NULL)
4984 		{
4985 			/*
4986 			 * This is REALLY DUMB, but X generates an expose event
4987 			 * for the destruction of the Widgte, even if it isn't
4988 			 * mapped at the time it is destroyed.
4989 			 * So I move the invisible widget to -1000,-1000
4990 			 * before destroying it, to avoid a visible flash.
4991 			 */
4992 			XtMoveWidget(tptr->w, -1000, -1000);
4993 			XtDestroyWidget(tptr->w);
4994 		}
4995 		if (tptr->name != NULL)
4996 		{
4997 			free(tptr->name);
4998 		}
4999 		if ((tptr->value != NULL)&&(tptr->type != W_OPTIONMENU))
5000 		{
5001 			free(tptr->value);
5002 		}
5003 		free((char *)tptr);
5004 	}
5005 }
5006 
5007 
5008 /*
5009  * Convenience function to redraw all active anchors in the
5010  * document.
5011  * Can also pass a new predicate function to check visited
5012  * anchors.  If NULL passed for function, uses default predicate
5013  * function.
5014  */
5015 void
5016 #ifdef _NO_PROTO
HTMLRetestAnchors(w,testFunc)5017 HTMLRetestAnchors(w, testFunc)
5018 	Widget w;
5019 	visitTestProc testFunc;
5020 #else
5021 HTMLRetestAnchors(Widget w, visitTestProc testFunc)
5022 #endif
5023 {
5024 	HTMLWidget hw = (HTMLWidget)w;
5025 	struct ele_rec *start;
5026 
5027 	if (testFunc == NULL)
5028 	{
5029 		testFunc = (visitTestProc)hw->html.previously_visited_test;
5030 	}
5031 
5032 	/*
5033 	 * Search all elements
5034 	 */
5035 	start = hw->html.formatted_elements;
5036 	while (start != NULL)
5037 	{
5038 		if ((start->internal == True)||
5039 		    (start->anchorHRef == NULL))
5040 		{
5041 			start = start->next;
5042 			continue;
5043 		}
5044 
5045 		if (testFunc != NULL)
5046 		{
5047 			if ((*testFunc)(hw, start->anchorHRef))
5048 			{
5049 			    start->fg = hw->html.visitedAnchor_fg;
5050 			    start->underline_number =
5051 				hw->html.num_visitedAnchor_underlines;
5052 			    start->dashed_underline =
5053 				hw->html.dashed_visitedAnchor_lines;
5054 			}
5055 			else
5056 			{
5057 			    start->fg = hw->html.anchor_fg;
5058 			    start->underline_number =
5059 				hw->html.num_anchor_underlines;
5060 			    start->dashed_underline =
5061 				hw->html.dashed_anchor_lines;
5062 			}
5063 		}
5064 		else
5065 		{
5066 			start->fg = hw->html.anchor_fg;
5067 			start->underline_number =
5068 				hw->html.num_anchor_underlines;
5069 			start->dashed_underline =
5070 				hw->html.dashed_anchor_lines;
5071 		}
5072 
5073 		/*
5074 		 * Since the element may have changed, redraw it
5075 		 */
5076 		switch(start->type)
5077 		{
5078 			case E_TEXT:
5079 				TextRefresh(hw, start,
5080 				     0, (start->edata_len - 2));
5081 				break;
5082 			case E_IMAGE:
5083 				ImageRefresh(hw, start);
5084 				break;
5085 			case E_BULLET:
5086 				BulletRefresh(hw, start);
5087 				break;
5088 			case E_LINEFEED:
5089 				LinefeedRefresh(hw, start);
5090 				break;
5091 		}
5092 
5093 		start = start->next;
5094 	}
5095 }
5096 
5097 
5098 void
5099 #ifdef _NO_PROTO
HTMLClearSelection(w)5100 HTMLClearSelection (w)
5101 	Widget w;
5102 #else
5103 HTMLClearSelection(Widget w)
5104 #endif
5105 {
5106 	LoseSelection (w, NULL);
5107 }
5108 
5109 
5110 /*
5111  * Set the current selection based on the ElementRefs passed in.
5112  * Both refs must be valid.
5113  */
5114 void
5115 #ifdef _NO_PROTO
HTMLSetSelection(w,start,end)5116 HTMLSetSelection (w, start, end)
5117 	Widget w;
5118 	ElementRef *start;
5119 	ElementRef *end;
5120 #else
5121 HTMLSetSelection(Widget w, ElementRef *start, ElementRef *end)
5122 #endif
5123 {
5124 	HTMLWidget hw = (HTMLWidget)w;
5125 	int found;
5126 	struct ele_rec *eptr;
5127 	struct ele_rec *e_start;
5128 	struct ele_rec *e_end;
5129 	int start_pos, end_pos;
5130 	Atom *atoms;
5131 	int i, buffer;
5132 	char *text;
5133 	char *params[2];
5134 
5135 	/*
5136 	 * If the starting position is not valid, fail the selection
5137 	 */
5138 	if ((start->id > 0)&&(start->pos >= 0))
5139 	{
5140 		found = 0;
5141 		eptr = hw->html.formatted_elements;
5142 
5143 		while (eptr != NULL)
5144 		{
5145 			if (eptr->ele_id == start->id)
5146 			{
5147 				e_start = eptr;
5148 				start_pos = start->pos;
5149 				found = 1;
5150 				break;
5151 			}
5152 			eptr = eptr->next;
5153 		}
5154 		if (!found)
5155 		{
5156 			return;
5157 		}
5158 	}
5159 
5160 	/*
5161 	 * If the ending position is not valid, fail the selection
5162 	 */
5163 	if ((end->id > 0)&&(end->pos >= 0))
5164 	{
5165 		found = 0;
5166 		eptr = hw->html.formatted_elements;
5167 
5168 		while (eptr != NULL)
5169 		{
5170 			if (eptr->ele_id == end->id)
5171 			{
5172 				e_end = eptr;
5173 				end_pos = end->pos;
5174 				found = 1;
5175 				break;
5176 			}
5177 			eptr = eptr->next;
5178 		}
5179 		if (!found)
5180 		{
5181 			return;
5182 		}
5183 	}
5184 
5185 	LoseSelection (w, NULL);
5186 
5187 	/*
5188 	 * We expect the ElementRefs came from HTMLSearchText, so we know
5189 	 * that the end_pos is one past what we want to select.
5190 	 */
5191 	end_pos = end_pos - 1;
5192 
5193 	/*
5194 	 * Sanify the position data
5195 	 */
5196 	if ((start_pos > 0)&&(start_pos >= e_start->edata_len - 1))
5197 	{
5198 		start_pos = e_start->edata_len - 2;
5199 	}
5200 	if ((end_pos > 0)&&(end_pos >= e_end->edata_len - 1))
5201 	{
5202 		end_pos = e_end->edata_len - 2;
5203 	}
5204 
5205 	hw->html.select_start = e_start;
5206 	hw->html.sel_start_pos = start_pos;
5207 	hw->html.select_end = e_end;
5208 	hw->html.sel_end_pos = end_pos;
5209 	SetSelection(hw);
5210 	hw->html.new_start = NULL;
5211 	hw->html.new_end = NULL;
5212 	hw->html.new_start_pos = 0;
5213 	hw->html.new_end_pos = 0;
5214 
5215 	/*
5216 	 * Do all the gunk from the end of the ExtendEnd function
5217 	 */
5218 	params[0] = "PRIMARY";
5219 	params[1] = "CUT_BUFFER0";
5220 	atoms = (Atom *)malloc(2 * sizeof(Atom));
5221 	if (atoms == NULL)
5222 	{
5223 		fprintf(stderr, "cannot allocate atom list\n");
5224 		return;
5225 	}
5226 	XmuInternStrings(XtDisplay((Widget)hw), params, 2, atoms);
5227 	hw->html.selection_time = CurrentTime;
5228 	for (i=0; i< 2; i++)
5229 	{
5230 		switch (atoms[i])
5231 		{
5232 			case XA_CUT_BUFFER0: buffer = 0; break;
5233 			case XA_CUT_BUFFER1: buffer = 1; break;
5234 			case XA_CUT_BUFFER2: buffer = 2; break;
5235 			case XA_CUT_BUFFER3: buffer = 3; break;
5236 			case XA_CUT_BUFFER4: buffer = 4; break;
5237 			case XA_CUT_BUFFER5: buffer = 5; break;
5238 			case XA_CUT_BUFFER6: buffer = 6; break;
5239 			case XA_CUT_BUFFER7: buffer = 7; break;
5240 			default: buffer = -1; break;
5241 		}
5242 		if (buffer >= 0)
5243 		{
5244 			if (hw->html.fancy_selections == True)
5245 			{
5246 			    text = ParseTextToPrettyString(hw,
5247 				hw->html.formatted_elements,
5248 				hw->html.select_start,
5249 				hw->html.select_end,
5250 				hw->html.sel_start_pos,
5251 				hw->html.sel_end_pos,
5252 				hw->html.font->max_bounds.width,
5253 				hw->html.margin_width);
5254 			}
5255 			else
5256 			{
5257 			    text = ParseTextToString(
5258 				hw->html.formatted_elements,
5259 				hw->html.select_start,
5260 				hw->html.select_end,
5261 				hw->html.sel_start_pos,
5262 				hw->html.sel_end_pos,
5263 				hw->html.font->max_bounds.width,
5264 				hw->html.margin_width);
5265 			}
5266 			XStoreBuffer(XtDisplay((Widget)hw),
5267 				text, strlen(text), buffer);
5268 			free(text);
5269 		}
5270 		else
5271 		{
5272 			XtOwnSelection((Widget)hw, atoms[i], CurrentTime,
5273 				       (XtConvertSelectionProc )ConvertSelection,
5274 				       (XtLoseSelectionProc )LoseSelection,
5275 				       (XtSelectionDoneProc )SelectionDone);
5276 		}
5277 	}
5278 	free((char *)atoms);
5279 }
5280 
5281 
5282 /*
5283  * Convenience function to return the text of the HTML document as a single
5284  * white space separated string, with pointers to the various start and
5285  * end points of selections.
5286  * This function allocates memory for the returned string, that it is up
5287  * to the user to free.
5288  */
5289 char *
5290 #ifdef _NO_PROTO
HTMLGetTextAndSelection(w,startp,endp,insertp)5291 HTMLGetTextAndSelection (w, startp, endp, insertp)
5292 	Widget w;
5293 	char **startp;
5294 	char **endp;
5295 	char **insertp;
5296 #else
5297 HTMLGetTextAndSelection(Widget w, char **startp, char **endp, char **insertp)
5298 #endif
5299 {
5300 	HTMLWidget hw = (HTMLWidget)w;
5301 	int length;
5302 	char *text;
5303 	char *tptr;
5304 	struct ele_rec *eptr;
5305 	struct ele_rec *sel_start;
5306 	struct ele_rec *sel_end;
5307 	struct ele_rec *insert_start;
5308 	int start_pos, end_pos, insert_pos;
5309 
5310 	if (SwapElements(hw->html.select_start, hw->html.select_end,
5311 		hw->html.sel_start_pos, hw->html.sel_end_pos))
5312 	{
5313 		sel_end = hw->html.select_start;
5314 		end_pos = hw->html.sel_start_pos;
5315 		sel_start = hw->html.select_end;
5316 		start_pos = hw->html.sel_end_pos;
5317 	}
5318 	else
5319 	{
5320 		sel_start = hw->html.select_start;
5321 		start_pos = hw->html.sel_start_pos;
5322 		sel_end = hw->html.select_end;
5323 		end_pos = hw->html.sel_end_pos;
5324 	}
5325 
5326 	insert_start = hw->html.new_start;
5327 	insert_pos = hw->html.new_start_pos;
5328 	*startp = NULL;
5329 	*endp = NULL;
5330 	*insertp = NULL;
5331 
5332 	length = 0;
5333 
5334 	eptr = hw->html.formatted_elements;
5335 	while (eptr != NULL)
5336 	{
5337 		/*
5338 		 * Skip the special internal text
5339 		 */
5340 		if (eptr->internal == True)
5341 		{
5342 			eptr = eptr->next;
5343 			continue;
5344 		}
5345 
5346 		if (eptr->type == E_TEXT)
5347 		{
5348 			length = length + eptr->edata_len - 1;
5349 		}
5350 		else if (eptr->type == E_LINEFEED)
5351 		{
5352 			length = length + 1;
5353 		}
5354 		eptr = eptr->next;
5355 	}
5356 
5357 	text = (char *)malloc(length + 1);
5358 	if (text == NULL)
5359 	{
5360 		fprintf(stderr, "No space for return string\n");
5361 		return(NULL);
5362 	}
5363 	strcpy(text, "");
5364 
5365 	tptr = text;
5366 
5367 	eptr = hw->html.formatted_elements;
5368 	while (eptr != NULL)
5369 	{
5370 		/*
5371 		 * Skip the special internal text
5372 		 */
5373 		if (eptr->internal == True)
5374 		{
5375 			eptr = eptr->next;
5376 			continue;
5377 		}
5378 
5379 		if (eptr->type == E_TEXT)
5380 		{
5381 			if (eptr == sel_start)
5382 			{
5383 				*startp = (char *)(tptr + start_pos);
5384 			}
5385 
5386 			if (eptr == sel_end)
5387 			{
5388 				*endp = (char *)(tptr + end_pos);
5389 			}
5390 
5391 			if (eptr == insert_start)
5392 			{
5393 				*insertp = (char *)(tptr + insert_pos);
5394 			}
5395 
5396 			strcat(text, (char *)eptr->edata);
5397 			tptr = tptr + eptr->edata_len - 1;
5398 		}
5399 		else if (eptr->type == E_LINEFEED)
5400 		{
5401 			if (eptr == sel_start)
5402 			{
5403 				*startp = tptr;
5404 			}
5405 
5406 			if (eptr == sel_end)
5407 			{
5408 				*endp = tptr;
5409 			}
5410 
5411 			if (eptr == insert_start)
5412 			{
5413 				*insertp = tptr;
5414 			}
5415 
5416 			strcat(text, " ");
5417 			tptr = tptr + 1;
5418 		}
5419 		eptr = eptr->next;
5420 	}
5421 	return(text);
5422 }
5423 
5424 
5425 /*
5426  * Convenience function to set the raw text into the widget.
5427  * Forces a reparse and a reformat.
5428  * If any pointer is passed in as NULL that text is unchanged,
5429  * if a pointer points to an empty string, that text is set to NULL;
5430  * Also pass an element ID to set the view area to that section of the new
5431  * text.  Finally pass an anchor NAME to set position of the new text
5432  * to that anchor.
5433  */
5434 void
5435 #ifdef _NO_PROTO
HTMLSetText(w,text,header_text,footer_text,element_id,target_anchor,ptr)5436 HTMLSetText (w, text, header_text, footer_text, element_id, target_anchor, ptr)
5437 	Widget w;
5438 	char *text;
5439 	char *header_text;
5440 	char *footer_text;
5441 	int element_id;
5442 	char *target_anchor;
5443 	void *ptr;
5444 #else
5445 HTMLSetText(Widget w, char *text, char *header_text, char *footer_text, int element_id, char *target_anchor, void *ptr)
5446 #endif
5447 {
5448 	HTMLWidget hw = (HTMLWidget)w;
5449 	WidgetInfo *wptr = (WidgetInfo *)ptr;
5450 	struct ele_rec *start;
5451 	struct ele_rec *eptr;
5452 	int newy;
5453 
5454 	if ((text == NULL)&&(header_text == NULL)&&(footer_text == NULL))
5455 	{
5456 		return;
5457 	}
5458 
5459 	/*
5460 	 * Free up the old visited href list.
5461 	 */
5462 	FreeHRefs(hw->html.my_visited_hrefs);
5463 	hw->html.my_visited_hrefs = NULL;
5464 
5465 	/*
5466 	 * Free up the old visited delayed images list.
5467 	 */
5468 	FreeDelayedImages(hw->html.my_delayed_images);
5469 	hw->html.my_delayed_images = NULL;
5470 
5471 	/*
5472 	 * Hide any old widgets
5473 	 */
5474 	HideWidgets(hw);
5475 	hw->html.widget_list = wptr;
5476 	hw->html.form_list = NULL;
5477 
5478 	if (text != NULL)
5479 	{
5480 		if (*text == '\0')
5481 		{
5482 			text = NULL;
5483 		}
5484 		hw->html.raw_text = text;
5485 
5486 		/*
5487 		 * Free any old colors and pixmaps
5488 		 */
5489 		FreeColors(XtDisplay(hw),DefaultColormapOfScreen(XtScreen(hw)));
5490 		FreeImages(hw);
5491 
5492 		/*
5493 		 * Parse the raw text with the HTML parser
5494 		 */
5495 		hw->html.html_objects = HTMLParse(hw->html.html_objects,
5496 			hw->html.raw_text);
5497 		CallLinkCallbacks(hw);
5498 	}
5499 	if (header_text != NULL)
5500 	{
5501 		if (*header_text == '\0')
5502 		{
5503 			header_text = NULL;
5504 		}
5505 		hw->html.header_text = header_text;
5506 
5507 		/*
5508 		 * Parse the header text with the HTML parser
5509 		 */
5510 		hw->html.html_header_objects =
5511 			HTMLParse(hw->html.html_header_objects,
5512 			hw->html.header_text);
5513 	}
5514 	if (footer_text != NULL)
5515 	{
5516 		if (*footer_text == '\0')
5517 		{
5518 			footer_text = NULL;
5519 		}
5520 		hw->html.footer_text = footer_text;
5521 
5522 		/*
5523 		 * Parse the footer text with the HTML parser
5524 		 */
5525 		hw->html.html_footer_objects =
5526 			HTMLParse(hw->html.html_footer_objects,
5527 			hw->html.footer_text);
5528 	}
5529 
5530 	/*
5531 	 * Reformat the new text
5532 	 */
5533 	hw->html.max_pre_width = DocumentWidth(hw, hw->html.html_objects);
5534 	ReformatWindow(hw);
5535 
5536 	/*
5537 	 * If a target anchor is passed, override the element id
5538 	 * with the id of that anchor.
5539 	 */
5540 	if (target_anchor != NULL)
5541 	{
5542 		int id;
5543 
5544 		id = HTMLAnchorToId(w, target_anchor);
5545 		if (id != 0)
5546 		{
5547 			element_id = id;
5548 		}
5549 	}
5550 
5551 	/*
5552 	 * Position text at id specified, or at top if no position
5553 	 * specified.
5554 	 * Find the element corrsponding to the id passed in.
5555 	 */
5556 	eptr = NULL;
5557 	if (element_id != 0)
5558 	{
5559 		start = hw->html.formatted_elements;
5560 		while (start != NULL)
5561 		{
5562 			if (start->ele_id == element_id)
5563 			{
5564 				eptr = start;
5565 				break;
5566 			}
5567 			start = start->next;
5568 		}
5569 	}
5570 	if (eptr == NULL)
5571 	{
5572 		newy = 0;
5573 	}
5574 	else
5575 	{
5576 		newy = eptr->y - 2;
5577 	}
5578 	if (newy < 0)
5579 	{
5580 		newy = 0;
5581 	}
5582 	if (newy > (hw->html.doc_height - (int)hw->html.view_height))
5583 	{
5584 		newy = hw->html.doc_height - (int)hw->html.view_height;
5585 	}
5586 	if (newy < 0)
5587 	{
5588 		newy = 0;
5589 	}
5590 	hw->html.scroll_x = 0;
5591 	hw->html.scroll_y = newy;
5592 #ifdef DEBUG
5593 fprintf (stderr, "calling in HTMLSetText\n");
5594 #endif
5595 	ConfigScrollBars(hw);
5596 	ScrollWidgets(hw);
5597 
5598 	/*
5599 	 * Display the new text
5600 	 */
5601 	ViewClearAndRefresh(hw);
5602 
5603 	/*
5604 	 * Clear any previous selection
5605 	 */
5606 	hw->html.select_start = NULL;
5607 	hw->html.select_end = NULL;
5608 	hw->html.sel_start_pos = 0;
5609 	hw->html.sel_end_pos = 0;
5610 	hw->html.new_start = NULL;
5611 	hw->html.new_end = NULL;
5612 	hw->html.new_start_pos = 0;
5613 	hw->html.new_end_pos = 0;
5614 	hw->html.active_anchor = NULL;
5615 
5616         hw->html.cached_tracked_ele = NULL;
5617 }
5618 
5619 
5620 /*
5621  * To use faster TOLOWER as set up in HTMLparse.c
5622  */
5623 #ifdef NOT_ASCII
5624 #define TOLOWER(x)      (tolower(x))
5625 #else
5626 extern char map_table[];
5627 #define TOLOWER(x)      (map_table[x])
5628 #endif /* NOT_ASCII */
5629 
5630 
5631 /*
5632  * Convenience function to search the text of the HTML document as a single
5633  * white space separated string. Linefeeds are converted into spaces.
5634  *
5635  * Takes a pattern, pointers to the start and end blocks to store the
5636  * start and end of the match into.  Start is also used as the location to
5637  * start the search from for incremental searching.  If start is an invalid
5638  * position (id = 0).  Default start is the beginning of the document for
5639  * forward searching, and the end of the document for backwards searching.
5640  * The backward and caseless parameters I hope are self-explanatory.
5641  *
5642  * returns 1 on success
5643  *      (and the start and end positions of the match).
5644  * returns -1 otherwise (and start and end are unchanged).
5645  */
5646 int
5647 #ifdef _NO_PROTO
HTMLSearchText(w,pattern,m_start,m_end,backward,caseless)5648 HTMLSearchText (w, pattern, m_start, m_end, backward, caseless)
5649 	Widget w;
5650 	char *pattern;
5651 	ElementRef *m_start;
5652 	ElementRef *m_end;
5653 	int backward;
5654 	int caseless;
5655 #else
5656 HTMLSearchText (Widget w, char *pattern, ElementRef *m_start, ElementRef *m_end,
5657 		int backward, int caseless)
5658 #endif
5659 {
5660 	HTMLWidget hw = (HTMLWidget)w;
5661 	int found, equal;
5662 	char *match;
5663 	char *tptr;
5664 	char *mptr;
5665 	char cval;
5666 	struct ele_rec *eptr;
5667 	int s_pos;
5668 	struct ele_rec *s_eptr;
5669 	ElementRef s_ref, e_ref;
5670 	ElementRef *start, *end;
5671 
5672 	/*
5673 	 * If bad parameters are passed, just fail the search
5674 	 */
5675 	if ((pattern == NULL)||(*pattern == '\0')||
5676 		(m_start == NULL)||(m_end == NULL))
5677 	{
5678 		return(-1);
5679 	}
5680 
5681 	/*
5682 	 * If we are caseless, make a lower case copy of the pattern to
5683 	 * match to use in compares.
5684 	 *
5685 	 * remember to free this before returning
5686 	 */
5687 	if (caseless)
5688 	{
5689 		match = (char *)malloc(strlen(pattern) + 1);
5690 		tptr = pattern;
5691 		mptr = match;
5692 		while (*tptr != '\0')
5693 		{
5694 			*mptr = (char)TOLOWER((int)*tptr);
5695 			mptr++;
5696 			tptr++;
5697 		}
5698 		*mptr = '\0';
5699 	}
5700 	else
5701 	{
5702 		match = pattern;
5703 	}
5704 
5705 	/*
5706 	 * Slimy coding.  I later decided I didn't want to change start and
5707 	 * end if the search failed.  Rather than changing all the code,
5708 	 * I just copy it into locals here, and copy it out again if a match
5709 	 * is found.
5710 	 */
5711 	start = &s_ref;
5712 	end = &e_ref;
5713 	start->id = m_start->id;
5714 	start->pos = m_start->pos;
5715 	end->id = m_end->id;
5716 	end->pos = m_end->pos;
5717 
5718 	/*
5719 	 * Find the user specified start position.
5720 	 */
5721 	if (start->id > 0)
5722 	{
5723 		found = 0;
5724 		eptr = hw->html.formatted_elements;
5725 
5726 		while (eptr != NULL)
5727 		{
5728 			if (eptr->ele_id == start->id)
5729 			{
5730 				s_eptr = eptr;
5731 				found = 1;
5732 				break;
5733 			}
5734 			eptr = eptr->next;
5735 		}
5736 		/*
5737 		 * Bad start position, fail them out.
5738 		 */
5739 		if (!found)
5740 		{
5741 			if (caseless)
5742 			{
5743 				free(match);
5744 			}
5745 			return(-1);
5746 		}
5747 		/*
5748 		 * Sanify the start position
5749 		 */
5750 		s_pos = start->pos;
5751 		if (s_pos >= s_eptr->edata_len - 1)
5752 		{
5753 			s_pos = s_eptr->edata_len - 2;
5754 		}
5755 		if (s_pos < 0)
5756 		{
5757 			s_pos = 0;
5758 		}
5759 	}
5760 	else
5761 	{
5762 		/*
5763 		 * Default search starts at end for backward, and
5764 		 * beginning for forwards.
5765 		 */
5766 		if (backward)
5767 		{
5768 			s_eptr = hw->html.formatted_elements;
5769 			while (s_eptr->next != NULL)
5770 			{
5771 				s_eptr = s_eptr->next;
5772 			}
5773 			s_pos = s_eptr->edata_len - 2;
5774 		}
5775 		else
5776 		{
5777 			s_eptr = hw->html.formatted_elements;
5778 			s_pos = 0;
5779 		}
5780 	}
5781 
5782 	if (backward)
5783 	{
5784 		char *mend;
5785 
5786 		/*
5787 		 * Save the end of match here for easy end to start searching
5788 		 */
5789 		mend = match;
5790 		while (*mend != '\0')
5791 		{
5792 			mend++;
5793 		}
5794 		if (mend > match)
5795 		{
5796 			mend--;
5797 		}
5798 		found = 0;
5799 		equal = 0;
5800 		mptr = mend;
5801 
5802 		if (s_eptr != NULL)
5803 		{
5804 			eptr = s_eptr;
5805 		}
5806 		else
5807 		{
5808 			eptr = hw->html.formatted_elements;
5809 			while (eptr->next != NULL)
5810 			{
5811 				eptr = eptr->next;
5812 			}
5813 		}
5814 
5815 		while (eptr != NULL)
5816 		{
5817 			/*
5818 			 * Skip the special internal text
5819 			 */
5820 			if (eptr->internal == True)
5821 			{
5822 				eptr = eptr->prev;
5823 				continue;
5824 			}
5825 
5826 			if (eptr->type == E_TEXT)
5827 			{
5828 			    tptr = (char *)(eptr->edata + eptr->edata_len - 2);
5829 			    if (eptr == s_eptr)
5830 			    {
5831 				tptr = (char *)(eptr->edata + s_pos);
5832 			    }
5833 			    while (tptr >= eptr->edata)
5834 			    {
5835 				if (equal)
5836 				{
5837 					if (caseless)
5838 					{
5839 						cval =(char)TOLOWER((int)*tptr);
5840 					}
5841 					else
5842 					{
5843 						cval = *tptr;
5844 					}
5845 					while ((mptr >= match)&&
5846 						(tptr >= eptr->edata)&&
5847 						(cval == *mptr))
5848 					{
5849 						tptr--;
5850 						mptr--;
5851 					    if (tptr >= eptr->edata)
5852 					    {
5853 						if (caseless)
5854 						{
5855 						cval =(char)TOLOWER((int)*tptr);
5856 						}
5857 						else
5858 						{
5859 							cval = *tptr;
5860 						}
5861 					    }
5862 					}
5863 					if (mptr < match)
5864 					{
5865 						found = 1;
5866 						start->id = eptr->ele_id;
5867 						start->pos = (int)
5868 						    (tptr - eptr->edata + 1);
5869 						break;
5870 					}
5871 					else if (tptr < eptr->edata)
5872 					{
5873 						break;
5874 					}
5875 					else
5876 					{
5877 						equal = 0;
5878 					}
5879 				}
5880 				else
5881 				{
5882 					mptr = mend;
5883 					if (caseless)
5884 					{
5885 						cval =(char)TOLOWER((int)*tptr);
5886 					}
5887 					else
5888 					{
5889 						cval = *tptr;
5890 					}
5891 					while ((tptr >= eptr->edata)&&
5892 						(cval != *mptr))
5893 					{
5894 						tptr--;
5895 					    if (tptr >= eptr->edata)
5896 					    {
5897 						if (caseless)
5898 						{
5899 						cval =(char)TOLOWER((int)*tptr);
5900 						}
5901 						else
5902 						{
5903 							cval = *tptr;
5904 						}
5905 					    }
5906 					}
5907 					if ((tptr >= eptr->edata)&&
5908 						(cval == *mptr))
5909 					{
5910 						equal = 1;
5911 						end->id = eptr->ele_id;
5912 						end->pos = (int)
5913 						    (tptr - eptr->edata + 1);
5914 					}
5915 				}
5916 			    }
5917 			}
5918 			/*
5919 			 * Linefeeds match to single space characters.
5920 			 */
5921 			else if (eptr->type == E_LINEFEED)
5922 			{
5923 				if (equal)
5924 				{
5925 					if (*mptr == ' ')
5926 					{
5927 						mptr--;
5928 						if (mptr < match)
5929 						{
5930 							found = 1;
5931 							start->id =eptr->ele_id;
5932 							start->pos = 0;
5933 						}
5934 					}
5935 					else
5936 					{
5937 						equal = 0;
5938 					}
5939 				}
5940 				else
5941 				{
5942 					mptr = mend;
5943 					if (*mptr == ' ')
5944 					{
5945 						equal = 1;
5946 						end->id = eptr->ele_id;
5947 						end->pos = 0;
5948 						mptr--;
5949 						if (mptr < match)
5950 						{
5951 							found = 1;
5952 							start->id =eptr->ele_id;
5953 							start->pos = 0;
5954 						}
5955 					}
5956 				}
5957 			}
5958 			if (found)
5959 			{
5960 				break;
5961 			}
5962 			eptr = eptr->prev;
5963 		}
5964 	}
5965 	else /* forward */
5966 	{
5967 		found = 0;
5968 		equal = 0;
5969 		mptr = match;
5970 
5971 		if (s_eptr != NULL)
5972 		{
5973 			eptr = s_eptr;
5974 		}
5975 		else
5976 		{
5977 			eptr = hw->html.formatted_elements;
5978 		}
5979 
5980 		while (eptr != NULL)
5981 		{
5982 			/*
5983 			 * Skip the special internal text
5984 			 */
5985 			if (eptr->internal == True)
5986 			{
5987 				eptr = eptr->next;
5988 				continue;
5989 			}
5990 
5991 			if (eptr->type == E_TEXT)
5992 			{
5993 			    tptr = eptr->edata;
5994 			    if (eptr == s_eptr)
5995 			    {
5996 				tptr = (char *)(tptr + s_pos);
5997 			    }
5998 			    while (*tptr != '\0')
5999 			    {
6000 				if (equal)
6001 				{
6002 					if (caseless)
6003 					{
6004 						cval =(char)TOLOWER((int)*tptr);
6005 					}
6006 					else
6007 					{
6008 						cval = *tptr;
6009 					}
6010 					while ((*mptr != '\0')&&
6011 						(cval == *mptr))
6012 					{
6013 						tptr++;
6014 						mptr++;
6015 						if (caseless)
6016 						{
6017 						cval =(char)TOLOWER((int)*tptr);
6018 						}
6019 						else
6020 						{
6021 							cval = *tptr;
6022 						}
6023 					}
6024 					if (*mptr == '\0')
6025 					{
6026 						found = 1;
6027 						end->id = eptr->ele_id;
6028 						end->pos = (int)
6029 							(tptr - eptr->edata);
6030 						break;
6031 					}
6032 					else if (*tptr == '\0')
6033 					{
6034 						break;
6035 					}
6036 					else
6037 					{
6038 						equal = 0;
6039 					}
6040 				}
6041 				else
6042 				{
6043 					mptr = match;
6044 					if (caseless)
6045 					{
6046 						cval =(char)TOLOWER((int)*tptr);
6047 					}
6048 					else
6049 					{
6050 						cval = *tptr;
6051 					}
6052 					while ((*tptr != '\0')&&
6053 						(cval != *mptr))
6054 					{
6055 						tptr++;
6056 						if (caseless)
6057 						{
6058 						cval =(char)TOLOWER((int)*tptr);
6059 						}
6060 						else
6061 						{
6062 							cval = *tptr;
6063 						}
6064 					}
6065 					if (cval == *mptr)
6066 					{
6067 						equal = 1;
6068 						start->id = eptr->ele_id;
6069 						start->pos = (int)
6070 							(tptr - eptr->edata);
6071 					}
6072 				}
6073 			    }
6074 			}
6075 			else if (eptr->type == E_LINEFEED)
6076 			{
6077 				if (equal)
6078 				{
6079 					if (*mptr == ' ')
6080 					{
6081 						mptr++;
6082 						if (*mptr == '\0')
6083 						{
6084 							found = 1;
6085 							end->id = eptr->ele_id;
6086 							end->pos = 0;
6087 						}
6088 					}
6089 					else
6090 					{
6091 						equal = 0;
6092 					}
6093 				}
6094 				else
6095 				{
6096 					mptr = match;
6097 					if (*mptr == ' ')
6098 					{
6099 						equal = 1;
6100 						start->id = eptr->ele_id;
6101 						start->pos = 0;
6102 						mptr++;
6103 						if (*mptr == '\0')
6104 						{
6105 							found = 1;
6106 							end->id = eptr->ele_id;
6107 							end->pos = 0;
6108 						}
6109 					}
6110 				}
6111 			}
6112 			if (found)
6113 			{
6114 				break;
6115 			}
6116 			eptr = eptr->next;
6117 		}
6118 	}
6119 
6120 	if (found)
6121 	{
6122 		m_start->id = start->id;
6123 		m_start->pos = start->pos;
6124 		m_end->id = end->id;
6125 		m_end->pos = end->pos;
6126 	}
6127 
6128 	if (caseless)
6129 	{
6130 		free(match);
6131 	}
6132 
6133 	if (found)
6134 	{
6135 		return(1);
6136 	}
6137 	else
6138 	{
6139 		return(-1);
6140 	}
6141 }
6142 
6143