/* * tvmenu.c * * API to build and maintain the app menubar. * * (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 #include #include "tvdefines.h" #include "tvtypes.h" #include "tvscreen.h" #include "xutil.h" #include "glob.h" #include "actions.h" #include "tvmenu.h" #include "imgsav_dlg.h" #include "appear_dlg.h" #include "audsav_dlg.h" #include "vidsav_dlg.h" /* ******************** Local defines ************** */ #define TOOLBOX_WGTNAME "toolBox" #define PIX_FNAME_SELECT "radio_on.xbm" #define PIX_FNAME_UNSELECT "radio_off.xbm" typedef enum { TV_MENU_FILE = 0, TV_MENU_INPUT, TV_MENU_FORMAT, TV_MENU_OPTIONS, TV_MENU_HELP, TV_NUM_MENUS } TV_MENU_KEY; typedef struct { TV_MENU_KEY menu; char *btn_wgt_name; Widget btn_wgt; Widget shell_wgt; } TV_MENU_DEF; typedef struct { TV_MENU_KEY menu; TV_MENUITEM_KEY item; char *wgt_name; WidgetClass *wgt_class; XtCallbackProc cb; Widget wgt; } TV_MENUITEM_DEF; typedef struct { TV_TOOLITEM_KEY item; char *wgt_name; WidgetClass *wgt_class; XtCallbackProc cb; Widget wgt; } TV_TOOLITEM_DEF; typedef void XT_CB( Widget w, XtPointer client_data, XtPointer cb_data ); /* ******************** Forward declarations ************** */ static XT_CB QuitCB, FreezeCB, MuteCB, ZoomCB, InputCB, AfcCB, TModeCB, ChanUpDnCB, AppearCB, AspectCB, AboutCB, ImgSavCB, ImgSavAsCB, AudSavAsCB, VidSavAsCB, FormatCB, AudInpCB, StationPopupCB; /* ******************** Private variables ************** */ #define WC_mcmd &smeBSBObjectClass #define WC_mline &smeLineObjectClass #define WC_mspace &smeObjectClass #define WC_cmd &commandWidgetClass #define WC_toggle &toggleWidgetClass #define WC_simple &simpleWidgetClass #define WC_text &asciiTextWidgetClass static TV_MENU_DEF Menu_def[] = { { TV_MENU_FILE , "fileMenu" }, { TV_MENU_INPUT , "inputMenu" }, { TV_MENU_FORMAT , "formatMenu" }, { TV_MENU_OPTIONS, "optionsMenu" }, { TV_MENU_HELP , "helpMenu" } }; #define TVMI(x,y) TV_MENU_##x, TV_MENUITEM_##y static TV_MENUITEM_DEF Menuitem_def[] = { { TVMI( FILE,FILE_IMGSAVE ), "imgSavCmd" , WC_mcmd , ImgSavCB }, { TVMI( FILE,FILE_IMGSAVEAS ), "imgSavAsCmd" , WC_mcmd , ImgSavAsCB}, { TVMI( FILE,FILE_AUDSAVEAS ), "audSavAsCmd" , WC_mcmd , AudSavAsCB}, { TVMI( FILE,FILE_VIDSAVEAS ), "vidSavAsCmd" , WC_mcmd , VidSavAsCB}, /* { TVMI( FILE,FILE_PRINT ), "printCmd" , WC_mcmd , NULL }, { TVMI( FILE,FILE_PRINTSETUP ), "printSetupCmd" , WC_mcmd , NULL }, */ { TV_MENU_FILE, -1 , "line" , WC_mline, NULL }, { TVMI( FILE,FILE_QUIT ), "quitCmd" , WC_mcmd , QuitCB }, { TVMI( INPUT,INPUT_TUNER ), "tunerCmd" , WC_mcmd , InputCB }, { TVMI( INPUT,INPUT_VIDEO ), "videoCmd" , WC_mcmd , InputCB }, { TVMI( INPUT,INPUT_SVIDEO ), "svideoCmd" , WC_mcmd , InputCB }, { TVMI( INPUT,INPUT_CSVIDEO ), "csvideoCmd" , WC_mcmd , InputCB }, { TVMI( INPUT,INPUT_DEV3 ), "dev3Cmd" , WC_mcmd , InputCB }, { TV_MENU_INPUT, -1 , "line" , WC_mline, NULL }, { TVMI( INPUT,TMODE_ANTENNA ), "tmodeAntenna" , WC_mcmd , TModeCB }, { TVMI( INPUT,TMODE_CABLE ), "tmodeCable" , WC_mcmd , TModeCB }, { TV_MENU_INPUT, -1 , "line" , WC_mline, NULL }, { TVMI( INPUT,AUDINP_AUTO ), "audInpAuto" , WC_mcmd , AudInpCB }, { TVMI( INPUT,AUDINP_INTERN ), "audInpIntern" , WC_mcmd , AudInpCB }, { TV_MENU_INPUT, -1 , "line" , WC_mline, NULL }, { TVMI( INPUT,INPUT_APPEARANCE ), "appearanceCmd" , WC_mcmd , AppearCB }, { TVMI( FORMAT,FORMAT_NTSCM ), "ntscmFmt" , WC_mcmd , FormatCB }, { TVMI( FORMAT,FORMAT_NTSCJ ), "ntscjFmt" , WC_mcmd , FormatCB }, { TVMI( FORMAT,FORMAT_PALBDGHI ), "palbdghiFmt" , WC_mcmd , FormatCB }, { TVMI( FORMAT,FORMAT_PALM ), "palmFmt" , WC_mcmd , FormatCB }, { TVMI( FORMAT,FORMAT_PALN ), "palnFmt" , WC_mcmd , FormatCB }, { TVMI( FORMAT,FORMAT_SECAM ), "secamFmt" , WC_mcmd , FormatCB }, { TVMI( FORMAT,FORMAT_PALNCOMB ), "palncombFmt" , WC_mcmd , FormatCB }, { TVMI( OPTIONS,OPTIONS_ASPECT ), "aspectLockCmd" , WC_mcmd , AspectCB }, { TVMI( OPTIONS,OPTIONS_AFC ), "setAfcCmd", WC_mcmd , AfcCB }, { TV_MENU_OPTIONS, -1 , "line" , WC_mline, NULL }, /* { TVMI( OPTIONS,OPTIONS_SAVE ), "saveOptionsCmd", WC_mcmd , NULL }, */ { TVMI( HELP,HELP_ABOUT ), "aboutCmd" , WC_mcmd , AboutCB } /* Use smeObjectClass for blank lines */ /* Use smeLineObjectClass for separators */ }; static TV_TOOLITEM_DEF Toolitem_def[] = { { TV_TOOLITEM_FREEZE , "freezeToggle" , WC_toggle, FreezeCB }, { TV_TOOLITEM_FULLSCREEN, "fullScreenCmd", WC_toggle, ZoomCB }, { -1 , "spacer" , WC_simple, NULL }, { TV_TOOLITEM_CHANDOWN , "channelDnCmd" , WC_cmd , ChanUpDnCB }, { TV_TOOLITEM_CHANTEXT , "channelText" , WC_text , NULL }, { TV_TOOLITEM_CHANUP , "channelUpCmd" , WC_cmd , ChanUpDnCB }, { -1 , "spacer" , WC_simple, NULL }, { TV_TOOLITEM_MUTE , "muteToggle" , WC_toggle, MuteCB }, }; static Widget Volume_scrollbar = NULL; static Pixmap Select_pixmap = None, Unselect_pixmap = None; static struct { TV_MENUITEM_KEY key; TV_INPUT_FORMAT fmt; } S_input_fmt_menu[] = { { TV_MENUITEM_FORMAT_NTSCM, TV_INPUT_NTSCM }, { TV_MENUITEM_FORMAT_NTSCJ, TV_INPUT_NTSCJ }, { TV_MENUITEM_FORMAT_PALBDGHI, TV_INPUT_PALBDGHI }, { TV_MENUITEM_FORMAT_PALM, TV_INPUT_PALM }, { TV_MENUITEM_FORMAT_PALN, TV_INPUT_PALN }, { TV_MENUITEM_FORMAT_SECAM, TV_INPUT_SECAM }, { TV_MENUITEM_FORMAT_PALNCOMB, TV_INPUT_PALNCOMB }, { -1, -1 } }; #define CHANTEXT_ACCEPT_ACTION "tv-channel-accept" /* These would be more logical, but Xaw dumps core after you enter a few two digit channels. Thus the above. Probably some missing cleanup associated with killing the selection. : select-all()\n\ : select-start() select-end()\n\ : kill-selection() insert-char()\ */ static char Chan_text_transl[] = "\ : select-all() beginning-of-line()\n\ : select-start() select-end() "CHANTEXT_ACCEPT_ACTION"()\n\ Return: select-all() beginning-of-line() "CHANTEXT_ACCEPT_ACTION"()\n\ KP_Enter: select-all() beginning-of-line() "CHANTEXT_ACCEPT_ACTION"()\n\ Linefeed: select-all() beginning-of-line() "CHANTEXT_ACCEPT_ACTION"()\n\ CtrlJ: select-all() beginning-of-line() "CHANTEXT_ACCEPT_ACTION"()\n\ CtrlM: select-all() beginning-of-line() "CHANTEXT_ACCEPT_ACTION"()\n\ : XawPositionSimpleMenu(stationpopup) MenuPopup(stationpopup)\n\ Delete: delete-previous-character() \n\ BackSpace: delete-previous-character() \n\ : kill-to-end-of-line() insert-char()\ "; static void ChanTextAcceptAction( Widget, XEvent *, String *, Cardinal *); static XtActionsRec Tool_actions[1] = { { CHANTEXT_ACCEPT_ACTION, ChanTextAcceptAction } }; /* ******************** Function Definitions ************** */ static void TVMENULoadRadioPixmaps( void ) { /* Load select/unselect pixmaps if we haven't already */ if ( Select_pixmap == None ) { if ( !XUTILBitmapLoad( PIX_FNAME_SELECT, TVTOPLEVEL, &Select_pixmap ) ) { fprintf( stderr, "Can't load '%s' pixmap\n", PIX_FNAME_SELECT ); exit(1); } if ( !XUTILBitmapLoad( PIX_FNAME_UNSELECT, TVTOPLEVEL, &Unselect_pixmap ) ) { fprintf( stderr, "Can't load '%s' pixmap\n", PIX_FNAME_UNSELECT ); exit(1); } } } static TV_MENUITEM_DEF *LookupMenuItemByKey( TV_MENUITEM_KEY key ) { TV_INT32 i; for ( i = 0; i < XtNumber( Menuitem_def ); i++ ) if ( Menuitem_def[i].item == key ) break; if ( i >= XtNumber( Menuitem_def ) ) return NULL; return &Menuitem_def[i]; } static TV_TOOLITEM_DEF *LookupToolItemByKey( TV_TOOLITEM_KEY key ) { TV_INT32 i; for ( i = 0; i < XtNumber( Toolitem_def ); i++ ) if ( Toolitem_def[i].item == key ) break; if ( i >= XtNumber( Toolitem_def ) ) return NULL; return &Toolitem_def[i]; } /* FreezeCB - Freeze/Restart the video window */ static void FreezeCB( Widget w, XtPointer cl, XtPointer cb ) { Boolean freeze; XtVaGetValues( w, XtNstate, &freeze, NULL ); EVPRINTF(( "Freeze video = %s\n", freeze ? "yes" : "no" )); TVSCREENSetFreezeState( freeze ); } /* ZoomCB - Zoom/Unzoom the video window */ static void ZoomCB( Widget w, XtPointer cl, XtPointer cb ) { Boolean zoom_on; XtVaGetValues( w, XtNstate, &zoom_on, NULL ); EVPRINTF(( "Zoom video = %s\n", zoom_on ? "yes" : "no" )); TVSCREENSetZoomState( zoom_on, False ); } /* InputCB - Change the capture input to that selected */ static void InputCB( Widget w, XtPointer cl, XtPointer cb ) { TV_DISPLAY *d = &G_glob.display; TV_CAPTURE *c = &G_glob.capture; TV_MENUITEM_DEF *tuner = LookupMenuItemByKey( TV_MENUITEM_INPUT_TUNER ); TV_MENUITEM_DEF *video = LookupMenuItemByKey( TV_MENUITEM_INPUT_VIDEO ); TV_MENUITEM_DEF *svideo = LookupMenuItemByKey( TV_MENUITEM_INPUT_SVIDEO ); TV_MENUITEM_DEF *csvideo= LookupMenuItemByKey( TV_MENUITEM_INPUT_CSVIDEO ); TV_MENUITEM_DEF *dev3 = LookupMenuItemByKey( TV_MENUITEM_INPUT_DEV3 ); TV_BOOL on; TV_INPUT_DEVICE dev; assert(( tuner != NULL ) && ( video != NULL ) && ( svideo != NULL ) && ( csvideo != NULL ) && ( dev3 != NULL )); if ( w == tuner->wgt ) dev = TV_DEVICE_TUNER; else if ( w == video->wgt ) dev = TV_DEVICE_VIDEO; else if ( w == svideo->wgt ) dev = TV_DEVICE_SVIDEO; else if ( w == csvideo->wgt ) dev = TV_DEVICE_CSVIDEO; else if ( w == dev3->wgt ) dev = TV_DEVICE_DEV3; else { fprintf( stderr, "Unknown input device widget: %s\n", XtName( w ) ); return; } on = d->enabled && TVSCREENVideoStarted(); /* Update input device setting */ if ( on ) TVSCREENStopVideo( False ); TVCAPTURESetInputDevice( c, dev ); TVANNOTSignalPropChange( &d->annot, TV_ANNOT_TYPE_INPUT_DEV ); if ( on ) TVSCREENStartVideo(); /* Update which menu item is selected */ TVMENUSetSelectedInputDevice( dev ); } /* FormatCB - Change the input format to that selected */ static void FormatCB( Widget w, XtPointer cl, XtPointer cb ) { TV_DISPLAY *d = &G_glob.display; TV_CAPTURE *c = &G_glob.capture; TV_BOOL on; TV_INPUT_FORMAT fmt; TV_INT32 i; fmt = -1; for ( i = 0 ; S_input_fmt_menu[i].key != -1 ; ++i ) if ( w == LookupMenuItemByKey( S_input_fmt_menu[i].key )->wgt ) { fmt = S_input_fmt_menu[i].fmt; break; } if ( fmt == -1 ) { fprintf( stderr, "Unknown input format widget: %s\n", XtName( w ) ); return; } on = d->enabled && TVSCREENVideoStarted(); /* Update input device setting */ if ( on ) TVSCREENStopVideo( False ); TVCAPTURESetInputFormat( c, fmt ); if ( on ) TVSCREENStartVideo(); /* Update which menu item is selected */ TVMENUSetSelectedInputFormat( fmt ); } /* AfcCB - Change the AFC mode */ static void AfcCB( Widget w, XtPointer cl, XtPointer cb ) { TV_PREFS *p = &G_glob.prefs; TV_CAPTURE *c = &G_glob.capture; p->afc_mode = !p->afc_mode; TVCAPTURESetAfc( c, p->afc_mode); TVMENUSetSelectedAfcMode( p->afc_mode ); } void TVMENUSetSelectedInputFormat( TV_INPUT_FORMAT fmt ) { TV_MENUITEM_DEF *mi; Pixmap pix; TV_INT32 i; if ( Select_pixmap == None ) TVMENULoadRadioPixmaps(); for ( i = 0 ; S_input_fmt_menu[i].key != -1 ; ++i ) { mi = LookupMenuItemByKey( S_input_fmt_menu[i].key ); assert( mi != NULL ); assert( mi->wgt != NULL ); pix = ( fmt == S_input_fmt_menu[i].fmt ) ? Select_pixmap : Unselect_pixmap; XtVaSetValues( mi->wgt, XtNleftBitmap, pix, NULL); } } /* TModeCB - Change the selected tuner channel mode */ static void TModeCB( Widget w, XtPointer cl, XtPointer cb ) { TV_DISPLAY *d = &G_glob.display; TV_CAPTURE *c = &G_glob.capture; TV_PREFS *p = &G_glob.prefs; TV_MENUITEM_DEF *ant = LookupMenuItemByKey( TV_MENUITEM_TMODE_ANTENNA ); TV_MENUITEM_DEF *cable = LookupMenuItemByKey( TV_MENUITEM_TMODE_CABLE ); TV_BOOL on; TV_FREQ_SET freq_set; assert(( ant != NULL ) && ( cable != NULL )); if ( w == ant->wgt ) p->tuner_mode = TV_TUNER_MODE_ANTENNA, freq_set = p->ant_freq_set; else if ( w == cable->wgt ) p->tuner_mode = TV_TUNER_MODE_CABLE, freq_set = p->cable_freq_set; else { fprintf( stderr, "Unknown tuner mode widget: %s\n", XtName( w ) ); return; } on = d->enabled && TVSCREENVideoStarted(); /* Update input device setting */ if ( on ) TVSCREENStopVideo( False ); TVCAPTURESetTunerFreqSet( c, freq_set ); TVANNOTSignalPropChange( &d->annot, TV_ANNOT_TYPE_TUNER_MODE ); if ( on ) TVSCREENStartVideo(); /* Update which menu item is selected */ TVMENUSetSelectedTunerMode( p->tuner_mode ); } /* AudInpCB - User has changed the audio input source (auto or intern) */ static void AudInpCB( Widget w, XtPointer cl, XtPointer cb ) { TV_DISPLAY *d = &G_glob.display; TV_CAPTURE *c = &G_glob.capture; TV_MENUITEM_DEF *autoc = LookupMenuItemByKey( TV_MENUITEM_AUDINP_AUTO ); TV_MENUITEM_DEF *intern = LookupMenuItemByKey( TV_MENUITEM_AUDINP_INTERN ); TV_INPUT_DEVICE dev; TV_BOOL on; assert(( autoc != NULL ) && ( intern != NULL )); if ( w == autoc->wgt ) dev = TV_AUDIO_INPUT_AUTO; else if ( w == intern->wgt ) dev = TV_AUDIO_INPUT_INTERN; else { fprintf( stderr, "Unknown audio device widget: %s\n", XtName( w ) ); return; } on = d->enabled && TVSCREENVideoStarted(); /* Update audio input device setting */ if ( on ) TVSCREENStopVideo( False ); TVCAPTURESetAudioInputDevice( c, dev ); if ( on ) TVSCREENStartVideo(); /* Update which menu item is selected */ TVMENUSetSelectedAudioInputDevice( dev ); } /* MuteCB - Mute/Unmute the audio */ static void MuteCB( Widget w, XtPointer cl, XtPointer cb ) { TV_DISPLAY *d = &G_glob.display; Boolean audio_on; XtVaGetValues( w, XtNstate, &audio_on, NULL ); EVPRINTF(( "Mute audio = %s\n", !audio_on ? "yes" : "no" )); TVAUDIOSetMuteState( !audio_on ); TVANNOTSignalPropChange( &d->annot, TV_ANNOT_TYPE_MUTE ); } /* ChanUpDnCB - Change the channel up/down by one */ static void ChanUpDnCB( Widget w, XtPointer cl, XtPointer cb ) { TV_TOOLITEM_DEF *chanup = LookupToolItemByKey( TV_TOOLITEM_CHANUP ); int inc; assert( chanup != NULL ); inc = (w == chanup->wgt) ? 1 : -1; /* Determine next channel number */ TVActionSetStationRel( inc ); } /* ChanTextAcceptAction - Action rtn to accept new Text widget chan num */ static void ChanTextAcceptAction( Widget wgt, XEvent *xevent, String *params, Cardinal *num_params ) { char *chan_str; XtVaGetValues( wgt, XtNstring, &chan_str, NULL ); if ( chan_str == NULL ) chan_str = ""; TVActionSetStation( chan_str ); } /* StationPopupCB - Callback invoked when a station in our station menu */ /* popup is invoked. */ static void StationPopupCB( Widget w, XtPointer cl, XtPointer cb ) { String new_station; XtVaGetValues(w, XtNlabel, &new_station, NULL); TVActionSetStation(new_station); } /* TVTOOLSUpdateStationPopup - Reset the selected station on the */ /* station pop-up menu */ static void TVTOOLSUpdateStationPopup() { Widget popup_win, new_popup_item = NULL; Cardinal num_children, i; WidgetList children; String actual_station = NULL, temp_station = NULL; #ifdef FIXME Pixmap pix; #endif TV_TOOLITEM_DEF *chantext = LookupToolItemByKey( TV_TOOLITEM_CHANTEXT ); /* FIXME: Popup geometry negotiation doesn't seem to work when */ /* we specify a left bitmap -- stomps on text. Possibly */ /* some other geometry manager tweak needed here. */ popup_win = XtNameToWidget(chantext->wgt, "stationpopup"); if(popup_win == NULL) return; XtVaGetValues(chantext->wgt, XtNstring, &actual_station, NULL); assert(actual_station); XtVaGetValues(popup_win, XtNnumChildren, &num_children, XtNchildren, &children, NULL); for( i = 0; i < num_children; i++) { XtVaGetValues(children[i], XtNlabel, &temp_station, NULL); assert(temp_station); #ifdef FIXME if ( strcmp( actual_station, temp_station ) != 0 ) pix = Unselect_pixmap; else { pix = Select_pixmap; new_popup_item = children[i]; } XtVaSetValues(children[i], XtNleftBitmap, pix, NULL); #else if ( strcmp( actual_station==NULL ? "" : actual_station, temp_station==NULL ? "" : temp_station ) == 0 ) new_popup_item = children[i]; #endif } XtVaSetValues(popup_win, XtNpopupOnEntry, new_popup_item, NULL); } /* TVTOOLSCreateStationPopup - Pop up a simple menu with all of our */ /* configured stations. */ void TVTOOLSCreateStationPopup() { TV_PREFS *p = &G_glob.prefs; TV_INT32 i, num_chan; TV_STATION *station; Widget menu_shell, item; String actual_chan; #ifdef FIXME Pixmap pix; #endif TV_TOOLITEM_DEF *chantext = LookupToolItemByKey( TV_TOOLITEM_CHANTEXT ); /* Figure out which tuner input we're dealing with */ if ( p->tuner_mode == TV_TUNER_MODE_ANTENNA ) { station = p->ant_station, num_chan = p->ant_num_stations; } else if ( p->tuner_mode == TV_TUNER_MODE_CABLE ) { station = p->cable_station, num_chan = p->cable_num_stations; } else { fprintf( stderr, "TVTOOLSCreateStationPopup: Unsupported tuner mode\n" ); return; } XtVaGetValues(chantext->wgt, XtNstring, &actual_chan, NULL); /* Create the menu and set item callbacks */ menu_shell = XtVaCreatePopupShell( "stationpopup", simpleMenuWidgetClass, chantext->wgt, NULL ); for ( i = 0; i < num_chan; i++ ) { /* FIXME: Popup geometry negotiation doesn't seem to work when */ /* we specify a left bitmap -- stomps on text. Possibly */ /* some other geometry manager tweak needed here. */ #ifdef FIXME if ( strcmp(actual_chan, station[i].id) != 0 ) pix = Unselect_pixmap; else pix = Select_pixmap; item = XtVaCreateManagedWidget( station[i].id, *WC_mcmd, menu_shell, XtNleftBitmap, pix, NULL ); #else item = XtVaCreateManagedWidget( station[i].id, *WC_mcmd, menu_shell, NULL ); #endif XtAddCallback( item, XtNcallback, StationPopupCB, NULL ); } } /* AppearCB - Bring up the capture appearance parameters dialog */ static void AppearCB( Widget w, XtPointer cl, XtPointer cb ) { TVAPPEARDIALOGPopUp(); } /* AspectCB - Turn on aspect lock (4:3 ratio) */ static void AspectCB( Widget w, XtPointer cl, XtPointer cb ) { TV_BOOL aspect_lock; TVSCREENGetAspectLock( &aspect_lock ); aspect_lock = !aspect_lock; EVPRINTF(( "Aspect lock = %s\n", aspect_lock ? "yes" : "no" )); TVSCREENSetAspectLock( aspect_lock ); TVMENUSetSelectedAspectLock( aspect_lock ); } /* AboutCB - Display information about Fxtv */ static void AboutCB( Widget w, XtPointer cl, XtPointer cb ) { XUTILDialogPause( TVTOPLEVEL, "About", "BSD X TV\n" "Version " VERS_STR "\n\n" "Written by Randall Hopper, 1997-2001.", TV_DIALOG_TYPE_OK ); } /* ImgSavCB - Do save without prompting, if we can */ static void ImgSavCB( Widget w, XtPointer cl, XtPointer cb ) { TVActionSaveImage(); } /* ImgSavAsCB - Bring up the image save parameters dialog */ static void ImgSavAsCB( Widget w, XtPointer cl, XtPointer cb ) { TVIMGSAVDIALOGPopUp(); } /* AudSaveAsCB - Bring up the audio save control dialog */ static void AudSavAsCB( Widget w, XtPointer cl, XtPointer cb ) { TVAUDSAVDIALOGPopUp(); } /* VidSaveAsCB - Bring up the video save control dialog */ static void VidSavAsCB( Widget w, XtPointer cl, XtPointer cb ) { TVVIDSAVDIALOGPopUp(); } /* QuitCB - Exit the app (invoking atexit behavior) */ static void QuitCB( Widget w, XtPointer cl, XtPointer cb ) { exit(0); } Widget TVMENUCreate( Widget parent ) { Widget box, menu_btn, menu_shell, item; TV_INT32 i, j; box = XtVaCreateManagedWidget( "menuBox", boxWidgetClass, parent, XtNorientation, XtorientHorizontal, NULL ); /* Create all the menus, one by one */ for ( i = 0; i < XtNumber( Menu_def ); i++ ) { menu_btn = XtVaCreateManagedWidget( Menu_def[i].btn_wgt_name, menuButtonWidgetClass, box, NULL ); Menu_def[i].btn_wgt = menu_btn; menu_shell = XtVaCreatePopupShell( "menu", simpleMenuWidgetClass, menu_btn, NULL ); Menu_def[i].shell_wgt = menu_shell; /* Create all items for this menu */ for ( j = 0; j < XtNumber( Menuitem_def ); j++ ) if ( Menuitem_def[j].menu == Menu_def[i].menu ) { item = XtVaCreateManagedWidget( Menuitem_def[j].wgt_name, *Menuitem_def[j].wgt_class, menu_shell, NULL ); Menuitem_def[j].wgt = item; if ( Menuitem_def[j].cb ) XtAddCallback( item, XtNcallback, Menuitem_def[j].cb, NULL ); else XtSetSensitive( item, False ); } } return box; } static void TVTOOLSVolSliderJumpCB( Widget w, XtPointer cl_data, XtPointer cb_data ) { TV_DISPLAY *d = &G_glob.display; TV_INT32 vol; Dimension min_thumb, length; float pos; XtVaGetValues( w, XtNminimumThumb, &min_thumb, XtNlength , &length, NULL ); pos = *(float *)cb_data + ((float)min_thumb / length); vol = MAX( 0, MIN( 100, pos * 100 ) ); TVAUDIOSetLineVolume( vol, False ); TVANNOTSignalPropChange( &d->annot, TV_ANNOT_TYPE_VOLUME ); } Widget TVTOOLSCreate( Widget parent ) { Widget box, form, item; TV_INT32 i; Display *display = XtDisplay(parent); XrmDatabase db = XtScreenDatabase( DefaultScreenOfDisplay(display) ); XrmValue value; char str_name[ 128 ], *str_type[ 20 ], rsrc_val[ MAXPATHLEN ]; Pixel fg_color, bg_color; Pixmap pixmap; TV_TOOLITEM_DEF *chantext = LookupToolItemByKey( TV_TOOLITEM_CHANTEXT ); XtTranslations transl; box = XtVaCreateManagedWidget( TOOLBOX_WGTNAME, boxWidgetClass, parent, XtNorientation, XtorientHorizontal, NULL ); /* Create all the tools, one by one */ for ( i = 0; i < XtNumber( Toolitem_def ); i++ ) { item = XtVaCreateManagedWidget( Toolitem_def[i].wgt_name, *Toolitem_def[i].wgt_class, box, NULL ); Toolitem_def[i].wgt = item; if ( Toolitem_def[i].cb ) XtAddCallback( item, XtNcallback, Toolitem_def[i].cb, NULL ); else if ( Toolitem_def[i].wgt_class == WC_mcmd ) XtSetSensitive( item, False ); /* Set ascii text resources */ if ( XtIsSubclass( item, asciiTextWidgetClass ) ) { XtVaSetValues( item, XtNtype , XawAsciiString, XtNuseStringInPlace, False, XtNscrollHorizontal, XawtextScrollNever, XtNscrollVertical , XawtextScrollNever, XtNdisplayCaret , False, XtNeditType , XawtextEdit, XtNresize , XawtextResizeNever, NULL ); transl = XtParseTranslationTable( G_transl_ovr_ascii_text ); XtOverrideTranslations( item, transl ); transl = XtParseTranslationTable( G_transl_ovr_ascii_text_1line ); XtOverrideTranslations( item, transl ); } /* Load the bitmap manually to support pixmaps. */ /* NOTE: resource name is "pixmap" to avoid conflict with */ /* width resource name ("bitmap"). */ else if ( XtIsSubclass( item, labelWidgetClass ) ) { sprintf( str_name, "*%s*%s.pixmap", TOOLBOX_WGTNAME, Toolitem_def[i].wgt_name ); if ( !XrmGetResource( db, str_name, NULL, str_type, &value ) ) fprintf( stderr, "Tool %s's pixmap rsrc not found...skipping\n", Toolitem_def[i].wgt_name ); else { rsrc_val[0] = '\0'; strncat ( rsrc_val, value.addr, MIN( value.size, sizeof(rsrc_val)-1 ) ); XtVaGetValues( item, XtNbackground, &bg_color, NULL ); fg_color = BlackPixelOfScreen( XtScreen( parent ) ); if ( !XUTILPixmapLoad( rsrc_val, item, fg_color, bg_color, &pixmap, NULL ) ) fprintf( stderr, "Failed to load Tool %s's pixmap (%s)...skipping\n", Toolitem_def[i].wgt_name, rsrc_val ); else XtVaSetValues( item, XtNbitmap, pixmap, NULL ); } } } /* Tool action routines */ XtAppAddActions( TVAPPCTX, Tool_actions, XtNumber( Tool_actions ) ); /* More override translations for channel text widget */ transl = XtParseTranslationTable( Chan_text_transl ); XtOverrideTranslations( chantext->wgt, transl ); /* Create the volume control */ form = XtVaCreateManagedWidget( "volumeForm", formWidgetClass, box, XtNborderWidth, 0, NULL ); item = XtVaCreateManagedWidget( "volumeScrollbar", scrollbarWidgetClass, form, XtNorientation, XtorientHorizontal, NULL ); XtAddCallback( item, XtNjumpProc, TVTOOLSVolSliderJumpCB, NULL ); Volume_scrollbar = item; return box; } void TVTOOLSSetToggleState( TV_TOOLITEM_KEY key, TV_BOOL state ) { TV_INT32 i; Boolean old_state; for ( i = 0; i < XtNumber( Toolitem_def ); i++ ) if ( Toolitem_def[i].item == key ) break; if ( i >= XtNumber( Toolitem_def ) ) { fprintf( stderr, "TVTOOLSETSetToggleState: Bad key %ld\n", i ); exit(1); } XtVaGetValues( Toolitem_def[i].wgt, XtNstate, &old_state, NULL ); if ( state != old_state ) XtVaSetValues( Toolitem_def[i].wgt, XtNstate, state, NULL ); } Widget TVTOOLSGetVolumeScrollbar( void ) { return Volume_scrollbar; } void TVMENUSetSelectedInputDevice( TV_INPUT_DEVICE dev ) { TV_MENUITEM_DEF *tuner = LookupMenuItemByKey( TV_MENUITEM_INPUT_TUNER ); TV_MENUITEM_DEF *video = LookupMenuItemByKey( TV_MENUITEM_INPUT_VIDEO ); TV_MENUITEM_DEF *svideo = LookupMenuItemByKey( TV_MENUITEM_INPUT_SVIDEO); TV_MENUITEM_DEF *csvideo= LookupMenuItemByKey( TV_MENUITEM_INPUT_CSVIDEO); TV_MENUITEM_DEF *dev3 = LookupMenuItemByKey( TV_MENUITEM_INPUT_DEV3); Pixmap pix; assert(( tuner != NULL ) && ( video != NULL ) && ( svideo != NULL ) && ( csvideo != NULL ) && ( dev3 != NULL )); assert(( tuner->wgt != NULL ) && (video->wgt != NULL ) && ( svideo->wgt != NULL) && ( csvideo->wgt != NULL) && ( dev3->wgt != NULL)); if ( Select_pixmap == None ) TVMENULoadRadioPixmaps(); pix = ( dev == TV_DEVICE_TUNER ) ? Select_pixmap : Unselect_pixmap; XtVaSetValues( tuner->wgt, XtNleftBitmap, pix, NULL); pix = ( dev == TV_DEVICE_VIDEO ) ? Select_pixmap : Unselect_pixmap; XtVaSetValues( video->wgt, XtNleftBitmap, pix, NULL ); pix = ( dev == TV_DEVICE_SVIDEO ) ? Select_pixmap : Unselect_pixmap; XtVaSetValues( svideo->wgt , XtNleftBitmap, pix, NULL ); pix = ( dev == TV_DEVICE_CSVIDEO ) ? Select_pixmap : Unselect_pixmap; XtVaSetValues( csvideo->wgt , XtNleftBitmap, pix, NULL ); pix = ( dev == TV_DEVICE_DEV3 ) ? Select_pixmap : Unselect_pixmap; XtVaSetValues( dev3->wgt , XtNleftBitmap, pix, NULL ); } void TVMENUSetSelectedAudioInputDevice( TV_AUDIO_INPUT_DEVICE dev ) { TV_MENUITEM_DEF *autoc = LookupMenuItemByKey( TV_MENUITEM_AUDINP_AUTO ); TV_MENUITEM_DEF *intern = LookupMenuItemByKey( TV_MENUITEM_AUDINP_INTERN ); Pixmap pix; assert(( autoc != NULL ) && ( intern != NULL )); assert(( autoc->wgt != NULL ) && (intern->wgt != NULL )); if ( Select_pixmap == None ) TVMENULoadRadioPixmaps(); pix = ( dev == TV_AUDIO_INPUT_AUTO ) ? Select_pixmap : Unselect_pixmap; XtVaSetValues( autoc->wgt, XtNleftBitmap, pix, NULL); pix = ( dev == TV_AUDIO_INPUT_INTERN ) ? Select_pixmap : Unselect_pixmap; XtVaSetValues( intern->wgt, XtNleftBitmap, pix, NULL ); } void TVMENUSetSelectedTunerMode( TV_TUNER_MODE mode ) { TV_MENUITEM_DEF *ant = LookupMenuItemByKey( TV_MENUITEM_TMODE_ANTENNA ); TV_MENUITEM_DEF *cable = LookupMenuItemByKey( TV_MENUITEM_TMODE_CABLE ); Pixmap pix; assert(( ant != NULL ) && ( cable != NULL )); assert(( ant->wgt != NULL ) && (cable->wgt != NULL )); if ( Select_pixmap == None ) TVMENULoadRadioPixmaps(); pix = ( mode == TV_TUNER_MODE_ANTENNA ) ? Select_pixmap : Unselect_pixmap; XtVaSetValues( ant->wgt , XtNleftBitmap, pix, NULL); pix = ( mode == TV_TUNER_MODE_CABLE ) ? Select_pixmap : Unselect_pixmap; XtVaSetValues( cable->wgt, XtNleftBitmap, pix, NULL ); } void TVMENUSetSelectedAfcMode( TV_BOOL afc ) { TV_MENUITEM_DEF *item = LookupMenuItemByKey( TV_MENUITEM_OPTIONS_AFC ); Pixmap pix; if ( Select_pixmap == None ) TVMENULoadRadioPixmaps(); pix = afc ? Select_pixmap : Unselect_pixmap; XtVaSetValues( item->wgt , XtNleftBitmap, pix, NULL); } void TVMENUSetSelectedAspectLock( TV_BOOL aspect_lock ) { TV_MENUITEM_DEF *item = LookupMenuItemByKey( TV_MENUITEM_OPTIONS_ASPECT ); Pixmap pix; if ( Select_pixmap == None ) TVMENULoadRadioPixmaps(); pix = aspect_lock ? Select_pixmap : Unselect_pixmap; XtVaSetValues( item->wgt , XtNleftBitmap, pix, NULL); } void TVMENUResync() { TV_CAPTURE *c = &G_glob.capture; TV_DRIVER_STATE s; TV_PREFS *p = &G_glob.prefs; TV_AUDIO_INPUT_DEVICE aud_input; /* Query capture driver's current values */ if ( !TVCAPTUREQueryDriverState( c, &s ) ) { fprintf( stderr, "TVCAPTUREQueryDriverState() failed\n" ); exit(1); } if ( s.audio_input_dev == TV_AUDIO_INPUT_INTERN ) aud_input = TV_AUDIO_INPUT_INTERN; else aud_input = TV_AUDIO_INPUT_AUTO; TVMENUSetSelectedInputDevice ( s.input_dev ); TVMENUSetSelectedAudioInputDevice( aud_input ); TVMENUSetSelectedTunerMode ( p->tuner_mode ); TVMENUSetSelectedAfcMode ( p->afc_mode ); } /* TVTOOLSSetStationText - Sets the channel text to the specified */ /* Also updates window title/icon, if enabled. */ void TVTOOLSSetStationText( char str[] ) { static char *orig_title = NULL; char *new_title; XawTextBlock tblk; TV_TOOLITEM_DEF *chantext = LookupToolItemByKey( TV_TOOLITEM_CHANTEXT ); char *old_str; int old_len; assert(( chantext != NULL ) && ( chantext->wgt != NULL )); memset( &tblk, '\0', sizeof( tblk ) ); tblk.firstPos = 0; tblk.length = strlen( str ); tblk.ptr = str; tblk.format = XawFmt8Bit; XtVaGetValues( chantext->wgt, XtNstring, &old_str, NULL ); old_len = (old_str == NULL) ? 0 : strlen( old_str ); XawTextReplace( chantext->wgt, 0, old_len, &tblk ); /* Set a new window title and/or icon, if enabled */ if ( App_res.station_in_win_title ) { if ( orig_title == NULL ) { /* doing it for the first time */ char *c_tmp; XtVaGetValues( TVTOPLEVEL, XtNtitle, &c_tmp, NULL ); orig_title = strdup( c_tmp ); if ( !orig_title ) TVUTILOutOfMemory(); } new_title = malloc( strlen(orig_title) + strlen(str) + 11 ); if ( !new_title ) TVUTILOutOfMemory(); sprintf( new_title, "%s *** %s ***", orig_title, str ); XtVaSetValues( TVTOPLEVEL, XtNtitle, new_title, NULL ); free ( new_title ); } if ( App_res.station_in_win_icon ) XtVaSetValues( TVTOPLEVEL, XtNiconName, str, NULL ); } void TVTOOLSResync() { static int Station_menu_created = 0; TV_DISPLAY *d = &G_glob.display; TV_CAPTURE *c = &G_glob.capture; TV_DRIVER_STATE s; TV_TOOLITEM_DEF *chantext = LookupToolItemByKey( TV_TOOLITEM_CHANTEXT ); TV_TOOLITEM_DEF *chanup = LookupToolItemByKey( TV_TOOLITEM_CHANUP ); TV_TOOLITEM_DEF *chandn = LookupToolItemByKey( TV_TOOLITEM_CHANDOWN ); char chan_str[ 80 ]; Boolean sensitive; TV_STATION *station; TV_INT32 line_vol_old, line_vol_new; assert(( chantext != NULL ) && ( chantext->wgt != NULL ) && ( chanup != NULL ) && ( chanup->wgt != NULL ) && ( chandn != NULL ) && ( chandn->wgt != NULL )); /* Query capture driver's current values */ if ( !TVCAPTUREQueryDriverState( c, &s ) ) { fprintf( stderr, "TVCAPTUREQueryDriverState() failed\n" ); exit(1); } /* Query soundcard's current values */ TVAUDIOGetLineVolume( &line_vol_old ); TVAUDIOResync( TRUE ); TVAUDIOGetLineVolume( &line_vol_new ); if ( line_vol_old != line_vol_new ) TVANNOTSignalPropChange( &d->annot, TV_ANNOT_TYPE_VOLUME ); /* Figure out which station we're on (if any) */ TVSTATIONLookup( &s, &station ); /* Update channel (station) text. Plop a station ID in if applicable. */ /* If not, display channel number or frequency. */ if ( station != NULL ) { chan_str[0] = '\0'; strncat( chan_str, station->id, sizeof(chan_str)-1 ); } else if ( s.tuner_chan_active ) sprintf( chan_str, "%ld", s.tuner_chan ); else sprintf( chan_str, "f%.2f", s.tuner_freq ); TVTOOLSSetStationText( chan_str ); /* Update channel widget sensitivity based on selected input device */ sensitive = (s.input_dev == TV_DEVICE_TUNER); XtSetSensitive( chantext->wgt, sensitive ); XtSetSensitive( chanup->wgt , sensitive ); XtSetSensitive( chandn->wgt , sensitive ); /* Create the channel popup we'll use later */ if ( !Station_menu_created ) { TVTOOLSCreateStationPopup(); Station_menu_created = 1; } TVTOOLSUpdateStationPopup(); }