Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / DtHelp / HyperText.c
1 /* $TOG: HyperText.c /main/9 1999/10/14 14:45:38 mgreess $ */
2 /************************************<+>*************************************
3  ****************************************************************************
4  **
5  **   File:        HyperText.c
6  **
7  **   Project:     Text Graphic Display Library
8  **
9  **   Description: This body of code does all the work for hypertext links
10  **
11  **
12  **  (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
13  **
14  **  (c) Copyright 1993, 1994 Hewlett-Packard Company
15  **  (c) Copyright 1993, 1994 International Business Machines Corp.
16  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
17  **  (c) Copyright 1993, 1994 Novell, Inc.
18  **
19  **
20  **
21  ****************************************************************************
22  ************************************<+>*************************************/
23
24 /*
25  * system includes
26  */
27 #include <errno.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #ifdef __hpux
31 #include <time.h>
32 #else /* SUN and IBM */
33 #ifdef  _AIX
34 #include <sys/select.h>
35 #endif
36 #include <sys/time.h>
37 #include <sys/types.h>
38 #endif
39 #include <unistd.h>
40 #include <sys/wait.h>
41 #include <Xm/DialogS.h>
42
43
44 /*
45  * Canvas Engine
46  */
47 #include "CanvasP.h"
48
49 /*
50  * private includes
51  */
52 #include "HelpErrorP.h"
53 #include "DisplayAreaP.h"
54 #include "DisplayAreaI.h"
55 #include "FontI.h"
56 #include "HourGlassI.h"
57 #include "HyperTextI.h"
58 #include "HelposI.h"
59
60 #ifdef NLS16
61 #endif
62
63 /********    Private Function Declarations    ********/
64 static  void    ProcessEvents (
65                         DtHelpDispAreaStruct    *pDAS,
66                         pid_t                    child_pid,
67                         Boolean                  child_flag);
68 /********    End Private Function Declarations    ********/
69
70 /*********************************************************************
71  *              Private Variables
72  *********************************************************************/
73
74 typedef struct {
75         char    *link_spec;
76         int      type;
77         char    *descrip;
78 } HyperList;
79
80 /*********************************************************************
81  *              Private Functions
82  *********************************************************************/
83 /*********************************************************************
84  * ProcessEvents
85  * 
86  *    ProcessEvents will do a select on the socket until the child
87  *       dies.
88  *
89  *********************************************************************/
90 static void
91 ProcessEvents (
92     DtHelpDispAreaStruct        *pDAS,
93     pid_t                        child_pid,
94     Boolean                      child_flag)
95 {
96     int    result;
97
98     int   rMask;
99     int   myFd;
100     pid_t pid;
101     struct timeval *topPtr;
102     struct timeval  toStruct;
103
104     Display *dpy = XtDisplay (pDAS->dispWid);
105     XEvent   event;
106
107
108     /*
109      * set a small time out.
110      */
111     toStruct.tv_usec = 500000;          /* 500 miliseconds */
112     toStruct.tv_sec  = 0;
113     topPtr = &toStruct;
114
115     /*
116      * get the socket's file descriptor
117      */
118     myFd = ConnectionNumber (dpy);
119
120     do
121       {
122         rMask = (1 << (myFd % 32));             /* on t.o. select will clear */
123
124         if (!XPending(dpy))
125           {
126 #if     0
127             result = select(myFd+1, &rMask, 0, 0, topPtr);
128 #else
129             result = select(myFd+1, ((fd_set *)&rMask), 0, 0, topPtr);
130 #endif
131
132             /*
133              * check to see if the select happened because of
134              * a system interrupt.
135              */
136             /*
137              * otherwise an exposure event happened.
138              * fall through and XPending will be true,
139              * forcing us to go to the XmUpdateDisplay call.
140              */
141           }
142         else
143           {
144 /*
145  * SYSTEM - Use XtDisplatchEvent????
146  */
147             XNextEvent (dpy, &event);
148             if (event.type == Expose)
149                 XmUpdateDisplay (pDAS->dispWid);
150           }
151
152         /*
153          * check to see if the child is still going
154          */
155         pid = waitpid (child_pid, (int *) 0, WNOHANG);
156         if (pid == child_pid || pid == -1)
157             child_flag = True;
158
159       } while (!child_flag);
160 }
161
162 /*********************************************************************
163  *              Internal Public Functions
164  *********************************************************************/
165 /*********************************************************************
166  * _DtHelpExecProcedure
167  * 
168  *    _DtHelpExecProcedure will fork/exec the command passed in. It will
169  *       then allow only exposure events to be processed until the
170  *       child dies.
171  *
172  *********************************************************************/
173 void
174 _DtHelpExecProcedure (
175         XtPointer       client_data,
176         char *cmd )
177 {
178     pid_t pid;
179     XWindowAttributes attr;
180     char        *pShell = "sh";
181     Widget       shellWidget;
182     Boolean      childFlag = False;
183     pid_t        childPid;
184     DtHelpDispAreaStruct *pDAS = (DtHelpDispAreaStruct *) client_data;
185
186     /*
187      * Turn on the wait cursor.
188      */
189     shellWidget = pDAS->dispWid;
190     while (!XtIsSubclass(shellWidget, xmDialogShellWidgetClass))
191         shellWidget = XtParent(shellWidget);
192     
193      _DtHelpTurnOnHourGlass(shellWidget);
194     /*
195      * Get the window event mask via the window attributes. Remember it.
196      * Set the Input to only Exposure events.
197      */
198     XGetWindowAttributes (XtDisplay(pDAS->dispWid), XtWindow (pDAS->dispWid),
199                                                                 &attr);
200     XSelectInput (XtDisplay(pDAS->dispWid), XtWindow (pDAS->dispWid),
201                                                                 ExposureMask);
202
203     XSync (XtDisplay(pDAS->dispWid), 0);
204
205     /*
206      * initialize the global flag and variable.
207      */
208     childPid  = -1;
209     childFlag = False;
210
211     /*
212      * fork a child process.
213      */
214 #ifdef __hpux
215     childPid = vfork ();
216 #else
217     childPid = fork ();
218 #endif /* __hpux */
219
220     /*
221      * If the child, exec the cmd with a shell parent
222      * so if the cmd ends in an ampersand, the command
223      * will be put in the background and the shell will
224      * die and return, creating a SIGCLD for us to catch.
225      */
226     if (childPid == 0)
227       {
228         execlp (pShell, pShell, "-c", cmd, ((char *) 0));
229         _exit (1);
230       }
231
232     /*
233      * Check to make sure the vfork was successful.
234      */
235     if (childPid != -1)
236       {
237         /*
238          * check to see if the child is still going
239          */
240         pid = waitpid (childPid, (int *) 0, WNOHANG);
241         if (!(pid == childPid || pid == -1))
242             /*
243              * process the exposure events in a special routine.
244              */
245             ProcessEvents (pDAS, childPid, childFlag);
246       }
247
248     /*
249      * reset the input mask
250      */
251     XSelectInput (XtDisplay(pDAS->dispWid), XtWindow (pDAS->dispWid),
252                                                 (attr.your_event_mask));
253     /*
254      * turn off the wait cursor
255      */
256     _DtHelpTurnOffHourGlass(shellWidget);
257
258 } /* End _DtHelpExecProcedure */
259
260 /*********************************************************************
261  * Function: _DtHelpProcessHyperSelection
262  *
263  *    Determine if the user selected a segment that is a hypertext
264  *        link. If so, call the appropriate function to process it.
265  *
266  *********************************************************************/
267 void
268 _DtHelpProcessHyperSelection (
269         XtPointer        client_data,
270         int              downX,
271         int              downY,
272         XEvent          *event )
273 {
274
275     int    upX;
276     int    upY;
277
278     _DtCvLinkInfo  ceHyper;
279     DtHelpHyperTextStruct callData;
280     DtHelpDispAreaStruct *pDAS = (DtHelpDispAreaStruct *) client_data;
281
282     if (pDAS->hyperCall == NULL)
283         return;
284
285     downY = downY + pDAS->firstVisible - pDAS->decorThickness;
286     downX = downX + pDAS->virtualX     - pDAS->decorThickness;
287     upX   = event->xbutton.x + pDAS->virtualX     - pDAS->decorThickness;
288     upY   = event->xbutton.y + pDAS->firstVisible - pDAS->decorThickness;
289
290     /*
291      * turn off the old traversal
292      */
293     if (pDAS->neededFlags & _DT_HELP_FOCUS_FLAG)
294       {
295         pDAS->toc_flag |= _DT_HELP_DRAW_TOC_IND;
296         _DtCanvasMoveTraversal(pDAS->canvas, _DtCvTRAVERSAL_OFF, False,
297                                 (XtIsRealized(pDAS->dispWid) ? True : False),
298                                         NULL, NULL, NULL, NULL, NULL);
299       }
300
301     if (_DtCvSTATUS_OK ==
302                 _DtCanvasGetPosLink(pDAS->canvas,downX,downY,upX,upY,&ceHyper))
303       {
304         /*
305          * turn the traversal on for the selected hyptext link.
306          */
307         if (pDAS->neededFlags & _DT_HELP_FOCUS_FLAG)
308           {
309             pDAS->toc_flag |= _DT_HELP_DRAW_TOC_IND;
310             _DtCanvasMoveTraversal(pDAS->canvas, _DtCvTRAVERSAL_ID, False,
311                                 (XtIsRealized(pDAS->dispWid) ? True : False),
312                                         ceHyper.specification,
313                                         NULL, NULL, NULL, NULL);
314           }
315
316         callData.reason        = XmCR_ACTIVATE;
317         callData.event         = event;
318         callData.window        = XtWindow (pDAS->dispWid);
319         callData.specification = ceHyper.specification;
320         callData.hyper_type    = ceHyper.hyper_type;
321         callData.window_hint   = ceHyper.win_hint;
322
323         (*(pDAS->hyperCall)) (pDAS, pDAS->clientData, &callData);
324       }
325     else if (pDAS->neededFlags & _DT_HELP_FOCUS_FLAG)
326         /*
327          * turn the traversal back on
328          */
329         _DtCanvasMoveTraversal(pDAS->canvas, _DtCvTRAVERSAL_ON, False,
330                                 (XtIsRealized(pDAS->dispWid) ? True : False),
331                                         NULL, NULL, NULL, NULL, NULL);
332
333 }  /* End _DtHelpProcessHyperSelection */
334