diff options
author | Benjamin Drung <bdrung@ubuntu.com> | 2010-08-04 01:29:13 +0200 |
---|---|---|
committer | Benjamin Drung <bdrung@ubuntu.com> | 2010-08-04 01:29:13 +0200 |
commit | cfc3a681cfae56b9feb6451654c3f51001156842 (patch) | |
tree | 88bbd99e30d4bb600e53d417acf68a01f466333f /src | |
parent | 7fc1ac65d6f941ed101328823c9dbceea05ff017 (diff) |
Imported Upstream version 2.4~beta2
Diffstat (limited to 'src')
-rw-r--r-- | src/audacious/Makefile | 1 | ||||
-rw-r--r-- | src/audacious/audconfig.c | 1 | ||||
-rw-r--r-- | src/audacious/chardet.c | 5 | ||||
-rw-r--r-- | src/audacious/credits.c | 7 | ||||
-rw-r--r-- | src/audacious/dbus-service.h | 6 | ||||
-rw-r--r-- | src/audacious/dbus.c | 35 | ||||
-rw-r--r-- | src/audacious/drct.c | 1 | ||||
-rw-r--r-- | src/audacious/equalizer.c | 7 | ||||
-rw-r--r-- | src/audacious/images/menu_randomize_playlist.png | bin | 767 -> 0 bytes | |||
-rw-r--r-- | src/audacious/interface.c | 49 | ||||
-rw-r--r-- | src/audacious/interface.h | 14 | ||||
-rw-r--r-- | src/audacious/main.c | 22 | ||||
-rw-r--r-- | src/audacious/main.h | 1 | ||||
-rw-r--r-- | src/audacious/mpris_tracklist.xml | 4 | ||||
-rw-r--r-- | src/audacious/playback.c | 3 | ||||
-rw-r--r-- | src/audacious/playlist-new.c | 38 | ||||
-rw-r--r-- | src/audacious/plugin-registry.c | 8 | ||||
-rw-r--r-- | src/audacious/plugin.h | 133 | ||||
-rw-r--r-- | src/audacious/visualization.c | 4 | ||||
-rw-r--r-- | src/libaudcore/tuple_compiler.c | 4 | ||||
-rw-r--r-- | src/libaudcore/vfs_buffer.c | 2 | ||||
-rw-r--r-- | src/libaudgui/equalizer.c | 6 | ||||
-rw-r--r-- | src/libaudtag/id3/id3v22.c | 5 | ||||
-rw-r--r-- | src/libaudtag/id3/id3v24.c | 184 |
24 files changed, 339 insertions, 201 deletions
diff --git a/src/audacious/Makefile b/src/audacious/Makefile index afe9e16..e4c5a91 100644 --- a/src/audacious/Makefile +++ b/src/audacious/Makefile @@ -75,7 +75,6 @@ DATA = images/about-logo.png \ images/menu_playlist.png \ images/menu_plugin.png \ images/menu_queue_toggle.png \ - images/menu_randomize_playlist.png \ images/playback.png \ images/playlist.png \ images/plugins.png \ diff --git a/src/audacious/audconfig.c b/src/audacious/audconfig.c index 8653e70..a0bc200 100644 --- a/src/audacious/audconfig.c +++ b/src/audacious/audconfig.c @@ -292,6 +292,7 @@ static void save_output_path (void) plugin_get_path (plugin_by_header (current_output_plugin), & path, & type, & number); + g_free (cfg.output_path); cfg.output_path = (path != NULL) ? g_strdup (path) : NULL; cfg.output_number = number; } diff --git a/src/audacious/chardet.c b/src/audacious/chardet.c index c9a2c3b..f79bc96 100644 --- a/src/audacious/chardet.c +++ b/src/audacious/chardet.c @@ -100,6 +100,9 @@ cd_chardet_to_utf8(const gchar * str, gssize len, gsize * arg_bytes_read, #ifdef USE_CHARDET if (libguess_validate_utf8(str, len)) +#else + if (g_utf8_validate(str, len, NULL)) +#endif { if (len < 0) len = strlen (str); @@ -115,7 +118,7 @@ cd_chardet_to_utf8(const gchar * str, gssize len, gsize * arg_bytes_read, return ret; } - +#ifdef USE_CHARDET if (cfg.chardet_detector) det = cfg.chardet_detector; diff --git a/src/audacious/credits.c b/src/audacious/credits.c index 4ae19fc..e53a4cb 100644 --- a/src/audacious/credits.c +++ b/src/audacious/credits.c @@ -103,6 +103,7 @@ static const gchar *credit_text[] = { "Juho Heikkinen", "Joseph Jezak", "Henrik Johansson", + "Mikael Magnusson", "Rodrigo Martins de Matos Ventura", "Diego Pettenò", "Mike Ryan", @@ -193,6 +194,9 @@ static const gchar *translators_text[] = { N_("Catalan:"), "Ernest Adrogué", NULL, + N_("Chinese:"), + "Chi Chiu Tsu", + NULL, N_("Croatian:"), "Marin Glibic", NULL, @@ -280,6 +284,9 @@ static const gchar *translators_text[] = { "Andrej Herceg", NULL, N_("Spanish:"), + "Cosme Domínguez Díaz", + "Jeki Sinneo Leinos", + "Francisco Javier F. Serrador", "Gustavo D. Vranjes", NULL, N_("Swedish:"), diff --git a/src/audacious/dbus-service.h b/src/audacious/dbus-service.h index 0475e1b..581556a 100644 --- a/src/audacious/dbus-service.h +++ b/src/audacious/dbus-service.h @@ -90,9 +90,15 @@ enum { LAST_SIG }; +enum { + TRACKLIST_CHANGE_SIG, + LAST_TRACKLIST_SIG +}; + gboolean mpris_emit_track_change(MprisPlayer *obj); gboolean mpris_emit_status_change(MprisPlayer *obj, PlaybackStatus status); gboolean mpris_emit_caps_change(MprisPlayer *obj); +gboolean mpris_emit_tracklist_change(MprisTrackList *obj, gint playlist); // MPRIS /TrackList gboolean mpris_tracklist_get_metadata(MprisTrackList *obj, gint pos, diff --git a/src/audacious/dbus.c b/src/audacious/dbus.c index 7b4778a..128f62d 100644 --- a/src/audacious/dbus.c +++ b/src/audacious/dbus.c @@ -87,6 +87,7 @@ struct MprisMetadataRequest static DBusGConnection *dbus_conn = NULL; static guint signals[LAST_SIG] = { 0 }; +static guint tracklist_signals[LAST_TRACKLIST_SIG] = { 0 }; static GThread *main_thread; static GMutex *info_mutex; @@ -99,6 +100,8 @@ G_DEFINE_TYPE (MprisTrackList, mpris_tracklist, G_TYPE_OBJECT) #define DBUS_TYPE_G_STRING_VALUE_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE)) +static void mpris_playlist_update_hook(gpointer unused, MprisTrackList *obj); + void audacious_rc_class_init(RemoteObjectClass * klass) { } @@ -119,6 +122,8 @@ void mpris_player_class_init(MprisPlayerClass * klass) void mpris_tracklist_class_init(MprisTrackListClass * klass) { + tracklist_signals[TRACKLIST_CHANGE_SIG] = g_signal_new("track_list_change", G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); } void audacious_rc_init(RemoteObject * object) @@ -191,6 +196,20 @@ void mpris_tracklist_init(MprisTrackList * object) // Register DBUS path dbus_g_connection_register_g_object(dbus_conn, AUDACIOUS_DBUS_PATH_MPRIS_TRACKLIST, G_OBJECT(object)); + + // Add signals + DBusGProxy *proxy = object->proxy; + if (proxy != NULL) + { + dbus_g_proxy_add_signal(proxy, "TrackListChange", G_TYPE_INT, G_TYPE_INVALID); + } + else + { + /* XXX / FIXME: Why does this happen? -- ccr */ + g_warning("in mpris_tracklist_init object->proxy == NULL, not adding some signals."); + } + + hook_associate("playlist update", (HookFunction) mpris_playlist_update_hook, object); } void init_dbus() @@ -850,6 +869,18 @@ gboolean mpris_emit_status_change(MprisPlayer * obj, PlaybackStatus status) } // MPRIS /TrackList +gboolean mpris_emit_tracklist_change(MprisTrackList * obj, gint playlist) +{ + g_signal_emit(obj, tracklist_signals[TRACKLIST_CHANGE_SIG], 0, playlist_entry_count(playlist)); + return TRUE; +} + +static void mpris_playlist_update_hook(gpointer unused, MprisTrackList * obj) +{ + gint playlist = playlist_get_active(); + + mpris_emit_tracklist_change(obj, playlist); +} gboolean mpris_tracklist_get_metadata(MprisTrackList * obj, gint pos, GHashTable * *metadata, GError * *error) { @@ -971,7 +1002,7 @@ gboolean audacious_rc_show_playlist(RemoteObject * obj, gboolean show, GError ** gboolean audacious_rc_get_tuple_fields(RemoteObject * obj, gchar *** fields, GError ** error) { - gchar **res = g_new0(gchar *, FIELD_LAST); + gchar **res = g_new0(gchar *, FIELD_LAST + 1); gint i; for (i = 0; i < FIELD_LAST; i++) { @@ -1256,7 +1287,7 @@ gboolean audacious_rc_clear(RemoteObject * obj, GError * *error) gboolean audacious_rc_auto_advance(RemoteObject * obj, gboolean * is_advance, GError ** error) { - *is_advance = cfg.no_playlist_advance; + *is_advance = !cfg.no_playlist_advance; return TRUE; } diff --git a/src/audacious/drct.c b/src/audacious/drct.c index eab2af9..bf54653 100644 --- a/src/audacious/drct.c +++ b/src/audacious/drct.c @@ -327,6 +327,7 @@ static void activate_temp (void) playlist_insert (playlists); playlist_set_title (playlists, title); + playlist_set_active (playlists); } void drct_pl_open_temp (const gchar * filename) diff --git a/src/audacious/equalizer.c b/src/audacious/equalizer.c index def49dd..af13771 100644 --- a/src/audacious/equalizer.c +++ b/src/audacious/equalizer.c @@ -28,8 +28,11 @@ #define Q 1.2247449 /* Center frequencies for band-pass filters (Hz) */ -static const gfloat CF[EQ_BANDS] = {60, 170, 310, 600, 1000, 3000, 6000, 12000, - 14000, 16000}; +/* These are not the historical WinAmp frequencies, because the IIR filters used + * here are designed for each frequency to be twice the previous. Using WinAmp + * frequencies leads to too much gain in some bands and too little in others. */ +static const gfloat CF[EQ_BANDS] = {31.25, 62.5, 125, 250, 500, 1000, 2000, + 4000, 8000, 16000}; static GStaticMutex mutex = G_STATIC_MUTEX_INIT; static gboolean active; diff --git a/src/audacious/images/menu_randomize_playlist.png b/src/audacious/images/menu_randomize_playlist.png Binary files differdeleted file mode 100644 index d6405c2..0000000 --- a/src/audacious/images/menu_randomize_playlist.png +++ /dev/null diff --git a/src/audacious/interface.c b/src/audacious/interface.c index 2e51740..30f6cd2 100644 --- a/src/audacious/interface.c +++ b/src/audacious/interface.c @@ -19,7 +19,7 @@ * Audacious or using our public API to be a derived work. */ -#include <glib.h> +#include <string.h> #include <gtk/gtk.h> #include <libaudcore/hook.h> @@ -29,6 +29,7 @@ #include "debug.h" #include "i18n.h" #include "interface.h" +#include "plugins.h" #include "ui_preferences.h" static Interface *current_interface = NULL; @@ -185,39 +186,33 @@ interface_show_about_window(gboolean show) } } -/* void interface_run_gtk_plugin (GtkWidget * parent, const gchar * name) */ -void interface_run_gtk_plugin (void * parent, const gchar * name) +static gboolean delete_cb (GtkWidget * window, GdkEvent * event, PluginHandle * + plugin) { - if (interface_cbs.run_gtk_plugin != NULL) - interface_cbs.run_gtk_plugin(parent, name); - else { - GtkWidget *win; - - g_return_if_fail(parent != NULL); - g_return_if_fail(name != NULL); - - win = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW(win), _(name)); - gtk_container_add(GTK_CONTAINER(win), parent); - gtk_widget_show_all(win); + vis_plugin_enable (plugin, FALSE); + return TRUE; +} - g_object_set_data(G_OBJECT(parent), "parentwin", win); +void interface_add_plugin_widget (PluginHandle * plugin, GtkWidget * widget) +{ + if (interface_cbs.run_gtk_plugin != NULL) + interface_cbs.run_gtk_plugin (widget, plugin_get_name (plugin)); + else + { + GtkWidget * window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title ((GtkWindow *) window, plugin_get_name (plugin)); + gtk_container_add ((GtkContainer *) window, widget); + g_signal_connect (window, "delete-event", (GCallback) delete_cb, plugin); + gtk_widget_show_all (window); } } -/* void interface_stop_gtk_plugin (GtkWidget * parent) */ -void interface_stop_gtk_plugin (void * parent) +void interface_remove_plugin_widget (PluginHandle * plugin, GtkWidget * widget) { if (interface_cbs.stop_gtk_plugin != NULL) - interface_cbs.stop_gtk_plugin(parent); - else { - GtkWidget *win; - - g_return_if_fail(parent != NULL); - - win = g_object_get_data(G_OBJECT(parent), "parentwin"); - gtk_widget_destroy(win); - } + interface_cbs.stop_gtk_plugin (widget); + else + gtk_widget_destroy (gtk_widget_get_parent (widget)); } void diff --git a/src/audacious/interface.h b/src/audacious/interface.h index 52c4649..e03df24 100644 --- a/src/audacious/interface.h +++ b/src/audacious/interface.h @@ -30,9 +30,6 @@ #define __AUDACIOUS2_INTERFACE_H__ #include <glib.h> -#include <mowgli.h> - -#include <audacious/plugins.h> #include <audacious/types.h> typedef struct { @@ -74,6 +71,11 @@ struct _Interface { InterfaceOps *ops; }; +#ifdef _AUDACIOUS_CORE + +#include <gtk/gtk.h> +#include <audacious/plugins.h> + PluginHandle * interface_get_default (void); void interface_set_default (PluginHandle * plugin); gboolean interface_load (PluginHandle * plugin); @@ -87,9 +89,8 @@ void interface_hide_filebrowser(void); void interface_toggle_visibility(void); void interface_show_error_message(const gchar * markup); void interface_show_jump_to_track(void); -/* void interface_run_gtk_plugin (GtkWidget * parent, const gchar * name); */ -void interface_run_gtk_plugin (void * parent, const gchar * name); -/* void interface_stop_gtk_plugin (GtkWidget * parent); */ +void interface_add_plugin_widget (PluginHandle * plugin, GtkWidget * widget); +void interface_remove_plugin_widget (PluginHandle * plugin, GtkWidget * widget); void interface_stop_gtk_plugin (void * parent); void interface_toggle_shuffle(void); void interface_toggle_repeat(void); @@ -97,3 +98,4 @@ void interface_toggle_repeat(void); void register_interface_hooks(void); #endif +#endif diff --git a/src/audacious/main.c b/src/audacious/main.c index 3fa932c..c32fdcc 100644 --- a/src/audacious/main.c +++ b/src/audacious/main.c @@ -88,6 +88,7 @@ gchar * aud_paths[BMP_PATH_COUNT]; #ifdef USE_DBUS MprisPlayer *mpris; +MprisTrackList *mpris_tracklist; #endif static void print_version(void) @@ -123,9 +124,13 @@ static void aud_init_paths() gchar *xdg_data_home; gchar *xdg_cache_home; - xdg_config_home = (getenv("XDG_CONFIG_HOME") == NULL ? g_build_filename(g_get_home_dir(), ".config", NULL) : g_strdup(getenv("XDG_CONFIG_HOME"))); - xdg_data_home = (getenv("XDG_DATA_HOME") == NULL ? g_build_filename(g_get_home_dir(), ".local", "share", NULL) : g_strdup(getenv("XDG_DATA_HOME"))); - xdg_cache_home = (getenv("XDG_CACHE_HOME") == NULL ? g_build_filename(g_get_home_dir(), ".cache", NULL) : g_strdup(getenv("XDG_CACHE_HOME"))); + xdg_config_home = (getenv ("XDG_CONFIG_HOME") == NULL) ? g_build_filename + (getenv ("HOME"), ".config", NULL) : g_strdup (getenv ("XDG_CONFIG_HOME")); + xdg_data_home = (getenv ("XDG_DATA_HOME") == NULL) ? g_build_filename + (getenv ("HOME"), ".local", "share", NULL) : g_strdup (getenv + ("XDG_DATA_HOME")); + xdg_cache_home = (getenv ("XDG_CACHE_HOME") == NULL) ? g_build_filename + (getenv ("HOME"), ".cache", NULL) : g_strdup (getenv ("XDG_CACHE_HOME")); aud_paths[BMP_PATH_USER_DIR] = g_build_filename(xdg_config_home, "audacious", NULL); aud_paths[BMP_PATH_USER_SKIN_DIR] = g_build_filename(xdg_data_home, "audacious", "Skins", NULL); @@ -178,11 +183,6 @@ static void parse_cmd_line_options(gint * argc, gchar *** argv) memset(&options, '\0', sizeof(AudCmdLineOpt)); options.session = -1; - /* If audacious2 is run with no arguments, bring it to the top. This is - handy when the user forgets that Audacious is already running. */ - if (*argc == 1) - options.mainwin = 1; - context = g_option_context_new(_("- play multimedia files")); g_option_context_add_main_entries(context, cmd_entries, PACKAGE_NAME); g_option_context_add_group(context, gtk_get_option_group(FALSE)); @@ -410,6 +410,9 @@ void iface_plugin_set_active (PluginHandle * plugin) g_message ("Unloading %s.", plugin_get_name (current_iface)); interface_unload (); + current_iface = plugin; + interface_set_default (plugin); + g_message ("Starting %s.", plugin_get_name (plugin)); if (! interface_load (plugin)) { @@ -417,9 +420,6 @@ void iface_plugin_set_active (PluginHandle * plugin) exit (EXIT_FAILURE); } - current_iface = plugin; - interface_set_default (plugin); - g_message ("Loading visualizers."); vis_init (); } diff --git a/src/audacious/main.h b/src/audacious/main.h index 649e876..fccbe24 100644 --- a/src/audacious/main.h +++ b/src/audacious/main.h @@ -52,6 +52,7 @@ extern gchar *aud_paths[]; #ifdef USE_DBUS extern MprisPlayer *mpris; +extern MprisTrackList *mpris_tracklist; #endif void aud_quit(void); diff --git a/src/audacious/mpris_tracklist.xml b/src/audacious/mpris_tracklist.xml index 9fe2ec9..826fde2 100644 --- a/src/audacious/mpris_tracklist.xml +++ b/src/audacious/mpris_tracklist.xml @@ -43,5 +43,9 @@ <method name="Random"> <arg type="b" direction="in" /> </method> + + <signal name="TrackListChange"> + <arg type="i" /> + </signal> </interface> </node> diff --git a/src/audacious/playback.c b/src/audacious/playback.c index 3b8dd84..ff6b97b 100644 --- a/src/audacious/playback.c +++ b/src/audacious/playback.c @@ -533,11 +533,10 @@ void playback_seek (gint time) if (current_playback->plugin->mseek != NULL) current_playback->plugin->mseek (current_playback, time); - else + else if (current_playback->plugin->seek != NULL) { fprintf (stderr, "%s should be updated to provide mseek().\n", current_playback->plugin->description); - g_return_if_fail (current_playback->plugin->seek != NULL); current_playback->plugin->seek (current_playback, time / 1000); } diff --git a/src/audacious/playlist-new.c b/src/audacious/playlist-new.c index 750f626..fd9c16f 100644 --- a/src/audacious/playlist-new.c +++ b/src/audacious/playlist-new.c @@ -235,6 +235,12 @@ static void entry_set_tuple (struct playlist * playlist, struct entry * entry, } } +static void entry_set_failed (struct playlist * playlist, struct entry * entry) +{ + entry_set_tuple (playlist, entry, tuple_new_from_filename (entry->filename)); + entry->failed = TRUE; +} + static struct entry *entry_new(gchar * filename, InputPlugin * decoder, Tuple * tuple) { struct entry *entry = g_malloc(sizeof(struct entry)); @@ -266,15 +272,15 @@ static void entry_free(struct entry *entry) g_free(entry); } -static void entry_check_has_decoder (struct entry * entry) +static void entry_check_has_decoder (struct playlist * playlist, struct entry * + entry) { if (entry->decoder != NULL || entry->failed) return; entry->decoder = file_find_decoder (entry->filename, FALSE); - - if (entry->decoder == NULL) - entry->failed = TRUE; + if (! entry->decoder) + entry_set_failed (playlist, entry); } static struct playlist *playlist_new(void) @@ -380,10 +386,11 @@ void scan_receive (void) SCAN_DEBUG ("receive (#%d): %d\n", i, scan_positions[i]); entry = index_get (active_playlist->entries, scan_positions[i]); - entry_set_tuple (active_playlist, entry, scan_tuples[i]); - if (! scan_tuples[i]) - entry->failed = TRUE; + if (scan_tuples[i]) + entry_set_tuple (active_playlist, entry, scan_tuples[i]); + else + entry_set_failed (active_playlist, entry); scan_filenames[i] = NULL; scan_tuples[i] = NULL; @@ -422,8 +429,7 @@ static gboolean scan_next (void * unused) if (entry->tuple) continue; - entry_check_has_decoder (entry); - + entry_check_has_decoder (active_playlist, entry); if (entry->failed) continue; @@ -544,7 +550,7 @@ static gboolean scan_threaded (struct playlist * playlist, struct entry * entry) scan_next (NULL); - if (entry->tuple != NULL || entry->failed) + if (entry->tuple) return TRUE; for (i = 0; i < SCAN_THREADS; i ++) @@ -574,17 +580,19 @@ FOUND: static void check_scanned (struct playlist * playlist, struct entry * entry) { - if (entry->tuple != NULL || entry->failed) + if (entry->tuple) return; if (scan_threaded (playlist, entry)) return; - entry_check_has_decoder (entry); + entry_check_has_decoder (playlist, entry); + if (entry->failed) + return; + entry_set_tuple (playlist, entry, file_read_tuple (entry->filename, entry->decoder)); - if (! entry->tuple) - entry->failed = TRUE; + entry_set_failed (playlist, entry); queue_update (PLAYLIST_UPDATE_METADATA); } @@ -1019,7 +1027,7 @@ InputPlugin *playlist_entry_get_decoder(gint playlist_num, gint entry_num) LOOKUP_PLAYLIST_ENTRY_RET (NULL); - entry_check_has_decoder (entry); + entry_check_has_decoder (playlist, entry); return entry->decoder; } diff --git a/src/audacious/plugin-registry.c b/src/audacious/plugin-registry.c index 01bb0ff..15ec913 100644 --- a/src/audacious/plugin-registry.c +++ b/src/audacious/plugin-registry.c @@ -106,7 +106,7 @@ static PluginHandle * plugin_new (ModuleData * module, gint type, gint number, plugin->number = number; plugin->confirmed = confirmed; plugin->header = header; - plugin->name = 0; + plugin->name = NULL; plugin->priority = 0; plugin->has_about = FALSE; plugin->has_configure = FALSE; @@ -478,6 +478,7 @@ void plugin_register (const gchar * path, gint type, gint number, void * header) if (type == PLUGIN_TYPE_INPUT) { InputPlugin * ip = header; + g_free (plugin->name); plugin->name = g_strdup (ip->description); plugin->priority = ip->priority; plugin->has_about = (ip->about != NULL); @@ -501,6 +502,7 @@ void plugin_register (const gchar * path, gint type, gint number, void * header) else if (type == PLUGIN_TYPE_OUTPUT) { OutputPlugin * op = header; + g_free (plugin->name); plugin->name = g_strdup (op->description); plugin->priority = 10 - op->probe_priority; plugin->has_about = (op->about != NULL); @@ -509,6 +511,7 @@ void plugin_register (const gchar * path, gint type, gint number, void * header) else if (type == PLUGIN_TYPE_EFFECT) { EffectPlugin * ep = header; + g_free (plugin->name); plugin->name = g_strdup (ep->description); plugin->priority = ep->order; plugin->has_about = (ep->about != NULL); @@ -517,6 +520,7 @@ void plugin_register (const gchar * path, gint type, gint number, void * header) else if (type == PLUGIN_TYPE_VIS) { VisPlugin * vp = header; + g_free (plugin->name); plugin->name = g_strdup (vp->description); plugin->has_about = (vp->about != NULL); plugin->has_configure = (vp->configure != NULL); @@ -524,11 +528,13 @@ void plugin_register (const gchar * path, gint type, gint number, void * header) else if (type == PLUGIN_TYPE_IFACE) { Interface * i = header; + g_free (plugin->name); plugin->name = g_strdup (i->desc); } else if (type == PLUGIN_TYPE_GENERAL) { GeneralPlugin * gp = header; + g_free (plugin->name); plugin->name = g_strdup (gp->description); plugin->has_about = (gp->about != NULL); plugin->has_configure = (gp->configure != NULL); diff --git a/src/audacious/plugin.h b/src/audacious/plugin.h index 9f52676..c8b4534 100644 --- a/src/audacious/plugin.h +++ b/src/audacious/plugin.h @@ -334,51 +334,114 @@ struct _InputPlayback { struct _InputPlugin { PLUGIN_COMMON_FIELDS - gboolean have_subtune; /**< Plugin supports/uses subtunes. */ - gchar **vfs_extensions; /**< Filename extension to be associated to this plugin. */ - gint priority; /* 0 = first, 10 = last */ - - gint (*is_our_file_from_vfs) (const gchar *filename, VFSFile *fd); - Tuple *(*get_song_tuple) (const gchar * filename); - Tuple *(*probe_for_tuple) (const gchar *uri, VFSFile *fd); - - /** - * Plugin can provide this function for file metadata (aka tag) - * writing functionality when there is no reason to provide its - * own custom file info dialog. - * - * - In current Audacious version, if plugin provides file_info_box(), the latter will be used in any case. - * - Each field in tuple means operation on one and only one tag field: - * - Set this field to appropriate value, if non-empty string or positive number provided. - * - Set this field to blank (or just delete, at plugins`s discretion), if empty string or negative number provided. + /* Nonzero if the files handled by the plugin may contain more than one + * song. When reading the tuple for such a file, the plugin should set the + * FIELD_SUBSONG_NUM field to the number of songs in the file. For all + * other files, the field should be left unset. * - * @param[in] tuple Tuple with the desired metadata. - * @param[in] fd VFS file descriptor pointing to file to modify. + * Example: + * 1. User adds a file named "somefile.xxx" to the playlist. Having + * determined that this plugin can handle the file, Audacious opens the file + * and calls probe_for_tuple(). probe_for_tuple() sees that there are 3 + * songs in the file and sets FIELD_SUBSONG_NUM to 3. + * 2. For each song in the file, Audacious opens the file and calls + * probe_for_tuple() -- this time, however, a question mark and song number + * are appended to the file name passed: "somefile.sid?2" refers to the + * second song in the file "somefile.sid". + * 3. When one of the songs is played, Audacious opens the file and calls + * play() with a file name modified in this way. */ + gboolean have_subtune; + + /* Pointer to an array (terminated with NULL) of file extensions associated + * with file types the plugin can handle. */ + const gchar * const * vfs_extensions; + + /* How quickly the plugin should be tried in searching for a plugin to + * handle a file which could not be identified from its extension. Plugins + * with priority 0 are tried first, 10 last. */ + gint priority; + + /* Must return nonzero if the plugin can handle this file. If the file + * could not be opened, "file" will be NULL. (This is normal in the case of + * special URI schemes like cdda:// that do not represent actual files.) */ + /* Bug: The return value should be a gboolean, not a gint. */ + gint (* is_our_file_from_vfs) (const gchar * filename, VFSFile * file); + + /* Deprecated. */ + Tuple * (* get_song_tuple) (const gchar * filename); /* Use probe_for_tuple. */ + + /* Must return a tuple containing metadata for this file, or NULL if no + * metadata could be read. If the file could not be opened, "file" will be + * NULL. Audacious takes over one reference to the tuple returned. */ + Tuple * (* probe_for_tuple) (const gchar * filename, VFSFile * file); + + /* Optional. Must write metadata from a tuple to this file. Must return + * nonzero on success or zero on failure. "file" will never be NULL. */ + /* Bug: This function does not support special URI schemes like cdda://, + * since no file name is passed. */ gboolean (* update_song_tuple) (const Tuple * tuple, VFSFile * file); - void (*file_info_box) (const gchar * filename); - /* Warning: Check for file == NULL. */ + /* Optional, and not recommended. Must show a window with information about + * this file. If this function is provided, update_song_tuple should not be. */ + /* Bug: Implementing this function duplicates user interface code and code + * to open the file in each and every plugin. */ + void (* file_info_box) (const gchar * filename); + + /* Optional. Must try to read an "album art" image embedded in this file. + * Must return nonzero on success or zero on failure. If the file could not + * be opened, "file" will be NULL. On success, must fill "data" with a + * pointer to a block of data allocated with g_malloc and "size" with the + * size in bytes of that block. The data may be in any format supported by + * GTK. Audacious will free the data when it is no longer needed. */ gboolean (* get_song_image) (const gchar * filename, VFSFile * file, void * * data, gint * size); - /* Warning: Check for file == NULL. */ + /* Must try to play this file. "playback" is a structure containing output- + * related functions which the plugin may make use of. It also contains a + * "data" pointer which the plugin may use to refer private data associated + * with the playback state. This pointer can then be used from pause, + * mseek, and stop. If the file could not be opened, "file" will be NULL. + * "start_time" is the position in milliseconds at which to start from, or + * -1 to start from the beginning of the file. "stop_time" is the position + * in milliseconds at which to end playback, or -1 to play to the end of the + * file. "paused" specifies whether playback should immediately be paused. + * Must return nonzero if some of the file was successfully played or zero + * on failure. */ gboolean (* play) (InputPlayback * playback, const gchar * filename, VFSFile * file, gint start_time, gint stop_time, gboolean pause); - void (*pause) (InputPlayback * playback, gshort paused); - void (*mseek) (InputPlayback * playback, gulong millisecond); - void (*stop) (InputPlayback * playback); - - /* advanced: for plugins that do not use Audacious's output system */ - gint (*get_time) (InputPlayback * playback); - gint (*get_volume) (gint * l, gint * r); - gint (*set_volume) (gint l, gint r); - - /* deprecated */ - gint (*is_our_file) (const gchar * filename); - void (*play_file) (InputPlayback * playback); - void (*seek) (InputPlayback * playback, gint time); + /* Must pause or unpause a file currently being played. This function will + * be called from a different thread than play, but it will not be called + * before the plugin calls set_pb_ready or after stop is called. */ + /* Bug: paused should be a gboolean, not a gshort. */ + /* Bug: There is no way to indicate success or failure. */ + void (* pause) (InputPlayback * playback, gshort paused); + + /* Optional. Must seek to the given position in milliseconds within a file + * currently being played. This function will be called from a different + * thread than play, but it will not be called before the plugin calls + * set_pb_ready or after stop is called. */ + /* Bug: time should be a gint, not a gulong. */ + /* Bug: There is no way to indicate success or failure. */ + void (* mseek) (InputPlayback * playback, gulong time); + + /* Must signal a currently playing song to stop and cause play to return. + * This function will be called from a different thread than play. It will + * only be called once. It should not join the thread from which play is + * called. */ + void (* stop) (InputPlayback * playback); + + /* Advanced, for plugins that do not use Audacious's output system. Use at + * your own risk. */ + gint (* get_time) (InputPlayback * playback); + gint (* get_volume) (gint * l, gint * r); + gint (* set_volume) (gint l, gint r); + + /* Deprecated. */ + gint (* is_our_file) (const gchar * filename); /* Use is_our_file_from_vfs. */ + void (* play_file) (InputPlayback * playback); /* Use play. */ + void (* seek) (InputPlayback * playback, gint time); /* Use mseek. */ }; struct _GeneralPlugin { diff --git a/src/audacious/visualization.c b/src/audacious/visualization.c index 39a1293..30a821b 100644 --- a/src/audacious/visualization.c +++ b/src/audacious/visualization.c @@ -228,7 +228,7 @@ static void vis_load (PluginHandle * plugin) AUDDBG ("Adding %s to interface.\n", plugin_get_name (plugin)); g_signal_connect (vis->widget, "destroy", (GCallback) gtk_widget_destroyed, & vis->widget); - interface_run_gtk_plugin (vis->widget, plugin_get_name (plugin)); + interface_add_plugin_widget (plugin, vis->widget); } if (playback_get_playing ()) @@ -257,7 +257,7 @@ static void vis_unload (PluginHandle * plugin) if (vis->widget != NULL) { AUDDBG ("Removing %s from interface.\n", plugin_get_name (plugin)); - interface_stop_gtk_plugin (vis->widget); + interface_remove_plugin_widget (plugin, vis->widget); g_return_if_fail (vis->widget == NULL); /* not destroyed? */ } diff --git a/src/libaudcore/tuple_compiler.c b/src/libaudcore/tuple_compiler.c index 9eac1b2..18f84a5 100644 --- a/src/libaudcore/tuple_compiler.c +++ b/src/libaudcore/tuple_compiler.c @@ -118,9 +118,7 @@ void tuple_evalctx_free(TupleEvalContext *ctx) tuple_evalctx_free_function(ctx->functions[i]); g_free(ctx->functions); - - /* Zero context */ - memset(ctx, 0, sizeof(TupleEvalContext)); + g_free(ctx); } diff --git a/src/libaudcore/vfs_buffer.c b/src/libaudcore/vfs_buffer.c index a977fc7..e023e67 100644 --- a/src/libaudcore/vfs_buffer.c +++ b/src/libaudcore/vfs_buffer.c @@ -190,7 +190,7 @@ buffer_vfs_fsize_impl(VFSFile * file) handle = (VFSBuffer *) file->handle; - return (off_t)handle->end; + return (off_t) (handle->end - handle->data); } static VFSConstructor buffer_const = { diff --git a/src/libaudgui/equalizer.c b/src/libaudgui/equalizer.c index 795a105..6b642df 100644 --- a/src/libaudgui/equalizer.c +++ b/src/libaudgui/equalizer.c @@ -137,9 +137,9 @@ static GtkWidget * create_slider (const gchar * name, gfloat * setting) static GtkWidget * create_window (void) { - static const gchar * names[AUD_EQUALIZER_NBANDS] = {N_("60 Hz"), - N_("170 Hz"), N_("310 Hz"), N_("600 Hz"), N_("1 kHz"), N_("3 kHz"), - N_("6 kHz"), N_("12 kHz"), N_("14 kHz"), N_("16 kHz")}; + const gchar * const names[AUD_EQUALIZER_NBANDS] = {N_("31 Hz"), N_("63 Hz"), + N_("125 Hz"), N_("250 Hz"), N_("500 Hz"), N_("1 kHz"), N_("2 kHz"), + N_("4 kHz"), N_("8 kHz"), N_("16 kHz")}; GtkWidget * window, * vbox, * hbox; gint i; diff --git a/src/libaudtag/id3/id3v22.c b/src/libaudtag/id3/id3v22.c index 69b09ab..ceec8e2 100644 --- a/src/libaudtag/id3/id3v22.c +++ b/src/libaudtag/id3/id3v22.c @@ -21,7 +21,6 @@ * using our public API to be a derived work. */ -#define DEBUG #include <glib.h> #include <libaudcore/audstrings.h> @@ -96,7 +95,7 @@ static gboolean validate_header (ID3v2Header * header) if ((header->version != 2)) return FALSE; - header->size = GUINT32_FROM_BE (header->size); + header->size = unsyncsafe32(GUINT32_FROM_BE(header->size)); AUDDBG ("Found ID3v2 header:\n"); AUDDBG (" magic = %.3s\n", header->magic); @@ -545,7 +544,7 @@ static gboolean parse_pic (const guchar * data, gint size, gchar * * mime, static gboolean id3v22_read_image (VFSFile * handle, void * * image_data, gint * image_size) { - gint version, header_size, data_size, parsed, i; + gint version, header_size, data_size, parsed; gboolean syncsafe; gsize offset; gboolean found = FALSE; diff --git a/src/libaudtag/id3/id3v24.c b/src/libaudtag/id3/id3v24.c index 457559a..5d59a69 100644 --- a/src/libaudtag/id3/id3v24.c +++ b/src/libaudtag/id3/id3v24.c @@ -109,13 +109,6 @@ GenericFrame; #define ID3_FRAME_SYNCSAFE 0x0002 #define ID3_FRAME_HAS_LENGTH 0x0001 -#define TAG_SIZE 1 - -static mowgli_dictionary_t * frames = NULL; -static mowgli_list_t * frameIDs = NULL; - -#define write_syncsafe_int32(x) vfs_fput_be32 (syncsafe32 (x)) - static gboolean skip_extended_header_3 (VFSFile * handle, gint * _size) { guint32 size; @@ -378,7 +371,7 @@ static void free_generic_frame (GenericFrame * frame) } static void read_all_frames (VFSFile * handle, gint version, gboolean syncsafe, - gint data_size) + gint data_size, mowgli_dictionary_t * dict) { gint pos; @@ -393,21 +386,29 @@ static void read_all_frames (VFSFile * handle, gint version, gboolean syncsafe, & frame_size, key, & data, & size)) break; + pos += frame_size; + + if (mowgli_dictionary_retrieve (dict, key) != NULL) + { + AUDDBG ("Discarding duplicate frame %s.\n", key); + g_free (data); + continue; + } + frame = g_malloc (sizeof (GenericFrame)); strcpy (frame->key, key); frame->data = data; frame->size = size; - mowgli_dictionary_add (frames, frame->key, frame); - mowgli_node_add (frame->key, mowgli_node_create (), frameIDs); - - pos += frame_size; + mowgli_dictionary_add (dict, key, frame); } } static gboolean write_frame (VFSFile * handle, GenericFrame * frame, gint * frame_size) { + AUDDBG ("Writing frame %s, size %d\n", frame->key, frame->size); + ID3v2FrameHeader header; memcpy (header.key, frame->key, 4); @@ -426,24 +427,28 @@ static gboolean write_frame (VFSFile * handle, GenericFrame * frame, gint * return TRUE; } -static guint32 writeAllFramesToFile (VFSFile * fd) +typedef struct { + VFSFile * file; + gint written_size; +} WriteState; + +static gint write_frame_cb (mowgli_dictionary_elem_t * elem, void * user) { - guint32 size = 0; - mowgli_node_t *n, *tn; - MOWGLI_LIST_FOREACH_SAFE(n, tn, frameIDs->head) - { - GenericFrame *frame = (GenericFrame *) mowgli_dictionary_retrieve(frames, (gchar *) (n->data)); - if (frame) - { - gint frame_size; + WriteState * state = user; + gint size; + if (! write_frame (state->file, elem->data, & size)) + return -1; + state->written_size += size; + return 0; +} - if (! write_frame (fd, frame, & frame_size)) - break; +static gint writeAllFramesToFile (VFSFile * fd, mowgli_dictionary_t * dict) +{ + WriteState state = {fd, 0}; + mowgli_dictionary_foreach (dict, write_frame_cb, & state); - size += frame_size; - } - } - return size; + AUDDBG ("Total frame bytes written = %d.\n", state.written_size); + return state.written_size; } static gboolean write_header (VFSFile * handle, gint size, gboolean is_footer) @@ -722,16 +727,16 @@ static void decode_genre (Tuple * tuple, const guchar * data, gint size) return; } -static GenericFrame * add_generic_frame (gint id, gint size) +static GenericFrame * add_generic_frame (gint id, gint size, + mowgli_dictionary_t * dict) { - GenericFrame * frame = mowgli_dictionary_retrieve (frames, id3_frames[id]); + GenericFrame * frame = mowgli_dictionary_retrieve (dict, id3_frames[id]); if (frame == NULL) { frame = g_malloc (sizeof (GenericFrame)); strcpy (frame->key, id3_frames[id]); - mowgli_dictionary_add (frames, frame->key, frame); - mowgli_node_add (frame->key, mowgli_node_create (), frameIDs); + mowgli_dictionary_add (dict, frame->key, frame); } else g_free (frame->data); @@ -741,36 +746,69 @@ static GenericFrame * add_generic_frame (gint id, gint size) return frame; } -static void add_text_frame (gint id, const gchar * text) +static void remove_frame (gint id, mowgli_dictionary_t * dict) { + GenericFrame * frame = mowgli_dictionary_retrieve (dict, id3_frames[id]); + if (frame == NULL) + return; + + AUDDBG ("Deleting frame %s.\n", id3_frames[id]); + mowgli_dictionary_delete (dict, id3_frames[id]); + free_generic_frame (frame); +} + +static void add_text_frame (gint id, const gchar * text, mowgli_dictionary_t * + dict) +{ + if (text == NULL) + { + remove_frame (id, dict); + return; + } + + AUDDBG ("Adding text frame %s = %s.\n", id3_frames[id], text); gint length = strlen (text); - GenericFrame * frame = add_generic_frame (id, length + 1); + GenericFrame * frame = add_generic_frame (id, length + 1, dict); frame->data[0] = 3; /* UTF-8 encoding */ memcpy (frame->data + 1, text, length); } -static void add_comment_frame (const gchar * text) +static void add_comment_frame (const gchar * text, mowgli_dictionary_t * dict) { + if (text == NULL) + { + remove_frame (ID3_COMMENT, dict); + return; + } + + AUDDBG ("Adding comment frame = %s.\n", text); gint length = strlen (text); - GenericFrame * frame = add_generic_frame (ID3_COMMENT, length + 5); + GenericFrame * frame = add_generic_frame (ID3_COMMENT, length + 5, dict); frame->data[0] = 3; /* UTF-8 encoding */ strcpy ((gchar *) frame->data + 1, "eng"); /* well, it *might* be English */ memcpy (frame->data + 5, text, length); } -static void add_frameFromTupleStr (const Tuple * tuple, int field, int id3_field) +static void add_frameFromTupleStr (const Tuple * tuple, gint field, gint + id3_field, mowgli_dictionary_t * dict) { - add_text_frame (id3_field, tuple_get_string (tuple, field, NULL)); + add_text_frame (id3_field, tuple_get_string (tuple, field, NULL), dict); } -static void add_frameFromTupleInt (const Tuple * tuple, int field, int id3_field) +static void add_frameFromTupleInt (const Tuple * tuple, gint field, gint + id3_field, mowgli_dictionary_t * dict) { - gchar scratch[16]; + if (tuple_get_value_type (tuple, field, NULL) != TUPLE_INT) + { + remove_frame (id3_field, dict); + return; + } + gchar scratch[16]; snprintf (scratch, sizeof scratch, "%d", tuple_get_int (tuple, field, NULL)); - add_text_frame (id3_field, scratch); + add_text_frame (id3_field, scratch, dict); } static gboolean id3v24_can_handle_file (VFSFile * handle) @@ -944,12 +982,6 @@ static void free_frame_cb (mowgli_dictionary_elem_t * element, void * unused) free_generic_frame (element->data); } -static void free_frame_dictionary (void) -{ - mowgli_dictionary_destroy (frames, free_frame_cb, NULL); - frames = NULL; -} - static gboolean id3v24_write_tag (const Tuple * tuple, VFSFile * f) { gint version, header_size, data_size, footer_size; @@ -960,70 +992,50 @@ static gboolean id3v24_write_tag (const Tuple * tuple, VFSFile * f) & data_size, & footer_size)) return FALSE; - if (frameIDs != NULL) - { - mowgli_node_t *n, *tn; - MOWGLI_LIST_FOREACH_SAFE(n, tn, frameIDs->head) - { - mowgli_node_delete(n, frameIDs); - } - } - frameIDs = mowgli_list_create(); - //read all frames into generic frames; - frames = mowgli_dictionary_create(strcasecmp); - read_all_frames (f, version, syncsafe, data_size); + mowgli_dictionary_t * dict = mowgli_dictionary_create (strcasecmp); + read_all_frames (f, version, syncsafe, data_size, dict); //make the new frames from tuple and replace in the dictionary the old frames with the new ones - if (tuple_get_string(tuple, FIELD_ARTIST, NULL)) - add_frameFromTupleStr(tuple, FIELD_ARTIST, ID3_ARTIST); - - if (tuple_get_string(tuple, FIELD_TITLE, NULL)) - add_frameFromTupleStr(tuple, FIELD_TITLE, ID3_TITLE); - - if (tuple_get_string(tuple, FIELD_ALBUM, NULL)) - add_frameFromTupleStr(tuple, FIELD_ALBUM, ID3_ALBUM); - - if (tuple_get_string (tuple, FIELD_COMMENT, NULL) != NULL) - add_comment_frame (tuple_get_string (tuple, FIELD_COMMENT, NULL)); - - if (tuple_get_string(tuple, FIELD_GENRE, NULL)) - add_frameFromTupleStr(tuple, FIELD_GENRE, ID3_GENRE); - - if (tuple_get_int(tuple, FIELD_YEAR, NULL) != 0) - add_frameFromTupleInt(tuple, FIELD_YEAR, ID3_YEAR); - - if (tuple_get_int(tuple, FIELD_TRACK_NUMBER, NULL) != 0) - add_frameFromTupleInt(tuple, FIELD_TRACK_NUMBER, ID3_TRACKNR); + add_frameFromTupleStr (tuple, FIELD_TITLE, ID3_TITLE, dict); + add_frameFromTupleStr (tuple, FIELD_ARTIST, ID3_ARTIST, dict); + add_frameFromTupleStr (tuple, FIELD_ALBUM, ID3_ALBUM, dict); + add_frameFromTupleInt (tuple, FIELD_YEAR, ID3_YEAR, dict); + add_frameFromTupleInt (tuple, FIELD_TRACK_NUMBER, ID3_TRACKNR, dict); + add_frameFromTupleStr (tuple, FIELD_GENRE, ID3_GENRE, dict); + add_comment_frame (tuple_get_string (tuple, FIELD_COMMENT, NULL), dict); if (! offset) { if (! cut_beginning_tag (f, header_size + data_size + footer_size)) - return FALSE; + goto ERROR; } else { if (offset + header_size + data_size + footer_size != vfs_fsize (f)) - return FALSE; - + goto ERROR; if (vfs_ftruncate (f, offset)) - return FALSE; + goto ERROR; } offset = vfs_fsize (f); if (offset < 0 || vfs_fseek (f, offset, SEEK_SET) || ! write_header (f, 0, FALSE)) - return FALSE; + goto ERROR; - data_size = writeAllFramesToFile (f); - free_frame_dictionary (); + data_size = writeAllFramesToFile (f, dict); if (! write_header (f, data_size, TRUE) || vfs_fseek (f, offset, SEEK_SET) || ! write_header (f, data_size, FALSE)) - return FALSE; + goto ERROR; + mowgli_dictionary_destroy (dict, free_frame_cb, NULL); return TRUE; + +ERROR: + mowgli_dictionary_destroy (dict, free_frame_cb, NULL); + return FALSE; } tag_module_t id3v24 = |