#include #include #include #include #include #include "../include/Y2/Y.h" #include "../include/Y2/Ylib.h" #include "../include/disk.h" #include "../include/string.h" #include "guiutils.h" #include "cdialog.h" #include "fb.h" #include "pdialog.h" #include "pstepper.h" #include "yc.h" #include "config.h" void YCSignalCB(int s); void YCPSPageChangeCB( gpointer ps_ptr, gint prev_page, gint new_page, gpointer data ); void YCPSExitCB(gpointer ps_ptr, gint cur_page, gpointer data); void YCPSFinishCB(gpointer ps_ptr, gint cur_page, gpointer data); gint YCWidgetExposeCB( GtkWidget *widget, GdkEventExpose *event, gpointer data ); void YCBrowseConfigurationFileCB(GtkWidget *widget, gpointer data); void YCBrowseYIFFProgramCB(GtkWidget *widget, gpointer data); void YCBrowseDSPDeviceCB(GtkWidget *widget, gpointer data); void YCBrowseMixerDeviceCB(GtkWidget *widget, gpointer data); gint YCYModesListMenuMapCB( GtkWidget *widget, GdkEvent *event, gpointer data ); void YCYModesListSelectCB( GtkWidget *widget, gint row, gint column, GdkEventButton *event, gpointer data ); void YCYModesListButtonCB(GtkWidget *widget, gpointer data); void YCCycleCalculateCB(GtkWidget *widget, gpointer data); void YCCycleSpinChangeCB(GtkWidget *widget, gpointer data); void YCYModeValuesApplyToYCB(GtkWidget *widget, gpointer data); void YCYModePlayCB(GtkWidget *widget, gpointer data); void YCRefreshIntSpinChangeCB(GtkWidget *widget, gpointer data); void YCBrowseMIDIPlayCmdCB(GtkWidget *widget, gpointer data); gint YCYSoundPathsMenuMapCB( GtkWidget *widget, GdkEvent *event, gpointer data ); void YCYSoundPathsListSelectCB( GtkWidget *widget, gint row, gint column, GdkEventButton *event, gpointer data ); static char *YCYSoundPathsPromptBrowseCB( gpointer prompt, gpointer client_data, int value_num ); void YCYSoundPathsListButtonCB(GtkWidget *widget, gpointer data); void YCConfermationListSelectCB( GtkWidget *widget, gint row, gint column, GdkEventButton *event, gpointer data ); void YCConfermVerboseToggleCB(GtkWidget *widget, gpointer data); void YCBrowseStartScriptCB(GtkWidget *widget, gpointer data); /* * Signal handler. */ void YCSignalCB(int s) { static int segfault_count = 0; switch(s) { case SIGSEGV: segfault_count++; fprintf( stderr, "%s triggered a segmentation fault (%i times)\n", PROG_NAME, segfault_count ); if(segfault_count >= 3) { fprintf( stderr, "%s attempting immediate process exit().\n", PROG_NAME ); exit(1); } case SIGINT: case SIGTERM: gtk_main_quit(); break; case SIGPIPE: fprintf( stderr, "Broken pipe.\n" ); gtk_main_quit(); break; } return; } /* * Page stepper page change callback. */ void YCPSPageChangeCB( gpointer ps_ptr, gint prev_page, gint new_page, gpointer data ) { static gboolean reenterant = FALSE; pstepper_struct *ps = (pstepper_struct *)ps_ptr; yc_struct *yc = (yc_struct *)data; if((ps == NULL) || (yc == NULL)) return; if(reenterant) return; else reenterant = TRUE; YCPageChange(yc, prev_page, new_page); reenterant = FALSE; return; } /* * Page stepper exit callback. */ void YCPSExitCB(gpointer ps_ptr, gint cur_page, gpointer data) { static gboolean reenterant = FALSE; pstepper_struct *ps = (pstepper_struct *)ps_ptr; yc_struct *yc = (yc_struct *)data; if((ps == NULL) || (yc == NULL)) return; if(reenterant) return; else reenterant = TRUE; /* Check for changes? */ if(yc->has_changes) { gint response; CDialogSetTransientFor(yc->toplevel); response = CDialogGetResponse( "Discard changes?", "Changes have not been saved, are you sure you\n\ want to discard those changes?", "There are changes made to the configuration which\n\ have not been saved. If you say 'Yes' then any\n\ changes you have made will be lost. If you want\n\ to preserve those changes then say 'No' and\n\ continue on with the configuration.", CDIALOG_ICON_WARNING, CDIALOG_BTNFLAG_YES | CDIALOG_BTNFLAG_NO | CDIALOG_BTNFLAG_HELP, CDIALOG_BTNFLAG_NO ); CDialogSetTransientFor(NULL); switch(response) { case CDIALOG_RESPONSE_NO: case CDIALOG_RESPONSE_NOT_AVAILABLE: /* Response was do not exit, so just return */ reenterant = FALSE; return; break; } } /* Unmap the page stepper, the YCManage() timeout function will * check and detect this then call gtk_main_quit() */ PStepperUnmap(ps); reenterant = FALSE; } /* * Page stepper finish callback. */ void YCPSFinishCB(gpointer ps_ptr, gint cur_page, gpointer data) { static gboolean reenterant = FALSE; gchar *configuration_file, *buf, *start_script_file; gint status; GtkWidget *w; pstepper_struct *ps = (pstepper_struct *)ps_ptr; yc_struct *yc = (yc_struct *)data; if((ps == NULL) || (yc == NULL)) return; if(reenterant) return; else reenterant = TRUE; /* Do finish procedure here, Unmap below only if completly * successful */ /* Save configuration file */ /* Get configuration file path */ w = yc->yiff_configuration_file_entry; if(w == NULL) configuration_file = NULL; else configuration_file = gtk_entry_get_text(GTK_ENTRY(w)); /* Make a duplicate configuration_file */ if(configuration_file != NULL) configuration_file = strdup(configuration_file); /* Save configuration to file */ status = YCSaveConfiguration(yc, configuration_file); /* Was save successful? */ if(status != 0) { switch(status) { case -1: /* Invalid input values */ CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Internal error!", "Invalid input values to YCSaveConfiguration().", NULL, CDIALOG_ICON_ERROR, CDIALOG_BTNFLAG_OK, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); break; case -2: /* Invalid values in configuration */ CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Invalid configuration value!", "There are one or more invalid configuration\n\ parameter values that could not be saved.", "One or more configuration parameter value\n\ is either invalid or out of bounds. Please\n\ go 'Back' and review the configuration\n\ values you have set.", CDIALOG_ICON_ERROR, CDIALOG_BTNFLAG_OK, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); break; case -3: /* Permission denied */ buf = g_strdup_printf( "Unable to open configuration file for writing:\n\ \n\ %s\n", configuration_file ); CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Permission denied!", buf, "The specified location for the YIFF Sound Server\n\ configuration file could not be opened for writing.\n\ This is probably due to the permissions set on the\n\ location which do not allow this program to write\n\ there. You may need to run this program with a higher\n\ permission uid (use \"su\").", CDIALOG_ICON_ERROR, CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); free(buf); break; } /* Free duplicated configuration file name */ g_free(configuration_file); configuration_file = NULL; reenterant = FALSE; return; } else { /* Free duplicated configuration file name */ g_free(configuration_file); configuration_file = NULL; } /* ****************************************************** */ /* Write YIFF start script if requested */ /* Get start script file path */ w = yc->start_script_entry; if(w == NULL) start_script_file = NULL; else start_script_file = gtk_entry_get_text(GTK_ENTRY(w)); /* Make a duplicate start_script_file */ if(start_script_file != NULL) start_script_file = g_strdup(start_script_file); /* Check if start script is specified (not NULL and not * an empty string) */ if((start_script_file != NULL) ? (*start_script_file != '\0') : FALSE ) { /* Double check if start script already exists and * query overwrite */ struct stat stat_buf; status = CDIALOG_RESPONSE_YES; if(!stat(start_script_file, &stat_buf)) { /* Start script already exists, query overwrite */ buf = g_strdup_printf( "Overwrite existing YIFF Start Script:\n\ \n\ %s\n", start_script_file ); CDialogSetTransientFor(yc->toplevel); status = CDialogGetResponse( "Confirm Overwrite", buf, "You are being asked if you want to overwrite\n\ the existing file specified above. If you\n\ overwrite this file then its previous contents\n\ will be permanently deleted.", CDIALOG_ICON_WARNING, CDIALOG_BTNFLAG_YES | CDIALOG_BTNFLAG_NO | CDIALOG_BTNFLAG_HELP, CDIALOG_BTNFLAG_NO ); CDialogSetTransientFor(NULL); g_free(buf); } /* Okay to write Y start script? */ switch(status) { case CDIALOG_RESPONSE_YES: case CDIALOG_RESPONSE_YES_TO_ALL: case CDIALOG_RESPONSE_OK: /* Write Y start script */ YCSaveStartScript(yc, start_script_file); break; } } /* Free coppied start_script_file */ g_free(start_script_file); start_script_file = NULL; /* ****************************************************** */ /* Y server still running? If so then query for shutdown */ if(yc->recorder != NULL) { CDialogSetTransientFor(yc->toplevel); status = CDialogGetResponse( "Shutdown Y server?", "For the changes to take affect the Y server\n\ needs to be shutdown and then restarted (to restart\n\ run \"yiff \" or the \"starty\"\n\ script).\n\ \n\ Any Y client programs currently connected to\n\ the Y server will be disconnected. Are you sure\n\ you want to shutdown the Y server?", NULL, CDIALOG_ICON_QUESTION, CDIALOG_BTNFLAG_YES | CDIALOG_BTNFLAG_NO, CDIALOG_BTNFLAG_YES ); CDialogSetTransientFor(NULL); switch(status) { case CDIALOG_RESPONSE_YES: case CDIALOG_RESPONSE_YES_TO_ALL: case CDIALOG_RESPONSE_OK: YShutdownServer(yc->recorder); yc->recorder = NULL; break; } } /* Notify about configuration finished! */ CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Configuration complete!", "The YIFF Sound Server has been configured!\n\ \n\ To get the most out of the YIFF Sound Server's\n\ powerful features, read the documentation\n\ available online at:\n\ \n\ http://www.battlefieldlinux.com/wolfpack/YIFF", NULL, CDIALOG_ICON_INFO, CDIALOG_BTNFLAG_OK, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); /* Unmap the page stepper, the YCManage() timeout function will * check and detect this then call gtk_main_quit() */ PStepperUnmap(ps); reenterant = FALSE; } /* * General widget expose event callback. */ gint YCWidgetExposeCB( GtkWidget *widget, GdkEventExpose *event, gpointer data ) { if((widget == NULL) || (event == NULL)) return(FALSE); gtk_widget_queue_draw(widget); return(TRUE); } /* * Browse YIFF Sound Server configuration file path callback. */ void YCBrowseConfigurationFileCB(GtkWidget *widget, gpointer data) { GtkEntry *entry; char **path; int total_paths; yc_struct *yc = (yc_struct *)data; if(yc == NULL) return; entry = (GtkEntry *)yc->yiff_configuration_file_entry; if(entry == NULL) return; if(FileBrowserGetResponse( "Select YIFF Configuration File", "Select", "Cancel", YC_DEF_CONFIG_FILE_DIR, yc->ftype, yc->total_ftypes, /* File extension types */ &path, &total_paths, NULL /* Type return */ )) { char *path_ptr = ((total_paths > 0) ? path[0] : NULL); if(path_ptr != NULL) { path_ptr = strdup(path_ptr); gtk_entry_set_text(entry, path_ptr); free(path_ptr); } } } /* * Browse YIFF Sound Server program path callback. */ void YCBrowseYIFFProgramCB(GtkWidget *widget, gpointer data) { GtkEntry *entry; char **path; int total_paths; yc_struct *yc = (yc_struct *)data; if(yc == NULL) return; entry = (GtkEntry *)yc->yiff_program_entry; if(entry == NULL) return; if(FileBrowserGetResponse( "Select YIFF Program File", "Select", "Cancel", YC_DEF_YIFF_PROGRAM_DIR, yc->ftype, yc->total_ftypes, /* File extension types */ &path, &total_paths, NULL /* Type return */ )) { char *path_ptr = ((total_paths > 0) ? path[0] : NULL); if(path_ptr != NULL) { path_ptr = strdup(path_ptr); gtk_entry_set_text(entry, path_ptr); free(path_ptr); } } } /* * Browse DSP device path callback. */ void YCBrowseDSPDeviceCB(GtkWidget *widget, gpointer data) { GtkEntry *entry; char **path; int total_paths; yc_struct *yc = (yc_struct *)data; if(yc == NULL) return; entry = (GtkEntry *)yc->dsp_device_entry; if(entry == NULL) return; if(FileBrowserGetResponse( "Select DSP Device", "Select", "Cancel", YC_DEF_DSP_DEVICE_DIR, /* Initial path */ yc->ftype, yc->total_ftypes, /* File extension types */ &path, &total_paths, NULL /* Type return */ )) { char *path_ptr = ((total_paths > 0) ? path[0] : NULL); if(path_ptr != NULL) { path_ptr = strdup(path_ptr); gtk_entry_set_text(entry, path_ptr); free(path_ptr); } } } /* * Browse mixer device path callback. */ void YCBrowseMixerDeviceCB(GtkWidget *widget, gpointer data) { GtkEntry *entry; char **path; int total_paths; yc_struct *yc = (yc_struct *)data; if(yc == NULL) return; entry = (GtkEntry *)yc->mixer_device_entry; if(entry == NULL) return; if(FileBrowserGetResponse( "Select Mixer Device", "Select", "Cancel", YC_DEF_MIXER_DEVICE_DIR, /* Initial path */ yc->ftype, yc->total_ftypes, /* File extension types */ &path, &total_paths, NULL /* Type return */ )) { char *path_ptr = ((total_paths > 0) ? path[0] : NULL); if(path_ptr != NULL) { path_ptr = strdup(path_ptr); gtk_entry_set_text(entry, path_ptr); free(path_ptr); } } } /* * Maps the YModes clist menu. */ gint YCYModesListMenuMapCB( GtkWidget *widget, GdkEvent *event, gpointer data ) { GtkWidget *w; GdkEventButton *button = (GdkEventButton *)event; yc_struct *yc = (yc_struct *)data; if((widget == NULL) || (event == NULL) || (yc == NULL)) return(FALSE); /* YModes clist? */ if(widget == yc->ymodes_clist) { w = yc->ymodes_menu; if((button != NULL) && (w != NULL)) { if(button->button == 3) { gtk_menu_popup( GTK_MENU(w), NULL, NULL, NULL, NULL, button->button, button->time ); return(TRUE); } } } return(FALSE); } /* * YModes clist select callback. */ void YCYModesListSelectCB( GtkWidget *widget, gint row, gint column, GdkEventButton *event, gpointer data ) { gint prev_row, new_row; yc_ymode_data_struct *ymode_data_ptr; GtkCList *clist; yc_struct *yc = (yc_struct *)data; if((widget == NULL) || (yc == NULL)) return; /* YModes clist? */ if(widget == yc->ymodes_clist) { prev_row = yc->selected_ymode; new_row = row; yc->selected_ymode = row; clist = (GtkCList *)widget; /* Update values currently in YMode widgets to the * Y Audio Mode data on the previously selected row. */ if((prev_row >= 0) && (prev_row < clist->rows)) { ymode_data_ptr = gtk_clist_get_row_data( clist, prev_row ); YCYModeFetchFromWidgets(yc, ymode_data_ptr); } /* Update YMode widgets to have the value of the Y Audio * Mode values on the newly selected row. */ if((new_row >= 0) && (new_row < clist->rows)) { ymode_data_ptr = gtk_clist_get_row_data( clist, new_row ); YCYModeSetToWidgets(yc, ymode_data_ptr); } /* Scroll if row not completely visable */ if(gtk_clist_row_is_visible(GTK_CLIST(widget), row) != GTK_VISIBILITY_FULL ) gtk_clist_moveto( GTK_CLIST(widget), row, 0, /* Row, column */ 0.5, 0.0 /* Row, column */ ); } return; } /* * Y Audio Modes list add/edit/remove button (and menu) * callbacks. */ void YCYModesListButtonCB(GtkWidget *widget, gpointer data) { gchar **strv, *name; gint strc, selected_row; GtkCList *clist; yc_struct *yc = (yc_struct *)data; if((widget == NULL) || (yc == NULL)) return; clist = (GtkCList *)yc->ymodes_clist; if(clist == NULL) return; selected_row = yc->selected_ymode; /* Add? */ if((widget == yc->ymode_add_btn) || (widget == yc->ymodes_menu_add) ) { PDialogDeleteAllPrompts(); PDialogAddPrompt(NULL, "Name:", NULL); strv = PDialogGetResponse( "Add Preset Y Audio Mode", NULL, NULL, PDIALOG_ICON_QUESTION, "Add", "Cancel", PDIALOG_BTNFLAG_SUBMIT | PDIALOG_BTNFLAG_CANCEL, PDIALOG_BTNFLAG_SUBMIT, &strc ); name = ((strc > 0) ? strv[0] : NULL); if(name != NULL) { /* Add new yaudio mode */ gint i; gchar *strptr, *text[1]; /* Check new name */ if(*name == '\0') { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Y Audio Mode name empty!", "You must specify a non-empty name string for\n\ the new Y Audio Mode name.", NULL, CDIALOG_ICON_ERROR, CDIALOG_BTNFLAG_OK, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); return; } if(strchr(name, ' ')) { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Y Audio Mode name invalid!", "Y Audio Mode names may not contain spaces.", NULL, CDIALOG_ICON_ERROR, CDIALOG_BTNFLAG_OK, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); return; } /* Name conflict? */ for(i = 0; i < clist->rows; i++) { gtk_clist_get_text(clist, i, 0, &strptr); if(strptr == NULL) continue; if(!g_strcasecmp(strptr, name)) { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Y Audio Mode name conflict!", "Another Y Audio Mode with the same name already exists,\n\ please pick a different name.", NULL, CDIALOG_ICON_ERROR, CDIALOG_BTNFLAG_OK, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); return; } } /* Make a copy of the name */ name = g_strdup(name); text[0] = name; if((selected_row >= 0) && (selected_row < clist->rows)) { /* Insert */ selected_row = gtk_clist_insert( clist, selected_row, text ); } else { /* Append */ gtk_clist_append(clist, text); selected_row = clist->rows - 1; } /* Create YMode data if row was successfully added */ if((selected_row >= 0) && (selected_row < clist->rows)) { yc_ymode_data_struct *yc_data_ptr = YCYModeDataStructNew(); if(yc_data_ptr != NULL) { free(yc_data_ptr->name); yc_data_ptr->name = ((name == NULL) ? NULL : strdup(name) ); yc_data_ptr->sample_rate = 8000; yc_data_ptr->channels = 1; yc_data_ptr->sample_size = 8; yc_data_ptr->fragment_size_bytes = 256; yc_data_ptr->direction = 0; yc_data_ptr->allow_fragmenting = TRUE; yc_data_ptr->num_fragments = 2; /* Default to 2 */ yc_data_ptr->cycle_us = YCalculateCycle( yc->recorder, yc_data_ptr->sample_rate, yc_data_ptr->channels, yc_data_ptr->sample_size, yc_data_ptr->fragment_size_bytes ); yc_data_ptr->write_ahead_us = yc_data_ptr->cycle_us * 1.5; } /* Set pointer of Y Audio Mode data to clist */ gtk_clist_set_row_data( clist, selected_row, (gpointer)yc_data_ptr ); yc->has_changes = TRUE; /* Force select new row, this should cause values * from Y Audio Mode structure to be applied to * the YMode widgets. */ yc->selected_ymode = -1; gtk_clist_select_row(clist, selected_row, 0); } /* Free coppied name */ free(name); name = NULL; } } /* Edit? */ else if((widget == yc->ymode_edit_btn) || (widget == yc->ymodes_menu_edit) ) { if((selected_row >= 0) && (selected_row < clist->rows)) { gint i; gchar *strptr; yc_ymode_data_struct *yc_data_ptr = (yc_ymode_data_struct *) gtk_clist_get_row_data( clist, selected_row ); PDialogDeleteAllPrompts(); PDialogAddPrompt( NULL, "Name:", (yc_data_ptr == NULL) ? NULL : yc_data_ptr->name ); strv = PDialogGetResponse( "Edit Preset Y Audio Mode", NULL, NULL, PDIALOG_ICON_QUESTION, "Set", "Cancel", PDIALOG_BTNFLAG_SUBMIT | PDIALOG_BTNFLAG_CANCEL, PDIALOG_BTNFLAG_SUBMIT, &strc ); name = ((strc > 0) ? strv[0] : NULL); if(name != NULL) { /* Check new name */ if(*name == '\0') { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Y Audio Mode name empty!", "You must specify a non-empty name string for\n\ the new Y Audio Mode name.", NULL, CDIALOG_ICON_ERROR, CDIALOG_BTNFLAG_OK, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); return; } if(strchr(name, ' ')) { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Y Audio Mode name invalid!", "Y Audio Mode names may not contain spaces.", NULL, CDIALOG_ICON_ERROR, CDIALOG_BTNFLAG_OK, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); return; } /* Name conflict? */ for(i = 0; i < clist->rows; i++) { if(i == selected_row) continue; gtk_clist_get_text(clist, i, 0, &strptr); if(strptr == NULL) continue; if(!g_strcasecmp(strptr, name)) { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Y Audio Mode name conflict!", "Another Y Audio Mode with the same name already exists,\n\ please pick a different name.", NULL, CDIALOG_ICON_ERROR, CDIALOG_BTNFLAG_OK, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); return; } } /* Make a copy of the name */ name = g_strdup(name); /* Update name on yc data structure */ if(yc_data_ptr != NULL) { g_free(yc_data_ptr->name); yc_data_ptr->name = (name != NULL) ? g_strdup(name) : NULL; } /* Update clist row item text */ gtk_clist_set_text( clist, selected_row, 0, name ); yc->has_changes = TRUE; g_free(name); } } } /* Remove? */ else if((widget == yc->ymode_remove_btn) || (widget == yc->ymodes_menu_remove) ) { if((selected_row >= 0) && (selected_row < clist->rows)) { gint status; const gchar *name; gchar *buf; yc_ymode_data_struct *yc_data_ptr = (yc_ymode_data_struct *) gtk_clist_get_row_data( clist, selected_row ); name = (yc_data_ptr != NULL) ? yc_data_ptr->name : NULL; if(name != NULL) buf = g_strdup_printf( "Remove Y Audio Mode \"%s\"?", name ); else buf = g_strdup_printf( "Remove Y Audio Mode #%i?", selected_row ); /* Make confermation */ CDialogSetTransientFor(yc->toplevel); status = CDialogGetResponse( "Confirm Remove", buf, "You are being asked for confermation about removing\n\ the selected Y Audio Mode from the list of Y Audio\n\ Modes.", CDIALOG_ICON_QUESTION, CDIALOG_BTNFLAG_YES | CDIALOG_BTNFLAG_NO | CDIALOG_BTNFLAG_HELP, CDIALOG_BTNFLAG_NO ); CDialogSetTransientFor(NULL); g_free(buf); /* Check response */ switch(status) { case CDIALOG_RESPONSE_YES: case CDIALOG_RESPONSE_YES_TO_ALL: case CDIALOG_RESPONSE_OK: break; default: return; break; } /* Begin removing the selected row */ if(yc_data_ptr != NULL) { YCYModeDataStructFree(yc_data_ptr); gtk_clist_set_row_data(clist, selected_row, NULL); } gtk_clist_remove(clist, selected_row); yc->has_changes = TRUE; /* Force select next row, this should cause values * from Y Audio Mode structure to be applied to * the YMode widgets */ if(selected_row < clist->rows) { yc->selected_ymode = -1; gtk_clist_select_row(clist, selected_row, 0); } } } /* Shift up? */ else if(widget == yc->ymode_shift_up_btn) { if((selected_row >= 0) && (selected_row < clist->rows) && (clist->rows > 1) ) { /* Make sure not first row */ if(selected_row > 0) { gtk_clist_swap_rows( clist, selected_row, selected_row - 1 ); /* Need to update selected row */ yc->selected_ymode = selected_row = selected_row - 1; yc->has_changes = TRUE; } else { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Unable to shift row", "Unable to shift row before the first position.", NULL, CDIALOG_ICON_WARNING, CDIALOG_BTNFLAG_OK, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); } } } /* Shift down? */ else if(widget == yc->ymode_shift_down_btn) { if((selected_row >= 0) && (selected_row < clist->rows) && (clist->rows > 1) ) { /* Make sure not last row */ if(selected_row < (clist->rows - 1)) { gtk_clist_swap_rows( clist, selected_row, selected_row + 1 ); /* Need to update selected row */ yc->selected_ymode = selected_row = selected_row + 1; yc->has_changes = TRUE; } else { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Unable to shift row", "Unable to shift row after the last position.", NULL, CDIALOG_ICON_WARNING, CDIALOG_BTNFLAG_OK, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); } } } } /* * Calculate theoretical cycle value button callback. */ void YCCycleCalculateCB(GtkWidget *widget, gpointer data) { glong cycle_us; gint sample_rate = 8000, sample_size = 8, channels = 1, fragment_size = 256; YConnection *recorder; GtkWidget *w; GtkEntry *entry; gchar *strptr; yc_struct *yc = (yc_struct *)data; if((widget == NULL) || (yc == NULL)) return; recorder = yc->recorder; /* Get audio values from widgets */ /* Sample rate */ w = yc->ymode_sample_rate_combo; if(w != NULL) { entry = (GtkEntry *)GTK_COMBO(w)->entry; if(entry != NULL) { /* Get sample rate in Hz */ strptr = gtk_entry_get_text(entry); if(strptr != NULL) sample_rate = atoi(strptr); } } /* Fragment size */ w = yc->ymode_fragment_size_combo; if(w != NULL) { entry = (GtkEntry *)GTK_COMBO(w)->entry; if(entry != NULL) { /* Get fragment size in bytes */ strptr = gtk_entry_get_text(entry); if(strptr != NULL) fragment_size = atoi(strptr); } } /* Channels */ w = yc->ymode_channels1_radio; if(w != NULL) { if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) channels = 1; } w = yc->ymode_channels2_radio; if(w != NULL) { if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) channels = 2; } /* Sample size */ w = yc->ymode_sample_size8_radio; if(w != NULL) { if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) sample_size = 8; } w = yc->ymode_sample_size16_radio; if(w != NULL) { if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) sample_size = 16; } /* Have Y calculate the cycle */ cycle_us = YCalculateCycle( recorder, sample_rate, channels, sample_size, fragment_size ); /* Update cycle spin button */ w = yc->ymode_cycle_spin; if(w != NULL) gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), cycle_us); yc->has_changes = TRUE; return; } /* * Y mode cycle spin button value change callback. */ void YCCycleSpinChangeCB(GtkWidget *widget, gpointer data) { glong cycle_us; YConnection *recorder; GtkWidget *w; yc_struct *yc = (yc_struct *)data; if((widget == NULL) || (yc == NULL)) return; recorder = yc->recorder; w = yc->ymode_cycle_spin; if(w == NULL) return; /* Get new cycle value from spin widget */ cycle_us = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON(w) ); /* Set new cycle value to Y server */ YSetCycle(recorder, cycle_us); yc->has_changes = TRUE; return; } /* * Apply current Y mode values in widgets to Y server. */ void YCYModeValuesApplyToYCB(GtkWidget *widget, gpointer data) { YConnection *recorder; GtkCList *clist; gint selected_row; yc_ymode_data_struct *ymode_data_ptr; yc_struct *yc = (yc_struct *)data; if((widget == NULL) || (yc == NULL)) return; recorder = yc->recorder; if(recorder == NULL) return; clist = (GtkCList *)yc->ymodes_clist; if(clist == NULL) return; /* First get currently selected Y Audio Mode from the * Y Audio Modes clist and its yc_ymode_data_struct * pointer. */ selected_row = yc->selected_ymode; if((selected_row < 0) || (selected_row >= clist->rows)) { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "No Y Audio Mode selected", "There is no Y Audio Mode currently selected to apply\n\ values for.", "You must select a Y Audio Mode from the list and then\n\ apply its values to the Y server.", CDIALOG_ICON_WARNING, CDIALOG_RESPONSE_OK | CDIALOG_RESPONSE_HELP, CDIALOG_RESPONSE_OK ); CDialogSetTransientFor(NULL); return; } ymode_data_ptr = (yc_ymode_data_struct *)gtk_clist_get_row_data( clist, selected_row ); if(ymode_data_ptr == NULL) { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Internal Error", "Unable to find the Y Audio Mode data associated with the\n\ selected row.", NULL, CDIALOG_ICON_ERROR, CDIALOG_RESPONSE_OK, CDIALOG_RESPONSE_OK ); CDialogSetTransientFor(NULL); return; } /* Now apply values currently in widgets to the Y Audio Mode * data structure. */ YCYModeFetchFromWidgets(yc, ymode_data_ptr); /* Now apply values to the Y server as arbitary values (not * using any preset Y Audio Modes). */ YSetAudioModeValues( recorder, ymode_data_ptr->sample_size, ymode_data_ptr->channels, ymode_data_ptr->sample_rate, ymode_data_ptr->direction, /* 0 = play, only play supported */ ymode_data_ptr->allow_fragmenting, ymode_data_ptr->num_fragments, ymode_data_ptr->fragment_size_bytes /* In bytes */ ); /* Update cycle just in case */ YSetCycle(recorder, ymode_data_ptr->cycle_us); } /* * Maps file browser to play a sound object. */ void YCYModePlayCB(GtkWidget *widget, gpointer data) { static gboolean reenterant = FALSE; gint i; YConnection *recorder; gchar **path; gint total_paths; fb_type_struct *type_rtn; fb_type_struct **type, *type_ptr; gint total_types; gchar tmp_path[PATH_MAX + NAME_MAX]; yc_struct *yc = (yc_struct *)data; if((widget == NULL) || (yc == NULL)) return; if(reenterant) return; else reenterant = TRUE; /* Allocate file extension types list */ total_types = 5; type = (fb_type_struct **)calloc(total_types, sizeof(fb_type_struct *)); if(type == NULL) total_types = 0; i = 0; if(i < total_types) { type_ptr = (fb_type_struct *)calloc(1, sizeof(fb_type_struct)); if(type_ptr != NULL) { type_ptr->name = strdup("Wave files"); type_ptr->extensions = strdup(".wav"); } type[i] = type_ptr; } i++; if(i < total_types) { type_ptr = (fb_type_struct *)calloc(1, sizeof(fb_type_struct)); if(type_ptr != NULL) { type_ptr->name = strdup("Voc files"); type_ptr->extensions = strdup(".voc"); } type[i] = type_ptr; } i++; if(i < total_types) { type_ptr = (fb_type_struct *)calloc(1, sizeof(fb_type_struct)); if(type_ptr != NULL) { type_ptr->name = strdup("Raw files"); type_ptr->extensions = strdup(".raw"); } type[i] = type_ptr; } i++; if(i < total_types) { type_ptr = (fb_type_struct *)calloc(1, sizeof(fb_type_struct)); if(type_ptr != NULL) { type_ptr->name = strdup("MIDI files"); type_ptr->extensions = strdup(".midi .mid"); } type[i] = type_ptr; } i++; if(i < total_types) { type_ptr = (fb_type_struct *)calloc(1, sizeof(fb_type_struct)); if(type_ptr != NULL) { type_ptr->name = strdup("All files"); type_ptr->extensions = strdup("*.*"); } type[i] = type_ptr; } /* Query user for path of sound object */ (*tmp_path) = '\0'; if(FileBrowserGetResponse( "Select Y Sound Object", "Play", "Cancel", NULL, /* Initial path */ type, total_types, /* File extension types */ &path, &total_paths, &type_rtn /* File extension type return */ )) { if((path != NULL) && (total_paths > 0)) { char *strptr = path[0]; strncpy( tmp_path, (strptr == NULL) ? "/" : strptr, PATH_MAX + NAME_MAX ); tmp_path[PATH_MAX + NAME_MAX - 1] = '\0'; } } /* Delete allocated file types */ FileBrowserDeleteTypeList(type, total_types); type = NULL; total_types = 0; /* No sepecified path from user? */ if((*tmp_path) == '\0') { reenterant = FALSE; return; } /* Get recorder after selected a sound object to play, this * is because the recorder may have been set to NULL while * waiting for the user to specify a sound object. */ recorder = yc->recorder; if(recorder == NULL) { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Not connected to Y server!", "Unable to play sound object, not connected to Y server.", NULL, CDIALOG_ICON_WARNING, CDIALOG_BTNFLAG_OK, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); reenterant = FALSE; return; } /* Stop current sound object from playing (if any) */ if(yc->current_sound_play != YIDNULL) { YDestroyPlaySoundObject( recorder, yc->current_sound_play ); yc->current_sound_play = YIDNULL; } /* Play new specified sound object */ yc->current_sound_play = YStartPlaySoundObjectSimple( recorder, tmp_path ); if(yc->current_sound_play == YIDNULL) { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Unable to play sound object", "The Y server was unable to play the specified sound object", NULL, CDIALOG_ICON_WARNING, CDIALOG_BTNFLAG_OK, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); } reenterant = FALSE; } /* * Sound refresh interval spine value change callback. */ void YCRefreshIntSpinChangeCB(GtkWidget *widget, gpointer data) { yc_struct *yc = (yc_struct *)data; if((widget == NULL) || (yc == NULL)) return; /* Cannot update this value directly on the server * right now. It needs to be saved to configuration file * later and takes affect when the YIFF Sound Server is * restarted */ yc->has_changes = TRUE; } /* * Browse MIDI play command callback. */ void YCBrowseMIDIPlayCmdCB(GtkWidget *widget, gpointer data) { GtkEntry *entry; char **path; int total_paths; yc_struct *yc = (yc_struct *)data; if(yc == NULL) return; entry = (GtkEntry *)yc->midi_play_cmd_entry; if(entry == NULL) return; if(FileBrowserGetResponse( "Select MIDI Player Program", "Select", "Cancel", YC_DEF_MIDI_PLAY_CMD_DIR, yc->ftype, yc->total_ftypes, /* File extension types */ &path, &total_paths, NULL /* Type return */ )) { char *path_ptr = ((total_paths > 0) ? path[0] : NULL); if(path_ptr != NULL) { path_ptr = strdup(path_ptr); gtk_entry_set_text(entry, path_ptr); free(path_ptr); } } } /* * Y Sound Paths list menu map callback. */ gint YCYSoundPathsMenuMapCB( GtkWidget *widget, GdkEvent *event, gpointer data ) { GtkWidget *w; GdkEventButton *button = (GdkEventButton *)event; yc_struct *yc = (yc_struct *)data; if((widget == NULL) || (event == NULL) || (yc == NULL)) return(FALSE); /* YSound Paths clist? */ if(widget == yc->ysound_paths_clist) { w = yc->ysound_paths_menu; if((button != NULL) && (w != NULL)) { if(button->button == 3) { gtk_menu_popup( GTK_MENU(w), NULL, NULL, NULL, NULL, button->button, button->time ); return(TRUE); } } } return(FALSE); } /* * YSound Paths clist select callback. */ void YCYSoundPathsListSelectCB( GtkWidget *widget, gint row, gint column, GdkEventButton *event, gpointer data ) { gint prev_row, new_row; GtkCList *clist; yc_struct *yc = (yc_struct *)data; if((widget == NULL) || (yc == NULL)) return; /* YSound Paths clist? */ if(widget == yc->ysound_paths_clist) { prev_row = yc->selected_ysound_path; new_row = row; yc->selected_ysound_path = row; clist = (GtkCList *)widget; /* Scroll if row not completely visable */ if(gtk_clist_row_is_visible(GTK_CLIST(widget), row) != GTK_VISIBILITY_FULL ) gtk_clist_moveto( GTK_CLIST(widget), row, 0, /* Row, column */ 0.5, 0.0 /* Row, column */ ); } return; } /* * Y Sound Paths prompt dialog browse button callback. */ static char *YCYSoundPathsPromptBrowseCB( gpointer prompt, gpointer client_data, int value_num ) { char **path, *strptr; int total_paths; static char rtn_path[PATH_MAX + NAME_MAX]; yc_struct *yc = (yc_struct *)client_data; if(yc == NULL) return(NULL); /* Handle by prompt number */ switch(value_num) { /* Path (first one) */ case 0: if(FileBrowserGetResponse( "Select Y Sound Path", "Select", "Cancel", NULL, /* Initial path */ yc->ftype, yc->total_ftypes, /* File extension types */ &path, &total_paths, NULL /* File extension type return */ )) { if((path != NULL) && (total_paths > 0)) { strptr = path[0]; strncpy( rtn_path, (strptr == NULL) ? "/" : strptr, PATH_MAX + NAME_MAX ); return(rtn_path); } else { return(NULL); } } else { /* Canceled */ return(NULL); } break; default: /* Some other prompt number, not suppose to happen, ignore */ break; } return(NULL); } /* * Y Sound Paths buttons callback. */ void YCYSoundPathsListButtonCB(GtkWidget *widget, gpointer data) { gchar **strv, *path; gint strc, selected_row; GtkCList *clist; yc_struct *yc = (yc_struct *)data; if((widget == NULL) || (yc == NULL)) return; clist = (GtkCList *)yc->ysound_paths_clist; if(clist == NULL) return; selected_row = yc->selected_ysound_path; /* Add? */ if((widget == yc->ysound_paths_add_btn) || (widget == yc->ysound_paths_menu_add) ) { PDialogDeleteAllPrompts(); PDialogAddPromptWithBrowse( NULL, "Path:", NULL, (void *)yc, YCYSoundPathsPromptBrowseCB ); strv = PDialogGetResponse( "Add Y Sound Path", NULL, NULL, PDIALOG_ICON_QUESTION, "Add", "Cancel", PDIALOG_BTNFLAG_SUBMIT | PDIALOG_BTNFLAG_CANCEL, PDIALOG_BTNFLAG_SUBMIT, &strc ); path = ((strc > 0) ? strv[0] : NULL); if(path != NULL) { /* Add new Y Sound Path */ gint i; gchar *strptr, *text[1]; /* Check new path, must be absolute */ if(!ISPATHABSOLUTE(path)) { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Not absolute path!", "You must specify an absolute path.", "You did not specify an absolute path as the\n\ value for the new Y Sound Path. Y Sound Paths\n\ need to be absolute paths, an absolute path is\n\ a path statement starting with a \"/\"\n\ character.", CDIALOG_ICON_WARNING, CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); return; } /* Check if another Y Sound Path has the same value */ for(i = 0; i < clist->rows; i++) { gtk_clist_get_text(clist, i, 0, &strptr); if(strptr == NULL) continue; if(!strcmp(strptr, path)) { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Value conflict!", "Another Y Sound Path exists with the same value.", "There is another Y Sound Path which already exists\n\ and has the same path as the one you just specified.", CDIALOG_ICON_WARNING, CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); return; } } /* Make a copy of the path */ path = strdup(path); text[0] = path; if((selected_row >= 0) && (selected_row < clist->rows)) { /* Insert */ selected_row = gtk_clist_insert( clist, selected_row, text ); } else { /* Append */ gtk_clist_append(clist, text); selected_row = clist->rows - 1; } /* Set row data to NULL */ gtk_clist_set_row_data(clist, selected_row, NULL); yc->has_changes = TRUE; /* Force select new row */ yc->selected_ysound_path = -1; gtk_clist_select_row(clist, selected_row, 0); /* Free coppied path */ free(path); path = NULL; } } /* Edit? */ else if((widget == yc->ysound_paths_edit_btn) || (widget == yc->ysound_paths_menu_edit) ) { if((selected_row >= 0) && (selected_row < clist->rows)) { gchar *strptr; gtk_clist_get_text(clist, selected_row, 0, &strptr); PDialogDeleteAllPrompts(); PDialogAddPromptWithBrowse( NULL, "Path:", strptr, /* Initial value */ (void *)yc, YCYSoundPathsPromptBrowseCB ); strv = PDialogGetResponse( "Edit Y Sound Path", NULL, NULL, PDIALOG_ICON_QUESTION, "Set", "Cancel", PDIALOG_BTNFLAG_SUBMIT | PDIALOG_BTNFLAG_CANCEL, PDIALOG_BTNFLAG_SUBMIT, &strc ); path = ((strc > 0) ? strv[0] : NULL); if(path != NULL) { /* Update Y Sound Path */ gint i; gchar *text[1]; path = ((strc > 0) ? strv[0] : NULL); if(path != NULL) { /* Check new path, must be absolute */ if(!ISPATHABSOLUTE(path)) { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Not absolute path!", "You must specify an absolute path.", "You did not specify an absolute path as the\n\ value for the Y Sound Path. Y Sound Paths\n\ need to be absolute paths, an absolute path is\n\ a path statement starting with a \"/\"\n\ character.", CDIALOG_ICON_WARNING, CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); return; } /* Check if another Y Sound Path has the same value */ for(i = 0; i < clist->rows; i++) { if(i == selected_row) continue; gtk_clist_get_text(clist, i, 0, &strptr); if(strptr == NULL) continue; if(!strcmp(strptr, path)) { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Value conflict!", "Another Y Sound Path exists with the same value.", "There is another Y Sound Path which already exists\n\ and has the same path as the one you just specified.", CDIALOG_ICON_WARNING, CDIALOG_BTNFLAG_OK | CDIALOG_BTNFLAG_HELP, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); return; } } /* Make a copy of the path */ path = strdup(path); text[0] = path; /* Update path value on clist */ gtk_clist_set_text(clist, selected_row, 0, path); /* No row data to update */ yc->has_changes = TRUE; /* Free coppied path */ free(path); path = NULL; } } } } /* Remove? */ else if((widget == yc->ysound_paths_remove_btn) || (widget == yc->ysound_paths_menu_remove) ) { if((selected_row >= 0) && (selected_row < clist->rows)) { gint status; gchar *buf; gchar *path = NULL; gtk_clist_get_text(clist, selected_row, 0, &path); /* Confirm remove path */ buf = g_strdup_printf( "Remove Y Sound Path:\n\ \n\ %s\n", path ); CDialogSetTransientFor(yc->toplevel); status = CDialogGetResponse( "Confirm Remove", buf, "You are being asked for confirmation about removing\n\ the selected Y Sound Path from the list of Y Sound\n\ Paths.", CDIALOG_ICON_QUESTION, CDIALOG_BTNFLAG_YES | CDIALOG_BTNFLAG_NO | CDIALOG_BTNFLAG_HELP, CDIALOG_BTNFLAG_NO ); CDialogSetTransientFor(NULL); free(buf); /* Check response */ switch(status) { case CDIALOG_RESPONSE_YES: case CDIALOG_RESPONSE_YES_TO_ALL: case CDIALOG_RESPONSE_OK: break; default: return; break; } /* Remove the item from the clist, note that there * is no row data to deallocate. */ gtk_clist_remove(clist, selected_row); yc->has_changes = TRUE; /* Force select next row */ if(selected_row < clist->rows) { yc->selected_ysound_path = -1; gtk_clist_select_row(clist, selected_row, 0); } } } /* Shift up? */ else if(widget == yc->ysound_paths_shift_up_btn) { if((selected_row >= 0) && (selected_row < clist->rows) && (clist->rows > 1) ) { /* Make sure not first row */ if(selected_row > 0) { gtk_clist_swap_rows( clist, selected_row, selected_row - 1 ); /* Need to update selected row */ yc->selected_ysound_path = selected_row = selected_row - 1; yc->has_changes = TRUE; } else { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Unable to shift row", "Unable to shift row before the first position.", NULL, CDIALOG_ICON_WARNING, CDIALOG_BTNFLAG_OK, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); } } } /* Shift down? */ else if(widget == yc->ysound_paths_shift_down_btn) { if((selected_row >= 0) && (selected_row < clist->rows) && (clist->rows > 1) ) { /* Make sure not last row */ if(selected_row < (clist->rows - 1)) { gtk_clist_swap_rows( clist, selected_row, selected_row + 1 ); /* Need to update selected row */ yc->selected_ysound_path = selected_row = selected_row + 1; yc->has_changes = TRUE; } else { CDialogSetTransientFor(yc->toplevel); CDialogGetResponse( "Unable to shift row", "Unable to shift row after the last position.", NULL, CDIALOG_ICON_WARNING, CDIALOG_BTNFLAG_OK, CDIALOG_BTNFLAG_OK ); CDialogSetTransientFor(NULL); } } } } /* * Confermation items list select callback. */ void YCConfermationListSelectCB( GtkWidget *widget, gint row, gint column, GdkEventButton *event, gpointer data ) { GtkCList *clist; yc_struct *yc = (yc_struct *)data; if((widget == NULL) || (yc == NULL)) return; /* Confermation items clist? */ if(widget == yc->conferm_items_clist) { clist = (GtkCList *)widget; /* Scroll if row not completely visable */ if(gtk_clist_row_is_visible(GTK_CLIST(widget), row) != GTK_VISIBILITY_FULL ) gtk_clist_moveto( GTK_CLIST(widget), row, 0, /* Row, column */ 0.5, 0.0 /* Row, column */ ); } return; } /* * Confermation list verbose listing toggle callback. */ void YCConfermVerboseToggleCB(GtkWidget *widget, gpointer data) { yc_struct *yc = (yc_struct *)data; if(yc == NULL) return; YCConfermListRefresh(yc); return; } /* * Start script browse callback. */ void YCBrowseStartScriptCB(GtkWidget *widget, gpointer data) { GtkEntry *entry; char **path; int total_paths; yc_struct *yc = (yc_struct *)data; if(yc == NULL) return; entry = (GtkEntry *)yc->start_script_entry; if(entry == NULL) return; if(FileBrowserGetResponse( "Select YIFF Start Script", "Select", "Cancel", YC_DEF_START_SCRIPT_DIR, yc->ftype, yc->total_ftypes, /* File extension types */ &path, &total_paths, NULL /* Type return */ )) { char *path_ptr = ((total_paths > 0) ? path[0] : NULL); if(path_ptr != NULL) { path_ptr = strdup(path_ptr); gtk_entry_set_text(entry, path_ptr); free(path_ptr); } } return; }