1 /*
2  * xutil.c
3  *
4  * Utilities for detailing with X
5  *
6  * (C) 1997 Randall Hopper
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met: 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer. 2.
12  * Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  */
29 
30 /*      ******************** Include Files                ************** */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <assert.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <signal.h>
41 #include <X11/Xlib.h>
42 #include <X11/Intrinsic.h>
43 #include <X11/StringDefs.h>
44 #include <X11/Shell.h>
45 #include <X11/Xaw/Dialog.h>
46 #include <X11/xpm.h>
47 #include "tvdefines.h"
48 #include "xutil.h"
49 #include "app_rsrc.h"
50 
51 /*  NOTE:  Do NOT include Scrollbar.h.  This incorrectly defines       */
52 /*    the arguments of XawScrolbarSetThumb to be doubles, not floats.  */
53 /*#include <X11/Xaw/Scrollbar.h>*/
54 void XawScrollbarSetThumb( Widget w, float top, float shown );
55 
56 /*      ******************** Local defines                ************** */
57 
58 #ifndef FXTV_LIBDIR
59 # define FXTV_LIBDIR X11BASE "/lib/X11/fxtv/%T/%N"
60 #endif
61 
62 #define RUNCMD_CHECK_TIMEOUT_MS 200
63 
64 #define WM_BORDER_PAD 40
65 
66 typedef struct {
67     pid_t                  cmd_pid;
68     TVUTIL_PIPE_END        end[3];
69     XtAppContext           app_context;
70     XUTIL_RUNCMD_CANCELCB *cancel_cb;
71     void                  *cancel_cb_data;
72     XUTIL_RUNCMD_DONECB   *done_cb;
73     void                  *done_cb_data;
74 } XUTIL_RUNCMD_STATE;
75 
76 
77 #define XLFD_SIZE_FOUNDRY 128
78 #define XLFD_SIZE_FAMILY  128
79 #define XLFD_SIZE_SMALL    30
80 
81 typedef struct {
82            char foundry    [ XLFD_SIZE_FOUNDRY ];
83            char family     [ XLFD_SIZE_FAMILY  ];
84            char weight     [ XLFD_SIZE_SMALL ];
85            char slant      [ XLFD_SIZE_SMALL ];
86            char set_width  [ XLFD_SIZE_SMALL ];
87            char ad_style   [ XLFD_SIZE_SMALL ];
88            char pixel_size [ XLFD_SIZE_SMALL ];
89            char point_size [ XLFD_SIZE_SMALL ];
90            char x_dpi      [ XLFD_SIZE_SMALL ];
91            char y_dpi      [ XLFD_SIZE_SMALL ];
92            char spacing    [ XLFD_SIZE_SMALL ];
93            char avg_width  [ XLFD_SIZE_SMALL ];
94            char charset_reg[ XLFD_SIZE_SMALL ];
95            char charset_enc[ XLFD_SIZE_SMALL ];
96 } TV_XLFD;
97 
98 /*      ******************** Private variables            ************** */
99 
100 static Atom         S_wm_delete_window;
101 
102 #ifdef THE_ACTUAL_ASCII_TEXT_TRANSLATIONS
103 
104 char G_transl_ascii_text[] =  "\
105 Ctrl<Key>A: beginning-of-line()\n\
106 Ctrl<Key>B: backward-character() \n\
107 Ctrl<Key>D: delete-next-character() \n\
108 Ctrl<Key>E: end-of-line() \n\
109 Ctrl<Key>F: forward-character() \n\
110 Ctrl<Key>G: multiply(Reset) \n\
111 Ctrl<Key>H: delete-previous-character() \n\
112 Ctrl<Key>J: newline-and-indent() \n\
113 Ctrl<Key>K: kill-to-end-of-line() \n\
114 Ctrl<Key>L: redraw-display() \n\
115 Ctrl<Key>M: newline() \n\
116 Ctrl<Key>N: next-line() \n\
117 Ctrl<Key>O: newline-and-backup() \n\
118 Ctrl<Key>P: previous-line() \n\
119 Ctrl<Key>R: search(backward) \n\
120 Ctrl<Key>S: search(forward) \n\
121 Ctrl<Key>T: transpose-characters() \n\
122 Ctrl<Key>U: multiply(4) \n\
123 Ctrl<Key>V: next-page() \n\
124 Ctrl<Key>W: kill-selection() \n\
125 Ctrl<Key>Y: insert-selection(CUT_BUFFER1) \n\
126 Ctrl<Key>Z: scroll-one-line-up() \n\
127 Ctrl<Key>\\\\: reconnect-im() \n\
128 Meta<Key>B: backward-word() \n\
129 Meta<Key>F: forward-word() \n\
130 Meta<Key>I: insert-file() \n\
131 Meta<Key>K: kill-to-end-of-paragraph() \n\
132 Meta<Key>Q: form-paragraph() \n\
133 Meta<Key>V: previous-page() \n\
134 Meta<Key>Y: insert-selection(PRIMARY, CUT_BUFFER0) \n\
135 Meta<Key>Z: scroll-one-line-down() \n\
136 Meta<Key>d: delete-next-word() \n\
137 Meta<Key>D: kill-word() \n\
138 Meta<Key>h: delete-previous-word() \n\
139 Meta<Key>H: backward-kill-word() \n\
140 Meta<Key>\\<: beginning-of-file() \n\
141 Meta<Key>\\>: end-of-file() \n\
142 Meta<Key>]: forward-paragraph() \n\
143 Meta<Key>[: backward-paragraph() \n\
144 ~Shift Meta<Key>Delete: delete-previous-word() \n\
145 Shift Meta<Key>Delete: backward-kill-word() \n\
146 ~Shift Meta<Key>BackSpace: delete-previous-word() \n\
147 Shift Meta<Key>BackSpace: backward-kill-word() \n\
148 <Key>Right: forward-character() \n\
149 <Key>Left: backward-character() \n\
150 <Key>Down: next-line() \n\
151 <Key>Up: previous-line() \n\
152 <Key>Delete: delete-previous-character() \n\
153 <Key>BackSpace: delete-previous-character() \n\
154 <Key>Linefeed: newline-and-indent() \n\
155 <Key>Return: newline() \n\
156 <Key>: insert-char() \n\
157 <Key>Kanji: reconnect-im() \n\
158 <FocusIn>: focus-in() \n\
159 <FocusOut>: focus-out() \n\
160 <Btn1Down>: select-start() \n\
161 <Btn1Motion>: extend-adjust() \n\
162 <Btn1Up>: extend-end(PRIMARY, CUT_BUFFER0) \n\
163 <Btn2Down>: insert-selection(PRIMARY, CUT_BUFFER0) \n\
164 <Btn3Down>: extend-start() \n\
165 <Btn3Motion>: extend-adjust() \n\
166 <Btn3Up>: extend-end(PRIMARY, CUT_BUFFER0) \n\
167 ";
168 
169 #endif
170 
171 char G_transl_ovr_ascii_text[] =  "\
172 <Enter>: display-caret(on) \n\
173 <Leave>: display-caret(off) \n\
174 ";
175 
176 char G_transl_ovr_ascii_text_1line[] =  "\
177 <Key>Return:   no-op()\n\
178 <Key>KP_Enter: no-op()\n\
179 <Key>Down:     no-op()\n\
180 <Key>Up:       no-op()\n\
181 <Key>Linefeed: no-op()\n\
182 Ctrl<Key>J:    no-op()\n\
183 Ctrl<Key>M:    no-op()\n\
184 Ctrl<Key>N:    no-op()\n\
185 Ctrl<Key>O:    no-op()\n\
186 Ctrl<Key>P:    no-op()\n\
187 Ctrl<Key>R:    no-op()\n\
188 Ctrl<Key>S:    no-op()\n\
189 Ctrl<Key>V:    no-op()\n\
190 Ctrl<Key>Z:    no-op()\n\
191 Meta<Key>V:    no-op()\n\
192 Meta<Key>Z:    no-op()\n\
193 ";
194 
195 /*      ******************** Forward declarations         ************** */
196 
197 /*      ******************** Function Definitions         ************** */
198 
199 
200 /**@BEGINFUNC**************************************************************
201 
202     Prototype  : TV_BOOL XUTILBitmapLoad(
203                       char   *bitmap_file,
204                       Widget  wgt,
205                       Pixmap *pixmap )
206 
207     Purpose    : Loads a bitmap (xbm) of depth 1.
208 
209     Programmer : 16-Mar-97  Randall Hopper
210 
211     Parameters : bitmap_file - I: filename of bitmap file
212                  wgt         - I: widget bitmap will be used on
213                  pixmap      - O: pixmap loaded (depth 1)
214 
215     Returns    : T = Success; F = Failure
216 
217     Globals    : None.
218 
219  **@ENDFUNC*****************************************************************/
220 
XUTILBitmapLoad(char * bitmap_file,Widget wgt,Pixmap * pixmap)221 TV_BOOL XUTILBitmapLoad( char   *bitmap_file,
222                       Widget  wgt,
223                       Pixmap *pixmap )
224 {
225     char           *pixmap_path = NULL;
226     unsigned        width,
227                     height;
228     int             x_hot,
229                     y_hot;
230 
231     /********************************************/
232     /*  Look for the pixmap file in FXTV_LIBDIR */
233     /********************************************/
234 
235     pixmap_path = XtResolvePathname( XtDisplay(wgt), "bitmaps", bitmap_file,
236                                      NULL, FXTV_LIBDIR, NULL, 0, NULL);
237 
238     if ( pixmap_path == NULL ) {
239         fprintf( stderr, "Failed to find bitmap '%s'\n", bitmap_file );
240         return False;
241     }
242 
243     if ( XReadBitmapFile( XtDisplay(wgt),
244                           RootWindowOfScreen( XtScreen( wgt ) ),
245                           pixmap_path, &width, &height, pixmap,
246                           &x_hot, &y_hot ) != BitmapSuccess ) {
247         fprintf( stderr, "Failed to load bitmap '%s'\n", pixmap_path );
248         if ( pixmap_path != NULL )
249             XtFree( pixmap_path );
250         return False;
251     }
252 
253     XtFree( pixmap_path );
254     return True;
255 }
256 
257 
258 /**@BEGINFUNC**************************************************************
259 
260     Prototype  : TV_BOOL XUTILPixmapLoad(
261                       char    *pixmap_file,
262                       Widget   wgt,
263                       Pixel    fg_color,
264                       Pixel    bg_color,
265                       Pixmap  *pixmap,
266                       Pixmap  *pixmap_mask )
267 
268     Purpose    : Loads the specified pixmap file (.xbm or .xpm) for the
269                    purpose of future use with the specified widget.
270 
271                  For pixmaps, transparency is resolved with the specified
272                    background color.
273                  For bitmaps, fg_color and bg_color are used directly to
274                   determine the colors of the on and off pixels in the
275                   pixmap.
276 
277                  On success, the resulting pixmap (and pixmap mask, if is
278                    pixmap file AND mask is present AND pixmap_mask != NULL)
279                    is/are returned.
280 
281                  Free these pixmaps using XFreePixmap.
282 
283                  NOTE:  The default X colormap is used for color matching.
284 
285     Programmer : 02-Mar-1997  Randall Hopper
286 
287     Parameters : pixmap_file - I: filename base for pixmap file
288                  wgt         - I: widget pixmap will be associated with
289                  fg_color    - I: foreground color
290                  bg_color    - I: background color
291                  pixmap      - O: returned pixmap      (input can't be NULL)
292                  pixmap_mask - O: returned pixmap mask (input can   be NULL)
293 
294     Returns    : T = Success; F = Failure
295 
296     Globals    : None.
297 
298  **@ENDFUNC*****************************************************************/
299 
XUTILPixmapLoad(char * pixmap_file,Widget wgt,Pixel fg_color,Pixel bg_color,Pixmap * pixmap,Pixmap * pixmap_mask)300 TV_BOOL XUTILPixmapLoad( char    *pixmap_file,
301                       Widget   wgt,
302                       Pixel    fg_color,
303                       Pixel    bg_color,
304                       Pixmap  *pixmap,
305                       Pixmap  *pixmap_mask )
306 {
307     XpmAttributes   xpmatts;
308     XpmColorSymbol  XpmTransparentColor[1] = { { NULL, "none", 0 } };
309     int             xpm_status,
310                     color_depth,
311                     x_hot,
312                     y_hot;
313     Pixmap          pix_returned,
314                     pix_mask_returned,
315                     pixmap_depth1;
316     Colormap        colormap;
317     char           *pixmap_path = NULL;
318     unsigned int    width,
319                     height;
320     XGCValues       gcv;
321     GC              gc;
322 
323     if ( pixmap == NULL )
324         return False;
325 
326     /********************************************/
327     /*  Look for the pixmap file in FXTV_LIBDIR */
328     /********************************************/
329     pixmap_path = XtResolvePathname( XtDisplay(wgt), "bitmaps", pixmap_file,
330                                      NULL, FXTV_LIBDIR, NULL, 0, NULL);
331 
332     if ( pixmap_path == NULL ) {
333         fprintf( stderr, "Failed to find bitmap/pixmap '%s'\n", pixmap_file );
334         return False;
335     }
336 
337     XtVaGetValues( wgt, XtNdepth, &color_depth, NULL );
338 
339     /********************************************************************/
340     /*  .xbm's aren't handled by Xpm.  Do something different for them  */
341     /********************************************************************/
342     if (( strlen( pixmap_path ) > 4 ) &&
343         ( strcmp( pixmap_path + strlen( pixmap_path ) - 4, ".xbm" ) == 0 )) {
344 
345         /*****************/
346         /*  Load bitmap  */
347         /*****************/
348         if (( XReadBitmapFile( XtDisplay(wgt),
349                                RootWindowOfScreen( XtScreen( wgt ) ),
350                                pixmap_path, &width, &height, &pixmap_depth1,
351                                &x_hot, &y_hot ) != BitmapSuccess ) ||
352             ( (*pixmap = XCreatePixmap( XtDisplay(wgt),
353                                      RootWindowOfScreen( XtScreen( wgt ) ),
354                                      width, height, color_depth )) == None )){
355             fprintf( stderr, "Failed to load bitmap %s\n", pixmap_path );
356             if ( pixmap_path != NULL )
357                 XtFree( pixmap_path );
358             return False;
359         }
360 
361         gcv.foreground         = fg_color;
362         gcv.background         = bg_color;
363         gcv.graphics_exposures = False;
364 
365         gc = XCreateGC( XtDisplay(wgt), RootWindowOfScreen( XtScreen( wgt ) ),
366                         GCForeground | GCBackground  | GCGraphicsExposures,
367                         &gcv );
368 
369         XCopyPlane( XtDisplay(wgt), pixmap_depth1, *pixmap, gc,
370                     0, 0, width, height, 0, 0, 0x00000001 );
371         XFreePixmap( XtDisplay( wgt ), pixmap_depth1 );
372         XFreeGC    ( XtDisplay( wgt ), gc );
373         if ( pixmap_mask != NULL )
374             *pixmap_mask = NULL;
375     }
376     else {
377 
378         /*****************/
379         /*  Load pixmap  */
380         /*****************/
381         colormap = XDefaultColormap( XtDisplay( wgt ),
382                                      DefaultScreen( XtDisplay( wgt ) ) );
383 
384         XpmTransparentColor[0].pixel = bg_color;
385         xpmatts.colormap = colormap;
386         xpmatts.valuemask = XpmColorSymbols | XpmCloseness | XpmDepth |
387                             XpmColormap;
388         xpmatts.colorsymbols = XpmTransparentColor;
389         xpmatts.numsymbols = 1;
390         xpmatts.closeness = 65536;
391         xpmatts.depth = color_depth;
392 
393         xpm_status = XpmReadFileToPixmap(
394                         XtDisplay( wgt ),
395                         DefaultRootWindow( XtDisplay( wgt ) ),
396                         pixmap_path,
397                         &pix_returned,
398                         &pix_mask_returned,
399                         &xpmatts);
400 
401         if ( xpm_status < 0 ) {
402             fprintf( stderr, "Failed to load pixmap %s\n", pixmap_path );
403             if ( pixmap_path != NULL )
404                 XtFree( pixmap_path );
405             return False;
406         }
407 
408         *pixmap = pix_returned;
409         if ( pix_mask_returned )
410             if ( pixmap_mask != NULL )
411                 *pixmap_mask = pix_mask_returned;
412             else
413                 XFreePixmap( XtDisplay( wgt ), pix_mask_returned );
414     }
415 
416     if ( pixmap_path != NULL )
417         XtFree( pixmap_path );
418     return True;
419 }
420 
421 /**@BEGINFUNC**************************************************************
422 
423     Prototype  : void XUTILXawScrollbarSetThumb(
424                       Widget w,
425                       float top,
426                       float shown )
427 
428     Purpose    : Wrapper function for XawScrollbarSetThumb -- in a
429                  separate module from that in which its called so we can
430                  avoid a Scrollbar.h declaration error which declares
431                  XawScrollbarSetThumb taking doubles instead of floats
432                  (the library function expects floats).
433 
434     Programmer : 29-Mar-97  Randall Hopper
435 
436     Parameters : w      - I: scrollbar widget
437                  top    - I: top value
438                  shown  - I: shown value
439 
440     Returns    : None.
441 
442     Globals    : None.
443 
444  **@ENDFUNC*****************************************************************/
445 
XUTILXawScrollbarSetThumb(Widget w,float top,float shown)446 void XUTILXawScrollbarSetThumb( Widget w, float top, float shown )
447 {
448     /*  This rtn is here to avoid a prototyping bug in Scrollbar.h  */
449     /*  where the args to the following function are incorrectly    */
450     /*  declared as doubles, not floats.                            */
451     XawScrollbarSetThumb( w, top, shown );
452 }
453 
454 
455 /**@BEGINFUNC**************************************************************
456 
457     Prototype  : void XUTILGetVisualBpp(
458                       Display     *display,
459                       XVisualInfo *vi,
460                       TV_INT32    *Bpp_pixmap,
461                       TV_INT32    *Bpp_fbuffer )
462 
463     Purpose    : Returns the number of bytes per pixel for the specified
464                  visual.
465 
466                  NOTE:  This is not always (depth+7)/8, which is the reason
467                  for the existance of this convenience function.  And even
468                  then this function will sometimes get it wrong because
469                  Pixmap pixel geometry doesn't necessarily equate to Frame
470                  buffer pixel geometry.
471 
472                  BACKGROUND: Some X servers define 4 Bpp 24bpp modes as
473                  depth 32 bpp (-bpp 32), while others define them as depth
474                  24 bpp (-bpp 24).  Others use implement both 24bpp and 32bpp
475                  in a 3Bpp mode (e.g. 3.3.1 S3V server).  So we can't use
476                  visual depth alone as a determining value.
477 
478                  Alternatively we probe the pixmap formats that are
479                  supported by the display to help determine the true Bpp.
480                  For both cases, the pixmap bits_per_pixel for the
481                  corresponding depth (24 or 32) is 32, usually reflecting
482                  the true depth of the frame buffer, but not always.
483 
484                  Because without probing hardware we can't really tell
485                  for sure what the frame buffer Bpp is, we allow the
486                  user to tell us (for 24bpp and 32bpp anyway) using the
487                  Bpp24bit and Bpp32bit settings
488 
489     Programmer : 29-Mar-97  Randall Hopper
490 
491     Parameters : display     - I: display that visual is on
492                  vi          - I: info struct for a visual
493                  Bpp_pixmap  - O: pixmap Bpp
494                  Bpp_fbuffer - O: frame buffer Bpp
495 
496     Returns    : Bytes per pixel for the visual
497 
498     Globals    : None.
499 
500  **@ENDFUNC*****************************************************************/
501 
XUTILGetVisualBpp(Display * display,XVisualInfo * vi,TV_INT32 * Bpp_pixmap,TV_INT32 * Bpp_fbuffer)502 void XUTILGetVisualBpp(
503           Display     *display,
504           XVisualInfo *vi,
505           TV_INT32    *Bpp_pixmap,
506           TV_INT32    *Bpp_fbuffer )
507 {
508     static struct {
509         VisualID  visualid;
510         TV_INT32  Bpp_pixmap;
511         TV_INT32  Bpp_fbuffer;
512     } *Vlist = NULL;
513     static int Vlist_len = 0;
514 
515     TV_INT32   i,
516                Bpp = 0;
517 
518     /*  Look up cached value  */
519     for ( i = 0; i < Vlist_len; i++ )
520         if ( Vlist[i].visualid == vi->visualid )
521             break;
522 
523     /*  Didn't have a cached value?  Go figure it out.  */
524     if ( i >= Vlist_len ) {
525         XPixmapFormatValues *pf;
526         int                  num_pf,
527                              pfi;
528 
529         /*  Try to grab Bpp from pixmap formats first  */
530         pf = XListPixmapFormats( display, &num_pf );
531         if ( pf != NULL ) {
532             for ( pfi = 0; pfi < num_pf; pfi++ )
533                 if ( pf[ pfi ].depth == vi->depth )
534                     break;
535             if ( pfi < num_pf )
536                 Bpp = ( pf[ pfi ].bits_per_pixel + 7 ) / 8;
537             XFree ( pf );
538         }
539 
540         /*  Or fallback to using depth  */
541         if ( Bpp == 0 )
542             Bpp = ( vi->depth + 7 ) / 8;
543 
544         /*  And finally, add to Bpp cache  */
545         Vlist_len++;
546         Vlist = realloc( Vlist, sizeof( Vlist[0] ) * Vlist_len );
547         if ( Vlist == NULL )
548             TVUTILOutOfMemory();
549         i = Vlist_len-1;
550         Vlist[i].visualid = vi->visualid;
551         Vlist[i].Bpp_pixmap  = Bpp;
552         Vlist[i].Bpp_fbuffer = Bpp;
553     }
554 
555     /*  Even then, this value may not be right for the frame buffer  */
556     /*    geometry.  Allow the user to override settings for 24bpp   */
557     /*    and 32bpp.                                                 */
558     if (( vi->depth == 24 ) && INRANGE( App_res.Bpp_24bit, 3, 4, 0 ))
559         Vlist[i].Bpp_fbuffer = App_res.Bpp_24bit;
560     else if (( vi->depth == 32 ) && INRANGE( App_res.Bpp_32bit, 3, 4, 0 ))
561         Vlist[i].Bpp_fbuffer = App_res.Bpp_32bit;
562 
563     if ( Bpp_pixmap )
564         *Bpp_pixmap = Vlist[i].Bpp_pixmap;
565     if ( Bpp_fbuffer )
566         *Bpp_fbuffer = Vlist[i].Bpp_fbuffer;
567 }
568 
569 
570 /**@BEGINFUNC**************************************************************
571 
572     Prototype  : void XUTILGetVisualSwaps(
573                       Display *display,
574                       XVisualInfo *vi,
575                       TV_BOOL *swap_bytes,
576                       TV_BOOL *swap_shorts )
577 
578     Purpose    : Based on the visual, determines whether bytes and/or
579                  shorts need to be swapped in the process of pixel blasting
580                  to display correctly.
581 
582                  Examples:
583                                               <--- lower addr  higher addr --->
584                       2Bpp 15bpp no-swap   =  xRRRRRGG GGGBBBBB
585                       2Bpp 15bpp byte-swap =  GGGBBBBB xRRRRRGG
586 
587                       3Bpp 24bpp no-swap   =  RGB RGB
588                       3Bpp 24bpp byte-swap =  BGR BGR
589 
590                       4Bpp 24bpp no-swap   =  ARGB ARGB
591                       4Bpp 24bpp both-swap =  BGRA BGRA
592 
593     Programmer : 22-Apr-97  Randall Hopper
594 
595     Parameters : display     - I: display for visual
596                  vi          - I: visual info
597                  swap_bytes  - O: whether byte  swap is needed
598                  swap_shorts - O: whether short swap is needed
599 
600     Returns    : None.
601 
602     Globals    : None.
603 
604  **@ENDFUNC*****************************************************************/
605 
XUTILGetVisualSwaps(Display * display,XVisualInfo * vi,TV_BOOL * swap_bytes,TV_BOOL * swap_shorts)606 void XUTILGetVisualSwaps( Display *display, XVisualInfo *vi,
607                           TV_BOOL *swap_bytes, TV_BOOL *swap_shorts )
608 {
609     TV_INT32 Bpp;
610 
611     /*  FIXME:  probably should make the settings based on bpp rather than  */
612     /*    Bpp since Bpp is ambiguous.  24bpp could be 3 or 4 Bpp.  Ditto    */
613     /*    for 32bpp.                                                        */
614     XUTILGetVisualBpp( display, vi, NULL, &Bpp );
615 
616     *swap_bytes = *swap_shorts = FALSE;
617 
618     /*  FIXME:  For now, just let the user override the default swaps.  */
619     /*    We have defaults, of course.                                  */
620     /*    Can't get this from the X server for 2Bpp modes -- assume     */
621     /*    swapped (makes sense -- more efficient).                      */
622     /*    But consider whether we can determine for 3/4Bpp modes; do    */
623     /*    all X servers report the visual masks assuming a 4Bpp blast?  */
624     /*    (i.e. dword already reversed?) -- hard to guess.              */
625     switch ( Bpp ) {
626         case 2 : *swap_bytes = App_res.bswap2Bpp;
627                  break;
628         case 3 : *swap_bytes = App_res.bswap3Bpp;
629                  break;
630         case 4 : *swap_bytes  = App_res.bswap4Bpp;
631                  *swap_shorts = App_res.wswap4Bpp;
632                  break;
633     }
634 }
635 
636 
637 /**@BEGINFUNC**************************************************************
638 
639     Prototype  : void XUTILDialogSmartPosition(
640                       Widget      main_wgt,
641                       Widget      dialog_wgt )
642 
643     Purpose    : Smart position a dialog so it lies on the screen.
644 
645     Programmer : 21-May-98  Randall Hopper
646 
647     Parameters : main_wgt    - I: window to place dialog beside
648                  dialog_wgt  - I: dialog to position
649     Returns    : None.
650 
651     Globals    : None.
652 
653  **@ENDFUNC*****************************************************************/
654 
XUTILDialogSmartPosition(Widget main_wgt,Widget dialog_wgt)655 void XUTILDialogSmartPosition(
656          Widget      main_wgt,
657          Widget      dialog_wgt )
658 {
659     Dimension m_width,
660               m_height,
661               d_width,
662               d_height;
663     Position  d_x,
664               d_y,
665               m_ul[2],
666               m_lr[2];
667     Screen   *screen  = XtScreen ( main_wgt );
668 
669     XtVaGetValues( dialog_wgt, XtNwidth , &d_width,
670                                XtNheight, &d_height,
671                                NULL );
672 
673     XtVaGetValues( main_wgt, XtNwidth , &m_width,
674                              XtNheight, &m_height,
675                              NULL);
676 
677     XtTranslateCoords( main_wgt, 0, 0, &m_ul[0], &m_ul[1] );
678     m_lr[0] = m_ul[0] + m_width ;
679     m_lr[1] = m_ul[1] + m_height;
680 
681     /*  Try below, right, above, left, then just slap it on top of main_wgt  */
682     if ( m_lr[1]+d_height+WM_BORDER_PAD <= HeightOfScreen(screen) )
683         d_x = m_ul[0],
684         d_y = m_lr[1]+WM_BORDER_PAD;
685     else if ( m_lr[0]+d_width+WM_BORDER_PAD <= WidthOfScreen(screen) )
686         d_x = m_lr[0]+WM_BORDER_PAD,
687         d_y = m_ul[1];
688     else if ( m_ul[1]-d_height-WM_BORDER_PAD >= 0 )
689         d_x = m_ul[0],
690         d_y = m_ul[1]-d_height-WM_BORDER_PAD;
691     else if ( m_ul[0]-d_width-WM_BORDER_PAD >= 0 )
692         d_x = m_ul[0]-d_width-WM_BORDER_PAD,
693         d_y = m_ul[1];
694     else
695         d_x = m_ul[0],
696         d_y = m_ul[1];
697 
698     d_x = MAX(0, d_x );
699     d_y = MAX(0, d_y );
700     d_x = MIN( WidthOfScreen (screen), d_x+d_width  ) - d_width;
701     d_y = MIN( HeightOfScreen(screen), d_y+d_height ) - d_height;
702 
703     XtVaSetValues( dialog_wgt, XtNx, d_x,
704                                XtNy, d_y,
705                                NULL );
706 }
707 
708 
709 /**@BEGINFUNC**************************************************************
710 
711     Prototype  : Widget XUTILDialogBuild(
712                       Widget toplevel,
713                       char title[],
714                       char msg[],
715                       TV_DIALOG_TYPE type )
716 
717     Prototype  : TV_INT32 XUTILDialogPause(
718                       Widget         toplevel,
719                       char           title[],
720                       char           msg[],
721                       TV_DIALOG_TYPE type )
722 
723     Purpose    : Utilities to build a dialog, and to put up a dialog with a
724                  user-specified message and sit-n-spin in our own local
725                  xevent loop until the user wakes up and answers the question.
726 
727     Programmer : 23-May-97  Randall Hopper
728 
729     Parameters : toplevel - I: top level shel widget for app
730                  title    - I: dialog title
731                  msg      - I: the message to display
732                  type     - I: type of dialog to display
733 
734     Returns    : For YES_NO dialogs, { TV_DIALOG_YES TV_DIALOG_NO }
735 
736     Globals    : None.
737 
738  **@ENDFUNC*****************************************************************/
739 
740 static TV_INT32 Dialog_answer;
741 
742 
DialogCB(Widget w,XtPointer client_data,XtPointer cb_data)743 static void DialogCB( Widget w, XtPointer client_data, XtPointer cb_data )
744 {
745     char *name = XtName( w );
746 
747     if ( strcmp( name, "yes" ) == 0 )
748         Dialog_answer = TV_DIALOG_YES;
749     else if ( strcmp( name, "no" ) == 0 )
750         Dialog_answer = TV_DIALOG_NO;
751     else
752         Dialog_answer = True;
753 
754     XtPopdown ( (Widget) client_data );
755     XtUnrealizeWidget( (Widget) client_data );
756 }
757 
758 
XUTILDialogBuild(Widget toplevel,char title[],char msg[],TV_DIALOG_TYPE type)759 Widget XUTILDialogBuild( Widget toplevel,
760                          char title[], char msg[], TV_DIALOG_TYPE type )
761 {
762     Widget      shell,
763                 dialog;
764 
765     /*  Construct dialog  */
766     shell = XtCreatePopupShell( "simplePromptShell",
767                                 transientShellWidgetClass,
768                                 toplevel, NULL, 0 );
769     XtVaSetValues( shell, XtNtitle           , title,
770                           XtNallowShellResize, False,
771                           NULL );
772 
773     dialog = XtVaCreateManagedWidget ( "simplePromptDialog",
774                                        dialogWidgetClass, shell,
775                                        XtNlabel, msg,
776                                        NULL );
777 
778     switch ( type ) {
779         case TV_DIALOG_TYPE_OK     :
780             XawDialogAddButton( dialog, "ok"    , DialogCB, shell );
781             break;
782         case TV_DIALOG_TYPE_CANCEL :
783             XawDialogAddButton( dialog, "cancel", DialogCB, shell );
784             break;
785         case TV_DIALOG_TYPE_YES_NO :
786             XawDialogAddButton( dialog, "yes"   , DialogCB, shell );
787             XawDialogAddButton( dialog, "no"    , DialogCB, shell );
788             break;
789         case TV_DIALOG_TYPE_NOBUTTONS :
790             break;
791         default:
792             fprintf( stderr, "Unsupported dialog type\n" );
793             exit(1);
794     }
795 
796     return shell;
797 }
798 
799 
XUTILDialogPause(Widget toplevel,char title[],char msg[],TV_DIALOG_TYPE type)800 TV_INT32 XUTILDialogPause( Widget toplevel,
801                            char title[], char msg[], TV_DIALOG_TYPE type )
802 {
803     Widget      shell;
804 
805     /*  Sanity check  */
806     if ( type == TV_DIALOG_TYPE_NOBUTTONS ) {
807         fprintf( stderr, "XUTILDialogPause: Bad dialog type\n" );
808         exit(1);
809     }
810 
811     /*  Build dialog  */
812     shell = XUTILDialogBuild( toplevel, title, msg, type );
813 
814     /*  Pop it up  */
815     XUTILXtPopup( shell, XtGrabNonexclusive, toplevel );
816 
817     /*  Wait until user answers the dialog  */
818     while ( XtIsRealized(shell) ) {
819         XEvent   ev;
820 
821         XtAppNextEvent( XtWidgetToApplicationContext(toplevel), &ev );
822         XtDispatchEvent( &ev );
823     }
824 
825     /*  Close and destroy the dialog  */
826     XtUnrealizeWidget( shell );
827     XtDestroyWidget( shell );
828     return Dialog_answer;
829 }
830 
831 
832 /**@BEGINFUNC**************************************************************
833 
834     Prototype  : static void XUTILGetPixelGeomInfo(
835                       TV_UINT32       rel_mask[3],
836                       int          bits    [3],
837                       int          shift   [3],
838                       int          mask    [3] )
839 
840     Purpose    : Get Pixel RGB component shifts, masks, and bit counts
841                  for the specified visual.
842 
843                  (mask[0] << shift[0]) | (mask[1] << shift[1]) |
844                  (mask[2] << shift[2])
845 
846                  FIXME: Duplicated in videolib
847 
848     Programmer : 07-Mar-97  Randall Hopper
849 
850     Parameters : rel_mask- I: R/G/B shifted mask for each compoent
851                  bits    - O: R/G/B bpp
852                  shift   - O: R/G/B left shift cnt to align component in pixel
853                  mask    - O: R/G/B mask to keep only desired bits
854 
855        E.g.:  INPUT : rel_mask = FF0000,00FF00,0000FF
856               OUTPUT: bits     = 8,8,8
857                       shift    = 16,8,0
858                       mask     = FF,FF,FF
859 
860     Returns    : None.
861 
862     Globals    : None.
863 
864  **@ENDFUNC*****************************************************************/
865 
XUTILGetPixelGeomInfo(TV_UINT32 rel_mask[3],int bits[3],int shift[3],int mask[3])866 static void XUTILGetPixelGeomInfo(
867                 TV_UINT32       rel_mask[3],
868                 int          bits    [3],
869                 int          shift   [3],
870                 int          mask    [3] )
871 {
872     int    i;
873     TV_UINT32 rel[3];
874 
875     memcpy( rel, rel_mask, sizeof( rel ) );
876 
877     for ( i = 0; i < 3; i++ ) {
878         if ( !rel[i] ) {
879             fprintf( stderr, "XUTILGetPixelGeomInfo: Bad X visual mask\n");
880             exit(1);
881         }
882         bits[i] = shift[i] = mask[i] = 0;
883 
884         while ( !(rel[i] & 0x01) )
885             rel[i] >>= 1, shift[i]++;
886 
887         mask[i] = rel[i];
888 
889         while (  (rel[i] & 0x01) )
890             rel[i] >>= 1, bits[i]++;
891     }
892 }
893 
894 /**@BEGINFUNC**************************************************************
895 
896     Prototype  : void XUTILGetPixelConvInfo(
897                       TV_UINT32 src_rel_mask[3],
898                       TV_UINT32 dst_rel_mask[3],
899                       TV_INT32  shift       [3],
900                       TV_UINT32 mask        [3] )
901 
902     Purpose    : Given a source pixel mask and a destination pixel mask,
903                  determines the shifts and masks necessary to map the
904                  source pixel geometry to the destination.
905 
906                  FIXME: Duplicated in videolib
907 
908     Programmer : 29-Mar-97  Randall Hopper
909 
910     Parameters : src_rel_mask - I: source relative pixel masks
911                  dst_rel_mask - I: dest   relative pixel masks
912                  shift        - O: initial pixel shifts
913                  mask         - O: final   pixel masks
914 
915        E.g.:  INPUT : src_rel_mask = 00FC00, 0003e0, 00001f
916                       dst_rel_mask = FF0000, 00FF00, 0000FF
917 
918               OUTPUT: shift        =      8,      6,      3
919                       mask         = FC0000, 00F800, 0000F8
920 
921     Returns    : None.
922 
923     Globals    : None.
924 
925  **@ENDFUNC*****************************************************************/
926 
XUTILGetPixelConvInfo(TV_UINT32 src_rel_mask[3],TV_UINT32 dst_rel_mask[3],TV_INT32 shift[3],TV_UINT32 mask[3])927 void XUTILGetPixelConvInfo(
928          TV_UINT32 src_rel_mask[3],
929          TV_UINT32 dst_rel_mask[3],
930          TV_INT32  shift       [3],
931          TV_UINT32 mask        [3] )
932 {
933     int   src_bits[3], src_shf[3], src_msk[3], src_soff[3],
934           dst_bits[3], dst_shf[3], dst_msk[3], dst_soff[3];
935     TV_INT32 i;
936 
937     /*  Get R/G/B shifts, masks, and bit counts  */
938     XUTILGetPixelGeomInfo( src_rel_mask, src_bits, src_shf, src_msk );
939     XUTILGetPixelGeomInfo( dst_rel_mask, dst_bits, dst_shf, dst_msk );
940 
941     /*  Calculate R/G/B left-most bit offsets  */
942     for ( i = 0; i < 3; i++ )
943         src_soff[i] = src_shf[i] + src_bits[i] - 1,
944         dst_soff[i] = dst_shf[i] + dst_bits[i] - 1;
945 
946     /*  Finally, calculate net shifts and masks  */
947     for ( i = 0; i < 3; i++ ) {
948         shift[i] = dst_soff[i] - src_soff[i];
949         if ( shift[i] >= 0 )
950             mask [i] = ( src_rel_mask[i] << shift[i] ) & dst_rel_mask[i];
951         else
952             mask [i] = ( src_rel_mask[i] >> -shift[i] ) & dst_rel_mask[i];
953     }
954 }
955 
956 
957 /**@BEGINFUNC**************************************************************
958 
959     Prototype  : static void XUTILRunCmdTimeoutCB(
960                       XtPointer          cl_data,
961                       XtIntervalId      *timer )
962 
963     Purpose    : Timer callback for XUTILRunCmdAllowCancel.
964 
965                  Called periodically to check on the status of the
966                  background command.
967 
968     Programmer : 19-Jul-97  Randall Hopper
969 
970     Parameters : cl_data - I: state data struct (malloced mem)
971                  timer   - I: <not used>
972 
973     Returns    : None.
974 
975     Globals    : None.
976 
977  **@ENDFUNC*****************************************************************/
978 
XUTILRunCmdTimeoutCB(XtPointer cl_data,XtIntervalId * timer)979 static void XUTILRunCmdTimeoutCB(
980                 XtPointer          cl_data,
981                 XtIntervalId      *timer )
982 {
983     XUTIL_RUNCMD_STATE *state = (XUTIL_RUNCMD_STATE *) cl_data;
984     int                 ret,
985                         status = 0;
986     TV_BOOL             aborted,
987                         complete;
988 
989     /*  Ok, is our process still out there crunching?  */
990     ret = kill( state->cmd_pid, 0 );
991 
992     if (( ret < 0 ) && ( errno != ESRCH )) {
993         TVUTILPipeCleanup( state->cmd_pid, state->end, &status );
994         perror( "kill(,0) failed on conv process" );
995         exit(1);
996     }
997 
998     aborted  = state->cancel_cb &&
999                state->cancel_cb( state->cancel_cb_data );
1000     complete = ( ret < 0 ) && ( errno == ESRCH );
1001 
1002     /*  If process is done or user aborted, clean up and get exit status,  */
1003     /*    and notify client.                                               */
1004     if ( aborted || complete ) {
1005         if ( aborted )
1006             kill( state->cmd_pid, SIGINT );
1007         TVUTILPipeCleanup( state->cmd_pid, state->end, &status );
1008 
1009         state->done_cb( aborted, status, state->done_cb_data );
1010 
1011         free(state);
1012     }
1013 
1014     /*  Otherwise, just go back to sleep and check again later  */
1015     else
1016         XtAppAddTimeOut( state->app_context, RUNCMD_CHECK_TIMEOUT_MS,
1017                          XUTILRunCmdTimeoutCB, state );
1018 }
1019 
1020 /**@BEGINFUNC**************************************************************
1021 
1022     Prototype  : void XUTILRunCmdAllowCancel(
1023                       XtAppContext           app_context,
1024                       char                  *cmd[],
1025                       TVUTIL_PIPE_END        end[3],
1026                       XUTIL_RUNCMD_CANCELCB *cancel_test,
1027                       void                  *cancel_cb_data,
1028                       XUTIL_RUNCMD_DONECB   *done_cb,
1029                       void                  *done_cb_data )
1030 
1031     Purpose    : Run a command (cmd,end) in the background giving the client
1032                  the opportunity to cancel the command using its own criteria
1033                  (e.g. dialog dismissed, cancel button pressed, etc.).
1034 
1035                  While the command is executing, its existance is checked and
1036                  the cancel_test callback is called (with cancel_cb_data)
1037                  periodically.
1038 
1039                  When the command completes or is cancelled, the user-defined
1040                  callback done_cb is called with done_cb_data.  The callback
1041                  is also passed whether the command was aborted as well as
1042                  the exit status of the command.
1043 
1044                  If the command is called (cancel_test returns TRUE),
1045                  the command is killed (SIGINT is issued).
1046 
1047     Programmer : 30-May-97  Randall Hopper
1048 
1049     Parameters : app-context    - I: Xt application context
1050                  cmd            - I: cmd to execute ( [argv[0],argv[1],...] )
1051                  end            - I: bindings for stdin/stdout of cmd
1052                  cancel_test    - I: callback to allow client to abort command
1053                  cancel_cb_data - I: client data to pass cancel callback
1054                  done_cb        - I: callback to call on cmd complete/abort
1055                  done_cb_data   - I: client data to pass done callback
1056 
1057     Returns    : None.
1058 
1059     Globals    : None.
1060 
1061  **@ENDFUNC*****************************************************************/
1062 
XUTILRunCmdAllowCancel(XtAppContext app_context,char * cmd[],TVUTIL_PIPE_END end[3],XUTIL_RUNCMD_CANCELCB * cancel_test,void * cancel_cb_data,XUTIL_RUNCMD_DONECB * done_cb,void * done_cb_data)1063 void XUTILRunCmdAllowCancel(
1064                 XtAppContext           app_context,
1065                 char                  *cmd[],
1066                 TVUTIL_PIPE_END        end[3],
1067                 XUTIL_RUNCMD_CANCELCB *cancel_test,
1068                 void                  *cancel_cb_data,
1069                 XUTIL_RUNCMD_DONECB   *done_cb,
1070                 void                  *done_cb_data )
1071 {
1072     XUTIL_RUNCMD_STATE *state;
1073 
1074     /*  We'll wake-up every once in a while and check on it.  */
1075     /*    First, build state data struct.                     */
1076     if ( (state = malloc( sizeof( *state ) )) == NULL )
1077         TVUTILOutOfMemory();
1078     memset( state, '\0', sizeof( *state ) );
1079 
1080     state->cmd_pid = -1;
1081     memcpy( state->end, end, sizeof( state->end ) );
1082     state->app_context  = app_context;
1083     state->cancel_cb      = cancel_test;
1084     state->cancel_cb_data = cancel_cb_data;
1085     state->done_cb        = done_cb;
1086     state->done_cb_data   = done_cb_data;
1087 
1088     /*  Ok, now fire-up the child process  */
1089     TVUTILPipeSetup( NULL, cmd, end, &state->cmd_pid );
1090 
1091     /*  Now go to sleep and wait on 1) user to cancel, or 2) cmd to complete */
1092     XtAppAddTimeOut( state->app_context, RUNCMD_CHECK_TIMEOUT_MS,
1093                      XUTILRunCmdTimeoutCB, state );
1094 }
1095 
1096 
1097 /*  XUTILIsWellFormedXLFDFont                                           */
1098 /*    This routine returns True if the passed name is a well-formed     */
1099 /*    XLFD style font name.  Adapted from XUtilIsScalableFont (below).  */
XUTILIsWellFormedXLFDFont(char * name)1100 Bool XUTILIsWellFormedXLFDFont( char *name )
1101 {
1102     int i, field, field_len;
1103     char *p;
1104 
1105     if ( !name || ( name[0] != '-' ))
1106         return False;
1107 
1108     for ( i = field = 0; name[i] != '\0'; i++ )
1109         if ( name[i] == '-' ) {
1110             field++;
1111 
1112             if ( (p = strchr( &name[i+1], '-' )) != NULL )
1113                 field_len = p - &name[i+1];
1114             else
1115                 field_len = strlen( &name[i+1] ) - i+1;
1116             if (( field != 6 ) && ( field_len == 0 ))
1117                 return False;
1118             switch ( field ) {
1119                 case 1  : if ( field_len >= XLFD_SIZE_FOUNDRY )
1120                              return False;
1121                           break;
1122                 case 2  : if ( field_len >= XLFD_SIZE_FAMILY )
1123                              return False;
1124                           break;
1125                 default : if ( field_len >= XLFD_SIZE_SMALL )
1126                             return False;
1127                           break;
1128             }
1129         }
1130 
1131     return ( field == 14 );
1132 }
1133 
1134 
1135 /*  XUTILIsScalableFont  - From O'Reilly X11R5 Vol 1 A.3.3 (pg 569).  */
1136 /*    This routine returns True if the passed name is a well-formed   */
1137 /*    XLFD style font name with a pixel size, point size, and average */
1138 /*    width (fields 7, 8, and 12) of "0".                             */
1139 /*  Modified: component length sanity checking added.                 */
XUTILIsScalableFont(char * name)1140 Bool XUTILIsScalableFont( char *name )
1141 {
1142     int i, field, field_len;
1143     char *p;
1144 
1145     if ( !name || ( name[0] != '-' ))
1146         return False;
1147 
1148     for ( i = field = 0; name[i] != '\0'; i++ )
1149         if ( name[i] == '-' ) {
1150             field++;
1151             if (( field == 7 ) || ( field == 8 ) || ( field == 12 ))
1152                 if (( name[i+1] != '0' ) || ( name[i+2] != '-' ))
1153                     return False;
1154 
1155             if ( (p = strchr( &name[i+1], '-' )) != NULL )
1156                 field_len = p - &name[i+1];
1157             else
1158                 field_len = strlen( &name[i+1] ) - i+1;
1159             switch ( field ) {
1160                 case 1  : if ( field_len >= XLFD_SIZE_FOUNDRY )
1161                              return False;
1162                           break;
1163                 case 2  : if ( field_len >= XLFD_SIZE_FAMILY )
1164                              return False;
1165                           break;
1166                 default : if ( field_len >= XLFD_SIZE_SMALL )
1167                             return False;
1168                           break;
1169             }
1170 
1171         }
1172 
1173     return ( field == 14 );
1174 }
1175 
1176 /* XUTILSplitXLFD - Split an XLFD font name up into components  */
XUTILSplitXLFD(char name[],TV_XLFD * xlfd)1177 static void XUTILSplitXLFD( char     name[],
1178                             TV_XLFD *xlfd )
1179 {
1180     int ret;
1181 
1182     if ( !XUTILIsWellFormedXLFDFont( name ) ) {
1183         fprintf( stderr, "XUTILSplitXLFD: Passed non-XLFD font\n" );
1184         exit(1);
1185     }
1186 
1187     xlfd->ad_style[0] = '\0';
1188 
1189     ret = sscanf( name,
1190            "-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]"
1191            "-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]",
1192            xlfd->foundry, xlfd->family, xlfd->weight, xlfd->slant,
1193            xlfd->set_width, xlfd->ad_style, xlfd->pixel_size, xlfd->point_size,
1194            xlfd->x_dpi, xlfd->y_dpi, xlfd->spacing, xlfd->avg_width,
1195            xlfd->charset_reg, xlfd->charset_enc );
1196 
1197     if ( ret != 14 ) {
1198         xlfd->ad_style[0] = '\0';
1199 
1200         ret = sscanf( name,
1201            "-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]--%[^-]-%[^-]"
1202            "-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]",
1203            xlfd->foundry, xlfd->family, xlfd->weight, xlfd->slant,
1204            xlfd->set_width, xlfd->pixel_size, xlfd->point_size,
1205            xlfd->x_dpi, xlfd->y_dpi, xlfd->spacing, xlfd->avg_width,
1206            xlfd->charset_reg, xlfd->charset_enc );
1207 
1208         if ( ret != 13 ) {
1209             fprintf( stderr, "XUTILSplitXLFD: Unexpected parse failure\n" );
1210             exit(1);
1211         }
1212     }
1213 }
1214 
1215 /* XUTILMergeXLFD - Build an XLFD font name string up from its components  */
1216 /*   It is assumed that name[] is large enough to hold the resulting str.  */
XUTILMergeXLFD(TV_XLFD * xlfd,char name[])1217 static void XUTILMergeXLFD( TV_XLFD *xlfd,
1218                             char     name[] )
1219 {
1220     sprintf( name, "-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s",
1221            xlfd->foundry, xlfd->family, xlfd->weight, xlfd->slant,
1222            xlfd->set_width, xlfd->ad_style, xlfd->pixel_size, xlfd->point_size,
1223            xlfd->x_dpi, xlfd->y_dpi, xlfd->spacing, xlfd->avg_width,
1224            xlfd->charset_reg, xlfd->charset_enc );
1225 }
1226 
1227 
1228 #define TV_XLFD_SPLIT( str_name, xlfd ) \
1229 
1230 
1231 
1232 /*  XUTILLoadQueryScalableFont  - From O'Reilly X11R5 Vol 1 A.3.3 (pg 570). */
1233 /*    This routine is passed a scalable font name and a point size.  It     */
1234 /*    returns an XFontStruct for the given font scaled to the specified     */
1235 /*    size and the exact resolution of the screen.  The font name is        */
1236 /*    assumed to be a well-formed XLFD name, and to have pixel size, point  */
1237 /*    size, and average width fields of "0" and arbitrary x-res and y-res   */
1238 /*    fields.  Size is specified in tenths of points.  Returns NULL if      */
1239 /*    no such font exists.                                                  */
1240 /*  ADAPTED: new_name, new_name_size args added.                            */
XUTILLoadQueryScalableFont(Display * dpy,int screen,char * name,int size,char * new_name,int new_name_size)1241 XFontStruct *XUTILLoadQueryScalableFont(
1242                   Display *dpy,
1243                   int      screen,
1244                   char    *name,
1245                   int      size,
1246                   char    *new_name,
1247                   int      new_name_size )
1248 {
1249     int i,j,field;
1250     char newname[500];
1251     int res_x,res_y;
1252 
1253     if ( !XUTILIsScalableFont( name ) ) {
1254         fprintf( stderr,
1255                  "XUTILLoadQueryScalableFont: Passed non-scalable font\n" );
1256         exit(1);
1257     }
1258 
1259     /*  Calculate our screen res in dots-per-inch.  25.4mm = 1in  */
1260     res_x = DisplayWidth( dpy, screen ) /
1261             ( DisplayWidthMM( dpy, screen ) / 25.4 );
1262     res_y = DisplayHeight( dpy, screen ) /
1263             ( DisplayHeightMM( dpy, screen ) / 25.4 );
1264 
1265     /*  Copy the font name, changing the scalable fields as we do so  */
1266     for ( i = j = field = 0; name[i] != '\0' && field <= 14; i++ ) {
1267         newname[j++] = name[i];
1268         if ( name[i] == '-' ) {
1269             field++;
1270             switch ( field ) {
1271                 case  7:  /*  pixel size */
1272                 case 12:  /* average width  */
1273                     /*  change from "-0-" to "-*-"  */
1274                     newname[j] = '*';
1275                     j++;
1276                     if ( name[i+1] != '\0' )
1277                         i++;
1278                     break;
1279 
1280                 case  8:  /* point size  */
1281                     /*  change from "-0-" to "-<size>-"  */
1282                     sprintf( &newname[j], "%d", size );
1283                     while ( newname[j] != '\0' )
1284                         j++;
1285                     if ( name[i+1] != '\0' )
1286                         i++;
1287                     break;
1288 
1289                 case  9: /* x-resolution  */
1290                 case 10: /* y-resolution  */
1291                     /*  change from an unspecified res to res_x or res_y  */
1292                     sprintf( &newname[j], "%d", (field == 9 ) ? res_x:res_y );
1293                     while ( newname[j] != '\0' )
1294                         j++;
1295                     while( (name[i+1] != '-') && (name[i+1] != '\0'))
1296                         i++;
1297                     break;
1298             }
1299         }
1300     }
1301     newname[j] = '\0';
1302 
1303     if ( new_name ) {
1304         new_name[0] = '\0';
1305         strncat( new_name, newname, new_name_size-1 );
1306     }
1307 
1308     /*  if there aren't 14 hyphens, it isn't a well-formed name  */
1309     assert( field == 14 );
1310 
1311     return XLoadQueryFont( dpy, newname );
1312 }
1313 
1314 /*  XUTILLoadPixelSizeFont                                                  */
1315 /*    This routine is passed a well-formed XLFD font name and a pixel size. */
1316 /*    It returns an XFontStruct for the given font scaled to the specified  */
1317 /*    pixel size (if possible).  Returns NULL if no such font can be built. */
1318 /*    Also, the pixel size is only plugged into the font name if the        */
1319 /*    pixel size component is wildcarded or 0.                              */
1320 /*  ADAPTED: from the adapted XUTILLoadQueryScalableFont                    */
XUTILLoadPixelSizeFont(Display * dpy,char * name,int pixel_size,char * new_name,int new_name_size)1321 XFontStruct *XUTILLoadPixelSizeFont(
1322                   Display *dpy,
1323                   char    *name,
1324                   int      pixel_size,
1325                   char    *new_name,
1326                   int      new_name_size )
1327 {
1328     TV_XLFD xlfd;
1329     char    newname[500];
1330 
1331     XUTILSplitXLFD( name, &xlfd );
1332 
1333     if (( strcmp( xlfd.pixel_size, "0" ) == 0 ) ||
1334         ( strcmp( xlfd.pixel_size, "*" ) == 0 ))
1335         sprintf( xlfd.pixel_size, "%d", abs(pixel_size) );
1336 
1337     XUTILMergeXLFD( &xlfd, newname );
1338 
1339     if ( new_name ) {
1340         new_name[0] = '\0';
1341         strncat( new_name, newname, new_name_size-1 );
1342     }
1343 
1344     return XLoadQueryFont( dpy, newname );
1345 }
1346 
1347 
1348 /*  XUTILXMDeleteChildWindow - Called when we receive a window manager  */
1349 /*    event for a shell window registered with XUTILRegisterWMDelete.   */
1350 /*    We register for WM_DELETE_WINDOW for WM Close events.  When this  */
1351 /*    occurs, ignore the event.                                         */
XUTILWMDeleteChildWindow(Widget w,XEvent * event,String * params,Cardinal num_params)1352 static void XUTILWMDeleteChildWindow(
1353                 Widget    w,
1354                 XEvent   *event,
1355                 String   *params,
1356                 Cardinal  num_params )
1357 {
1358     if ( event->type == ClientMessage &&
1359          ( event->xclient.data.l[0] != S_wm_delete_window ) ) {
1360         XBell ( XtDisplay(w), 0 );
1361         return;
1362     }
1363 
1364     /*  Ignore WM_DELETE  */
1365     XBell ( XtDisplay(w), 0 );
1366 }
1367 
1368 /*  XUTILRegisterWMDelete - Adds translation to shell widgets so that      */
1369 /*    the app doesn't blow up when the user selects the WM Close function  */
1370 /*    on out child windows.                                                */
XUTILRegisterWMDelete(Widget shell_wgt)1371 void XUTILRegisterWMDelete(
1372          Widget   shell_wgt )
1373 {
1374     static TV_BOOL      S_wm_delete_inited = FALSE;
1375     static XtActionsRec S_wm_delete_actions[] = {
1376         { "WMDeleteChildWindow", (XtActionProc) XUTILWMDeleteChildWindow }
1377     };
1378 
1379     if ( !XtIsRealized( shell_wgt ) ) {
1380         fprintf( stderr, "XUTILRegisterWMDelete: Called with an unrealized "
1381                  "widget: %s\n", XtName( shell_wgt ) );
1382         exit(1);
1383     }
1384 
1385     /*  One-time init  */
1386     if ( !S_wm_delete_inited ) {
1387 
1388         /*  WM Delete Window (Close) callback for FXTV child windows  */
1389         XtAppAddActions ( XtWidgetToApplicationContext( shell_wgt ),
1390                           S_wm_delete_actions,
1391                           XtNumber( S_wm_delete_actions ) );
1392         S_wm_delete_inited = TRUE;
1393     }
1394 
1395     /*  Add WM callback translation to shell widget  */
1396     XtOverrideTranslations( shell_wgt,
1397         XtParseTranslationTable(
1398             "<Message>WM_PROTOCOLS: WMDeleteChildWindow()" ) );
1399 
1400     /*  And ask window manager to call us for WM_DELETE_WINDOW events  */
1401     S_wm_delete_window = XInternAtom( XtDisplay( shell_wgt ),
1402                                       "WM_DELETE_WINDOW", False );
1403     XSetWMProtocols( XtDisplay( shell_wgt ), XtWindow( shell_wgt ),
1404                      &S_wm_delete_window, 1);
1405 }
1406 
1407 /*  XUTILXtPopup - XtPopup but additionally register a WM callback  */
1408 /*    to ignore WM_DELETE_WINDOW, and smart-positions the dialog.   */
XUTILXtPopup(Widget popup_shell,XtGrabKind grab_kind,Widget toplevel)1409 void XUTILXtPopup( Widget popup_shell, XtGrabKind grab_kind,
1410                    Widget toplevel )
1411 {
1412     Dimension height;
1413     Position  x,y;
1414 
1415     /*  Tentatively position it  */
1416     XtVaGetValues( toplevel, XtNheight, &height,
1417                              NULL );
1418     XtTranslateCoords( toplevel, 0, 0, &x, &y );
1419     XtVaSetValues( popup_shell, XtNx, x,
1420                                 XtNy, y+height,
1421                                 NULL );
1422 
1423     XtPopup( popup_shell, grab_kind );
1424 
1425     /*  Position it for keeps  */
1426     XUTILDialogSmartPosition( toplevel, popup_shell );
1427 
1428     /*  Ignore WM_DELETE  */
1429     XUTILRegisterWMDelete( popup_shell );
1430 }
1431 
1432 
1433 /*  XUTILXServerIsLocal - Returns TRUE if the X server we're connecting to  */
1434 /*    is on the local machine (X via IPC or IP is assigned to an interface  */
1435 /*    of the local box.                                                     */
XUTILXServerIsLocal(Display * display)1436 TV_BOOL XUTILXServerIsLocal( Display *display )
1437 {
1438     char  host_str[ 80 ],
1439          *p;
1440 
1441     /*  Grab the host part of the display string  */
1442     host_str[0] = '\0';
1443     strncat( host_str, DisplayString(display), sizeof(host_str)-1 );
1444     if ( (p = strchr( host_str, ':' )) == NULL )
1445         return FALSE;
1446     *p = '\0';
1447     TVUTILstrlwr( host_str );
1448 
1449     /*  If local IPC, is local  */
1450     if (( host_str[0] == '\0' ) || ( strcmp( host_str, "unix" ) == 0 ))
1451         return TRUE;
1452 
1453     /*  If hostname or IP belongs to one of our network interfaces, its  */
1454     /*    local.                                                         */
1455     /*  FIXME:  Add this  */
1456 
1457     return FALSE;
1458 }
1459 
1460 
1461 /**@BEGINFUNC**************************************************************
1462 
1463     Prototype  : void XUTILDetermineFrameBufferVisual(
1464                       Display      *display,
1465                       int           screen,
1466                       XVisualInfo **fb_visual )
1467 
1468     Purpose    : Determine which visual corresponds the native format
1469                  of the frame buffer.
1470 
1471     Programmer : 16-Oct-99  Randall Hopper
1472 
1473     Parameters : display   - I: X display
1474                  screen    - I: X screen
1475                  fb_visual - O: XVisualInfo for frame buffer visual
1476 
1477     Returns    : None.
1478 
1479     Globals    : None.
1480 
1481  **@ENDFUNC*****************************************************************/
1482 
XUTILDetermineFrameBufferVisual(Display * display,int screen,XVisualInfo ** fb_visual)1483 void XUTILDetermineFrameBufferVisual( Display      *display,
1484                                       int           screen,
1485                                       XVisualInfo **fb_visual )
1486 {
1487     XVisualInfo          vinfo_pref;
1488     XVisualInfo         *visual;
1489     int                  num_visuals;
1490     TV_INT32             Bpp_pixmap_best  = -1,
1491                          Bpp_fbuffer_best = -1,
1492                          best_i           = -1,
1493                          i;
1494 
1495     /**********************************************************************/
1496     /*  FIXME:  This algorithm is heuristic and prone to failure.  Until  */
1497     /*    we have an enhanced XFree86 DGA 2.0 to tell us, we simply       */
1498     /*    assume the frame buffer visual is the one with the most         */
1499     /*    impressive pixel format.                                        */
1500     /**********************************************************************/
1501 
1502     vinfo_pref.screen = screen;
1503     vinfo_pref.depth = DefaultDepth( display, screen );
1504     visual = XGetVisualInfo( display,
1505                              VisualScreenMask | VisualDepthMask,
1506                              &vinfo_pref, &num_visuals );
1507     if ( num_visuals == 0 ) {
1508         fprintf( stderr, "XGetVisualInfo() says no visuals available!\n" );
1509         exit(1);
1510     }
1511 
1512     for ( i = 0; i < num_visuals; i++ ) {
1513         TV_INT32     Bpp_pixmap,
1514                      Bpp_fbuffer;
1515 
1516         XUTILGetVisualBpp( display, &visual[i], &Bpp_pixmap, &Bpp_fbuffer );
1517         if ( (( visual[i].class == PseudoColor ) ||
1518               ( visual[i].class == TrueColor   )) &&
1519              (( Bpp_pixmap  > Bpp_pixmap_best ) ||
1520               ( Bpp_fbuffer > Bpp_fbuffer_best )) ) {
1521             Bpp_pixmap_best  = Bpp_pixmap;
1522             Bpp_fbuffer_best = Bpp_fbuffer;
1523             best_i           = i;
1524         }
1525     }
1526 
1527     if ( best_i >= 0 )
1528         *fb_visual = &visual[ best_i ];
1529     else {
1530         Visual *def_vis;
1531 
1532         fprintf( stderr, "XUTILDetermineFrameBufferVisual failed.  "
1533                          "Falling back to default visual.\n" );
1534 
1535         def_vis = DefaultVisual( display, screen );
1536         vinfo_pref.screen   = screen;
1537         vinfo_pref.visualid = XVisualIDFromVisual( def_vis );
1538 
1539         *fb_visual = XGetVisualInfo( display,
1540                                      VisualScreenMask | VisualIDMask,
1541                                      &vinfo_pref, &num_visuals );
1542         if ( num_visuals != 1 ) {
1543             fprintf( stderr, "XGetVisualInfo() failed for default visual\n" );
1544             exit(1);
1545         }
1546     }
1547 }
1548