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