Mercurial > hg > xmms-sid
view src/xmms-sid.c @ 184:4406e91d2da3
Subtune control slider in fileinfo-window now works. Various fixes.
Pop-up subtune control can now be exited via ESC-button. The slider
is focused by default.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Wed, 18 Aug 2004 05:16:00 +0000 |
parents | 6e350784aa57 |
children | e9e97670f7d7 |
line wrap: on
line source
/* XMMS-SID - SIDPlay input plugin for X MultiMedia System (XMMS) Main source file Written by Matti "ccr" Hamalainen <ccr@tnsp.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <pthread.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #include <errno.h> #include <xmms/plugin.h> #include <xmms/util.h> #include <gdk/gdkkeysyms.h> #include <gtk/gtk.h> #include "xmms-sid.h" #include "xs_support.h" #include "xs_config.h" #include "xs_length.h" #include "xs_stil.h" #include "xs_interface.h" #include "xs_glade.h" /* * Include player engines */ #ifdef HAVE_SIDPLAY1 #include "xs_sidplay1.h" #endif #ifdef HAVE_SIDPLAY2 #include "xs_sidplay2.h" #endif #ifdef HAVE_NANOSID #include "xs_nanosid.h" #endif /* * Structure defining methods/functions of each player */ typedef struct { gint plrIdent; gboolean (*plrIsOurFile)(gchar *); gboolean (*plrInit)(t_xs_status *); void (*plrClose)(t_xs_status *); gboolean (*plrInitSong)(t_xs_status *); guint (*plrFillBuffer)(t_xs_status *, gchar *, guint); gboolean (*plrLoadSID)(t_xs_status *, gchar *); void (*plrDeleteSID)(t_xs_status *); t_xs_tune* (*plrGetSIDInfo)(gchar *); } t_xs_player; /* * List of players and links to their functions */ t_xs_player xs_playerlist[] = { #ifdef HAVE_SIDPLAY1 { XS_ENG_SIDPLAY1, xs_sidplay1_isourfile, xs_sidplay1_init, xs_sidplay1_close, xs_sidplay1_initsong, xs_sidplay1_fillbuffer, xs_sidplay1_loadsid, xs_sidplay1_deletesid, xs_sidplay1_getsidinfo }, #endif #ifdef HAVE_SIDPLAY2 { XS_ENG_SIDPLAY2, xs_sidplay2_isourfile, xs_sidplay2_init, xs_sidplay2_close, xs_sidplay2_initsong, xs_sidplay2_fillbuffer, xs_sidplay2_loadsid, xs_sidplay2_deletesid, xs_sidplay2_getsidinfo }, #endif #ifdef HAVE_NANOSID { XS_ENG_NANOSID, xs_nanosid_isourfile, xs_nanosid_init, xs_nanosid_close, xs_nanosid_initsong, xs_nanosid_fillbuffer, xs_nanosid_loadsid, xs_nanosid_deletesid, xs_nanosid_getsidinfo }, #endif }; const gint xs_nplayerlist = (sizeof(xs_playerlist) / sizeof(t_xs_player)); /* * Global variables */ static pthread_t xs_decode_thread; static pthread_mutex_t xs_mutex = PTHREAD_MUTEX_INITIALIZER; struct t_xs_cfg xs_cfg; t_xs_status xs_status; t_xs_player *xs_player = NULL; static GtkWidget *xs_fileinfowin = NULL, *xs_subctrl = NULL; static GtkObject *xs_subctrl_adj = NULL; static t_xs_tune *xs_fileinfotune = NULL; static t_xs_stil_node *xs_fileinfostil = NULL; void xs_subctrl_close(void); void xs_subctrl_update(void); /* * Re-initialize some settings */ void xs_reinit(void) { gint iPlayer; gboolean isInitialized; /* Stop playing, if we are */ if (xs_status.isPlaying) xs_stop(); /* Initialize status */ memset(&xs_status, 0, sizeof(xs_status)); xs_status.audioFrequency = xs_cfg.audioFrequency; xs_status.audioBitsPerSample = xs_cfg.audioBitsPerSample; xs_status.audioChannels = xs_cfg.audioChannels; xs_status.audioFormat = -1; /* Try to initialize emulator engine */ XSDEBUG("initializing emulator engine #%i...\n", xs_cfg.playerEngine); iPlayer = 0; isInitialized = FALSE; while ((iPlayer < xs_nplayerlist) && !isInitialized) { if (xs_playerlist[iPlayer].plrIdent == xs_cfg.playerEngine) { if (xs_playerlist[iPlayer].plrInit(&xs_status)) { isInitialized = TRUE; xs_player = (t_xs_player *) &xs_playerlist[iPlayer]; } } iPlayer++; } XSDEBUG("init#1: %s, %i\n", (isInitialized) ? "OK" : "FAILED", iPlayer); iPlayer = 0; while ((iPlayer < xs_nplayerlist) && !isInitialized) { if (xs_playerlist[iPlayer].plrInit(&xs_status)) { isInitialized = TRUE; xs_player = (t_xs_player *) &xs_playerlist[iPlayer]; } else iPlayer++; } XSDEBUG("init#2: %s, %i\n", (isInitialized) ? "OK" : "FAILED", iPlayer); /* Initialize song-length database */ xs_songlen_close(); if (xs_cfg.songlenDBEnable && (xs_songlen_init() < 0)) { XSERR("Error initializing song-length database!\n"); } /* Initialize STIL database */ xs_stil_close(); if (xs_cfg.stilDBEnable && (xs_stil_init() < 0)) { XSERR("Error initializing STIL database!\n"); } } /* * Initialize XMMS-SID */ void xs_init(void) { XSDEBUG("xs_init()\n"); /* Initialize and get configuration */ memset(&xs_cfg, 0, sizeof(xs_cfg)); xs_read_configuration(); /* Initialize subsystems */ xs_reinit(); XSDEBUG("OK\n"); } /* * Shut down XMMS-SID */ void xs_close(void) { XSDEBUG("xs_close(): shutting down...\n"); /* Stop playing, free structures */ xs_stop(); xs_tune_free(xs_status.pTune); xs_status.pTune = NULL; xs_player->plrDeleteSID(&xs_status); xs_player->plrClose(&xs_status); xs_songlen_close(); xs_stil_close(); XSDEBUG("shutdown finished.\n"); } /* * Check whether the given file is handled by this plugin */ gint xs_is_our_file(gchar *pcFilename) { char *pcExt; assert(xs_player); /* Check the filename */ if (pcFilename == NULL) return FALSE; /* Try to detect via detection routine, if required */ if (xs_cfg.detectMagic && xs_player->plrIsOurFile(pcFilename)) return TRUE; /* Detect just by checking filename extension */ pcExt = strrchr(pcFilename, '.'); if (pcExt) { pcExt++; switch (xs_cfg.playerEngine) { case XS_ENG_SIDPLAY1: case XS_ENG_SIDPLAY2: if (!strcasecmp(pcExt, "psid")) return TRUE; if (!strcasecmp(pcExt, "sid")) return TRUE; if (!strcasecmp(pcExt, "dat")) return TRUE; if (!strcasecmp(pcExt, "inf")) return TRUE; if (!strcasecmp(pcExt, "info")) return TRUE; break; case XS_ENG_NANOSID: if (!strcasecmp(pcExt, "zsid")) return TRUE; break; } } return FALSE; } /* * Main playing thread loop */ void *xs_play_loop(void *argPointer) { t_xs_status myStatus; t_xs_tune *myTune; gboolean audioOpen = FALSE, doPlay = FALSE; guint audioGot; gint songLength; gchar audioBuffer[XS_BUFSIZE]; /* Initialize */ pthread_mutex_lock(&xs_mutex); XSDEBUG("entering play thread\n"); memcpy(&myStatus, &xs_status, sizeof(t_xs_status)); myTune = xs_status.pTune; pthread_mutex_unlock(&xs_mutex); /* * Main player loop: while not stopped, loop here - play subtunes */ doPlay = TRUE; while (xs_status.isPlaying && doPlay) { pthread_mutex_lock(&xs_mutex); myStatus.currSong = xs_status.currSong; pthread_mutex_unlock(&xs_mutex); xs_subctrl_update(); XSDEBUG("subtune #%i selected, initializing...\n", myStatus.currSong); songLength = myTune->subTunes[myStatus.currSong - 1].tuneLength; /* Check minimum playtime */ if (xs_cfg.playMinTimeEnable) { if (songLength < xs_cfg.playMinTime) songLength = xs_cfg.playMinTime; } /* Initialize song */ if (!xs_player->plrInitSong(&myStatus)) { XSERR("Couldn't initialize SID-tune '%s' (sub-tune #%i)!\n", myTune->tuneFilename, myStatus.currSong); goto xs_err_exit; } /* Get song information for current subtune */ xs_plugin_ip.set_info( myTune->subTunes[myStatus.currSong - 1].tuneTitle, (songLength > 0) ? (songLength * 1000) : -1, (myTune->subTunes[myStatus.currSong - 1].tuneSpeed > 0) ? (myTune->subTunes[myStatus.currSong - 1].tuneSpeed * 1000) : -1, myStatus.audioFrequency, myStatus.audioChannels); /* Open the audio output */ if (!xs_plugin_ip.output->open_audio(myStatus.audioFormat, myStatus.audioFrequency, myStatus.audioChannels)) { XSERR("Couldn't open XMMS audio output (fmt=%x, freq=%i, nchan=%i)!\n", myStatus.audioFormat, myStatus.audioFrequency, myStatus.audioChannels); pthread_mutex_lock(&xs_mutex); xs_status.isError = TRUE; pthread_mutex_unlock(&xs_mutex); goto xs_err_exit; } audioOpen = TRUE; /* * Play the subtune */ while (xs_status.isPlaying && myStatus.isPlaying && (xs_status.currSong == myStatus.currSong)) { /* Render audio data */ audioGot = xs_player->plrFillBuffer(&myStatus, audioBuffer, XS_BUFSIZE); /* I <3 visualice/haujobb */ xs_plugin_ip.add_vis_pcm( xs_plugin_ip.output->written_time(), myStatus.audioFormat, myStatus.audioChannels, audioGot, audioBuffer); /* Wait a little */ while (xs_status.isPlaying && (xs_status.currSong == myStatus.currSong) && ((guint) xs_plugin_ip.output->buffer_free() < audioGot)) xmms_usleep(10000); /* Output audio */ if (xs_status.isPlaying && (xs_status.currSong == myStatus.currSong)) xs_plugin_ip.output->write_audio(audioBuffer, audioGot); /* Check if we have played enough */ if (xs_cfg.playMaxTimeEnable) { if (xs_cfg.playMaxTimeUnknown) { if ((songLength == -1) && (xs_plugin_ip.output->output_time() >= (xs_cfg.playMaxTime * 1000))) myStatus.isPlaying = FALSE; } else { if (xs_plugin_ip.output->output_time() >= (xs_cfg.playMaxTime * 1000)) myStatus.isPlaying = FALSE; } } if (songLength > 0) { if (xs_plugin_ip.output->output_time() >= (songLength * 1000)) myStatus.isPlaying = FALSE; } } XSDEBUG("subtune ended/stopped\n"); /* Close audio */ if (audioOpen) { XSDEBUG("close audio #1\n"); xs_plugin_ip.output->close_audio(); audioOpen = FALSE; } /* Now determine if we continue by selecting other subtune or something */ if (!myStatus.isPlaying) doPlay = FALSE; } xs_err_exit: /* Close audio */ if (audioOpen) { XSDEBUG("close audio #2\n"); xs_plugin_ip.output->close_audio(); } /* Exit the playing thread */ XSDEBUG("exiting thread, bye.\n"); pthread_mutex_lock(&xs_mutex); xs_status.isPlaying = FALSE; pthread_mutex_unlock(&xs_mutex); pthread_exit(NULL); } /* * Start playing the given file */ void xs_play_file(gchar *pcFilename) { XSDEBUG("play '%s'\n", pcFilename); /* Get tune information */ if ((xs_status.pTune = xs_player->plrGetSIDInfo(pcFilename)) == NULL) return; /* Initialize the tune */ if (!xs_player->plrLoadSID(&xs_status, pcFilename)) { xs_tune_free(xs_status.pTune); xs_status.pTune = NULL; return; } XSDEBUG("load ok\n"); /* Set general status information */ xs_status.isPlaying = TRUE; xs_status.isError = FALSE; xs_status.currSong = xs_status.pTune->startTune; /* Start the playing thread! */ if (pthread_create(&xs_decode_thread, NULL, xs_play_loop, NULL) < 0) { XSERR("Couldn't start playing thread! Possible reason reported by system: %s\n", strerror(errno)); xs_tune_free(xs_status.pTune); xs_status.pTune = NULL; xs_player->plrDeleteSID(&xs_status); } XSDEBUG("systems should be up?\n"); } /* * Stop playing */ void xs_stop(void) { XSDEBUG("STOP_REQ\n"); xs_subctrl_close(); if (xs_status.isPlaying) { /* Stop playing */ XSDEBUG("stopping...\n"); pthread_mutex_lock(&xs_mutex); xs_status.isPlaying = FALSE; pthread_mutex_unlock(&xs_mutex); pthread_join(xs_decode_thread, NULL); } /* Free tune information */ xs_player->plrDeleteSID(&xs_status); xs_tune_free(xs_status.pTune); xs_status.pTune = NULL; /* Update subtune control */ xs_subctrl_update(); } /* * Pause/unpause the playing */ void xs_pause(short pauseState) { xs_subctrl_close(); xs_plugin_ip.output->pause(pauseState); } /* * Pop-up subtune selector */ #define LUW(x...) lookup_widget(xs_fileinfowin, ## x) void xs_subctrl_update(void) { GtkAdjustment *tmpAdj; gboolean isEnabled; /* Check if control window exists, we are currently playing and have a tune */ if (xs_subctrl && xs_status.pTune && xs_status.isPlaying) { tmpAdj = GTK_ADJUSTMENT(xs_subctrl_adj); tmpAdj->value = xs_status.currSong; tmpAdj->lower = 1; tmpAdj->upper = xs_status.pTune->nsubTunes; gtk_adjustment_value_changed(tmpAdj); } if (xs_fileinfowin) { /* Check if we are currently playing and have a tune */ if (xs_status.pTune && xs_status.isPlaying) { tmpAdj = gtk_range_get_adjustment(GTK_RANGE(LUW("fileinfo_subctrl_adj"))); tmpAdj->value = xs_status.currSong; tmpAdj->lower = 1; tmpAdj->upper = xs_status.pTune->nsubTunes; gtk_adjustment_value_changed(tmpAdj); isEnabled = TRUE; } else isEnabled = FALSE; /* Enable or disable subtune-control in fileinfo window */ gtk_widget_set_sensitive(LUW("fileinfo_subctrl_prev"), isEnabled); gtk_widget_set_sensitive(LUW("fileinfo_subctrl_adj"), isEnabled); gtk_widget_set_sensitive(LUW("fileinfo_subctrl_next"), isEnabled); } } void xs_fileinfo_setsong(void) { pthread_mutex_lock(&xs_mutex); xs_status.currSong = gtk_range_get_adjustment(GTK_RANGE(LUW("fileinfo_subctrl_adj")))->value; pthread_mutex_unlock(&xs_mutex); } void xs_subctrl_setsong(void) { pthread_mutex_lock(&xs_mutex); xs_status.currSong = GTK_ADJUSTMENT(xs_subctrl_adj)->value; pthread_mutex_unlock(&xs_mutex); } void xs_subctrl_prevsong(void) { if (xs_status.pTune && xs_status.isPlaying) { pthread_mutex_lock(&xs_mutex); if (xs_status.currSong > 1) xs_status.currSong--; pthread_mutex_unlock(&xs_mutex); } xs_subctrl_update(); } void xs_subctrl_nextsong(void) { if (xs_status.pTune && xs_status.isPlaying) { pthread_mutex_lock(&xs_mutex); if (xs_status.currSong < xs_status.pTune->nsubTunes) xs_status.currSong++; pthread_mutex_unlock(&xs_mutex); } xs_subctrl_update(); } void xs_subctrl_close(void) { if (xs_subctrl) { gtk_widget_destroy(xs_subctrl); xs_subctrl = NULL; } } gboolean xs_subctrl_keypress(GtkWidget *win, GdkEventKey *ev) { if (ev->keyval == GDK_Escape) xs_subctrl_close(); return FALSE; } void xs_subctrl_open() { GtkWidget *frame25, *hbox15, *subctrl_prev, *subctrl_current, *subctrl_next; if (xs_subctrl) return; /* Create the pop-up window */ xs_subctrl = gtk_window_new (GTK_WINDOW_DIALOG); gtk_widget_set_name (xs_subctrl, "xs_subctrl"); gtk_object_set_data (GTK_OBJECT (xs_subctrl), "xs_subctrl", xs_subctrl); gtk_window_set_title(GTK_WINDOW(xs_subctrl), "Subtune Control"); gtk_window_set_position(GTK_WINDOW(xs_subctrl), GTK_WIN_POS_MOUSE); gtk_container_set_border_width(GTK_CONTAINER(xs_subctrl), 0); gtk_window_set_policy(GTK_WINDOW(xs_subctrl), FALSE, FALSE, FALSE); gtk_signal_connect(GTK_OBJECT(xs_subctrl), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &xs_subctrl); gtk_signal_connect(GTK_OBJECT(xs_subctrl), "focus_out_event", GTK_SIGNAL_FUNC(xs_subctrl_close), NULL); gtk_widget_realize(xs_subctrl); gdk_window_set_decorations(xs_subctrl->window, 0); /* Create the control widgets */ frame25 = gtk_frame_new (NULL); gtk_container_add (GTK_CONTAINER (xs_subctrl), frame25); gtk_container_set_border_width (GTK_CONTAINER (frame25), 2); gtk_frame_set_shadow_type (GTK_FRAME (frame25), GTK_SHADOW_OUT); hbox15 = gtk_hbox_new (FALSE, 4); gtk_container_add (GTK_CONTAINER (frame25), hbox15); subctrl_prev = gtk_button_new_with_label (" < "); gtk_widget_set_name (subctrl_prev, "subctrl_prev"); gtk_box_pack_start (GTK_BOX (hbox15), subctrl_prev, FALSE, FALSE, 0); xs_subctrl_adj = gtk_adjustment_new (xs_status.currSong, 1, xs_status.pTune->nsubTunes, 1, 1, 0); gtk_signal_connect (GTK_OBJECT (xs_subctrl_adj), "value_changed", GTK_SIGNAL_FUNC (xs_subctrl_setsong), NULL); subctrl_current = gtk_hscale_new (GTK_ADJUSTMENT(xs_subctrl_adj)); gtk_widget_set_name (subctrl_current, "subctrl_current"); gtk_box_pack_start (GTK_BOX (hbox15), subctrl_current, FALSE, TRUE, 0); gtk_scale_set_digits (GTK_SCALE (subctrl_current), 0); gtk_range_set_update_policy (GTK_RANGE (subctrl_current), GTK_UPDATE_DELAYED); gtk_widget_grab_focus (subctrl_current); subctrl_next = gtk_button_new_with_label (" > "); gtk_widget_set_name (subctrl_next, "subctrl_next"); gtk_box_pack_start (GTK_BOX (hbox15), subctrl_next, FALSE, FALSE, 0); gtk_signal_connect (GTK_OBJECT (subctrl_prev), "clicked", GTK_SIGNAL_FUNC (xs_subctrl_prevsong), NULL); gtk_signal_connect (GTK_OBJECT (subctrl_next), "clicked", GTK_SIGNAL_FUNC (xs_subctrl_nextsong), NULL); gtk_signal_connect (GTK_OBJECT (xs_subctrl), "key_press_event", GTK_SIGNAL_FUNC (xs_subctrl_keypress), NULL); gtk_widget_show_all(xs_subctrl); } /* * Set the time-seek position * (the playing thread will do the "seeking" aka song-change) */ void xs_seek(gint iTime) { /* Check status */ if (!xs_status.pTune || !xs_status.isPlaying) return; /* Act according to settings */ switch (xs_cfg.subsongControl) { case XS_SSC_SEEK: if (iTime < xs_status.lastTime) xs_subctrl_prevsong(); else if (iTime > xs_status.lastTime) xs_subctrl_nextsong(); break; case XS_SSC_POPUP: xs_subctrl_open(); break; /* If we have song-position patch, check settings */ #ifdef HAVE_SONG_POSITION case XS_SSC_PATCH: pthread_mutex_lock(&xs_mutex); if ((iTime > 0) && (iTime <= xs_status.pTune->nsubTunes)) xs_status.currSong = iTime; pthread_mutex_unlock(&xs_mutex); break; #endif default: break; } } /* * Return the playing "position/time" */ gint xs_get_time(void) { /* If errorflag is set, return -2 to signal it to XMMS's idle callback */ if (xs_status.isError) return -2; /* If there is no tune, return -1 */ if (!xs_status.pTune) return -1; /* If tune has ended, return -1 */ if (!xs_status.isPlaying) return -1; /* Let's see what we do */ switch (xs_cfg.subsongControl) { case XS_SSC_SEEK: xs_status.lastTime = (xs_plugin_ip.output->output_time() / 1000); break; #ifdef HAVE_SONG_POSITION case XS_SSC_PATCH: pthread_mutex_lock(&xs_mutex); set_song_position(xs_status.currSong, 1, xs_status.pTune->nsubTunes); pthread_mutex_unlock(&xs_mutex); break; #endif } /* Return output time reported by audio output plugin */ return xs_plugin_ip.output->output_time(); } /* * Return song information */ void xs_get_song_info(gchar *songFilename, gchar **songTitle, gint *songLength) { t_xs_tune *pInfo; gint tmpInt; /* Get tune information from emulation engine */ pInfo = xs_player->plrGetSIDInfo(songFilename); if (!pInfo) return; /* Get sub-tune information, if available */ if ((pInfo->startTune >= 0) && (pInfo->startTune <= pInfo->nsubTunes)) { (*songTitle) = g_strdup(pInfo->subTunes[pInfo->startTune - 1].tuneTitle); tmpInt = pInfo->subTunes[pInfo->startTune - 1].tuneLength; if (tmpInt < 0) (*songLength) = -1; else (*songLength) = (tmpInt * 1000); } /* Free tune information */ xs_tune_free(pInfo); } /* * Allocate a new tune structure */ t_xs_tune *xs_tune_new(gchar *pcFilename, gint nsubTunes, gint startTune, gchar *tuneName, gchar *tuneComposer, gchar *tuneCopyright) { t_xs_tune *pResult; pResult = (t_xs_tune *) g_malloc0(sizeof(t_xs_tune)); if (!pResult) return NULL; pResult->tuneFilename = g_strdup(pcFilename); if (!pResult->tuneFilename) { g_free(pResult); return NULL; } pResult->tuneName = g_strdup(tuneName); pResult->tuneComposer = g_strdup(tuneComposer); pResult->tuneCopyright = g_strdup(tuneCopyright); pResult->nsubTunes = nsubTunes; pResult->startTune = startTune; return pResult; } /* * Free tune information */ void xs_tune_free(t_xs_tune *pTune) { gint i; if (!pTune) return; g_free(pTune->tuneFilename); pTune->tuneFilename = NULL; g_free(pTune->tuneName); pTune->tuneName = NULL; g_free(pTune->tuneComposer); pTune->tuneComposer = NULL; g_free(pTune->tuneCopyright); pTune->tuneCopyright = NULL; for (i = 0; i < pTune->nsubTunes; i++) { if (pTune->subTunes[i].tuneTitle) { g_free(pTune->subTunes[i].tuneTitle); pTune->subTunes[i].tuneTitle = NULL; } } g_free(pTune); } /* * File-information window */ void xs_fileinfo_ok(void) { gtk_widget_destroy(xs_fileinfowin); xs_fileinfowin = NULL; } void xs_fileinfo_subtune(GtkWidget *widget, void *data) { t_xs_stil_subnode *tmpNode; GtkWidget *tmpItem, *tmpText; gint tmpIndex; gchar *subName, *subAuthor; /* Freeze text-widget and delete the old text */ tmpText = LUW("fileinfo_sub_info"); gtk_text_freeze(GTK_TEXT(tmpText)); gtk_text_set_point(GTK_TEXT(tmpText), 0); gtk_text_forward_delete(GTK_TEXT(tmpText), gtk_text_get_length(GTK_TEXT(tmpText))); if (xs_fileinfostil) { /* Get subtune number */ tmpItem = gtk_menu_get_active(GTK_MENU(data)); tmpIndex = g_list_index(GTK_MENU_SHELL(data)->children, tmpItem); /* Get subtune information */ tmpNode = &xs_fileinfostil->subTune[tmpIndex]; subName = tmpNode->pName; subAuthor = tmpNode->pAuthor; /* Put in the new text, if available */ if (tmpNode->pInfo) { gtk_text_insert (GTK_TEXT (tmpText), NULL, NULL, NULL, tmpNode->pInfo, strlen(tmpNode->pInfo)); } } else { /* We don't have any information */ subName = NULL; subAuthor = NULL; } /* Get and set subtune information */ gtk_entry_set_text(GTK_ENTRY(LUW("fileinfo_sub_name")), subName ? subName : ""); gtk_entry_set_text(GTK_ENTRY(LUW("fileinfo_sub_author")), subAuthor ? subAuthor : ""); /* Un-freeze the widget */ gtk_text_thaw(GTK_TEXT(tmpText)); } void xs_fileinfo(gchar *pcFilename) { GtkWidget *tmpMenuItem, *tmpMenu, *tmpOptionMenu; t_xs_stil_subnode *tmpNode; gchar tmpStr[32], *tmpS; gint n; /* Free old info, if set */ if (xs_fileinfotune) xs_tune_free(xs_fileinfotune); /* Get new tune information */ if ((xs_fileinfotune = xs_player->plrGetSIDInfo(pcFilename)) == NULL) return; if (xs_cfg.stilDBEnable) xs_fileinfostil = xs_stil_get(pcFilename); else xs_fileinfostil = NULL; /* Check if there already is an open fileinfo window */ if (xs_fileinfowin) { /* Raise old window */ gdk_window_raise(xs_fileinfowin->window); /* Delete items */ tmpOptionMenu = LUW("fileinfo_sub_tune"); gtk_widget_destroy(GTK_OPTION_MENU(tmpOptionMenu)->menu); GTK_OPTION_MENU(tmpOptionMenu)->menu = gtk_menu_new(); } else { /* If not, create a new one */ xs_fileinfowin = create_xs_fileinfowin(); /* Connect additional signals */ gtk_signal_connect(GTK_OBJECT( gtk_range_get_adjustment(GTK_RANGE(LUW("fileinfo_subctrl_adj")))), "value_changed", GTK_SIGNAL_FUNC (xs_fileinfo_setsong), NULL); } /* Set the generic song information */ gtk_entry_set_text(GTK_ENTRY(LUW("fileinfo_filename")), pcFilename); gtk_entry_set_text(GTK_ENTRY(LUW("fileinfo_songname")), xs_fileinfotune->tuneName); gtk_entry_set_text(GTK_ENTRY(LUW("fileinfo_composer")), xs_fileinfotune->tuneComposer); gtk_entry_set_text(GTK_ENTRY(LUW("fileinfo_copyright")), xs_fileinfotune->tuneCopyright); /* Main tune - the pseudo tune */ tmpOptionMenu = LUW("fileinfo_sub_tune"); tmpMenu = GTK_OPTION_MENU(tmpOptionMenu)->menu; tmpMenuItem = gtk_menu_item_new_with_label ("General info"); gtk_widget_show (tmpMenuItem); gtk_menu_append (GTK_MENU(tmpMenu), tmpMenuItem); gtk_signal_connect (GTK_OBJECT (tmpMenuItem), "activate", GTK_SIGNAL_FUNC (xs_fileinfo_subtune), tmpMenu); /* Other menu items */ for (n = 1; n <= xs_fileinfotune->nsubTunes; n++) { if (xs_fileinfostil) { tmpNode = &xs_fileinfostil->subTune[n]; if (tmpNode->pName) tmpS = tmpNode->pName; else if (tmpNode->pInfo) tmpS = tmpNode->pInfo; else tmpS = "---"; snprintf(tmpStr, sizeof(tmpStr), "Tune #%i: %s", n, tmpS); } else snprintf(tmpStr, sizeof(tmpStr), "Tune #%i", n); tmpMenuItem = gtk_menu_item_new_with_label(tmpStr); gtk_widget_show (tmpMenuItem); gtk_menu_append (GTK_MENU(tmpMenu), tmpMenuItem); gtk_signal_connect (GTK_OBJECT(tmpMenuItem), "activate", GTK_SIGNAL_FUNC(xs_fileinfo_subtune), tmpMenu); } /* Set the subtune information */ xs_fileinfo_subtune(NULL, tmpMenu); /* Update subtune controls */ xs_subctrl_update(); /* Show the window */ gtk_widget_show(xs_fileinfowin); }