/* * actions.c * * Xt action routines for FXTV. * * (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 "tvdefines.h" #include "glob.h" #include "tvcapture.h" #include "vidsav_dlg.h" #include "tvmenu.h" #include "xutil.h" #include "tvutil.h" #include "imgsav.h" #include "imgsav_dlg.h" #include "annot.h" #include "actions.h" #include "remote.h" /* ******************** Local defines ************** */ typedef enum { TVA_KEY_KeySym, /* This one is a cheat so our list isn't huge */ TVA_KEY_Power, TVA_KEY_AllOn, TVA_KEY_PC, TVA_KEY_CD, TVA_KEY_Web, TVA_KEY_DVD, TVA_KEY_Phone, TVA_KEY_0, TVA_KEY_1, TVA_KEY_2, TVA_KEY_3, TVA_KEY_4, TVA_KEY_5, TVA_KEY_6, TVA_KEY_7, TVA_KEY_8, TVA_KEY_9, TVA_KEY_Home, TVA_KEY_Up, TVA_KEY_PgUp, TVA_KEY_Left, TVA_KEY_Right, TVA_KEY_End, TVA_KEY_Down, TVA_KEY_PgDn, TVA_KEY_Shift, TVA_KEY_Enter, TVA_KEY_VolUp, TVA_KEY_BrightUp, TVA_KEY_VolDn, TVA_KEY_BrightDn, TVA_KEY_ChanUp, TVA_KEY_On, TVA_KEY_ChanDn, TVA_KEY_Off, TVA_KEY_Mute, TVA_KEY_AllOff, TVA_KEY_AB, TVA_KEY_Disp, TVA_KEY_Play, TVA_KEY_Rew, TVA_KEY_FF, TVA_KEY_Stop, TVA_KEY_Rec, TVA_KEY_Pause, TVA_KEY_Freq, TVA_KEY_Chan, TVA_KEY_Last, TVA_KEY_NUM_KEYS } TVACTION_KEY; /* ******************** Private variables ************** */ static TV_BOOL S_chan_entry_active = FALSE; static struct { TVACTION_KEY val; char *str; } TVACTION_keys[] = { { TVA_KEY_Power, "POWER" }, { TVA_KEY_AllOn, "ALLON" }, { TVA_KEY_PC, "PC" }, { TVA_KEY_CD, "CD" }, { TVA_KEY_Web, "WEB" }, { TVA_KEY_DVD, "DVD" }, { TVA_KEY_Phone, "PHONE" }, { TVA_KEY_0, "0" }, { TVA_KEY_1, "1" }, { TVA_KEY_Home, "Home" }, { TVA_KEY_2, "2" }, { TVA_KEY_Up, "Up" }, { TVA_KEY_3, "3" }, { TVA_KEY_PgUp, "PgUp" }, { TVA_KEY_4, "4" }, { TVA_KEY_Left, "Left" }, { TVA_KEY_5, "5" }, { TVA_KEY_6, "6" }, { TVA_KEY_Right, "Right" }, { TVA_KEY_7, "7" }, { TVA_KEY_End, "End" }, { TVA_KEY_8, "8" }, { TVA_KEY_Down, "Down" }, { TVA_KEY_9, "9" }, { TVA_KEY_PgDn, "PgDn" }, { TVA_KEY_Shift, "SHIFT" }, { TVA_KEY_Enter, "ENTER" }, { TVA_KEY_VolUp, "VOLUP" }, { TVA_KEY_BrightUp, "BRIGHTUP" }, { TVA_KEY_VolDn, "VOLDN" }, { TVA_KEY_BrightDn, "BRIGHTDN" }, { TVA_KEY_ChanUp, "CHANUP" }, { TVA_KEY_On, "ON" }, { TVA_KEY_ChanDn, "CHANDN" }, { TVA_KEY_Off, "OFF" }, { TVA_KEY_Mute, "MUTE" }, { TVA_KEY_AllOff, "ALLOFF" }, { TVA_KEY_AB, "A-B" }, { TVA_KEY_Disp, "DISP" }, { TVA_KEY_Play, "PLAY" }, { TVA_KEY_Rew, "REW" }, { TVA_KEY_FF, "FF" }, { TVA_KEY_Stop, "STOP" }, { TVA_KEY_Rec, "REC" }, { TVA_KEY_Pause, "PAUSE" }, { TVA_KEY_Freq, "FREQ" }, { TVA_KEY_Chan, "CHAN" }, { TVA_KEY_Last, "LAST" } }; /* ******************** Forward declarations ************** */ /* ******************** Function Definitions ************** */ /* FIXME: Update the tvmenu stuff to call the action routines -- */ /* alot of the code came from there and is duplicated. */ /**@BEGINFUNC************************************************************** Prototype : static void TVACTIONKeyStationEntryHdlr( TVACTION_KEY key, KeySym keysym, char keysym_buf[], TV_BOOL *handled ) Purpose : Handles key events for the station entry line. Programmer : 17-May-98 Randall Hopper Parameters : key - I: key to process keysym - I: if key == TVA_KEY_KeySym, keysym to process keysym_buf - I: if key == TVA_KEY_KeySym, string rep of keysym handled - O: T = we took it Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ static void TVACTIONKeyStationEntryHdlr( TVACTION_KEY key, KeySym keysym, char keysym_buf[], TV_BOOL *handled ) { static TV_BOOL S_entry_freq; static char S_chan_str[ 80 ]; TV_BOOL do_freq, do_chan, isa_digit, isa_return; char *str, str_buf[10]; TV_INT32 digit; *handled = FALSE; /* Determine some basics about the key event */ if ( key == TVA_KEY_KeySym ) { do_freq = ( !S_chan_entry_active && ( keysym == XK_F )); do_chan = ( !S_chan_entry_active && ( keysym == XK_C )); isa_digit = ( keysym >= XK_0 ) && ( keysym <= XK_9 ); isa_return = keysym == XK_Return; digit = keysym - XK_0; } else { do_freq = ( key == TVA_KEY_Freq ); do_chan = ( key == TVA_KEY_Chan ); isa_digit = (key >= TVA_KEY_0) && (key <= TVA_KEY_9); isa_return = ( key == TVA_KEY_Enter ); digit = key - TVA_KEY_0; } /* If not in entry mode, and this key can't start entry mode, */ /* don't grab this keypress. */ if ( !S_chan_entry_active && !( isa_digit || do_freq || do_chan ) ) return; *handled = TRUE; /* Ok, deal with start of entry mode */ if ( !S_chan_entry_active ) { S_chan_entry_active = TRUE; S_entry_freq = do_freq; if ( isa_digit ) sprintf( S_chan_str, "%ld", digit ); else if ( do_freq ) strcpy( S_chan_str, "f" ); else S_chan_str[0] = '\0'; TVTOOLSSetStationText( S_chan_str ); } /* Deal with end of entry mode */ else if ( isa_return ) { TVActionSetStation( S_chan_str ); S_chan_entry_active = FALSE; S_chan_str[0] = '\0'; } /* Deal with further key-ins while in entry mode */ else if ( keysym == XK_BackSpace ) { if ( S_chan_str[0] != '\0' ) { S_chan_str[ strlen(S_chan_str)-1 ] = '\0'; TVTOOLSSetStationText( S_chan_str ); } } else if ( (( key == TVA_KEY_KeySym ) && ((( keysym >= XK_KP_Space ) && ( keysym <= XK_KP_9 )) || (( keysym >= XK_space ) && ( keysym <= XK_asciitilde )))) || isa_digit ) { /* Abort if in freq mode and user keys in a non-float char */ if ( S_entry_freq && !(isa_digit || ( keysym == XK_period ) || ( keysym == XK_KP_Decimal )) ){ XBell( TVDISPLAY, 100 ); S_chan_entry_active = FALSE; S_chan_str[0] = '\0'; TVTOOLSResync(); return; } if ( key == TVA_KEY_KeySym ) str = keysym_buf; else { str_buf[0] = '0' + digit; str_buf[1] = '\0'; str = str_buf; } strncat( S_chan_str, str, sizeof(S_chan_str)-1 ); TVTOOLSSetStationText( S_chan_str ); } /* Deal with abort of entry mode (invalid character) */ else { XBell( TVDISPLAY, 100 ); S_chan_entry_active = FALSE; S_chan_str[0] = '\0'; TVTOOLSResync(); } } /**@BEGINFUNC************************************************************** Prototype : void TVACTIONKeyEventHdlr( const char key_str[], TV_BOOL *handled ) Purpose : Generic handler for "keys". These can come from a keyboard, a mouse remote, or wherever. Programmer : 17-May-98 Randall Hopper Parameters : key_str - I: string representing a key (e.g. "0","ENTER",...) handled - O: T if we processed this key Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void TVACTIONKeyEventHdlr( const char key_str[], TV_BOOL *handled ) { TV_INT32 i; char str[20]; TVACTION_KEY key; KeySym keysym = 0; char keysym_buf[30]; XEvent xev; TV_DISPLAY *d = &G_glob.display; String action, args[10]; Cardinal num_args; Widget wgt = d->video_wgt; *handled = FALSE; keysym = 0; keysym_buf[0] = '\0'; /* Translate key to val */ str[0] = '\0'; strncat( str, key_str, sizeof(str)-1 ); TVUTILstrupr( str ); if ( strncmp( str, "KEYSYM", 6 ) == 0 ) { key = TVA_KEY_KeySym; sscanf( str+6, "%ld,%s", &keysym, keysym_buf ); } else { for ( i = 0; i < XtNumber( TVACTION_keys ); i++ ) if ( strcmp( str, TVACTION_keys[i].str ) == 0 ) break; /* If we don't know this key, ignore it */ if ( i >= XtNumber( TVACTION_keys ) ) return; key = TVACTION_keys[i].val; } /* Toss this key to the station entry line first */ TVACTIONKeyStationEntryHdlr( key, keysym, keysym_buf, handled ); if ( *handled ) return; /* Handle other events */ action = NULL; for ( i = 0; i < XtNumber( args ); i++ ) args[i] = NULL; switch ( key ) { case TVA_KEY_ChanUp : case TVA_KEY_ChanDn : action = "TVSetStation"; args[0] = ( key == TVA_KEY_ChanUp ) ? "+1" : "-1"; break; case TVA_KEY_VolUp : case TVA_KEY_VolDn : action = "TVSetVolume"; args[0] = ( key == TVA_KEY_VolUp ) ? "+1" : "-1"; break; case TVA_KEY_Mute : action = "TVToggleMute"; break; default : break; } if ( action ) { /* Set up a dummy xevent */ memset( &xev, '\0', sizeof(xev) ); xev.xany.type = ClientMessage; xev.xclient.display = TVDISPLAY; xev.xclient.window = d->win; /* Count args */ for ( i = 0; i < XtNumber( args ); i++ ) if ( args[i] == NULL ) break; num_args = i; XtCallActionProc( wgt, action, &xev, args, num_args ); } } /**@BEGINFUNC************************************************************** Prototype : void TVACTIONVideoWinEventHdlr( Widget wgt, XtPointer cl_data, XEvent *ev, Boolean *continue_dispatch ) Purpose : Event handler for our video window's widget. Used to effect station changes via user key-in of station IDs ("c"[ID]), channel numbers ("c"[num] or [num] for short), or station frequencies ("f"[freq]). Programmer : 04-Mar-97 Randall Hopper Parameters : wgt - I: video window's widget cl_data - I: ev - I: xevent received for widget window continue_dispatch - I: whether to keep propagating or not Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void TVACTIONVideoWinEventHdlr( Widget wgt, XtPointer cl_data, XEvent *ev, Boolean *continue_dispatch ) { char key_buf[20], key_str[30]; KeySym keysym; XComposeStatus compose; TV_BOOL handled; switch ( ev->type ) { case KeyPress: XLookupString( &ev->xkey, key_buf, sizeof(key_buf), &keysym, &compose ); /* Ignore modifiers */ if (( keysym >= XK_Shift_L ) && ( keysym <= XK_Hyper_R )) break; /* Collapse keysyms a bit */ if (( keysym >= XK_KP_0 ) && ( keysym <= XK_KP_9 )) keysym -= XK_KP_0 - XK_0; if (( keysym >= XK_a ) && ( keysym <= XK_z )) keysym -= XK_a - XK_A; if (( keysym == XK_KP_Enter ) || ( keysym == XK_Linefeed )) keysym = XK_Return; if ( keysym == XK_Delete ) keysym = XK_BackSpace; /* Don't pass anything but the Return/BS & printable chars */ if (( keysym != XK_Return ) && ( keysym != XK_BackSpace ) && !((( keysym >= XK_KP_Space ) && ( keysym <= XK_KP_9 )) || (( keysym >= XK_space ) && ( keysym <= XK_asciitilde )))){ S_chan_entry_active = FALSE; TVTOOLSResync(); break; } sprintf( key_str, "KEYSYM%ld,%s", keysym, key_buf ); TVACTIONKeyEventHdlr( key_str, &handled ); *continue_dispatch = !handled; break; } } /**@BEGINFUNC************************************************************** Prototype : static void TVActionSetStationAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) Purpose : Set channel action routine. Allows for setting the channel to a specific channel identified by a channel (station) identifier, or a channel (station) relative to the currently-selected channel (station) definition (-int | +int). Programmer : 12-Apr-97 Randall Hopper Parameters : wgt - I: xevent - I: params - I: 1 arg -- rel count or channel ID num_params - I: must be 1 Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ static void TVActionSetStationAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) { TV_CAPTURE *c = &G_glob.capture; TV_PREFS *p = &G_glob.prefs; TV_DISPLAY *d = &G_glob.display; TV_DRIVER_STATE s; TV_INT32 i, num_chan; TV_STATION *channel; TV_INT8 chan_inc = 0, freq_inc = 0; TV_INT32 chan_num = -1; float chan_freq; TV_BOOL valid; char *str = NULL; /* Get current channel (Query capture driver's current values) */ if ( !TVCAPTUREQueryDriverState( c, &s ) ) { fprintf( stderr, "TVCAPTUREQueryDriverState() failed\n" ); return; } /* Verify and extract argument (INT, -INT, +INT) */ valid = True; if (( *num_params != 1 ) || ( strlen( params[0] ) == 0 )) valid = False; else { str = params[0]; /* Are we incrementally changing the channel or frequency? */ if (( str[0] == '+' ) || ( str[0] == '-' )) { if ( toupper( str[1] ) == 'F' ) freq_inc = ( str[0] == '-' ? -1 : +1 ); else { chan_inc = atoi( str ); if ( chan_inc == 0 ) valid = False; } } /* No, so save the channel/freq we're leaving as the last station */ else { if ( s.tuner_chan_active ) p->last_chan = s.tuner_chan, p->last_freq = 0.0; else p->last_chan = -1 , p->last_freq = s.tuner_freq; } } if ( !valid ) { fprintf( stderr, "TVActionSetStationAction: Bad or missing channel specifier\n" "\tExpected channel identifier or channel delta (+#/-#).\n" ); return; } /* Figure out which tuner input we're dealing with */ if ( p->tuner_mode == TV_TUNER_MODE_ANTENNA ) channel = p->ant_station, num_chan = p->ant_num_stations; else if ( p->tuner_mode == TV_TUNER_MODE_CABLE ) channel = p->cable_station, num_chan = p->cable_num_stations; else { fprintf( stderr, "TVActionSetStationAction: Unsupported tuner mode\n" ); return; } /* Determine new station */ if ( chan_inc == 0 && freq_inc == 0 ) /* station ID, chan num, or freq */ { char chan_id[ 80 ]; chan_id[0] = '\0'; strncat( chan_id, str, sizeof(chan_id)-1 ); /* 1st, look for a predefined station with a matching identifier */ for ( i = 0; i < num_chan; i++ ) if ( strcasecmp( chan_id, channel[i].id ) == 0 ) { if ( channel[ i ].set_via_channel ) chan_num = channel[ i ].channel; else chan_num = -1, chan_freq = channel[ i ].freq; break; } /* 2nd, as fall back, see if its a channel number or frequency */ if ( i >= num_chan ) { if (( sscanf( str, "f%f", &chan_freq ) == 1 ) || ( sscanf( str, "F%f", &chan_freq ) == 1 )) chan_num = -1; else if (( sscanf( str, "%ld", &chan_num ) == 1 ) && ( chan_num >= TV_CHAN_MIN )) chan_freq = 0.0; else { /* Bad station string. Beep and display curr station. */ XBell( TVDISPLAY, 100 ); TVTOOLSResync(); return; } } } else if ( chan_inc != 0 ) /* chan_inc */ { /* Freq Active. Tuning is by 1/16th of a MHz */ /* First figure out which station definition we're on now */ if ( !s.tuner_chan_active ) { for ( i = 0; i < num_chan; i++ ) if ( !channel[i].set_via_channel && APPROX( channel[i].freq, s.tuner_freq, 1.1/FREQFACTOR ) ) break; if ( i >= num_chan ) i = 0; } else { for ( i = 0; i < num_chan; i++ ) if ( channel[i].set_via_channel && channel[i].channel == s.tuner_chan ) break; /* as a fall-back, find the chan with the next-higher chan #) */ if ( i >= num_chan ) { for ( i = 0; i < num_chan; i++ ) if ( channel[i].set_via_channel && channel[i].channel > s.tuner_chan ) break; if ( i >= num_chan ) i = 0; if ( chan_inc > 0 ) chan_inc--; } } /* Compute new station def relative to current */ i = (i + chan_inc + num_chan) % num_chan; if ( channel[ i ].set_via_channel ) chan_num = channel[ i ].channel; else chan_num = -1, chan_freq = channel[ i ].freq; } else /* freq_inc */ { chan_num = -1; chan_freq = s.tuner_freq + freq_inc * 1.5/FREQFACTOR; } /* Bump channel, and update GUI */ if ( chan_num >= TV_CHAN_MIN ) { if ( !s.tuner_chan_active || ( s.tuner_chan != chan_num ) ) { TVCAPTURESetTunerChannel( c, chan_num ); TVANNOTSignalPropChange( &d->annot, TV_ANNOT_TYPE_STATION ); } } else { if ( s.tuner_chan_active || !APPROX( s.tuner_freq, chan_freq, 1.1/FREQFACTOR ) ) { TVCAPTURESetTunerFreq ( c, chan_freq ); TVANNOTSignalPropChange( &d->annot, TV_ANNOT_TYPE_STATION ); } } TVTOOLSResync(); } /**@BEGINFUNC************************************************************** Prototype : static void TVActionToggleZoomAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) Purpose : Action to toggle window zoom on and off. Programmer : 12-Apr-97 Randall Hopper Parameters : wgt - I: xevent - I: params - I: [0] in { "window", "fullscreen" } num_params - I: must be 1 Returns : Globals : None. **@ENDFUNC*****************************************************************/ static void TVActionToggleZoomAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) { TV_DISPLAY *d = &G_glob.display; TV_BOOL valid, fullscreen = False; char arg[80]; /* Verify and extract argument ("window" or "fullscreen") */ valid = True; if ( *num_params != 1 ) valid = False; else { char *p = arg; arg[0] = '\0'; strncat( arg, params[0], sizeof(arg)-1 ); while ( *p != '\0' ) *(p++) = tolower( *p ); if ( strncmp( arg, "win", strlen("win") ) == 0 ) fullscreen = False; else if ( strncmp( arg, "full", strlen("full") ) == 0 ) fullscreen = True; else valid = False; } if ( !valid ) { fprintf( stderr, "TVActionToggleZoomAction: Bad or missing zoom type specifier\n" "\tExpected 'window' or 'fullscreen'.\n" ); return; } /* FIXME: Parameterize the full-screen arg */ TVSCREENSetZoomState( !d->zoom_on, fullscreen ); TVTOOLSSetToggleState( TV_TOOLITEM_FULLSCREEN, d->zoom_on ); /* This is an ugly hack. Changing the video mode can take a while, */ /* If this was initiated by a remote event, this delay messes up */ /* remote key debouncing. Just flush the buffer of any repeats. */ TVREMOTEFlush(); } /**@BEGINFUNC************************************************************** Prototype : static void TVActionSetVolumeAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) Purpose : Set volume action routine. Allows for setting the volume to an absolute volume number (int) or a volume relative to the current volume percentage (-int | +int). Programmer : 12-Apr-97 Randall Hopper Parameters : wgt - I: xevent - I: params - I: 1 arg -- rel or abs volume percentage num_params - I: must be 1 Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ static void TVActionSetVolumeAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) { TV_DISPLAY *d = &G_glob.display; TV_INT32 vol_val = -1, vol_inc = 0; TV_BOOL valid; /* Verify and extract argument (INT, -INT, +INT) */ valid = True; if (( *num_params != 1 ) || ( strlen( params[0] ) == 0 )) valid = False; else { char *str = params[0]; if (( str[0] == '+' ) || ( str[0] == '-' )) vol_inc = atoi( str ); else vol_val = atoi( str ); if (( vol_inc == 0 ) && ( vol_val < 0 )) valid = False; } if ( !valid ) { fprintf( stderr, "TVActionSetVolumeAction: Bad or missing volume specifier\n" "\tExpected volume percentage (#) or volume delta (+#/-#).\n" ); return; } /* Determine new channel number */ if ( vol_inc ) { TVAUDIOGetLineVolume( &vol_val ); vol_val += vol_inc; } vol_val = MAX( TV_VOLUME_MIN, MIN( TV_VOLUME_MAX, vol_val ) ); /* Bump volume, and update GUI */ TVAUDIOSetLineVolume( vol_val, TRUE ); TVANNOTSignalPropChange( &d->annot, TV_ANNOT_TYPE_VOLUME ); } /**@BEGINFUNC************************************************************** Prototype : static void TVActionToggleMuteAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) Purpose : Action to toggle audio mute on and off. Programmer : 12-Apr-97 Randall Hopper Parameters : wgt - I: xevent - I: params - I: num_params - I: should be 0 Returns : Globals : None. **@ENDFUNC*****************************************************************/ static void TVActionToggleMuteAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) { TV_DISPLAY *d = &G_glob.display; TV_BOOL mute_on; if ( *num_params > 0 ) { fprintf( stderr, "TVActionToggleMuteAction: Unexpected argument ignored.\n" ); } TVAUDIOGetMuteState( &mute_on ); TVAUDIOSetMuteState( !mute_on ); TVANNOTSignalPropChange( &d->annot, TV_ANNOT_TYPE_MUTE ); } /**@BEGINFUNC************************************************************** Prototype : static void TVActionSetCaptureInputAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) Purpose : Set "capture input" action routine. Allows for setting the input to a specific input, or an input relative to the current input (-int | +int). Programmer : 12-Apr-97 Randall Hopper Parameters : wgt - I: xevent - I: params - I: 1 arg -- rel num or input identifier ident in { "tuner","video","svideo" } num_params - I: must be 1 Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ static void TVActionSetCaptureInputAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) { TV_DISPLAY *d = &G_glob.display; TV_CAPTURE *c = &G_glob.capture; TV_BOOL valid, video_on; TV_INPUT_DEVICE dev = (TV_INPUT_DEVICE) -1; TV_INT32 dev_inc = 0; TV_DRIVER_STATE s; /* Verify and extract argument (tuner, video, svideo, -INT, +INT) */ valid = True; if (( *num_params != 1 ) || ( strlen( params[0] ) == 0 )) valid = False; else { char *str = params[0]; if (( str[0] == '+' ) || ( str[0] == '-' )) dev_inc = atoi( str ); else { char arg[80], *p = arg; arg[0] = '\0'; strncat( arg, str, sizeof(arg)-1 ); while ( *p != '\0' ) *(p++) = tolower( *p ); if ( strncmp( str, "tuner", strlen("tuner") ) == 0 ) dev = TV_DEVICE_TUNER; else if ( strncmp( str, "video", strlen("video") ) == 0 ) dev = TV_DEVICE_VIDEO; else if ( strncmp( str, "svideo", strlen("svideo") ) == 0 ) dev = TV_DEVICE_SVIDEO; else if ( strncmp( str, "csvideo", strlen("csvideo") ) == 0 ) dev = TV_DEVICE_CSVIDEO; else if ( strncmp( str, "dev3", strlen("dev3") ) == 0 ) dev = TV_DEVICE_DEV3; } if (( dev_inc == 0 ) && ( dev == (TV_INPUT_DEVICE) -1 )) valid = False; } if ( !valid ) { fprintf( stderr, "TVActionSetCaptureInputAction: Bad or missing capture input.\n" "\tExpected delta or 'tuner', 'video', or 'svideo'.\n" ); return; } /* Determine new capture input */ if ( !TVCAPTUREQueryDriverState( c, &s ) ) { fprintf( stderr, "TVCAPTUREQueryDriverState() failed\n" ); exit(1); } if ( dev_inc ) { dev = (s.input_dev + dev_inc + TV_NUM_INPUT_DEVICES) % TV_NUM_INPUT_DEVICES; dev = MAX( 0, MIN( TV_NUM_INPUT_DEVICES-1, dev ) ); } /* Update input device setting */ if ( dev != s.input_dev ) { video_on = d->enabled && TVSCREENVideoStarted(); if ( video_on ) TVSCREENStopVideo( False ); TVCAPTURESetInputDevice( c, dev ); TVANNOTSignalPropChange( &d->annot, TV_ANNOT_TYPE_INPUT_DEV ); if ( video_on ) TVSCREENStartVideo(); TVMENUResync(); } } /**@BEGINFUNC************************************************************** Prototype : static void TVActionSetTunerModeAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) Purpose : Set "tuner mode" action routine. Allows for setting the mode to a specific mode, or a mode relative to the current mode (-int | +int). Programmer : 12-Apr-97 Randall Hopper Parameters : wgt - I: xevent - I: params - I: 1 arg -- rel num or mode identifier ident in { "antenna","cable" } num_params - I: must be 1 Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ static void TVActionSetTunerModeAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) { TV_DISPLAY *d = &G_glob.display; TV_CAPTURE *c = &G_glob.capture; TV_PREFS *p = &G_glob.prefs; TV_BOOL valid, video_on; TV_TUNER_MODE mode = (TV_TUNER_MODE) -1; TV_INT32 mode_inc = 0; /* Verify and extract argument (antenna, cable, -INT, +INT) */ valid = True; if (( *num_params != 1 ) || ( strlen( params[0] ) == 0 )) valid = False; else { char *str = params[0]; if (( str[0] == '+' ) || ( str[0] == '-' )) mode_inc = atoi( str ); else { char arg[80], *p = arg; arg[0] = '\0'; strncat( arg, str, sizeof(arg)-1 ); while ( *p != '\0' ) *(p++) = tolower( *p ); if ( strncmp( str, "ant", strlen("ant") ) == 0 ) mode = TV_TUNER_MODE_ANTENNA; else if ( strncmp( str, "cable", strlen("cable") ) == 0 ) mode = TV_TUNER_MODE_CABLE; } if (( mode_inc == 0 ) && ( mode == (TV_TUNER_MODE) -1 )) valid = False; } if ( !valid ) { fprintf( stderr, "TVActionSetTunerModeAction: Bad or missing tuner mode.\n" "\tExpected delta or 'antenna' or 'cable'.\n" ); return; } /* Determine new tuner mode */ if ( mode_inc ) { mode = (p->tuner_mode + mode_inc + TV_NUM_TUNER_MODES) % TV_NUM_TUNER_MODES; mode = MAX( 0, MIN( TV_NUM_TUNER_MODES-1, mode ) ); } /* Update input device setting */ if ( mode != p->tuner_mode ) { video_on = d->enabled && TVSCREENVideoStarted(); if ( video_on ) TVSCREENStopVideo( False ); p->tuner_mode = mode; if ( mode == TV_TUNER_MODE_ANTENNA ) TVCAPTURESetTunerFreqSet( c, p->ant_freq_set ); else TVCAPTURESetTunerFreqSet( c, p->cable_freq_set ); TVANNOTSignalPropChange( &d->annot, TV_ANNOT_TYPE_TUNER_MODE ); if ( video_on ) TVSCREENStartVideo(); TVMENUResync(); } } /**@BEGINFUNC************************************************************** Prototype : static void TVActionSaveImageAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) Purpose : Save the last specified image in the last specified format using the last specified filename. Use a filename # suffix if that was configured. If the specified file already exists, prompt the user whether to overwrite it. If this Save action hasn't ever been invoked before, fall back to a "Save As", popping up a dialog where we prompt the user to enter a filename to save under first. This then reinvokes this Save action to do the save. Programmer : 12-Apr-97 Randall Hopper Parameters : wgt - I: xevent - I: params - I: num_params - I: must be 0 Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ static void TVActionSaveImageAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) { TV_DISK *dsk = &G_glob.disk; TV_DISPLAY *dpy = &G_glob.display; char *p, fname[ MAXPATHLEN ]; TV_INT32 len; TV_BOOL exists; struct stat sb; if ( *num_params != 0 ) { fprintf( stderr, "TVActionSaveImage: Unexpected argument(s)\n" ); return; } /* If we don't have a frozen img to save, this is pointless */ if ( dpy->image.buf == NULL ) { XUTILDialogPause( TVTOPLEVEL, "Error", "No frozen image to save.", TV_DIALOG_TYPE_OK ); return; } /* If no filename has been entered yet, we need to prompt for it */ if ( dsk->fn_freeze_base[0] == '\0' ) { TVIMGSAVDIALOGPopUp(); return; } /* Construct filename to save under */ if ( dsk->freeze_use_suffix ) { if ( (p = strrchr( dsk->fn_freeze_base, '.' )) == NULL ) len = strlen( dsk->fn_freeze_base ); else len = p - dsk->fn_freeze_base; sprintf( fname, "%.*s%.3ld%s", (int)len, dsk->fn_freeze_base, dsk->freeze_next_suffix, (p ? p : "") ); } else strcpy( fname, dsk->fn_freeze_base ); /* See if the file exists; if so, we need to verify user wants */ /* to overwrite. */ exists = TRUE; if ( stat( fname, &sb ) < 0 ) { if ( errno != ENOENT ) { fprintf( stderr, "Whoah! stat() failed on '%s'.\n", fname ); XBell( TVDISPLAY, 100 ); return; } exists = FALSE; } if ( exists ) { char msg[160]; /* FIXME: I18N me and all other DialogPause refs */ sprintf( msg, "This file exists (%s).\nOverwrite?", fname ); if ( XUTILDialogPause( TVTOPLEVEL, "Confirm", msg, TV_DIALOG_TYPE_YES_NO ) != TV_DIALOG_YES ) return; } /* Ok, we've got a filename. Do the save */ TVIMGSAVDoSave( fname, dsk->freeze_fmt, &dpy->image ); /* Finally, bump the image number for next time */ if ( dsk->freeze_use_suffix ) dsk->freeze_next_suffix++; } /**@BEGINFUNC************************************************************** Prototype : static void TVActionToggleFreezeAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) Purpose : Action to toggle the freeze state on and off. Programmer : 12-Apr-97 Randall Hopper Parameters : wgt - I: xevent - I: params - I: num_params - I: should be 0 Returns : Globals : None. **@ENDFUNC*****************************************************************/ static void TVActionToggleFreezeAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) { TV_DISPLAY *d = &G_glob.display; if ( *num_params > 0 ) { fprintf( stderr, "TVActionToggleFreezeAction: Unexpected argument ignored.\n" ); } TVSCREENToggleFreezeState(); TVTOOLSSetToggleState( TV_TOOLITEM_FREEZE, d->freeze_on ); } /**@BEGINFUNC************************************************************** Prototype : static void TVActionQuitAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) Purpose : Action to toggle the freeze state on and off. Programmer : 12-Apr-97 Randall Hopper Parameters : wgt - I: xevent - I: params - I: num_params - I: should be 0 Returns : Globals : None. **@ENDFUNC*****************************************************************/ static void TVActionQuitAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) { if ( *num_params > 0 ) { fprintf( stderr, "TVActionQuitAction: Unexpected argument ignored.\n" ); } exit(0); } /**@BEGINFUNC************************************************************** Prototype : static void TVActionVideoRecordStartAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) Purpose : Action to start recording video using the default video capture parameters. Programmer : 12-Apr-97 Randall Hopper Parameters : wgt - I: xevent - I: params - I: num_params - I: should be 0 Returns : Globals : None. **@ENDFUNC*****************************************************************/ static void TVActionVideoRecordStartAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) { TV_INT32 w,h; if (( *num_params > 1 )) { fprintf( stderr, "TVActionVideoRecordStartAction: Unexpected argument ignored.\n" ); } if (( *num_params == 1 ) && params[0] ) { if (( sscanf( params[0], "%ldx%ld", &w, &h ) != 2 ) || ( w <= 0 ) || ( h <= 0 )) { fprintf( stderr, "TVActionVideoRecordStartAction: Bad resolution.\n" ); return; } } else w = h = 0; TVVIDSAVDIALOGRecordStart( w,h ); } /**@BEGINFUNC************************************************************** Prototype : static void TVActionVideoRecordStopAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) Purpose : Action to stop recording video. Programmer : 12-Apr-97 Randall Hopper Parameters : wgt - I: xevent - I: params - I: num_params - I: should be 0 Returns : Globals : None. **@ENDFUNC*****************************************************************/ static void TVActionVideoRecordStopAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) { if ( *num_params > 0 ) { fprintf( stderr, "TVActionVideoRecordStopAction: Unexpected argument ignored.\n" ); } TVVIDSAVDIALOGRecordStop(); } static void TVActionNoOp( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) { /* * This one doesn't deserve a header. It's a no-op action routine. */ } /**@BEGINFUNC************************************************************** Prototype : void TVActionSetStation( char chan_id[] ) Prototype : void TVActionSetStationRel( TV_INT8 chan_delta ) Prototype : void TVActionSetVolume( TV_INT32 vol ) Prototype : void TVActionSetVolumeRel( TV_INT32 vol_delta ) Prototype : void TVActionSetCaptureInput( TV_INPUT_DEVICE dev ) Prototype : void TVActionSetCaptureInputRel( TV_INT32 dev_delta ) Purpose : Convenience wrappers for accessing action routine functionality. Programmer : 12-Apr-97 Randall Hopper Parameters : chan_id - I: channel identifier chan_delta - I: channel offset from current chan vol - I: volume percentage vol_delta - I: volume percentage offset from current vol dev - I: capture input device dev_delta - I: device identifier delta Returns : None. Globals : None. **@ENDFUNC*****************************************************************/ void TVActionSetStation( char chan_id[] ) { String param[1] = { chan_id }; Cardinal num_param = 1; TVActionSetStationAction( NULL, NULL, param, &num_param ); } void TVActionSetStationRel( TV_INT8 chan_delta ) { char str[80]; String param[1] = { str }; Cardinal num_param = 1; sprintf( str, "%+d", chan_delta ); TVActionSetStationAction( NULL, NULL, param, &num_param ); } void TVActionSetVolume( TV_INT32 vol ) { char str[80]; String param[1] = { str }; Cardinal num_param = 1; sprintf( str, "%ld", vol ); TVActionSetVolumeAction( NULL, NULL, param, &num_param ); } void TVActionSetVolumeRel( TV_INT32 vol_delta ) { char str[80]; String param[1] = { str }; Cardinal num_param = 1; sprintf( str, "%+ld", vol_delta ); TVActionSetVolumeAction( NULL, NULL, param, &num_param ); } void TVActionSetCaptureInput( TV_INPUT_DEVICE dev ) { char str[80]; String param[1] = { str }; Cardinal num_param = 1; switch ( dev ) { case TV_DEVICE_TUNER : strcpy( str, "tuner" ); break; case TV_DEVICE_VIDEO : strcpy( str, "video" ); break; case TV_DEVICE_SVIDEO : strcpy( str, "svideo" ); break; case TV_DEVICE_CSVIDEO : strcpy( str, "csvideo" ); break; case TV_DEVICE_DEV3 : strcpy( str, "dev3" ); break; default : fprintf( stderr, "TVActionSetCaptureInput: Bad arg %d\n", dev ); exit(1); } TVActionSetCaptureInputAction( NULL, NULL, param, &num_param ); } void TVActionSetCaptureInputRel( TV_INT32 dev_delta ) { char str[80]; String param[1] = { str }; Cardinal num_param = 1; sprintf( str, "%+ld", dev_delta ); TVActionSetCaptureInputAction( NULL, NULL, param, &num_param ); } void TVActionSaveImage( void ) { Cardinal num_param = 0; TVActionSaveImageAction( NULL, NULL, NULL, &num_param ); } void TVActionToggleFreeze( void ) { Cardinal num_param = 0; TVActionToggleFreezeAction( NULL, NULL, NULL, &num_param ); } void TVActionQuit( void ) { Cardinal num_param = 0; TVActionQuitAction( NULL, NULL, NULL, &num_param ); } /**@BEGINFUNC************************************************************** Prototype : static void TVActionFlipStationAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) Purpose : Flip to previously selected station. Programmer : 14-Mar-2000 Steve Reid Parameters : wgt - I: xevent - I: params - I: num_params - I: should be 0 Returns : Globals : None. **@ENDFUNC*****************************************************************/ static void TVActionFlipStationAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) { TV_PREFS *p = &G_glob.prefs; char chan_str[ 80 ]; if ( *num_params > 0 ) { fprintf( stderr, "TVActionFlipStationAction: Unexpected argument ignored.\n" ); } if ( p->last_chan >= TV_CHAN_MIN ) sprintf( chan_str, "%ld" , p->last_chan ); else sprintf( chan_str, "f%f", p->last_freq ); TVActionSetStation( chan_str ); } /**@BEGINFUNC************************************************************** Prototype : void TVActionAddAppActions() Purpose : Add TV action routines to the app context. Programmer : 12-Apr-97 Randall Hopper Parameters : None. Returns : None. Globals : TVAPPCTX **@ENDFUNC*****************************************************************/ void TVActionAddAppActions() { static XtActionsRec S_actions[] = {{ "TVSetStation" , TVActionSetStationAction }, { "TVToggleZoom" , TVActionToggleZoomAction }, { "TVSetVolume" , TVActionSetVolumeAction }, { "TVToggleMute" , TVActionToggleMuteAction }, { "TVSetCaptureInput" , TVActionSetCaptureInputAction }, { "TVSetTunerMode" , TVActionSetTunerModeAction }, { "TVSaveImage" , TVActionSaveImageAction }, { "TVToggleFreeze" , TVActionToggleFreezeAction }, { "TVVideoRecordStart" , TVActionVideoRecordStartAction }, { "TVVideoRecordStop" , TVActionVideoRecordStopAction }, { "TVFlipStation" , TVActionFlipStationAction }, { "TVQuit" , TVActionQuitAction }, { "no-op" , TVActionNoOp } }; XtAppAddActions( TVAPPCTX, (XtActionsRec *) S_actions, XtNumber( S_actions ) ); }