Link with C++ linker
[oweals/cde.git] / cde / programs / dthello / dthello.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 /*                                                                      *
24  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
25  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
26  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
27  * (c) Copyright 1993, 1994 Novell, Inc.                                *
28  */
29 #ifdef VERBOSE_REV_INFO
30 static char rcsid[] = "$TOG: dthello.c /main/9 1998/04/20 12:52:17 mgreess $";
31 #endif /* VERBOSE_REV_INFO */
32 /******************************<+>*************************************
33  **********************************************************************
34  **
35  **  File:        dthello.c
36  **
37  **  Project:     HP Visual User Environment
38  **
39  **  Description:
40  **  -----------
41  **  This file implements the startup transition for the DT 
42  **  environment
43  **
44  **
45  **********************************************************************
46  **
47  **     (c) Copyright 1990, 1991, 1992 Hewlett-Packard Company
48  **     All rights reserved
49  **
50  **********************************************************************
51  ******************************<+>*************************************/
52
53 /*
54  * Notes on conditional compilation:
55  *
56  * AUTO_TOP     If defined, the dthello window will automatically
57  *              raise itself over any window that obscures it.
58  *
59  * BLOCK_CENTER_FILES
60  *              If defined, dthello will center the text from
61  *              input files as a block as opposed to line-by-line.
62  */
63
64 /*
65  * Included Files:
66  */
67
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <X11/Xlib.h>
71 #include <X11/Intrinsic.h>
72 #include <X11/StringDefs.h>
73 #include <X11/Xutil.h>
74 #include <Xm/MwmUtil.h>
75 #include <sys/signal.h>
76 #include <Xm/Xm.h>
77 #include <Dt/GetDispRes.h>
78 #ifdef __apollo
79 #include </sys5/usr/include/limits.h>
80 #else
81 #include <limits.h>
82 #endif
83 #include <locale.h>
84 #ifndef NO_MESSAGE_CATALOG
85 # include <nl_types.h>
86 #endif
87
88 #include <Dt/EnvControlP.h>
89 #include "dthello.h"
90
91 #ifndef NO_MESSAGE_CATALOG
92 # define GETMESSAGE(set, number, string)    GetMessage(set, number, string)
93 #else
94 # define GETMESSAGE(set, number, string)    string
95 #endif
96
97 #if !defined(NL_CAT_LOCALE)
98 #define NL_CAT_LOCALE 0
99 #endif
100
101 /* 
102  * Globals
103  */
104 Window              welcome;            /* Welcome window ID */
105 Display            *dpy;                /* X server connection */
106 struct globalStruct vhGD;
107 int                 x_offset = 0;       /* for left-justifying text */
108 int                 box_line_width = 0; /* for drawing a box */
109 XFontSet            fontset;            /* Font descriptor for ILS */
110 unsigned long       textHeight;         /* Font size parameters */
111 unsigned long       fg, bg;             /* Pixel values */
112 Boolean             colorSuccess = True; /* Success at allocating colors */
113 XGCValues           gcv;                /* Struct for creating GC */
114 unsigned int        totalHeight;        /* total Height used for text */
115 unsigned int        displayHeight;      /* height of display in pixels */
116 int                 maxWidth;           /* max width of lines read in from file */
117 unsigned int        displayWidth;       /* width of display in pixels */
118 GC                  gc;                 /* GC to draw with */
119
120 static XrmOptionDescRec optTable[] = {
121 {"-font",       "*vfont",       XrmoptionSepArg,        (XtPointer) NULL},
122 {"-fnt",        "*vfont",       XrmoptionSepArg,        (XtPointer) NULL},
123 };
124 static int noptTable = sizeof(optTable)/sizeof(optTable[0]);
125
126 ArgSpec argSpecs[] =
127 {
128     {"-bground", 8},    /* background color */
129 #define BG_ARG          0
130
131     {"-fground", 8},    /* foreground color */
132 #define FG_ARG          1
133
134     {"-string", 7},     /* string to display */
135 #define STRING_ARG      2
136
137     {"-fnt", 4},        /* font to use */
138 #define FONT_ARG        3
139
140     {"-timeout", 8},    /* timeout amount in seconds*/
141 #define TIME_ARG        4
142
143     {"-file", 5},       /* file */
144 #define FILE_ARG        5
145
146 };
147
148 char          *ppchFileNames[MAX_FILES]; /* names of files to print */
149 unsigned char *ppchText[MAX_LINES]; /* text lines to print out */
150 int            numFiles;            /* number of files to print */
151 int numLines;                       /* number of text lines to print out */
152 #ifdef BLOCK_CENTER_FILES
153 int            centerLines;         /* number of text lines to print centered */
154 #endif /* BLOCK_CENTER_FILES */
155 char *progName;                     /* who we are */
156 char          *fontArg;             /* font argument */
157 int            sizeFontArg;
158 char          *stringArg;           /* string argument */
159 int            sizeStringArg;
160 char          *bgArg;               /* background argument */
161 int            sizeBgArg;
162 char          *fgArg;               /* foreground argument */
163 int            sizeFgArg;
164 char          *xoffsetArg;          /* text x_offset argument */
165 int            sizeXoffsetArg;
166 char          *timeArg;             /* timeout argument, in seconds */
167 int            sizeTimeArg;
168 int            sizeFileArg;
169 Boolean        Done;                /* while painting text */
170
171 static VhResourceEntry restable[] = {
172     { vNbackground,  vCBackground, &bgArg,              &sizeBgArg      },
173     { vNforeground,  vCForeground, &fgArg,              &sizeFgArg      },
174     { vNfont,        vCFont,       &fontArg,            &sizeFontArg    },
175     { vNxoffset,     vCXoffset,    &xoffsetArg,         &sizeXoffsetArg },
176     { vNstring,      vCString,     &stringArg,          &sizeStringArg  },
177     { vNfile,        vCFile,       &ppchFileNames[0],   &sizeFileArg    },
178     { vNtimeout,     vCTimeout,    &timeArg,            &sizeTimeArg    },
179 };
180
181 void
182 Usage(void)
183 {
184       fprintf(stderr, (char *) GETMESSAGE (4, 4, 
185 "usage: %s [-display <display>] [-bground <color>] [-fground <color>]\n"),
186                   progName);
187       fprintf(stderr, (char *) GETMESSAGE (4, 5, 
188 "\t[-font <font>] [-string <message>] [-timeout <seconds>] [-file <name>]\n"));
189 }
190
191 \f
192 /*************************************<->*************************************
193  *
194  *  main (argc, argv)
195  *
196  *
197  *  Description:
198  *  -----------
199  *  This is the main routine that does almost all the work.
200  *
201  *  Inputs:
202  *  ------
203  *  argc = Std C argument count
204  *  argv = Std C argument vector
205  *
206  *  Outputs:
207  *  --------
208  *  Exit code
209  *
210  *  Comments:
211  *  ---------
212  *  This works by creating an override-redirect window the size of
213  *  the screen and painting a message on it. At the same time, a 
214  *  1x1 window is created that will be picked up by the window 
215  *  manager.  When the window manager reparents the little window,
216  *  this program exits.
217  *
218  *  Synopsis:
219  *  ---------
220  *  dthello [-display <display>] [-fground <color>] [-bground <color>]
221  *           [-font <fontname>] [-string <message>] [-file <filename>]
222  *           [-timeout <seconds>]
223  * 
224  *************************************<->***********************************/
225 main (int argc, char **argv)
226 {
227     Window      wmwin;          /* Window ID for wm */
228     XEvent      event;          /* Event received */
229     unsigned long mask;         /* mask for window attribs */
230     XSetWindowAttributes xwa;   /* Set Window Attribute struct */
231     int         argn;           /* temp for parsing args */
232     XColor      colorDef;       /* for parsing/allocating colors */
233     Colormap    colormap;       /* color map of screen */
234     Atom        xaMwmHints;     /* mwm hints atom */
235     PropMotifWmHints  mwmHints; /* mwm hints structure */
236     Visual *pdv;                /* X visual structure */
237     FILE        *fp;            /* file pointer */
238     int         i;              /* loop index */
239     char        *default_string;        /* default message */
240     XtAppContext appcontext;
241     int         n;              /* for Arglist processing */
242     Arg         args[10];
243     Widget                      topLevelWid;
244     char        *def_str;
245     char        **missing_clist;
246     int         missing_count;
247     XFontSetExtents *extents;
248
249     XtSetLanguageProc( NULL, NULL, NULL );
250
251     /*
252      * Initialization
253      */
254     /*
255      * Set up NLSPATH, app-defaults, etc. for this DT client.
256      */
257     _DtEnvControl(DT_ENV_SET);
258
259     /*
260      * Process command line arguments
261      */
262     progName = argv[0];
263     /* fontArg = DEFAULT_FONT; */
264     bgArg = NULL;
265     fgArg = NULL;
266     timeArg = DEFAULT_TIME;
267     numFiles = 0;
268     sizeFileArg = 0;
269
270     /*
271      * Initialize  Toolkit, open display
272      */
273     XtToolkitInitialize();
274     appcontext = XtCreateApplicationContext();
275
276     dpy = XtOpenDisplay (appcontext, NULL, argv[0], DTHELLO_CLASS_NAME, 
277                          optTable, noptTable, (int *)(&argc), argv);
278
279     if (dpy == NULL) 
280     {
281         setlocale(LC_ALL, "");
282         fprintf(stderr, (char *) 
283             GETMESSAGE(4, 1, "%s: can't open display\n"), progName);
284         exit(1);
285     }
286
287     default_string = strdup (
288     ((char *)GETMESSAGE(2, 3, 
289                         "Starting the\nCommon Desktop Environment\n\n")));
290
291     stringArg = default_string;
292
293     /*
294      * Find appropriate default font
295      * and offset from the left side of the screen
296      */
297
298     switch (_DtGetDisplayResolution(dpy, XDefaultScreen(dpy)))
299     {
300         case LOW_RES_DISPLAY:
301                 fontArg = DEFAULT_FONT_SMALL;
302                 x_offset = DEFAULT_XOFFSET_SMALL;
303                 box_line_width = BOX_LINE_WIDTH_SMALL;
304                 break;
305         
306         case MED_RES_DISPLAY:
307                 fontArg = DEFAULT_FONT_MEDIUM;
308                 x_offset = DEFAULT_XOFFSET_MEDIUM;
309                 box_line_width = BOX_LINE_WIDTH_MEDIUM;
310                 break;
311
312         case HIGH_RES_DISPLAY:
313                 fontArg = DEFAULT_FONT_LARGE;
314                 x_offset = DEFAULT_XOFFSET_LARGE;
315                 box_line_width = BOX_LINE_WIDTH_LARGE;
316                 break;
317         default:
318                 fontArg = DEFAULT_FONT_SMALL;
319                 x_offset = DEFAULT_XOFFSET_SMALL;
320                 box_line_width = BOX_LINE_WIDTH_SMALL;
321                 break;
322     }
323
324     /*
325      * Fetch resources
326      */
327     VhGetResources (dpy, progName, DTHELLO_CLASS, 
328                         restable, XtNumber(restable));
329
330     /* assign the x_offset to the value set in the resource list if given by the user */
331     /* RK 11.06.93                                                                    */
332     if( xoffsetArg != NULL)
333         x_offset = atoi(xoffsetArg);
334     if (x_offset < 0)
335     {
336         x_offset = -x_offset;
337     }
338
339     if (sizeFileArg != 0)
340     {
341         numFiles = 1;
342     }
343
344     /*
345      * Parse remaining command line arguments
346      */
347     for (argn = 1; argn < argc; argn++)
348     {
349         if ((*argv[argn] == '-') &&
350             (argn+1 < argc))
351         {
352             if (ArgMatch (argv[argn], BG_ARG))
353             {
354                 bgArg = argv[++argn];
355                 continue;
356             }
357
358             else if (ArgMatch (argv[argn], FG_ARG))
359             {
360                 fgArg = argv[++argn];
361                 continue;
362             }
363
364             else if (ArgMatch (argv[argn], STRING_ARG))
365             {
366                 stringArg = argv[++argn];
367                 continue;
368             }
369
370             else if (ArgMatch (argv[argn], FONT_ARG))
371             {
372                 fontArg = argv[++argn];
373                 continue;
374             }
375
376             else if (ArgMatch (argv[argn], TIME_ARG))
377             {
378                 timeArg = argv[++argn];
379                 if (atoi(timeArg) <= 0)
380                 {
381                     fprintf (stderr, (char *) 
382                         GETMESSAGE(4, 2, "%s: timeout must be positive\n"),
383                         argv[0]);
384                     timeArg = DEFAULT_TIME;
385                 }
386                 continue;
387             }
388
389             else if (ArgMatch (argv[argn], FILE_ARG))
390             {
391                 argn++;
392                 if (numFiles < MAX_FILES)
393                 {
394                     ppchFileNames[numFiles] = (char *) argv[argn];
395                     numFiles++;
396                 }
397                 else
398                 {
399                   fprintf(stderr, (char *) GETMESSAGE(4, 3, 
400                       "%1$s: Maxiumum of %2$d files allowed, skipping %3$s\n"), 
401                       argv[0], MAX_FILES, argv[argn]);
402                 }
403                 continue;
404             }
405
406             else
407             {
408                 Usage();
409                 exit(1);
410             }
411         }
412         else
413         {
414             Usage();
415             exit(1);
416         }
417     }
418
419
420     displayHeight = XDisplayHeight (dpy, XDefaultScreen(dpy));
421     displayWidth = XDisplayWidth (dpy, XDefaultScreen(dpy));
422
423     /*
424      * Set default fg/bg colors if not specified.
425      * (adjust for low-color systems)
426      */
427
428     pdv = XDefaultVisual(dpy, XDefaultScreen(dpy));
429
430     /*
431      * Set default colors if not specified on command line.
432      */
433     if ((XDefaultDepth(dpy, XDefaultScreen(dpy)) <= 4) ||
434         (pdv->class == StaticGray) ||
435         (pdv->class == GrayScale))
436     {
437         /*
438          * B&W, GrayScale, or low-color systems
439          */
440         if (!bgArg)
441         {
442             bgArg = DEFAULT_LOW_BG;
443         }
444
445         if (!fgArg)
446         {
447             fgArg = DEFAULT_LOW_FG;
448         }
449     }
450     else
451     {
452         /*
453          * Medium- to High-color systems
454          */
455         if (!bgArg)
456         {
457             bgArg = DEFAULT_BG;
458         }
459
460         if (!fgArg)
461         {
462             fgArg = DEFAULT_FG;
463         }
464     }
465
466     /*
467      * Load the font.
468      */
469     if ((fontset = XCreateFontSet(dpy, fontArg, &missing_clist, &missing_count,
470                                   &def_str)) == NULL)
471     {
472         fprintf(stderr, (char *) 
473             GETMESSAGE (4, 6, "%1$s: display %2$s doesn't know font %3$s\n"),
474                 argv[0], DisplayString(dpy), fontArg);
475
476         if ((fontset = XCreateFontSet(dpy, DEFAULT_FONT, &missing_clist,
477                                         &missing_count, &def_str)) == NULL)
478         {
479             fprintf(stderr, (char *)
480             GETMESSAGE (4, 6, "%1$s: display %2$s doesn't know font %3$s\n"),
481                     argv[0], DisplayString(dpy), DEFAULT_FONT);
482         }
483   
484         if ((NULL == fontset) &&
485             (fontset = XCreateFontSet(dpy, FIXED_FONT, &missing_clist,
486                                       &missing_count, &def_str)) == NULL)
487         {
488             fprintf(stderr, (char *)
489             GETMESSAGE (4, 6, "%1$s: display %2$s doesn't know font %3$s\n"),
490                     argv[0], DisplayString(dpy), FIXED_FONT);
491             exit(1);
492         }
493     }
494     extents = XExtentsOfFontSet(fontset);
495     textHeight = extents->max_ink_extent.height;
496
497     /*
498      * Print the copyright file by default if no other file
499      * specified
500      */
501 #ifdef DEFAULT_FILE
502     if (numFiles == 0)
503     {
504         ppchFileNames[numFiles] = (char *) DEFAULT_FILE;
505         numFiles = 1;
506     }
507 #endif
508
509     /*
510      * Break the text string up into separate lines
511      * and place into message buffer.
512      */
513     SeparateTextLines ((unsigned char *)stringArg);
514
515 #ifdef BLOCK_CENTER_FILES
516     centerLines = numLines;
517 #endif /* BLOCK_CENTER_FILES */
518
519     for (i = 0; i < numFiles; i++)
520     {
521         maxWidth = 0;
522         if (!(fp = fopen ((char *)ppchFileNames[i], "r")))
523         {
524             fprintf (stderr, (char *) 
525                 GETMESSAGE (4, 7, "%1$s: unable to open file %2$s\n"),
526                 argv[0], ppchFileNames[i]);
527         }
528         else
529         {
530             /* 
531              * read in lines
532              */
533             ReadInTextLines (fp, fontset, (unsigned int *)&maxWidth);
534         }
535     }
536
537     /*
538      * Get the colors 
539      */
540     colormap = XDefaultColormap (dpy, XDefaultScreen(dpy));
541
542     /* 
543      * Get background color
544      */
545     if (!XParseColor (dpy, colormap, bgArg, &colorDef))
546     {
547         /* failed to get background color, try low color default */
548         colorSuccess = False; 
549         fprintf(stderr, (char *) GETMESSAGE (4, 8, 
550             "%1$s: can't set background to %2$s, using %3$s.\n"),
551                     argv[0], bgArg, DEFAULT_LOW_BG);
552         XParseColor (dpy, colormap, DEFAULT_LOW_BG, &colorDef);
553     }
554     XAllocColor (dpy, colormap, &colorDef);
555
556     bg = colorDef.pixel;
557
558     /* 
559      * Get foreground color
560      */
561     if (!XParseColor (dpy, colormap, fgArg, &colorDef))
562     {
563         /* failed to get foreground color, try low color default */
564         colorSuccess = False; 
565         fprintf(stderr, (char *) GETMESSAGE (4, 9, 
566             "%1$s: can't set foreground to %2$s, using %3$s.\n"),
567                     argv[0], fgArg, DEFAULT_LOW_FG);
568         XParseColor (dpy, colormap, DEFAULT_LOW_FG, &colorDef);
569     }
570     XAllocColor (dpy, colormap, &colorDef);
571
572     fg = colorDef.pixel;
573
574     /* 
575      * Create 1x1 window to catch reparenting action of window manager
576      * Request no mwm decoration to reduce flash.
577      * Request no mwm functions to avoid icon in icon box.
578      */
579     wmwin = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
580                               0, 0, 1, 1, 0, bg, bg);
581
582     xaMwmHints = XInternAtom (dpy, _XA_MOTIF_WM_HINTS, 0);
583
584     mwmHints.flags = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS;
585     mwmHints.decorations = 0;
586     mwmHints.functions = 0;
587
588     XChangeProperty (dpy, wmwin, xaMwmHints, xaMwmHints, 32, 
589         PropModeReplace, (unsigned char *) &mwmHints, 
590         sizeof(PropMotifWmHints)/sizeof(long));
591
592     XSelectInput (dpy, wmwin, StructureNotifyMask);
593
594     XMapWindow(dpy, wmwin);
595
596     /* 
597      * Create override-redirect window for display of transition
598      * message.
599      */
600
601     welcome = XCreateSimpleWindow (dpy, DefaultRootWindow (dpy), 0, 0,
602         displayWidth, displayHeight, 0, bg, bg);
603
604     mask = CWOverrideRedirect | CWEventMask | CWCursor;
605
606     xwa.override_redirect = 1;
607 #ifdef AUTO_TOP
608     xwa.event_mask = ExposureMask | VisibilityChangeMask;
609 #else /* AUTO_TOP */
610     xwa.event_mask = ExposureMask;
611 #endif /* AUTO_TOP */
612     xwa.cursor = GetHourGlass (dpy);
613
614     XChangeWindowAttributes (dpy, welcome, mask, &xwa);
615
616     XMapWindow(dpy, welcome);
617     /*
618      * Event loop for painting text
619      */
620
621     Done = True;
622
623     while (Done) 
624     {
625         /*
626          * Get the next event
627          */
628         /* XNextEvent(dpy, &event); */
629
630         XtAppNextEvent(appcontext, &event);
631
632         if (event.type == Expose && 
633             event.xexpose.window == welcome &&
634             event.xexpose.count == 0) 
635         {
636
637             /*
638              * Remove any other pending Expose events from the queue 
639              */
640             while (XCheckTypedEvent(dpy, Expose, &event));
641
642             /*
643              * Create the GC for drawing the box and painting the text.
644              */
645             gcv.foreground = fg;
646             gcv.background = bg;
647             gc = XCreateGC(dpy, welcome, (GCForeground | GCBackground), &gcv);
648             XClearWindow(dpy, welcome);
649             DrawBox();
650             PaintText();
651             XFlush(dpy);
652             Done = False;
653         }
654     } /* end while */
655
656     /* 
657      * set up the timeout
658      */
659     signal (SIGALRM, (void (*)()) CatchAlarm);
660     alarm (atoi(timeArg));
661
662     /*
663      * Event loop
664      */
665     while (True) 
666     {
667         /*
668          * Get the next event
669          */
670         /* XNextEvent(dpy, &event); */
671
672         XtAppNextEvent(appcontext, &event);
673
674         if (event.type == ReparentNotify &&
675             event.xany.window == wmwin)
676         {
677             /*
678              * this is our cue...exit, stage left
679              */
680             alarm(0);
681             break;
682         }
683         else
684         {
685                 /* normal color serving process */
686                 XtDispatchEvent(&event);                
687         }
688
689     } /* end while */
690
691     exit(0);
692 }
693
694 \f
695 /*************************************<->*************************************
696  *
697  *  ArgMatch (pch, arn)
698  *
699  *
700  *  Description:
701  *  -----------
702  *  This function determines if a string matches a predefined switch.
703  *
704  *  Inputs:
705  *  ------
706  *  pch = candidate string
707  *  arn = number of switch we are trying to match.
708  *
709  *  Outputs:
710  *  --------
711  *  Return = True if match succeeds.
712  *
713  *  Comments:
714  *  ---------
715  *  Would need work to be localized.
716  *
717  *************************************<->***********************************/
718 int
719 ArgMatch (char *pch, int arn)
720 {
721     int rval = False;
722
723     if (!strncmp(pch, argSpecs[arn].name, argSpecs[arn].len))
724     {
725         rval = True;
726     }
727
728     return (rval);
729 }
730
731 \f
732 /*************************************<->*************************************
733  *
734  *  SkipWhitespace (*pch)
735  *
736  *
737  *  Description:
738  *  -----------
739  *  This procedure scans a string and returns a pointer to the first
740  *  non-whitespace character.
741  *
742  *  Inputs:
743  *  ------
744  *  pch = pointer to string to scan
745  *
746  *  Outputs:
747  *  --------
748  *  Return = pointer to first non-white character
749  *
750  *  Comments:
751  *  ---------
752  *  Skips blanks and horizontal tabs.
753  *
754  *************************************<->***********************************/
755 unsigned char *
756 SkipWhitespace (unsigned char *pch)
757 {
758     int chlen;
759
760     if (pch)
761     {
762         while ((*pch != NULL) &&
763                ((chlen = mblen ((char *)pch, MB_CUR_MAX)) == 1) &&
764                ((*pch == '\t') || (*pch == ' ')))
765         {
766                 pch += chlen;
767         }
768     }
769     return (pch);
770 }
771
772
773 \f
774 /*************************************<->*************************************
775  *
776  *  KillNewlines (*pch)
777  *
778  *
779  *  Description:
780  *  -----------
781  *  This procedure scans a string and replaces the first newline
782  *  with a NULL.
783  *
784  *  Inputs:
785  *  ------
786  *  pch = pointer to string to scan
787  *
788  *  Outputs:
789  *  --------
790  *  pch = modified
791  *
792  *  Comments:
793  *  ---------
794  *
795  *************************************<->***********************************/
796 void
797 KillNewlines (unsigned char *pch)
798 {
799     int chlen;
800
801     if (pch)
802     {
803         while (*pch != NULL)
804         {
805             if (((chlen = mblen ((char *)pch, MB_CUR_MAX)) == 1) &&
806                 (*pch == '\n'))
807             {
808                 *pch = NULL;
809                 break;
810             }
811             pch += chlen;
812         }
813     }
814 }
815
816 \f
817 /*************************************<->*************************************
818  *
819  *  ReadInTextLines (fp, font, pMaxWidth)
820  *
821  *
822  *  Description:
823  *  -----------
824  *  This procedure reads in lines from a file for the message to 
825  *  display.
826  *
827  *  Inputs:
828  *  ------
829  *  pchIn = pointer to message string
830  *  font = font structure to be used to print with
831  *  pMaxWidth = width of largest line
832  *
833  *  Outputs:
834  *  --------
835  *  Return = none
836  *  modifies global numLines
837  *
838  *  Comments:
839  *  ---------
840  *  Global data ppchText is modified by this routine to contain 
841  *  copies of the text lines from pchIn. pchIn is not modified.
842  *
843  *************************************<->***********************************/
844 void
845 ReadInTextLines (FILE *fp, XFontSet fontset, unsigned int *pMaxWidth)
846 {
847     unsigned int width;
848     int allowedLines;
849
850     /* count the number of lines in the file */
851     allowedLines = (displayHeight - (2 * box_line_width))/ textHeight;
852
853     while (numLines < allowedLines)
854     {
855         ppchText[numLines] = (unsigned char *) malloc (1+MAX_COLUMNS);
856         if (!ppchText[numLines] ||
857             !fgets ((char *)ppchText[numLines], MAX_COLUMNS, fp))
858         {
859             break;
860         }
861         KillNewlines (ppchText[numLines]);
862 #ifndef BLOCK_CENTER_FILES
863         ppchText[numLines] = SkipWhitespace (ppchText[numLines]);
864 #endif /* not BLOCK_CENTER_FILES */
865         width = XmbTextEscapement(fontset, (char *)(ppchText[numLines]),
866                         strlen((char *)ppchText[numLines]));
867         if (width > *pMaxWidth)
868         {
869             *pMaxWidth = width;
870         }
871         numLines++;
872     }
873 }
874
875 \f
876 /*************************************<->*************************************
877  *
878  *  SeparateTextLines (pchIn)
879  *
880  *
881  *  Description:
882  *  -----------
883  *  This procedure takes a message string and separates it into
884  *  text lines based on the presence of new line characters.
885  *
886  *  Inputs:
887  *  ------
888  *  pchIn = pointer to message string
889  *
890  *  Outputs:
891  *  --------
892  *  Return = none
893  *
894  *  Comments:
895  *  ---------
896  *  Global data ppchText is modified by this routine to contain 
897  *  copies of the text lines from pchIn. pchIn is not modified.
898  *
899  *************************************<->***********************************/
900 void
901 SeparateTextLines (unsigned char *pchIn)
902 {
903     unsigned char *pch, *pch1, *pch2;
904     unsigned char *pchInEnd;
905     int i, chlen;
906
907     /* count the number of new line characters in the string */
908
909     numLines = 1;
910     for (pch = pchIn; *pch; )
911     {
912         if (((chlen = mblen ((char *)pch, MB_CUR_MAX)) == 1) &&
913             (*pch == '\n'))
914         {
915             numLines++;
916         }
917         pch += chlen;
918     }
919
920     if ((chlen == 1) && (*(pch-1) == '\n'))
921     {
922         numLines--;             /* don't count terminating newline */
923     }
924
925     pch2 = pch1 = pchIn;
926     pchInEnd = pchIn + strlen((char *)pchIn);
927
928     for (i = 0; (i < numLines) && (pch1 < pchInEnd); i++)
929     {
930         while ((*pch2 != NULL) &&
931                !(((chlen = mblen ((char *)pch2, MB_CUR_MAX)) == 1) &&
932                  (*pch2 == '\n')))
933         {
934             pch2 += chlen;
935         }
936         if (*pch2 == '\n')
937         {
938             *pch2 = '\0';
939         }
940
941         ppchText[i] = (unsigned char *) malloc (1+strlen ((char *)pch1));
942         if (ppchText[i])
943         {
944             strcpy ((char *)ppchText[i], (char *)pch1);
945         }
946         else
947         {
948             fprintf (stderr, (char *) GETMESSAGE (4, 10, 
949                 "%s: Insufficient memory (SeparateTextLines)\n"), 
950                 progName);
951             exit (1);
952         }
953
954         /* advance pointers */
955         pch1 = ++pch2;
956   
957     }
958 }
959
960
961 \f
962 /*************************************<->*************************************
963  *
964  *  CatchAlarm (sig)
965  *
966  *
967  *  Description:
968  *  -----------
969  *  This function catches the SIG_ALRM signal generated when the
970  *  timer expires.
971  *
972  *  Inputs:
973  *  ------
974  *  sig = signal number
975  *
976  *  Outputs:
977  *  --------
978  *  Return = none
979  *
980  *  Comments:
981  *  ---------
982  *
983  *************************************<->***********************************/
984 void
985 CatchAlarm ( int sig)
986 {
987     /* timer expired, exit */
988     exit(0);
989 }
990
991 \f
992 /*************************************<->*************************************
993  *
994  *  Cursor GetHourGlass ()
995  *
996  *
997  *  Description:
998  *  -----------
999  *  Builds and returns the appropriate Hourglass cursor
1000  *
1001  *
1002  *  Inputs:
1003  *  ------
1004  *  dpy = display
1005  * 
1006  *  Outputs:
1007  *  -------
1008  *  Return = cursor.
1009  *
1010  *  Comments:
1011  *  --------
1012  *  None. (None doesn't count as a comment)
1013  * 
1014  *************************************<->***********************************/
1015
1016 #define time32_width 32
1017 #define time32_height 32
1018 #define time32_x_hot 15
1019 #define time32_y_hot 15
1020 static unsigned char time32_bits[] = {
1021    0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
1022    0x8c, 0x00, 0x00, 0x31, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32,
1023    0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32,
1024    0x8c, 0x00, 0x00, 0x31, 0x0c, 0x7f, 0xfe, 0x30, 0x0c, 0xfe, 0x7f, 0x30,
1025    0x0c, 0xfc, 0x3f, 0x30, 0x0c, 0xf8, 0x1f, 0x30, 0x0c, 0xe0, 0x07, 0x30,
1026    0x0c, 0x80, 0x01, 0x30, 0x0c, 0x80, 0x01, 0x30, 0x0c, 0x60, 0x06, 0x30,
1027    0x0c, 0x18, 0x18, 0x30, 0x0c, 0x04, 0x20, 0x30, 0x0c, 0x02, 0x40, 0x30,
1028    0x0c, 0x01, 0x80, 0x30, 0x8c, 0x00, 0x00, 0x31, 0x4c, 0x80, 0x01, 0x32,
1029    0x4c, 0xc0, 0x03, 0x32, 0x4c, 0xf0, 0x1f, 0x32, 0x4c, 0xff, 0xff, 0x32,
1030    0xcc, 0xff, 0xff, 0x33, 0x8c, 0xff, 0xff, 0x31, 0xfe, 0xff, 0xff, 0x7f,
1031    0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00};
1032
1033 #define time32m_width 32
1034 #define time32m_height 32
1035 static unsigned char time32m_bits[] = {
1036    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1037    0xcf, 0x00, 0x00, 0xf3, 0x6e, 0x00, 0x00, 0x76, 0x6e, 0x00, 0x00, 0x76,
1038    0x6e, 0x00, 0x00, 0x76, 0x6e, 0x00, 0x00, 0x76, 0x6e, 0x00, 0x00, 0x76,
1039    0xce, 0x00, 0x00, 0x73, 0x8e, 0x7f, 0xfe, 0x71, 0x0e, 0xff, 0xff, 0x70,
1040    0x0e, 0xfe, 0x7f, 0x70, 0x0e, 0xfc, 0x3f, 0x70, 0x0e, 0xf8, 0x1f, 0x70,
1041    0x0e, 0xe0, 0x07, 0x70, 0x0e, 0xe0, 0x07, 0x70, 0x0e, 0x78, 0x1e, 0x70,
1042    0x0e, 0x1c, 0x38, 0x70, 0x0e, 0x06, 0x60, 0x70, 0x0e, 0x03, 0xc0, 0x70,
1043    0x8e, 0x01, 0x80, 0x71, 0xce, 0x00, 0x00, 0x73, 0x6e, 0x80, 0x01, 0x76,
1044    0x6e, 0xc0, 0x03, 0x76, 0x6e, 0xf0, 0x1f, 0x76, 0x6e, 0xff, 0xff, 0x76,
1045    0xee, 0xff, 0xff, 0x77, 0xcf, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff,
1046    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
1047
1048
1049 #define time16_x_hot 7
1050 #define time16_y_hot 7
1051 #define time16_width 16
1052 #define time16_height 16
1053 static unsigned char time16_bits[] = {
1054    0x00, 0x00, 0xfe, 0x7f, 0x14, 0x28, 0x14, 0x28, 0x14, 0x28, 0x24, 0x24,
1055    0x44, 0x22, 0x84, 0x21, 0x84, 0x21, 0x44, 0x22, 0x24, 0x24, 0x14, 0x28,
1056    0x94, 0x29, 0xd4, 0x2b, 0xfe, 0x7f, 0x00, 0x00};
1057
1058 #define time16m_width 16
1059 #define time16m_height 16
1060 static unsigned char time16m_bits[] = {
1061    0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f,
1062    0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f,
1063    0xfe, 0x7f, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff};
1064
1065
1066 Cursor GetHourGlass (Display *dpy)
1067 {
1068     unsigned char *bits;
1069     unsigned char *maskBits;
1070     unsigned int width;
1071     unsigned int height;
1072     unsigned int xHotspot;
1073     unsigned int yHotspot;
1074     Pixmap       pixmap;
1075     Pixmap       maskPixmap;
1076     XColor       xcolors[2];
1077     int          scr;
1078     unsigned int cWidth;
1079     unsigned int cHeight;
1080     int          useLargeCursors = 0;
1081     Cursor       waitCursor;
1082
1083     if (XQueryBestCursor (dpy, DefaultRootWindow(dpy), 
1084         32, 32, &cWidth, &cHeight))
1085     {
1086         if ((cWidth >= 32) && (cHeight >= 32))
1087         {
1088             useLargeCursors = 1;
1089         }
1090     }
1091
1092     if (useLargeCursors)
1093     {
1094         width = time32_width;
1095         height = time32_height;
1096         bits = time32_bits;
1097         maskBits = time32m_bits;
1098         xHotspot = time32_x_hot;
1099         yHotspot = time32_y_hot;
1100     }
1101     else
1102     {
1103         width = time16_width;
1104         height = time16_height;
1105         bits = time16_bits;
1106         maskBits = time16m_bits;
1107         xHotspot = time16_x_hot;
1108         yHotspot = time16_y_hot;
1109     }
1110
1111     pixmap = XCreateBitmapFromData (dpy, 
1112                      DefaultRootWindow(dpy), (char *)bits, 
1113                      width, height);
1114
1115     maskPixmap = XCreateBitmapFromData (dpy, 
1116                      DefaultRootWindow(dpy), (char *)maskBits, 
1117                      width, height);
1118
1119     xcolors[0].pixel = BlackPixelOfScreen(DefaultScreenOfDisplay(dpy));
1120     xcolors[1].pixel = WhitePixelOfScreen(DefaultScreenOfDisplay(dpy));
1121
1122     XQueryColors (dpy, 
1123                   DefaultColormapOfScreen(DefaultScreenOfDisplay
1124                                           (dpy)), xcolors, 2);
1125
1126     waitCursor = XCreatePixmapCursor (dpy, pixmap, maskPixmap,
1127                                       &(xcolors[0]), &(xcolors[1]),
1128                                       xHotspot, yHotspot);
1129     XFreePixmap (dpy, pixmap);
1130     XFreePixmap (dpy, maskPixmap);
1131
1132     return (waitCursor);
1133 }
1134
1135 #ifndef NO_MESSAGE_CATALOG
1136 /*****************************************************************************
1137  *
1138  * Function: GetMessage
1139  *
1140  * Parameters:
1141  *
1142  *   int        set -           The message catalog set number.
1143  *
1144  *   int        n -             The message number.
1145  *
1146  *   char       *s -            The default message if the message is not
1147  *                              retrieved from a message catalog.
1148  *
1149  * Returns: the string for set 'set' and number 'n'.
1150  *
1151  *****************************************************************************/
1152
1153 char * 
1154 GetMessage(
1155         int set,
1156         int n,
1157         char *s )
1158 {
1159         char *msg;
1160         char *lang;
1161         nl_catd catopen();
1162         char *catgets();
1163         static int first = 1;
1164         static nl_catd nlmsg_fd;
1165         if ( first ) 
1166         {
1167                 first = 0;
1168
1169                 lang = (char *) getenv ("LANG");
1170
1171                 if (!lang || !(strcmp (lang, "C"))) 
1172                         /*
1173                          * If LANG is not set or if LANG=C, then there
1174                          * is no need to open the message catalog - just
1175                          * return the built-in string "s".
1176                          */
1177                         nlmsg_fd = (nl_catd)-1;
1178                 else
1179                         nlmsg_fd = catopen("dthello", NL_CAT_LOCALE);
1180         }
1181         msg=catgets(nlmsg_fd,set,n,s);
1182         return (msg);
1183 }
1184 #endif
1185
1186 \f
1187 /*************************************<->*************************************
1188  *
1189  *  void VhGetResources
1190  *
1191  *
1192  *  Description:
1193  *  -----------
1194  *  Gets the resources for the client
1195  *
1196  *
1197  *  Inputs:
1198  *  ------
1199  * 
1200  *  Outputs:
1201  *  -------
1202  *
1203  *  Comments:
1204  *  --------
1205  * 
1206  *************************************<->***********************************/
1207
1208 void 
1209 VhGetResources(Display *dpy, char *name, char *class, 
1210     VhResourceEntry *res, int num)
1211 {
1212 #define INIT_SIZE   256
1213 #define SRCH_SIZE   20
1214     int i;
1215     XrmValue xrmv;
1216     XrmQuark  Qtype, Qstring, Qname, Qclass;
1217     XrmQuark Qnres[4], Qcres[4];
1218     XrmHashTable searchList[SRCH_SIZE];
1219
1220     /*
1221      * We only deal with string-type resources
1222      */
1223
1224     Qstring = XrmStringToQuark (XtRString);
1225
1226     /*
1227      * Get resource search list for "dthello"
1228      */
1229     XrmStringToQuarkList (name, Qnres);
1230     XrmStringToQuarkList (class, Qcres);
1231
1232     if (XrmQGetSearchList(XtDatabase(dpy), Qnres, Qcres, searchList,
1233                         SRCH_SIZE))
1234     {
1235         /*
1236          * Look for all resources at this level
1237          */
1238
1239         for (i = 0; i < num; i++)
1240         {
1241             Qname = XrmStringToQuark (res[i].resname);
1242             Qclass = XrmStringToQuark (res[i].resclass);
1243
1244             if ((XrmQGetSearchResource (searchList, Qname, Qclass, 
1245                                   &Qtype, &xrmv)) &&
1246                 (Qtype == Qstring))
1247             {
1248                 *(res[i].ppvalue) = (char *) xrmv.addr;
1249                 *res[i].size = (int) xrmv.size;
1250             }
1251         }
1252     }
1253 }
1254
1255 void
1256 PaintText( void )
1257 {
1258             int i, x, y;
1259             XFontSetExtents *extents;
1260
1261             /* 
1262              * Paint the string onto the screen
1263              */
1264
1265
1266             y = (displayHeight - totalHeight) / 2;
1267             if (y < 0)
1268             {
1269                y = 0;
1270             }
1271
1272             /* adjust origin by font metric */
1273             extents = XExtentsOfFontSet(fontset);
1274             y += -(extents->max_logical_extent.y);
1275
1276             x = box_line_width + x_offset;
1277
1278             for (i = 0; i < numLines; i++)
1279             {
1280                 /* draw the string */
1281                 XmbDrawString (dpy, welcome, fontset, gc, x, y, 
1282                         (char *)(ppchText[i]), strlen((char *)ppchText[i]));
1283
1284                 /* move to next "line" */
1285                 y += textHeight;
1286             }
1287 }
1288 void
1289 DrawBox( void )
1290 {
1291         int LTX, LTY, RTX, RTY, LBX, LBY, RBX, RBY;
1292         int L_middle;  /* pixels to the midpoint of the line width */
1293
1294         Boolean useDecoration = True;
1295
1296         /* compute the height of the font */
1297         totalHeight = textHeight * numLines;
1298
1299         /* 
1300          * Set limits
1301          */
1302         if ((( 2 * box_line_width ) + x_offset + maxWidth) > displayWidth)
1303         {
1304                 useDecoration = False;
1305                 x_offset = 0;
1306         }
1307
1308         if (!useDecoration)
1309                 return;
1310
1311         L_middle = box_line_width / 2;
1312         /********************************************************
1313         +----------------------------------------------+
1314         | (LTX, LTY)                        (RTX, RTY) |
1315         |                                              |
1316         |   (Draw counterclockwise, beginning from     |
1317         |    top left.)                                |
1318         |                                              |
1319         |                                              |
1320         |                                              |
1321         |                                              |
1322         |                                              |
1323         |                                              |
1324         | (LBX, LBY)                        (RBX, RBY) |
1325         +----------------------------------------------+
1326         ********************************************************/
1327         LTX = 0;
1328         LTY = 0;
1329
1330         RTX = displayWidth;
1331         RTY = 0;
1332
1333         LBX = 0;
1334         LBY = displayHeight;
1335
1336         RBX = displayWidth ;
1337         RBY = displayHeight;
1338
1339         XSetLineAttributes(dpy, gc, box_line_width, LineSolid, CapButt, JoinMiter);
1340         XDrawLine(dpy, welcome, gc, 
1341                                   LTX, LTY + L_middle,
1342                                   RTX, RTY + L_middle);
1343
1344         XDrawLine(dpy, welcome, gc, 
1345                                 RTX - L_middle, RTY, 
1346                                 RBX - L_middle, RBY);
1347
1348         XDrawLine(dpy, welcome, gc, 
1349                                 RBX, RBY - L_middle, 
1350                                 LBX, LBY - L_middle);
1351
1352         XDrawLine(dpy, welcome, gc, 
1353                                 LBX + L_middle, LBY, 
1354                                 LTX + L_middle, LTY);
1355
1356 }
1357
1358 int
1359 Xestrcmp(const char * const s1, const char * const s2)
1360 {
1361     if (s1 == s2) return 0;
1362     {
1363         const char * p1 = (s1) ? s1 : "";
1364         const char * p2 = (s2) ? s2 : "";
1365
1366         return strcmp((char *)p1, (char *)p2);
1367     }
1368 }
1369
1370 /**************         eof          ******************/