/* * annot.c * * Routines to manage the display of annotation on top of the video window. * * (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 "tvdefines.h" #include "tvtypes.h" #include "app_rsrc.h" #include "annot.h" #include "glob.h" #include "tvutil.h" #include "tvscreen.h" #include "tvaudio.h" #include "tvcapture.h" /* ******************** Local defines ************** */ #define TIMEBASE_SEC 876000000L #define FALLBACK_FONT "10x20" #define QUANTIZE_FONT_SIZE(size) MAX( ((TV_INT32)(size)+4)/5*5, 10 ) /* Let's not go nuts creating different font sizes. They */ /* use memory and take CPU to compute. */ #define AUTOMODE_TIMER_MS 8 #define VOLUME_FMT "Volume: %ld%%" #define MUTE_STR "MUTE" /*#define FNPRINTF(x) printf x*/ #define FNPRINTF(x) /* ******************** Forward declarations ************** */ /* ******************** Private variables ************** */ /* ******************** Function Definitions ************** */ /**@BEGINFUNC************************************************************** Prototype : static void TVANNOTLoadFont( Display *display, char font[], TV_INT32 pixel_size, XFontSet *fontset ) Purpose : Loads the specified font pattern in the specified pixel_size, if possible. If multiple fonts match the pattern, the first match is loaded. If the first match is not an XLFD font with '0' or '*' in the pixel_size component, pixel_size is ignored and the font is loaded as-is. If the font is invalid, a fallback font is loaded. Programmer : 04-Oct-97 Randall Hopper Parameters : display - I: X display font - I: font pattern. Examples: -*-utopia-regular-r-*-*-0-0-*-*-*-0-iso8859-1 9x15 pixel_size - I: desired pixel size to load font in fontset - O: fontset handle to the loaded font Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ static void TVANNOTLoadFont( Display *display, char font[], TV_INT32 pixel_size, XFontSet *fontset ) { char **fonts; int count; char new_font[ 256 ] = ""; XFontStruct *fontstr = NULL; char **missing_charset_list; int missing_count; *fontset = NULL; FNPRINTF(( "Validating font spec '%s'\n", font )); fonts = XListFonts( display, font, 1, &count ); if ( count == 0 ) fprintf( stderr, "No matching font(s) registered with X Server:\n %s\n", font ); else if ( XUTILIsWellFormedXLFDFont( fonts[0] ) ) { FNPRINTF(( "Found at least one registered font, and the first " "one is an XLFD font:\n '%s'\n", fonts[0] )); FNPRINTF(( "Trying to load a '%d' pixel size version\n", pixel_size )); fontstr = XUTILLoadPixelSizeFont( TVDISPLAY, fonts[0], pixel_size, new_font, sizeof(new_font) ); if ( fontstr == NULL ) { new_font[0] = '\0'; fprintf( stderr, "Load failed:\n %s\n", fonts[0] ); } else { XFreeFontInfo( NULL, fontstr, 0 ); FNPRINTF(( "Load successful: '%s'\n", new_font )); } } else { FNPRINTF(( "Found at least one registered font; the first " "one isn't an XLFD font:\n '%s'\n", fonts[0] )); strncat( new_font, fonts[0], sizeof(new_font)-1 ); fontstr = XLoadQueryFont( TVDISPLAY, fonts[0] ); if ( fontstr == NULL ) new_font[0] = '\0'; else XFreeFontInfo( NULL, fontstr, 0 ); if ( fontstr ) FNPRINTF(( "Load successful.\n" )); else fprintf( stderr, "Load failed:\n %s\n", fonts[0] ); } if ( count ) XFreeFontNames( fonts ); if ( new_font[0] == '\0' ) { strcpy( new_font, FALLBACK_FONT ); fprintf( stderr, "Falling back on '%s' font.\n", new_font ); fontstr = XLoadQueryFont( TVDISPLAY, new_font ); if ( fontstr == NULL ) { fprintf( stderr, "Failed to load the fall-back '%s' font.\n", new_font ); exit(1); } XFreeFontInfo( NULL, fontstr, 0 ); } *fontset = XCreateFontSet( TVDISPLAY, new_font, &missing_charset_list, &missing_count, NULL ); if ( ! *fontset ) { fprintf( stderr, "Whoah! Failed to load font '%s' which X 'said' it knew about.\n" "This shouldn't happen (but does in XFree86 3.9.16).\n" "Basically, choose another font or take the default font.\n", new_font ); exit(1); } } /*---------------------------------------------------------------------------*/ static void TVANNOTPropInit( TV_ANNOT_PROP *p ) { p->gc = NULL; p->font_pattern = NULL; p->fontset = NULL; p->delay = 2000; p->start_time.tv_sec = -1; } void TVANNOTInit( TV_ANNOT *a, Display *display, int screen, XtAppContext app_context ) { memset( a, '\0', sizeof(*a) ); a->display = display; a->screen = screen; a->app_context = app_context; a->drawable = None; a->geom.w = a->geom.h = -1; a->auto_update = False; TVANNOTPropInit( &a->station ); TVANNOTPropInit( &a->tuner_mode ); TVANNOTPropInit( &a->input_dev ); TVANNOTPropInit( &a->volume ); TVANNOTPropInit( &a->mute ); /* Station */ a->station.delay = App_res.station_annot_delay; a->station.font_pattern = App_res.station_annot_font; a->station.fg_pixel = App_res.station_annot_color; /* Tuner mode */ a->tuner_mode.delay = App_res.tuner_mode_annot_delay; a->tuner_mode.font_pattern = App_res.tuner_mode_annot_font; a->tuner_mode.fg_pixel = App_res.tuner_mode_annot_color; /* Input Device */ a->input_dev.delay = App_res.input_dev_annot_delay; a->input_dev.font_pattern = App_res.input_dev_annot_font; a->input_dev.fg_pixel = App_res.input_dev_annot_color; /* Volume */ a->volume.delay = App_res.volume_annot_delay; a->volume.font_pattern = App_res.volume_annot_font; a->volume.fg_pixel = App_res.volume_annot_color; /* Mute */ a->mute.delay = App_res.mute_annot_delay; a->mute.font_pattern = App_res.mute_annot_font; a->mute.fg_pixel = App_res.mute_annot_color; } /*---------------------------------------------------------------------------*/ static void TVANNOTPropSetDrawable( TV_ANNOT_PROP *p, Display *display, Drawable drawable ) { if ( p->gc != NULL ) XFreeGC( display, p->gc ); p->gc = XCreateGC( display, drawable, 0, NULL ); } void TVANNOTSetDrawable( TV_ANNOT *a, Drawable drawable ) { if ( a->drawable == drawable ) return; a->drawable = drawable; a->geom.w = a->geom.h = -1; /* When the drawable is set or changes, we need to recreate the GCs */ TVANNOTPropSetDrawable( &a->station , a->display, drawable ); TVANNOTPropSetDrawable( &a->tuner_mode, a->display, drawable ); TVANNOTPropSetDrawable( &a->input_dev , a->display, drawable ); TVANNOTPropSetDrawable( &a->volume , a->display, drawable ); TVANNOTPropSetDrawable( &a->mute , a->display, drawable ); } /*---------------------------------------------------------------------------*/ static void TVANNOTGetModeGeom( Dimension *width, Dimension *height ) { TV_XSCREEN *s = &G_glob.x; if ( s->vmode_ext_supported ) TVSCREENGetCurVidModeGeometry( s, width, height ); else *width = DisplayWidth ( TVDISPLAY, TVSCREEN ), *height = DisplayHeight( TVDISPLAY, TVSCREEN ); } static void TVANNOTStationPropSetDrawableSize( TV_ANNOT *a, TV_ANNOT_PROP *p, Display *display, Dimension width, Dimension height ) { TV_INT32 pixel_size; Dimension vm_width, vm_height; XFontSetExtents *extents; /* Determine new pixel size based on Drawable size and Video Mode */ TVANNOTGetModeGeom( &vm_width, &vm_height ); pixel_size = QUANTIZE_FONT_SIZE( (TV_INT32)height * vm_height / 768 / 15 ); /* If different than the one we've got, reload at the new size */ if (( p->fontset == NULL ) || ( p->pixel_size != pixel_size )) { FNPRINTF(( "\nSTATION ANNOTATION FONT:\n" )); if ( p->fontset != NULL ) XFreeFontSet( display, p->fontset ); TVANNOTLoadFont( display, p->font_pattern, pixel_size, &p->fontset ); assert( p->fontset != NULL ); p->pixel_size = pixel_size; } /* Determine new location */ extents = XExtentsOfFontSet( p->fontset ); p->loc.x = 15; p->loc.y = height - 15; } static void TVANNOTTunerModePropSetDrawableSize( TV_ANNOT *a, TV_ANNOT_PROP *p, Display *display, Dimension width, Dimension height ) { TV_INT32 pixel_size; Dimension vm_width, vm_height; XFontSetExtents *extents; /* Determine new pixel size based on Drawable size and Video Mode */ TVANNOTGetModeGeom( &vm_width, &vm_height ); pixel_size = QUANTIZE_FONT_SIZE( (TV_INT32)height * vm_height / 768 / 20 ); /* If different than the one we've got, reload at the new size */ if (( p->fontset == NULL ) || ( p->pixel_size != pixel_size )) { FNPRINTF(( "\nTUNER MODE ANNOTATION FONT:\n" )); if ( p->fontset != NULL ) XFreeFontSet( display, p->fontset ); TVANNOTLoadFont( display, p->font_pattern, pixel_size, &p->fontset ); assert( p->fontset != NULL ); p->pixel_size = pixel_size; } /* Determine new location */ extents = XExtentsOfFontSet( p->fontset ); p->loc.x = 15; p->loc.y = 5 + extents->max_logical_extent.height; } static void TVANNOTInputDevPropSetDrawableSize( TV_ANNOT *a, TV_ANNOT_PROP *p, Display *display, Dimension width, Dimension height ) { TV_INT32 pixel_size; Dimension vm_width, vm_height; XFontSetExtents *extents_tm, *extents; /* Determine new pixel size based on Drawable size and Video Mode */ TVANNOTGetModeGeom( &vm_width, &vm_height ); pixel_size = QUANTIZE_FONT_SIZE( (TV_INT32)height * vm_height / 768 / 20 ); /* If different than the one we've got, reload at the new size */ if (( p->fontset == NULL ) || ( p->pixel_size != pixel_size )) { FNPRINTF(( "\nINPUT DEVICE ANNOTATION FONT:\n" )); if ( p->fontset != NULL ) XFreeFontSet( display, p->fontset ); TVANNOTLoadFont( display, p->font_pattern, pixel_size, &p->fontset ); assert( p->fontset != NULL ); p->pixel_size = pixel_size; } /* Determine new location - put it below Tuner Mode annotation */ extents_tm = XExtentsOfFontSet( a->tuner_mode.fontset ); extents = XExtentsOfFontSet( p->fontset ); p->loc.x = 15; p->loc.y = a->tuner_mode.loc.y + extents_tm->max_logical_extent.height / 2 + extents->max_logical_extent.height / 2; } static void TVANNOTVolumePropSetDrawableSize( TV_ANNOT *a, TV_ANNOT_PROP *p, Display *display, Dimension width, Dimension height ) { TV_INT32 pixel_size; Dimension vm_width, vm_height; XFontSetExtents *extents; char str[80]; int str_width; /* Determine new pixel size based on Drawable size and Video Mode */ TVANNOTGetModeGeom( &vm_width, &vm_height ); pixel_size = QUANTIZE_FONT_SIZE( (TV_INT32)height * vm_height / 768 / 20 ); /* If different than the one we've got, reload at the new size */ if (( p->fontset == NULL ) || ( p->pixel_size != pixel_size )) { FNPRINTF(( "\nVOLUME ANNOTATION FONT:\n" )); if ( p->fontset != NULL ) XFreeFontSet( display, p->fontset ); TVANNOTLoadFont( display, p->font_pattern, pixel_size, &p->fontset ); assert( p->fontset != NULL ); p->pixel_size = pixel_size; } /* Determine new location */ sprintf( str, VOLUME_FMT, 100L ); str_width = XmbTextEscapement( p->fontset, str, strlen(str) ); extents = XExtentsOfFontSet( p->fontset ); p->loc.x = width - 15 - str_width; p->loc.y = 5 + extents->max_logical_extent.height; } static void TVANNOTMutePropSetDrawableSize( TV_ANNOT *a, TV_ANNOT_PROP *p, Display *display, Dimension width, Dimension height ) { TV_INT32 pixel_size; Dimension vm_width, vm_height; XFontSetExtents *extents_v, *extents; int str_width; /* Determine new pixel size based on Drawable size and Video Mode */ TVANNOTGetModeGeom( &vm_width, &vm_height ); pixel_size = QUANTIZE_FONT_SIZE( (TV_INT32)height * vm_height / 768 / 25 ); /* If different than the one we've got, reload at the new size */ if (( p->fontset == NULL ) || ( p->pixel_size != pixel_size )) { FNPRINTF(( "\nMUTE ANNOTATION FONT:\n" )); if ( p->fontset != NULL ) XFreeFontSet( display, p->fontset ); TVANNOTLoadFont( display, p->font_pattern, pixel_size, &p->fontset ); assert( p->fontset != NULL ); p->pixel_size = pixel_size; } /* Determine new location - Put below Volume Annotation */ str_width = XmbTextEscapement( p->fontset, MUTE_STR, strlen(MUTE_STR) ); extents_v = XExtentsOfFontSet( a->volume.fontset ); extents = XExtentsOfFontSet( p->fontset ); p->loc.x = width - 15 - str_width; p->loc.y = a->volume.loc.y + extents_v->max_logical_extent.height / 2 + extents->max_logical_extent.height / 2; } void TVANNOTSetDrawableSize( TV_ANNOT *a, Dimension width, Dimension height ) { Display *d = a->display; a->geom.w = width; a->geom.h = height; TVANNOTStationPropSetDrawableSize ( a, &a->station , d, width, height ); TVANNOTTunerModePropSetDrawableSize( a, &a->tuner_mode, d, width, height ); TVANNOTInputDevPropSetDrawableSize ( a, &a->input_dev , d, width, height ); TVANNOTVolumePropSetDrawableSize ( a, &a->volume , d, width, height ); TVANNOTMutePropSetDrawableSize ( a, &a->mute , d, width, height ); } /*---------------------------------------------------------------------------*/ static TV_BOOL TVANNOTUpdateIsRequired( TV_ANNOT_PROP *p, struct timeval *cur_time ) { TV_BOOL required; TV_INT32 elapsed = -1; if (( p->delay > 0 ) && ( p->start_time.tv_sec >= 0 )) elapsed = ( cur_time->tv_usec - p->start_time.tv_usec ) / 1000 + ( cur_time->tv_sec - p->start_time.tv_sec ) * 1000; required = ( p->delay < 0 ) || (( elapsed >= 0 ) && ( elapsed <= p->delay )); if ( !required ) p->start_time.tv_sec = -1; return required; } static void TVANNOTDrawShadowedText( TV_ANNOT *a, TV_ANNOT_PROP *p, char str[] ) { XGCValues gcv; XtGCMask gcmask; gcmask = GCForeground; gcv.foreground = BlackPixel( a->display, a->screen ); XChangeGC( a->display, p->gc, gcmask, &gcv ); XmbDrawString( a->display, a->drawable, p->fontset, p->gc, p->loc.x+1, p->loc.y+1, str, strlen(str) ); gcv.foreground = p->fg_pixel; XChangeGC( a->display, p->gc, gcmask, &gcv ); XmbDrawString( a->display, a->drawable, p->fontset, p->gc, p->loc.x, p->loc.y, str, strlen(str) ); } static TV_BOOL TVANNOTStationPropUpdate( TV_ANNOT *a, struct timeval *cur_time, TV_ANNOT_PROP *p ) { TV_CAPTURE *c = &G_glob.capture; TV_DRIVER_STATE state; TV_STATION *station; char chan_str[ 80 ]; /* First, see if we even need to display */ if ( !TVANNOTUpdateIsRequired( p, cur_time ) ) return FALSE; /* Paranoid sanity check */ assert((p->gc != NULL ) && ( p->fontset != NULL )); /* Query driver state (freq or channel) */ /* FIXME: Add CAPTURE interface to just query indiv params */ if ( !TVCAPTUREQueryDriverState( c, &state ) ) { fprintf( stderr, "TVCAPTUREQueryDriverState() failed\n" ); exit(1); } /* Figure out which station we're on (if any) */ TVSTATIONLookup( &state, &station ); /* Format station text */ if ( station != NULL ) { if ( station->set_via_channel ) { sprintf( chan_str, "%d", station->channel ); if ( strcmp( station->id, chan_str ) != 0 ) { if ( App_res.station_annot_idonly ) sprintf( chan_str, "%s", station->id ); else sprintf( chan_str, "%s (%d)", station->id, station->channel ); } } else if ( App_res.station_annot_idonly ) sprintf( chan_str, "%s", station->id ); else sprintf( chan_str, "%s (%.2f MHz)", station->id, station->freq ); } else if ( state.tuner_chan_active ) sprintf( chan_str, "%ld", state.tuner_chan ); else sprintf( chan_str, "%.2f MHz", state.tuner_freq ); /* And display it */ TVANNOTDrawShadowedText( a, p, chan_str ); return TRUE; } static TV_BOOL TVANNOTTunerModePropUpdate( TV_ANNOT *a, struct timeval *cur_time, TV_ANNOT_PROP *p ) { TV_PREFS *prefs = &G_glob.prefs; char *str; /* First, see if we even need to display */ if ( !TVANNOTUpdateIsRequired( p, cur_time ) ) return FALSE; /* Paranoid sanity check */ assert((p->gc != NULL ) && ( p->fontset != NULL )); /* Format text */ switch ( prefs->tuner_mode ) { case TV_TUNER_MODE_ANTENNA : str = "ANTENNA"; break; case TV_TUNER_MODE_CABLE : str = "CABLE"; break; default : fprintf( stderr, "TVANNOTTunerModePropUpdate: Unknown mode\n" ); exit(1); } /* And display it */ TVANNOTDrawShadowedText( a, p, str ); return TRUE; } static TV_BOOL TVANNOTInputDevPropUpdate( TV_ANNOT *a, struct timeval *cur_time, TV_ANNOT_PROP *p ) { TV_CAPTURE *c = &G_glob.capture; TV_DRIVER_STATE state; char *str; /* First, see if we even need to display */ if ( !TVANNOTUpdateIsRequired( p, cur_time ) ) return FALSE; /* Paranoid sanity check */ assert((p->gc != NULL ) && ( p->fontset != NULL )); /* Query driver state (input device) */ /* FIXME: Add CAPTURE interface to just query indiv params */ if ( !TVCAPTUREQueryDriverState( c, &state ) ) { fprintf( stderr, "TVCAPTUREQueryDriverState() failed\n" ); exit(1); } /* Format text */ switch ( state.input_dev ) { case TV_DEVICE_TUNER : str = "TUNER IN" ; break; case TV_DEVICE_VIDEO : str = "VIDEO IN" ; break; case TV_DEVICE_SVIDEO : str = "SVIDEO IN" ; break; case TV_DEVICE_CSVIDEO : str = "CSVIDEO IN"; break; default : fprintf( stderr, "TVANNOTInputDevPropUpdate: Bad device\n" ); exit(1); } /* And display it */ TVANNOTDrawShadowedText( a, p, str ); return TRUE; } static TV_BOOL TVANNOTVolumePropUpdate( TV_ANNOT *a, struct timeval *cur_time, TV_ANNOT_PROP *p ) { TV_INT32 vol; char str[80]; /* First, see if we even need to display */ if ( !TVANNOTUpdateIsRequired( p, cur_time ) ) return FALSE; /* Paranoid sanity check */ assert((p->gc != NULL ) && ( p->fontset != NULL )); /* Query current line volume */ TVAUDIOGetLineVolume( &vol ); /* Format text */ sprintf( str, VOLUME_FMT, vol ); /* And display it */ TVANNOTDrawShadowedText( a, p, str ); return TRUE; } static TV_BOOL TVANNOTMutePropUpdate( TV_ANNOT *a, struct timeval *cur_time, TV_ANNOT_PROP *p ) { TV_BOOL mute_on; char *str; /* Query current mute state */ TVAUDIOGetMuteState( &mute_on ); /* See if we even need to display */ if ( !mute_on || !TVANNOTUpdateIsRequired( p, cur_time ) ) return FALSE; /* Paranoid sanity check */ assert((p->gc != NULL ) && ( p->fontset != NULL )); /* Format text */ str = mute_on ? MUTE_STR : ""; /* And display it */ TVANNOTDrawShadowedText( a, p, str ); return TRUE; } /**@BEGINFUNC************************************************************** Prototype : TV_BOOL TVANNOTUpdate( TV_ANNOT *a ) Purpose : Give annotations a chance to update. Returns TRUE if any annotations were active and thus needed to be drawn. Programmer : 05-Oct-97 Randall Hopper Parameters : a - I: annotation def Returns : T = something was drawn; F = nothing drawn Globals : None. **@ENDFUNC*****************************************************************/ TV_BOOL TVANNOTUpdate( TV_ANNOT *a ) { struct timeval tv; TV_BOOL changed = FALSE, ch[5]; /* If drawable and its size haven't been set yet, no action */ if (( a->drawable == None ) || ( a->geom.w < 0 )) return FALSE; /* Compute current time (in msec) */ gettimeofday( &tv, NULL ); /* Update all annotation properties */ ch[0] = TVANNOTStationPropUpdate ( a, &tv, &a->station ); ch[1] = TVANNOTTunerModePropUpdate( a, &tv, &a->tuner_mode ); ch[2] = TVANNOTInputDevPropUpdate ( a, &tv, &a->input_dev ); ch[3] = TVANNOTVolumePropUpdate ( a, &tv, &a->volume ); ch[4] = TVANNOTMutePropUpdate ( a, &tv, &a->mute ); changed = ch[0] || ch[1] || ch[2] || ch[3] || ch[4]; return changed; } /*---------------------------------------------------------------------------*/ static void TVANNOTUpdateTimeoutCB( XtPointer cl_data, XtIntervalId *timer ) { TV_BOOL changed; TV_ANNOT *a = (TV_ANNOT *) cl_data; a->timer_set = FALSE; /* If somebody killed auto-update mode, bail */ if ( !a->auto_update ) return; changed = TVANNOTUpdate( a ); /* If anything changed, reregister our timer */ if ( changed ) { a->timer = XtAppAddTimeOut( a->app_context, AUTOMODE_TIMER_MS, TVANNOTUpdateTimeoutCB, a ); a->timer_set = TRUE; } } /**@BEGINFUNC************************************************************** Prototype : void TVANNOTSetAutoUpdateMode( TV_ANNOT *a, TV_BOOL enabled ) Purpose : The annotation module can be set in one of two different modes: 1) AutoUpdate OFF means the client has to call TVANNOTUpdate manually to add the annotation to the registered drawable If no annotation is pending, the call is a no-op. 2) AutoUpdate ON means that this module sets a timer and periodically calls TVANNOTUpdate itself. The timer is only registered when annotation is pending. After all annotation expires, the timer is canceled. Programmer : 05-Oct-97 Randall Hopper Parameters : a - I: annotation def enabled - I: new state for auto-update mode Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void TVANNOTSetAutoUpdateMode( TV_ANNOT *a, TV_BOOL enabled ) { enabled = (enabled != 0); if ( a->auto_update == enabled ) return; a->auto_update = enabled; /* If leaving auto-update, kill timer */ if ( !a->auto_update ) { if ( a->timer_set ) { XtRemoveTimeOut( a->timer ); a->timer_set = FALSE; } } /* Else entering auto-update; start timer */ else { a->timer = XtAppAddTimeOut( a->app_context, AUTOMODE_TIMER_MS, TVANNOTUpdateTimeoutCB, a ); a->timer_set = TRUE; } } /*---------------------------------------------------------------------------*/ void TVANNOTSignalPropChange( TV_ANNOT *a, TV_ANNOT_TYPE type ) { struct timeval tv; TV_ANNOT_PROP *p; gettimeofday( &tv, NULL ); switch ( type ) { case TV_ANNOT_TYPE_STATION : p = &a->station ; break; case TV_ANNOT_TYPE_TUNER_MODE : p = &a->tuner_mode; break; case TV_ANNOT_TYPE_INPUT_DEV : p = &a->input_dev ; break; case TV_ANNOT_TYPE_VOLUME : p = &a->volume ; break; case TV_ANNOT_TYPE_MUTE : p = &a->mute ; break; default : fprintf( stderr, "TVANNOTSignalPropChange: Bad type\n" ); exit(1); } memcpy( &p->start_time, &tv, sizeof(tv) ); /* If we're in auto-update mode, start the auto-update timer */ if ( a->auto_update && !a->timer_set ) { a->timer = XtAppAddTimeOut( a->app_context, AUTOMODE_TIMER_MS, TVANNOTUpdateTimeoutCB, a ); a->timer_set = TRUE; } }