Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dthelp / dthelpdemo / HelpCache.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: HelpCache.c /main/4 1995/11/08 09:17:54 rswiston $ */
24 /*************************************<+>*************************************
25  *****************************************************************************
26  **
27  **  File:        HelpCache.c
28  **
29  **  Project:      dthelpdemo demo program
30  **
31  **  Description: Contains the Help Callbacks and Utility functions for our
32  **               demo tool dthelpdemo.
33  **
34  **
35  **  (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994
36  **      Hewlett-Packard Company
37  **  (c) Copyright 1993, 1994 International Business Machines Corp.
38  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
39  **  (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of
40  **      Novell, Inc.
41  **
42  ****************************************************************************
43  ************************************<+>*************************************/
44
45 /* System Include Files  */
46
47
48 #include <Xm/Xm.h>
49 #include <Xm/XmP.h>
50
51
52 #include <Dt/Help.h>
53 #include <Dt/HelpDialog.h>
54 #include <Dt/HelpQuickD.h>
55
56 /* Local Includes */
57 #include "Main.h"
58 #include "HelpCacheI.h"
59 #include "HourGlassI.h"
60
61
62 /********    Static Function Declarations    ********/
63
64
65 static void CloseHelpCB (
66     Widget w,
67     XtPointer clientData,
68     XtPointer callData);
69 static Boolean GetFromCache(
70     Widget parent,
71     CacheListStruct **pCurrentNode);
72
73
74
75 /* Global Main Help Dialog Widget */
76 static Widget helpMain=NULL;
77 static Widget versionMain=NULL;
78
79
80 /*****************************************************************************
81  * Function:        void HelpMapCB()
82  *                   
83  *                            
84  *
85  * Parameters:      clientData is the widget in reference to
86  *                  which widget w is placed
87  *
88  * Return Value:    Void.
89  *
90  * Purpose:         Determins where a new child dialog should be mapped in
91  *                  relation to its parent.
92  *
93  * Algorithm:       1. attempt left or right placement with no overlap
94  *                  2. if fails, attempt up or down placement with no overlap
95  *                  3. if fails, determines location with least
96  *                     amount of overlap, and places there.
97  *
98  *****************************************************************************/
99 XtCallbackProc HelpMapCB(
100     Widget w,
101     XtPointer clientData,
102     XtPointer callData)
103
104 {
105
106     Arg         args[2];
107     Widget      parent;
108     Position    centeredY, bestX, bestY, pX, pY; 
109     Dimension   pHeight, myHeight, pWidth, myWidth;
110     Dimension   maxX, maxY;
111     int         rhsX, lhsX, topY, botY;   /* needs to be int, not Dimension */
112     Display *   display;
113     Screen *    screen;
114     int         screenNumber;
115
116     parent = (Widget)clientData;
117     display = XtDisplay(w);
118     screen = XtScreen(w);
119     screenNumber = XScreenNumberOfScreen(screen);
120     pX = XtX(parent);
121     pY = XtY(parent);
122     if (pX < 0) pX = 0;
123     if (pY < 0) pY = 0;
124     pHeight = XtHeight(parent);
125     pWidth = XtWidth(parent);
126     myHeight = XtHeight(w);
127     myWidth = XtWidth(w);
128     maxX = XDisplayWidth(display,screenNumber);
129     maxY = XDisplayHeight(display,screenNumber);
130
131     /* algorithm 
132      * 1. attempt left or right placement with no overlap
133      * 2. if fails, attempt up or down placement with no overlap
134      * 3. if fails, places on the right in the middle
135      */
136     
137     /* first try left right placement */
138     bestY = pY + pHeight/2 - myHeight/2;
139     centeredY = bestY;
140     rhsX = pX + pWidth;
141     lhsX = pX - myWidth - 8;     /* 8: account for border */
142     if ( (rhsX + myWidth) < maxX ) bestX = rhsX;
143     else if ( lhsX > 0 ) bestX = lhsX;
144     else
145     {
146           /* then try up down placement */
147         bestX = pX + pWidth/2 - myWidth/2;
148         botY = pY + pHeight;
149         topY = pY - myHeight - 44;     /* 44: account for menu border */
150         if ( (botY + myWidth) < maxY ) bestY = botY;
151         else if ( topY > 0 ) bestY = topY;
152         else
153         {
154             /* otherwise, center vertically and on the right */
155             bestX = maxX - myWidth;
156             bestY = centeredY;
157         }
158     }
159
160     XtSetArg(args[0], XmNx, bestX);
161     XtSetArg(args[1], XmNy,  bestY);
162     XtSetValues(w, args, 2);
163
164     return((XtCallbackProc) NULL);
165
166 }
167
168 \f
169 /****************************************************************************
170  * Function:         CloseHelpCB(
171  *                              Widget w,
172  *                              XtPointer clientData, 
173  *                              XtPointer callData
174  *
175  * Parameters:      
176  *
177  * Return Value:    Void.
178  *
179  * Purpose:         Process close requests on all Help Dialog widgets 
180  *                  created and managed by this application.
181  *
182  ***************************************************************************/
183 static void CloseHelpCB (
184     Widget w,
185     XtPointer clientData,
186     XtPointer callData)
187 {
188
189   Widget helpDialog = (Widget) clientData;
190
191   CacheListStruct *pTemp; 
192  
193   pTemp = pCacheListHead;
194   
195   /* Search our Cache List for the closed help dialog */
196   while ((pTemp->helpDialog != helpDialog) && (pTemp != NULL))
197      pTemp = pTemp->pNext;
198  
199
200   if (pTemp == NULL)
201     /* ERROR */
202     printf("We did not find our help dialog widget in the cache list??? /n");
203
204   /* Un Map and Clean up the help widget */
205    XtUnmanageChild(helpDialog);
206   pTemp->inUseFlag  = FALSE;
207    
208
209 }
210
211
212 \f
213 /****************************************************************************
214  * Function:         CloseMainCB(
215  *                              Widget w,
216  *                              XtPointer clientData, 
217  *                              XtPointer callData
218  *
219  * Parameters:      
220  *
221  * Return Value:    Void.
222  *
223  * Purpose:         Process close requests on our main help dialog.
224  *
225  ***************************************************************************/
226 static void CloseMainCB (
227     Widget w,
228     XtPointer clientData,
229     XtPointer callData)
230 {
231    Widget currentDialog = (Widget) clientData;
232  
233
234
235   /* Un Map and Clean up the help widget */
236    XtUnmanageChild(currentDialog);
237
238 }
239
240
241
242 \f
243 /****************************************************************************
244  * Function:        void ProcessLinkCB(
245  *                              Widget w,
246  *                              XtPointer  clientData, 
247  *                              XtPointer callData
248  *
249  * Parameters:      
250  *
251  * Return Value:    Void.
252  *
253  * Purpose:         Process JUMP-NEW and APP-LINK hypertext requests in a 
254  *                  given Help Dialog Window.
255  *                 
256  *                  This is the callback used for the DtNhyperLinkCallback
257  *                  on each of the help dialog widges created.
258  *
259  ****************************************************************************/
260 void ProcessLinkCB (
261     Widget w,
262     XtPointer clientData,
263     XtPointer callData)
264
265 {
266   Arg               args[20];
267   int               n;
268   Position          xPos, yPos;
269   int               appLinkNum=0;
270   int               count;
271   static Dimension  width=0;
272   static Dimension  height=0;
273   static Boolean    goBigger=TRUE;
274
275   DtHelpDialogCallbackStruct * hyperData = 
276                          (DtHelpDialogCallbackStruct *) callData;
277   
278
279   switch (hyperData->hyperType)
280     {
281       case DtHELP_LINK_JUMP_NEW:
282
283         DisplayTopic (XtParent(w), hyperData->helpVolume,
284                       hyperData->locationId);
285         
286         break;
287
288        case  DtHELP_LINK_MAN_PAGE:
289
290          /* Create and display the requested man page */
291         DisplayMan(XtParent(w), hyperData->specification);
292
293         
294          break;
295
296       case  DtHELP_LINK_TEXT_FILE:
297
298          /* Create a quick help dialog and display the text file in it */
299         
300          break;
301
302        case  DtHELP_LINK_APP_DEFINE:
303
304        appLinkNum = atoi(hyperData->specification);
305
306       if (appLinkNum == 100)     /* Move the window */
307         {
308
309           /* First Place the window in the upper left */
310           n = 0;
311           XtSetArg(args[n], XmNx, 0); ++n; 
312           XtSetArg(args[n], XmNy, 0); ++n;
313           XtSetValues(topLevel, args, n);
314         
315           /* Now move it down to the center of the display */
316
317           for (count = 1;count < 500; count= count+5)
318             {
319               n = 0;
320               XtSetArg(args[n], XmNx, count); ++n; 
321               XtSetArg(args[n], XmNy, count); ++n;
322               XtSetValues(topLevel, args, n);
323               XmUpdateDisplay(topLevel);
324             }
325
326         }
327
328
329       if (appLinkNum == 101)      /* Resize the window */
330         {
331
332         if (width == 0)
333           {
334             /* Get the current dialog size */
335             n =0;
336             XtSetArg (args[n], XmNheight, &height);  n++;
337             XtSetArg (args[n], XmNwidth, &width);   n++;
338             XtGetValues(topLevel, args, n);
339           }
340
341         if (goBigger)
342           {
343             n =0;
344             XtSetArg (args[n], XmNheight, height+100);  n++;
345             XtSetArg (args[n], XmNwidth, width+50);   n++;
346             XtSetValues(topLevel, args, n);
347             goBigger = FALSE;
348           }
349         else
350           {
351             /* Go smaller */
352             n =0;
353             XtSetArg (args[n], XmNheight, height);  n++;
354             XtSetArg (args[n], XmNwidth, width);   n++;
355             XtSetValues(topLevel, args, n);
356             goBigger = TRUE;
357           }
358
359         }
360  
361
362       if (appLinkNum == 102)  
363         {
364
365         }
366
367       if (appLinkNum == 103)  
368         {
369
370         }
371
372       break;
373
374       default:  /* Catches any other  applicaion definded link types */
375
376          printf("We some how got a bogus hyptertext link type/n");
377
378
379     }  /* End Switch Statement */
380  
381 }
382
383
384
385 \f
386 /****************************************************************************
387  * Function:        void DisplayMan()
388  *
389  * Parameters:      
390  *
391  * Return Value:    Void.
392  *
393  * Purpose:         Displays a UNIX man page in a quick help dialog.
394  *
395  ****************************************************************************/
396 void DisplayMan(
397     Widget  parent,
398     char    *man)
399
400 {
401
402   Arg  args[20];
403   int    n;
404   Widget helpWidget;
405   char *title;
406
407   XmUpdateDisplay(topLevel);
408  
409
410
411   if (manWidget == NULL)
412     {    
413       /* Create the QuickHelpDialog widget for help on help */
414       title = XtNewString(man);
415  
416       n =0;
417       XtSetArg (args[n], XmNuseAsyncGeometry, True);         n++;
418       XtSetArg (args[n], XmNtitle, title);                   n++;
419       XtSetArg (args[n], DtNhelpType,DtHELP_TYPE_MAN_PAGE); n++; 
420       XtSetArg (args[n], DtNmanPage, man);                   n++;
421       manWidget = DtCreateHelpQuickDialog(topLevel,"manBox", args, n);
422       XtFree((char*) title);
423
424
425       XtAddCallback(manWidget, DtNcloseCallback,
426                     CloseMainCB, (XtPointer) manWidget);
427  
428       /* Add the popup position callback to our man dialog */
429       XtAddCallback (XtParent(manWidget), XmNpopupCallback,
430                     (XtCallbackProc)HelpMapCB, 
431                     (XtPointer)topLevel);
432  
433
434
435
436       /* We do not want a help button for now so we unmap it */     
437       helpWidget = DtHelpQuickDialogGetChild (manWidget,
438                               DtHELP_QUICK_HELP_BUTTON);
439       XtUnmanageChild (helpWidget);
440
441       XtManageChild(manWidget);  
442     }
443   else
444     {
445        TurnOnHourGlass(manWidget);
446   
447        /* We already have a quick help dialog so re-use it */
448        n = 0;
449        XtSetArg (args[n], DtNhelpType,DtHELP_TYPE_MAN_PAGE); n++; 
450        XtSetArg (args[n], DtNmanPage, man);                   n++;
451      
452        XtSetValues(manWidget, args, n);
453        
454
455        title = XtNewString(man);
456        n = 0;
457        XtSetArg (args[n], XmNtitle, title);                   n++;
458        XtSetValues(XtParent(manWidget), args, n);
459        XtFree((char*) title);
460
461        XtManageChild(manWidget); 
462        XtMapWidget(XtParent(manWidget));    
463        XRaiseWindow(XtDisplay(parent), XtWindow(XtParent(manWidget)));
464        TurnOffHourGlass(manWidget);       
465
466      }
467
468 }
469
470   
471 /****************************************************************************
472  * Function:        void DisplayTopic(
473  *                              Widget parent,
474  *                              char *helpVolume,
475  *                              char *locationId)
476  *
477  * Parameters:      
478  *
479  * Return Value:    Void.
480  *
481  * Purpose:         Creats and displays a new help dialog w/the requested help
482  *                  volume and topic.
483  *
484  ****************************************************************************/
485 void DisplayTopic(
486     Widget  parent,
487     char    *helpVolume,
488     char    *locationId)
489
490 {
491   Arg           args[10];       
492   int           n;
493
494  CacheListStruct *pCurrentNode = NULL;
495   Boolean       cachedNode = FALSE;
496
497
498   /* Get a inuse node if we have one or a Cached one */
499   cachedNode = GetFromCache(parent, &pCurrentNode);
500
501
502   /* If we got a free one from the Cache, use it */
503   /* Set Values on current free one, then map it */
504   if (cachedNode)
505     {
506        n = 0;
507        XtSetArg (args[n], XmNtitle, "HelpDemo Help");          n++;
508        if (helpVolume != NULL)
509          {
510            XtSetArg (args[n],DtNhelpVolume,helpVolume);     n++; 
511          }
512        XtSetArg (args[n], DtNlocationId,locationId);        n++;
513        XtSetValues(pCurrentNode->helpDialog, args, n);
514   
515        XtManageChild(pCurrentNode->helpDialog);    
516        XtMapWidget(XtParent(pCurrentNode->helpDialog));
517      }
518    else
519      {
520        while (!XtIsSubclass(parent, applicationShellWidgetClass))
521          parent = XtParent(parent);
522      
523
524
525         /* Build a new one in our cached list */
526         n = 0;
527         XtSetArg (args[n], XmNtitle, "Helpdemo Help");          n++;
528        if (helpVolume != NULL)
529          {
530            XtSetArg (args[n],DtNhelpVolume,helpVolume);     n++; 
531          }
532         XtSetArg (args[n], DtNlocationId,locationId);        n++;
533         pCurrentNode->helpDialog =  
534                    DtCreateHelpDialog(parent, "helpWidget", args, n);
535
536
537         XtAddCallback(pCurrentNode->helpDialog, DtNhyperLinkCallback,
538                        ProcessLinkCB, NULL);
539              
540         XtAddCallback(pCurrentNode->helpDialog, DtNcloseCallback,
541                       CloseHelpCB, (XtPointer) pCurrentNode->helpDialog);
542
543         XtManageChild(pCurrentNode->helpDialog);    
544         XtMapWidget(XtParent(pCurrentNode->helpDialog));
545      }
546 }
547
548
549
550
551 \f
552 /****************************************************************************
553  * Function:        void DisplayMain(
554  *                              Widget parent,
555  *                              char *helpVolume,
556  *                              char *locationId)
557  *
558  * Parameters:      
559  *
560  * Return Value:    Void.
561  *
562  * Purpose:         Displays help for helpdemo in the one helpDialog window 
563  *                  created for the applicaiton.
564  *
565  ****************************************************************************/
566 void DisplayMain (
567     Widget  parent,
568     char    *helpVolume,
569     char    *locationId)
570
571 {
572   Arg           args[10];       
573   int           n;
574  
575   if (helpMain != NULL)
576     {
577        n = 0;
578        XtSetArg (args[n], XmNtitle, "hemodemo Help");          n++;
579        if (helpVolume != NULL)
580          {
581            XtSetArg (args[n],DtNhelpVolume,helpVolume);     n++; 
582          }
583        XtSetArg (args[n], DtNlocationId,locationId);        n++;
584        XtSetValues(helpMain, args, n);
585   
586        XtManageChild(helpMain);    
587        
588      }
589    else
590      {
591        while (!XtIsSubclass(parent, applicationShellWidgetClass))
592          parent = XtParent(parent);
593      
594
595         /* Build a new one in our cached list */
596         n = 0;
597         XtSetArg (args[n], XmNtitle, "Helpdemo Help");       n++;
598        if (helpVolume != NULL)
599          {
600            XtSetArg (args[n],DtNhelpVolume,helpVolume);     n++; 
601          }
602         XtSetArg (args[n], DtNlocationId,locationId);        n++;
603         helpMain = DtCreateHelpDialog(parent, "helpWidget", args, n);
604
605         XtAddCallback(helpMain, DtNhyperLinkCallback,
606                        ProcessLinkCB, NULL);
607              
608         XtAddCallback(helpMain, DtNcloseCallback,
609                       CloseMainCB, (XtPointer) helpMain);
610
611         /* Add the popup position callback to our main help dialog */
612         XtAddCallback (XtParent(helpMain), XmNpopupCallback,
613                         (XtCallbackProc)HelpMapCB, 
614                         (XtPointer)parent);
615  
616         XtManageChild(helpMain);    
617         
618      }
619 }
620
621
622
623
624
625 \f
626 /****************************************************************************
627  * Function:        void DisplayVersion(
628  *                              Widget parent,
629  *                              char *helpVolume,
630  *                              char *locationId)
631  *
632  * Parameters:      
633  *
634  * Return Value:    Void.
635  *
636  * Purpose:         Displays the version dialog for the helpdemo program.
637  *
638  ****************************************************************************/
639 void DisplayVersion (
640     Widget  parent,
641     char    *helpVolume,
642     char    *locationId)
643
644 {
645   Arg           args[10];       
646   int           n;
647   Widget        printWidget;
648   Widget        helpWidget;
649   Widget        backWidget;
650
651  
652   if (versionMain != NULL)
653     {
654        n = 0;
655        XtSetArg (args[n], XmNtitle, "Helpdemo Version Dialog");          n++;
656        if (helpVolume != NULL)
657          {
658            XtSetArg (args[n],DtNhelpVolume,helpVolume);     n++; 
659          }
660        XtSetArg (args[n], DtNlocationId,locationId);        n++;
661        XtSetValues(versionMain, args, n);
662   
663        XtManageChild(versionMain);    
664        
665      }
666    else
667      {
668        while (!XtIsSubclass(parent, applicationShellWidgetClass))
669          parent = XtParent(parent);
670      
671
672         /* Build a new one in our cached list */
673         n = 0;
674         XtSetArg (args[n], XmNtitle, "Helpdemo Version Dialog");       n++;
675        if (helpVolume != NULL)
676          {
677            XtSetArg (args[n],DtNhelpVolume,helpVolume);     n++; 
678          }
679         XtSetArg (args[n], DtNlocationId,locationId);        n++;
680         XtSetArg (args[n], DtNhelpType, DtHELP_TYPE_TOPIC);  n++;
681         versionMain = DtCreateHelpQuickDialog(parent,"versionWidget",args,n);
682
683         XtAddCallback(versionMain, DtNcloseCallback,
684                       CloseMainCB, (XtPointer) versionMain);
685
686
687         /* We do not want a print button for now so we unmap it */     
688         printWidget = DtHelpQuickDialogGetChild (versionMain, 
689                                          DtHELP_QUICK_PRINT_BUTTON);
690         XtUnmanageChild (printWidget);
691   
692
693         /* We do not want a help button for now so we unmap it */     
694         helpWidget = DtHelpQuickDialogGetChild (versionMain, 
695                                         DtHELP_QUICK_HELP_BUTTON);
696         XtUnmanageChild (helpWidget);
697   
698         backWidget = DtHelpQuickDialogGetChild (versionMain, 
699                                         DtHELP_QUICK_BACK_BUTTON);
700         XtUnmanageChild (backWidget);
701
702         XtManageChild(versionMain);    
703         
704      }
705 }
706
707
708
709
710
711 \f
712 /****************************************************************************
713  * Function:        static CacheListStruct GetFromCache(
714  *                                  Widget parent);
715  *
716  * Parameters:      
717  *
718  * Return Value:    Void.
719  *
720  * Purpose:         Gets a free help node form our cache list.  If none are
721  *                  free, it will return fallse and the calling routine will
722  *                  create a new help dialog widget.
723  *
724  ****************************************************************************/
725 static Boolean GetFromCache(
726     Widget parent,
727     CacheListStruct **pCurrentNode)
728
729 {
730
731   CacheListStruct *pTemp; 
732  
733   if (pCacheListHead == NULL)
734     {
735        /* We have a new list so lets create one and pass it back */
736        pCacheListHead = 
737                 (CacheListStruct *) XtMalloc((sizeof(CacheListStruct)));
738
739        /* Assign the default values to our node */
740        pCacheListHead->helpDialog = NULL;
741        pCacheListHead->inUseFlag  = TRUE;
742        pCacheListHead->pNext      = NULL;
743        pCacheListHead->pPrevious = NULL;
744
745        /* Assign our tale pointer */
746        pCacheListTale = pCacheListHead;
747
748        /* Make sure or totalNodes counter is correct, e.g. force it to 1 */
749        totalCacheNodes = 1;
750     
751        /* Return our head pointer because it's our first and only node */
752        *pCurrentNode = pCacheListHead;
753        return (FALSE);
754
755     }
756   else
757     { 
758        /* We have need for an in-use help dialog or a new one, so look */
759        pTemp = pCacheListHead;
760       
761        while (pTemp != NULL)
762          {
763            if (pTemp->inUseFlag == FALSE)
764              {
765                 pTemp->inUseFlag = TRUE;
766                 *pCurrentNode = pTemp;
767                 return (TRUE);
768               }
769            else
770              pTemp = pTemp->pNext;
771          }
772       
773
774        /* If we did not find a free nod then we must add a new one to the
775         * top of the list, and return it.
776         */
777
778        pTemp =  (CacheListStruct *) XtMalloc((sizeof(CacheListStruct)));
779
780        /* Assign the default values to our node */
781        pTemp->helpDialog = NULL;
782        pTemp->inUseFlag  = TRUE;
783      
784        pTemp->pNext      = pCacheListHead;
785        pTemp->pPrevious  = NULL;
786
787        pCacheListHead->pPrevious = pTemp;
788
789        /* Re-Assign our head pointer to point to the new head of the list */
790        pCacheListHead = pTemp;
791
792        /* Make sure or totalNodes counter is correct, e.g. force it to 1 */
793        totalCacheNodes = totalCacheNodes + 1;
794
795        /* Return our head pointer because it's our new node */
796        *pCurrentNode = pCacheListHead;
797        return (FALSE);
798
799      }
800   
801
802 }
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821