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