Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / DtHelp / Callbacks.c
1 /* $XConsortium: Callbacks.c /main/21 1996/10/22 12:22:33 cde-hp $ */
2 /************************************<+>*************************************
3  ****************************************************************************
4  **
5  **   File:        Callbacks.c
6  **
7  **   Project:     Display Area Library
8  **
9  **  
10  **   Description: This body of code handles the callbacks for the
11  **                Display Area.
12  **
13  ****************************************************************************
14  ************************************<+>*************************************/
15 /*
16  * (c) Copyright 1996 Digital Equipment Corporation.
17  * (c) Copyright 1987-1994, 1996 Hewlett-Packard Company.
18  * (c) Copyright 1993, 1994, 1996 International Business Machines Corp.
19  * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.
20  * (c) Copyright 1993, 1994, 1996 Novell, Inc. 
21  * (c) Copyright 1996 FUJITSU LIMITED.
22  * (c) Copyright 1996 Hitachi.
23  */
24
25 /*
26  * system includes
27  */
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <limits.h>
31 #include <X11/Xlib.h>
32 #include <X11/Xatom.h>
33 #include <X11/Intrinsic.h>
34 #include <Xm/Xm.h>
35 #include <Xm/AtomMgr.h>
36 #include <Xm/DrawnB.h>
37 #include <Xm/CutPaste.h>
38
39
40 /*
41  * Canvas Engine
42  */
43 #include "CanvasP.h"
44
45 /*
46  * private includes
47  */
48 #include "DisplayAreaP.h"
49 #include "CallbacksI.h"
50 #include "FontI.h"
51 #include "FontAttrI.h"
52 #include "HyperTextI.h"
53 #include "SetListI.h"
54 #include "HelposI.h"
55 #include "XInterfaceI.h"
56
57 #ifdef NLS16
58 #endif
59
60 /********    Private Function Declarations    ********/
61 static  Boolean  ConvertSelectionCB (
62                         Widget           widget,
63                         Atom            *selection,
64                         Atom            *target,
65                         Atom            *type,
66                         XtPointer       *value,
67                         unsigned long   *length,
68                         int             *format );
69 static  void     ScrollTimerCB (
70                         XtPointer        client_data,
71                         XtIntervalId    *id );
72 static  void     StartSelection (
73                         Widget          widget,
74                         XtPointer       client_data );
75 /********    End Private Function Declarations    ********/
76
77 /********    Private Defines                 ********/
78 #define SCROLL_BAR_FLAGS 0x03
79 #define HORIZONTAL       0
80 #define VERTICAL         1
81
82 /********    End Private Defines             ********/
83
84 /********    Private Variable Declarations    ********/
85
86 /********    End Private Variable Declarations    ********/
87
88 /******************************************************************************
89  *                             Private Functions
90  ******************************************************************************/
91 /*****************************************************************************
92  * Function: ConvertSelectionCB
93  *
94  *    ConvertSelectionCB - this routine is called when someone asks for
95  *                              our selection.
96  *
97  *****************************************************************************/
98 static  Boolean
99 ConvertSelectionCB (
100         Widget           widget,
101         Atom            *selection,
102         Atom            *target,
103         Atom            *type,
104         XtPointer       *value,
105         unsigned long   *length,
106         int             *format )
107 {
108     Atom  TARGETS    = XmInternAtom(XtDisplay(widget), "TARGETS"  , False);
109     Atom  TIMESTAMP  = XmInternAtom(XtDisplay(widget), "TIMESTAMP", False);
110     Atom  TEXT       = XmInternAtom(XtDisplay(widget), "TEXT"     , False);
111     Atom  CMP_TEXT   = XmInternAtom(XtDisplay(widget), "COMPOUND_TEXT",False);
112     Atom  LOCALE;
113     int   retStatus  = 0;
114     char *testString = "ABC";  /* these are characters in XPCS, so... safe */
115     char *tmpString  = NULL;
116     Arg    args[2];
117     DtHelpDispAreaStruct *pDAS;
118
119     XTextProperty  tmpProp;
120
121     XtSetArg(args[0], XmNuserData, &pDAS);
122     XtGetValues(widget, args, 1);
123
124     if (pDAS == NULL || pDAS->primary == False || *selection != XA_PRIMARY)
125         return False;
126
127     retStatus = XmbTextListToTextProperty(XtDisplay(widget), &testString, 1,
128                                 (XICCEncodingStyle)XTextStyle, &tmpProp);
129
130     LOCALE = (Atom) 9999; /* XmbTextList... should always be able
131                                      * to convert XPCS characters; but in
132                                      * case its broken, this prevents a core
133                                      * dump.
134                                      */
135     if (retStatus == Success)
136       {
137         LOCALE = tmpProp.encoding;
138         XFree(tmpProp.value);
139       }
140
141     /*
142      * List the targets understood
143      */
144     if (*target == TARGETS)
145       {
146         Atom *targs = (Atom *)XtMalloc((unsigned) (5 * sizeof(Atom)));
147
148         *value   = (char *) targs;
149         *targs++ = LOCALE;
150         *targs++ = TIMESTAMP;
151         *targs++ = TEXT;
152         *targs++ = CMP_TEXT;
153         *targs++ = XA_STRING;
154
155         *type   = XA_ATOM;
156         *length = (5 * sizeof(Atom)) >> 2;
157         *format = 32;
158       }
159     else if (*target == TIMESTAMP)
160       {
161         Time *timestamp;
162         timestamp  = (Time *) XtMalloc(sizeof(Time));
163         *timestamp = pDAS->anchor_time;
164
165         *value  = (char *) timestamp;
166         *type   = XA_INTEGER;
167         *length = sizeof(Time);
168         *format = 32;
169       }
170     else if (*target == XA_STRING)
171       {
172         /*
173          * initialize the return type here in case we fail
174          */
175         *type   = (Atom) XA_STRING;
176         *format = 8;
177
178         /*
179          * get the string
180          */
181         _DtCanvasGetSelection (pDAS->canvas,
182                                 (_DtCvSELECTED_TEXT | _DtCvSELECTED_REGION),
183                                                 (_DtCvPointer *)(&tmpString));
184         retStatus = -1;
185         if (tmpString != NULL && *tmpString != '\0')
186             retStatus = XmbTextListToTextProperty(XtDisplay(widget),
187                                 &tmpString, 1,
188                                 (XICCEncodingStyle)XStringStyle, &tmpProp);
189
190         /*
191          * free the original copy of the string and check the results
192          */
193         if (tmpString != NULL)
194             free(tmpString);
195
196         if (retStatus == Success || retStatus > 0)
197           {
198             *value  = (XtPointer) tmpProp.value;
199             *length = tmpProp.nitems;
200           }
201         else
202           {
203             *value = NULL;
204             *length = 0;
205             return False;
206           }
207       }
208     else if (*target == TEXT)
209       {
210         /*
211          * set the type and format to those calculated
212          */
213         *type   = TEXT;
214         *format = 8;
215
216         /*
217          * get the string
218          */
219         _DtCanvasGetSelection (pDAS->canvas, 
220                                 (_DtCvSELECTED_TEXT | _DtCvSELECTED_REGION),
221                                                 (_DtCvPointer *)(&tmpString));
222
223         retStatus = -1;
224         if (tmpString != NULL && *tmpString != '\0')
225             retStatus = XmbTextListToTextProperty(XtDisplay(widget),
226                                 &tmpString, 1,
227                                 (XICCEncodingStyle)XStdICCTextStyle, &tmpProp);
228
229         /*
230          * free the original copy of the string and check the results
231          */
232         if (tmpString != NULL)
233             free(tmpString);
234
235         if (retStatus == Success || retStatus > 0)
236           {
237             *value  = (XtPointer) tmpProp.value;
238             *length = tmpProp.nitems;
239           }
240         else
241           {
242             *value = NULL;
243             *length = 0;
244             return False;
245           }
246       }
247     else if (*target == LOCALE)
248       {
249         /*
250          * pass the string straight through
251          */
252         *type   = LOCALE;
253         *format = 8;
254
255         _DtCanvasGetSelection (pDAS->canvas, 
256                                 (_DtCvSELECTED_TEXT | _DtCvSELECTED_REGION),
257                                                 (_DtCvPointer *)(value));
258         *length = 0;
259         if (*value != NULL)
260             *length = strlen((char *)(*value));
261       }
262     else if (*target == CMP_TEXT)
263       {
264         *type   = CMP_TEXT;
265         *format = 8;
266
267         /*
268          * get the selected text.
269          */
270         _DtCanvasGetSelection (pDAS->canvas, 
271                                 (_DtCvSELECTED_TEXT | _DtCvSELECTED_REGION),
272                                                 (_DtCvPointer *)(&tmpString));
273
274         retStatus = -1;
275         if (tmpString != NULL && *tmpString != '\0')
276             retStatus = XmbTextListToTextProperty(XtDisplay(widget),
277                         &tmpString, 1,
278                         (XICCEncodingStyle)XCompoundTextStyle, &tmpProp);
279
280         /*
281          * free the original copy of the string and check the results
282          */
283         if (tmpString != NULL)
284             free(tmpString);
285
286         if (retStatus == Success || retStatus > 0)
287           {
288             *value  = (XtPointer) tmpProp.value;
289             *length = tmpProp.nitems;
290           }
291         else
292           {
293             *value = NULL;
294             *length = 0;
295             return False;
296           }
297       }
298     else
299         return False;
300
301     return True;
302
303 } /* End ConvertSelectionCB */
304
305 /*****************************************************************************
306  * Function: ScrollTimerCB
307  *
308  *    ScrollTimerCB - This routine is called when we have a timer
309  *              go off with the mouse outside the Display Area during a
310  *              selection.
311  *
312  *****************************************************************************/
313 static  void
314 ScrollTimerCB (
315         XtPointer        client_data,   /*  data from applicaiton   */
316         XtIntervalId    *id )           /*  timer id                */
317 {
318     int    diffY = 0;
319     int    diffX = 0;
320     int    x;
321     int    y;
322     int    scrollTimeOut;
323     int    maxY;
324     int    dispY;
325     Arg    args[2];
326     XmScrollBarCallbackStruct callData;
327     DtHelpDispAreaStruct  *pDAS = (DtHelpDispAreaStruct *) client_data;
328
329     if (*id != pDAS->scr_timer_id)
330       return;
331
332     pDAS->scr_timer_id = NULL;
333
334     maxY  = pDAS->maxYpos;
335     dispY = pDAS->firstVisible + pDAS->dispUseHeight;
336
337     if ((pDAS->scr_timer_data.vertical_reason == XmCR_INCREMENT && maxY <= dispY)
338                 ||
339         (pDAS->scr_timer_data.vertical_reason == XmCR_DECREMENT &&
340                 !pDAS->firstVisible))
341         pDAS->scr_timer_data.vertical_reason = XmCR_NONE;
342
343     if ((pDAS->scr_timer_data.horizontal_reason == XmCR_INCREMENT &&
344         pDAS->maxX <= pDAS->virtualX + ((int)pDAS->dispUseWidth))
345                 ||
346         (pDAS->scr_timer_data.horizontal_reason == XmCR_DECREMENT &&
347                 !pDAS->virtualX))
348         pDAS->scr_timer_data.horizontal_reason = XmCR_NONE;
349
350     if ( pDAS->scr_timer_data.vertical_reason == XmCR_NONE &&
351                 pDAS->scr_timer_data.horizontal_reason == XmCR_NONE)
352         return;
353
354     y = pDAS->firstVisible;
355     if (pDAS->scr_timer_data.vertical_reason == XmCR_NONE)
356         y = pDAS->scr_timer_y - pDAS->decorThickness;
357     else if (pDAS->scr_timer_data.vertical_reason == XmCR_INCREMENT)
358       {
359         y = y + pDAS->dispUseHeight + pDAS->lineHeight;
360         if (y > pDAS->maxYpos)
361             y = pDAS->maxYpos;
362
363         diffY = y - pDAS->firstVisible - pDAS->dispUseHeight;
364       }
365     else if (pDAS->scr_timer_data.vertical_reason == XmCR_DECREMENT)
366       {
367         y -= pDAS->lineHeight;
368         if (y < 0)
369             y = 0;
370
371         diffY = y - pDAS->firstVisible;
372       }
373
374     if (pDAS->scr_timer_data.horizontal_reason == XmCR_NONE)
375         x = pDAS->scr_timer_x - pDAS->decorThickness;
376     else
377       {
378         if (pDAS->scr_timer_data.horizontal_reason == XmCR_INCREMENT)
379           {
380             diffX = (int) (pDAS->charWidth / 10);
381             x = pDAS->dispUseWidth;
382
383             if (x + pDAS->virtualX + diffX > pDAS->maxX)
384                 diffX = pDAS->maxX - x - pDAS->virtualX;
385           }
386         else if (pDAS->scr_timer_data.horizontal_reason == XmCR_DECREMENT)
387           {
388             diffX = -((int)(pDAS->charWidth / 10));
389             x = 0;
390
391             if (pDAS->virtualX + diffX < 0)
392                 diffX = -(pDAS->virtualX);
393           }
394       }
395    
396     _DtCanvasProcessSelection (pDAS->canvas,
397                         (x + diffX + pDAS->virtualX - pDAS->decorThickness),
398                         y, _DtCvSELECTION_UPDATE);
399
400     callData.event = NULL;
401     if (diffX)
402       {
403         scrollTimeOut   = pDAS->horz_rep_scr;
404         callData.reason = pDAS->scr_timer_data.horizontal_reason;
405         callData.value  = pDAS->virtualX + diffX;
406         _DtHelpHorzScrollCB (pDAS->horzScrollWid, client_data,
407                                         (XtPointer) &callData);
408
409         if (pDAS->horzScrollWid)
410           {
411             XtSetArg (args[0], XmNvalue, pDAS->virtualX);
412             XtSetValues (pDAS->horzScrollWid, args, 1);
413           }
414
415         if (diffY != 0 && pDAS->vertScrollWid)
416           {
417             XtSetArg (args[0], XmNvalue, y);
418             XtSetValues (pDAS->vertScrollWid, args, 1);
419             if (pDAS->vScrollNotify)
420               (pDAS->vScrollNotify)(pDAS->clientData, y);
421           }
422       }
423     else
424       {
425         scrollTimeOut   = pDAS->vert_rep_scr;
426         callData.reason = pDAS->scr_timer_data.vertical_reason;
427         callData.value  = pDAS->firstVisible + diffY;
428         _DtHelpVertScrollCB (pDAS->vertScrollWid, client_data,
429                                         (XtPointer) &callData);
430
431         if (pDAS->vertScrollWid)
432           {
433             XtSetArg (args[0], XmNvalue, pDAS->firstVisible);
434             XtSetValues (pDAS->vertScrollWid, args, 1);
435             if (pDAS->vScrollNotify)
436               (pDAS->vScrollNotify)(pDAS->clientData, pDAS->firstVisible);
437           }
438       }
439
440     pDAS->scr_timer_id = XtAppAddTimeOut (
441                 XtWidgetToApplicationContext (pDAS->dispWid),
442                 ((unsigned long) scrollTimeOut),
443                 ScrollTimerCB, client_data);
444
445 } /* End ScrollTimerCB */
446
447 /******************************************************************************
448  * Function: DrawWholeCanvas
449  *
450  *****************************************************************************/
451 static void
452 DrawWholeCanvas(
453     DtHelpDispAreaStruct  *pDAS)
454 {
455     _DtCvUnit    top;
456     _DtCvUnit    bottom;
457     _DtCvUnit    right;
458     _DtCvUnit    next_y;
459
460     _DtCanvasMoveTraversal(pDAS->canvas,_DtCvTRAVERSAL_OFF, False,
461                                 (XtIsRealized(pDAS->dispWid) ? True : False),
462                                 NULL, NULL, NULL, NULL, NULL);
463
464     top     = pDAS->firstVisible;
465     bottom  = top + pDAS->dispUseHeight;
466     right   = pDAS->virtualX + pDAS->dispUseWidth;
467
468     _DtCanvasRender (pDAS->canvas, pDAS->virtualX, top, right, bottom,
469                      pDAS->render_type, _DtCvTRUE, NULL, &next_y);
470     pDAS->nextNonVisible =
471         (pDAS->render_type == _DtCvRENDER_PARTIAL) ? bottom : next_y;
472
473     /*
474      * If we have a hypertext link boxed, draw it
475      */
476     _DtCanvasMoveTraversal(pDAS->canvas, _DtCvTRAVERSAL_ON, False,
477                                 (XtIsRealized(pDAS->dispWid) ? True : False),
478                                         NULL, NULL, NULL, NULL, NULL);
479     /*
480      * if the toc exists within this area, draw it.
481      */
482     if ((pDAS->toc_flag & _DT_HELP_TOC_ON) &&
483                 pDAS->toc_y + pDAS->toc_height >= top && pDAS->toc_y <  bottom)
484         _DtHelpDATocMarker((XtPointer) pDAS, True);
485
486 } /* End DrawWholeCanvas */
487
488 /******************************************************************************
489  *                          Semi Public Functions
490  *****************************************************************************/
491 /******************************************************************************
492  * Function: _DtHelpCleanAndDrawWholeCanvas
493  *
494  *****************************************************************************/
495 void
496 _DtHelpCleanAndDrawWholeCanvas(
497     XtPointer  client_data)
498 {
499     DtHelpDispAreaStruct  *pDAS = (DtHelpDispAreaStruct *) client_data;
500
501     XClearArea (XtDisplay(pDAS->dispWid), XtWindow(pDAS->dispWid),
502                                 pDAS->decorThickness, pDAS->decorThickness,
503                                 pDAS->dispUseWidth,
504                                 pDAS->dispUseHeight,
505                                 False);
506     DrawWholeCanvas (pDAS);
507
508 }
509
510 void
511 _DtHelpSearchMoveTraversal(XtPointer client_data, int search_hit_index)
512 {
513     _DtCvUnit baseline, ascend, descend;
514
515     DtHelpDispAreaStruct *pDAS = (DtHelpDispAreaStruct *) client_data;
516
517     if (_DtCvGetSearchLineMetrics(pDAS->canvas, search_hit_index,
518                                         &baseline, &descend, &ascend) == 0) {
519
520         _DtCvUnit top, hitY, height;
521
522         top    = pDAS->firstVisible;
523         hitY   = baseline - ascend - pDAS->lineThickness;
524         height = ascend + descend + 2 * pDAS->lineThickness;
525
526         if (hitY < top)
527             top = hitY;
528         else if (hitY + height > top + ((int) pDAS->dispUseHeight))
529             top = hitY + height - ((int) pDAS->dispUseHeight);
530
531         if (top != pDAS->firstVisible) {
532
533             _DtCvUnit dispUseHeightHalf =
534                         pDAS->dispUseHeight / 2 + pDAS->dispUseHeight % 2;
535
536             /* put search hit in the middle of the viewport */
537             if (top == hitY)
538                 top -= dispUseHeightHalf - height;
539             else {
540                 top += dispUseHeightHalf + height;
541                 if (top + ((int)pDAS->dispUseHeight) > pDAS->maxYpos)
542                     top = pDAS->maxYpos - pDAS->dispUseHeight;
543             }
544             if (top < 0)
545                 top = 0;
546
547             if (top != pDAS->firstVisible) {
548
549                 Arg arg;
550
551                 pDAS->firstVisible = top;
552
553                 XtSetArg(arg, XmNvalue, pDAS->firstVisible);
554                 XtSetValues(pDAS->vertScrollWid, &arg, 1);
555
556                 if (pDAS->vScrollNotify)
557                   (pDAS->vScrollNotify)(pDAS->clientData, pDAS->firstVisible);
558
559                 _DtHelpCleanAndDrawWholeCanvas(pDAS);
560             }
561         }
562     }
563 }
564
565 /******************************************************************************
566  * Function: _DtHelpCancelSelection
567  *
568  * Returns : True    if a selection was active and cancelled.
569  *           False   if a selection was not active.
570  *
571  *****************************************************************************/
572 Boolean
573 _DtHelpCancelSelection(
574     XtPointer  client_data)
575 {
576     Boolean selActive = False;
577     DtHelpDispAreaStruct  *pDAS = (DtHelpDispAreaStruct *) client_data;
578
579     if (pDAS->select_state == _DtHelpSelectingText && pDAS->primary == True)
580       {
581         selActive = True;
582         if (pDAS->scr_timer_id)
583           {
584             XtRemoveTimeOut (pDAS->scr_timer_id);
585             pDAS->scr_timer_id = NULL;
586           }
587         _DtHelpClearSelection (client_data);
588       }
589
590     return selActive;
591 }
592
593 /******************************************************************************
594  *                          Public Functions
595  *****************************************************************************/
596 /******************************************************************************
597  * Function: _DtHelpExposeCB
598  *
599  *    _DtHelpExposeCB handles the exposure events for a Text Graphic Area.
600  *
601  *****************************************************************************/
602 void
603 _DtHelpExposeCB(
604         Widget  widget,
605         XtPointer client_data,
606         XtPointer call_data )
607 {
608     Arg    args[4];
609
610     Dimension  height;
611     Dimension  width;
612
613     DtHelpDispAreaStruct *pDAS = (DtHelpDispAreaStruct *) client_data;
614
615     XmDrawnButtonCallbackStruct *callback =
616                                 (XmDrawnButtonCallbackStruct *) call_data;
617
618     if (callback->reason != XmCR_EXPOSE ||
619                 (pDAS->neededFlags & (1 << (VisibilityFullyObscured + 3))))
620         return;
621
622     /*
623      * get the width and height.
624      */
625     XtSetArg(args[0], XmNwidth, &width);
626     XtSetArg(args[1], XmNheight, &height);
627     XtGetValues(widget, args, 2);
628
629     /*
630      * if this exposure is a result of a resize,
631      * wait for the resize to handle it.
632      */
633     if (width != pDAS->dispWidth || height != pDAS->dispHeight)
634         return;
635
636     if (!(callback->event) || callback->event->xexpose.count)
637         return;
638
639     /*
640      * re-draw the information in the display area
641      */
642     DrawWholeCanvas (pDAS);
643
644 }  /* End _DtHelpExposeCB */
645
646 /*********************************************************************
647  * Function: _DtHelpResizeCB
648  *
649  *    _DtHelpResizeCB handles the exposure events for a Text Graphic Area.
650  *
651  *********************************************************************/
652 void
653 _DtHelpResizeCB(
654         Widget  widget,
655         XtPointer client_data,
656         XtPointer call_data )
657 {
658     Arg  args[4];
659     Dimension width;
660     Dimension height;
661
662     DtHelpDispAreaStruct *pDAS = (DtHelpDispAreaStruct *) client_data;
663     XmDrawnButtonCallbackStruct *callback =
664                                 (XmDrawnButtonCallbackStruct *) call_data;
665
666     if (callback->reason != XmCR_RESIZE)
667         return;
668
669     /*
670      * get the width and height of the form.
671      */
672     XtSetArg(args[0], XmNwidth, &width);
673     XtSetArg(args[1], XmNheight, &height);
674     XtGetValues(XtParent(widget), args, 2);
675     if (width == pDAS->formWidth && height == pDAS->formHeight)
676         return;
677
678     pDAS->formWidth  = width;
679     pDAS->formHeight = height;
680
681     /*
682      * get the width and height.
683      */
684     XtSetArg(args[0], XmNwidth, &width);
685     XtSetArg(args[1], XmNheight, &height);
686     XtGetValues(widget, args, 2);
687
688     if (width == pDAS->dispWidth && height == pDAS->dispHeight)
689         return;
690
691     /*
692
693     _DtHelpClearSelection (pDAS);
694      * reset the scroll bars and possibly reformat the text for the size.
695      */
696     (void) _DtHelpSetScrollBars (client_data, width, height);
697     if (XtIsRealized (pDAS->dispWid))
698         _DtHelpCleanAndDrawWholeCanvas (client_data);
699
700     /*
701      * I will get an expose event after the resize.
702      */
703
704 }  /* End _DtHelpResizeCB */
705
706 /***************************************************************************
707  * Function:  _DtHelpVertScrollCB
708  *
709  * _DtHelpVertScrollCB is called when the vertical scroll bar is changed.
710  *
711  **************************************************************************/
712 void 
713 _DtHelpVertScrollCB(
714         Widget widget,
715         XtPointer clientData,
716         XtPointer callData )
717 {
718     DtHelpDispAreaStruct      *pDAS     = (DtHelpDispAreaStruct *) clientData;
719     XmScrollBarCallbackStruct *callBack =
720                                         (XmScrollBarCallbackStruct *) callData;
721     int         diff   = pDAS->lineHeight;
722     int         srcY, dstY;
723     int         clearY;
724     int         reason = callBack->reason;
725     _DtCvUnit   absTop;
726     _DtCvUnit   absBot;
727     Display    *dpy;
728     Window      win;
729   
730     /*
731      * if the policy is XmEXPLICIT, don't want the focus on the scrollbar
732      */
733     if (callBack->event != NULL && callBack->event->type == ButtonPress &&
734               _XmGetFocusPolicy(XtParent(XtParent(pDAS->dispWid))) != XmPOINTER)
735         XmProcessTraversal(pDAS->dispWid, XmTRAVERSE_CURRENT);
736
737     /*
738      * check to make sure we don't do a rerender when we don't have to.
739      */
740     if (pDAS->firstVisible == callBack->value)
741         return;
742
743     /* If a drag occured, reset the reason to increment, decrement, page    */
744     /* increment, or page decrement depending on the distance and direction */
745     /* dragged. */
746     if (callBack->reason == XmCR_DRAG || callBack->reason == XmCR_VALUE_CHANGED)
747       {
748         diff = callBack->value - pDAS->firstVisible;
749
750         if (diff > 0 && diff <= ((int) pDAS->dispUseHeight))
751             reason = XmCR_INCREMENT;
752         else if (diff < 0 && -(diff) <= ((int) pDAS->dispUseHeight))
753           {
754             reason = XmCR_DECREMENT;
755             diff   = -diff;
756           }
757         else if (diff > ((int) pDAS->dispUseHeight))
758             reason = XmCR_PAGE_DECREMENT;
759         else
760             reason = XmCR_PAGE_INCREMENT;
761       }
762     else if (callBack->reason == XmCR_INCREMENT ||
763                                         callBack->reason == XmCR_DECREMENT)
764       {
765         diff = callBack->value - pDAS->firstVisible;
766         if (diff < 0)
767             diff = -diff;
768       }
769
770     /* Reset first visible to the returned scrollbar value. */
771     pDAS->firstVisible = callBack->value;
772
773     /* For page increment and decrement, call _DtHelpCleanAndDrawWholeCanvas
774      * to clear the view area and redisplay the text.
775      *
776      * For increment and decrement, 
777      * use XCopyArea to move the visible lines and draw the cleared out line.
778      */
779     if (!pDAS->maxYpos ||
780                 (pDAS->neededFlags & (1 << (VisibilityFullyObscured + 3))))
781         return;
782   
783     dpy = XtDisplay (widget);
784     win = XtWindow (pDAS->dispWid);
785
786     if (reason == XmCR_PAGE_INCREMENT || reason == XmCR_PAGE_DECREMENT ||
787                 reason == XmCR_TO_TOP || reason == XmCR_TO_BOTTOM)
788         _DtHelpCleanAndDrawWholeCanvas (clientData);
789     else
790       {
791         if (reason == XmCR_INCREMENT)
792           {
793             dstY   = pDAS->decorThickness;
794             srcY   = dstY + diff;
795             clearY = pDAS->dispHeight - pDAS->decorThickness - diff;
796           }
797         else
798           {
799             srcY   = pDAS->decorThickness;
800             dstY   = srcY + diff;
801             clearY = srcY;
802           }
803         XCopyArea(dpy, win, win, pDAS->normalGC, pDAS->decorThickness, srcY,
804                 pDAS->dispUseWidth, (pDAS->dispUseHeight - diff),
805                 pDAS->decorThickness, dstY);
806
807         XClearArea(dpy, win, pDAS->decorThickness, clearY,
808                  pDAS->dispUseWidth, ((unsigned int) diff), False);
809
810         if (pDAS->neededFlags & (1 << (VisibilityPartiallyObscured + 3)))
811           {
812             /*
813              * redraw all the information
814              */
815             DrawWholeCanvas (pDAS);
816           }
817         else
818           {
819             /*
820              * draw the line that sits on the cleared line
821              */
822             absTop = clearY + pDAS->firstVisible - pDAS->decorThickness;
823             absBot = absTop + diff;
824
825             _DtCanvasRender (pDAS->canvas, 0, absTop,
826                                 pDAS->virtualX + pDAS->dispWidth, absBot,
827                                 _DtCvRENDER_PARTIAL, _DtCvFALSE, NULL, NULL);
828             /*
829              * if the toc exists within this area, draw it.
830              */
831             if ((pDAS->toc_flag & _DT_HELP_TOC_ON)
832                                 && pDAS->toc_y + pDAS->toc_height >= absTop
833                                 && pDAS->toc_y < absBot)
834                 _DtHelpDATocMarker((XtPointer) pDAS, True);
835           }
836       }
837
838 }  /* End _DtHelpVertScrollCB */
839
840 /***************************************************************************
841  * Function:  _DtHelpHorzScrollCB
842  *
843  * _DtHelpHorzScrollCB is called when the horizontal scroll bar is changed.
844  *
845  **************************************************************************/
846 void 
847 _DtHelpHorzScrollCB(
848         Widget widget,
849         XtPointer clientData,
850         XtPointer callData )
851 {
852     DtHelpDispAreaStruct *pDAS = (DtHelpDispAreaStruct *) clientData;
853     XmScrollBarCallbackStruct *callBack =
854                                         (XmScrollBarCallbackStruct *) callData;
855     int          diff = (int)(pDAS->charWidth / 10);
856     int          srcX;
857     int          dstX;
858     int          clearX;
859     int          reason = callBack->reason;
860     _DtCvUnit    absLeft;
861     _DtCvUnit    absRight;
862     _DtCvUnit    absY;
863     Display     *dpy;
864     Window       win;
865
866     /*
867      * if the policy is XmEXPLICIT, don't want the focus on the scrollbar
868      */
869     if (callBack->event != NULL && callBack->event->type == ButtonPress &&
870               _XmGetFocusPolicy(XtParent(XtParent(pDAS->dispWid))) != XmPOINTER)
871         XmProcessTraversal(pDAS->dispWid, XmTRAVERSE_CURRENT);
872
873     /*
874      * check to make sure we don't do a rerender when we don't have to.
875      */
876     if (pDAS->virtualX == callBack->value)
877         return;
878
879     /* If a drag occured, reset the reason to increment, decrement, page    */
880     /* increment, or page decrement depending on the distance and direction */
881     /* dragged. */
882     if (callBack->reason == XmCR_DRAG || callBack->reason == XmCR_VALUE_CHANGED)
883       {
884         diff = callBack->value - pDAS->virtualX;
885
886         if (diff > 0 && diff <= ((int) pDAS->dispUseWidth))
887             reason = XmCR_INCREMENT;
888         else if (diff < 0 && -(diff) <= ((int) pDAS->dispUseWidth))
889           {
890             reason = XmCR_DECREMENT;
891             diff   = -diff;
892           }
893         else if (diff > ((int) pDAS->dispUseWidth))
894             reason = XmCR_PAGE_DECREMENT;
895         else
896             reason = XmCR_PAGE_INCREMENT;
897       }
898     else if (callBack->reason == XmCR_INCREMENT ||
899                                         callBack->reason == XmCR_DECREMENT)
900       {
901         diff = callBack->value - pDAS->virtualX;
902         if (diff < 0)
903             diff = -diff;
904       }
905
906     /* Reset first visible to the returned scrollbar value. */
907     pDAS->virtualX = callBack->value;
908
909     /* For page increment and decrement, call _DtHelpCleanAndDrawWholeCanvas
910      * to clear the view area and redisplay the text.
911      *
912      * For increment and decrement, 
913      * use XCopyArea to move the visible lines and draw the cleared out line.
914      */
915     if (!pDAS->maxX || !pDAS->visibleCount ||
916                 (pDAS->neededFlags & (1 << (VisibilityFullyObscured + 3))))
917         return;
918   
919     dpy = XtDisplay (widget);
920     win = XtWindow (pDAS->dispWid);
921
922     /* For page increment and decrement, clear the view area and call
923      * View_DtHelpExposeCB to redisplay the text. For increment and decrement,
924      * use XCopyArea to move the visible lines and draw the cleared out line.
925      */
926     if (reason == XmCR_PAGE_INCREMENT || reason == XmCR_PAGE_DECREMENT ||
927                 reason == XmCR_TO_TOP || reason == XmCR_TO_BOTTOM)
928         _DtHelpCleanAndDrawWholeCanvas (clientData);
929     else
930       {
931         if (reason == XmCR_INCREMENT)
932           {
933             dstX   = pDAS->decorThickness;
934             srcX   = dstX + diff;
935             clearX = pDAS->dispWidth - pDAS->decorThickness - diff;
936           }
937         else
938           {
939             srcX   = pDAS->decorThickness;
940             dstX   = srcX + diff;
941             clearX = srcX;
942           }
943
944         XCopyArea(dpy, win, win, pDAS->normalGC, srcX, pDAS->decorThickness,
945                         pDAS->dispUseWidth - diff, pDAS->dispUseHeight,
946                         dstX, pDAS->decorThickness);
947
948         XClearArea(dpy, win, clearX, pDAS->decorThickness,
949                 ((unsigned int) diff), pDAS->dispUseHeight, False);
950
951         if (pDAS->neededFlags & (1 << (VisibilityPartiallyObscured + 3)))
952           {
953             /*
954              * redraw all the information
955              */
956             DrawWholeCanvas (pDAS);
957           }
958         else
959           {
960             /*
961              * draw the line that sits on the cleared line
962              */
963             absLeft  = clearX + pDAS->virtualX - pDAS->decorThickness;
964             absRight = absLeft + diff;
965             absY     = pDAS->firstVisible - pDAS->decorThickness;
966
967             _DtCanvasRender (pDAS->canvas, absLeft, absY,
968                                 absRight, absY + pDAS->dispHeight,
969                                 _DtCvRENDER_PARTIAL, _DtCvFALSE, NULL, NULL);
970
971             /*
972              * if the toc exists within this area, draw it.
973              */
974             if ((pDAS->toc_flag & _DT_HELP_TOC_ON)
975                 && ((int) (pDAS->toc_y + pDAS->toc_height)) >= ((int) absY)
976                 && ((int) pDAS->toc_y) < ((int) (absY + pDAS->dispHeight)))
977                 _DtHelpDATocMarker((XtPointer) pDAS, True);
978
979           }
980       }
981
982 }  /* End _DtHelpHorzScrollCB */
983
984 /***************************************************************************
985  * Function:  _DtHelpClickOrSelectCB
986  *
987  * _DtHelpClickOrSelectCB is called when the vertical scroll bar is changed.
988  *
989  **************************************************************************/
990 void 
991 _DtHelpClickOrSelectCB(
992         Widget widget,
993         XtPointer clientData,
994         XtPointer callData )
995 {
996     XmDrawnButtonCallbackStruct *callBack =
997                                 (XmDrawnButtonCallbackStruct *) callData;
998     DtHelpDispAreaStruct *pDAS = (DtHelpDispAreaStruct*) clientData;
999
1000     /*
1001      * If this is not an ARM call or entered through an Arm&Activate
1002      * (event-type will be keypress or keyrelease) throw it away.
1003      */
1004     if (callBack->reason != XmCR_ARM || callBack->event == NULL ||
1005         callBack->event->type == KeyPress ||
1006         callBack->event->type == KeyRelease)
1007         return;
1008
1009     pDAS->timerX       = callBack->event->xbutton.x;
1010     pDAS->timerY       = callBack->event->xbutton.y;
1011     pDAS->select_state = _DtHelpCopyOrLink;
1012
1013     if (NULL != pDAS->armCallback)
1014         (pDAS->armCallback)(pDAS->clientData);
1015
1016 }  /* End _DtHelpClickOrSelectCB */
1017
1018 /*****************************************************************************
1019  * Function: _DtHelpEndSelectionCB
1020  *
1021  *
1022  * Called by: Callback for the Selection mechanism
1023  *****************************************************************************/
1024 void
1025 _DtHelpEndSelectionCB (
1026         Widget          w,              /*  widget id           */
1027         XtPointer       client_data,    /*  data from applicaiton   */
1028         XtPointer       call_data )     /*  data from widget class  */
1029 {
1030     XmDrawnButtonCallbackStruct *callback =
1031                                 (XmDrawnButtonCallbackStruct *) call_data;
1032     DtHelpDispAreaStruct *pDAS = (DtHelpDispAreaStruct*) client_data;
1033     int    newX;
1034     int    newY;
1035
1036     if (callback->reason != XmCR_DISARM || callback->event == NULL ||
1037         callback->event->type == KeyPress ||
1038         callback->event->type == KeyRelease)
1039         return;
1040
1041     /*
1042      * if a scroll timer is active, we are selecting text.
1043      * stop it.
1044      */
1045     if (pDAS->scr_timer_id)
1046       {
1047         XtRemoveTimeOut (pDAS->scr_timer_id);
1048         pDAS->scr_timer_id = NULL;
1049       }
1050
1051     newX = callback->event->xbutton.x;
1052     newY = callback->event->xbutton.y;
1053     if (pDAS->select_state == _DtHelpCopyOrLink)
1054       {
1055         if (abs (pDAS->timerX - newX) <= pDAS->moveThreshold &&
1056                         abs (pDAS->timerY - newY) <= pDAS->moveThreshold)
1057           {
1058             _DtHelpClearSelection (client_data);
1059
1060             /*
1061              * If this is null, we came the the Arm&Activate routine
1062              * which means a key was pressed, so we ignore this call.
1063              */
1064             if (callback->event)
1065                 /*
1066                  * find the hypertext link and process it.
1067                  */
1068                 _DtHelpProcessHyperSelection (client_data,
1069                                                 pDAS->timerX, pDAS->timerY,
1070                                                 callback->event);
1071           }
1072         else
1073             StartSelection (w, client_data);
1074         return;
1075       }
1076
1077     /*
1078      * The user was doing a selection, finish it up.
1079      */
1080     if (pDAS->select_state != _DtHelpNothingDoing)
1081       {
1082         _DtCanvasProcessSelection(pDAS->canvas,
1083                 (newX + pDAS->virtualX - pDAS->decorThickness),
1084                 (newY + pDAS->firstVisible - pDAS->decorThickness),
1085                 _DtCvSELECTION_END);
1086         _DtCanvasMoveTraversal(pDAS->canvas, _DtCvTRAVERSAL_ON, False, True,
1087                                 NULL, NULL, NULL, NULL, NULL);
1088
1089       }
1090
1091     pDAS->select_state = _DtHelpNothingDoing;
1092     return;
1093
1094 }  /* End _DtHelpEndSelectionCB */
1095
1096 /***************************************************************************
1097  * Function:  _DtHelpMouseMoveCB
1098  *
1099  * _DtHelpMouseMoveCB tracks the mouse movement for the Selection mechanism
1100  *
1101  **************************************************************************/
1102 void 
1103 _DtHelpMouseMoveCB(
1104         Widget     widget,
1105         XtPointer  client_data,
1106         XEvent    *event )
1107 {
1108     _DtCvUnit   newX;
1109     _DtCvUnit   newY;
1110     DtHelpDispAreaStruct *pDAS = (DtHelpDispAreaStruct *) client_data;
1111
1112     /*
1113      * If a selection is not in progress, don't do anything.
1114      */
1115     if (pDAS->select_state == _DtHelpNothingDoing || event->type != MotionNotify)
1116         return;
1117
1118     if (pDAS->scr_timer_id)
1119       {
1120         XtRemoveTimeOut (pDAS->scr_timer_id);
1121         pDAS->scr_timer_id = NULL;
1122       }
1123
1124     newX = event->xmotion.x;
1125     newY = event->xmotion.y;
1126
1127     if (pDAS->select_state == _DtHelpCopyOrLink)
1128       {
1129         if (abs (newX - pDAS->timerX) < pDAS->moveThreshold &&
1130                         abs (newY - pDAS->timerY) < pDAS->moveThreshold)
1131             return;
1132
1133         StartSelection (widget, client_data);
1134         return;
1135       }
1136
1137     if (newY < ((int) pDAS->decorThickness) && pDAS->firstVisible)
1138         pDAS->scr_timer_data.vertical_reason = XmCR_DECREMENT;
1139
1140     else if ((newY >
1141             (((int) pDAS->dispHeight)-((int)pDAS->decorThickness))) &&
1142             (pDAS->maxYpos >
1143                 (((int)pDAS->firstVisible)
1144                                 + ((int)pDAS->dispUseHeight))))
1145         pDAS->scr_timer_data.vertical_reason = XmCR_INCREMENT;
1146     else
1147         pDAS->scr_timer_data.vertical_reason = XmCR_NONE;
1148
1149     if (newX < ((int) pDAS->decorThickness) && pDAS->virtualX)
1150         pDAS->scr_timer_data.horizontal_reason = XmCR_DECREMENT;
1151     else if (newX > ((int) pDAS->dispWidth) &&
1152             pDAS->maxX > pDAS->virtualX + ((int) pDAS->dispUseWidth))
1153         pDAS->scr_timer_data.horizontal_reason = XmCR_INCREMENT;
1154     else
1155         pDAS->scr_timer_data.horizontal_reason = XmCR_NONE;
1156
1157     if (pDAS->scr_timer_data.vertical_reason != XmCR_NONE ||
1158         pDAS->scr_timer_data.horizontal_reason != XmCR_NONE)
1159       {
1160         int scrollTimeOut = pDAS->vert_init_scr;
1161
1162         if (pDAS->scr_timer_data.horizontal_reason != XmCR_NONE)
1163             scrollTimeOut = pDAS->horz_init_scr;
1164
1165         pDAS->scr_timer_x  = newX;
1166         pDAS->scr_timer_y  = newY;
1167         pDAS->scr_timer_id =
1168                         XtAppAddTimeOut(XtWidgetToApplicationContext(widget),
1169                                 ((unsigned long) scrollTimeOut),
1170                                 ScrollTimerCB, (XtPointer) pDAS);
1171         return;
1172       }
1173
1174     newX = newX + pDAS->virtualX - pDAS->decorThickness;
1175     if (newX < 0)
1176         newX = 0;
1177
1178     newY = newY + pDAS->firstVisible - pDAS->decorThickness;
1179     if (newY < 0)
1180         newY = 0;
1181
1182     _DtCanvasProcessSelection(pDAS->canvas, newX, newY, _DtCvSELECTION_UPDATE);
1183
1184 } /* End _DtHelpMouseMoveCB */
1185
1186 /*****************************************************************************
1187  * Function: StartSelection
1188  *
1189  *    StartSelection - If this routine is called, the user has initiated a
1190  *                   selection.
1191  *
1192  *****************************************************************************/
1193 static  void
1194 StartSelection (
1195         Widget          widget,         /*  widget id               */
1196         XtPointer       client_data )   /*  data from applicaiton   */
1197 {
1198     DtHelpDispAreaStruct *pDAS = (DtHelpDispAreaStruct*) client_data;
1199
1200     /*
1201      * If this widget doesn't own the primary selection, get it.
1202      */
1203     _DtHelpGetClearSelection(widget, client_data);
1204
1205     /*
1206      * check to see if we have the primary selection.
1207      */
1208     if (pDAS->primary == True)
1209       {
1210         _DtCanvasMoveTraversal(pDAS->canvas, _DtCvTRAVERSAL_OFF, False, True,
1211                                 NULL, NULL, NULL, NULL, NULL);
1212         _DtCanvasProcessSelection(pDAS->canvas,
1213                         pDAS->timerX + pDAS->virtualX - pDAS->decorThickness,
1214                         pDAS->timerY + pDAS->firstVisible -pDAS->decorThickness,
1215                         _DtCvSELECTION_START);
1216
1217         pDAS->select_state  = _DtHelpSelectingText;
1218         pDAS->text_selected = True;
1219       }
1220
1221 }  /* End StartSelection */
1222
1223 /*****************************************************************************
1224  * Function: _DtHelpLoseSelectionCB
1225  *
1226  *    _DtHelpLoseSelectionCB - This routine is called when we lose the selection
1227  *
1228  *****************************************************************************/
1229 void
1230 _DtHelpLoseSelectionCB (
1231         Widget   widget,
1232         Atom    *selection )
1233 {
1234     Arg    args[2];
1235     DtHelpDispAreaStruct *pDAS;
1236
1237     XtSetArg(args[0], XmNuserData, &pDAS);
1238     XtGetValues(widget, args, 1);
1239
1240     if (pDAS != NULL && pDAS->dispWid == widget && *selection == XA_PRIMARY)
1241       {
1242         _DtHelpClearSelection ((XtPointer) pDAS);
1243         pDAS->primary       = False;
1244         pDAS->text_selected = False;
1245       }
1246 } /* End _DtHelpLoseSelectionCB */
1247
1248 /*****************************************************************************
1249  * Function: _DtHelpClearSelection
1250  *
1251  *    Clears the selection pointers and variables
1252  *
1253  *****************************************************************************/
1254 void
1255 _DtHelpClearSelection ( XtPointer client_data)
1256 {
1257     DtHelpDispAreaStruct *pDAS = (DtHelpDispAreaStruct*) client_data;
1258
1259     if (pDAS->primary == True)
1260       {
1261         if (NULL != pDAS->canvas)
1262           {
1263             _DtCanvasMoveTraversal(pDAS->canvas, _DtCvTRAVERSAL_OFF, False, True,
1264                                    NULL, NULL, NULL, NULL, NULL);
1265             _DtCanvasProcessSelection(pDAS->canvas, 0, 0, _DtCvSELECTION_CLEAR);
1266             _DtCanvasMoveTraversal(pDAS->canvas, _DtCvTRAVERSAL_ON, False, True,
1267                                    NULL, NULL, NULL, NULL, NULL);
1268           }
1269         pDAS->select_state  = _DtHelpNothingDoing;
1270         pDAS->text_selected = False;
1271       }
1272 }
1273
1274 /***************************************************************************
1275  * Function:  _DtHelpFocusCB
1276  *
1277  * _DtHelpFocusCB tracks the traversal of the hypertext.
1278  *
1279  **************************************************************************/
1280 void 
1281 _DtHelpFocusCB(
1282         Widget     widget,
1283         XtPointer  client_data,
1284         XEvent    *event )
1285 {
1286     Boolean                oldFlag;
1287     Boolean                newFlag = False;
1288     DtHelpDispAreaStruct  *pDAS = (DtHelpDispAreaStruct *) client_data;
1289
1290     if (pDAS->hyperCall == NULL ||
1291                 (event->type != FocusIn && event->type != FocusOut) ||
1292                 !event->xfocus.send_event)
1293         return;
1294
1295     /*
1296      * get the old flag
1297      */
1298     oldFlag = (pDAS->neededFlags & _DT_HELP_FOCUS_FLAG) ? True : False;
1299
1300     /*
1301      * get the new flag
1302      */
1303     if (event->type == FocusIn)
1304         newFlag = True;
1305
1306     if (oldFlag != newFlag)
1307       {
1308         if (newFlag == False)
1309           {
1310             _DtCanvasMoveTraversal (pDAS->canvas, _DtCvTRAVERSAL_OFF, False,
1311                                 (XtIsRealized(widget) ? True : False),
1312                                 NULL, NULL, NULL, NULL, NULL);
1313             pDAS->neededFlags = pDAS->neededFlags & ~(_DT_HELP_FOCUS_FLAG);
1314           }
1315         else
1316           {
1317             pDAS->neededFlags = pDAS->neededFlags | _DT_HELP_FOCUS_FLAG;
1318             _DtCanvasMoveTraversal (pDAS->canvas, _DtCvTRAVERSAL_ON, False,
1319                                 (XtIsRealized(widget) ? True : False),
1320                                 NULL, NULL, NULL, NULL, NULL);
1321           }
1322       }
1323
1324 } /* End _DtHelpFocusCB */
1325
1326 /***************************************************************************
1327  * Function:  _DtHelpEnterLeaveCB
1328  *
1329  * _DtHelpEnterLeaveCB tracks the traversal of the hypertext.
1330  *
1331  **************************************************************************/
1332 void
1333 _DtHelpEnterLeaveCB(
1334         Widget     widget,
1335         XtPointer  client_data,
1336         XEvent    *event )
1337 {
1338     Boolean                oldFlag;
1339     Boolean                newFlag = False;
1340     DtHelpDispAreaStruct  *pDAS = (DtHelpDispAreaStruct *) client_data;
1341
1342     if (pDAS->hyperCall == NULL ||
1343                 (event->type != EnterNotify && event->type != LeaveNotify))
1344         return;
1345
1346     /*
1347      * get the old flag
1348      */
1349     oldFlag = (pDAS->neededFlags & _DT_HELP_FOCUS_FLAG) ? True : False;
1350
1351     /*
1352      * get the new flag
1353      */
1354     if (event->type == FocusIn)
1355         newFlag = True;
1356
1357     if (oldFlag != newFlag)
1358       {
1359         if (oldFlag == True)
1360           {
1361             _DtCanvasMoveTraversal (pDAS->canvas, _DtCvTRAVERSAL_OFF, False,
1362                                 (XtIsRealized(widget) ? True : False),
1363                                 NULL, NULL, NULL, NULL, NULL);
1364             pDAS->neededFlags = pDAS->neededFlags & ~(_DT_HELP_FOCUS_FLAG);
1365           }
1366         else
1367           {
1368             pDAS->neededFlags = pDAS->neededFlags | _DT_HELP_FOCUS_FLAG;
1369             _DtCanvasMoveTraversal (pDAS->canvas, _DtCvTRAVERSAL_ON, False,
1370                                 (XtIsRealized(widget) ? True : False),
1371                                 NULL, NULL, NULL, NULL, NULL);
1372           }
1373       }
1374 } /* End _DtHelpEnterLeaveCB */
1375
1376 /***************************************************************************
1377  * Function:  _DtHelpVisibilityCB
1378  *
1379  * _DtHelpVisibilityCB tracks whether the window becomes obscured.
1380  *
1381  **************************************************************************/
1382 void 
1383 _DtHelpVisibilityCB(
1384         Widget     widget,
1385         XtPointer  client_data,
1386         XEvent    *event )
1387 {
1388     DtHelpDispAreaStruct  *pDAS = (DtHelpDispAreaStruct *) client_data;
1389
1390     if (event->type != VisibilityNotify)
1391         return;
1392
1393     /*
1394      * save the scrollbar and focus flags while clearing the visibility flags.
1395      */
1396     pDAS->neededFlags = pDAS->neededFlags &
1397                                 (_DT_HELP_FOCUS_FLAG | SCROLL_BAR_FLAGS);
1398
1399     /*
1400      * set the visibility flag
1401      */
1402     pDAS->neededFlags = pDAS->neededFlags |
1403                                 (1 << (event->xvisibility.state + 3));
1404
1405 } /* End _DtHelpVisibilityCB */
1406
1407 /*****************************************************************************
1408  * Function: _DtHelpInitiateClipboard
1409  *
1410  *    _DtHelpInitiateClipboard
1411  *
1412  *****************************************************************************/
1413 void
1414 _DtHelpInitiateClipboard (
1415     XtPointer  client_data)
1416 {
1417     DtHelpDispAreaStruct  *pDAS = (DtHelpDispAreaStruct *) client_data;
1418
1419     /*
1420      * check to see if we have the primary selection
1421      * before trying for the clipboard.
1422      */
1423     if (pDAS->primary == True && pDAS->text_selected == True)
1424       {
1425         long      itemId = 0L;                       /* clipboard item id */
1426         long      dataId = 0L;                       /* clipboard data id */
1427         int       status;                            /* clipboard status  */
1428         XmString  clipLabel;
1429         Display  *dpy = XtDisplay(pDAS->dispWid);
1430         Window    win = XtWindow(pDAS->dispWid);
1431         char     *atomName;
1432         char     *tmpString;
1433         XTextProperty tmpProp;
1434
1435         /*
1436          * get the selected text
1437          */
1438         _DtCanvasGetSelection (pDAS->canvas, 
1439                                 (_DtCvSELECTED_TEXT | _DtCvSELECTED_REGION),
1440                                                 (_DtCvPointer *)(&tmpString));
1441
1442         /*
1443          * Using the Xm clipboard facilities,
1444          * copy the selected text to the clipboard
1445          */
1446         if (tmpString != NULL)
1447           {
1448             clipLabel = XmStringCreateLocalized ("DT_HELP");
1449
1450             /*
1451              * start copy to clipboard
1452              */
1453             status = XmClipboardStartCopy(dpy, win, clipLabel,
1454                                         XtLastTimestampProcessed(dpy),
1455                                         pDAS->dispWid, NULL, &itemId);
1456
1457             /*
1458              * no longer need the label
1459              */
1460             XmStringFree(clipLabel);
1461
1462             if (status != ClipboardSuccess)
1463               {
1464                 free(tmpString);
1465                 return;
1466               }
1467    
1468             status = XmbTextListToTextProperty(dpy, &tmpString, 1,
1469                                             (XICCEncodingStyle)XStdICCTextStyle,
1470                                             &tmpProp);
1471             /*
1472              * free the original copy of the string and check the results.
1473              */
1474             free(tmpString);
1475
1476             if (status != Success && status <= 0)
1477               {
1478                 XmClipboardCancelCopy(dpy, win, itemId);
1479                 return;
1480               }
1481
1482             atomName = XGetAtomName(dpy, tmpProp.encoding);
1483
1484             /* move the data to the clipboard */
1485             status = XmClipboardCopy(dpy, win, itemId, atomName,
1486                                   (XtPointer)tmpProp.value, tmpProp.nitems,
1487                                   0, &dataId);
1488
1489             XtFree(atomName);
1490
1491             if (status != ClipboardSuccess)
1492               {
1493                 XmClipboardCancelCopy(dpy, win, itemId);
1494                 XFree((char*)tmpProp.value);
1495                 return;
1496               }
1497
1498             /*
1499              * end the copy to the clipboard
1500              */
1501             status = XmClipboardEndCopy (dpy, win, itemId);
1502
1503             XFree((char*)tmpProp.value);
1504           }
1505       }
1506
1507 }  /* End _DtHelpInitiateClipboard */
1508
1509 /***************************************************************************
1510  * Function:  _DtHelpMoveBtnFocusCB
1511  *
1512  * _DtHelpMoveBtnFocusCB tracks the mouse movement for the Selection mechanism
1513  *
1514  **************************************************************************/
1515 void 
1516 _DtHelpMoveBtnFocusCB(
1517         Widget     widget,
1518         XtPointer  client_data,
1519         XEvent    *event )
1520 {
1521     DtHelpDispAreaStruct *pDAS = (DtHelpDispAreaStruct *) client_data;
1522
1523     /*
1524      * if the policy is XmEXPLICIT, don't want the focus on the scrollbar
1525      */
1526     if (event->type == ButtonPress &&
1527               _XmGetFocusPolicy(XtParent(XtParent(pDAS->dispWid))) != XmPOINTER)
1528         XmProcessTraversal(pDAS->dispWid, XmTRAVERSE_CURRENT);
1529
1530 }
1531
1532 /*****************************************************************************
1533  * Function: _DtHelpGetClearSelection
1534  *
1535  *  _DtHelpGetClearSelection - If this routine is called,
1536  *            the user has initiated a selection.
1537  *
1538  *****************************************************************************/
1539  void
1540 _DtHelpGetClearSelection (
1541         Widget          widget,         /*  widget id               */
1542         XtPointer       client_data )   /*  data from applicaiton   */
1543 {
1544     DtHelpDispAreaStruct *pDAS = (DtHelpDispAreaStruct *) client_data;
1545
1546     /*
1547      * If this widget doesn't own the primary selection, get it.
1548      */
1549     if (pDAS->primary != True)
1550       {
1551         if (XtOwnSelection (widget, XA_PRIMARY,
1552                         XtLastTimestampProcessed(XtDisplay(widget)),
1553                         (XtConvertSelectionProc) ConvertSelectionCB,
1554                         (XtLoseSelectionProc) _DtHelpLoseSelectionCB,
1555                         (XtSelectionDoneProc) NULL))
1556           {
1557             pDAS->primary = True;
1558             pDAS->anchor_time = XtLastTimestampProcessed(XtDisplay(widget));
1559           }
1560       }
1561     else
1562         _DtHelpClearSelection (client_data);
1563
1564 }  /* End _DtHelpGetClearSelection */