/* * xutil.c * * Utilities for detailing with X * * (C) 1997 Randall Hopper * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* ******************** Include Files ************** */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tvdefines.h" #include "xutil.h" #include "app_rsrc.h" /* NOTE: Do NOT include Scrollbar.h. This incorrectly defines */ /* the arguments of XawScrolbarSetThumb to be doubles, not floats. */ /*#include */ void XawScrollbarSetThumb( Widget w, float top, float shown ); /* ******************** Local defines ************** */ #ifndef FXTV_LIBDIR # define FXTV_LIBDIR X11BASE "/lib/X11/fxtv/%T/%N" #endif #define RUNCMD_CHECK_TIMEOUT_MS 200 #define WM_BORDER_PAD 40 typedef struct { pid_t cmd_pid; TVUTIL_PIPE_END end[3]; XtAppContext app_context; XUTIL_RUNCMD_CANCELCB *cancel_cb; void *cancel_cb_data; XUTIL_RUNCMD_DONECB *done_cb; void *done_cb_data; } XUTIL_RUNCMD_STATE; #define XLFD_SIZE_FOUNDRY 128 #define XLFD_SIZE_FAMILY 128 #define XLFD_SIZE_SMALL 30 typedef struct { char foundry [ XLFD_SIZE_FOUNDRY ]; char family [ XLFD_SIZE_FAMILY ]; char weight [ XLFD_SIZE_SMALL ]; char slant [ XLFD_SIZE_SMALL ]; char set_width [ XLFD_SIZE_SMALL ]; char ad_style [ XLFD_SIZE_SMALL ]; char pixel_size [ XLFD_SIZE_SMALL ]; char point_size [ XLFD_SIZE_SMALL ]; char x_dpi [ XLFD_SIZE_SMALL ]; char y_dpi [ XLFD_SIZE_SMALL ]; char spacing [ XLFD_SIZE_SMALL ]; char avg_width [ XLFD_SIZE_SMALL ]; char charset_reg[ XLFD_SIZE_SMALL ]; char charset_enc[ XLFD_SIZE_SMALL ]; } TV_XLFD; /* ******************** Private variables ************** */ static Atom S_wm_delete_window; #ifdef THE_ACTUAL_ASCII_TEXT_TRANSLATIONS char G_transl_ascii_text[] = "\ CtrlA: beginning-of-line()\n\ CtrlB: backward-character() \n\ CtrlD: delete-next-character() \n\ CtrlE: end-of-line() \n\ CtrlF: forward-character() \n\ CtrlG: multiply(Reset) \n\ CtrlH: delete-previous-character() \n\ CtrlJ: newline-and-indent() \n\ CtrlK: kill-to-end-of-line() \n\ CtrlL: redraw-display() \n\ CtrlM: newline() \n\ CtrlN: next-line() \n\ CtrlO: newline-and-backup() \n\ CtrlP: previous-line() \n\ CtrlR: search(backward) \n\ CtrlS: search(forward) \n\ CtrlT: transpose-characters() \n\ CtrlU: multiply(4) \n\ CtrlV: next-page() \n\ CtrlW: kill-selection() \n\ CtrlY: insert-selection(CUT_BUFFER1) \n\ CtrlZ: scroll-one-line-up() \n\ Ctrl\\\\: reconnect-im() \n\ MetaB: backward-word() \n\ MetaF: forward-word() \n\ MetaI: insert-file() \n\ MetaK: kill-to-end-of-paragraph() \n\ MetaQ: form-paragraph() \n\ MetaV: previous-page() \n\ MetaY: insert-selection(PRIMARY, CUT_BUFFER0) \n\ MetaZ: scroll-one-line-down() \n\ Metad: delete-next-word() \n\ MetaD: kill-word() \n\ Metah: delete-previous-word() \n\ MetaH: backward-kill-word() \n\ Meta\\<: beginning-of-file() \n\ Meta\\>: end-of-file() \n\ Meta]: forward-paragraph() \n\ Meta[: backward-paragraph() \n\ ~Shift MetaDelete: delete-previous-word() \n\ Shift MetaDelete: backward-kill-word() \n\ ~Shift MetaBackSpace: delete-previous-word() \n\ Shift MetaBackSpace: backward-kill-word() \n\ Right: forward-character() \n\ Left: backward-character() \n\ Down: next-line() \n\ Up: previous-line() \n\ Delete: delete-previous-character() \n\ BackSpace: delete-previous-character() \n\ Linefeed: newline-and-indent() \n\ Return: newline() \n\ : insert-char() \n\ Kanji: reconnect-im() \n\ : focus-in() \n\ : focus-out() \n\ : select-start() \n\ : extend-adjust() \n\ : extend-end(PRIMARY, CUT_BUFFER0) \n\ : insert-selection(PRIMARY, CUT_BUFFER0) \n\ : extend-start() \n\ : extend-adjust() \n\ : extend-end(PRIMARY, CUT_BUFFER0) \n\ "; #endif char G_transl_ovr_ascii_text[] = "\ : display-caret(on) \n\ : display-caret(off) \n\ "; char G_transl_ovr_ascii_text_1line[] = "\ Return: no-op()\n\ KP_Enter: no-op()\n\ Down: no-op()\n\ Up: no-op()\n\ Linefeed: no-op()\n\ CtrlJ: no-op()\n\ CtrlM: no-op()\n\ CtrlN: no-op()\n\ CtrlO: no-op()\n\ CtrlP: no-op()\n\ CtrlR: no-op()\n\ CtrlS: no-op()\n\ CtrlV: no-op()\n\ CtrlZ: no-op()\n\ MetaV: no-op()\n\ MetaZ: no-op()\n\ "; /* ******************** Forward declarations ************** */ /* ******************** Function Definitions ************** */ /**@BEGINFUNC************************************************************** Prototype : TV_BOOL XUTILBitmapLoad( char *bitmap_file, Widget wgt, Pixmap *pixmap ) Purpose : Loads a bitmap (xbm) of depth 1. Programmer : 16-Mar-97 Randall Hopper Parameters : bitmap_file - I: filename of bitmap file wgt - I: widget bitmap will be used on pixmap - O: pixmap loaded (depth 1) Returns : T = Success; F = Failure Globals : None. **@ENDFUNC*****************************************************************/ TV_BOOL XUTILBitmapLoad( char *bitmap_file, Widget wgt, Pixmap *pixmap ) { char *pixmap_path = NULL; unsigned width, height; int x_hot, y_hot; /********************************************/ /* Look for the pixmap file in FXTV_LIBDIR */ /********************************************/ pixmap_path = XtResolvePathname( XtDisplay(wgt), "bitmaps", bitmap_file, NULL, FXTV_LIBDIR, NULL, 0, NULL); if ( pixmap_path == NULL ) { fprintf( stderr, "Failed to find bitmap '%s'\n", bitmap_file ); return False; } if ( XReadBitmapFile( XtDisplay(wgt), RootWindowOfScreen( XtScreen( wgt ) ), pixmap_path, &width, &height, pixmap, &x_hot, &y_hot ) != BitmapSuccess ) { fprintf( stderr, "Failed to load bitmap '%s'\n", pixmap_path ); if ( pixmap_path != NULL ) XtFree( pixmap_path ); return False; } XtFree( pixmap_path ); return True; } /**@BEGINFUNC************************************************************** Prototype : TV_BOOL XUTILPixmapLoad( char *pixmap_file, Widget wgt, Pixel fg_color, Pixel bg_color, Pixmap *pixmap, Pixmap *pixmap_mask ) Purpose : Loads the specified pixmap file (.xbm or .xpm) for the purpose of future use with the specified widget. For pixmaps, transparency is resolved with the specified background color. For bitmaps, fg_color and bg_color are used directly to determine the colors of the on and off pixels in the pixmap. On success, the resulting pixmap (and pixmap mask, if is pixmap file AND mask is present AND pixmap_mask != NULL) is/are returned. Free these pixmaps using XFreePixmap. NOTE: The default X colormap is used for color matching. Programmer : 02-Mar-1997 Randall Hopper Parameters : pixmap_file - I: filename base for pixmap file wgt - I: widget pixmap will be associated with fg_color - I: foreground color bg_color - I: background color pixmap - O: returned pixmap (input can't be NULL) pixmap_mask - O: returned pixmap mask (input can be NULL) Returns : T = Success; F = Failure Globals : None. **@ENDFUNC*****************************************************************/ TV_BOOL XUTILPixmapLoad( char *pixmap_file, Widget wgt, Pixel fg_color, Pixel bg_color, Pixmap *pixmap, Pixmap *pixmap_mask ) { XpmAttributes xpmatts; XpmColorSymbol XpmTransparentColor[1] = { { NULL, "none", 0 } }; int xpm_status, color_depth, x_hot, y_hot; Pixmap pix_returned, pix_mask_returned, pixmap_depth1; Colormap colormap; char *pixmap_path = NULL; unsigned int width, height; XGCValues gcv; GC gc; if ( pixmap == NULL ) return False; /********************************************/ /* Look for the pixmap file in FXTV_LIBDIR */ /********************************************/ pixmap_path = XtResolvePathname( XtDisplay(wgt), "bitmaps", pixmap_file, NULL, FXTV_LIBDIR, NULL, 0, NULL); if ( pixmap_path == NULL ) { fprintf( stderr, "Failed to find bitmap/pixmap '%s'\n", pixmap_file ); return False; } XtVaGetValues( wgt, XtNdepth, &color_depth, NULL ); /********************************************************************/ /* .xbm's aren't handled by Xpm. Do something different for them */ /********************************************************************/ if (( strlen( pixmap_path ) > 4 ) && ( strcmp( pixmap_path + strlen( pixmap_path ) - 4, ".xbm" ) == 0 )) { /*****************/ /* Load bitmap */ /*****************/ if (( XReadBitmapFile( XtDisplay(wgt), RootWindowOfScreen( XtScreen( wgt ) ), pixmap_path, &width, &height, &pixmap_depth1, &x_hot, &y_hot ) != BitmapSuccess ) || ( (*pixmap = XCreatePixmap( XtDisplay(wgt), RootWindowOfScreen( XtScreen( wgt ) ), width, height, color_depth )) == None )){ fprintf( stderr, "Failed to load bitmap %s\n", pixmap_path ); if ( pixmap_path != NULL ) XtFree( pixmap_path ); return False; } gcv.foreground = fg_color; gcv.background = bg_color; gcv.graphics_exposures = False; gc = XCreateGC( XtDisplay(wgt), RootWindowOfScreen( XtScreen( wgt ) ), GCForeground | GCBackground | GCGraphicsExposures, &gcv ); XCopyPlane( XtDisplay(wgt), pixmap_depth1, *pixmap, gc, 0, 0, width, height, 0, 0, 0x00000001 ); XFreePixmap( XtDisplay( wgt ), pixmap_depth1 ); XFreeGC ( XtDisplay( wgt ), gc ); if ( pixmap_mask != NULL ) *pixmap_mask = NULL; } else { /*****************/ /* Load pixmap */ /*****************/ colormap = XDefaultColormap( XtDisplay( wgt ), DefaultScreen( XtDisplay( wgt ) ) ); XpmTransparentColor[0].pixel = bg_color; xpmatts.colormap = colormap; xpmatts.valuemask = XpmColorSymbols | XpmCloseness | XpmDepth | XpmColormap; xpmatts.colorsymbols = XpmTransparentColor; xpmatts.numsymbols = 1; xpmatts.closeness = 65536; xpmatts.depth = color_depth; xpm_status = XpmReadFileToPixmap( XtDisplay( wgt ), DefaultRootWindow( XtDisplay( wgt ) ), pixmap_path, &pix_returned, &pix_mask_returned, &xpmatts); if ( xpm_status < 0 ) { fprintf( stderr, "Failed to load pixmap %s\n", pixmap_path ); if ( pixmap_path != NULL ) XtFree( pixmap_path ); return False; } *pixmap = pix_returned; if ( pix_mask_returned ) if ( pixmap_mask != NULL ) *pixmap_mask = pix_mask_returned; else XFreePixmap( XtDisplay( wgt ), pix_mask_returned ); } if ( pixmap_path != NULL ) XtFree( pixmap_path ); return True; } /**@BEGINFUNC************************************************************** Prototype : void XUTILXawScrollbarSetThumb( Widget w, float top, float shown ) Purpose : Wrapper function for XawScrollbarSetThumb -- in a separate module from that in which its called so we can avoid a Scrollbar.h declaration error which declares XawScrollbarSetThumb taking doubles instead of floats (the library function expects floats). Programmer : 29-Mar-97 Randall Hopper Parameters : w - I: scrollbar widget top - I: top value shown - I: shown value Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void XUTILXawScrollbarSetThumb( Widget w, float top, float shown ) { /* This rtn is here to avoid a prototyping bug in Scrollbar.h */ /* where the args to the following function are incorrectly */ /* declared as doubles, not floats. */ XawScrollbarSetThumb( w, top, shown ); } /**@BEGINFUNC************************************************************** Prototype : void XUTILGetVisualBpp( Display *display, XVisualInfo *vi, TV_INT32 *Bpp_pixmap, TV_INT32 *Bpp_fbuffer ) Purpose : Returns the number of bytes per pixel for the specified visual. NOTE: This is not always (depth+7)/8, which is the reason for the existance of this convenience function. And even then this function will sometimes get it wrong because Pixmap pixel geometry doesn't necessarily equate to Frame buffer pixel geometry. BACKGROUND: Some X servers define 4 Bpp 24bpp modes as depth 32 bpp (-bpp 32), while others define them as depth 24 bpp (-bpp 24). Others use implement both 24bpp and 32bpp in a 3Bpp mode (e.g. 3.3.1 S3V server). So we can't use visual depth alone as a determining value. Alternatively we probe the pixmap formats that are supported by the display to help determine the true Bpp. For both cases, the pixmap bits_per_pixel for the corresponding depth (24 or 32) is 32, usually reflecting the true depth of the frame buffer, but not always. Because without probing hardware we can't really tell for sure what the frame buffer Bpp is, we allow the user to tell us (for 24bpp and 32bpp anyway) using the Bpp24bit and Bpp32bit settings Programmer : 29-Mar-97 Randall Hopper Parameters : display - I: display that visual is on vi - I: info struct for a visual Bpp_pixmap - O: pixmap Bpp Bpp_fbuffer - O: frame buffer Bpp Returns : Bytes per pixel for the visual Globals : None. **@ENDFUNC*****************************************************************/ void XUTILGetVisualBpp( Display *display, XVisualInfo *vi, TV_INT32 *Bpp_pixmap, TV_INT32 *Bpp_fbuffer ) { static struct { VisualID visualid; TV_INT32 Bpp_pixmap; TV_INT32 Bpp_fbuffer; } *Vlist = NULL; static int Vlist_len = 0; TV_INT32 i, Bpp = 0; /* Look up cached value */ for ( i = 0; i < Vlist_len; i++ ) if ( Vlist[i].visualid == vi->visualid ) break; /* Didn't have a cached value? Go figure it out. */ if ( i >= Vlist_len ) { XPixmapFormatValues *pf; int num_pf, pfi; /* Try to grab Bpp from pixmap formats first */ pf = XListPixmapFormats( display, &num_pf ); if ( pf != NULL ) { for ( pfi = 0; pfi < num_pf; pfi++ ) if ( pf[ pfi ].depth == vi->depth ) break; if ( pfi < num_pf ) Bpp = ( pf[ pfi ].bits_per_pixel + 7 ) / 8; XFree ( pf ); } /* Or fallback to using depth */ if ( Bpp == 0 ) Bpp = ( vi->depth + 7 ) / 8; /* And finally, add to Bpp cache */ Vlist_len++; Vlist = realloc( Vlist, sizeof( Vlist[0] ) * Vlist_len ); if ( Vlist == NULL ) TVUTILOutOfMemory(); i = Vlist_len-1; Vlist[i].visualid = vi->visualid; Vlist[i].Bpp_pixmap = Bpp; Vlist[i].Bpp_fbuffer = Bpp; } /* Even then, this value may not be right for the frame buffer */ /* geometry. Allow the user to override settings for 24bpp */ /* and 32bpp. */ if (( vi->depth == 24 ) && INRANGE( App_res.Bpp_24bit, 3, 4, 0 )) Vlist[i].Bpp_fbuffer = App_res.Bpp_24bit; else if (( vi->depth == 32 ) && INRANGE( App_res.Bpp_32bit, 3, 4, 0 )) Vlist[i].Bpp_fbuffer = App_res.Bpp_32bit; if ( Bpp_pixmap ) *Bpp_pixmap = Vlist[i].Bpp_pixmap; if ( Bpp_fbuffer ) *Bpp_fbuffer = Vlist[i].Bpp_fbuffer; } /**@BEGINFUNC************************************************************** Prototype : void XUTILGetVisualSwaps( Display *display, XVisualInfo *vi, TV_BOOL *swap_bytes, TV_BOOL *swap_shorts ) Purpose : Based on the visual, determines whether bytes and/or shorts need to be swapped in the process of pixel blasting to display correctly. Examples: <--- lower addr higher addr ---> 2Bpp 15bpp no-swap = xRRRRRGG GGGBBBBB 2Bpp 15bpp byte-swap = GGGBBBBB xRRRRRGG 3Bpp 24bpp no-swap = RGB RGB 3Bpp 24bpp byte-swap = BGR BGR 4Bpp 24bpp no-swap = ARGB ARGB 4Bpp 24bpp both-swap = BGRA BGRA Programmer : 22-Apr-97 Randall Hopper Parameters : display - I: display for visual vi - I: visual info swap_bytes - O: whether byte swap is needed swap_shorts - O: whether short swap is needed Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void XUTILGetVisualSwaps( Display *display, XVisualInfo *vi, TV_BOOL *swap_bytes, TV_BOOL *swap_shorts ) { TV_INT32 Bpp; /* FIXME: probably should make the settings based on bpp rather than */ /* Bpp since Bpp is ambiguous. 24bpp could be 3 or 4 Bpp. Ditto */ /* for 32bpp. */ XUTILGetVisualBpp( display, vi, NULL, &Bpp ); *swap_bytes = *swap_shorts = FALSE; /* FIXME: For now, just let the user override the default swaps. */ /* We have defaults, of course. */ /* Can't get this from the X server for 2Bpp modes -- assume */ /* swapped (makes sense -- more efficient). */ /* But consider whether we can determine for 3/4Bpp modes; do */ /* all X servers report the visual masks assuming a 4Bpp blast? */ /* (i.e. dword already reversed?) -- hard to guess. */ switch ( Bpp ) { case 2 : *swap_bytes = App_res.bswap2Bpp; break; case 3 : *swap_bytes = App_res.bswap3Bpp; break; case 4 : *swap_bytes = App_res.bswap4Bpp; *swap_shorts = App_res.wswap4Bpp; break; } } /**@BEGINFUNC************************************************************** Prototype : void XUTILDialogSmartPosition( Widget main_wgt, Widget dialog_wgt ) Purpose : Smart position a dialog so it lies on the screen. Programmer : 21-May-98 Randall Hopper Parameters : main_wgt - I: window to place dialog beside dialog_wgt - I: dialog to position Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void XUTILDialogSmartPosition( Widget main_wgt, Widget dialog_wgt ) { Dimension m_width, m_height, d_width, d_height; Position d_x, d_y, m_ul[2], m_lr[2]; Screen *screen = XtScreen ( main_wgt ); XtVaGetValues( dialog_wgt, XtNwidth , &d_width, XtNheight, &d_height, NULL ); XtVaGetValues( main_wgt, XtNwidth , &m_width, XtNheight, &m_height, NULL); XtTranslateCoords( main_wgt, 0, 0, &m_ul[0], &m_ul[1] ); m_lr[0] = m_ul[0] + m_width ; m_lr[1] = m_ul[1] + m_height; /* Try below, right, above, left, then just slap it on top of main_wgt */ if ( m_lr[1]+d_height+WM_BORDER_PAD <= HeightOfScreen(screen) ) d_x = m_ul[0], d_y = m_lr[1]+WM_BORDER_PAD; else if ( m_lr[0]+d_width+WM_BORDER_PAD <= WidthOfScreen(screen) ) d_x = m_lr[0]+WM_BORDER_PAD, d_y = m_ul[1]; else if ( m_ul[1]-d_height-WM_BORDER_PAD >= 0 ) d_x = m_ul[0], d_y = m_ul[1]-d_height-WM_BORDER_PAD; else if ( m_ul[0]-d_width-WM_BORDER_PAD >= 0 ) d_x = m_ul[0]-d_width-WM_BORDER_PAD, d_y = m_ul[1]; else d_x = m_ul[0], d_y = m_ul[1]; d_x = MAX(0, d_x ); d_y = MAX(0, d_y ); d_x = MIN( WidthOfScreen (screen), d_x+d_width ) - d_width; d_y = MIN( HeightOfScreen(screen), d_y+d_height ) - d_height; XtVaSetValues( dialog_wgt, XtNx, d_x, XtNy, d_y, NULL ); } /**@BEGINFUNC************************************************************** Prototype : Widget XUTILDialogBuild( Widget toplevel, char title[], char msg[], TV_DIALOG_TYPE type ) Prototype : TV_INT32 XUTILDialogPause( Widget toplevel, char title[], char msg[], TV_DIALOG_TYPE type ) Purpose : Utilities to build a dialog, and to put up a dialog with a user-specified message and sit-n-spin in our own local xevent loop until the user wakes up and answers the question. Programmer : 23-May-97 Randall Hopper Parameters : toplevel - I: top level shel widget for app title - I: dialog title msg - I: the message to display type - I: type of dialog to display Returns : For YES_NO dialogs, { TV_DIALOG_YES TV_DIALOG_NO } Globals : None. **@ENDFUNC*****************************************************************/ static TV_INT32 Dialog_answer; static void DialogCB( Widget w, XtPointer client_data, XtPointer cb_data ) { char *name = XtName( w ); if ( strcmp( name, "yes" ) == 0 ) Dialog_answer = TV_DIALOG_YES; else if ( strcmp( name, "no" ) == 0 ) Dialog_answer = TV_DIALOG_NO; else Dialog_answer = True; XtPopdown ( (Widget) client_data ); XtUnrealizeWidget( (Widget) client_data ); } Widget XUTILDialogBuild( Widget toplevel, char title[], char msg[], TV_DIALOG_TYPE type ) { Widget shell, dialog; /* Construct dialog */ shell = XtCreatePopupShell( "simplePromptShell", transientShellWidgetClass, toplevel, NULL, 0 ); XtVaSetValues( shell, XtNtitle , title, XtNallowShellResize, False, NULL ); dialog = XtVaCreateManagedWidget ( "simplePromptDialog", dialogWidgetClass, shell, XtNlabel, msg, NULL ); switch ( type ) { case TV_DIALOG_TYPE_OK : XawDialogAddButton( dialog, "ok" , DialogCB, shell ); break; case TV_DIALOG_TYPE_CANCEL : XawDialogAddButton( dialog, "cancel", DialogCB, shell ); break; case TV_DIALOG_TYPE_YES_NO : XawDialogAddButton( dialog, "yes" , DialogCB, shell ); XawDialogAddButton( dialog, "no" , DialogCB, shell ); break; case TV_DIALOG_TYPE_NOBUTTONS : break; default: fprintf( stderr, "Unsupported dialog type\n" ); exit(1); } return shell; } TV_INT32 XUTILDialogPause( Widget toplevel, char title[], char msg[], TV_DIALOG_TYPE type ) { Widget shell; /* Sanity check */ if ( type == TV_DIALOG_TYPE_NOBUTTONS ) { fprintf( stderr, "XUTILDialogPause: Bad dialog type\n" ); exit(1); } /* Build dialog */ shell = XUTILDialogBuild( toplevel, title, msg, type ); /* Pop it up */ XUTILXtPopup( shell, XtGrabNonexclusive, toplevel ); /* Wait until user answers the dialog */ while ( XtIsRealized(shell) ) { XEvent ev; XtAppNextEvent( XtWidgetToApplicationContext(toplevel), &ev ); XtDispatchEvent( &ev ); } /* Close and destroy the dialog */ XtUnrealizeWidget( shell ); XtDestroyWidget( shell ); return Dialog_answer; } /**@BEGINFUNC************************************************************** Prototype : static void XUTILGetPixelGeomInfo( TV_UINT32 rel_mask[3], int bits [3], int shift [3], int mask [3] ) Purpose : Get Pixel RGB component shifts, masks, and bit counts for the specified visual. (mask[0] << shift[0]) | (mask[1] << shift[1]) | (mask[2] << shift[2]) FIXME: Duplicated in videolib Programmer : 07-Mar-97 Randall Hopper Parameters : rel_mask- I: R/G/B shifted mask for each compoent bits - O: R/G/B bpp shift - O: R/G/B left shift cnt to align component in pixel mask - O: R/G/B mask to keep only desired bits E.g.: INPUT : rel_mask = FF0000,00FF00,0000FF OUTPUT: bits = 8,8,8 shift = 16,8,0 mask = FF,FF,FF Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ static void XUTILGetPixelGeomInfo( TV_UINT32 rel_mask[3], int bits [3], int shift [3], int mask [3] ) { int i; TV_UINT32 rel[3]; memcpy( rel, rel_mask, sizeof( rel ) ); for ( i = 0; i < 3; i++ ) { if ( !rel[i] ) { fprintf( stderr, "XUTILGetPixelGeomInfo: Bad X visual mask\n"); exit(1); } bits[i] = shift[i] = mask[i] = 0; while ( !(rel[i] & 0x01) ) rel[i] >>= 1, shift[i]++; mask[i] = rel[i]; while ( (rel[i] & 0x01) ) rel[i] >>= 1, bits[i]++; } } /**@BEGINFUNC************************************************************** Prototype : void XUTILGetPixelConvInfo( TV_UINT32 src_rel_mask[3], TV_UINT32 dst_rel_mask[3], TV_INT32 shift [3], TV_UINT32 mask [3] ) Purpose : Given a source pixel mask and a destination pixel mask, determines the shifts and masks necessary to map the source pixel geometry to the destination. FIXME: Duplicated in videolib Programmer : 29-Mar-97 Randall Hopper Parameters : src_rel_mask - I: source relative pixel masks dst_rel_mask - I: dest relative pixel masks shift - O: initial pixel shifts mask - O: final pixel masks E.g.: INPUT : src_rel_mask = 00FC00, 0003e0, 00001f dst_rel_mask = FF0000, 00FF00, 0000FF OUTPUT: shift = 8, 6, 3 mask = FC0000, 00F800, 0000F8 Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void XUTILGetPixelConvInfo( TV_UINT32 src_rel_mask[3], TV_UINT32 dst_rel_mask[3], TV_INT32 shift [3], TV_UINT32 mask [3] ) { int src_bits[3], src_shf[3], src_msk[3], src_soff[3], dst_bits[3], dst_shf[3], dst_msk[3], dst_soff[3]; TV_INT32 i; /* Get R/G/B shifts, masks, and bit counts */ XUTILGetPixelGeomInfo( src_rel_mask, src_bits, src_shf, src_msk ); XUTILGetPixelGeomInfo( dst_rel_mask, dst_bits, dst_shf, dst_msk ); /* Calculate R/G/B left-most bit offsets */ for ( i = 0; i < 3; i++ ) src_soff[i] = src_shf[i] + src_bits[i] - 1, dst_soff[i] = dst_shf[i] + dst_bits[i] - 1; /* Finally, calculate net shifts and masks */ for ( i = 0; i < 3; i++ ) { shift[i] = dst_soff[i] - src_soff[i]; if ( shift[i] >= 0 ) mask [i] = ( src_rel_mask[i] << shift[i] ) & dst_rel_mask[i]; else mask [i] = ( src_rel_mask[i] >> -shift[i] ) & dst_rel_mask[i]; } } /**@BEGINFUNC************************************************************** Prototype : static void XUTILRunCmdTimeoutCB( XtPointer cl_data, XtIntervalId *timer ) Purpose : Timer callback for XUTILRunCmdAllowCancel. Called periodically to check on the status of the background command. Programmer : 19-Jul-97 Randall Hopper Parameters : cl_data - I: state data struct (malloced mem) timer - I: Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ static void XUTILRunCmdTimeoutCB( XtPointer cl_data, XtIntervalId *timer ) { XUTIL_RUNCMD_STATE *state = (XUTIL_RUNCMD_STATE *) cl_data; int ret, status = 0; TV_BOOL aborted, complete; /* Ok, is our process still out there crunching? */ ret = kill( state->cmd_pid, 0 ); if (( ret < 0 ) && ( errno != ESRCH )) { TVUTILPipeCleanup( state->cmd_pid, state->end, &status ); perror( "kill(,0) failed on conv process" ); exit(1); } aborted = state->cancel_cb && state->cancel_cb( state->cancel_cb_data ); complete = ( ret < 0 ) && ( errno == ESRCH ); /* If process is done or user aborted, clean up and get exit status, */ /* and notify client. */ if ( aborted || complete ) { if ( aborted ) kill( state->cmd_pid, SIGINT ); TVUTILPipeCleanup( state->cmd_pid, state->end, &status ); state->done_cb( aborted, status, state->done_cb_data ); free(state); } /* Otherwise, just go back to sleep and check again later */ else XtAppAddTimeOut( state->app_context, RUNCMD_CHECK_TIMEOUT_MS, XUTILRunCmdTimeoutCB, state ); } /**@BEGINFUNC************************************************************** Prototype : void 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 ) Purpose : Run a command (cmd,end) in the background giving the client the opportunity to cancel the command using its own criteria (e.g. dialog dismissed, cancel button pressed, etc.). While the command is executing, its existance is checked and the cancel_test callback is called (with cancel_cb_data) periodically. When the command completes or is cancelled, the user-defined callback done_cb is called with done_cb_data. The callback is also passed whether the command was aborted as well as the exit status of the command. If the command is called (cancel_test returns TRUE), the command is killed (SIGINT is issued). Programmer : 30-May-97 Randall Hopper Parameters : app-context - I: Xt application context cmd - I: cmd to execute ( [argv[0],argv[1],...] ) end - I: bindings for stdin/stdout of cmd cancel_test - I: callback to allow client to abort command cancel_cb_data - I: client data to pass cancel callback done_cb - I: callback to call on cmd complete/abort done_cb_data - I: client data to pass done callback Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void 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 ) { XUTIL_RUNCMD_STATE *state; /* We'll wake-up every once in a while and check on it. */ /* First, build state data struct. */ if ( (state = malloc( sizeof( *state ) )) == NULL ) TVUTILOutOfMemory(); memset( state, '\0', sizeof( *state ) ); state->cmd_pid = -1; memcpy( state->end, end, sizeof( state->end ) ); state->app_context = app_context; state->cancel_cb = cancel_test; state->cancel_cb_data = cancel_cb_data; state->done_cb = done_cb; state->done_cb_data = done_cb_data; /* Ok, now fire-up the child process */ TVUTILPipeSetup( NULL, cmd, end, &state->cmd_pid ); /* Now go to sleep and wait on 1) user to cancel, or 2) cmd to complete */ XtAppAddTimeOut( state->app_context, RUNCMD_CHECK_TIMEOUT_MS, XUTILRunCmdTimeoutCB, state ); } /* XUTILIsWellFormedXLFDFont */ /* This routine returns True if the passed name is a well-formed */ /* XLFD style font name. Adapted from XUtilIsScalableFont (below). */ Bool XUTILIsWellFormedXLFDFont( char *name ) { int i, field, field_len; char *p; if ( !name || ( name[0] != '-' )) return False; for ( i = field = 0; name[i] != '\0'; i++ ) if ( name[i] == '-' ) { field++; if ( (p = strchr( &name[i+1], '-' )) != NULL ) field_len = p - &name[i+1]; else field_len = strlen( &name[i+1] ) - i+1; if (( field != 6 ) && ( field_len == 0 )) return False; switch ( field ) { case 1 : if ( field_len >= XLFD_SIZE_FOUNDRY ) return False; break; case 2 : if ( field_len >= XLFD_SIZE_FAMILY ) return False; break; default : if ( field_len >= XLFD_SIZE_SMALL ) return False; break; } } return ( field == 14 ); } /* XUTILIsScalableFont - From O'Reilly X11R5 Vol 1 A.3.3 (pg 569). */ /* This routine returns True if the passed name is a well-formed */ /* XLFD style font name with a pixel size, point size, and average */ /* width (fields 7, 8, and 12) of "0". */ /* Modified: component length sanity checking added. */ Bool XUTILIsScalableFont( char *name ) { int i, field, field_len; char *p; if ( !name || ( name[0] != '-' )) return False; for ( i = field = 0; name[i] != '\0'; i++ ) if ( name[i] == '-' ) { field++; if (( field == 7 ) || ( field == 8 ) || ( field == 12 )) if (( name[i+1] != '0' ) || ( name[i+2] != '-' )) return False; if ( (p = strchr( &name[i+1], '-' )) != NULL ) field_len = p - &name[i+1]; else field_len = strlen( &name[i+1] ) - i+1; switch ( field ) { case 1 : if ( field_len >= XLFD_SIZE_FOUNDRY ) return False; break; case 2 : if ( field_len >= XLFD_SIZE_FAMILY ) return False; break; default : if ( field_len >= XLFD_SIZE_SMALL ) return False; break; } } return ( field == 14 ); } /* XUTILSplitXLFD - Split an XLFD font name up into components */ static void XUTILSplitXLFD( char name[], TV_XLFD *xlfd ) { int ret; if ( !XUTILIsWellFormedXLFDFont( name ) ) { fprintf( stderr, "XUTILSplitXLFD: Passed non-XLFD font\n" ); exit(1); } xlfd->ad_style[0] = '\0'; ret = sscanf( name, "-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]" "-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]", xlfd->foundry, xlfd->family, xlfd->weight, xlfd->slant, xlfd->set_width, xlfd->ad_style, xlfd->pixel_size, xlfd->point_size, xlfd->x_dpi, xlfd->y_dpi, xlfd->spacing, xlfd->avg_width, xlfd->charset_reg, xlfd->charset_enc ); if ( ret != 14 ) { xlfd->ad_style[0] = '\0'; ret = sscanf( name, "-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]--%[^-]-%[^-]" "-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]-%[^-]", xlfd->foundry, xlfd->family, xlfd->weight, xlfd->slant, xlfd->set_width, xlfd->pixel_size, xlfd->point_size, xlfd->x_dpi, xlfd->y_dpi, xlfd->spacing, xlfd->avg_width, xlfd->charset_reg, xlfd->charset_enc ); if ( ret != 13 ) { fprintf( stderr, "XUTILSplitXLFD: Unexpected parse failure\n" ); exit(1); } } } /* XUTILMergeXLFD - Build an XLFD font name string up from its components */ /* It is assumed that name[] is large enough to hold the resulting str. */ static void XUTILMergeXLFD( TV_XLFD *xlfd, char name[] ) { sprintf( name, "-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s", xlfd->foundry, xlfd->family, xlfd->weight, xlfd->slant, xlfd->set_width, xlfd->ad_style, xlfd->pixel_size, xlfd->point_size, xlfd->x_dpi, xlfd->y_dpi, xlfd->spacing, xlfd->avg_width, xlfd->charset_reg, xlfd->charset_enc ); } #define TV_XLFD_SPLIT( str_name, xlfd ) \ /* XUTILLoadQueryScalableFont - From O'Reilly X11R5 Vol 1 A.3.3 (pg 570). */ /* This routine is passed a scalable font name and a point size. It */ /* returns an XFontStruct for the given font scaled to the specified */ /* size and the exact resolution of the screen. The font name is */ /* assumed to be a well-formed XLFD name, and to have pixel size, point */ /* size, and average width fields of "0" and arbitrary x-res and y-res */ /* fields. Size is specified in tenths of points. Returns NULL if */ /* no such font exists. */ /* ADAPTED: new_name, new_name_size args added. */ XFontStruct *XUTILLoadQueryScalableFont( Display *dpy, int screen, char *name, int size, char *new_name, int new_name_size ) { int i,j,field; char newname[500]; int res_x,res_y; if ( !XUTILIsScalableFont( name ) ) { fprintf( stderr, "XUTILLoadQueryScalableFont: Passed non-scalable font\n" ); exit(1); } /* Calculate our screen res in dots-per-inch. 25.4mm = 1in */ res_x = DisplayWidth( dpy, screen ) / ( DisplayWidthMM( dpy, screen ) / 25.4 ); res_y = DisplayHeight( dpy, screen ) / ( DisplayHeightMM( dpy, screen ) / 25.4 ); /* Copy the font name, changing the scalable fields as we do so */ for ( i = j = field = 0; name[i] != '\0' && field <= 14; i++ ) { newname[j++] = name[i]; if ( name[i] == '-' ) { field++; switch ( field ) { case 7: /* pixel size */ case 12: /* average width */ /* change from "-0-" to "-*-" */ newname[j] = '*'; j++; if ( name[i+1] != '\0' ) i++; break; case 8: /* point size */ /* change from "-0-" to "--" */ sprintf( &newname[j], "%d", size ); while ( newname[j] != '\0' ) j++; if ( name[i+1] != '\0' ) i++; break; case 9: /* x-resolution */ case 10: /* y-resolution */ /* change from an unspecified res to res_x or res_y */ sprintf( &newname[j], "%d", (field == 9 ) ? res_x:res_y ); while ( newname[j] != '\0' ) j++; while( (name[i+1] != '-') && (name[i+1] != '\0')) i++; break; } } } newname[j] = '\0'; if ( new_name ) { new_name[0] = '\0'; strncat( new_name, newname, new_name_size-1 ); } /* if there aren't 14 hyphens, it isn't a well-formed name */ assert( field == 14 ); return XLoadQueryFont( dpy, newname ); } /* XUTILLoadPixelSizeFont */ /* This routine is passed a well-formed XLFD font name and a pixel size. */ /* It returns an XFontStruct for the given font scaled to the specified */ /* pixel size (if possible). Returns NULL if no such font can be built. */ /* Also, the pixel size is only plugged into the font name if the */ /* pixel size component is wildcarded or 0. */ /* ADAPTED: from the adapted XUTILLoadQueryScalableFont */ XFontStruct *XUTILLoadPixelSizeFont( Display *dpy, char *name, int pixel_size, char *new_name, int new_name_size ) { TV_XLFD xlfd; char newname[500]; XUTILSplitXLFD( name, &xlfd ); if (( strcmp( xlfd.pixel_size, "0" ) == 0 ) || ( strcmp( xlfd.pixel_size, "*" ) == 0 )) sprintf( xlfd.pixel_size, "%d", abs(pixel_size) ); XUTILMergeXLFD( &xlfd, newname ); if ( new_name ) { new_name[0] = '\0'; strncat( new_name, newname, new_name_size-1 ); } return XLoadQueryFont( dpy, newname ); } /* XUTILXMDeleteChildWindow - Called when we receive a window manager */ /* event for a shell window registered with XUTILRegisterWMDelete. */ /* We register for WM_DELETE_WINDOW for WM Close events. When this */ /* occurs, ignore the event. */ static void XUTILWMDeleteChildWindow( Widget w, XEvent *event, String *params, Cardinal num_params ) { if ( event->type == ClientMessage && ( event->xclient.data.l[0] != S_wm_delete_window ) ) { XBell ( XtDisplay(w), 0 ); return; } /* Ignore WM_DELETE */ XBell ( XtDisplay(w), 0 ); } /* XUTILRegisterWMDelete - Adds translation to shell widgets so that */ /* the app doesn't blow up when the user selects the WM Close function */ /* on out child windows. */ void XUTILRegisterWMDelete( Widget shell_wgt ) { static TV_BOOL S_wm_delete_inited = FALSE; static XtActionsRec S_wm_delete_actions[] = { { "WMDeleteChildWindow", (XtActionProc) XUTILWMDeleteChildWindow } }; if ( !XtIsRealized( shell_wgt ) ) { fprintf( stderr, "XUTILRegisterWMDelete: Called with an unrealized " "widget: %s\n", XtName( shell_wgt ) ); exit(1); } /* One-time init */ if ( !S_wm_delete_inited ) { /* WM Delete Window (Close) callback for FXTV child windows */ XtAppAddActions ( XtWidgetToApplicationContext( shell_wgt ), S_wm_delete_actions, XtNumber( S_wm_delete_actions ) ); S_wm_delete_inited = TRUE; } /* Add WM callback translation to shell widget */ XtOverrideTranslations( shell_wgt, XtParseTranslationTable( "WM_PROTOCOLS: WMDeleteChildWindow()" ) ); /* And ask window manager to call us for WM_DELETE_WINDOW events */ S_wm_delete_window = XInternAtom( XtDisplay( shell_wgt ), "WM_DELETE_WINDOW", False ); XSetWMProtocols( XtDisplay( shell_wgt ), XtWindow( shell_wgt ), &S_wm_delete_window, 1); } /* XUTILXtPopup - XtPopup but additionally register a WM callback */ /* to ignore WM_DELETE_WINDOW, and smart-positions the dialog. */ void XUTILXtPopup( Widget popup_shell, XtGrabKind grab_kind, Widget toplevel ) { Dimension height; Position x,y; /* Tentatively position it */ XtVaGetValues( toplevel, XtNheight, &height, NULL ); XtTranslateCoords( toplevel, 0, 0, &x, &y ); XtVaSetValues( popup_shell, XtNx, x, XtNy, y+height, NULL ); XtPopup( popup_shell, grab_kind ); /* Position it for keeps */ XUTILDialogSmartPosition( toplevel, popup_shell ); /* Ignore WM_DELETE */ XUTILRegisterWMDelete( popup_shell ); } /* XUTILXServerIsLocal - Returns TRUE if the X server we're connecting to */ /* is on the local machine (X via IPC or IP is assigned to an interface */ /* of the local box. */ TV_BOOL XUTILXServerIsLocal( Display *display ) { char host_str[ 80 ], *p; /* Grab the host part of the display string */ host_str[0] = '\0'; strncat( host_str, DisplayString(display), sizeof(host_str)-1 ); if ( (p = strchr( host_str, ':' )) == NULL ) return FALSE; *p = '\0'; TVUTILstrlwr( host_str ); /* If local IPC, is local */ if (( host_str[0] == '\0' ) || ( strcmp( host_str, "unix" ) == 0 )) return TRUE; /* If hostname or IP belongs to one of our network interfaces, its */ /* local. */ /* FIXME: Add this */ return FALSE; } /**@BEGINFUNC************************************************************** Prototype : void XUTILDetermineFrameBufferVisual( Display *display, int screen, XVisualInfo **fb_visual ) Purpose : Determine which visual corresponds the native format of the frame buffer. Programmer : 16-Oct-99 Randall Hopper Parameters : display - I: X display screen - I: X screen fb_visual - O: XVisualInfo for frame buffer visual Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void XUTILDetermineFrameBufferVisual( Display *display, int screen, XVisualInfo **fb_visual ) { XVisualInfo vinfo_pref; XVisualInfo *visual; int num_visuals; TV_INT32 Bpp_pixmap_best = -1, Bpp_fbuffer_best = -1, best_i = -1, i; /**********************************************************************/ /* FIXME: This algorithm is heuristic and prone to failure. Until */ /* we have an enhanced XFree86 DGA 2.0 to tell us, we simply */ /* assume the frame buffer visual is the one with the most */ /* impressive pixel format. */ /**********************************************************************/ vinfo_pref.screen = screen; vinfo_pref.depth = DefaultDepth( display, screen ); visual = XGetVisualInfo( display, VisualScreenMask | VisualDepthMask, &vinfo_pref, &num_visuals ); if ( num_visuals == 0 ) { fprintf( stderr, "XGetVisualInfo() says no visuals available!\n" ); exit(1); } for ( i = 0; i < num_visuals; i++ ) { TV_INT32 Bpp_pixmap, Bpp_fbuffer; XUTILGetVisualBpp( display, &visual[i], &Bpp_pixmap, &Bpp_fbuffer ); if ( (( visual[i].class == PseudoColor ) || ( visual[i].class == TrueColor )) && (( Bpp_pixmap > Bpp_pixmap_best ) || ( Bpp_fbuffer > Bpp_fbuffer_best )) ) { Bpp_pixmap_best = Bpp_pixmap; Bpp_fbuffer_best = Bpp_fbuffer; best_i = i; } } if ( best_i >= 0 ) *fb_visual = &visual[ best_i ]; else { Visual *def_vis; fprintf( stderr, "XUTILDetermineFrameBufferVisual failed. " "Falling back to default visual.\n" ); def_vis = DefaultVisual( display, screen ); vinfo_pref.screen = screen; vinfo_pref.visualid = XVisualIDFromVisual( def_vis ); *fb_visual = XGetVisualInfo( display, VisualScreenMask | VisualIDMask, &vinfo_pref, &num_visuals ); if ( num_visuals != 1 ) { fprintf( stderr, "XGetVisualInfo() failed for default visual\n" ); exit(1); } } }