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