diff options
author | Mateusz Łukasik <mati75@linuxmint.pl> | 2015-06-05 16:46:36 +0200 |
---|---|---|
committer | Mateusz Łukasik <mati75@linuxmint.pl> | 2015-06-05 16:46:36 +0200 |
commit | b541fedc97ad4ed5e658ce34ee50c74ad756f330 (patch) | |
tree | 5da244a1063a2529a5419083b2ea23f8fa76cb63 /src/audacious | |
parent | 5f4fd4397e8b75ad152aec919f59ecb039ac6105 (diff) |
Imported Upstream version 3.6.2
Diffstat (limited to 'src/audacious')
85 files changed, 1253 insertions, 16680 deletions
diff --git a/src/audacious/Makefile b/src/audacious/Makefile index bccf836..89a017e 100644 --- a/src/audacious/Makefile +++ b/src/audacious/Makefile @@ -1,79 +1,17 @@ include ../../extra.mk PROG = audacious${PROG_SUFFIX} -SRCS = adder.c \ - art.c \ - chardet.c \ - config.c \ - drct.c \ - effect.c \ - equalizer.c \ - equalizer_preset.c \ - fft.c \ - general.c \ - history.c \ - interface.c \ - main.c \ - output.c \ - playback.c \ - playlist-files.c \ - playlist-new.c \ - playlist-utils.c \ - pluginenum.c \ - plugin-preferences.c \ - plugin-registry.c \ - plugin-init.c \ - plugin-view.c \ - preferences.c \ - probe.c \ - probe-buffer.c \ - scanner.c \ - signals.c \ - ui_plugin_menu.c \ - ui_preferences.c \ - util.c \ - vis_runner.c \ - visualization.c \ - ui_albumart.c + +SRCS = main.cc \ + signals.cc \ + util.cc ifeq ($(HAVE_MSWINDOWS),yes) SRCS += audacious.rc endif -INCLUDES = api.h \ - api-alias-begin.h \ - api-alias-end.h \ - api-define-begin.h \ - api-define-end.h \ - debug.h \ - drct.h \ - drct-api.h \ - i18n.h \ - input.h \ - input-api.h \ - misc.h \ - misc-api.h \ - playlist.h \ - playlist-api.h \ - plugin.h \ - plugins.h \ - plugins-api.h \ - preferences.h \ - types.h - -DATA = images/about-logo.png \ - images/album.png \ - images/appearance.png \ - images/audio.png \ - images/connectivity.png \ - images/info.png \ - images/playlist.png \ - images/plugins.png - -CLEAN = build_stamp.c - ifeq ($(USE_DBUS),yes) -SRCS += dbus-server.c +SRCS += dbus-server.cc EXT_DEPS += ../dbus/aud-dbus.a endif @@ -84,30 +22,16 @@ CPPFLAGS := -I../dbus ${CPPFLAGS} ${GIO_CFLAGS} LIBS := ../dbus/aud-dbus.a ${LIBS} ${GIO_LIBS} endif +LD = ${CXX} + CPPFLAGS := -I.. -I../.. \ ${CPPFLAGS} \ - ${GLIB_CFLAGS} \ - ${GMODULE_CFLAGS} \ - ${GTK_CFLAGS} \ - ${LIBGUESS_CFLAGS} + ${GLIB_CFLAGS} -CPPFLAGS := ${CPPFLAGS} \ - -D_AUDACIOUS_CORE \ - -DHARDCODE_BINDIR=\"${bindir}\" \ - -DHARDCODE_DATADIR=\"${datadir}/audacious\" \ - -DHARDCODE_PLUGINDIR=\"${plugindir}\" \ - -DHARDCODE_LOCALEDIR=\"${localedir}\" \ - -DHARDCODE_DESKTOPFILE=\"${datarootdir}/applications/audacious.desktop\" \ - -DHARDCODE_ICONFILE=\"${datarootdir}/pixmaps/audacious.png\" +CPPFLAGS += -D_AUDACIOUS_CORE LIBS := -L../libaudcore -laudcore \ - -L../libaudgui -laudgui \ - -L../libaudtag -laudtag \ ${LIBS} -lm \ - ${LIBINTL} \ - ${GLIB_LIBS} \ - ${GMODULE_LIBS} \ - ${GTK_LIBS} + ${LIBINTL} \ + ${GLIB_LIBS} -desktop_DATA = audacious.desktop -desktopdir = ${datarootdir}/applications diff --git a/src/audacious/adder.c b/src/audacious/adder.c deleted file mode 100644 index 509f363..0000000 --- a/src/audacious/adder.c +++ /dev/null @@ -1,573 +0,0 @@ -/* - * adder.c - * Copyright 2011-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <pthread.h> -#include <string.h> -#include <sys/stat.h> - -#include <glib/gstdio.h> -#include <gtk/gtk.h> - -#include <libaudcore/audstrings.h> -#include <libaudcore/hook.h> - -#include "drct.h" -#include "i18n.h" -#include "playlist.h" -#include "plugins.h" -#include "main.h" -#include "misc.h" -#include "util.h" - -typedef struct { - int playlist_id, at; - bool_t play; - Index * filenames, * tuples; - PlaylistFilterFunc filter; - void * user; -} AddTask; - -typedef struct { - int playlist_id, at; - bool_t play; - char * title; - Index * filenames, * tuples, * decoders; -} AddResult; - -static GList * add_tasks = NULL; -static GList * add_results = NULL; -static int current_playlist_id = -1; - -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; -static bool_t add_quit; -static pthread_t add_thread; -static int add_source = 0; - -static int status_source = 0; -static char status_path[512]; -static int status_count; -static GtkWidget * status_window = NULL, * status_path_label, - * status_count_label; - -static bool_t status_cb (void * unused) -{ - if (! headless_mode () && ! status_window) - { - status_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_type_hint ((GtkWindow *) status_window, - GDK_WINDOW_TYPE_HINT_DIALOG); - gtk_window_set_title ((GtkWindow *) status_window, _("Searching ...")); - gtk_window_set_resizable ((GtkWindow *) status_window, FALSE); - gtk_container_set_border_width ((GtkContainer *) status_window, 6); - - GtkWidget * vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); - gtk_container_add ((GtkContainer *) status_window, vbox); - - status_path_label = gtk_label_new (NULL); - gtk_label_set_width_chars ((GtkLabel *) status_path_label, 40); - gtk_label_set_max_width_chars ((GtkLabel *) status_path_label, 40); - gtk_label_set_ellipsize ((GtkLabel *) status_path_label, - PANGO_ELLIPSIZE_MIDDLE); - gtk_box_pack_start ((GtkBox *) vbox, status_path_label, FALSE, FALSE, 0); - - status_count_label = gtk_label_new (NULL); - gtk_label_set_width_chars ((GtkLabel *) status_count_label, 40); - gtk_label_set_max_width_chars ((GtkLabel *) status_count_label, 40); - gtk_box_pack_start ((GtkBox *) vbox, status_count_label, FALSE, FALSE, 0); - - gtk_widget_show_all (status_window); - - g_signal_connect (status_window, "destroy", (GCallback) - gtk_widget_destroyed, & status_window); - } - - pthread_mutex_lock (& mutex); - - char scratch[128]; - snprintf (scratch, sizeof scratch, dngettext (PACKAGE, "%d file found", - "%d files found", status_count), status_count); - - if (headless_mode ()) - { - printf ("Searching, %s ...\r", scratch); - fflush (stdout); - } - else - { - gtk_label_set_text ((GtkLabel *) status_path_label, status_path); - gtk_label_set_text ((GtkLabel *) status_count_label, scratch); - } - - pthread_mutex_unlock (& mutex); - return TRUE; -} - -static void status_update (const char * filename, int found) -{ - pthread_mutex_lock (& mutex); - - snprintf (status_path, sizeof status_path, "%s", filename); - status_count = found; - - if (! status_source) - status_source = g_timeout_add (250, status_cb, NULL); - - pthread_mutex_unlock (& mutex); -} - -static void status_done_locked (void) -{ - if (status_source) - { - g_source_remove (status_source); - status_source = 0; - } - - if (headless_mode ()) - printf ("\n"); - else if (status_window) - gtk_widget_destroy (status_window); -} - -static AddTask * add_task_new (int playlist_id, int at, bool_t play, - Index * filenames, Index * tuples, PlaylistFilterFunc filter, - void * user) -{ - AddTask * task = g_slice_new (AddTask); - task->playlist_id = playlist_id; - task->at = at; - task->play = play; - task->filenames = filenames; - task->tuples = tuples; - task->filter = filter; - task->user = user; - return task; -} - -static void add_task_free (AddTask * task) -{ - if (task->filenames) - index_free_full (task->filenames, (IndexFreeFunc) str_unref); - if (task->tuples) - index_free_full (task->tuples, (IndexFreeFunc) tuple_unref); - - g_slice_free (AddTask, task); -} - -static AddResult * add_result_new (int playlist_id, int at, bool_t play) -{ - AddResult * result = g_slice_new (AddResult); - result->playlist_id = playlist_id; - result->at = at; - result->play = play; - result->title = NULL; - result->filenames = index_new (); - result->tuples = index_new (); - result->decoders = index_new (); - return result; -} - -static void add_result_free (AddResult * result) -{ - str_unref (result->title); - - if (result->filenames) - index_free_full (result->filenames, (IndexFreeFunc) str_unref); - if (result->tuples) - index_free_full (result->tuples, (IndexFreeFunc) tuple_unref); - if (result->decoders) - index_free (result->decoders); - - g_slice_free (AddResult, result); -} - -static void add_file (char * filename, Tuple * tuple, PluginHandle * decoder, - PlaylistFilterFunc filter, void * user, AddResult * result, bool_t validate) -{ - g_return_if_fail (filename); - if (filter && ! filter (filename, user)) - { - str_unref (filename); - return; - } - - status_update (filename, index_count (result->filenames)); - - if (! tuple && ! decoder) - { - decoder = file_find_decoder (filename, TRUE); - if (validate && ! decoder) - { - str_unref (filename); - return; - } - } - - if (! tuple && decoder && input_plugin_has_subtunes (decoder) && ! strchr - (filename, '?')) - tuple = file_read_tuple (filename, decoder); - - int n_subtunes = tuple ? tuple_get_n_subtunes (tuple) : 0; - - if (n_subtunes) - { - for (int sub = 0; sub < n_subtunes; sub ++) - { - char * subname = str_printf ("%s?%d", filename, - tuple_get_nth_subtune (tuple, sub)); - add_file (subname, NULL, decoder, filter, user, result, FALSE); - } - - str_unref (filename); - tuple_unref (tuple); - return; - } - - index_insert (result->filenames, -1, filename); - index_insert (result->tuples, -1, tuple); - index_insert (result->decoders, -1, decoder); -} - -static void add_folder (char * filename, PlaylistFilterFunc filter, - void * user, AddResult * result, bool_t is_single) -{ - char * path = NULL; - - g_return_if_fail (filename); - - if (filter && ! filter (filename, user)) - goto DONE; - - status_update (filename, index_count (result->filenames)); - - if (! (path = uri_to_filename (filename))) - goto DONE; - - GList * files = NULL; - GDir * folder = g_dir_open (path, 0, NULL); - if (! folder) - goto DONE; - - const char * name; - while ((name = g_dir_read_name (folder))) - { - char * filepath = filename_build (path, name); - files = g_list_prepend (files, filepath); - } - - g_dir_close (folder); - - if (files && is_single) - { - char * last = last_path_element (path); - result->title = str_get (last ? last : path); - } - - files = g_list_sort (files, (GCompareFunc) str_compare); - - while (files) - { - GStatBuf info; - if (g_lstat (files->data, & info) < 0) - goto NEXT; - - if (S_ISREG (info.st_mode)) - { - char * item_name = filename_to_uri (files->data); - if (item_name) - add_file (item_name, NULL, NULL, filter, user, result, TRUE); - } - else if (S_ISDIR (info.st_mode)) - { - char * item_name = filename_to_uri (files->data); - if (item_name) - add_folder (item_name, filter, user, result, FALSE); - } - - NEXT: - str_unref (files->data); - files = g_list_delete_link (files, files); - } - -DONE: - str_unref (filename); - str_unref (path); -} - -static void add_playlist (char * filename, PlaylistFilterFunc filter, - void * user, AddResult * result, bool_t is_single) -{ - g_return_if_fail (filename); - if (filter && ! filter (filename, user)) - { - str_unref (filename); - return; - } - - status_update (filename, index_count (result->filenames)); - - char * title = NULL; - Index * filenames, * tuples; - if (! playlist_load (filename, & title, & filenames, & tuples)) - { - str_unref (filename); - return; - } - - if (is_single) - result->title = title; - else - str_unref (title); - - int count = index_count (filenames); - for (int i = 0; i < count; i ++) - add_file (index_get (filenames, i), tuples ? index_get (tuples, i) : - NULL, NULL, filter, user, result, FALSE); - - str_unref (filename); - index_free (filenames); - if (tuples) - index_free (tuples); -} - -static void add_generic (char * filename, Tuple * tuple, - PlaylistFilterFunc filter, void * user, AddResult * result, bool_t is_single) -{ - g_return_if_fail (filename); - - if (tuple) - add_file (filename, tuple, NULL, filter, user, result, FALSE); - else if (vfs_file_test (filename, G_FILE_TEST_IS_DIR)) - add_folder (filename, filter, user, result, is_single); - else if (filename_is_playlist (filename)) - add_playlist (filename, filter, user, result, is_single); - else - add_file (filename, NULL, NULL, filter, user, result, FALSE); -} - -static bool_t add_finish (void * unused) -{ - pthread_mutex_lock (& mutex); - - while (add_results) - { - AddResult * result = add_results->data; - add_results = g_list_delete_link (add_results, add_results); - - int playlist = playlist_by_unique_id (result->playlist_id); - if (playlist < 0) /* playlist deleted */ - goto FREE; - - int count = playlist_entry_count (playlist); - if (result->at < 0 || result->at > count) - result->at = count; - - if (result->title && ! count) - { - char * old_title = playlist_get_title (playlist); - - if (! strcmp (old_title, N_("New Playlist"))) - playlist_set_title (playlist, result->title); - - str_unref (old_title); - } - - playlist_entry_insert_batch_raw (playlist, result->at, - result->filenames, result->tuples, result->decoders); - result->filenames = NULL; - result->tuples = NULL; - result->decoders = NULL; - - if (result->play && playlist_entry_count (playlist) > count) - { - if (! get_bool (NULL, "shuffle")) - playlist_set_position (playlist, result->at); - - drct_play_playlist (playlist); - } - - FREE: - add_result_free (result); - } - - if (add_source) - { - g_source_remove (add_source); - add_source = 0; - } - - if (! add_tasks) - status_done_locked (); - - pthread_mutex_unlock (& mutex); - - hook_call ("playlist add complete", NULL); - return FALSE; -} - -static void * add_worker (void * unused) -{ - pthread_mutex_lock (& mutex); - - while (! add_quit) - { - if (! add_tasks) - { - pthread_cond_wait (& cond, & mutex); - continue; - } - - AddTask * task = add_tasks->data; - add_tasks = g_list_delete_link (add_tasks, add_tasks); - - current_playlist_id = task->playlist_id; - pthread_mutex_unlock (& mutex); - - AddResult * result = add_result_new (task->playlist_id, task->at, - task->play); - - int count = index_count (task->filenames); - if (task->tuples) - count = MIN (count, index_count (task->tuples)); - - for (int i = 0; i < count; i ++) - { - add_generic (index_get (task->filenames, i), task->tuples ? - index_get (task->tuples, i) : NULL, task->filter, task->user, - result, (count == 1)); - - index_set (task->filenames, i, NULL); - if (task->tuples) - index_set (task->tuples, i, NULL); - } - - add_task_free (task); - - pthread_mutex_lock (& mutex); - current_playlist_id = -1; - - add_results = g_list_append (add_results, result); - - if (! add_source) - add_source = g_timeout_add (0, add_finish, NULL); - } - - pthread_mutex_unlock (& mutex); - return NULL; -} - -void adder_init (void) -{ - pthread_mutex_lock (& mutex); - add_quit = FALSE; - pthread_create (& add_thread, NULL, add_worker, NULL); - pthread_mutex_unlock (& mutex); -} - -void adder_cleanup (void) -{ - pthread_mutex_lock (& mutex); - add_quit = TRUE; - pthread_cond_broadcast (& cond); - pthread_mutex_unlock (& mutex); - pthread_join (add_thread, NULL); - - g_list_free_full (add_tasks, (GDestroyNotify) add_task_free); - add_tasks = NULL; - g_list_free_full (add_results, (GDestroyNotify) add_result_free); - add_results = NULL; - - if (add_source) - { - g_source_remove (add_source); - add_source = 0; - } - - status_done_locked (); -} - -void playlist_entry_insert (int playlist, int at, const char * filename, - Tuple * tuple, bool_t play) -{ - Index * filenames = index_new (); - Index * tuples = index_new (); - index_insert (filenames, -1, str_get (filename)); - index_insert (tuples, -1, tuple); - - playlist_entry_insert_batch (playlist, at, filenames, tuples, play); -} - -void playlist_entry_insert_batch (int playlist, int at, - Index * filenames, Index * tuples, bool_t play) -{ - playlist_entry_insert_filtered (playlist, at, filenames, tuples, NULL, NULL, play); -} - -void playlist_entry_insert_filtered (int playlist, int at, - Index * filenames, Index * tuples, PlaylistFilterFunc filter, - void * user, bool_t play) -{ - int playlist_id = playlist_get_unique_id (playlist); - g_return_if_fail (playlist_id >= 0); - - AddTask * task = add_task_new (playlist_id, at, play, filenames, tuples, filter, user); - - pthread_mutex_lock (& mutex); - add_tasks = g_list_append (add_tasks, task); - pthread_cond_broadcast (& cond); - pthread_mutex_unlock (& mutex); -} - -bool_t playlist_add_in_progress (int playlist) -{ - pthread_mutex_lock (& mutex); - - if (playlist >= 0) - { - int playlist_id = playlist_get_unique_id (playlist); - - for (GList * node = add_tasks; node; node = node->next) - { - if (((AddTask *) node->data)->playlist_id == playlist_id) - goto YES; - } - - if (current_playlist_id == playlist_id) - goto YES; - - for (GList * node = add_results; node; node = node->next) - { - if (((AddResult *) node->data)->playlist_id == playlist_id) - goto YES; - } - } - else - { - if (add_tasks || current_playlist_id >= 0 || add_results) - goto YES; - } - - pthread_mutex_unlock (& mutex); - return FALSE; - -YES: - pthread_mutex_unlock (& mutex); - return TRUE; -} diff --git a/src/audacious/api-alias-begin.h b/src/audacious/api-alias-begin.h deleted file mode 100644 index 457d29d..0000000 --- a/src/audacious/api-alias-begin.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * api-alias-begin.h - * Copyright 2010-2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#if ! defined AUD_API_NAME || ! defined AUD_API_SYMBOL || defined AUD_API_ALIAS -#error Bad usage of api-alias-begin.h -#endif - -#define AUD_API_ALIAS - -extern AudAPITable * _aud_api_table; - -#define AUD_FUNC0(t,n) static inline t aud_##n(void) {return _aud_api_table->AUD_API_SYMBOL->n();} -#define AUD_FUNC1(t,n,t1,n1) static inline t aud_##n(t1 n1) {return _aud_api_table->AUD_API_SYMBOL->n(n1);} -#define AUD_FUNC2(t,n,t1,n1,t2,n2) static inline t aud_##n(t1 n1, t2 n2) {return _aud_api_table->AUD_API_SYMBOL->n(n1,n2);} -#define AUD_FUNC3(t,n,t1,n1,t2,n2,t3,n3) static inline t aud_##n(t1 n1, t2 n2, t3 n3) {return _aud_api_table->AUD_API_SYMBOL->n(n1,n2,n3);} -#define AUD_FUNC4(t,n,t1,n1,t2,n2,t3,n3,t4,n4) static inline t aud_##n(t1 n1, t2 n2, t3 n3, t4 n4) {return _aud_api_table->AUD_API_SYMBOL->n(n1,n2,n3,n4);} -#define AUD_FUNC5(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5) static inline t aud_##n(t1 n1, t2 n2, t3 n3, t4 n4, t5 n5) {return _aud_api_table->AUD_API_SYMBOL->n(n1,n2,n3,n4,n5);} -#define AUD_FUNC6(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6) static inline t aud_##n(t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6) {return _aud_api_table->AUD_API_SYMBOL->n(n1,n2,n3,n4,n5,n6);} -#define AUD_FUNC7(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7) static inline t aud_##n(t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6, t7 n7) {return _aud_api_table->AUD_API_SYMBOL->n(n1,n2,n3,n4,n5,n6,n7);} -#define AUD_FUNC8(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7,t8,n8) static inline t aud_##n(t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6, t7 n7, t8 n8) {return _aud_api_table->AUD_API_SYMBOL->n(n1,n2,n3,n4,n5,n6,n7,n8);} - -#define AUD_VFUNC0(n) static inline void aud_##n(void) {_aud_api_table->AUD_API_SYMBOL->n();} -#define AUD_VFUNC1(n,t1,n1) static inline void aud_##n(t1 n1) {_aud_api_table->AUD_API_SYMBOL->n(n1);} -#define AUD_VFUNC2(n,t1,n1,t2,n2) static inline void aud_##n(t1 n1, t2 n2) {_aud_api_table->AUD_API_SYMBOL->n(n1,n2);} -#define AUD_VFUNC3(n,t1,n1,t2,n2,t3,n3) static inline void aud_##n(t1 n1, t2 n2, t3 n3) {_aud_api_table->AUD_API_SYMBOL->n(n1,n2,n3);} -#define AUD_VFUNC4(n,t1,n1,t2,n2,t3,n3,t4,n4) static inline void aud_##n(t1 n1, t2 n2, t3 n3, t4 n4) {_aud_api_table->AUD_API_SYMBOL->n(n1,n2,n3,n4);} -#define AUD_VFUNC5(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5) static inline void aud_##n(t1 n1, t2 n2, t3 n3, t4 n4, t5 n5) {_aud_api_table->AUD_API_SYMBOL->n(n1,n2,n3,n4,n5);} -#define AUD_VFUNC6(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6) static inline void aud_##n(t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6) {_aud_api_table->AUD_API_SYMBOL->n(n1,n2,n3,n4,n5,n6);} -#define AUD_VFUNC7(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7) static inline void aud_##n(t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6, t7 n7) {_aud_api_table->AUD_API_SYMBOL->n(n1,n2,n3,n4,n5,n6,n7);} -#define AUD_VFUNC8(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7,t8,n8) static inline void aud_##n(t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6, t7 n7, t8 n8) {_aud_api_table->AUD_API_SYMBOL->n(n1,n2,n3,n4,n5,n6,n7,n8);} diff --git a/src/audacious/api-alias-end.h b/src/audacious/api-alias-end.h deleted file mode 100644 index a003cde..0000000 --- a/src/audacious/api-alias-end.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * api-alias-end.h - * Copyright 2010-2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#if ! defined AUD_API_NAME || ! defined AUD_API_SYMBOL || ! defined AUD_API_ALIAS -#error Bad usage of api-alias-end.h -#endif - -#undef AUD_API_ALIAS - -#undef AUD_FUNC0 -#undef AUD_FUNC1 -#undef AUD_FUNC2 -#undef AUD_FUNC3 -#undef AUD_FUNC4 -#undef AUD_FUNC5 -#undef AUD_FUNC6 -#undef AUD_FUNC7 -#undef AUD_FUNC8 - -#undef AUD_VFUNC0 -#undef AUD_VFUNC1 -#undef AUD_VFUNC2 -#undef AUD_VFUNC3 -#undef AUD_VFUNC4 -#undef AUD_VFUNC5 -#undef AUD_VFUNC6 -#undef AUD_VFUNC7 -#undef AUD_VFUNC8 diff --git a/src/audacious/api-declare-begin.h b/src/audacious/api-declare-begin.h deleted file mode 100644 index defc557..0000000 --- a/src/audacious/api-declare-begin.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * api-declare-begin.h - * Copyright 2010-2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#if ! defined AUD_API_NAME || ! defined AUD_API_SYMBOL || defined AUD_API_DECLARE_H -#error Bad usage of api-declare-begin.h -#endif - -#define AUD_API_DECLARE_H - -#define AUD_FUNC0(t,n) .n = n, -#define AUD_FUNC1(t,n,t1,n1) .n = n, -#define AUD_FUNC2(t,n,t1,n1,t2,n2) .n = n, -#define AUD_FUNC3(t,n,t1,n1,t2,n2,t3,n3) .n = n, -#define AUD_FUNC4(t,n,t1,n1,t2,n2,t3,n3,t4,n4) .n = n, -#define AUD_FUNC5(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5) .n = n, -#define AUD_FUNC6(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6) .n = n, -#define AUD_FUNC7(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7) .n = n, -#define AUD_FUNC8(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7,t8,n8) .n = n, - -#define AUD_VFUNC0(n) .n = n, -#define AUD_VFUNC1(n,t1,n1) .n = n, -#define AUD_VFUNC2(n,t1,n1,t2,n2) .n = n, -#define AUD_VFUNC3(n,t1,n1,t2,n2,t3,n3) .n = n, -#define AUD_VFUNC4(n,t1,n1,t2,n2,t3,n3,t4,n4) .n = n, -#define AUD_VFUNC5(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5) .n = n, -#define AUD_VFUNC6(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6) .n = n, -#define AUD_VFUNC7(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7) .n = n, -#define AUD_VFUNC8(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7,t8,n8) .n = n, - -const struct AUD_API_NAME AUD_API_SYMBOL = { diff --git a/src/audacious/api-declare-end.h b/src/audacious/api-declare-end.h deleted file mode 100644 index fa73092..0000000 --- a/src/audacious/api-declare-end.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * api-declare-end.h - * Copyright 2010-2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#if ! defined AUD_API_NAME || ! defined AUD_API_SYMBOL || ! defined AUD_API_DECLARE_H -#error Bad usage of api-declare-end.h -#endif - -}; - -#undef AUD_API_DECLARE_H - -#undef AUD_FUNC0 -#undef AUD_FUNC1 -#undef AUD_FUNC2 -#undef AUD_FUNC3 -#undef AUD_FUNC4 -#undef AUD_FUNC5 -#undef AUD_FUNC6 -#undef AUD_FUNC7 -#undef AUD_FUNC8 - -#undef AUD_VFUNC0 -#undef AUD_VFUNC1 -#undef AUD_VFUNC2 -#undef AUD_VFUNC3 -#undef AUD_VFUNC4 -#undef AUD_VFUNC5 -#undef AUD_VFUNC6 -#undef AUD_VFUNC7 -#undef AUD_VFUNC8 diff --git a/src/audacious/api-define-begin.h b/src/audacious/api-define-begin.h deleted file mode 100644 index 5fe32cd..0000000 --- a/src/audacious/api-define-begin.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * api-define-begin.h - * Copyright 2010-2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#if ! defined AUD_API_NAME || ! defined AUD_API_SYMBOL || defined AUD_API_DEFINE_H -#error Bad usage of api-define-begin.h -#endif - -#define AUD_API_DEFINE_H - -#define AUD_FUNC0(t,n) t (* n) (void); -#define AUD_FUNC1(t,n,t1,n1) t (* n) (t1 n1); -#define AUD_FUNC2(t,n,t1,n1,t2,n2) t (* n) (t1 n1, t2 n2); -#define AUD_FUNC3(t,n,t1,n1,t2,n2,t3,n3) t (* n) (t1 n1, t2 n2, t3 n3); -#define AUD_FUNC4(t,n,t1,n1,t2,n2,t3,n3,t4,n4) t (* n) (t1 n1, t2 n2, t3 n3, t4 n4); -#define AUD_FUNC5(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5) t (* n) (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5); -#define AUD_FUNC6(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6) t (* n) (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6); -#define AUD_FUNC7(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7) t (* n) (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6, t7 n7); -#define AUD_FUNC8(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7,t8,n8) t (* n) (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6, t7 n7, t8 n8); - -#define AUD_VFUNC0(n) void (* n) (void); -#define AUD_VFUNC1(n,t1,n1) void (* n) (t1 n1); -#define AUD_VFUNC2(n,t1,n1,t2,n2) void (* n) (t1 n1, t2 n2); -#define AUD_VFUNC3(n,t1,n1,t2,n2,t3,n3) void (* n) (t1 n1, t2 n2, t3 n3); -#define AUD_VFUNC4(n,t1,n1,t2,n2,t3,n3,t4,n4) void (* n) (t1 n1, t2 n2, t3 n3, t4 n4); -#define AUD_VFUNC5(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5) void (* n) (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5); -#define AUD_VFUNC6(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6) void (* n) (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6); -#define AUD_VFUNC7(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7) void (* n) (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6, t7 n7); -#define AUD_VFUNC8(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7,t8,n8) void (* n) (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6, t7 n7, t8 n8); - -struct AUD_API_NAME { diff --git a/src/audacious/api-define-end.h b/src/audacious/api-define-end.h deleted file mode 100644 index 91bd85f..0000000 --- a/src/audacious/api-define-end.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * api-define-end.h - * Copyright 2010-2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#if ! defined AUD_API_NAME || ! defined AUD_API_SYMBOL || ! defined AUD_API_DEFINE_H -#error Bad usage of api-define-end.h -#endif - -}; - -#undef AUD_API_DEFINE_H - -#undef AUD_FUNC0 -#undef AUD_FUNC1 -#undef AUD_FUNC2 -#undef AUD_FUNC3 -#undef AUD_FUNC4 -#undef AUD_FUNC5 -#undef AUD_FUNC6 -#undef AUD_FUNC7 -#undef AUD_FUNC8 - -#undef AUD_VFUNC0 -#undef AUD_VFUNC1 -#undef AUD_VFUNC2 -#undef AUD_VFUNC3 -#undef AUD_VFUNC4 -#undef AUD_VFUNC5 -#undef AUD_VFUNC6 -#undef AUD_VFUNC7 -#undef AUD_VFUNC8 diff --git a/src/audacious/api-local-begin.h b/src/audacious/api-local-begin.h deleted file mode 100644 index b32eeb1..0000000 --- a/src/audacious/api-local-begin.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * api-local-begin.h - * Copyright 2010-2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#if ! defined AUD_API_NAME || ! defined AUD_API_SYMBOL || defined AUD_API_LOCAL_H -#error Bad usage of api-local-begin.h -#endif - -#define AUD_API_LOCAL_H - -#define AUD_FUNC0(t,n) t n (void); -#define AUD_FUNC1(t,n,t1,n1) t n (t1 n1); -#define AUD_FUNC2(t,n,t1,n1,t2,n2) t n (t1 n1, t2 n2); -#define AUD_FUNC3(t,n,t1,n1,t2,n2,t3,n3) t n (t1 n1, t2 n2, t3 n3); -#define AUD_FUNC4(t,n,t1,n1,t2,n2,t3,n3,t4,n4) t n (t1 n1, t2 n2, t3 n3, t4 n4); -#define AUD_FUNC5(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5) t n (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5); -#define AUD_FUNC6(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6) t n (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6); -#define AUD_FUNC7(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7) t n (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6, t7 n7); -#define AUD_FUNC8(t,n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7,t8,n8) t n (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6, t7 n7, t8 n8); - -#define AUD_VFUNC0(n) void n (void); -#define AUD_VFUNC1(n,t1,n1) void n (t1 n1); -#define AUD_VFUNC2(n,t1,n1,t2,n2) void n (t1 n1, t2 n2); -#define AUD_VFUNC3(n,t1,n1,t2,n2,t3,n3) void n (t1 n1, t2 n2, t3 n3); -#define AUD_VFUNC4(n,t1,n1,t2,n2,t3,n3,t4,n4) void n (t1 n1, t2 n2, t3 n3, t4 n4); -#define AUD_VFUNC5(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5) void n (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5); -#define AUD_VFUNC6(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6) void n (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6); -#define AUD_VFUNC7(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7) void n (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6, t7 n7); -#define AUD_VFUNC8(n,t1,n1,t2,n2,t3,n3,t4,n4,t5,n5,t6,n6,t7,n7,t8,n8) void n (t1 n1, t2 n2, t3 n3, t4 n4, t5 n5, t6 n6, t7 n7, t8 n8); diff --git a/src/audacious/api-local-end.h b/src/audacious/api-local-end.h deleted file mode 100644 index 81ec43d..0000000 --- a/src/audacious/api-local-end.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * api-local-end.h - * Copyright 2010-2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#if ! defined AUD_API_NAME || ! defined AUD_API_SYMBOL || ! defined AUD_API_LOCAL_H -#error Bad usage of api-local-end.h -#endif - -#undef AUD_API_LOCAL_H - -#undef AUD_FUNC0 -#undef AUD_FUNC1 -#undef AUD_FUNC2 -#undef AUD_FUNC3 -#undef AUD_FUNC4 -#undef AUD_FUNC5 -#undef AUD_FUNC6 -#undef AUD_FUNC7 -#undef AUD_FUNC8 - -#undef AUD_VFUNC0 -#undef AUD_VFUNC1 -#undef AUD_VFUNC2 -#undef AUD_VFUNC3 -#undef AUD_VFUNC4 -#undef AUD_VFUNC5 -#undef AUD_VFUNC6 -#undef AUD_VFUNC7 -#undef AUD_VFUNC8 diff --git a/src/audacious/api.h b/src/audacious/api.h deleted file mode 100644 index f68987a..0000000 --- a/src/audacious/api.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * api.h - * Copyright 2010-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_API_H -#define AUDACIOUS_API_H - -/* API version. Plugins are marked with this number at compile time. - * - * _AUD_PLUGIN_VERSION is the current version; _AUD_PLUGIN_VERSION_MIN is - * the oldest one we are backward compatible with. Plugins marked older than - * _AUD_PLUGIN_VERSION_MIN or newer than _AUD_PLUGIN_VERSION are not loaded. - * - * Before releases that add new pointers to the end of the API tables, increment - * _AUD_PLUGIN_VERSION but leave _AUD_PLUGIN_VERSION_MIN the same. - * - * Before releases that break backward compatibility (e.g. remove pointers from - * the API tables), increment _AUD_PLUGIN_VERSION *and* set - * _AUD_PLUGIN_VERSION_MIN to the same value. */ - -#define _AUD_PLUGIN_VERSION_MIN 45 /* 3.5-devel */ -#define _AUD_PLUGIN_VERSION 45 /* 3.5-devel */ - -typedef const struct { - const struct ConfigDBAPI * configdb_api; - const struct DRCTAPI * drct_api; - const struct InputAPI * input_api; - const struct MiscAPI * misc_api; - const struct PlaylistAPI * playlist_api; - const struct PluginsAPI * plugins_api; - char * verbose; -} AudAPITable; - -#ifdef _AUDACIOUS_CORE -extern char verbose; -#else -extern AudAPITable * _aud_api_table; -#endif - -#endif diff --git a/src/audacious/art.c b/src/audacious/art.c deleted file mode 100644 index 24658a0..0000000 --- a/src/audacious/art.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * art.c - * Copyright 2011-2012 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <assert.h> -#include <errno.h> -#include <pthread.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <glib.h> -#include <glib/gstdio.h> - -#include <libaudcore/audstrings.h> -#include <libaudcore/hook.h> - -#include "main.h" -#include "misc.h" -#include "playlist.h" -#include "scanner.h" -#include "util.h" - -#define FLAG_DONE 1 -#define FLAG_SENT 2 - -typedef struct { - int refcount; - int flag; - - /* album art as JPEG or PNG data */ - void * data; - int64_t len; - - /* album art as (possibly a temporary) file */ - char * art_file; /* pooled */ - bool_t is_temp; -} ArtItem; - -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - -static GHashTable * art_items; /* of ArtItem */ -static char * current_ref; /* pooled */ -static int send_source; - -static void art_item_free (ArtItem * item) -{ - /* delete temporary file */ - if (item->art_file && item->is_temp) - { - char * unixname = uri_to_filename (item->art_file); - if (unixname) - { - g_unlink (unixname); - str_unref (unixname); - } - } - - g_free (item->data); - str_unref (item->art_file); - g_slice_free (ArtItem, item); -} - -static bool_t send_requests (void * unused) -{ - pthread_mutex_lock (& mutex); - - GQueue queue = G_QUEUE_INIT; - - GHashTableIter iter; - void * ptr1, * ptr2; - - g_hash_table_iter_init (& iter, art_items); - while (g_hash_table_iter_next (& iter, & ptr1, & ptr2)) - { - char * file = ptr1; - ArtItem * item = ptr2; - - if (item->flag == FLAG_DONE) - { - g_queue_push_tail (& queue, str_ref (file)); - item->flag = FLAG_SENT; - } - } - - if (send_source) - { - g_source_remove (send_source); - send_source = 0; - } - - pthread_mutex_unlock (& mutex); - - char * current = NULL; - if (! current_ref) - current = playback_entry_get_filename (); - - char * file; - while ((file = g_queue_pop_head (& queue))) - { - hook_call ("art ready", file); - - if (current && ! strcmp (file, current)) - { - hook_call ("current art ready", file); - current_ref = file; - } - else - { - art_unref (file); /* release temporary reference */ - str_unref (file); - } - } - - str_unref (current); - return FALSE; -} - -static void request_callback (ScanRequest * request) -{ - pthread_mutex_lock (& mutex); - - const char * file = scan_request_get_filename (request); - ArtItem * item = g_hash_table_lookup (art_items, file); - assert (item != NULL && ! item->flag); - - scan_request_get_image_data (request, & item->data, & item->len); - item->art_file = str_get (scan_request_get_image_file (request)); - item->flag = FLAG_DONE; - - if (! send_source) - send_source = g_idle_add (send_requests, NULL); - - pthread_mutex_unlock (& mutex); -} - -static ArtItem * art_item_get (const char * file) -{ - ArtItem * item = g_hash_table_lookup (art_items, file); - - if (item && item->flag) - { - item->refcount ++; - return item; - } - - if (! item) - { - item = g_slice_new0 (ArtItem); - g_hash_table_insert (art_items, str_get (file), item); - item->refcount = 1; /* temporary reference */ - - scan_request (file, SCAN_IMAGE, NULL, request_callback); - } - - return NULL; -} - -static void art_item_unref (const char * file, ArtItem * item) -{ - if (! -- item->refcount) - g_hash_table_remove (art_items, file); -} - -static void release_current (void) -{ - if (current_ref) - { - art_unref (current_ref); - str_unref (current_ref); - current_ref = NULL; - } -} - -void art_init (void) -{ - art_items = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) str_unref, (GDestroyNotify) art_item_free); - - hook_associate ("playlist position", (HookFunction) release_current, NULL); - hook_associate ("playlist set playing", (HookFunction) release_current, NULL); -} - -void art_cleanup (void) -{ - hook_dissociate ("playlist position", (HookFunction) release_current); - hook_dissociate ("playlist set playing", (HookFunction) release_current); - - if (send_source) - { - g_source_remove (send_source); - send_source = 0; - } - - release_current (); - - g_hash_table_destroy (art_items); - art_items = NULL; -} - -void art_request_data (const char * file, const void * * data, int64_t * len) -{ - * data = NULL; - * len = 0; - - pthread_mutex_lock (& mutex); - - ArtItem * item = art_item_get (file); - if (! item) - goto UNLOCK; - - /* load data from external image file */ - if (! item->data && item->art_file) - vfs_file_get_contents (item->art_file, & item->data, & item->len); - - if (item->data) - { - * data = item->data; - * len = item->len; - } - else - art_item_unref (file, item); - -UNLOCK: - pthread_mutex_unlock (& mutex); -} - -const char * art_request_file (const char * file) -{ - const char * art_file = NULL; - pthread_mutex_lock (& mutex); - - ArtItem * item = art_item_get (file); - if (! item) - goto UNLOCK; - - /* save data to temporary file */ - if (item->data && ! item->art_file) - { - char * unixname = write_temp_file (item->data, item->len); - if (unixname) - { - item->art_file = filename_to_uri (unixname); - item->is_temp = TRUE; - str_unref (unixname); - } - } - - if (item->art_file) - art_file = item->art_file; - else - art_item_unref (file, item); - -UNLOCK: - pthread_mutex_unlock (& mutex); - return art_file; -} - -void art_unref (const char * file) -{ - pthread_mutex_lock (& mutex); - - ArtItem * item = g_hash_table_lookup (art_items, file); - assert (item != NULL); - - art_item_unref (file, item); - - pthread_mutex_unlock (& mutex); -} diff --git a/src/audacious/audacious.rc b/src/audacious/audacious.rc index b37beeb..c7b9839 100644 --- a/src/audacious/audacious.rc +++ b/src/audacious/audacious.rc @@ -4,4 +4,4 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL #define IDI_ICON_AUDACIOUS 102 -IDI_ICON_AUDACIOUS ICON "../../pixmaps/audacious.ico" +IDI_ICON_AUDACIOUS ICON "../../images/audacious.ico" diff --git a/src/audacious/chardet.c b/src/audacious/chardet.c deleted file mode 100644 index 08fe97e..0000000 --- a/src/audacious/chardet.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * chardet.c - * Copyright 2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <libaudcore/audstrings.h> -#include <libaudcore/hook.h> - -#include "main.h" -#include "misc.h" - -static void chardet_update (void) -{ - char * region = get_str (NULL, "chardet_detector"); - char * fallbacks = get_str (NULL, "chardet_fallback"); - - Index * list = str_list_to_index (fallbacks, ", "); - str_set_charsets (region[0] ? region : NULL, list); - - str_unref (region); - str_unref (fallbacks); -} - -void chardet_init (void) -{ - chardet_update (); - - hook_associate ("set chardet_detector", (HookFunction) chardet_update, NULL); - hook_associate ("set chardet_fallback", (HookFunction) chardet_update, NULL); -} - -void chardet_cleanup (void) -{ - hook_dissociate ("set chardet_detector", (HookFunction) chardet_update); - hook_dissociate ("set chardet_fallback", (HookFunction) chardet_update); - - str_set_charsets (NULL, NULL); -} diff --git a/src/audacious/config.c b/src/audacious/config.c deleted file mode 100644 index 0bc4966..0000000 --- a/src/audacious/config.c +++ /dev/null @@ -1,453 +0,0 @@ -/* - * config.c - * Copyright 2011-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <glib.h> -#include <string.h> - -#include <libaudcore/audstrings.h> -#include <libaudcore/hook.h> -#include <libaudcore/inifile.h> -#include <libaudcore/multihash.h> - -#include "main.h" -#include "misc.h" - -#define DEFAULT_SECTION "audacious" - -static const char * const core_defaults[] = { - - /* general */ - "advance_on_delete", "FALSE", - "clear_playlist", "TRUE", - "open_to_temporary", "TRUE", - "resume_playback_on_startup", "FALSE", - "show_interface", "TRUE", - - /* equalizer */ - "eqpreset_default_file", "", - "eqpreset_extension", "", - "equalizer_active", "FALSE", - "equalizer_autoload", "FALSE", - "equalizer_bands", "0,0,0,0,0,0,0,0,0,0", - "equalizer_preamp", "0", - - /* info popup / info window */ - "cover_name_exclude", "back", - "cover_name_include", "album,cover,front,folder", - "filepopup_delay", "5", - "filepopup_showprogressbar", "TRUE", - "recurse_for_cover", "FALSE", - "recurse_for_cover_depth", "0", - "show_filepopup_for_tuple", "TRUE", - "use_file_cover", "FALSE", - - /* network */ - "use_proxy", "FALSE", - "use_proxy_auth", "FALSE", - - /* output */ - "default_gain", "0", - "enable_replay_gain", "TRUE", - "enable_clipping_prevention", "TRUE", - "output_bit_depth", "16", - "output_buffer_size", "500", - "replay_gain_album", "FALSE", - "replay_gain_preamp", "0", - "soft_clipping", "FALSE", - "software_volume_control", "FALSE", - "sw_volume_left", "100", - "sw_volume_right", "100", - - /* playback */ - "no_playlist_advance", "FALSE", - "repeat", "FALSE", - "shuffle", "FALSE", - "stop_after_current_song", "FALSE", - - /* playlist */ - "chardet_fallback", "ISO-8859-1", -#ifdef _WIN32 - "convert_backslash", "TRUE", -#else - "convert_backslash", "FALSE", -#endif - "generic_title_format", "${?artist:${artist} - }${?album:${album} - }${title}", - "leading_zero", "FALSE", - "metadata_on_play", "FALSE", - "show_numbers_in_pl", "FALSE", - - NULL}; - -typedef enum { - OP_IS_DEFAULT, - OP_GET, - OP_SET, - OP_SET_NO_FLAG, - OP_CLEAR, - OP_CLEAR_NO_FLAG -} OpType; - -typedef struct { - const char * section; - const char * key; - const char * value; -} ConfigItem; - -typedef struct { - MultihashNode node; - ConfigItem item; -} ConfigNode; - -typedef struct { - OpType type; - ConfigItem item; - unsigned hash; - bool_t result; -} ConfigOp; - -typedef struct { - char * section; -} LoadState; - -typedef struct { - GArray * list; -} SaveState; - -static unsigned item_hash (const ConfigItem * item) -{ - return g_str_hash (item->section) + g_str_hash (item->key); -} - -/* assumes pooled strings */ -static int item_compare (const ConfigItem * a, const ConfigItem * b) -{ - if (str_equal (a->section, b->section)) - return strcmp (a->key, b->key); - else - return strcmp (a->section, b->section); -} - -/* assumes pooled strings */ -static void item_clear (ConfigItem * item) -{ - str_unref ((char *) item->section); - str_unref ((char *) item->key); - str_unref ((char *) item->value); -} - -static unsigned config_node_hash (const MultihashNode * node0) -{ - const ConfigNode * node = (const ConfigNode *) node0; - - return item_hash (& node->item); -} - -static bool_t config_node_match (const MultihashNode * node0, const void * data, unsigned hash) -{ - const ConfigNode * node = (const ConfigNode *) node0; - const ConfigItem * item = data; - - return ! strcmp (node->item.section, item->section) && ! strcmp (node->item.key, item->key); -} - -static MultihashTable defaults = { - .hash_func = config_node_hash, - .match_func = config_node_match -}; - -static MultihashTable config = { - .hash_func = config_node_hash, - .match_func = config_node_match -}; - -static volatile bool_t modified; - -static MultihashNode * add_cb (const void * data, unsigned hash, void * state) -{ - ConfigOp * op = state; - - switch (op->type) - { - case OP_IS_DEFAULT: - op->result = ! op->item.value[0]; /* empty string is default */ - return NULL; - - case OP_SET: - op->result = TRUE; - modified = TRUE; - - case OP_SET_NO_FLAG:; - ConfigNode * node = g_slice_new (ConfigNode); - node->item.section = str_get (op->item.section); - node->item.key = str_get (op->item.key); - node->item.value = str_get (op->item.value); - return (MultihashNode *) node; - - default: - return NULL; - } -} - -static bool_t action_cb (MultihashNode * node0, void * state) -{ - ConfigNode * node = (ConfigNode *) node0; - ConfigOp * op = state; - - switch (op->type) - { - case OP_IS_DEFAULT: - op->result = ! strcmp (node->item.value, op->item.value); - return FALSE; - - case OP_GET: - op->item.value = str_ref (node->item.value); - return FALSE; - - case OP_SET: - op->result = !! strcmp (node->item.value, op->item.value); - if (op->result) - modified = TRUE; - - case OP_SET_NO_FLAG: - str_unref ((char *) node->item.value); - node->item.value = str_get (op->item.value); - return FALSE; - - case OP_CLEAR: - op->result = TRUE; - modified = TRUE; - - case OP_CLEAR_NO_FLAG: - item_clear (& node->item); - g_slice_free (ConfigNode, node); - return TRUE; - - default: - return FALSE; - } -} - -static bool_t config_op_run (ConfigOp * op, OpType type, MultihashTable * table) -{ - if (! op->hash) - op->hash = item_hash (& op->item); - - op->type = type; - op->result = FALSE; - multihash_lookup (table, & op->item, op->hash, add_cb, action_cb, op); - return op->result; -} - -static void load_heading (const char * section, void * data) -{ - LoadState * state = data; - - str_unref (state->section); - state->section = str_get (section); -} - -static void load_entry (const char * key, const char * value, void * data) -{ - LoadState * state = data; - g_return_if_fail (state->section); - - ConfigOp op = {.item = {state->section, key, value}}; - config_op_run (& op, OP_SET_NO_FLAG, & config); -} - -void config_load (void) -{ - char * folder = filename_to_uri (get_path (AUD_PATH_USER_DIR)); - SCONCAT2 (path, folder, "/config"); - str_unref (folder); - - if (vfs_file_test (path, VFS_EXISTS)) - { - VFSFile * file = vfs_fopen (path, "r"); - - if (file) - { - LoadState state = {0}; - - inifile_parse (file, load_heading, load_entry, & state); - - str_unref (state.section); - vfs_fclose (file); - } - } - - config_set_defaults (NULL, core_defaults); -} - -static bool_t add_to_save_list (MultihashNode * node0, void * state0) -{ - ConfigNode * node = (ConfigNode *) node0; - SaveState * state = state0; - - int pos = state->list->len; - g_array_set_size (state->list, pos + 1); - - ConfigItem * copy = & g_array_index (state->list, ConfigItem, pos); - copy->section = str_ref (node->item.section); - copy->key = str_ref (node->item.key); - copy->value = str_ref (node->item.value); - - modified = FALSE; - - return FALSE; -} - -void config_save (void) -{ - if (! modified) - return; - - SaveState state = {.list = g_array_new (FALSE, FALSE, sizeof (ConfigItem))}; - - multihash_iterate (& config, add_to_save_list, & state); - g_array_sort (state.list, (GCompareFunc) item_compare); - - char * folder = filename_to_uri (get_path (AUD_PATH_USER_DIR)); - SCONCAT2 (path, folder, "/config"); - str_unref (folder); - - VFSFile * file = vfs_fopen (path, "w"); - - if (file) - { - const char * current_heading = NULL; - - for (int i = 0; i < state.list->len; i ++) - { - ConfigItem * item = & g_array_index (state.list, ConfigItem, i); - - if (! str_equal (item->section, current_heading)) - { - inifile_write_heading (file, item->section); - current_heading = item->section; - } - - inifile_write_entry (file, item->key, item->value); - } - - vfs_fclose (file); - } - - g_array_set_clear_func (state.list, (GDestroyNotify) item_clear); - g_array_free (state.list, TRUE); -} - -void config_set_defaults (const char * section, const char * const * entries) -{ - if (! section) - section = DEFAULT_SECTION; - - while (1) - { - const char * name = * entries ++; - const char * value = * entries ++; - if (! name || ! value) - break; - - ConfigOp op = {.item = {section, name, value}}; - config_op_run (& op, OP_SET_NO_FLAG, & defaults); - } -} - -void config_cleanup (void) -{ - ConfigOp op = {.type = OP_CLEAR_NO_FLAG}; - multihash_iterate (& config, action_cb, & op); - multihash_iterate (& defaults, action_cb, & op); -} - -void set_str (const char * section, const char * name, const char * value) -{ - g_return_if_fail (name && value); - - ConfigOp op = {.item = {section ? section : DEFAULT_SECTION, name, value}}; - - bool_t is_default = config_op_run (& op, OP_IS_DEFAULT, & defaults); - bool_t changed = config_op_run (& op, is_default ? OP_CLEAR : OP_SET, & config); - - if (changed && ! section) - { - SCONCAT2 (event, "set ", name); - event_queue (event, NULL); - } -} - -char * get_str (const char * section, const char * name) -{ - g_return_val_if_fail (name, NULL); - - ConfigOp op = {.item = {section ? section : DEFAULT_SECTION, name, NULL}}; - - config_op_run (& op, OP_GET, & config); - - if (! op.item.value) - config_op_run (& op, OP_GET, & defaults); - - return op.item.value ? (char *) op.item.value : str_get (""); -} - -void set_bool (const char * section, const char * name, bool_t value) -{ - set_str (section, name, value ? "TRUE" : "FALSE"); -} - -bool_t get_bool (const char * section, const char * name) -{ - char * string = get_str (section, name); - bool_t value = ! strcmp (string, "TRUE"); - str_unref (string); - return value; -} - -void set_int (const char * section, const char * name, int value) -{ - char * string = int_to_str (value); - g_return_if_fail (string); - set_str (section, name, string); - str_unref (string); -} - -int get_int (const char * section, const char * name) -{ - char * string = get_str (section, name); - int value = str_to_int (string); - str_unref (string); - return value; -} - -void set_double (const char * section, const char * name, double value) -{ - char * string = double_to_str (value); - g_return_if_fail (string); - set_str (section, name, string); - str_unref (string); -} - -double get_double (const char * section, const char * name) -{ - char * string = get_str (section, name); - double value = str_to_double (string); - str_unref (string); - return value; -} diff --git a/src/audacious/dbus-server.c b/src/audacious/dbus-server.c deleted file mode 100644 index af55f20..0000000 --- a/src/audacious/dbus-server.c +++ /dev/null @@ -1,779 +0,0 @@ -/* - * dbus-server.c - * Copyright 2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <stdio.h> - -#include <libaudgui/libaudgui.h> - -#include "aud-dbus.h" -#include "drct.h" -#include "main.h" -#include "misc.h" -#include "playlist.h" -#include "ui_preferences.h" - -typedef ObjAudacious Obj; -typedef GDBusMethodInvocation Invoc; - -#define FINISH(name) \ - obj_audacious_complete_##name (obj, invoc) - -#define FINISH2(name, ...) \ - obj_audacious_complete_##name (obj, invoc, __VA_ARGS__) - -static Index * strv_to_index (const char * const * strv) -{ - Index * index = index_new (); - while (* strv) - index_insert (index, -1, str_get (* strv ++)); - - return index; -} - -static bool_t do_add (Obj * obj, Invoc * invoc, const char * file) -{ - playlist_entry_insert (playlist_get_active (), -1, file, NULL, FALSE); - FINISH (add); - return TRUE; -} - -static bool_t do_add_list (Obj * obj, Invoc * invoc, const char * const * filenames) -{ - playlist_entry_insert_batch (playlist_get_active (), -1, - strv_to_index (filenames), NULL, FALSE); - FINISH (add_list); - return TRUE; -} - -static bool_t do_add_url (Obj * obj, Invoc * invoc, const char * url) -{ - playlist_entry_insert (playlist_get_active (), -1, url, NULL, FALSE); - FINISH (add_url); - return TRUE; -} - -static bool_t do_advance (Obj * obj, Invoc * invoc) -{ - drct_pl_next (); - FINISH (advance); - return TRUE; -} - -static bool_t do_auto_advance (Obj * obj, Invoc * invoc) -{ - FINISH2 (auto_advance, ! get_bool (NULL, "no_playlist_advance")); - return TRUE; -} - -static bool_t do_balance (Obj * obj, Invoc * invoc) -{ - int balance; - drct_get_volume_balance (& balance); - FINISH2 (balance, balance); - return TRUE; -} - -static bool_t do_clear (Obj * obj, Invoc * invoc) -{ - int playlist = playlist_get_active (); - playlist_entry_delete (playlist, 0, playlist_entry_count (playlist)); - FINISH (clear); - return TRUE; -} - -static bool_t do_delete (Obj * obj, Invoc * invoc, unsigned pos) -{ - playlist_entry_delete (playlist_get_active (), pos, 1); - FINISH (delete); - return TRUE; -} - -static bool_t do_delete_active_playlist (Obj * obj, Invoc * invoc) -{ - playlist_delete (playlist_get_active ()); - FINISH (delete_active_playlist); - return TRUE; -} - -static bool_t do_eject (Obj * obj, Invoc * invoc) -{ - if (! headless_mode ()) - audgui_run_filebrowser (TRUE); - - FINISH (eject); - return TRUE; -} - -static bool_t do_equalizer_activate (Obj * obj, Invoc * invoc, bool_t active) -{ - set_bool (NULL, "equalizer_active", active); - FINISH (equalizer_activate); - return TRUE; -} - -static bool_t do_get_active_playlist (Obj * obj, Invoc * invoc) -{ - FINISH2 (get_active_playlist, playlist_get_active ()); - return TRUE; -} - -static bool_t do_get_active_playlist_name (Obj * obj, Invoc * invoc) -{ - char * title = playlist_get_title (playlist_get_active ()); - FINISH2 (get_active_playlist_name, title ? title : ""); - str_unref (title); - return TRUE; -} - -static bool_t do_get_eq (Obj * obj, Invoc * invoc) -{ - double preamp = get_double (NULL, "equalizer_preamp"); - double bands[AUD_EQUALIZER_NBANDS]; - eq_get_bands (bands); - - GVariant * var = g_variant_new_fixed_array (G_VARIANT_TYPE_DOUBLE, bands, - AUD_EQUALIZER_NBANDS, sizeof (double)); - FINISH2 (get_eq, preamp, var); - return TRUE; -} - -static bool_t do_get_eq_band (Obj * obj, Invoc * invoc, int band) -{ - FINISH2 (get_eq_band, eq_get_band (band)); - return TRUE; -} - -static bool_t do_get_eq_preamp (Obj * obj, Invoc * invoc) -{ - FINISH2 (get_eq_preamp, get_double (NULL, "equalizer_preamp")); - return TRUE; -} - -static bool_t do_get_info (Obj * obj, Invoc * invoc) -{ - int bitrate, samplerate, channels; - drct_get_info (& bitrate, & samplerate, & channels); - FINISH2 (get_info, bitrate, samplerate, channels); - return TRUE; -} - -static bool_t do_get_playqueue_length (Obj * obj, Invoc * invoc) -{ - FINISH2 (get_playqueue_length, playlist_queue_count (playlist_get_active ())); - return TRUE; -} - -static bool_t do_get_tuple_fields (Obj * obj, Invoc * invoc) -{ - const char * fields[TUPLE_FIELDS + 1]; - - for (int i = 0; i < TUPLE_FIELDS; i ++) - fields[i] = tuple_field_get_name (i); - - fields[TUPLE_FIELDS] = NULL; - - FINISH2 (get_tuple_fields, fields); - return TRUE; -} - -static bool_t do_info (Obj * obj, Invoc * invoc) -{ - int bitrate, samplerate, channels; - drct_get_info (& bitrate, & samplerate, & channels); - FINISH2 (info, bitrate, samplerate, channels); - return TRUE; -} - -static bool_t do_jump (Obj * obj, Invoc * invoc, unsigned pos) -{ - playlist_set_position (playlist_get_active (), pos); - FINISH (jump); - return TRUE; -} - -static bool_t do_length (Obj * obj, Invoc * invoc) -{ - FINISH2 (length, playlist_entry_count (playlist_get_active ())); - return TRUE; -} - -static bool_t do_main_win_visible (Obj * obj, Invoc * invoc) -{ - FINISH2 (main_win_visible, ! headless_mode () && interface_is_shown ()); - return TRUE; -} - -static bool_t do_new_playlist (Obj * obj, Invoc * invoc) -{ - playlist_insert (-1); - playlist_set_active (playlist_count () - 1); - FINISH (new_playlist); - return TRUE; -} - -static bool_t do_number_of_playlists (Obj * obj, Invoc * invoc) -{ - FINISH2 (number_of_playlists, playlist_count ()); - return TRUE; -} - -static bool_t do_open_list (Obj * obj, Invoc * invoc, const char * const * filenames) -{ - drct_pl_open_list (strv_to_index (filenames)); - FINISH (open_list); - return TRUE; -} - -static bool_t do_open_list_to_temp (Obj * obj, Invoc * invoc, const char * const * filenames) -{ - drct_pl_open_temp_list (strv_to_index (filenames)); - FINISH (open_list_to_temp); - return TRUE; -} - -static bool_t do_pause (Obj * obj, Invoc * invoc) -{ - drct_pause (); - FINISH (pause); - return TRUE; -} - -static bool_t do_paused (Obj * obj, Invoc * invoc) -{ - FINISH2 (paused, drct_get_paused ()); - return TRUE; -} - -static bool_t do_play (Obj * obj, Invoc * invoc) -{ - drct_play (); - FINISH (play); - return TRUE; -} - -static bool_t do_play_active_playlist (Obj * obj, Invoc * invoc) -{ - drct_play_playlist (playlist_get_active ()); - FINISH (play_active_playlist); - return TRUE; -} - -static bool_t do_play_pause (Obj * obj, Invoc * invoc) -{ - drct_play_pause (); - FINISH (play_pause); - return TRUE; -} - -static bool_t do_playing (Obj * obj, Invoc * invoc) -{ - FINISH2 (playing, drct_get_playing ()); - return TRUE; -} - -static bool_t do_playlist_add (Obj * obj, Invoc * invoc, const char * list) -{ - playlist_entry_insert (playlist_get_active (), -1, list, NULL, FALSE); - FINISH (playlist_add); - return TRUE; -} - -static bool_t do_playlist_enqueue_to_temp (Obj * obj, Invoc * invoc, const char * url) -{ - drct_pl_open_temp (url); - FINISH (playlist_enqueue_to_temp); - return TRUE; -} - -static bool_t do_playlist_ins_url_string (Obj * obj, Invoc * invoc, const char * url, int pos) -{ - playlist_entry_insert (playlist_get_active (), pos, url, NULL, FALSE); - FINISH (playlist_ins_url_string); - return TRUE; -} - -static bool_t do_playqueue_add (Obj * obj, Invoc * invoc, int pos) -{ - playlist_queue_insert (playlist_get_active (), -1, pos); - FINISH (playqueue_add); - return TRUE; -} - -static bool_t do_playqueue_clear (Obj * obj, Invoc * invoc) -{ - int playlist = playlist_get_active (); - playlist_queue_delete (playlist, 0, playlist_queue_count (playlist)); - FINISH (playqueue_clear); - return TRUE; -} - -static bool_t do_playqueue_is_queued (Obj * obj, Invoc * invoc, int pos) -{ - bool_t queued = (playlist_queue_find_entry (playlist_get_active (), pos) >= 0); - FINISH2 (playqueue_is_queued, queued); - return TRUE; -} - -static bool_t do_playqueue_remove (Obj * obj, Invoc * invoc, int pos) -{ - int playlist = playlist_get_active (); - int qpos = playlist_queue_find_entry (playlist, pos); - - if (qpos >= 0) - playlist_queue_delete (playlist, qpos, 1); - - FINISH (playqueue_remove); - return TRUE; -} - -static bool_t do_position (Obj * obj, Invoc * invoc) -{ - FINISH2 (position, playlist_get_position (playlist_get_active ())); - return TRUE; -} - -static bool_t do_queue_get_list_pos (Obj * obj, Invoc * invoc, unsigned qpos) -{ - FINISH2 (queue_get_list_pos, playlist_queue_get_entry (playlist_get_active (), qpos)); - return TRUE; -} - -static bool_t do_queue_get_queue_pos (Obj * obj, Invoc * invoc, unsigned pos) -{ - FINISH2 (queue_get_queue_pos, playlist_queue_find_entry (playlist_get_active (), pos)); - return TRUE; -} - -static bool_t do_quit (Obj * obj, Invoc * invoc) -{ - drct_quit (); - FINISH (quit); - return TRUE; -} - -static bool_t do_repeat (Obj * obj, Invoc * invoc) -{ - FINISH2 (repeat, get_bool (NULL, "repeat")); - return TRUE; -} - -static bool_t do_reverse (Obj * obj, Invoc * invoc) -{ - drct_pl_prev (); - FINISH (reverse); - return TRUE; -} - -static bool_t do_seek (Obj * obj, Invoc * invoc, unsigned pos) -{ - drct_seek (pos); - FINISH (seek); - return TRUE; -} - -static bool_t do_set_active_playlist (Obj * obj, Invoc * invoc, int playlist) -{ - playlist_set_active (playlist); - FINISH (set_active_playlist); - return TRUE; -} - -static bool_t do_set_active_playlist_name (Obj * obj, Invoc * invoc, const char * title) -{ - playlist_set_title (playlist_get_active (), title); - FINISH (set_active_playlist_name); - return TRUE; -} - -static bool_t do_set_eq (Obj * obj, Invoc * invoc, double preamp, GVariant * var) -{ - if (! g_variant_is_of_type (var, G_VARIANT_TYPE ("ad"))) - return FALSE; - - size_t nbands = 0; - const double * bands = g_variant_get_fixed_array (var, & nbands, sizeof (double)); - - if (nbands != AUD_EQUALIZER_NBANDS) - return FALSE; - - set_double (NULL, "equalizer_preamp", preamp); - eq_set_bands (bands); - FINISH (set_eq); - return TRUE; -} - -static bool_t do_set_eq_band (Obj * obj, Invoc * invoc, int band, double value) -{ - eq_set_band (band, value); - FINISH (set_eq_band); - return TRUE; -} - -static bool_t do_set_eq_preamp (Obj * obj, Invoc * invoc, double preamp) -{ - set_double (NULL, "equalizer_preamp", preamp); - FINISH (set_eq_preamp); - return TRUE; -} - -static bool_t do_set_volume (Obj * obj, Invoc * invoc, int vl, int vr) -{ - drct_set_volume (vl, vr); - FINISH (set_volume); - return TRUE; -} - -static bool_t do_show_about_box (Obj * obj, Invoc * invoc, bool_t show) -{ - if (! headless_mode ()) - { - if (show) - audgui_show_about_window (); - else - audgui_hide_about_window (); - } - - FINISH (show_about_box); - return TRUE; -} - -static bool_t do_show_filebrowser (Obj * obj, Invoc * invoc, bool_t show) -{ - if (! headless_mode ()) - { - if (show) - audgui_run_filebrowser (FALSE); - else - audgui_hide_filebrowser (); - } - - FINISH (show_filebrowser); - return TRUE; -} - -static bool_t do_show_jtf_box (Obj * obj, Invoc * invoc, bool_t show) -{ - if (! headless_mode ()) - { - if (show) - audgui_jump_to_track (); - else - audgui_jump_to_track_hide (); - } - - FINISH (show_jtf_box); - return TRUE; -} - -static bool_t do_show_main_win (Obj * obj, Invoc * invoc, bool_t show) -{ - if (! headless_mode ()) - interface_show (show); - - FINISH (show_main_win); - return TRUE; -} - -static bool_t do_show_prefs_box (Obj * obj, Invoc * invoc, bool_t show) -{ - if (! headless_mode ()) - { - if (show) - show_prefs_window (); - else - hide_prefs_window (); - } - - FINISH (show_prefs_box); - return TRUE; -} - -static bool_t do_shuffle (Obj * obj, Invoc * invoc) -{ - FINISH2 (shuffle, get_bool (NULL, "shuffle")); - return TRUE; -} - -static bool_t do_song_filename (Obj * obj, Invoc * invoc, unsigned pos) -{ - char * filename = playlist_entry_get_filename (playlist_get_active (), pos); - FINISH2 (song_filename, filename ? filename : ""); - str_unref (filename); - return TRUE; -} - -static bool_t do_song_frames (Obj * obj, Invoc * invoc, unsigned pos) -{ - FINISH2 (song_frames, playlist_entry_get_length (playlist_get_active (), pos, FALSE)); - return TRUE; -} - -static bool_t do_song_length (Obj * obj, Invoc * invoc, unsigned pos) -{ - int length = playlist_entry_get_length (playlist_get_active (), pos, FALSE); - FINISH2 (song_length, length >= 0 ? length / 1000 : -1); - return TRUE; -} - -static bool_t do_song_title (Obj * obj, Invoc * invoc, unsigned pos) -{ - char * title = playlist_entry_get_title (playlist_get_active (), pos, FALSE); - FINISH2 (song_title, title ? title : ""); - str_unref (title); - return TRUE; -} - -static bool_t do_song_tuple (Obj * obj, Invoc * invoc, unsigned pos, const char * key) -{ - int field = tuple_field_by_name (key); - Tuple * tuple = NULL; - GVariant * var = NULL; - - if (field >= 0) - tuple = playlist_entry_get_tuple (playlist_get_active (), pos, FALSE); - - if (tuple) - { - char * str; - - switch (tuple_get_value_type (tuple, field)) - { - case TUPLE_STRING: - str = tuple_get_str (tuple, field); - var = g_variant_new_string (str); - str_unref (str); - break; - - case TUPLE_INT: - var = g_variant_new_int32 (tuple_get_int (tuple, field)); - break; - - default: - break; - } - - tuple_unref (tuple); - } - - if (! var) - var = g_variant_new_string (""); - - FINISH2 (song_tuple, g_variant_new_variant (var)); - return TRUE; -} - -static bool_t do_status (Obj * obj, Invoc * invoc) -{ - const char * status = "stopped"; - if (drct_get_playing ()) - status = drct_get_paused () ? "paused" : "playing"; - - FINISH2 (status, status); - return TRUE; -} - -static bool_t do_stop (Obj * obj, Invoc * invoc) -{ - drct_stop (); - FINISH (stop); - return TRUE; -} - -static bool_t do_stop_after (Obj * obj, Invoc * invoc) -{ - FINISH2 (stop_after, get_bool (NULL, "stop_after_current_song")); - return TRUE; -} - -static bool_t do_stopped (Obj * obj, Invoc * invoc) -{ - FINISH2 (stopped, ! drct_get_playing ()); - return TRUE; -} - -static bool_t do_time (Obj * obj, Invoc * invoc) -{ - FINISH2 (time, drct_get_time ()); - return TRUE; -} - -static bool_t do_toggle_auto_advance (Obj * obj, Invoc * invoc) -{ - set_bool (NULL, "no_playlist_advance", ! get_bool (NULL, "no_playlist_advance")); - FINISH (toggle_auto_advance); - return TRUE; -} - -static bool_t do_toggle_repeat (Obj * obj, Invoc * invoc) -{ - set_bool (NULL, "repeat", ! get_bool (NULL, "repeat")); - FINISH (toggle_repeat); - return TRUE; -} - -static bool_t do_toggle_shuffle (Obj * obj, Invoc * invoc) -{ - set_bool (NULL, "shuffle", ! get_bool (NULL, "shuffle")); - FINISH (toggle_shuffle); - return TRUE; -} - -static bool_t do_toggle_stop_after (Obj * obj, Invoc * invoc) -{ - set_bool (NULL, "stop_after_current_song", ! get_bool (NULL, "stop_after_current_song")); - FINISH (toggle_stop_after); - return TRUE; -} - -static bool_t do_version (Obj * obj, Invoc * invoc) -{ - FINISH2 (version, VERSION); - return TRUE; -} - -static bool_t do_volume (Obj * obj, Invoc * invoc) -{ - int left, right; - drct_get_volume (& left, & right); - FINISH2 (volume, left, right); - return TRUE; -} - -static const struct -{ - const char * signal; - GCallback callback; -} -handlers[] = -{ - {"handle-add", (GCallback) do_add}, - {"handle-add-list", (GCallback) do_add_list}, - {"handle-add-url", (GCallback) do_add_url}, - {"handle-advance", (GCallback) do_advance}, - {"handle-auto-advance", (GCallback) do_auto_advance}, - {"handle-balance", (GCallback) do_balance}, - {"handle-clear", (GCallback) do_clear}, - {"handle-delete", (GCallback) do_delete}, - {"handle-delete-active-playlist", (GCallback) do_delete_active_playlist}, - {"handle-eject", (GCallback) do_eject}, - {"handle-equalizer-activate", (GCallback) do_equalizer_activate}, - {"handle-get-active-playlist", (GCallback) do_get_active_playlist}, - {"handle-get-active-playlist-name", (GCallback) do_get_active_playlist_name}, - {"handle-get-eq", (GCallback) do_get_eq}, - {"handle-get-eq-band", (GCallback) do_get_eq_band}, - {"handle-get-eq-preamp", (GCallback) do_get_eq_preamp}, - {"handle-get-info", (GCallback) do_get_info}, - {"handle-get-playqueue-length", (GCallback) do_get_playqueue_length}, - {"handle-get-tuple-fields", (GCallback) do_get_tuple_fields}, - {"handle-info", (GCallback) do_info}, - {"handle-jump", (GCallback) do_jump}, - {"handle-length", (GCallback) do_length}, - {"handle-main-win-visible", (GCallback) do_main_win_visible}, - {"handle-new-playlist", (GCallback) do_new_playlist}, - {"handle-number-of-playlists", (GCallback) do_number_of_playlists}, - {"handle-open-list", (GCallback) do_open_list}, - {"handle-open-list-to-temp", (GCallback) do_open_list_to_temp}, - {"handle-pause", (GCallback) do_pause}, - {"handle-paused", (GCallback) do_paused}, - {"handle-play", (GCallback) do_play}, - {"handle-play-active-playlist", (GCallback) do_play_active_playlist}, - {"handle-play-pause", (GCallback) do_play_pause}, - {"handle-playing", (GCallback) do_playing}, - {"handle-playlist-add", (GCallback) do_playlist_add}, - {"handle-playlist-enqueue-to-temp", (GCallback) do_playlist_enqueue_to_temp}, - {"handle-playlist-ins-url-string", (GCallback) do_playlist_ins_url_string}, - {"handle-playqueue-add", (GCallback) do_playqueue_add}, - {"handle-playqueue-clear", (GCallback) do_playqueue_clear}, - {"handle-playqueue-is-queued", (GCallback) do_playqueue_is_queued}, - {"handle-playqueue-remove", (GCallback) do_playqueue_remove}, - {"handle-position", (GCallback) do_position}, - {"handle-queue-get-list-pos", (GCallback) do_queue_get_list_pos}, - {"handle-queue-get-queue-pos", (GCallback) do_queue_get_queue_pos}, - {"handle-quit", (GCallback) do_quit}, - {"handle-repeat", (GCallback) do_repeat}, - {"handle-reverse", (GCallback) do_reverse}, - {"handle-seek", (GCallback) do_seek}, - {"handle-set-active-playlist", (GCallback) do_set_active_playlist}, - {"handle-set-active-playlist-name", (GCallback) do_set_active_playlist_name}, - {"handle-set-eq", (GCallback) do_set_eq}, - {"handle-set-eq-band", (GCallback) do_set_eq_band}, - {"handle-set-eq-preamp", (GCallback) do_set_eq_preamp}, - {"handle-set-volume", (GCallback) do_set_volume}, - {"handle-show-about-box", (GCallback) do_show_about_box}, - {"handle-show-filebrowser", (GCallback) do_show_filebrowser}, - {"handle-show-jtf-box", (GCallback) do_show_jtf_box}, - {"handle-show-main-win", (GCallback) do_show_main_win}, - {"handle-show-prefs-box", (GCallback) do_show_prefs_box}, - {"handle-shuffle", (GCallback) do_shuffle}, - {"handle-song-filename", (GCallback) do_song_filename}, - {"handle-song-frames", (GCallback) do_song_frames}, - {"handle-song-length", (GCallback) do_song_length}, - {"handle-song-title", (GCallback) do_song_title}, - {"handle-song-tuple", (GCallback) do_song_tuple}, - {"handle-status", (GCallback) do_status}, - {"handle-stop", (GCallback) do_stop}, - {"handle-stop-after", (GCallback) do_stop_after}, - {"handle-stopped", (GCallback) do_stopped}, - {"handle-time", (GCallback) do_time}, - {"handle-toggle-auto-advance", (GCallback) do_toggle_auto_advance}, - {"handle-toggle-repeat", (GCallback) do_toggle_repeat}, - {"handle-toggle-shuffle", (GCallback) do_toggle_shuffle}, - {"handle-toggle-stop-after", (GCallback) do_toggle_stop_after}, - {"handle-version", (GCallback) do_version}, - {"handle-volume", (GCallback) do_volume} -}; - -static GDBusInterfaceSkeleton * skeleton = NULL; - -void dbus_server_init (void) -{ - GError * error = NULL; - GDBusConnection * bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, & error); - - if (! bus) - goto ERROR; - - g_bus_own_name_on_connection (bus, "org.atheme.audacious", 0, NULL, NULL, NULL, NULL); - - skeleton = (GDBusInterfaceSkeleton *) obj_audacious_skeleton_new (); - - for (int i = 0; i < ARRAY_LEN (handlers); i ++) - g_signal_connect (skeleton, handlers[i].signal, handlers[i].callback, NULL); - - if (! g_dbus_interface_skeleton_export (skeleton, bus, "/org/atheme/audacious", & error)) - goto ERROR; - - return; - -ERROR: - if (error) - { - fprintf (stderr, "D-Bus error: %s\n", error->message); - g_error_free (error); - } -} - -void dbus_server_cleanup (void) -{ - if (skeleton) - { - g_object_unref (skeleton); - skeleton = NULL; - } -} diff --git a/src/audacious/dbus-server.cc b/src/audacious/dbus-server.cc new file mode 100644 index 0000000..90f464e --- /dev/null +++ b/src/audacious/dbus-server.cc @@ -0,0 +1,815 @@ +/* + * dbus-server.c + * Copyright 2013 John Lindgren + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions, and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions, and the following disclaimer in the documentation + * provided with the distribution. + * + * This software is provided "as is" and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising from + * the use of this software. + */ + +#include <libaudcore/drct.h> +#include <libaudcore/equalizer.h> +#include <libaudcore/interface.h> +#include <libaudcore/playlist.h> +#include <libaudcore/runtime.h> +#include <libaudcore/tuple.h> + +#include "aud-dbus.h" +#include "main.h" + +typedef ObjAudacious Obj; +typedef GDBusMethodInvocation Invoc; + +#define FINISH(name) \ + obj_audacious_complete_##name (obj, invoc) + +#define FINISH2(name, ...) \ + obj_audacious_complete_##name (obj, invoc, __VA_ARGS__) + +static Index<PlaylistAddItem> strv_to_index (const char * const * strv) +{ + Index<PlaylistAddItem> index; + while (* strv) + index.append (String (* strv ++)); + + return index; +} + +static gboolean do_add (Obj * obj, Invoc * invoc, const char * file) +{ + aud_playlist_entry_insert (aud_playlist_get_active (), -1, file, Tuple (), false); + FINISH (add); + return true; +} + +static gboolean do_add_list (Obj * obj, Invoc * invoc, const char * const * filenames) +{ + aud_playlist_entry_insert_batch (aud_playlist_get_active (), -1, + strv_to_index (filenames), false); + FINISH (add_list); + return true; +} + +static gboolean do_add_url (Obj * obj, Invoc * invoc, const char * url) +{ + aud_playlist_entry_insert (aud_playlist_get_active (), -1, url, Tuple (), false); + FINISH (add_url); + return true; +} + +static gboolean do_advance (Obj * obj, Invoc * invoc) +{ + aud_drct_pl_next (); + FINISH (advance); + return true; +} + +static gboolean do_auto_advance (Obj * obj, Invoc * invoc) +{ + FINISH2 (auto_advance, ! aud_get_bool (nullptr, "no_playlist_advance")); + return true; +} + +static gboolean do_balance (Obj * obj, Invoc * invoc) +{ + FINISH2 (balance, aud_drct_get_volume_balance ()); + return true; +} + +static gboolean do_clear (Obj * obj, Invoc * invoc) +{ + int playlist = aud_playlist_get_active (); + aud_playlist_entry_delete (playlist, 0, aud_playlist_entry_count (playlist)); + FINISH (clear); + return true; +} + +static gboolean do_delete (Obj * obj, Invoc * invoc, unsigned pos) +{ + aud_playlist_entry_delete (aud_playlist_get_active (), pos, 1); + FINISH (delete); + return true; +} + +static gboolean do_delete_active_playlist (Obj * obj, Invoc * invoc) +{ + aud_playlist_delete (aud_playlist_get_active ()); + FINISH (delete_active_playlist); + return true; +} + +static gboolean do_eject (Obj * obj, Invoc * invoc) +{ + if (! aud_get_headless_mode ()) + aud_ui_show_filebrowser (true); + + FINISH (eject); + return true; +} + +static gboolean do_equalizer_activate (Obj * obj, Invoc * invoc, gboolean active) +{ + aud_set_bool (nullptr, "equalizer_active", active); + FINISH (equalizer_activate); + return true; +} + +static gboolean do_get_active_playlist (Obj * obj, Invoc * invoc) +{ + FINISH2 (get_active_playlist, aud_playlist_get_active ()); + return true; +} + +static gboolean do_get_active_playlist_name (Obj * obj, Invoc * invoc) +{ + String title = aud_playlist_get_title (aud_playlist_get_active ()); + FINISH2 (get_active_playlist_name, title ? title : ""); + return true; +} + +static gboolean do_get_eq (Obj * obj, Invoc * invoc) +{ + double preamp = aud_get_double (nullptr, "equalizer_preamp"); + double bands[AUD_EQ_NBANDS]; + aud_eq_get_bands (bands); + + GVariant * var = g_variant_new_fixed_array (G_VARIANT_TYPE_DOUBLE, bands, + AUD_EQ_NBANDS, sizeof (double)); + FINISH2 (get_eq, preamp, var); + return true; +} + +static gboolean do_get_eq_band (Obj * obj, Invoc * invoc, int band) +{ + FINISH2 (get_eq_band, aud_eq_get_band (band)); + return true; +} + +static gboolean do_get_eq_preamp (Obj * obj, Invoc * invoc) +{ + FINISH2 (get_eq_preamp, aud_get_double (nullptr, "equalizer_preamp")); + return true; +} + +static gboolean do_get_info (Obj * obj, Invoc * invoc) +{ + int bitrate, samplerate, channels; + aud_drct_get_info (bitrate, samplerate, channels); + FINISH2 (get_info, bitrate, samplerate, channels); + return true; +} + +static gboolean do_get_playqueue_length (Obj * obj, Invoc * invoc) +{ + FINISH2 (get_playqueue_length, aud_playlist_queue_count (aud_playlist_get_active ())); + return true; +} + +static gboolean do_get_tuple_fields (Obj * obj, Invoc * invoc) +{ + const char * fields[Tuple::n_fields + 1]; + + for (auto f : Tuple::all_fields ()) + fields[f] = Tuple::field_get_name (f); + + fields[Tuple::n_fields] = nullptr; + + FINISH2 (get_tuple_fields, fields); + return true; +} + +static gboolean do_info (Obj * obj, Invoc * invoc) +{ + int bitrate, samplerate, channels; + aud_drct_get_info (bitrate, samplerate, channels); + FINISH2 (info, bitrate, samplerate, channels); + return true; +} + +static gboolean do_jump (Obj * obj, Invoc * invoc, unsigned pos) +{ + aud_playlist_set_position (aud_playlist_get_active (), pos); + FINISH (jump); + return true; +} + +static gboolean do_length (Obj * obj, Invoc * invoc) +{ + FINISH2 (length, aud_playlist_entry_count (aud_playlist_get_active ())); + return true; +} + +static gboolean do_main_win_visible (Obj * obj, Invoc * invoc) +{ + FINISH2 (main_win_visible, ! aud_get_headless_mode () && aud_ui_is_shown ()); + return true; +} + +static gboolean do_new_playlist (Obj * obj, Invoc * invoc) +{ + aud_playlist_insert (-1); + aud_playlist_set_active (aud_playlist_count () - 1); + FINISH (new_playlist); + return true; +} + +static gboolean do_number_of_playlists (Obj * obj, Invoc * invoc) +{ + FINISH2 (number_of_playlists, aud_playlist_count ()); + return true; +} + +static gboolean do_open_list (Obj * obj, Invoc * invoc, const char * const * filenames) +{ + aud_drct_pl_open_list (strv_to_index (filenames)); + FINISH (open_list); + return true; +} + +static gboolean do_open_list_to_temp (Obj * obj, Invoc * invoc, const char * const * filenames) +{ + aud_drct_pl_open_temp_list (strv_to_index (filenames)); + FINISH (open_list_to_temp); + return true; +} + +static gboolean do_pause (Obj * obj, Invoc * invoc) +{ + aud_drct_pause (); + FINISH (pause); + return true; +} + +static gboolean do_paused (Obj * obj, Invoc * invoc) +{ + FINISH2 (paused, aud_drct_get_paused ()); + return true; +} + +static gboolean do_play (Obj * obj, Invoc * invoc) +{ + aud_drct_play (); + FINISH (play); + return true; +} + +static gboolean do_play_active_playlist (Obj * obj, Invoc * invoc) +{ + aud_playlist_play (aud_playlist_get_active ()); + FINISH (play_active_playlist); + return true; +} + +static gboolean do_play_pause (Obj * obj, Invoc * invoc) +{ + aud_drct_play_pause (); + FINISH (play_pause); + return true; +} + +static gboolean do_playing (Obj * obj, Invoc * invoc) +{ + FINISH2 (playing, aud_drct_get_playing ()); + return true; +} + +static gboolean do_playlist_add (Obj * obj, Invoc * invoc, const char * list) +{ + aud_playlist_entry_insert (aud_playlist_get_active (), -1, list, Tuple (), false); + FINISH (playlist_add); + return true; +} + +static gboolean do_playlist_enqueue_to_temp (Obj * obj, Invoc * invoc, const char * url) +{ + aud_drct_pl_open_temp (url); + FINISH (playlist_enqueue_to_temp); + return true; +} + +static gboolean do_playlist_ins_url_string (Obj * obj, Invoc * invoc, const char * url, int pos) +{ + aud_playlist_entry_insert (aud_playlist_get_active (), pos, url, Tuple (), false); + FINISH (playlist_ins_url_string); + return true; +} + +static gboolean do_playqueue_add (Obj * obj, Invoc * invoc, int pos) +{ + aud_playlist_queue_insert (aud_playlist_get_active (), -1, pos); + FINISH (playqueue_add); + return true; +} + +static gboolean do_playqueue_clear (Obj * obj, Invoc * invoc) +{ + int playlist = aud_playlist_get_active (); + aud_playlist_queue_delete (playlist, 0, aud_playlist_queue_count (playlist)); + FINISH (playqueue_clear); + return true; +} + +static gboolean do_playqueue_is_queued (Obj * obj, Invoc * invoc, int pos) +{ + bool queued = (aud_playlist_queue_find_entry (aud_playlist_get_active (), pos) >= 0); + FINISH2 (playqueue_is_queued, queued); + return true; +} + +static gboolean do_playqueue_remove (Obj * obj, Invoc * invoc, int pos) +{ + int playlist = aud_playlist_get_active (); + int qpos = aud_playlist_queue_find_entry (playlist, pos); + + if (qpos >= 0) + aud_playlist_queue_delete (playlist, qpos, 1); + + FINISH (playqueue_remove); + return true; +} + +static gboolean do_position (Obj * obj, Invoc * invoc) +{ + FINISH2 (position, aud_playlist_get_position (aud_playlist_get_active ())); + return true; +} + +static gboolean do_queue_get_list_pos (Obj * obj, Invoc * invoc, unsigned qpos) +{ + FINISH2 (queue_get_list_pos, aud_playlist_queue_get_entry (aud_playlist_get_active (), qpos)); + return true; +} + +static gboolean do_queue_get_queue_pos (Obj * obj, Invoc * invoc, unsigned pos) +{ + FINISH2 (queue_get_queue_pos, aud_playlist_queue_find_entry (aud_playlist_get_active (), pos)); + return true; +} + +static gboolean do_quit (Obj * obj, Invoc * invoc) +{ + aud_quit (); + FINISH (quit); + return true; +} + +static gboolean do_repeat (Obj * obj, Invoc * invoc) +{ + FINISH2 (repeat, aud_get_bool (nullptr, "repeat")); + return true; +} + +static gboolean do_reverse (Obj * obj, Invoc * invoc) +{ + aud_drct_pl_prev (); + FINISH (reverse); + return true; +} + +static gboolean do_seek (Obj * obj, Invoc * invoc, unsigned pos) +{ + aud_drct_seek (pos); + FINISH (seek); + return true; +} + +static gboolean do_set_active_playlist (Obj * obj, Invoc * invoc, int playlist) +{ + aud_playlist_set_active (playlist); + FINISH (set_active_playlist); + return true; +} + +static gboolean do_set_active_playlist_name (Obj * obj, Invoc * invoc, const char * title) +{ + aud_playlist_set_title (aud_playlist_get_active (), title); + FINISH (set_active_playlist_name); + return true; +} + +static gboolean do_set_eq (Obj * obj, Invoc * invoc, double preamp, GVariant * var) +{ + if (! g_variant_is_of_type (var, G_VARIANT_TYPE ("ad"))) + return false; + + size_t nbands = 0; + const double * bands = (double *) g_variant_get_fixed_array (var, & nbands, sizeof (double)); + + if (nbands != AUD_EQ_NBANDS) + return false; + + aud_set_double (nullptr, "equalizer_preamp", preamp); + aud_eq_set_bands (bands); + FINISH (set_eq); + return true; +} + +static gboolean do_set_eq_band (Obj * obj, Invoc * invoc, int band, double value) +{ + aud_eq_set_band (band, value); + FINISH (set_eq_band); + return true; +} + +static gboolean do_set_eq_preamp (Obj * obj, Invoc * invoc, double preamp) +{ + aud_set_double (nullptr, "equalizer_preamp", preamp); + FINISH (set_eq_preamp); + return true; +} + +static gboolean do_set_volume (Obj * obj, Invoc * invoc, int vl, int vr) +{ + aud_drct_set_volume ({vl, vr}); + FINISH (set_volume); + return true; +} + +static gboolean do_show_about_box (Obj * obj, Invoc * invoc, gboolean show) +{ + if (! aud_get_headless_mode ()) + { + if (show) + aud_ui_show_about_window (); + else + aud_ui_hide_about_window (); + } + + FINISH (show_about_box); + return true; +} + +static gboolean do_show_filebrowser (Obj * obj, Invoc * invoc, gboolean show) +{ + if (! aud_get_headless_mode ()) + { + if (show) + aud_ui_show_filebrowser (false); + else + aud_ui_hide_filebrowser (); + } + + FINISH (show_filebrowser); + return true; +} + +static gboolean do_show_jtf_box (Obj * obj, Invoc * invoc, gboolean show) +{ + if (! aud_get_headless_mode ()) + { + if (show) + aud_ui_show_jump_to_song (); + else + aud_ui_hide_jump_to_song (); + } + + FINISH (show_jtf_box); + return true; +} + +static gboolean do_show_main_win (Obj * obj, Invoc * invoc, gboolean show) +{ + if (! aud_get_headless_mode ()) + aud_ui_show (show); + + FINISH (show_main_win); + return true; +} + +static gboolean do_show_prefs_box (Obj * obj, Invoc * invoc, gboolean show) +{ + if (! aud_get_headless_mode ()) + { + if (show) + aud_ui_show_prefs_window (); + else + aud_ui_hide_prefs_window (); + } + + FINISH (show_prefs_box); + return true; +} + +static gboolean do_shuffle (Obj * obj, Invoc * invoc) +{ + FINISH2 (shuffle, aud_get_bool (nullptr, "shuffle")); + return true; +} + +static gboolean do_song_filename (Obj * obj, Invoc * invoc, unsigned pos) +{ + String filename = aud_playlist_entry_get_filename (aud_playlist_get_active (), pos); + FINISH2 (song_filename, filename ? filename : ""); + return true; +} + +static gboolean do_song_frames (Obj * obj, Invoc * invoc, unsigned pos) +{ + Tuple tuple = aud_playlist_entry_get_tuple (aud_playlist_get_active (), pos); + FINISH2 (song_frames, aud::max (0, tuple.get_int (Tuple::Length))); + return true; +} + +static gboolean do_song_length (Obj * obj, Invoc * invoc, unsigned pos) +{ + Tuple tuple = aud_playlist_entry_get_tuple (aud_playlist_get_active (), pos); + int length = aud::max (0, tuple.get_int (Tuple::Length)); + FINISH2 (song_length, length / 1000); + return true; +} + +static gboolean do_song_title (Obj * obj, Invoc * invoc, unsigned pos) +{ + Tuple tuple = aud_playlist_entry_get_tuple (aud_playlist_get_active (), pos); + String title = tuple.get_str (Tuple::FormattedTitle); + FINISH2 (song_title, title ? title : ""); + return true; +} + +static gboolean do_song_tuple (Obj * obj, Invoc * invoc, unsigned pos, const char * key) +{ + Tuple::Field field = Tuple::field_by_name (key); + Tuple tuple; + GVariant * var = nullptr; + + if (field >= 0) + tuple = aud_playlist_entry_get_tuple (aud_playlist_get_active (), pos); + + if (tuple) + { + switch (tuple.get_value_type (field)) + { + case Tuple::String: + var = g_variant_new_string (tuple.get_str (field)); + break; + + case Tuple::Int: + var = g_variant_new_int32 (tuple.get_int (field)); + break; + + default: + break; + } + } + + if (! var) + var = g_variant_new_string (""); + + FINISH2 (song_tuple, g_variant_new_variant (var)); + return true; +} + +static gboolean do_status (Obj * obj, Invoc * invoc) +{ + const char * status = "stopped"; + if (aud_drct_get_playing ()) + status = aud_drct_get_paused () ? "paused" : "playing"; + + FINISH2 (status, status); + return true; +} + +static gboolean do_stop (Obj * obj, Invoc * invoc) +{ + aud_drct_stop (); + FINISH (stop); + return true; +} + +static gboolean do_stop_after (Obj * obj, Invoc * invoc) +{ + FINISH2 (stop_after, aud_get_bool (nullptr, "stop_after_current_song")); + return true; +} + +static gboolean do_stopped (Obj * obj, Invoc * invoc) +{ + FINISH2 (stopped, ! aud_drct_get_playing ()); + return true; +} + +static gboolean do_time (Obj * obj, Invoc * invoc) +{ + FINISH2 (time, aud_drct_get_time ()); + return true; +} + +static gboolean do_toggle_auto_advance (Obj * obj, Invoc * invoc) +{ + aud_set_bool (nullptr, "no_playlist_advance", ! aud_get_bool (nullptr, "no_playlist_advance")); + FINISH (toggle_auto_advance); + return true; +} + +static gboolean do_toggle_repeat (Obj * obj, Invoc * invoc) +{ + aud_set_bool (nullptr, "repeat", ! aud_get_bool (nullptr, "repeat")); + FINISH (toggle_repeat); + return true; +} + +static gboolean do_toggle_shuffle (Obj * obj, Invoc * invoc) +{ + aud_set_bool (nullptr, "shuffle", ! aud_get_bool (nullptr, "shuffle")); + FINISH (toggle_shuffle); + return true; +} + +static gboolean do_toggle_stop_after (Obj * obj, Invoc * invoc) +{ + aud_set_bool (nullptr, "stop_after_current_song", ! aud_get_bool (nullptr, "stop_after_current_song")); + FINISH (toggle_stop_after); + return true; +} + +static gboolean do_version (Obj * obj, Invoc * invoc) +{ + FINISH2 (version, VERSION); + return true; +} + +static gboolean do_volume (Obj * obj, Invoc * invoc) +{ + StereoVolume volume = aud_drct_get_volume (); + FINISH2 (volume, volume.left, volume.right); + return true; +} + +static const struct +{ + const char * signal; + GCallback callback; +} +handlers[] = +{ + {"handle-add", (GCallback) do_add}, + {"handle-add-list", (GCallback) do_add_list}, + {"handle-add-url", (GCallback) do_add_url}, + {"handle-advance", (GCallback) do_advance}, + {"handle-auto-advance", (GCallback) do_auto_advance}, + {"handle-balance", (GCallback) do_balance}, + {"handle-clear", (GCallback) do_clear}, + {"handle-delete", (GCallback) do_delete}, + {"handle-delete-active-playlist", (GCallback) do_delete_active_playlist}, + {"handle-eject", (GCallback) do_eject}, + {"handle-equalizer-activate", (GCallback) do_equalizer_activate}, + {"handle-get-active-playlist", (GCallback) do_get_active_playlist}, + {"handle-get-active-playlist-name", (GCallback) do_get_active_playlist_name}, + {"handle-get-eq", (GCallback) do_get_eq}, + {"handle-get-eq-band", (GCallback) do_get_eq_band}, + {"handle-get-eq-preamp", (GCallback) do_get_eq_preamp}, + {"handle-get-info", (GCallback) do_get_info}, + {"handle-get-playqueue-length", (GCallback) do_get_playqueue_length}, + {"handle-get-tuple-fields", (GCallback) do_get_tuple_fields}, + {"handle-info", (GCallback) do_info}, + {"handle-jump", (GCallback) do_jump}, + {"handle-length", (GCallback) do_length}, + {"handle-main-win-visible", (GCallback) do_main_win_visible}, + {"handle-new-playlist", (GCallback) do_new_playlist}, + {"handle-number-of-playlists", (GCallback) do_number_of_playlists}, + {"handle-open-list", (GCallback) do_open_list}, + {"handle-open-list-to-temp", (GCallback) do_open_list_to_temp}, + {"handle-pause", (GCallback) do_pause}, + {"handle-paused", (GCallback) do_paused}, + {"handle-play", (GCallback) do_play}, + {"handle-play-active-playlist", (GCallback) do_play_active_playlist}, + {"handle-play-pause", (GCallback) do_play_pause}, + {"handle-playing", (GCallback) do_playing}, + {"handle-playlist-add", (GCallback) do_playlist_add}, + {"handle-playlist-enqueue-to-temp", (GCallback) do_playlist_enqueue_to_temp}, + {"handle-playlist-ins-url-string", (GCallback) do_playlist_ins_url_string}, + {"handle-playqueue-add", (GCallback) do_playqueue_add}, + {"handle-playqueue-clear", (GCallback) do_playqueue_clear}, + {"handle-playqueue-is-queued", (GCallback) do_playqueue_is_queued}, + {"handle-playqueue-remove", (GCallback) do_playqueue_remove}, + {"handle-position", (GCallback) do_position}, + {"handle-queue-get-list-pos", (GCallback) do_queue_get_list_pos}, + {"handle-queue-get-queue-pos", (GCallback) do_queue_get_queue_pos}, + {"handle-quit", (GCallback) do_quit}, + {"handle-repeat", (GCallback) do_repeat}, + {"handle-reverse", (GCallback) do_reverse}, + {"handle-seek", (GCallback) do_seek}, + {"handle-set-active-playlist", (GCallback) do_set_active_playlist}, + {"handle-set-active-playlist-name", (GCallback) do_set_active_playlist_name}, + {"handle-set-eq", (GCallback) do_set_eq}, + {"handle-set-eq-band", (GCallback) do_set_eq_band}, + {"handle-set-eq-preamp", (GCallback) do_set_eq_preamp}, + {"handle-set-volume", (GCallback) do_set_volume}, + {"handle-show-about-box", (GCallback) do_show_about_box}, + {"handle-show-filebrowser", (GCallback) do_show_filebrowser}, + {"handle-show-jtf-box", (GCallback) do_show_jtf_box}, + {"handle-show-main-win", (GCallback) do_show_main_win}, + {"handle-show-prefs-box", (GCallback) do_show_prefs_box}, + {"handle-shuffle", (GCallback) do_shuffle}, + {"handle-song-filename", (GCallback) do_song_filename}, + {"handle-song-frames", (GCallback) do_song_frames}, + {"handle-song-length", (GCallback) do_song_length}, + {"handle-song-title", (GCallback) do_song_title}, + {"handle-song-tuple", (GCallback) do_song_tuple}, + {"handle-status", (GCallback) do_status}, + {"handle-stop", (GCallback) do_stop}, + {"handle-stop-after", (GCallback) do_stop_after}, + {"handle-stopped", (GCallback) do_stopped}, + {"handle-time", (GCallback) do_time}, + {"handle-toggle-auto-advance", (GCallback) do_toggle_auto_advance}, + {"handle-toggle-repeat", (GCallback) do_toggle_repeat}, + {"handle-toggle-shuffle", (GCallback) do_toggle_shuffle}, + {"handle-toggle-stop-after", (GCallback) do_toggle_stop_after}, + {"handle-version", (GCallback) do_version}, + {"handle-volume", (GCallback) do_volume} +}; + +static GMainLoop * mainloop = nullptr; +static unsigned owner_id = 0; + +static GDBusInterfaceSkeleton * skeleton = nullptr; + +static void name_acquired (GDBusConnection *, const char *, void *) +{ + AUDINFO ("Owned D-Bus name (org.atheme.audacious) on session bus.\n"); + + g_main_loop_quit (mainloop); +} + +static void name_lost (GDBusConnection *, const char *, void *) +{ + AUDINFO ("Owning D-Bus name (org.atheme.audacious) failed, already taken?\n"); + + g_bus_unown_name (owner_id); + owner_id = 0; + + g_main_loop_quit (mainloop); +} + +StartupType dbus_server_init (void) +{ + GError * error = nullptr; + GDBusConnection * bus = g_bus_get_sync (G_BUS_TYPE_SESSION, nullptr, & error); + GMainContext * context; + + if (! bus) + goto ERROR; + + skeleton = (GDBusInterfaceSkeleton *) obj_audacious_skeleton_new (); + + for (auto & handler : handlers) + g_signal_connect (skeleton, handler.signal, handler.callback, nullptr); + + if (! g_dbus_interface_skeleton_export (skeleton, bus, "/org/atheme/audacious", & error)) + goto ERROR; + + context = g_main_context_new (); + g_main_context_push_thread_default (context); + + owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, "org.atheme.audacious", + (GBusNameOwnerFlags) 0, nullptr, name_acquired, name_lost, nullptr, nullptr); + + mainloop = g_main_loop_new (context, true); + g_main_loop_run (mainloop); + g_main_loop_unref (mainloop); + mainloop = nullptr; + + g_main_context_pop_thread_default (context); + g_main_context_unref (context); + + if (owner_id) + return StartupType::Server; + + dbus_server_cleanup (); + return StartupType::Client; + +ERROR: + if (error) + { + AUDERR ("D-Bus error: %s\n", error->message); + g_error_free (error); + } + + dbus_server_cleanup (); + return StartupType::Unknown; +} + +void dbus_server_cleanup (void) +{ + if (owner_id) + { + g_bus_unown_name (owner_id); + owner_id = 0; + } + + if (skeleton) + { + g_object_unref (skeleton); + skeleton = nullptr; + } +} diff --git a/src/audacious/drct-api.h b/src/audacious/drct-api.h deleted file mode 100644 index cffaf4b..0000000 --- a/src/audacious/drct-api.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * drct-api.h - * Copyright 2010-2012 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -/* Do not include this file directly; use drct.h instead. */ - -/* CAUTION: These functions are not thread safe. */ - -/* --- PROGRAM CONTROL --- */ - -AUD_VFUNC0 (drct_quit) - -/* --- PLAYBACK CONTROL --- */ - -/* The strings returned by drct_get_filename() and drct_get_title() are pooled - * and must be freed with str_unref(). */ - -AUD_VFUNC0 (drct_play) -AUD_VFUNC0 (drct_play_pause) -AUD_VFUNC1 (drct_play_playlist, int, playlist) -AUD_VFUNC0 (drct_pause) -AUD_VFUNC0 (drct_stop) -AUD_FUNC0 (bool_t, drct_get_playing) -AUD_FUNC0 (bool_t, drct_get_ready) -AUD_FUNC0 (bool_t, drct_get_paused) -AUD_FUNC0 (char *, drct_get_filename) -AUD_FUNC0 (char *, drct_get_title) -AUD_VFUNC3 (drct_get_info, int *, bitrate, int *, samplerate, int *, channels) -AUD_FUNC0 (int, drct_get_time) -AUD_FUNC0 (int, drct_get_length) -AUD_VFUNC1 (drct_seek, int, time) - -/* "A-B repeat": when playback reaches point B, it returns to point A (where A - * and B are in milliseconds). The value -1 is interpreted as the beginning of - * the song (for A) or the end of the song (for B). A-B repeat is disabled - * entirely by setting both A and B to -1. */ -AUD_VFUNC2 (drct_set_ab_repeat, int, a, int, b) -AUD_VFUNC2 (drct_get_ab_repeat, int *, a, int *, b) - -/* --- VOLUME CONTROL --- */ - -AUD_VFUNC2 (drct_get_volume, int *, left, int *, right) -AUD_VFUNC2 (drct_set_volume, int, left, int, right) -AUD_VFUNC1 (drct_get_volume_main, int *, volume) -AUD_VFUNC1 (drct_set_volume_main, int, volume) -AUD_VFUNC1 (drct_get_volume_balance, int *, balance) -AUD_VFUNC1 (drct_set_volume_balance, int, balance) - -/* --- PLAYLIST CONTROL --- */ - -/* The indexes passed to drct_pl_add_list(), drct_pl_open_list(), and - * drct_pl_open_temp_list() contain pooled strings to which the caller gives up - * one reference. The indexes themselves are freed by these functions. */ - -AUD_VFUNC0 (drct_pl_next) -AUD_VFUNC0 (drct_pl_prev) - -AUD_VFUNC2 (drct_pl_add, const char *, filename, int, at) -AUD_VFUNC2 (drct_pl_add_list, Index *, filenames, int, at) -AUD_VFUNC1 (drct_pl_open, const char *, filename) -AUD_VFUNC1 (drct_pl_open_list, Index *, filenames) -AUD_VFUNC1 (drct_pl_open_temp, const char *, filename) -AUD_VFUNC1 (drct_pl_open_temp_list, Index *, filenames) diff --git a/src/audacious/drct.c b/src/audacious/drct.c deleted file mode 100644 index 5fbef8f..0000000 --- a/src/audacious/drct.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * drct.c - * Copyright 2009-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <libaudcore/hook.h> -#include <libaudcore/vfs.h> - -#include "drct.h" -#include "i18n.h" -#include "misc.h" -#include "playlist.h" - -/* --- PLAYBACK CONTROL --- */ - -void drct_play (void) -{ - if (drct_get_playing ()) - { - if (drct_get_paused ()) - drct_pause (); - else - { - int a, b; - drct_get_ab_repeat (& a, & b); - drct_seek (MAX (a, 0)); - } - } - else - { - int playlist = playlist_get_active (); - playlist_set_position (playlist, playlist_get_position (playlist)); - drct_play_playlist (playlist); - } -} - -void drct_play_pause (void) -{ - if (drct_get_playing ()) - drct_pause (); - else - drct_play (); -} - -void drct_play_playlist (int playlist) -{ - playlist_set_playing (playlist); - if (drct_get_paused ()) - drct_pause (); -} - -void drct_stop (void) -{ - playlist_set_playing (-1); -} - -/* --- VOLUME CONTROL --- */ - -void drct_get_volume_main (int * volume) -{ - int left, right; - drct_get_volume (& left, & right); - * volume = MAX (left, right); -} - -void drct_set_volume_main (int volume) -{ - int left, right, current; - drct_get_volume (& left, & right); - current = MAX (left, right); - - if (current > 0) - drct_set_volume (volume * left / current, volume * right / current); - else - drct_set_volume (volume, volume); -} - -void drct_get_volume_balance (int * balance) -{ - int left, right; - drct_get_volume (& left, & right); - - if (left == right) - * balance = 0; - else if (left > right) - * balance = -100 + right * 100 / left; - else - * balance = 100 - left * 100 / right; -} - -void drct_set_volume_balance (int balance) -{ - int left, right; - drct_get_volume_main (& left); - - if (balance < 0) - right = left * (100 + balance) / 100; - else - { - right = left; - left = right * (100 - balance) / 100; - } - - drct_set_volume (left, right); -} - -/* --- PLAYLIST CONTROL --- */ - -void drct_pl_next (void) -{ - int playlist = playlist_get_playing (); - if (playlist < 0) - playlist = playlist_get_active (); - - playlist_next_song (playlist, get_bool (NULL, "repeat")); -} - -void drct_pl_prev (void) -{ - int playlist = playlist_get_playing (); - if (playlist < 0) - playlist = playlist_get_active (); - - playlist_prev_song (playlist); -} - -static void add_list (Index * filenames, int at, bool_t to_temp, bool_t play) -{ - if (to_temp) - playlist_set_active (playlist_get_temporary ()); - - int playlist = playlist_get_active (); - - /* queue the new entries before deleting the old ones */ - /* this is to avoid triggering the --quit-after-play condition */ - playlist_entry_insert_batch (playlist, at, filenames, NULL, play); - - if (play) - { - if (get_bool (NULL, "clear_playlist")) - playlist_entry_delete (playlist, 0, playlist_entry_count (playlist)); - else - playlist_queue_delete (playlist, 0, playlist_queue_count (playlist)); - } -} - -void drct_pl_add (const char * filename, int at) -{ - Index * filenames = index_new (); - index_insert (filenames, -1, str_get (filename)); - add_list (filenames, at, FALSE, FALSE); -} - -void drct_pl_add_list (Index * filenames, int at) -{ - add_list (filenames, at, FALSE, FALSE); -} - -void drct_pl_open (const char * filename) -{ - Index * filenames = index_new (); - index_insert (filenames, -1, str_get (filename)); - add_list (filenames, -1, get_bool (NULL, "open_to_temporary"), TRUE); -} - -void drct_pl_open_list (Index * filenames) -{ - add_list (filenames, -1, get_bool (NULL, "open_to_temporary"), TRUE); -} - -void drct_pl_open_temp (const char * filename) -{ - Index * filenames = index_new (); - index_insert (filenames, -1, str_get (filename)); - add_list (filenames, -1, TRUE, TRUE); -} - -void drct_pl_open_temp_list (Index * filenames) -{ - add_list (filenames, -1, TRUE, TRUE); -} diff --git a/src/audacious/drct.h b/src/audacious/drct.h deleted file mode 100644 index 836a9bc..0000000 --- a/src/audacious/drct.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * drct.h - * Copyright 2010 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_DRCT_H -#define AUDACIOUS_DRCT_H - -#include <audacious/api.h> -#include <libaudcore/core.h> -#include <libaudcore/index.h> - -#define AUD_API_NAME DRCTAPI -#define AUD_API_SYMBOL drct_api - -#ifdef _AUDACIOUS_CORE - -#include "api-local-begin.h" -#include "drct-api.h" -#include "api-local-end.h" - -#else - -#include <audacious/api-define-begin.h> -#include <audacious/drct-api.h> -#include <audacious/api-define-end.h> - -#include <audacious/api-alias-begin.h> -#include <audacious/drct-api.h> -#include <audacious/api-alias-end.h> - -#endif - -#undef AUD_API_NAME -#undef AUD_API_SYMBOL - -#endif - -#ifdef AUD_API_DECLARE - -#define AUD_API_NAME DRCTAPI -#define AUD_API_SYMBOL drct_api - -#include "api-define-begin.h" -#include "drct-api.h" -#include "api-define-end.h" - -#include "api-declare-begin.h" -#include "drct-api.h" -#include "api-declare-end.h" - -#undef AUD_API_NAME -#undef AUD_API_SYMBOL - -#endif diff --git a/src/audacious/effect.c b/src/audacious/effect.c deleted file mode 100644 index 7d34368..0000000 --- a/src/audacious/effect.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * effect.c - * Copyright 2010-2012 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <glib.h> -#include <pthread.h> - -#include "debug.h" -#include "drct.h" -#include "effect.h" -#include "misc.h" -#include "plugin.h" -#include "plugins.h" - -typedef struct { - PluginHandle * plugin; - EffectPlugin * header; - int channels_returned, rate_returned; - bool_t remove_flag; -} RunningEffect; - -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -static GList * running_effects = NULL; /* (RunningEffect *) */ -static int input_channels, input_rate; - -typedef struct { - int * channels, * rate; -} EffectStartState; - -static bool_t effect_start_cb (PluginHandle * plugin, EffectStartState * state) -{ - AUDDBG ("Starting %s at %d channels, %d Hz.\n", plugin_get_name (plugin), - * state->channels, * state->rate); - EffectPlugin * header = plugin_get_header (plugin); - g_return_val_if_fail (header != NULL, TRUE); - header->start (state->channels, state->rate); - - RunningEffect * effect = g_slice_new (RunningEffect); - effect->plugin = plugin; - effect->header = header; - effect->channels_returned = * state->channels; - effect->rate_returned = * state->rate; - effect->remove_flag = FALSE; - - running_effects = g_list_prepend (running_effects, effect); - return TRUE; -} - -void effect_start (int * channels, int * rate) -{ - pthread_mutex_lock (& mutex); - - AUDDBG ("Starting effects.\n"); - - for (GList * node = running_effects; node; node = node->next) - g_slice_free (RunningEffect, node->data); - - g_list_free (running_effects); - running_effects = NULL; - - input_channels = * channels; - input_rate = * rate; - - EffectStartState state = {channels, rate}; - plugin_for_enabled (PLUGIN_TYPE_EFFECT, (PluginForEachFunc) effect_start_cb, - & state); - running_effects = g_list_reverse (running_effects); - - pthread_mutex_unlock (& mutex); -} - -typedef struct { - float * * data; - int * samples; -} EffectProcessState; - -static void effect_process_cb (RunningEffect * effect, EffectProcessState * - state) -{ - if (effect->remove_flag) - { - /* call finish twice to completely drain buffers */ - effect->header->finish (state->data, state->samples); - effect->header->finish (state->data, state->samples); - - running_effects = g_list_remove (running_effects, effect); - g_slice_free (RunningEffect, effect); - } - else - effect->header->process (state->data, state->samples); -} - -void effect_process (float * * data, int * samples) -{ - pthread_mutex_lock (& mutex); - - EffectProcessState state = {data, samples}; - g_list_foreach (running_effects, (GFunc) effect_process_cb, & state); - - pthread_mutex_unlock (& mutex); -} - -void effect_flush (void) -{ - pthread_mutex_lock (& mutex); - - for (GList * node = running_effects; node != NULL; node = node->next) - { - if (PLUGIN_HAS_FUNC (((RunningEffect *) node->data)->header, flush)) - ((RunningEffect *) node->data)->header->flush (); - } - - pthread_mutex_unlock (& mutex); -} - -void effect_finish (float * * data, int * samples) -{ - pthread_mutex_lock (& mutex); - - for (GList * node = running_effects; node != NULL; node = node->next) - ((RunningEffect *) node->data)->header->finish (data, samples); - - pthread_mutex_unlock (& mutex); -} - -int effect_adjust_delay (int delay) -{ - pthread_mutex_lock (& mutex); - - for (GList * node = g_list_last (running_effects); node != NULL; node = node->prev) - { - if (PLUGIN_HAS_FUNC (((RunningEffect *) node->data)->header, adjust_delay)) - delay = ((RunningEffect *) node->data)->header->adjust_delay (delay); - } - - pthread_mutex_unlock (& mutex); - return delay; -} - -static int effect_find_cb (RunningEffect * effect, PluginHandle * plugin) -{ - return (effect->plugin == plugin) ? 0 : -1; -} - -static int effect_compare (RunningEffect * a, RunningEffect * b) -{ - return plugin_compare (a->plugin, b->plugin); -} - -static void effect_insert (PluginHandle * plugin, EffectPlugin * header) -{ - GList * node = g_list_find_custom (running_effects, plugin, (GCompareFunc) effect_find_cb); - - if (node) - { - ((RunningEffect *) node->data)->remove_flag = FALSE; - return; - } - - AUDDBG ("Adding %s without reset.\n", plugin_get_name (plugin)); - RunningEffect * effect = g_slice_new (RunningEffect); - effect->plugin = plugin; - effect->header = header; - effect->remove_flag = FALSE; - - running_effects = g_list_insert_sorted (running_effects, effect, - (GCompareFunc) effect_compare); - node = g_list_find (running_effects, effect); - - int channels, rate; - if (node->prev != NULL) - { - RunningEffect * prev = node->prev->data; - AUDDBG ("Added %s after %s.\n", plugin_get_name (plugin), - plugin_get_name (prev->plugin)); - channels = prev->channels_returned; - rate = prev->rate_returned; - } - else - { - AUDDBG ("Added %s as first effect.\n", plugin_get_name (plugin)); - channels = input_channels; - rate = input_rate; - } - - AUDDBG ("Starting %s at %d channels, %d Hz.\n", plugin_get_name (plugin), - channels, rate); - header->start (& channels, & rate); - effect->channels_returned = channels; - effect->rate_returned = rate; -} - -static void effect_remove (PluginHandle * plugin) -{ - GList * node = g_list_find_custom (running_effects, plugin, (GCompareFunc) - effect_find_cb); - if (node == NULL) - return; - - AUDDBG ("Removing %s without reset.\n", plugin_get_name (plugin)); - ((RunningEffect *) node->data)->remove_flag = TRUE; -} - -static void effect_enable (PluginHandle * plugin, EffectPlugin * ep, bool_t - enable) -{ - if (ep->preserves_format) - { - pthread_mutex_lock (& mutex); - - if (enable) - effect_insert (plugin, ep); - else - effect_remove (plugin); - - pthread_mutex_unlock (& mutex); - } - else - { - AUDDBG ("Reset to add/remove %s.\n", plugin_get_name (plugin)); - output_reset (OUTPUT_RESET_EFFECTS_ONLY); - } -} - -bool_t effect_plugin_start (PluginHandle * plugin) -{ - if (drct_get_playing ()) - { - EffectPlugin * ep = plugin_get_header (plugin); - g_return_val_if_fail (ep != NULL, FALSE); - effect_enable (plugin, ep, TRUE); - } - - return TRUE; -} - -void effect_plugin_stop (PluginHandle * plugin) -{ - if (drct_get_playing ()) - { - EffectPlugin * ep = plugin_get_header (plugin); - g_return_if_fail (ep != NULL); - effect_enable (plugin, ep, FALSE); - } -} diff --git a/src/audacious/effect.h b/src/audacious/effect.h deleted file mode 100644 index 2a0add9..0000000 --- a/src/audacious/effect.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * effect.h - * Copyright 2010-2012 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_EFFECT_H -#define AUDACIOUS_EFFECT_H - -#include <libaudcore/core.h> - -#include "types.h" - -void effect_start (int * channels, int * rate); -void effect_process (float * * data, int * samples); -void effect_flush (void); -void effect_finish (float * * data, int * samples); -int effect_adjust_delay (int delay); - -bool_t effect_plugin_start (PluginHandle * plugin); -void effect_plugin_stop (PluginHandle * plugin); - -#endif diff --git a/src/audacious/equalizer.c b/src/audacious/equalizer.c deleted file mode 100644 index 1b74f31..0000000 --- a/src/audacious/equalizer.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * equalizer.c - * Copyright 2001 Anders Johansson - * Copyright 2010-2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -/* - * Anders Johansson prefers float *ptr; formatting. Please keep it that way. - * - tallica - */ - -#include <glib.h> -#include <math.h> -#include <pthread.h> -#include <string.h> - -#include <libaudcore/audstrings.h> -#include <libaudcore/hook.h> - -#include "equalizer.h" -#include "misc.h" -#include "types.h" - -#define EQ_BANDS AUD_EQUALIZER_NBANDS -#define MAX_CHANNELS 10 - -/* Q value for band-pass filters 1.2247 = (3/2)^(1/2) - * Gives 4 dB suppression at Fc*2 and Fc/2 */ -#define Q 1.2247449 - -/* Center frequencies for band-pass filters (Hz) */ -/* 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 float CF[EQ_BANDS] = {31.25, 62.5, 125, 250, 500, 1000, 2000, - 4000, 8000, 16000}; - -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -static bool_t active; -static int channels, rate; -static float a[EQ_BANDS][2]; /* A weights */ -static float b[EQ_BANDS][2]; /* B weights */ -static float wqv[MAX_CHANNELS][EQ_BANDS][2]; /* Circular buffer for W data */ -static float gv[MAX_CHANNELS][EQ_BANDS]; /* Gain factor for each channel and band */ -static int K; /* Number of used eq bands */ - -/* 2nd order band-pass filter design */ -static void bp2 (float *a, float *b, float fc, float q) -{ - float th = 2 * M_PI * fc; - float C = (1 - tanf (th * q / 2)) / (1 + tanf (th * q / 2)); - - a[0] = (1 + C) * cosf (th); - a[1] = -C; - b[0] = (1 - C) / 2; - b[1] = -1.005; -} - -void eq_set_format (int new_channels, int new_rate) -{ - int k; - - pthread_mutex_lock (& mutex); - - channels = new_channels; - rate = new_rate; - - /* Calculate number of active filters */ - K = EQ_BANDS; - - while (CF[K - 1] > (float) rate / 2.2) - K --; - - /* Generate filter taps */ - for (k = 0; k < K; k ++) - bp2 (a[k], b[k], CF[k] / (float) rate, Q); - - /* Reset state */ - memset (wqv[0][0], 0, sizeof wqv); - - pthread_mutex_unlock (& mutex); -} - -static void eq_set_bands_real (double preamp, double *values) -{ - float adj[EQ_BANDS]; - for (int i = 0; i < EQ_BANDS; i ++) - adj[i] = preamp + values[i]; - - for (int c = 0; c < MAX_CHANNELS; c ++) - for (int i = 0; i < EQ_BANDS; i ++) - gv[c][i] = pow (10, adj[i] / 20) - 1; -} - -void eq_filter (float *data, int samples) -{ - int channel; - - pthread_mutex_lock (& mutex); - - if (! active) - { - pthread_mutex_unlock (& mutex); - return; - } - - for (channel = 0; channel < channels; channel ++) - { - float *g = gv[channel]; /* Gain factor */ - float *end = data + samples; - float *f; - - for (f = data + channel; f < end; f += channels) - { - int k; /* Frequency band index */ - float yt = *f; /* Current input sample */ - - for (k = 0; k < K; k ++) - { - /* Pointer to circular buffer wq */ - float *wq = wqv[channel][k]; - /* Calculate output from AR part of current filter */ - float w = yt * b[k][0] + wq[0] * a[k][0] + wq[1] * a[k][1]; - - /* Calculate output from MA part of current filter */ - yt += (w + wq[1] * b[k][1]) * g[k]; - - /* Update circular buffer */ - wq[1] = wq[0]; - wq[0] = w; - } - - /* Calculate output */ - *f = yt; - } - } - - pthread_mutex_unlock (& mutex); -} - -static void eq_update (void *data, void *user) -{ - pthread_mutex_lock (& mutex); - - active = get_bool (NULL, "equalizer_active"); - - double values[EQ_BANDS]; - eq_get_bands (values); - eq_set_bands_real (get_double (NULL, "equalizer_preamp"), values); - - pthread_mutex_unlock (& mutex); -} - -void eq_init (void) -{ - eq_update (NULL, NULL); - hook_associate ("set equalizer_active", eq_update, NULL); - hook_associate ("set equalizer_preamp", eq_update, NULL); - hook_associate ("set equalizer_bands", eq_update, NULL); -} - -void eq_cleanup (void) -{ - hook_dissociate ("set equalizer_active", eq_update); - hook_dissociate ("set equalizer_preamp", eq_update); - hook_dissociate ("set equalizer_bands", eq_update); -} - -void eq_set_bands (const double *values) -{ - char *string = double_array_to_str (values, EQ_BANDS); - g_return_if_fail (string); - set_str (NULL, "equalizer_bands", string); - str_unref (string); -} - -void eq_get_bands (double *values) -{ - memset (values, 0, sizeof (double) * EQ_BANDS); - char *string = get_str (NULL, "equalizer_bands"); - str_to_double_array (string, values, EQ_BANDS); - str_unref (string); -} - -void eq_set_band (int band, double value) -{ - g_return_if_fail (band >= 0 && band < EQ_BANDS); - double values[EQ_BANDS]; - eq_get_bands (values); - values[band] = value; - eq_set_bands (values); -} - -double eq_get_band (int band) -{ - g_return_val_if_fail (band >= 0 && band < EQ_BANDS, 0); - double values[EQ_BANDS]; - eq_get_bands (values); - return values[band]; -} diff --git a/src/audacious/equalizer.h b/src/audacious/equalizer.h deleted file mode 100644 index 3acb472..0000000 --- a/src/audacious/equalizer.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * equalizer.h - * Copyright 2010 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_EQUALIZER_H -#define AUDACIOUS_EQUALIZER_H - -void eq_init (void); -void eq_cleanup (void); -void eq_set_format (int new_channels, int new_rate); -void eq_filter (float * data, int samples); - -#endif diff --git a/src/audacious/equalizer_preset.c b/src/audacious/equalizer_preset.c deleted file mode 100644 index 6c70eb8..0000000 --- a/src/audacious/equalizer_preset.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * equalizer_preset.c - * Copyright 2003-2013 Eugene Zagidullin, William Pitcock, John Lindgren, and - * Thomas Lange - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <glib.h> -#include <math.h> -#include <string.h> - -#include <libaudcore/audstrings.h> - -#include "debug.h" -#include "i18n.h" -#include "misc.h" - -EqualizerPreset * equalizer_preset_new (const char * name) -{ - EqualizerPreset * preset = g_slice_new0 (EqualizerPreset); - preset->name = str_get (name); - return preset; -} - -void equalizer_preset_free (EqualizerPreset * preset) -{ - str_unref (preset->name); - g_slice_free (EqualizerPreset, preset); -} - -Index * equalizer_read_presets (const char * basename) -{ - GKeyFile * rcfile = g_key_file_new (); - - char * filename = filename_build (get_path (AUD_PATH_USER_DIR), basename); - - if (! g_key_file_load_from_file (rcfile, filename, G_KEY_FILE_NONE, NULL)) - { - str_unref (filename); - filename = filename_build (get_path (AUD_PATH_DATA_DIR), basename); - - if (! g_key_file_load_from_file (rcfile, filename, G_KEY_FILE_NONE, NULL)) - { - str_unref (filename); - g_key_file_free (rcfile); - return NULL; - } - } - - str_unref (filename); - - Index * list = index_new (); - - for (int p = 0;; p ++) - { - SPRINTF (section, "Preset%d", p); - - char * name = g_key_file_get_string (rcfile, "Presets", section, NULL); - if (! name) - break; - - EqualizerPreset * preset = equalizer_preset_new (name); - preset->preamp = g_key_file_get_double (rcfile, name, "Preamp", NULL); - - for (int i = 0; i < AUD_EQUALIZER_NBANDS; i++) - { - SPRINTF (band, "Band%d", i); - preset->bands[i] = g_key_file_get_double (rcfile, name, band, NULL); - } - - index_insert (list, -1, preset); - - g_free (name); - } - - g_key_file_free (rcfile); - - return list; -} - -bool_t equalizer_write_presets (Index * list, const char * basename) -{ - GKeyFile * rcfile = g_key_file_new (); - - for (int p = 0; p < index_count (list); p ++) - { - EqualizerPreset * preset = index_get (list, p); - - SPRINTF (tmp, "Preset%d", p); - g_key_file_set_string (rcfile, "Presets", tmp, preset->name); - g_key_file_set_double (rcfile, preset->name, "Preamp", preset->preamp); - - for (int i = 0; i < AUD_EQUALIZER_NBANDS; i ++) - { - SPRINTF (tmp, "Band%d", i); - g_key_file_set_double (rcfile, preset->name, tmp, preset->bands[i]); - } - } - - size_t len; - char * data = g_key_file_to_data (rcfile, & len, NULL); - - char * filename = filename_build (get_path (AUD_PATH_USER_DIR), basename); - bool_t success = g_file_set_contents (filename, data, len, NULL); - str_unref (filename); - - g_key_file_free (rcfile); - g_free (data); - - return success; -} - -/* Note: Winamp 2.x had a +/- 20 dB range. - * Winamp 5.x had a +/- 12 dB range, which we use here. */ -#define FROM_WINAMP_VAL(x) ((31.5 - (x)) * (12.0 / 31.5)) -#define TO_WINAMP_VAL(x) (round (31.5 - (x) * (31.5 / 12.0))) - -Index * import_winamp_presets (VFSFile * file) -{ - char header[31]; - char bands[11]; - char preset_name[181]; - - if (vfs_fread (header, 1, sizeof header, file) != sizeof header || - strncmp (header, "Winamp EQ library file v1.1", 27)) - return NULL; - - Index * list = index_new (); - - while (vfs_fread (preset_name, 1, 180, file) == 180) - { - preset_name[180] = 0; /* protect against buffer overflow */ - - if (vfs_fseek (file, 77, SEEK_CUR)) /* unknown crap --asphyx */ - break; - - if (vfs_fread (bands, 1, 11, file) != 11) - break; - - EqualizerPreset * preset = equalizer_preset_new (preset_name); - preset->preamp = FROM_WINAMP_VAL (bands[10]); - - for (int i = 0; i < AUD_EQUALIZER_NBANDS; i ++) - preset->bands[i] = FROM_WINAMP_VAL (bands[i]); - - index_insert (list, -1, preset); - } - - return list; -} - -bool_t export_winamp_preset (EqualizerPreset * preset, VFSFile * file) -{ - char name[257]; - char bands[11]; - - if (vfs_fwrite ("Winamp EQ library file v1.1\x1a!--", 1, 31, file) != 31) - return FALSE; - - strncpy (name, preset->name, 257); - - if (vfs_fwrite (name, 1, 257, file) != 257) - return FALSE; - - for (int i = 0; i < AUD_EQUALIZER_NBANDS; i ++) - bands[i] = TO_WINAMP_VAL (preset->bands[i]); - - bands[10] = TO_WINAMP_VAL (preset->preamp); - - if (vfs_fwrite (bands, 1, 11, file) != 11) - return FALSE; - - return TRUE; -} - -bool_t save_preset_file (EqualizerPreset * preset, const char * filename) -{ - GKeyFile * rcfile = g_key_file_new (); - - g_key_file_set_double (rcfile, "Equalizer preset", "Preamp", preset->preamp); - - for (int i = 0; i < AUD_EQUALIZER_NBANDS; i ++) - { - SPRINTF (tmp, "Band%d", i); - g_key_file_set_double (rcfile, "Equalizer preset", tmp, preset->bands[i]); - } - - size_t len; - char * data = g_key_file_to_data (rcfile, & len, NULL); - - VFSFile * file = vfs_fopen (filename, "w"); - bool_t success = FALSE; - - if (file) - { - success = (vfs_fwrite (data, 1, len, file) == len); - vfs_fclose (file); - } - - g_key_file_free (rcfile); - g_free (data); - - return success; -} - -EqualizerPreset * load_preset_file (const char * filename) -{ - GKeyFile * rcfile = g_key_file_new (); - - if (! g_key_file_load_from_file (rcfile, filename, G_KEY_FILE_NONE, NULL)) - { - g_key_file_free (rcfile); - return NULL; - } - - EqualizerPreset * preset = equalizer_preset_new (""); - - preset->preamp = g_key_file_get_double (rcfile, "Equalizer preset", "Preamp", NULL); - - for (int i = 0; i < AUD_EQUALIZER_NBANDS; i ++) - { - SPRINTF (tmp, "Band%d", i); - preset->bands[i] = g_key_file_get_double (rcfile, "Equalizer preset", tmp, NULL); - } - - g_key_file_free (rcfile); - - return preset; -} diff --git a/src/audacious/fft.c b/src/audacious/fft.c deleted file mode 100644 index 09a6602..0000000 --- a/src/audacious/fft.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * fft.c - * Copyright 2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <complex.h> -#include <math.h> - -#include "fft.h" - -#define N 512 /* size of the DFT */ -#define LOGN 9 /* log N (base 2) */ - -static float hamming[N]; /* hamming window, scaled to sum to 1 */ -static int reversed[N]; /* bit-reversal table */ -static float complex roots[N / 2]; /* N-th roots of unity */ -static char generated = 0; /* set if tables have been generated */ - -/* Reverse the order of the lowest LOGN bits in an integer. */ - -static int bit_reverse (int x) -{ - int y = 0; - - for (int n = LOGN; n --; ) - { - y = (y << 1) | (x & 1); - x >>= 1; - } - - return y; -} - -/* Generate lookup tables. */ - -static void generate_tables (void) -{ - if (generated) - return; - - for (int n = 0; n < N; n ++) - hamming[n] = 1 - 0.85 * cosf (2 * M_PI * n / N); - for (int n = 0; n < N; n ++) - reversed[n] = bit_reverse (n); - for (int n = 0; n < N / 2; n ++) - roots[n] = cexpf (2 * M_PI * I * n / N); - - generated = 1; -} - -/* Perform the DFT using the Cooley-Tukey algorithm. At each step s, where - * s=1..log N (base 2), there are N/(2^s) groups of intertwined butterfly - * operations. Each group contains (2^s)/2 butterflies, and each butterfly has - * a span of (2^s)/2. The twiddle factors are nth roots of unity where n = 2^s. */ - -static void do_fft (float complex a[N]) -{ - int half = 1; /* (2^s)/2 */ - int inv = N / 2; /* N/(2^s) */ - - /* loop through steps */ - while (inv) - { - /* loop through groups */ - for (int g = 0; g < N; g += half << 1) - { - /* loop through butterflies */ - for (int b = 0, r = 0; b < half; b ++, r += inv) - { - float complex even = a[g + b]; - float complex odd = roots[r] * a[g + half + b]; - a[g + b] = even + odd; - a[g + half + b] = even - odd; - } - } - - half <<= 1; - inv >>= 1; - } -} - -/* Input is N=512 PCM samples. - * Output is intensity of frequencies from 1 to N/2=256. */ - -void calc_freq (const float data[N], float freq[N / 2]) -{ - generate_tables (); - - /* input is filtered by a Hamming window */ - /* input values are in bit-reversed order */ - float complex a[N]; - for (int n = 0; n < N; n ++) - a[reversed[n]] = data[n] * hamming[n]; - - do_fft (a); - - /* output values are divided by N */ - /* frequencies from 1 to N/2-1 are doubled */ - for (int n = 0; n < N / 2 - 1; n ++) - freq[n] = 2 * cabsf (a[1 + n]) / N; - - /* frequency N/2 is not doubled */ - freq[N / 2 - 1] = cabsf (a[N / 2]) / N; -} diff --git a/src/audacious/fft.h b/src/audacious/fft.h deleted file mode 100644 index bb8cba3..0000000 --- a/src/audacious/fft.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * fft.h - * Copyright 2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_FFT_H -#define AUDACIOUS_FFT_H - -void calc_freq (const float data[512], float freq[256]); - -#endif diff --git a/src/audacious/general.c b/src/audacious/general.c deleted file mode 100644 index e0b9ea2..0000000 --- a/src/audacious/general.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * general.c - * Copyright 2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <gtk/gtk.h> - -#include "debug.h" -#include "general.h" -#include "interface.h" -#include "plugin.h" -#include "plugins.h" -#include "ui_preferences.h" - -typedef struct { - PluginHandle * plugin; - GeneralPlugin * gp; - GtkWidget * widget; -} LoadedGeneral; - -static int running = FALSE; -static GList * loaded_general_plugins = NULL; - -static int general_find_cb (LoadedGeneral * general, PluginHandle * plugin) -{ - return (general->plugin == plugin) ? 0 : -1; -} - -static void general_load (PluginHandle * plugin) -{ - GList * node = g_list_find_custom (loaded_general_plugins, plugin, - (GCompareFunc) general_find_cb); - if (node != NULL) - return; - - AUDDBG ("Loading %s.\n", plugin_get_name (plugin)); - GeneralPlugin * gp = plugin_get_header (plugin); - g_return_if_fail (gp != NULL); - - LoadedGeneral * general = g_slice_new (LoadedGeneral); - general->plugin = plugin; - general->gp = gp; - general->widget = NULL; - - if (gp->get_widget != NULL) - general->widget = gp->get_widget (); - - if (general->widget != NULL) - { - AUDDBG ("Adding %s to interface.\n", plugin_get_name (plugin)); - g_signal_connect (general->widget, "destroy", (GCallback) - gtk_widget_destroyed, & general->widget); - interface_add_plugin_widget (plugin, general->widget); - } - - loaded_general_plugins = g_list_prepend (loaded_general_plugins, general); -} - -static void general_unload (PluginHandle * plugin) -{ - GList * node = g_list_find_custom (loaded_general_plugins, plugin, - (GCompareFunc) general_find_cb); - if (node == NULL) - return; - - AUDDBG ("Unloading %s.\n", plugin_get_name (plugin)); - LoadedGeneral * general = node->data; - loaded_general_plugins = g_list_delete_link (loaded_general_plugins, node); - - if (general->widget != NULL) - { - AUDDBG ("Removing %s from interface.\n", plugin_get_name (plugin)); - interface_remove_plugin_widget (plugin, general->widget); - g_return_if_fail (general->widget == NULL); /* not destroyed? */ - } - - g_slice_free (LoadedGeneral, general); -} - -static bool_t general_init_cb (PluginHandle * plugin) -{ - general_load (plugin); - return TRUE; -} - -void general_init (void) -{ - g_return_if_fail (! running); - running = TRUE; - - plugin_for_enabled (PLUGIN_TYPE_GENERAL, (PluginForEachFunc) - general_init_cb, NULL); -} - -static void general_cleanup_cb (LoadedGeneral * general) -{ - general_unload (general->plugin); -} - -void general_cleanup (void) -{ - g_return_if_fail (running); - running = FALSE; - - g_list_foreach (loaded_general_plugins, (GFunc) general_cleanup_cb, NULL); -} - -bool_t general_plugin_start (PluginHandle * plugin) -{ - GeneralPlugin * gp = plugin_get_header (plugin); - g_return_val_if_fail (gp != NULL, FALSE); - - if (gp->init != NULL && ! gp->init ()) - return FALSE; - - if (running) - general_load (plugin); - - return TRUE; -} - -void general_plugin_stop (PluginHandle * plugin) -{ - GeneralPlugin * gp = plugin_get_header (plugin); - g_return_if_fail (gp != NULL); - - if (running) - general_unload (plugin); - - if (gp->cleanup != NULL) - gp->cleanup (); -} - -PluginHandle * general_plugin_by_widget (/* GtkWidget * */ void * widget) -{ - g_return_val_if_fail (widget, NULL); - - for (GList * node = loaded_general_plugins; node; node = node->next) - { - LoadedGeneral * general = node->data; - if (general->widget == widget) - return general->plugin; - } - - return NULL; -} diff --git a/src/audacious/general.h b/src/audacious/general.h deleted file mode 100644 index c9a7c9e..0000000 --- a/src/audacious/general.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * general.h - * Copyright 2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_GENERAL_H -#define AUDACIOUS_GENERAL_H - -#include "plugins.h" - -void general_init (void); -void general_cleanup (void); - -bool_t general_plugin_start (PluginHandle * plugin); -void general_plugin_stop (PluginHandle * plugin); - -PluginHandle * general_plugin_by_widget (/* GtkWidget * */ void * widget); - -#endif diff --git a/src/audacious/history.c b/src/audacious/history.c deleted file mode 100644 index 4dde368..0000000 --- a/src/audacious/history.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * history.c - * Copyright 2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <glib.h> -#include <stdio.h> -#include <string.h> - -#include <libaudcore/hook.h> - -#include "main.h" -#include "misc.h" - -#define MAX_ENTRIES 30 - -static GQueue history = G_QUEUE_INIT; -static bool_t loaded, modified; - -static void history_save (void) -{ - if (! modified) - return; - - GList * node = history.head; - for (int i = 0; i < MAX_ENTRIES; i ++) - { - if (! node) - break; - - char name[32]; - snprintf (name, sizeof name, "entry%d", i); - set_str ("history", name, node->data); - - node = node->next; - } - - modified = FALSE; -} - -static void history_load (void) -{ - if (loaded) - return; - - for (int i = 0; ; i ++) - { - char name[32]; - snprintf (name, sizeof name, "entry%d", i); - char * path = get_str ("history", name); - - if (! path[0]) - { - str_unref (path); - break; - } - - g_queue_push_tail (& history, path); - } - - loaded = TRUE; - hook_associate ("config save", (HookFunction) history_save, NULL); -} - -void history_cleanup (void) -{ - if (! loaded) - return; - - hook_dissociate ("config save", (HookFunction) history_save); - - g_queue_foreach (& history, (GFunc) str_unref, NULL); - g_queue_clear (& history); - - loaded = FALSE; - modified = FALSE; -} - -const char * history_get (int entry) -{ - history_load (); - return g_queue_peek_nth (& history, entry); -} - -void history_add (const char * path) -{ - history_load (); - - GList * next; - for (GList * node = history.head; node; node = next) - { - next = node->next; - if (! strcmp (node->data, path)) - { - str_unref (node->data); - g_queue_delete_link (& history, node); - } - } - - g_queue_push_head (& history, str_get (path)); - modified = TRUE; -} diff --git a/src/audacious/i18n.h b/src/audacious/i18n.h deleted file mode 100644 index 5b5205c..0000000 --- a/src/audacious/i18n.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * i18n.h - * Copyright 2007 William Pitcock - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_I18N_H -#define AUDACIOUS_I18N_H - -#include <libintl.h> - -#define _(String) dgettext (PACKAGE, String) -#ifdef gettext_noop -#define N_(String) gettext_noop (String) -#else -#define N_(String) (String) -#endif - -#endif /* AUDACIOUS_I18N_H */ diff --git a/src/audacious/images/about-logo.png b/src/audacious/images/about-logo.png Binary files differdeleted file mode 100644 index 32fb69f..0000000 --- a/src/audacious/images/about-logo.png +++ /dev/null diff --git a/src/audacious/images/album.png b/src/audacious/images/album.png Binary files differdeleted file mode 100644 index a47bc7d..0000000 --- a/src/audacious/images/album.png +++ /dev/null diff --git a/src/audacious/images/appearance.png b/src/audacious/images/appearance.png Binary files differdeleted file mode 100644 index f73239a..0000000 --- a/src/audacious/images/appearance.png +++ /dev/null diff --git a/src/audacious/images/audio.png b/src/audacious/images/audio.png Binary files differdeleted file mode 100644 index a41d51a..0000000 --- a/src/audacious/images/audio.png +++ /dev/null diff --git a/src/audacious/images/connectivity.png b/src/audacious/images/connectivity.png Binary files differdeleted file mode 100644 index 2d80e79..0000000 --- a/src/audacious/images/connectivity.png +++ /dev/null diff --git a/src/audacious/images/info.png b/src/audacious/images/info.png Binary files differdeleted file mode 100644 index 91e2c17..0000000 --- a/src/audacious/images/info.png +++ /dev/null diff --git a/src/audacious/images/playlist.png b/src/audacious/images/playlist.png Binary files differdeleted file mode 100644 index 2574ef0..0000000 --- a/src/audacious/images/playlist.png +++ /dev/null diff --git a/src/audacious/images/plugins.png b/src/audacious/images/plugins.png Binary files differdeleted file mode 100644 index da9f9e1..0000000 --- a/src/audacious/images/plugins.png +++ /dev/null diff --git a/src/audacious/input-api.h b/src/audacious/input-api.h deleted file mode 100644 index 7c49b0e..0000000 --- a/src/audacious/input-api.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * input-api.h - * Copyright 2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -/* Do not include this file directly; use input.h instead. */ - -/* These functions are to be used only from the play() function of an input plugin. */ - -/* Prepares the output system for playback in the specified format. Returns - * TRUE on success, FALSE if the selected format is not supported. */ -AUD_FUNC3 (bool_t, input_open_audio, int, format, int, rate, int, channels) - -/* Informs the output system of replay gain values for the current song so - * that volume levels can be adjusted accordingly, if the user so desires. - * This may be called at any time during playback should the values change. */ -AUD_VFUNC1 (input_set_gain, const ReplayGainInfo *, info) - -/* Passes audio data to the output system for playback. The data must be in - * the format passed to open_audio, and the length (in bytes) must be an - * integral number of frames. This function blocks until all the data has - * been written (though it may not yet be heard by the user). */ -AUD_VFUNC2 (input_write_audio, void *, data, int, length) - -/* Returns the time counter. Note that this represents the amount of audio - * data passed to the output system, not the amount actually heard by the - * user. */ -AUD_FUNC0 (int, input_written_time) - -/* Returns a reference to the current tuple for the stream. */ -AUD_FUNC0 (Tuple *, input_get_tuple) - -/* Updates the tuple for the stream. The caller gives up ownership of one - * reference to the tuple. */ -AUD_VFUNC1 (input_set_tuple, Tuple *, tuple) - -/* Updates the displayed bitrate, in bits per second. */ -AUD_VFUNC1 (input_set_bitrate, int, bitrate) - -/* Checks whether playback is to be stopped. The play() function should poll - * check_stop() periodically and return as soon as check_stop() returns TRUE. */ -AUD_FUNC0 (bool_t, input_check_stop) - -/* Checks whether a seek has been requested. If so, discards any buffered audio - * and returns the position to seek to, in milliseconds. Otherwise, returns -1. */ -AUD_FUNC0 (int, input_check_seek) diff --git a/src/audacious/input.h b/src/audacious/input.h deleted file mode 100644 index 4935483..0000000 --- a/src/audacious/input.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * input.h - * Copyright 2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_INPUT_H -#define AUDACIOUS_INPUT_H - -#include <audacious/api.h> -#include <audacious/types.h> -#include <libaudcore/tuple.h> - -#define AUD_API_NAME InputAPI -#define AUD_API_SYMBOL input_api - -#ifdef _AUDACIOUS_CORE - -#include "api-local-begin.h" -#include "input-api.h" -#include "api-local-end.h" - -#else - -#include <audacious/api-define-begin.h> -#include <audacious/input-api.h> -#include <audacious/api-define-end.h> - -#include <audacious/api-alias-begin.h> -#include <audacious/input-api.h> -#include <audacious/api-alias-end.h> - -#endif - -#undef AUD_API_NAME -#undef AUD_API_SYMBOL - -#endif - -#ifdef AUD_API_DECLARE - -#define AUD_API_NAME InputAPI -#define AUD_API_SYMBOL input_api - -#include "api-define-begin.h" -#include "input-api.h" -#include "api-define-end.h" - -#include "api-declare-begin.h" -#include "input-api.h" -#include "api-declare-end.h" - -#undef AUD_API_NAME -#undef AUD_API_SYMBOL - -#endif diff --git a/src/audacious/interface.c b/src/audacious/interface.c deleted file mode 100644 index 5c8045f..0000000 --- a/src/audacious/interface.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * interface.c - * Copyright 2010-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <gtk/gtk.h> -#include <pthread.h> - -#include <libaudcore/hook.h> -#include <libaudgui/libaudgui-gtk.h> - -#include "debug.h" -#include "general.h" -#include "i18n.h" -#include "interface.h" -#include "misc.h" -#include "plugin.h" -#include "plugins.h" -#include "visualization.h" - -static IfacePlugin * current_interface = NULL; - -static pthread_mutex_t error_mutex = PTHREAD_MUTEX_INITIALIZER; -static GQueue error_queue = G_QUEUE_INIT; -static int error_source; -static GtkWidget * error_win; - -bool_t interface_load (PluginHandle * plugin) -{ - IfacePlugin * i = plugin_get_header (plugin); - g_return_val_if_fail (i, FALSE); - - if (PLUGIN_HAS_FUNC (i, init) && ! i->init ()) - return FALSE; - - current_interface = i; - return TRUE; -} - -void interface_unload (void) -{ - g_return_if_fail (current_interface); - - if (PLUGIN_HAS_FUNC (current_interface, cleanup)) - current_interface->cleanup (); - - current_interface = NULL; -} - -void interface_show (bool_t show) -{ - g_return_if_fail (current_interface); - - set_bool (NULL, "show_interface", show); - - if (PLUGIN_HAS_FUNC (current_interface, show)) - current_interface->show (show); -} - -bool_t interface_is_shown (void) -{ - g_return_val_if_fail (current_interface, FALSE); - - return get_bool (NULL, "show_interface"); -} - -static bool_t error_idle_func (void * unused) -{ - pthread_mutex_lock (& error_mutex); - - char * message; - while ((message = g_queue_pop_head (& error_queue))) - { - pthread_mutex_unlock (& error_mutex); - - if (headless_mode ()) - fprintf (stderr, "ERROR: %s\n", message); - else - audgui_simple_message (& error_win, GTK_MESSAGE_ERROR, _("Error"), message); - - str_unref (message); - - pthread_mutex_lock (& error_mutex); - } - - error_source = 0; - - pthread_mutex_unlock (& error_mutex); - return FALSE; -} - -void interface_show_error (const char * message) -{ - pthread_mutex_lock (& error_mutex); - - g_queue_push_tail (& error_queue, str_get (message)); - - if (! error_source) - error_source = g_idle_add (error_idle_func, NULL); - - pthread_mutex_unlock (& error_mutex); -} - -static bool_t delete_cb (GtkWidget * window, GdkEvent * event, PluginHandle * - plugin) -{ - plugin_enable (plugin, FALSE); - return TRUE; -} - -void interface_add_plugin_widget (PluginHandle * plugin, GtkWidget * widget) -{ - g_return_if_fail (current_interface); - - if (PLUGIN_HAS_FUNC (current_interface, run_gtk_plugin)) - current_interface->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_window_set_default_size ((GtkWindow *) window, 300, 200); - gtk_window_set_has_resize_grip ((GtkWindow *) window, FALSE); - gtk_container_add ((GtkContainer *) window, widget); - g_signal_connect (window, "delete-event", (GCallback) delete_cb, plugin); - gtk_widget_show_all (window); - } -} - -void interface_remove_plugin_widget (PluginHandle * plugin, GtkWidget * widget) -{ - g_return_if_fail (current_interface); - - if (PLUGIN_HAS_FUNC (current_interface, stop_gtk_plugin)) - current_interface->stop_gtk_plugin (widget); - else - gtk_widget_destroy (gtk_widget_get_parent (widget)); -} - -static bool_t probe_cb (PluginHandle * p, PluginHandle * * pp) -{ - * pp = p; - return FALSE; -} - -PluginHandle * iface_plugin_probe (void) -{ - PluginHandle * p = NULL; - plugin_for_each (PLUGIN_TYPE_IFACE, (PluginForEachFunc) probe_cb, & p); - return p; -} - -static PluginHandle * current_plugin = NULL; - -PluginHandle * iface_plugin_get_current (void) -{ - return current_plugin; -} - -bool_t iface_plugin_set_current (PluginHandle * plugin) -{ - hook_call ("config save", NULL); /* tell interface to save layout */ - - if (current_plugin != NULL) - { - if (get_bool (NULL, "show_interface") && current_interface && - PLUGIN_HAS_FUNC (current_interface, show)) - current_interface->show (FALSE); - - AUDDBG ("Unloading plugin widgets.\n"); - general_cleanup (); - - AUDDBG ("Unloading visualizers.\n"); - vis_cleanup (); - - AUDDBG ("Unloading %s.\n", plugin_get_name (current_plugin)); - interface_unload (); - - current_plugin = NULL; - } - - if (plugin != NULL) - { - AUDDBG ("Loading %s.\n", plugin_get_name (plugin)); - - if (! interface_load (plugin)) - return FALSE; - - current_plugin = plugin; - - AUDDBG ("Loading visualizers.\n"); - vis_init (); - - AUDDBG ("Loading plugin widgets.\n"); - general_init (); - - if (get_bool (NULL, "show_interface") && current_interface && - PLUGIN_HAS_FUNC (current_interface, show)) - current_interface->show (TRUE); - } - - return TRUE; -} diff --git a/src/audacious/interface.h b/src/audacious/interface.h deleted file mode 100644 index 8bc5727..0000000 --- a/src/audacious/interface.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * interface.h - * Copyright 2010-2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef __AUDACIOUS2_INTERFACE_H__ -#define __AUDACIOUS2_INTERFACE_H__ - -#include <gtk/gtk.h> -#include <audacious/plugins.h> - -bool_t interface_load (PluginHandle * plugin); -void interface_unload (void); - -void interface_add_plugin_widget (PluginHandle * plugin, GtkWidget * widget); -void interface_remove_plugin_widget (PluginHandle * plugin, GtkWidget * widget); - -PluginHandle * iface_plugin_probe (void); -PluginHandle * iface_plugin_get_current (void); -bool_t iface_plugin_set_current (PluginHandle * plugin); - -#endif diff --git a/src/audacious/main.c b/src/audacious/main.c deleted file mode 100644 index 8440969..0000000 --- a/src/audacious/main.c +++ /dev/null @@ -1,634 +0,0 @@ -/* - * main.c - * Copyright 2007-2013 William Pitcock and John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <errno.h> -#include <fcntl.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <unistd.h> -#include <locale.h> - -#include <gtk/gtk.h> - -#include <libaudcore/audstrings.h> -#include <libaudcore/hook.h> -#include <libaudgui/libaudgui.h> -#include <libaudtag/audtag.h> - -#ifdef USE_DBUS -#include "aud-dbus.h" -#endif - -#include "debug.h" -#include "drct.h" -#include "equalizer.h" -#include "i18n.h" -#include "interface.h" -#include "main.h" -#include "misc.h" -#include "playlist.h" -#include "plugins.h" -#include "scanner.h" -#include "util.h" - -#define AUTOSAVE_INTERVAL 300 /* seconds */ - -static struct { - bool_t help, version; - bool_t play, pause, play_pause, stop, fwd, rew; - bool_t enqueue, enqueue_to_temp; - bool_t mainwin, show_jump_box; - bool_t headless, quit_after_play; - bool_t verbose; -} options; - -static Index * filenames; - -static const struct { - const char * long_arg; - char short_arg; - bool_t * value; - const char * desc; -} arg_map[] = { - {"help", 'h', & options.help, N_("Show command-line help")}, - {"version", 'v', & options.version, N_("Show version")}, - {"play", 'p', & options.play, N_("Start playback")}, - {"pause", 'u', & options.pause, N_("Pause playback")}, - {"play-pause", 't', & options.play_pause, N_("Pause if playing, play otherwise")}, - {"stop", 's', & options.stop, N_("Stop playback")}, - {"rew", 'r', & options.rew, N_("Skip to previous song")}, - {"fwd", 'f', & options.fwd, N_("Skip to next song")}, - {"enqueue", 'e', & options.enqueue, N_("Add files to the playlist")}, - {"enqueue-to-temp", 'E', & options.enqueue_to_temp, N_("Add files to a temporary playlist")}, - {"show-main-window", 'm', & options.mainwin, N_("Display the main window")}, - {"show-jump-box", 'j', & options.show_jump_box, N_("Display the jump-to-song window")}, - {"headless", 'H', & options.headless, N_("Start without a graphical interface")}, - {"quit-after-play", 'q', & options.quit_after_play, N_("Quit on playback stop")}, - {"verbose", 'V', & options.verbose, N_("Print debugging messages")}, -}; - -static char * aud_paths[AUD_PATH_COUNT]; - -static void make_dirs(void) -{ -#ifdef S_IRGRP - const mode_t mode755 = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; -#else - const mode_t mode755 = S_IRWXU; -#endif - - make_directory(aud_paths[AUD_PATH_USER_DIR], mode755); - make_directory(aud_paths[AUD_PATH_PLAYLISTS_DIR], mode755); -} - -static char * relocate_path (const char * path, const char * old, const char * new) -{ - int oldlen = strlen (old); - int newlen = strlen (new); - - if (oldlen && old[oldlen - 1] == G_DIR_SEPARATOR) - oldlen --; - if (newlen && new[newlen - 1] == G_DIR_SEPARATOR) - newlen --; - -#ifdef _WIN32 - if (g_ascii_strncasecmp (path, old, oldlen) || (path[oldlen] && path[oldlen] != G_DIR_SEPARATOR)) -#else - if (strncmp (path, old, oldlen) || (path[oldlen] && path[oldlen] != G_DIR_SEPARATOR)) -#endif - { - fprintf (stderr, "Failed to relocate a data path. Falling back to " - "compile-time path: %s\n", path); - return str_get (path); - } - - return str_printf ("%.*s%s", newlen, new, path + oldlen); -} - -static void relocate_paths (void) -{ - char bindir[] = HARDCODE_BINDIR; - char datadir[] = HARDCODE_DATADIR; - char plugindir[] = HARDCODE_PLUGINDIR; - char localedir[] = HARDCODE_LOCALEDIR; - char desktopfile[] = HARDCODE_DESKTOPFILE; - char iconfile[] = HARDCODE_ICONFILE; - - filename_normalize (bindir); - filename_normalize (datadir); - filename_normalize (plugindir); - filename_normalize (localedir); - filename_normalize (desktopfile); - filename_normalize (iconfile); - - /* Compare the compile-time path to the executable and the actual path to - * see if we have been moved. */ - char * self = get_path_to_self (); - if (! self) - { -FALLBACK: - /* Fall back to compile-time paths. */ - aud_paths[AUD_PATH_BIN_DIR] = str_get (bindir); - aud_paths[AUD_PATH_DATA_DIR] = str_get (datadir); - aud_paths[AUD_PATH_PLUGIN_DIR] = str_get (plugindir); - aud_paths[AUD_PATH_LOCALE_DIR] = str_get (localedir); - aud_paths[AUD_PATH_DESKTOP_FILE] = str_get (desktopfile); - aud_paths[AUD_PATH_ICON_FILE] = str_get (iconfile); - - return; - } - - SCOPY (old, bindir); - SCOPY (new, self); - - str_unref (self); - - filename_normalize (new); - - /* Strip the name of the executable file, leaving the path. */ - char * base = last_path_element (new); - if (! base) - goto FALLBACK; - - cut_path_element (new, base); - - /* Strip innermost folder names from both paths as long as they match. This - * leaves a compile-time prefix and a run-time one to replace it with. */ - char * a, * b; - while ((a = last_path_element (old)) && (b = last_path_element (new)) && -#ifdef _WIN32 - ! g_ascii_strcasecmp (a, b)) -#else - ! strcmp (a, b)) -#endif - { - cut_path_element (old, a); - cut_path_element (new, b); - } - - /* Do the replacements. */ - aud_paths[AUD_PATH_BIN_DIR] = relocate_path (bindir, old, new); - aud_paths[AUD_PATH_DATA_DIR] = relocate_path (datadir, old, new); - aud_paths[AUD_PATH_PLUGIN_DIR] = relocate_path (plugindir, old, new); - aud_paths[AUD_PATH_LOCALE_DIR] = relocate_path (localedir, old, new); - aud_paths[AUD_PATH_DESKTOP_FILE] = relocate_path (desktopfile, old, new); - aud_paths[AUD_PATH_ICON_FILE] = relocate_path (iconfile, old, new); -} - -static void init_paths (void) -{ - relocate_paths (); - - const char * xdg_config_home = g_get_user_config_dir (); - - aud_paths[AUD_PATH_USER_DIR] = filename_build (xdg_config_home, "audacious"); - aud_paths[AUD_PATH_PLAYLISTS_DIR] = filename_build (aud_paths[AUD_PATH_USER_DIR], "playlists"); - -#ifdef _WIN32 - /* Some libraries (libmcs) and plugins (filewriter) use these variables, - * which are generally not set on Windows. */ - g_setenv ("HOME", g_get_home_dir (), TRUE); - g_setenv ("XDG_CONFIG_HOME", xdg_config_home, TRUE); - g_setenv ("XDG_DATA_HOME", g_get_user_data_dir (), TRUE); - g_setenv ("XDG_CACHE_HOME", g_get_user_cache_dir (), TRUE); -#endif -} - -const char * get_path (int id) -{ - g_return_val_if_fail (id >= 0 && id < AUD_PATH_COUNT, NULL); - return aud_paths[id]; -} - -static bool_t parse_options (int argc, char * * argv) -{ - char * cur = g_get_current_dir (); - bool_t success = TRUE; - -#ifdef _WIN32 - get_argv_utf8 (& argc, & argv); -#endif - - for (int n = 1; n < argc; n ++) - { - if (argv[n][0] != '-') /* filename */ - { - char * uri = NULL; - - if (strstr (argv[n], "://")) - uri = str_get (argv[n]); - else if (g_path_is_absolute (argv[n])) - uri = filename_to_uri (argv[n]); - else - { - char * tmp = filename_build (cur, argv[n]); - uri = filename_to_uri (tmp); - str_unref (tmp); - } - - if (uri) - { - if (! filenames) - filenames = index_new (); - - index_insert (filenames, -1, uri); - } - } - else if (argv[n][1] == '-') /* long option */ - { - int i; - - for (i = 0; i < ARRAY_LEN (arg_map); i ++) - { - if (! strcmp (argv[n] + 2, arg_map[i].long_arg)) - { - * arg_map[i].value = TRUE; - break; - } - } - - if (i == ARRAY_LEN (arg_map)) - { - fprintf (stderr, _("Unknown option: %s\n"), argv[n]); - success = FALSE; - goto OUT; - } - } - else /* short form */ - { - for (int c = 1; argv[n][c]; c ++) - { - int i; - - for (i = 0; i < ARRAY_LEN (arg_map); i ++) - { - if (argv[n][c] == arg_map[i].short_arg) - { - * arg_map[i].value = TRUE; - break; - } - } - - if (i == ARRAY_LEN (arg_map)) - { - fprintf (stderr, _("Unknown option: -%c\n"), argv[n][c]); - success = FALSE; - goto OUT; - } - } - } - } - - verbose = options.verbose; - -OUT: -#ifdef _WIN32 - free_argv_utf8 (& argc, & argv); -#endif - - g_free (cur); - return success; -} - -static void print_help (void) -{ - static const char pad[20] = " "; - - fprintf (stderr, _("Usage: audacious [OPTION] ... [FILE] ...\n\n")); - - for (int i = 0; i < ARRAY_LEN (arg_map); i ++) - fprintf (stderr, " -%c, --%s%.*s%s\n", arg_map[i].short_arg, - arg_map[i].long_arg, (int) (20 - strlen (arg_map[i].long_arg)), pad, - _(arg_map[i].desc)); - - fprintf (stderr, "\n"); -} - -bool_t headless_mode (void) -{ - return options.headless; -} - -#ifdef USE_DBUS -static void do_remote (void) -{ - GDBusConnection * bus = NULL; - ObjAudacious * obj = NULL; - GError * error = NULL; - - if (! (bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, & error))) - goto ERR; - - if (! (obj = obj_audacious_proxy_new_sync (bus, 0, "org.atheme.audacious", - "/org/atheme/audacious", NULL, & error))) - goto ERR; - - /* check whether remote is running */ - char * version = NULL; - obj_audacious_call_version_sync (obj, & version, NULL, NULL); - - if (! version) - goto DONE; - - AUDDBG ("Connected to remote version %s.\n", version); - - /* if no command line options, then present running instance */ - if (! (filenames || options.play || options.pause || options.play_pause || - options.stop || options.rew || options.fwd || options.show_jump_box || - options.mainwin)) - options.mainwin = TRUE; - - if (filenames) - { - int n_filenames = index_count (filenames); - const char * * list = g_new (const char *, n_filenames + 1); - - for (int i = 0; i < n_filenames; i ++) - list[i] = index_get (filenames, i); - - list[n_filenames] = NULL; - - if (options.enqueue_to_temp) - obj_audacious_call_open_list_to_temp_sync (obj, list, NULL, NULL); - else if (options.enqueue) - obj_audacious_call_add_list_sync (obj, list, NULL, NULL); - else - obj_audacious_call_open_list_sync (obj, list, NULL, NULL); - - g_free (list); - } - - if (options.play) - obj_audacious_call_play_sync (obj, NULL, NULL); - if (options.pause) - obj_audacious_call_pause_sync (obj, NULL, NULL); - if (options.play_pause) - obj_audacious_call_play_pause_sync (obj, NULL, NULL); - if (options.stop) - obj_audacious_call_stop_sync (obj, NULL, NULL); - if (options.rew) - obj_audacious_call_reverse_sync (obj, NULL, NULL); - if (options.fwd) - obj_audacious_call_advance_sync (obj, NULL, NULL); - if (options.show_jump_box) - obj_audacious_call_show_jtf_box_sync (obj, TRUE, NULL, NULL); - if (options.mainwin) - obj_audacious_call_show_main_win_sync (obj, TRUE, NULL, NULL); - - g_free (version); - g_object_unref (obj); - - exit (EXIT_SUCCESS); - -ERR: - fprintf (stderr, "D-Bus error: %s\n", error->message); - g_error_free (error); - -DONE: - if (obj) - g_object_unref (obj); - - return; -} -#endif - -static void do_commands (void) -{ - bool_t resume = get_bool (NULL, "resume_playback_on_startup"); - - if (filenames) - { - if (options.enqueue_to_temp) - { - drct_pl_open_temp_list (filenames); - resume = FALSE; - } - else if (options.enqueue) - drct_pl_add_list (filenames, -1); - else - { - drct_pl_open_list (filenames); - resume = FALSE; - } - - filenames = NULL; - } - - if (resume) - playlist_resume (); - - if (options.play || options.play_pause) - { - if (! drct_get_playing ()) - drct_play (); - else if (drct_get_paused ()) - drct_pause (); - } - - if (options.show_jump_box && ! options.headless) - audgui_jump_to_track (); - if (options.mainwin && ! options.headless) - interface_show (TRUE); -} - -static void main_cleanup (void) -{ - for (int i = 0; i < AUD_PATH_COUNT; i ++) - str_unref (aud_paths[i]); - - if (filenames) - index_free_full (filenames, (IndexFreeFunc) str_unref); - - strpool_shutdown (); -} - -static void init_one (void) -{ - atexit (main_cleanup); - -#ifdef HAVE_SIGWAIT - signals_init_one (); -#endif - - init_paths (); - make_dirs (); - - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, aud_paths[AUD_PATH_LOCALE_DIR]); - bind_textdomain_codeset (PACKAGE, "UTF-8"); - bindtextdomain (PACKAGE "-plugins", aud_paths[AUD_PATH_LOCALE_DIR]); - bind_textdomain_codeset (PACKAGE "-plugins", "UTF-8"); - textdomain (PACKAGE); - -#if ! GLIB_CHECK_VERSION (2, 36, 0) - g_type_init (); -#endif -} - -static void init_two (void) -{ - if (! options.headless) - gtk_init (NULL, NULL); - -#ifdef HAVE_SIGWAIT - signals_init_two (); -#endif - - AUDDBG ("Loading configuration.\n"); - config_load (); - - AUDDBG ("Initializing.\n"); - art_init (); - chardet_init (); - eq_init (); - playlist_init (); - - tag_set_verbose (verbose); - vfs_set_verbose (verbose); - - AUDDBG ("Loading lowlevel plugins.\n"); - start_plugins_one (); - - AUDDBG ("Starting worker threads.\n"); - adder_init (); - scanner_init (); - - AUDDBG ("Restoring state.\n"); - load_playlists (); - - do_commands (); - - AUDDBG ("Loading highlevel plugins.\n"); - start_plugins_two (); - -#ifdef USE_DBUS - dbus_server_init (); -#endif -} - -static void shut_down (void) -{ - AUDDBG ("Saving playlist state.\n"); - save_playlists (TRUE); - - AUDDBG ("Unloading highlevel plugins.\n"); - stop_plugins_two (); - -#ifdef USE_DBUS - dbus_server_cleanup (); -#endif - - AUDDBG ("Stopping playback.\n"); - if (drct_get_playing ()) - drct_stop (); - - AUDDBG ("Stopping worker threads.\n"); - adder_cleanup (); - scanner_cleanup (); - - AUDDBG ("Unloading lowlevel plugins.\n"); - stop_plugins_one (); - - event_queue_cancel_all (); - - AUDDBG ("Saving configuration.\n"); - config_save (); - config_cleanup (); - - AUDDBG ("Cleaning up.\n"); - art_cleanup (); - chardet_cleanup (); - eq_cleanup (); - history_cleanup (); - playlist_end (); -} - -bool_t do_autosave (void) -{ - AUDDBG ("Saving configuration.\n"); - hook_call ("config save", NULL); - save_playlists (FALSE); - config_save (); - return TRUE; -} - -static bool_t check_should_quit (void) -{ - return options.quit_after_play && ! drct_get_playing () && ! playlist_add_in_progress (-1); -} - -static void maybe_quit (void) -{ - if (check_should_quit ()) - gtk_main_quit (); -} - -int main (int argc, char * * argv) -{ - init_one (); - - if (! parse_options (argc, argv)) - { - print_help (); - return EXIT_FAILURE; - } - - if (options.help) - { - print_help (); - return EXIT_SUCCESS; - } - - if (options.version) - { - printf ("%s %s (%s)\n", _("Audacious"), VERSION, BUILDSTAMP); - return EXIT_SUCCESS; - } - -#if USE_DBUS - do_remote (); /* may exit */ -#endif - - AUDDBG ("No remote session; starting up.\n"); - init_two (); - - AUDDBG ("Startup complete.\n"); - g_timeout_add_seconds (AUTOSAVE_INTERVAL, (GSourceFunc) do_autosave, NULL); - - if (check_should_quit ()) - goto QUIT; - - hook_associate ("playback stop", (HookFunction) maybe_quit, NULL); - hook_associate ("playlist add complete", (HookFunction) maybe_quit, NULL); - - gtk_main (); - - hook_dissociate ("playback stop", (HookFunction) maybe_quit); - hook_dissociate ("playlist add complete", (HookFunction) maybe_quit); - -QUIT: - shut_down (); - return EXIT_SUCCESS; -} - -void drct_quit (void) -{ - gtk_main_quit (); -} diff --git a/src/audacious/main.cc b/src/audacious/main.cc new file mode 100644 index 0000000..ca6526f --- /dev/null +++ b/src/audacious/main.cc @@ -0,0 +1,384 @@ +/* + * main.c + * Copyright 2007-2013 William Pitcock and John Lindgren + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions, and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions, and the following disclaimer in the documentation + * provided with the distribution. + * + * This software is provided "as is" and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising from + * the use of this software. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <glib.h> /* for g_get_current_dir, g_path_is_absolute */ + +#include <libaudcore/audstrings.h> +#include <libaudcore/drct.h> +#include <libaudcore/hook.h> +#include <libaudcore/i18n.h> +#include <libaudcore/interface.h> +#include <libaudcore/playlist.h> +#include <libaudcore/runtime.h> +#include <libaudcore/tuple.h> + +#ifdef USE_DBUS +#include "aud-dbus.h" +#endif + +#include "main.h" +#include "util.h" + +static struct { + int help, version; + int play, pause, play_pause, stop, fwd, rew; + int enqueue, enqueue_to_temp; + int mainwin, show_jump_box; + int headless, quit_after_play; + int verbose; + int qt; +} options; + +static Index<PlaylistAddItem> filenames; + +static const struct { + const char * long_arg; + char short_arg; + int * value; + const char * desc; +} arg_map[] = { + {"help", 'h', & options.help, N_("Show command-line help")}, + {"version", 'v', & options.version, N_("Show version")}, + {"play", 'p', & options.play, N_("Start playback")}, + {"pause", 'u', & options.pause, N_("Pause playback")}, + {"play-pause", 't', & options.play_pause, N_("Pause if playing, play otherwise")}, + {"stop", 's', & options.stop, N_("Stop playback")}, + {"rew", 'r', & options.rew, N_("Skip to previous song")}, + {"fwd", 'f', & options.fwd, N_("Skip to next song")}, + {"enqueue", 'e', & options.enqueue, N_("Add files to the playlist")}, + {"enqueue-to-temp", 'E', & options.enqueue_to_temp, N_("Add files to a temporary playlist")}, + {"show-main-window", 'm', & options.mainwin, N_("Display the main window")}, + {"show-jump-box", 'j', & options.show_jump_box, N_("Display the jump-to-song window")}, + {"headless", 'H', & options.headless, N_("Start without a graphical interface")}, + {"quit-after-play", 'q', & options.quit_after_play, N_("Quit on playback stop")}, + {"verbose", 'V', & options.verbose, N_("Print debugging messages (may be used twice)")}, +#if defined(USE_QT) && defined(USE_GTK) + {"qt", 'Q', & options.qt, N_("Run in Qt mode")}, +#endif +}; + +static bool parse_options (int argc, char * * argv) +{ + char * cur = g_get_current_dir (); + bool success = true; + +#ifdef _WIN32 + Index<String> args = get_argv_utf8 (); + + for (int n = 1; n < args.len (); n ++) + { + const char * arg = args[n]; +#else + for (int n = 1; n < argc; n ++) + { + const char * arg = argv[n]; +#endif + + if (arg[0] != '-') /* filename */ + { + String uri; + + if (strstr (arg, "://")) + uri = String (arg); + else if (g_path_is_absolute (arg)) + uri = String (filename_to_uri (arg)); + else + uri = String (filename_to_uri (filename_build ({cur, arg}))); + + if (uri) + filenames.append (uri); + } + else if (arg[1] == '-') /* long option */ + { + bool found = false; + + for (auto & arg_info : arg_map) + { + if (! strcmp (arg + 2, arg_info.long_arg)) + { + (* arg_info.value) ++; + found = true; + break; + } + } + + if (! found) + { + fprintf (stderr, _("Unknown option: %s\n"), arg); + success = false; + goto OUT; + } + } + else /* short form */ + { + for (int c = 1; arg[c]; c ++) + { + bool found = false; + + for (auto & arg_info : arg_map) + { + if (arg[c] == arg_info.short_arg) + { + (* arg_info.value) ++; + found = true; + break; + } + } + + if (! found) + { + fprintf (stderr, _("Unknown option: -%c\n"), arg[c]); + success = false; + goto OUT; + } + } + } + } + + aud_set_headless_mode (options.headless); + + if (options.verbose >= 2) + audlog::set_stderr_level (audlog::Debug); + else if (options.verbose) + audlog::set_stderr_level (audlog::Info); + + if (options.qt) + aud_set_mainloop_type (MainloopType::Qt); + +OUT: + g_free (cur); + return success; +} + +static void print_help (void) +{ + static const char pad[21] = " "; + + fprintf (stderr, _("Usage: audacious [OPTION] ... [FILE] ...\n\n")); + + for (auto & arg_info : arg_map) + fprintf (stderr, " -%c, --%s%.*s%s\n", arg_info.short_arg, + arg_info.long_arg, (int) (20 - strlen (arg_info.long_arg)), pad, + _(arg_info.desc)); + + fprintf (stderr, "\n"); +} + +#ifdef USE_DBUS +static void do_remote (void) +{ + GDBusConnection * bus = nullptr; + ObjAudacious * obj = nullptr; + GError * error = nullptr; + +#if ! GLIB_CHECK_VERSION (2, 36, 0) + g_type_init (); +#endif + + /* check whether this is the first instance */ + if (dbus_server_init () != StartupType::Client) + return; + + if (! (bus = g_bus_get_sync (G_BUS_TYPE_SESSION, nullptr, & error))) + goto ERR; + + if (! (obj = obj_audacious_proxy_new_sync (bus, (GDBusProxyFlags) 0, + "org.atheme.audacious", "/org/atheme/audacious", nullptr, & error))) + goto ERR; + + AUDINFO ("Connected to remote session.\n"); + + /* if no command line options, then present running instance */ + if (! (filenames.len () || options.play || options.pause || + options.play_pause || options.stop || options.rew || options.fwd || + options.show_jump_box || options.mainwin)) + options.mainwin = true; + + if (filenames.len ()) + { + Index<const char *> list; + + for (auto & item : filenames) + list.append (item.filename); + + list.append (nullptr); + + if (options.enqueue_to_temp) + obj_audacious_call_open_list_to_temp_sync (obj, list.begin (), nullptr, nullptr); + else if (options.enqueue) + obj_audacious_call_add_list_sync (obj, list.begin (), nullptr, nullptr); + else + obj_audacious_call_open_list_sync (obj, list.begin (), nullptr, nullptr); + } + + if (options.play) + obj_audacious_call_play_sync (obj, nullptr, nullptr); + if (options.pause) + obj_audacious_call_pause_sync (obj, nullptr, nullptr); + if (options.play_pause) + obj_audacious_call_play_pause_sync (obj, nullptr, nullptr); + if (options.stop) + obj_audacious_call_stop_sync (obj, nullptr, nullptr); + if (options.rew) + obj_audacious_call_reverse_sync (obj, nullptr, nullptr); + if (options.fwd) + obj_audacious_call_advance_sync (obj, nullptr, nullptr); + if (options.show_jump_box) + obj_audacious_call_show_jtf_box_sync (obj, true, nullptr, nullptr); + if (options.mainwin) + obj_audacious_call_show_main_win_sync (obj, true, nullptr, nullptr); + + g_object_unref (obj); + + exit (EXIT_SUCCESS); + +ERR: + if (error) + { + AUDERR ("D-Bus error: %s\n", error->message); + g_error_free (error); + } +} +#endif + +static void do_commands (void) +{ + bool resume = aud_get_bool (nullptr, "resume_playback_on_startup"); + + if (filenames.len ()) + { + if (options.enqueue_to_temp) + { + aud_drct_pl_open_temp_list (std::move (filenames)); + resume = false; + } + else if (options.enqueue) + aud_drct_pl_add_list (std::move (filenames), -1); + else + { + aud_drct_pl_open_list (std::move (filenames)); + resume = false; + } + } + + if (resume) + aud_resume (); + + if (options.play || options.play_pause) + { + if (! aud_drct_get_playing ()) + aud_drct_play (); + else if (aud_drct_get_paused ()) + aud_drct_pause (); + } + + if (options.show_jump_box && ! options.headless) + aud_ui_show_jump_to_song (); + if (options.mainwin && ! options.headless) + aud_ui_show (true); +} + +static void main_cleanup (void) +{ + filenames.clear (); + aud_cleanup_paths (); + aud_leak_check (); +} + +static bool check_should_quit (void) +{ + return options.quit_after_play && ! aud_drct_get_playing () && + ! aud_playlist_add_in_progress (-1); +} + +static void maybe_quit (void) +{ + if (check_should_quit ()) + aud_quit (); +} + +int main (int argc, char * * argv) +{ + atexit (main_cleanup); + +#ifdef HAVE_SIGWAIT + signals_init_one (); +#endif + + aud_init_paths (); + aud_init_i18n (); + + if (! parse_options (argc, argv)) + { + print_help (); + return EXIT_FAILURE; + } + + if (options.help) + { + print_help (); + return EXIT_SUCCESS; + } + + if (options.version) + { + printf ("%s %s (%s)\n", _("Audacious"), VERSION, BUILDSTAMP); + return EXIT_SUCCESS; + } + +#if USE_DBUS + do_remote (); /* may exit */ +#endif + + AUDINFO ("No remote session; starting up.\n"); + +#ifdef HAVE_SIGWAIT + signals_init_two (); +#endif + + aud_init (); + + do_commands (); + + if (check_should_quit ()) + goto QUIT; + + hook_associate ("playback stop", (HookFunction) maybe_quit, nullptr); + hook_associate ("playlist add complete", (HookFunction) maybe_quit, nullptr); + hook_associate ("quit", (HookFunction) aud_quit, nullptr); + + aud_run (); + + hook_dissociate ("playback stop", (HookFunction) maybe_quit); + hook_dissociate ("playlist add complete", (HookFunction) maybe_quit); + hook_dissociate ("quit", (HookFunction) aud_quit); + +QUIT: +#ifdef USE_DBUS + dbus_server_cleanup (); +#endif + + aud_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/src/audacious/main.h b/src/audacious/main.h index 0fa3432..88fd0de 100644 --- a/src/audacious/main.h +++ b/src/audacious/main.h @@ -17,41 +17,22 @@ * the use of this software. */ -/* Header for all those files that have just one or two public identifiers. */ - #ifndef _AUDACIOUS_MAIN_H #define _AUDACIOUS_MAIN_H -#include <libaudcore/core.h> - -/* adder.c */ -void adder_init (void); -void adder_cleanup (void); - -/* art.c */ -void art_init (void); -void art_cleanup (void); - /* dbus-server.c */ #ifdef USE_DBUS -void dbus_server_init (void); -void dbus_server_cleanup (void); -#endif - -/* chardet.c */ -void chardet_init (void); -void chardet_cleanup (void); -/* config.c */ -void config_load (void); -void config_save (void); -void config_cleanup (void); +enum class StartupType { + Server, + Client, + Unknown +}; -/* history.c */ -void history_cleanup (void); +StartupType dbus_server_init (void); +void dbus_server_cleanup (void); -/* main.c */ -bool_t do_autosave (void); +#endif /* signals.c */ #ifdef HAVE_SIGWAIT @@ -59,7 +40,4 @@ void signals_init_one (void); void signals_init_two (void); #endif -/* ui_albumart.c */ -char * get_associated_image_file (const char * filename); /* pooled */ - #endif diff --git a/src/audacious/misc-api.h b/src/audacious/misc-api.h deleted file mode 100644 index b9ea2a5..0000000 --- a/src/audacious/misc-api.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * misc-api.h - * Copyright 2010-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -/* Do not include this file directly; use misc.h instead. */ - -/* all (char *) return values must be freed with str_unref() */ - -/* art.c (thread-safe) */ - -/* Gets album art for <file> (the URI of a song file) as JPEG or PNG data. If - * the album art is not yet loaded, sets <data> to NULL and begins to load the - * album art in the background. On completion, the "art ready" hook is called, - * with <file> as a parameter. The "current art ready" hook is also called if - * <file> is the currently playing song. */ -AUD_VFUNC3 (art_request_data, const char *, file, const void * *, data, int64_t *, len) - -/* Similar to art_request_data() but returns the URI of an image file. - * (A temporary file will be created if necessary.) */ -AUD_FUNC1 (const char *, art_request_file, const char *, file) - -/* Releases album art returned by art_request_data() or art_request_file(). */ -AUD_VFUNC1 (art_unref, const char *, file) - -/* config.c (thread-safe) */ - -AUD_VFUNC2 (config_set_defaults, const char *, section, const char * const *, entries) - -AUD_VFUNC3 (set_str, const char *, section, const char *, name, const char *, value) -AUD_FUNC2 (char *, get_str, const char *, section, const char *, name) -AUD_VFUNC3 (set_bool, const char *, section, const char *, name, bool_t, value) -AUD_FUNC2 (bool_t, get_bool, const char *, section, const char *, name) -AUD_VFUNC3 (set_int, const char *, section, const char *, name, int, value) -AUD_FUNC2 (int, get_int, const char *, section, const char *, name) -AUD_VFUNC3 (set_double, const char *, section, const char *, name, double, value) -AUD_FUNC2 (double, get_double, const char *, section, const char *, name) - -/* equalizer.c */ -AUD_VFUNC1 (eq_set_bands, const double *, values) -AUD_VFUNC1 (eq_get_bands, double *, values) -AUD_VFUNC2 (eq_set_band, int, band, double, value) -AUD_FUNC1 (double, eq_get_band, int, band) - -/* equalizer_preset.c */ -AUD_FUNC1 (EqualizerPreset *, equalizer_preset_new, const char *, name) -AUD_VFUNC1 (equalizer_preset_free, EqualizerPreset *, preset) -AUD_FUNC1 (Index *, equalizer_read_presets, const char *, basename) -AUD_FUNC2 (bool_t, equalizer_write_presets, Index *, list, const char *, basename) - -/* note: legacy code! these are local filenames, not URIs */ -AUD_FUNC1 (EqualizerPreset *, load_preset_file, const char *, filename) -AUD_FUNC2 (bool_t, save_preset_file, EqualizerPreset *, preset, const char *, filename) - -AUD_FUNC1 (Index *, import_winamp_presets, VFSFile *, file) -AUD_FUNC2 (bool_t, export_winamp_preset, EqualizerPreset *, preset, VFSFile *, file) - -/* history.c */ -AUD_FUNC1 (const char *, history_get, int, entry) -AUD_VFUNC1 (history_add, const char *, path) - -/* interface.c */ -AUD_VFUNC1 (interface_show, bool_t, show) -AUD_FUNC0 (bool_t, interface_is_shown) - -/* interface_show_error() is safe to call from any thread */ -AUD_VFUNC1 (interface_show_error, const char *, message) - -/* main.c */ -AUD_FUNC1 (const char *, get_path, int, path) -AUD_FUNC0 (bool_t, headless_mode) - -/* output.c */ -AUD_VFUNC1 (output_reset, int, type) - -/* probe.c */ -AUD_FUNC2 (PluginHandle *, file_find_decoder, const char *, filename, bool_t, - fast) -AUD_FUNC2 (Tuple *, file_read_tuple, const char *, filename, PluginHandle *, - decoder) -AUD_FUNC4 (bool_t, file_read_image, const char *, filename, PluginHandle *, - decoder, void * *, data, int64_t *, size) -AUD_FUNC2 (bool_t, file_can_write_tuple, const char *, filename, - PluginHandle *, decoder) -AUD_FUNC3 (bool_t, file_write_tuple, const char *, filename, PluginHandle *, - decoder, const Tuple *, tuple) -AUD_FUNC2 (bool_t, custom_infowin, const char *, filename, PluginHandle *, - decoder) - -/* ui_plugin_menu.c */ -AUD_FUNC1 (/* GtkWidget * */ void *, get_plugin_menu, int, id) -AUD_VFUNC4 (plugin_menu_add, int, id, MenuFunc, func, const char *, name, - const char *, icon) -AUD_VFUNC2 (plugin_menu_remove, int, id, MenuFunc, func) - -/* ui_preferences.c */ -AUD_VFUNC4 (create_widgets_with_domain, /* GtkWidget * */ void *, box, - const PreferencesWidget *, widgets, int, n_widgets, const char *, domain) -AUD_VFUNC0 (show_prefs_window) -AUD_VFUNC1 (show_prefs_for_plugin_type, int, type) - -/* util.c */ - -/* Constructs a full URI given: - * 1. path: one of the following: - * a. a full URI (returned unchanged) - * b. an absolute filename (in the system locale) - * c. a relative path (character set detected according to user settings) - * 2. reference: the full URI of the playlist containing <path> */ -AUD_FUNC2 (char *, construct_uri, const char *, path, const char *, reference) - -/* visualization.c */ -AUD_VFUNC2 (vis_func_add, int, type, VisFunc, func) -AUD_VFUNC1 (vis_func_remove, VisFunc, func) diff --git a/src/audacious/misc.h b/src/audacious/misc.h deleted file mode 100644 index 3d25517..0000000 --- a/src/audacious/misc.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * misc.h - * Copyright 2010-2012 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_MISC_H -#define AUDACIOUS_MISC_H - -#include <audacious/api.h> -#include <audacious/types.h> -#include <libaudcore/index.h> -#include <libaudcore/tuple.h> -#include <libaudcore/vfs.h> - -enum { - AUD_PATH_BIN_DIR, - AUD_PATH_DATA_DIR, - AUD_PATH_PLUGIN_DIR, - AUD_PATH_LOCALE_DIR, - AUD_PATH_DESKTOP_FILE, - AUD_PATH_ICON_FILE, - AUD_PATH_USER_DIR, - AUD_PATH_PLAYLISTS_DIR, - AUD_PATH_COUNT -}; - -enum {OUTPUT_RESET_EFFECTS_ONLY, OUTPUT_RESET_SOFT, OUTPUT_RESET_HARD}; - -enum { - AUD_MENU_MAIN, - AUD_MENU_PLAYLIST, - AUD_MENU_PLAYLIST_ADD, - AUD_MENU_PLAYLIST_REMOVE, - AUD_MENU_COUNT}; - -typedef void (* MenuFunc) (void); - -enum { - AUD_VIS_TYPE_CLEAR, /* like VisPlugin::clear() */ - AUD_VIS_TYPE_MONO_PCM, /* like VisPlugin::render_mono_pcm() */ - AUD_VIS_TYPE_MULTI_PCM, /* like VisPlugin::render_multi_pcm() */ - AUD_VIS_TYPE_FREQ, /* like VisPlugin::render_freq() */ - AUD_VIS_TYPES}; - -/* generic type; does not correspond to actual function types */ -typedef void (* VisFunc) (void); - -#define AUD_API_NAME MiscAPI -#define AUD_API_SYMBOL misc_api - -#ifdef _AUDACIOUS_CORE - -#include "api-local-begin.h" -#include "misc-api.h" -#include "api-local-end.h" - -#define create_widgets(b, w, a) create_widgets_with_domain (b, w, a, PACKAGE) - -#else - -#include <audacious/api-define-begin.h> -#include <audacious/misc-api.h> -#include <audacious/api-define-end.h> - -#include <audacious/api-alias-begin.h> -#include <audacious/misc-api.h> -#include <audacious/api-alias-end.h> - -#define aud_create_widgets(b, w, a) aud_create_widgets_with_domain (b, w, a, \ - PACKAGE) - -#endif - -#undef AUD_API_NAME -#undef AUD_API_SYMBOL - -#endif - -#ifdef AUD_API_DECLARE - -#define AUD_API_NAME MiscAPI -#define AUD_API_SYMBOL misc_api - -#include "api-define-begin.h" -#include "misc-api.h" -#include "api-define-end.h" - -#include "api-declare-begin.h" -#include "misc-api.h" -#include "api-declare-end.h" - -#undef AUD_API_NAME -#undef AUD_API_SYMBOL - -#endif diff --git a/src/audacious/output.c b/src/audacious/output.c deleted file mode 100644 index b6f862a..0000000 --- a/src/audacious/output.c +++ /dev/null @@ -1,642 +0,0 @@ -/* - * output.c - * Copyright 2009-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <math.h> -#include <pthread.h> -#include <stdlib.h> -#include <string.h> - -#include <glib.h> /* for g_usleep */ - -#include "debug.h" -#include "effect.h" -#include "equalizer.h" -#include "misc.h" -#include "output.h" -#include "plugin.h" -#include "plugins.h" -#include "vis_runner.h" - -#define SW_VOLUME_RANGE 40 /* decibels */ - -static pthread_mutex_t mutex_major = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t mutex_minor = PTHREAD_MUTEX_INITIALIZER; - -#define LOCK_MAJOR pthread_mutex_lock (& mutex_major) -#define UNLOCK_MAJOR pthread_mutex_unlock (& mutex_major) -#define LOCK_MINOR pthread_mutex_lock (& mutex_minor) -#define UNLOCK_MINOR pthread_mutex_unlock (& mutex_minor) -#define LOCK_ALL do { LOCK_MAJOR; LOCK_MINOR; } while (0) -#define UNLOCK_ALL do { UNLOCK_MINOR; UNLOCK_MAJOR; } while (0) - -/* State variables. State changes that are allowed between LOCK_MINOR and - * UNLOCK_MINOR (all others must take place between LOCK_ALL and UNLOCK_ALL): - * s_paused -> TRUE or FALSE, s_aborted -> TRUE, s_resetting -> TRUE */ - -static bool_t s_input; /* input plugin connected */ -static bool_t s_output; /* output plugin connected */ -static bool_t s_gain; /* replay gain info set */ -static bool_t s_paused; /* paused */ -static bool_t s_aborted; /* writes aborted */ -static bool_t s_resetting; /* resetting output system */ - -static OutputPlugin * cop; -static int seek_time; -static int in_format, in_channels, in_rate; -static int out_format, out_channels, out_rate; -static int64_t in_frames, out_frames; -static ReplayGainInfo gain_info; - -static bool_t change_op; -static OutputPlugin * new_op; - -static void * buffer1, * buffer2; -static int buffer1_size, buffer2_size; - -static inline int FR2MS (int64_t f, int r) - { return (f > 0) ? (f * 1000 + r / 2) / r : (f * 1000 - r / 2) / r; } -static inline int MS2FR (int64_t ms, int r) - { return (ms > 0) ? (ms * r + 500) / 1000 : (ms * r - 500) / 1000; } - -static inline int get_format (void) -{ - switch (get_int (NULL, "output_bit_depth")) - { - case 16: return FMT_S16_NE; - case 24: return FMT_S24_NE; - case 32: return FMT_S32_NE; - default: return FMT_FLOAT; - } -} - -static void ensure_buffer (void * * buffer, int * size, int newsize) -{ - if (newsize > * size) - { - g_free (* buffer); - * buffer = g_malloc (newsize); - * size = newsize; - } -} - -/* assumes LOCK_ALL, s_output */ -static void cleanup_output (void) -{ - if (! (s_paused || s_aborted) && PLUGIN_HAS_FUNC (cop, drain)) - { - UNLOCK_MINOR; - cop->drain (); - LOCK_MINOR; - } - - s_output = FALSE; - - g_free (buffer1); - g_free (buffer2); - buffer1 = NULL; - buffer2 = NULL; - buffer1_size = 0; - buffer2_size = 0; - - if (PLUGIN_HAS_FUNC (cop, close_audio)) - cop->close_audio (); - - effect_flush (); - vis_runner_start_stop (FALSE, FALSE); -} - -/* assumes LOCK_ALL, s_output */ -static void apply_pause (void) -{ - if (PLUGIN_HAS_FUNC (cop, pause)) - cop->pause (s_paused); - - vis_runner_start_stop (TRUE, s_paused); -} - -/* assumes LOCK_ALL, s_input */ -static void setup_output (void) -{ - int format = get_format (); - int channels = in_channels; - int rate = in_rate; - - effect_start (& channels, & rate); - eq_set_format (channels, rate); - - if (s_output && format == out_format && channels == out_channels && rate == - out_rate && ! PLUGIN_HAS_FUNC (cop, force_reopen)) - return; - - if (s_output) - cleanup_output (); - - if (! cop || ! PLUGIN_HAS_FUNC (cop, open_audio) || ! cop->open_audio (format, rate, channels)) - return; - - s_output = TRUE; - - out_format = format; - out_channels = channels; - out_rate = rate; - out_frames = 0; - - apply_pause (); -} - -/* assumes LOCK_MINOR, s_output */ -static void flush_output (void) -{ - if (PLUGIN_HAS_FUNC (cop, flush)) - { - cop->flush (0); - out_frames = 0; - } - - effect_flush (); - vis_runner_flush (); -} - -static void apply_replay_gain (float * data, int samples) -{ - if (! get_bool (NULL, "enable_replay_gain")) - return; - - float factor = powf (10, get_double (NULL, "replay_gain_preamp") / 20); - - if (s_gain) - { - float peak; - - if (get_bool (NULL, "replay_gain_album")) - { - factor *= powf (10, gain_info.album_gain / 20); - peak = gain_info.album_peak; - } - else - { - factor *= powf (10, gain_info.track_gain / 20); - peak = gain_info.track_peak; - } - - if (get_bool (NULL, "enable_clipping_prevention") && peak * factor > 1) - factor = 1 / peak; - } - else - factor *= powf (10, get_double (NULL, "default_gain") / 20); - - if (factor < 0.99 || factor > 1.01) - audio_amplify (data, 1, samples, & factor); -} - -static void apply_software_volume (float * data, int channels, int samples) -{ - if (! get_bool (NULL, "software_volume_control")) - return; - - int l = get_int (NULL, "sw_volume_left"); - int r = get_int (NULL, "sw_volume_right"); - - if (l == 100 && r == 100) - return; - - float lfactor = (l == 0) ? 0 : powf (10, (float) SW_VOLUME_RANGE * (l - 100) / 100 / 20); - float rfactor = (r == 0) ? 0 : powf (10, (float) SW_VOLUME_RANGE * (r - 100) / 100 / 20); - float factors[channels]; - - if (channels == 2) - { - factors[0] = lfactor; - factors[1] = rfactor; - } - else - { - for (int c = 0; c < channels; c ++) - factors[c] = MAX (lfactor, rfactor); - } - - audio_amplify (data, channels, samples / channels, factors); -} - -/* assumes LOCK_ALL, s_output */ -static void write_output_raw (void * data, int samples) -{ - vis_runner_pass_audio (FR2MS (out_frames, out_rate), data, samples, - out_channels, out_rate); - out_frames += samples / out_channels; - - eq_filter (data, samples); - apply_software_volume (data, out_channels, samples); - - if (get_bool (NULL, "soft_clipping")) - audio_soft_clip (data, samples); - - if (out_format != FMT_FLOAT) - { - ensure_buffer (& buffer2, & buffer2_size, FMT_SIZEOF (out_format) * samples); - audio_to_int (data, buffer2, out_format, samples); - data = buffer2; - } - - while (! (s_aborted || s_resetting)) - { - bool_t blocking = ! PLUGIN_HAS_FUNC (cop, buffer_free); - int ready; - - if (blocking) - ready = out_channels * (out_rate / 50); - else - ready = cop->buffer_free () / FMT_SIZEOF (out_format); - - ready = MIN (ready, samples); - - if (PLUGIN_HAS_FUNC (cop, write_audio)) - { - cop->write_audio (data, FMT_SIZEOF (out_format) * ready); - data = (char *) data + FMT_SIZEOF (out_format) * ready; - samples -= ready; - } - - if (samples == 0) - break; - - UNLOCK_MINOR; - - if (! blocking) - { - if (PLUGIN_HAS_FUNC (cop, period_wait)) - cop->period_wait (); - else - g_usleep (20000); - } - - LOCK_MINOR; - } -} - -/* assumes LOCK_ALL, s_input, s_output */ -static bool_t write_output (void * data, int size, int stop_time) -{ - bool_t stopped = FALSE; - - int64_t cur_frame = in_frames; - int samples = size / FMT_SIZEOF (in_format); - - /* always update in_frames, whether we use all the decoded frames or not */ - in_frames += samples / in_channels; - - if (stop_time != -1) - { - int64_t frames_left = MS2FR (stop_time - seek_time, in_rate) - cur_frame; - int64_t samples_left = in_channels * MAX (0, frames_left); - - if (samples >= samples_left) - { - samples = samples_left; - stopped = TRUE; - } - } - - if (s_aborted) - return ! stopped; - - if (in_format != FMT_FLOAT) - { - ensure_buffer (& buffer1, & buffer1_size, sizeof (float) * samples); - audio_from_int (data, in_format, buffer1, samples); - data = buffer1; - } - - float * fdata = data; - apply_replay_gain (fdata, samples); - effect_process (& fdata, & samples); - write_output_raw (fdata, samples); - - return ! stopped; -} - -/* assumes LOCK_ALL, s_output */ -static void finish_effects (void) -{ - float * data = NULL; - int samples = 0; - - effect_finish (& data, & samples); - write_output_raw (data, samples); -} - -bool_t output_open_audio (int format, int rate, int channels) -{ - /* prevent division by zero */ - if (rate < 1 || channels < 1) - return FALSE; - - LOCK_ALL; - - if (s_output && s_paused) - { - flush_output (); - s_paused = FALSE; - apply_pause (); - } - - s_input = TRUE; - s_gain = s_paused = s_aborted = FALSE; - seek_time = 0; - - in_format = format; - in_channels = channels; - in_rate = rate; - in_frames = 0; - - setup_output (); - - UNLOCK_ALL; - return TRUE; -} - -void output_set_replaygain_info (const ReplayGainInfo * info) -{ - LOCK_ALL; - - if (s_input) - { - memcpy (& gain_info, info, sizeof (ReplayGainInfo)); - s_gain = TRUE; - - AUDDBG ("Replay Gain info:\n"); - AUDDBG (" album gain: %f dB\n", info->album_gain); - AUDDBG (" album peak: %f\n", info->album_peak); - AUDDBG (" track gain: %f dB\n", info->track_gain); - AUDDBG (" track peak: %f\n", info->track_peak); - } - - UNLOCK_ALL; -} - -/* returns FALSE if stop_time is reached */ -bool_t output_write_audio (void * data, int size, int stop_time) -{ - LOCK_ALL; - bool_t good = FALSE; - - if (s_input) - { - while ((! s_output || s_resetting) && ! s_aborted) - { - UNLOCK_ALL; - g_usleep (20000); - LOCK_ALL; - } - - good = write_output (data, size, stop_time); - } - - UNLOCK_ALL; - return good; -} - -void output_abort_write (void) -{ - LOCK_MINOR; - - if (s_input) - { - s_aborted = TRUE; - - if (s_output) - flush_output (); - } - - UNLOCK_MINOR; -} - -void output_pause (bool_t pause) -{ - LOCK_MINOR; - - if (s_input) - { - s_paused = pause; - - if (s_output) - apply_pause (); - } - - UNLOCK_MINOR; -} - -int output_written_time (void) -{ - LOCK_MINOR; - int time = 0; - - if (s_input) - time = seek_time + FR2MS (in_frames, in_rate); - - UNLOCK_MINOR; - return time; -} - -void output_set_time (int time) -{ - LOCK_ALL; - - if (s_input) - { - s_aborted = FALSE; - seek_time = time; - in_frames = 0; - } - - UNLOCK_ALL; -} - -bool_t output_is_open (void) -{ - LOCK_MINOR; - bool_t is_open = s_input; - UNLOCK_MINOR; - return is_open; -} - -int output_get_time (void) -{ - LOCK_MINOR; - int time = 0, delay = 0; - - if (s_input) - { - if (s_output && PLUGIN_HAS_FUNC (cop, output_time)) - delay = FR2MS (out_frames, out_rate) - cop->output_time (); - - delay = effect_adjust_delay (delay); - time = FR2MS (in_frames, in_rate); - time = seek_time + MAX (time - delay, 0); - } - - UNLOCK_MINOR; - return time; -} - -int output_get_raw_time (void) -{ - LOCK_MINOR; - int time = 0; - - if (s_output && PLUGIN_HAS_FUNC (cop, output_time)) - time = cop->output_time (); - - UNLOCK_MINOR; - return time; -} - -void output_close_audio (void) -{ - LOCK_ALL; - - if (s_input) - { - s_input = FALSE; - - if (s_output && ! (s_paused || s_aborted || s_resetting)) - finish_effects (); /* first time for end of song */ - } - - UNLOCK_ALL; -} - -void output_drain (void) -{ - LOCK_ALL; - - if (! s_input && s_output) - { - finish_effects (); /* second time for end of playlist */ - cleanup_output (); - } - - UNLOCK_ALL; -} - -void output_reset (int type) -{ - LOCK_MINOR; - - s_resetting = TRUE; - - if (s_output) - flush_output (); - - UNLOCK_MINOR; - LOCK_ALL; - - if (s_output && type != OUTPUT_RESET_EFFECTS_ONLY) - cleanup_output (); - - if (type == OUTPUT_RESET_HARD) - { - if (cop && PLUGIN_HAS_FUNC (cop, cleanup)) - cop->cleanup (); - - if (change_op) - cop = new_op; - - if (cop && PLUGIN_HAS_FUNC (cop, init) && ! cop->init ()) - cop = NULL; - } - - if (s_input) - setup_output (); - - s_resetting = FALSE; - - UNLOCK_ALL; -} - -void output_get_volume (int * left, int * right) -{ - LOCK_MINOR; - - * left = * right = 0; - - if (get_bool (NULL, "software_volume_control")) - { - * left = get_int (NULL, "sw_volume_left"); - * right = get_int (NULL, "sw_volume_right"); - } - else if (cop && PLUGIN_HAS_FUNC (cop, get_volume)) - cop->get_volume (left, right); - - UNLOCK_MINOR; -} - -void output_set_volume (int left, int right) -{ - LOCK_MINOR; - - if (get_bool (NULL, "software_volume_control")) - { - set_int (NULL, "sw_volume_left", left); - set_int (NULL, "sw_volume_right", right); - } - else if (cop && PLUGIN_HAS_FUNC (cop, set_volume)) - cop->set_volume (left, right); - - UNLOCK_MINOR; -} - -static bool_t probe_cb (PluginHandle * p, PluginHandle * * pp) -{ - OutputPlugin * op = plugin_get_header (p); - - if (! op || (PLUGIN_HAS_FUNC (op, init) && ! op->init ())) - return TRUE; /* keep searching */ - - if (PLUGIN_HAS_FUNC (op, cleanup)) - op->cleanup (); - - * pp = p; - return FALSE; /* stop searching */ -} - -PluginHandle * output_plugin_probe (void) -{ - PluginHandle * p = NULL; - plugin_for_each (PLUGIN_TYPE_OUTPUT, (PluginForEachFunc) probe_cb, & p); - return p; -} - -PluginHandle * output_plugin_get_current (void) -{ - return cop ? plugin_by_header (cop) : NULL; -} - -bool_t output_plugin_set_current (PluginHandle * plugin) -{ - change_op = TRUE; - new_op = plugin ? plugin_get_header (plugin) : NULL; - output_reset (OUTPUT_RESET_HARD); - - bool_t success = (cop == new_op); - change_op = FALSE; - new_op = NULL; - - return success; -} diff --git a/src/audacious/output.h b/src/audacious/output.h deleted file mode 100644 index ac9ee48..0000000 --- a/src/audacious/output.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * output.h - * Copyright 2010-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_OUTPUT_H -#define AUDACIOUS_OUTPUT_H - -#include <libaudcore/core.h> -#include "types.h" - -bool_t output_open_audio (int format, int rate, int channels); -void output_set_replaygain_info (const ReplayGainInfo * info); -bool_t output_write_audio (void * data, int size, int stop_time); -void output_abort_write (void); -void output_pause (bool_t pause); -int output_written_time (void); -void output_set_time (int time); - -bool_t output_is_open (void); -int output_get_time (void); -int output_get_raw_time (void); -void output_close_audio (void); -void output_drain (void); - -void output_get_volume (int * left, int * right); -void output_set_volume (int left, int right); - -PluginHandle * output_plugin_probe (void); -PluginHandle * output_plugin_get_current (void); -bool_t output_plugin_set_current (PluginHandle * plugin); - -#endif /* AUDACIOUS_OUTPUT_H */ diff --git a/src/audacious/playback.c b/src/audacious/playback.c deleted file mode 100644 index 7d9c56f..0000000 --- a/src/audacious/playback.c +++ /dev/null @@ -1,652 +0,0 @@ -/* - * playback.c - * Copyright 2009-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <glib.h> -#include <pthread.h> -#include <string.h> - -#include <libaudcore/audstrings.h> -#include <libaudcore/hook.h> -#include <libaudgui/libaudgui.h> - -#include "drct.h" -#include "i18n.h" -#include "input.h" -#include "interface.h" -#include "misc.h" -#include "output.h" -#include "playback.h" -#include "playlist.h" -#include "plugin.h" - -static pthread_t playback_thread_handle; -static int end_source = 0; - -static pthread_mutex_t ready_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t ready_cond = PTHREAD_COND_INITIALIZER; - -static pthread_mutex_t control_mutex = PTHREAD_MUTEX_INITIALIZER; - -/* level 1 data (persists to end of song) */ -static bool_t playing = FALSE; -static int time_offset = 0; -static int stop_time = -1; -static bool_t paused = FALSE; -static bool_t ready_flag = FALSE; -static bool_t playback_error = FALSE; -static bool_t song_finished = FALSE; - -static int seek_request = -1; /* under control_mutex */ -static int repeat_a = -1; /* under control_mutex */ - -static volatile int repeat_b = -1; /* atomic */ -static volatile int stop_flag = FALSE; /* atomic */ - -static int current_bitrate = -1, current_samplerate = -1, current_channels = -1; - -static int current_entry = -1; -static char * current_filename = NULL; /* pooled */ -static char * current_title = NULL; /* pooled */ -static int current_length = -1; - -static InputPlugin * current_decoder = NULL; -static VFSFile * current_file = NULL; -static ReplayGainInfo current_gain; - -/* level 2 data (persists to end of playlist) */ -static bool_t stopped = TRUE; -static int failed_entries = 0; - -/* clears gain info if tuple == NULL */ -static void read_gain_from_tuple (const Tuple * tuple) -{ - memset (& current_gain, 0, sizeof current_gain); - - if (tuple == NULL) - return; - - int album_gain = tuple_get_int (tuple, FIELD_GAIN_ALBUM_GAIN); - int album_peak = tuple_get_int (tuple, FIELD_GAIN_ALBUM_PEAK); - int track_gain = tuple_get_int (tuple, FIELD_GAIN_TRACK_GAIN); - int track_peak = tuple_get_int (tuple, FIELD_GAIN_TRACK_PEAK); - int gain_unit = tuple_get_int (tuple, FIELD_GAIN_GAIN_UNIT); - int peak_unit = tuple_get_int (tuple, FIELD_GAIN_PEAK_UNIT); - - if (gain_unit) - { - current_gain.album_gain = album_gain / (float) gain_unit; - current_gain.track_gain = track_gain / (float) gain_unit; - } - - if (peak_unit) - { - current_gain.album_peak = album_peak / (float) peak_unit; - current_gain.track_peak = track_peak / (float) peak_unit; - } -} - -static bool_t update_from_playlist (void) -{ - int entry = playback_entry_get_position (); - char * title = playback_entry_get_title (); - int length = playback_entry_get_length (); - - if (entry == current_entry && str_equal (title, current_title) && length == current_length) - { - str_unref (title); - return FALSE; - } - - current_entry = entry; - str_unref (current_title); - current_title = title; - current_length = length; - return TRUE; -} - -bool_t drct_get_ready (void) -{ - if (! playing) - return FALSE; - - pthread_mutex_lock (& ready_mutex); - bool_t ready = ready_flag; - pthread_mutex_unlock (& ready_mutex); - return ready; -} - -static void set_ready (void) -{ - g_return_if_fail (playing); - - pthread_mutex_lock (& ready_mutex); - - update_from_playlist (); - event_queue ("playback ready", NULL); - ready_flag = TRUE; - - pthread_cond_signal (& ready_cond); - pthread_mutex_unlock (& ready_mutex); -} - -static void wait_until_ready (void) -{ - g_return_if_fail (playing); - pthread_mutex_lock (& ready_mutex); - - /* on restart, we still have to wait, but presumably not long */ - while (! ready_flag) - pthread_cond_wait (& ready_cond, & ready_mutex); - - pthread_mutex_unlock (& ready_mutex); -} - -static void update_cb (void * hook_data, void * user_data) -{ - g_return_if_fail (playing); - - if (GPOINTER_TO_INT (hook_data) < PLAYLIST_UPDATE_METADATA || ! drct_get_ready ()) - return; - - if (update_from_playlist ()) - event_queue ("title change", NULL); -} - -int drct_get_time (void) -{ - if (! playing) - return 0; - - wait_until_ready (); - - return output_get_time () - time_offset; -} - -void drct_pause (void) -{ - if (! playing) - return; - - wait_until_ready (); - - paused = ! paused; - - output_pause (paused); - - if (paused) - hook_call ("playback pause", NULL); - else - hook_call ("playback unpause", NULL); -} - -static void playback_cleanup (void) -{ - g_return_if_fail (playing); - wait_until_ready (); - - if (! song_finished) - { - g_atomic_int_set (& stop_flag, TRUE); - output_abort_write (); - } - - pthread_join (playback_thread_handle, NULL); - output_close_audio (); - - hook_dissociate ("playlist update", update_cb); - - event_queue_cancel ("playback ready", NULL); - event_queue_cancel ("playback seek", NULL); - event_queue_cancel ("info change", NULL); - event_queue_cancel ("title change", NULL); - - if (end_source) - { - g_source_remove (end_source); - end_source = 0; - } - - /* level 1 data cleanup */ - playing = FALSE; - time_offset = 0; - stop_time = -1; - paused = FALSE; - ready_flag = FALSE; - playback_error = FALSE; - song_finished = FALSE; - - seek_request = -1; - repeat_a = -1; - - g_atomic_int_set (& repeat_b, -1); - g_atomic_int_set (& stop_flag, FALSE); - - current_bitrate = current_samplerate = current_channels = -1; - - current_entry = -1; - str_unref (current_filename); - current_filename = NULL; - str_unref (current_title); - current_title = NULL; - current_length = -1; - - current_decoder = NULL; - - if (current_file) - { - vfs_fclose (current_file); - current_file = NULL; - } - - read_gain_from_tuple (NULL); - - set_bool (NULL, "stop_after_current_song", FALSE); -} - -void playback_stop (void) -{ - if (stopped) - return; - - if (playing) - playback_cleanup (); - - output_drain (); - - /* level 2 data cleanup */ - stopped = TRUE; - failed_entries = 0; - - hook_call ("playback stop", NULL); -} - -static void do_stop (int playlist) -{ - playlist_set_playing (-1); - playlist_set_position (playlist, playlist_get_position (playlist)); -} - -static void do_next (int playlist) -{ - if (! playlist_next_song (playlist, get_bool (NULL, "repeat"))) - { - playlist_set_position (playlist, -1); - hook_call ("playlist end reached", NULL); - } -} - -static bool_t end_cb (void * unused) -{ - g_return_val_if_fail (playing, FALSE); - - if (! playback_error) - song_finished = TRUE; - - hook_call ("playback end", NULL); - - if (playback_error) - failed_entries ++; - else - failed_entries = 0; - - int playlist = playlist_get_playing (); - - if (get_bool (NULL, "stop_after_current_song")) - { - do_stop (playlist); - - if (! get_bool (NULL, "no_playlist_advance")) - do_next (playlist); - } - else if (get_bool (NULL, "no_playlist_advance")) - { - if (get_bool (NULL, "repeat") && ! failed_entries) - playback_play (0, FALSE); - else - do_stop (playlist); - } - else - { - if (failed_entries < 10) - do_next (playlist); - else - do_stop (playlist); - } - - return FALSE; -} - -static bool_t open_file (void) -{ - /* no need to open a handle for custom URI schemes */ - if (current_decoder->schemes && current_decoder->schemes[0]) - return TRUE; - - current_file = vfs_fopen (current_filename, "r"); - return (current_file != NULL); -} - -static void * playback_thread (void * unused) -{ - if (! current_decoder) - { - PluginHandle * p = playback_entry_get_decoder (); - current_decoder = p ? plugin_get_header (p) : NULL; - - if (! current_decoder) - { - SPRINTF (error, _("No decoder found for %s."), current_filename); - interface_show_error (error); - playback_error = TRUE; - goto DONE; - } - } - - Tuple * tuple = playback_entry_get_tuple (); - int length = playback_entry_get_length (); - - if (length < 1) - seek_request = -1; - - if (tuple && length > 0) - { - if (tuple_get_value_type (tuple, FIELD_SEGMENT_START) == TUPLE_INT) - { - time_offset = tuple_get_int (tuple, FIELD_SEGMENT_START); - if (time_offset) - seek_request = time_offset + MAX (seek_request, 0); - } - - if (tuple_get_value_type (tuple, FIELD_SEGMENT_END) == TUPLE_INT) - stop_time = tuple_get_int (tuple, FIELD_SEGMENT_END); - } - - read_gain_from_tuple (tuple); - - if (tuple) - tuple_unref (tuple); - - if (! open_file ()) - { - SPRINTF (error, _("%s could not be opened."), current_filename); - interface_show_error (error); - playback_error = TRUE; - goto DONE; - } - - playback_error = ! current_decoder->play (current_filename, current_file); - -DONE: - if (! ready_flag) - set_ready (); - - end_source = g_timeout_add (0, end_cb, NULL); - return NULL; -} - -void playback_play (int seek_time, bool_t pause) -{ - char * new_filename = playback_entry_get_filename (); - g_return_if_fail (new_filename); - - if (playing) - playback_cleanup (); - - current_filename = new_filename; - - playing = TRUE; - paused = pause; - - seek_request = (seek_time > 0) ? seek_time : -1; - - stopped = FALSE; - - hook_associate ("playlist update", update_cb, NULL); - pthread_create (& playback_thread_handle, NULL, playback_thread, NULL); - - hook_call ("playback begin", NULL); -} - -bool_t drct_get_playing (void) -{ - return playing; -} - -bool_t drct_get_paused (void) -{ - return paused; -} - -void drct_seek (int time) -{ - if (! playing) - return; - - wait_until_ready (); - - if (current_length < 1) - return; - - pthread_mutex_lock (& control_mutex); - - seek_request = time_offset + CLAMP (time, 0, current_length); - output_abort_write (); - - pthread_mutex_unlock (& control_mutex); -} - -bool_t input_open_audio (int format, int rate, int channels) -{ - g_return_val_if_fail (playing, FALSE); - - if (! output_open_audio (format, rate, channels)) - return FALSE; - - output_set_replaygain_info (& current_gain); - - if (paused) - output_pause (TRUE); - - current_samplerate = rate; - current_channels = channels; - - if (ready_flag) - event_queue ("info change", NULL); - - return TRUE; -} - -void input_set_gain (const ReplayGainInfo * info) -{ - g_return_if_fail (playing); - memcpy (& current_gain, info, sizeof current_gain); - output_set_replaygain_info (& current_gain); -} - -void input_write_audio (void * data, int length) -{ - g_return_if_fail (playing); - - if (! ready_flag) - set_ready (); - - int b = g_atomic_int_get (& repeat_b); - - if (b >= 0) - { - if (! output_write_audio (data, length, b)) - { - pthread_mutex_lock (& control_mutex); - seek_request = MAX (repeat_a, time_offset); - pthread_mutex_unlock (& control_mutex); - } - } - else - { - if (! output_write_audio (data, length, stop_time)) - g_atomic_int_set (& stop_flag, TRUE); - } -} - -int input_written_time (void) -{ - g_return_val_if_fail (playing, -1); - return output_written_time (); -} - -Tuple * input_get_tuple (void) -{ - g_return_val_if_fail (playing, NULL); - return playback_entry_get_tuple (); -} - -void input_set_tuple (Tuple * tuple) -{ - g_return_if_fail (playing); - playback_entry_set_tuple (tuple); -} - -void input_set_bitrate (int bitrate) -{ - g_return_if_fail (playing); - current_bitrate = bitrate; - - if (ready_flag) - event_queue ("info change", NULL); -} - -bool_t input_check_stop (void) -{ - g_return_val_if_fail (playing, TRUE); - return g_atomic_int_get (& stop_flag); -} - -int input_check_seek (void) -{ - g_return_val_if_fail (playing, -1); - - pthread_mutex_lock (& control_mutex); - int seek = seek_request; - - if (seek != -1) - { - output_set_time (seek); - seek_request = -1; - - event_queue ("playback seek", NULL); - } - - pthread_mutex_unlock (& control_mutex); - return seek; -} - -char * drct_get_filename (void) -{ - if (! playing) - return NULL; - - return str_ref (current_filename); -} - -char * drct_get_title (void) -{ - if (! playing) - return NULL; - - wait_until_ready (); - - char s[32]; - - if (current_length > 0) - { - char t[16]; - audgui_format_time (t, sizeof t, current_length); - snprintf (s, sizeof s, " (%s)", t); - } - else - s[0] = 0; - - if (get_bool (NULL, "show_numbers_in_pl")) - return str_printf ("%d. %s%s", 1 + current_entry, current_title, s); - - return str_printf ("%s%s", current_title, s); -} - -int drct_get_length (void) -{ - if (playing) - wait_until_ready (); - - return current_length; -} - -void drct_get_info (int * bitrate, int * samplerate, int * channels) -{ - if (playing) - wait_until_ready (); - - * bitrate = current_bitrate; - * samplerate = current_samplerate; - * channels = current_channels; -} - -void drct_get_volume (int * l, int * r) -{ - output_get_volume (l, r); -} - -void drct_set_volume (int l, int r) -{ - output_set_volume (CLAMP (l, 0, 100), CLAMP (r, 0, 100)); -} - -void drct_set_ab_repeat (int a, int b) -{ - if (! playing) - return; - - wait_until_ready (); - - if (current_length < 1) - return; - - if (a >= 0) - a += time_offset; - if (b >= 0) - b += time_offset; - - pthread_mutex_lock (& control_mutex); - - repeat_a = a; - g_atomic_int_set (& repeat_b, b); - - if (b != -1 && output_get_time () >= b) - { - seek_request = MAX (a, time_offset); - output_abort_write (); - } - - pthread_mutex_unlock (& control_mutex); -} - -void drct_get_ab_repeat (int * a, int * b) -{ - * a = (playing && repeat_a != -1) ? repeat_a - time_offset : -1; - * b = (playing && repeat_b != -1) ? repeat_b - time_offset : -1; -} diff --git a/src/audacious/playback.h b/src/audacious/playback.h deleted file mode 100644 index 2937791..0000000 --- a/src/audacious/playback.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * playback.h - * Copyright 2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_PLAYBACK_H -#define AUDACIOUS_PLAYBACK_H - -#include <libaudcore/core.h> - -/* for use from playback.c and playlist-new.c ONLY */ -/* anywhere else, use drct_* and/or playlist_* functions */ -void playback_play (int seek_time, bool_t pause); -void playback_stop (void); - -#endif /* AUDACIOUS_PLAYBACK_H */ diff --git a/src/audacious/playlist-api.h b/src/audacious/playlist-api.h deleted file mode 100644 index 634fd05..0000000 --- a/src/audacious/playlist-api.h +++ /dev/null @@ -1,362 +0,0 @@ -/* - * playlist-api.h - * Copyright 2010-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -/* Do not include this file directly; use playlist.h instead. */ - -/* Any functions in this API with a return type of (char *) return pooled - * strings that must not be modified and must be released with str_unref() when - * no longer needed. */ - -/* --- PLAYLIST CORE API --- */ - -/* Returns the number of playlists currently open. There will always be at - * least one playlist open. The playlists are numbered starting from zero. */ -AUD_FUNC0 (int, playlist_count) - -/* Adds a new playlist before the one numbered <at>. If <at> is -1 or equal to - * the number of playlists, adds a new playlist after the last one. */ -AUD_VFUNC1 (playlist_insert, int, at) - -/* Moves a contiguous block of <count> playlists starting with the one numbered - * <from> such that that playlist ends up at the position <to>. */ -AUD_VFUNC3 (playlist_reorder, int, from, int, to, int, count) - -/* Closes a playlist. CAUTION: The playlist is not saved, and no confirmation - * is presented to the user. If <playlist> is the only playlist, a new playlist - * is added. If <playlist> is the active playlist, another playlist is marked - * active. If <playlist> is the currently playing playlist, playback is - * stopped. */ -AUD_VFUNC1 (playlist_delete, int, playlist) - -/* Returns a unique non-negative integer which can be used to identify a given - * playlist even if its numbering changes (as when playlists are reordered). - * On error, returns -1. */ -AUD_FUNC1 (int, playlist_get_unique_id, int, playlist) - -/* Returns the number of the playlist identified by a given integer ID as - * returned by playlist_get_unique_id(). If the playlist no longer exists, - * returns -1. */ -AUD_FUNC1 (int, playlist_by_unique_id, int, id) - -/* Sets the filename associated with a playlist. (Audacious currently makes no - * use of the filename.) */ -AUD_VFUNC2 (playlist_set_filename, int, playlist, const char *, filename) - -/* Returns the filename associated with a playlist. */ -AUD_FUNC1 (char *, playlist_get_filename, int, playlist) - -/* Sets the title associated with a playlist. */ -AUD_VFUNC2 (playlist_set_title, int, playlist, const char *, title) - -/* Returns the title associated with a playlist. */ -AUD_FUNC1 (char *, playlist_get_title, int, playlist) - -/* Sets the active playlist. This is the playlist that user interfaces will - * show to the user. */ -AUD_VFUNC1 (playlist_set_active, int, playlist) - -/* Returns the number of the active playlist. */ -AUD_FUNC0 (int, playlist_get_active) - -/* Sets the currently playing playlist. Starts playback, resuming from the - * position last played if possible. If <playlist> is -1 or if the requested - * playlist is empty, stops playback. */ -AUD_VFUNC1 (playlist_set_playing, int, playlist) - -/* Returns the number of the currently playing playlist. If no playlist is - * playing, returns -1. */ -AUD_FUNC0 (int, playlist_get_playing) - -/* Returns the number of a "blank" playlist. The active playlist is returned if - * it has the default title and has no entries; otherwise, a new playlist is - * added and returned. */ -AUD_FUNC0 (int, playlist_get_blank) - -/* Returns the number of the "temporary" playlist (which is no different from - * any other playlist except in name). If the playlist does not exist, a - * "blank" playlist is obtained from playlist_get_blank() and is renamed to - * become the temporary playlist. */ -AUD_FUNC0 (int, playlist_get_temporary) - -/* Returns the number of entries in a playlist. The entries are numbered - * starting from zero. */ -AUD_FUNC1 (int, playlist_entry_count, int, playlist) - -/* Adds a song file, playlist file, or folder to a playlist before the entry - * numbered <at>. If <at> is negative or equal to the number of entries, the - * item is added after the last entry. <tuple> may be NULL, in which case - * Audacious will attempt to read metadata from the song file. The caller gives - * up one reference count to <tuple>. If <play> is nonzero, Audacious will - * begin playback of the items once they have been added. - * - * Because adding items to the playlist can be a slow process, this function may - * return before the process is complete. Hence, the caller must not assume - * that there will be new entries in the playlist immediately. */ -AUD_VFUNC5 (playlist_entry_insert, int, playlist, int, at, const char *, - filename, Tuple *, tuple, bool_t, play) - -/* Similar to playlist_entry_insert, adds multiple song files, playlist files, - * or folders to a playlist. The filenames, stored as (char *) in an index - * (see libaudcore/index.h), must be pooled with str_get(); the caller gives up - * one reference count to each filename. Tuples are likewise stored as - * (Tuple *) in an index of the same length; the caller gives up one reference - * count to each tuple. <tuples> may be NULL, or individual pointers within it - * may be NULL. Finally, the caller also gives up ownership of the indexes - * themselves and should not access them after the call. */ -AUD_VFUNC5 (playlist_entry_insert_batch, int, playlist, int, at, - Index *, filenames, Index *, tuples, bool_t, play) - -/* Similar to playlist_entry_insert_batch, but allows the caller to prevent some - * items from being added by returning false from the <filter> callback. Useful - * for searching a folder and adding only new files to the playlist. Filenames - * passed to the callback can be used with str_ref(), str_equal(), etc. <user> - * is an additional, untyped pointer passed to the callback. */ -AUD_VFUNC7 (playlist_entry_insert_filtered, int, playlist, int, at, - Index *, filenames, Index *, tuples, PlaylistFilterFunc, filter, - void *, user, bool_t, play) - -/* Removes a contiguous block of <number> entries starting from the one numbered - * <at> from a playlist. If necessary, the playback position is moved elsewhere - * in the playlist and playback is restarted (or stopped). */ -AUD_VFUNC3 (playlist_entry_delete, int, playlist, int, at, int, number) - -/* Returns the filename of an entry. */ -AUD_FUNC2 (char *, playlist_entry_get_filename, int, playlist, int, entry) - -/* Returns a handle to the decoder plugin associated with an entry, or NULL if - * none can be found. If <fast> is nonzero, returns NULL if no decoder plugin - * has yet been found. */ -AUD_FUNC3 (PluginHandle *, playlist_entry_get_decoder, int, playlist, int, - entry, bool_t, fast) - -/* Returns the tuple associated with an entry, or NULL if one is not available. - * The reference count of the tuple is incremented. If <fast> is nonzero, - * returns NULL if metadata for the entry has not yet been read from the song - * file. */ -AUD_FUNC3 (Tuple *, playlist_entry_get_tuple, int, playlist, int, entry, - bool_t, fast) - -/* Returns a formatted title string for an entry. This may include information - * such as the filename, song title, and/or artist. If <fast> is nonzero, - * returns a "best guess" based on the entry's filename if metadata for the - * entry has not yet been read. */ -AUD_FUNC3 (char *, playlist_entry_get_title, int, playlist, int, entry, - bool_t, fast) - -/* Returns three strings (title, artist, and album) describing an entry. The - * strings are pooled, and the usual cautions apply. If <fast> is nonzero, - * returns a "best guess" based on the entry's filename if metadata for the - * entry has not yet been read. The caller may pass NULL for any values that - * are not needed; NULL may also be returned for any values that are not - * available. */ -AUD_VFUNC6 (playlist_entry_describe, int, playlist, int, entry, - char * *, title, char * *, artist, char * *, album, bool_t, fast) - -/* Returns the length in milliseconds of an entry, or -1 if the length is not - * known. <fast> is as in playlist_entry_get_tuple(). */ -AUD_FUNC3 (int, playlist_entry_get_length, int, playlist, int, entry, - bool_t, fast) - -/* Moves the playback position to the beginning of the entry at <position>. If - * <position> is -1, unsets the playback position. If <playlist> is the - * currently playing playlist, playback is restarted (or stopped). */ -AUD_VFUNC2 (playlist_set_position, int, playlist, int, position) - -/* Returns the playback position, or -1 if it is not set. Note that the - * position may be set even if <playlist> is not currently playing. */ -AUD_FUNC1 (int, playlist_get_position, int, playlist) - -/* Sets whether an entry is selected. */ -AUD_VFUNC3 (playlist_entry_set_selected, int, playlist, int, entry, - bool_t, selected) - -/* Returns whether an entry is selected. */ -AUD_FUNC2 (bool_t, playlist_entry_get_selected, int, playlist, int, entry) - -/* Returns the number of selected entries in a playlist. */ -AUD_FUNC1 (int, playlist_selected_count, int, playlist) - -/* Selects all (or none) of the entries in a playlist. */ -AUD_VFUNC2 (playlist_select_all, int, playlist, bool_t, selected) - -/* Moves a selected entry within a playlist by an offset of <distance> entries. - * Other selected entries are gathered around it. Returns the offset by which - * the entry was actually moved, which may be less in absolute value than the - * requested offset. */ -AUD_FUNC3 (int, playlist_shift, int, playlist, int, position, int, distance) - -/* Removes the selected entries from a playlist. If necessary, the playback - * position is moved elsewhere in the playlist and playback is restarted (or - * stopped). */ -AUD_VFUNC1 (playlist_delete_selected, int, playlist) - -/* Sorts the entries in a playlist based on filename. The callback function - * should return negative if the first filename comes before the second, - * positive if it comes after, or zero if the two are indistinguishable. */ -AUD_VFUNC2 (playlist_sort_by_filename, int, playlist, - PlaylistStringCompareFunc, compare) - -/* Sorts the entries in a playlist based on tuple. May fail if metadata - * scanning is still in progress (or has been disabled). */ -AUD_VFUNC2 (playlist_sort_by_tuple, int, playlist, - PlaylistTupleCompareFunc, compare) - -/* Sorts the entries in a playlist based on formatted title string. May fail if - * metadata scanning is still in progress (or has been disabled). */ -AUD_VFUNC2 (playlist_sort_by_title, int, playlist, - PlaylistStringCompareFunc, compare) - -/* Sorts only the selected entries in a playlist based on filename. */ -AUD_VFUNC2 (playlist_sort_selected_by_filename, int, playlist, - PlaylistStringCompareFunc, compare) - -/* Sorts only the selected entries in a playlist based on tuple. May fail if - * metadata scanning is still in progress (or has been disabled). */ -AUD_VFUNC2 (playlist_sort_selected_by_tuple, int, playlist, - PlaylistTupleCompareFunc, compare) - -/* Sorts only the selected entries in a playlist based on formatted title - * string. May fail if metadata scanning is still in progress (or has been - * disabled). */ -AUD_VFUNC2 (playlist_sort_selected_by_title, int, playlist, - PlaylistStringCompareFunc, compare) - -/* Reverses the order of the entries in a playlist. */ -AUD_VFUNC1 (playlist_reverse, int, playlist) - -/* Reorders the entries in a playlist randomly. */ -AUD_VFUNC1 (playlist_randomize, int, playlist) - -/* Discards the metadata stored for all the entries in a playlist and starts - * reading it afresh from the song files in the background. */ -AUD_VFUNC1 (playlist_rescan, int, playlist) - -/* Like playlist_rescan, but applies only to the selected entries in a playlist. */ -AUD_VFUNC1 (playlist_rescan_selected, int, playlist) - -/* Discards the metadata stored for all the entries that refer to a particular - * song file, in whatever playlist they appear, and starts reading it afresh - * from that file in the background. */ -AUD_VFUNC1 (playlist_rescan_file, const char *, filename) - -/* Calculates the total length in milliseconds of all the entries in a playlist. - * Only takes into account entries for which metadata has already been read. */ -AUD_FUNC1 (int64_t, playlist_get_total_length, int, playlist) - -/* Calculates the total length in milliseconds of only the selected entries in a - * playlist. Only takes into account entries for which metadata has already - * been read. */ -AUD_FUNC1 (int64_t, playlist_get_selected_length, int, playlist) - -/* Returns the number of entries in a playlist queue. The entries are numbered - * starting from zero, lower numbers being played first. */ -AUD_FUNC1 (int, playlist_queue_count, int, playlist) - -/* Adds an entry to a playlist's queue before the entry numbered <at> in the - * queue. If <at> is negative or equal to the number of entries in the queue, - * adds the entry after the last one in the queue. The same entry cannot be - * added to the queue more than once. */ -AUD_VFUNC3 (playlist_queue_insert, int, playlist, int, at, int, entry) - -/* Adds the selected entries in a playlist to the queue, if they are not already - * in it. */ -AUD_VFUNC2 (playlist_queue_insert_selected, int, playlist, int, at) - -/* Returns the position in the playlist of the entry at a given position in the - * queue. */ -AUD_FUNC2 (int, playlist_queue_get_entry, int, playlist, int, at) - -/* Returns the position in the queue of the entry at a given position in the - * playlist. If it is not in the queue, returns -1. */ -AUD_FUNC2 (int, playlist_queue_find_entry, int, playlist, int, entry) - -/* Removes a contiguous block of <number> entries starting with the one numbered - * <at> from the queue. */ -AUD_VFUNC3 (playlist_queue_delete, int, playlist, int, at, int, number) - -/* Removes the selected entries in a playlist from the queue, if they are in it. */ -AUD_VFUNC1 (playlist_queue_delete_selected, int, playlist) - -/* Returns nonzero if a "playlist update" hook call is pending. If called from - * within the hook, the current hook call is not considered pending. */ -AUD_FUNC0 (bool_t, playlist_update_pending) - -/* May be called within the "playlist update" hook to determine the update level - * and number of entries changed in a playlist. Returns the update level for - * the playlist, storing the number of the first entry changed in <at> and the - * number of contiguous entries to be updated in <count>. Note that entries may - * have been added or removed within this range. If no entries in the playlist - * have changed, returns zero. */ -AUD_FUNC3 (int, playlist_updated_range, int, playlist, int *, at, int *, count) - -/* Returns nonzero if entries are being added to a playlist in the background. - * If <playlist> is -1, checks all playlists. */ -AUD_FUNC1 (bool_t, playlist_add_in_progress, int, playlist) - -/* Returns nonzero if entries in a playlist are being scanned for metadata in - * the background. If <playlist> is -1, checks all playlists. */ -AUD_FUNC1 (bool_t, playlist_scan_in_progress, int, playlist) - -/* --- PLAYLIST UTILITY API --- */ - -/* Sorts the entries in a playlist according to one of the schemes listed in - * playlist.h. */ -AUD_VFUNC2 (playlist_sort_by_scheme, int, playlist, int, scheme) - -/* Sorts only the selected entries in a playlist according to one of those - * schemes. */ -AUD_VFUNC2 (playlist_sort_selected_by_scheme, int, playlist, int, scheme) - -/* Removes duplicate entries in a playlist according to one of those schemes. - * As currently implemented, first sorts the playlist. */ -AUD_VFUNC2 (playlist_remove_duplicates_by_scheme, int, playlist, int, - scheme) - -/* Removes all entries referring to unavailable files in a playlist. ("Remove - * failed" is something of a misnomer for the current behavior.) As currently - * implemented, only works for file:// URIs. */ -AUD_VFUNC1 (playlist_remove_failed, int, playlist) - -/* Selects all the entries in a playlist that match regular expressions stored - * in the fields of a tuple. Does not free the memory used by the tuple. - * Example: To select all the songs whose title starts with the letter "A", - * create a blank tuple and set its title field to "^A". */ -AUD_VFUNC2 (playlist_select_by_patterns, int, playlist, const Tuple *, - patterns) - -/* Returns nonzero if <filename> refers to a playlist file. */ -AUD_FUNC1 (bool_t, filename_is_playlist, const char *, filename) - -/* Saves the entries in a playlist to a playlist file. The format of the file - * is determined from the file extension. Returns nonzero on success. */ -AUD_FUNC2 (bool_t, playlist_save, int, playlist, const char *, filename) - -/* added in Audacious 3.4 */ - -/* Reverses the order of the selected entries in a playlist. */ -AUD_VFUNC1 (playlist_reverse_selected, int, playlist) - -/* Reorders the selected entries in a playlist randomly. */ -AUD_VFUNC1 (playlist_randomize_selected, int, playlist) - -/* Sets the entry which has keyboard focus (-1 means no entry). */ -AUD_VFUNC2 (playlist_set_focus, int, playlist_num, int, entry_num) - -/* Gets the entry which has keyboard focus (-1 means no entry). */ -AUD_FUNC1 (int, playlist_get_focus, int, playlist_num) diff --git a/src/audacious/playlist-files.c b/src/audacious/playlist-files.c deleted file mode 100644 index 8ebe521..0000000 --- a/src/audacious/playlist-files.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * playlist-files.c - * Copyright 2010-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <glib.h> -#include <libaudcore/audstrings.h> - -#include "debug.h" -#include "i18n.h" -#include "misc.h" -#include "playlist.h" -#include "plugin.h" -#include "plugins.h" - -typedef struct -{ - const char * filename; - char * title; - Index * filenames; - Index * tuples; - bool_t plugin_found; - bool_t success; -} -PlaylistData; - -static void plugin_for_filename (const char * filename, PluginForEachFunc func, void * data) -{ - char ext[32]; - if (uri_get_extension (filename, ext, sizeof ext)) - playlist_plugin_for_ext (ext, func, data); -} - -static bool_t plugin_found_cb (PluginHandle * plugin, void * data) -{ - * (PluginHandle * *) data = plugin; - return FALSE; /* stop when first plugin is found */ -} - -bool_t filename_is_playlist (const char * filename) -{ - PluginHandle * plugin = NULL; - plugin_for_filename (filename, plugin_found_cb, & plugin); - return (plugin != NULL); -} - -static bool_t playlist_load_cb (PluginHandle * plugin, void * data_) -{ - PlaylistData * data = (PlaylistData *) data_; - - PlaylistPlugin * pp = plugin_get_header (plugin); - if (! pp || ! PLUGIN_HAS_FUNC (pp, load)) - return TRUE; /* try another plugin */ - - data->plugin_found = TRUE; - - VFSFile * file = vfs_fopen (data->filename, "r"); - if (! file) - return FALSE; /* stop if we can't open file */ - - data->success = pp->load (data->filename, file, & data->title, data->filenames, data->tuples); - - vfs_fclose (file); - return ! data->success; /* stop when playlist is loaded */ -} - -bool_t playlist_load (const char * filename, char * * title, Index * * filenames, Index * * tuples) -{ - PlaylistData data = - { - .filename = filename, - .filenames = index_new (), - .tuples = index_new () - }; - - AUDDBG ("Loading playlist %s.\n", filename); - plugin_for_filename (filename, playlist_load_cb, & data); - - if (! data.plugin_found) - { - SPRINTF (error, _("Cannot load %s: unsupported file extension."), filename); - interface_show_error (error); - } - - if (! data.success) - { - str_unref (data.title); - index_free_full (data.filenames, (IndexFreeFunc) str_unref); - index_free_full (data.tuples, (IndexFreeFunc) tuple_unref); - return FALSE; - } - - if (index_count (data.tuples)) - g_return_val_if_fail (index_count (data.tuples) == index_count (data.filenames), FALSE); - else - { - index_free (data.tuples); - data.tuples = NULL; - } - - * title = data.title; - * filenames = data.filenames; - * tuples = data.tuples; - return TRUE; -} - -bool_t playlist_insert_playlist_raw (int list, int at, const char * filename) -{ - char * title = NULL; - Index * filenames, * tuples; - - if (! playlist_load (filename, & title, & filenames, & tuples)) - return FALSE; - - if (title && ! playlist_entry_count (list)) - playlist_set_title (list, title); - - playlist_entry_insert_batch_raw (list, at, filenames, tuples, NULL); - - str_unref (title); - return TRUE; -} - -static bool_t playlist_save_cb (PluginHandle * plugin, void * data_) -{ - PlaylistData * data = data_; - - PlaylistPlugin * pp = plugin_get_header (plugin); - if (! pp || ! PLUGIN_HAS_FUNC (pp, save)) - return TRUE; /* try another plugin */ - - data->plugin_found = TRUE; - - VFSFile * file = vfs_fopen (data->filename, "w"); - if (! file) - return FALSE; /* stop if we can't open file */ - - data->success = pp->save (data->filename, file, data->title, data->filenames, data->tuples); - - vfs_fclose (file); - return FALSE; /* stop after first attempt (successful or not) */ -} - -bool_t playlist_save (int list, const char * filename) -{ - PlaylistData data = - { - .filename = filename, - .title = playlist_get_title (list), - .filenames = index_new (), - .tuples = index_new () - }; - - int entries = playlist_entry_count (list); - bool_t fast = get_bool (NULL, "metadata_on_play"); - - index_allocate (data.filenames, entries); - index_allocate (data.tuples, entries); - - for (int i = 0; i < entries; i ++) - { - index_insert (data.filenames, -1, playlist_entry_get_filename (list, i)); - index_insert (data.tuples, -1, playlist_entry_get_tuple (list, i, fast)); - } - - AUDDBG ("Saving playlist %s.\n", filename); - plugin_for_filename (filename, playlist_save_cb, & data); - - if (! data.plugin_found) - { - SPRINTF (error, _("Cannot save %s: unsupported file extension."), filename); - interface_show_error (error); - } - - str_unref (data.title); - index_free_full (data.filenames, (IndexFreeFunc) str_unref); - index_free_full (data.tuples, (IndexFreeFunc) tuple_unref); - - return data.success; -} diff --git a/src/audacious/playlist-new.c b/src/audacious/playlist-new.c deleted file mode 100644 index 23696b0..0000000 --- a/src/audacious/playlist-new.c +++ /dev/null @@ -1,2401 +0,0 @@ -/* - * playlist-new.c - * Copyright 2009-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include <glib.h> -#include <glib/gstdio.h> - -#include <libaudcore/audstrings.h> -#include <libaudcore/hook.h> -#include <libaudcore/tuple.h> - -#include "drct.h" -#include "i18n.h" -#include "misc.h" -#include "playback.h" -#include "playlist.h" -#include "plugins.h" -#include "scanner.h" -#include "util.h" - -enum {RESUME_STOP, RESUME_PLAY, RESUME_PAUSE}; - -#define STATE_FILE "playlist-state" - -#define ENTER pthread_mutex_lock (& mutex) -#define LEAVE pthread_mutex_unlock (& mutex) - -#define RETURN(...) do { \ - pthread_mutex_unlock (& mutex); \ - return __VA_ARGS__; \ -} while (0) - -#define ENTER_GET_PLAYLIST(...) ENTER; \ - Playlist * playlist = lookup_playlist (playlist_num); \ - if (! playlist) \ - RETURN (__VA_ARGS__); - -#define ENTER_GET_ENTRY(...) ENTER_GET_PLAYLIST (__VA_ARGS__); \ - Entry * entry = lookup_entry (playlist, entry_num); \ - if (! entry) \ - RETURN (__VA_ARGS__); - -typedef struct { - int level, before, after; -} Update; - -typedef struct { - int number; - char * filename; - PluginHandle * decoder; - Tuple * tuple; - char * formatted, * title, * artist, * album; - int length; - bool_t failed; - bool_t selected; - int shuffle_num; - bool_t queued; -} Entry; - -typedef struct { - int number, unique_id; - char * filename, * title; - bool_t modified; - Index * entries; - Entry * position, * focus; - int selected_count; - int last_shuffle_num; - GList * queued; - int64_t total_length, selected_length; - bool_t scanning, scan_ending; - Update next_update, last_update; - bool_t resume_paused; - int resume_time; -} Playlist; - -static const char * const default_title = N_("New Playlist"); -static const char * const temp_title = N_("Now Playing"); - -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; - -/* The unique ID table contains pointers to Playlist for ID's in use and NULL - * for "dead" (previously used and therefore unavailable) ID's. */ -static GHashTable * unique_id_table = NULL; -static int next_unique_id = 1000; - -static Index * playlists = NULL; -static Playlist * active_playlist = NULL; -static Playlist * playing_playlist = NULL; -static int resume_playlist = -1; - -static int update_source = 0, update_level; - -typedef struct { - Playlist * playlist; - Entry * entry; - ScanRequest * request; -} ScanItem; - -static int scan_playlist, scan_row; -static GList * scan_list = NULL; - -static void scan_finish (ScanRequest * request); -static void scan_cancel (Entry * entry); -static void scan_restart (void); - -static bool_t next_song_locked (Playlist * playlist, bool_t repeat, int hint); - -static TupleFormatter * title_formatter; - -static void entry_set_tuple_real (Entry * entry, Tuple * tuple) -{ - /* Hack: We cannot refresh segmented entries (since their info is read from - * the cue sheet when it is first loaded), so leave them alone. -jlindgren */ - if (entry->tuple && tuple_get_value_type (entry->tuple, FIELD_SEGMENT_START) == TUPLE_INT) - { - if (tuple) - tuple_unref (tuple); - return; - } - - if (entry->tuple) - tuple_unref (entry->tuple); - - entry->tuple = tuple; - entry->failed = FALSE; - - str_unref (entry->formatted); - str_unref (entry->title); - str_unref (entry->artist); - str_unref (entry->album); - - describe_song (entry->filename, tuple, & entry->title, & entry->artist, & entry->album); - - if (! tuple) - { - entry->formatted = NULL; - entry->length = 0; - } - else - { - entry->formatted = tuple_format_title (title_formatter, tuple); - entry->length = tuple_get_int (tuple, FIELD_LENGTH); - if (entry->length < 0) - entry->length = 0; - } -} - -static void entry_set_tuple (Playlist * playlist, Entry * entry, Tuple * tuple) -{ - scan_cancel (entry); - - if (entry->tuple) - { - playlist->total_length -= entry->length; - if (entry->selected) - playlist->selected_length -= entry->length; - } - - entry_set_tuple_real (entry, tuple); - - if (tuple) - { - playlist->total_length += entry->length; - if (entry->selected) - playlist->selected_length += entry->length; - } -} - -static void entry_set_failed (Playlist * playlist, Entry * entry) -{ - entry_set_tuple (playlist, entry, tuple_new_from_filename (entry->filename)); - entry->failed = TRUE; -} - -static Entry * entry_new (char * filename, Tuple * tuple, PluginHandle * decoder) -{ - Entry * entry = g_slice_new (Entry); - - entry->filename = filename; - entry->decoder = decoder; - entry->tuple = NULL; - entry->formatted = NULL; - entry->title = NULL; - entry->artist = NULL; - entry->album = NULL; - entry->failed = FALSE; - entry->number = -1; - entry->selected = FALSE; - entry->shuffle_num = 0; - entry->queued = FALSE; - - entry_set_tuple_real (entry, tuple); - return entry; -} - -static void entry_free (Entry * entry) -{ - scan_cancel (entry); - - str_unref (entry->filename); - if (entry->tuple) - tuple_unref (entry->tuple); - - str_unref (entry->formatted); - str_unref (entry->title); - str_unref (entry->artist); - str_unref (entry->album); - g_slice_free (Entry, entry); -} - -static int new_unique_id (int preferred) -{ - if (preferred >= 0 && ! g_hash_table_lookup_extended (unique_id_table, - GINT_TO_POINTER (preferred), NULL, NULL)) - return preferred; - - while (g_hash_table_lookup_extended (unique_id_table, - GINT_TO_POINTER (next_unique_id), NULL, NULL)) - next_unique_id ++; - - return next_unique_id ++; -} - -static Playlist * playlist_new (int id) -{ - Playlist * playlist = g_slice_new (Playlist); - - playlist->number = -1; - playlist->unique_id = new_unique_id (id); - playlist->filename = NULL; - playlist->title = str_get (_(default_title)); - playlist->modified = TRUE; - playlist->entries = index_new(); - playlist->position = NULL; - playlist->focus = NULL; - playlist->selected_count = 0; - playlist->last_shuffle_num = 0; - playlist->queued = NULL; - playlist->total_length = 0; - playlist->selected_length = 0; - playlist->scanning = FALSE; - playlist->scan_ending = FALSE; - playlist->resume_paused = FALSE; - playlist->resume_time = 0; - - memset (& playlist->last_update, 0, sizeof (Update)); - memset (& playlist->next_update, 0, sizeof (Update)); - - g_hash_table_insert (unique_id_table, GINT_TO_POINTER (playlist->unique_id), playlist); - return playlist; -} - -static void playlist_free (Playlist * playlist) -{ - g_hash_table_insert (unique_id_table, GINT_TO_POINTER (playlist->unique_id), NULL); - - str_unref (playlist->filename); - str_unref (playlist->title); - index_free_full (playlist->entries, (IndexFreeFunc) entry_free); - g_list_free (playlist->queued); - g_slice_free (Playlist, playlist); -} - -static void number_playlists (int at, int length) -{ - for (int count = 0; count < length; count ++) - { - Playlist * playlist = index_get (playlists, at + count); - playlist->number = at + count; - } -} - -static Playlist * lookup_playlist (int playlist_num) -{ - return (playlists && playlist_num >= 0 && playlist_num < index_count - (playlists)) ? index_get (playlists, playlist_num) : NULL; -} - -static void number_entries (Playlist * playlist, int at, int length) -{ - for (int count = 0; count < length; count ++) - { - Entry * entry = index_get (playlist->entries, at + count); - entry->number = at + count; - } -} - -static Entry * lookup_entry (Playlist * playlist, int entry_num) -{ - return (entry_num >= 0 && entry_num < index_count (playlist->entries)) ? - index_get (playlist->entries, entry_num) : NULL; -} - -static bool_t update (void * unused) -{ - ENTER; - - for (int i = 0; i < index_count (playlists); i ++) - { - Playlist * p = index_get (playlists, i); - memcpy (& p->last_update, & p->next_update, sizeof (Update)); - memset (& p->next_update, 0, sizeof (Update)); - } - - int level = update_level; - update_level = 0; - - if (update_source) - { - g_source_remove (update_source); - update_source = 0; - } - - LEAVE; - - hook_call ("playlist update", GINT_TO_POINTER (level)); - return FALSE; -} - -static void queue_update (int level, int list, int at, int count) -{ - Playlist * p = lookup_playlist (list); - - if (p) - { - if (level >= PLAYLIST_UPDATE_METADATA) - { - p->modified = TRUE; - - if (! get_bool (NULL, "metadata_on_play")) - { - p->scanning = TRUE; - p->scan_ending = FALSE; - scan_restart (); - } - } - - if (p->next_update.level) - { - p->next_update.level = MAX (p->next_update.level, level); - p->next_update.before = MIN (p->next_update.before, at); - p->next_update.after = MIN (p->next_update.after, - index_count (p->entries) - at - count); - } - else - { - p->next_update.level = level; - p->next_update.before = at; - p->next_update.after = index_count (p->entries) - at - count; - } - } - - update_level = MAX (update_level, level); - - if (! update_source) - update_source = g_idle_add_full (G_PRIORITY_HIGH, update, NULL, NULL); -} - -bool_t playlist_update_pending (void) -{ - ENTER; - bool_t pending = update_level ? TRUE : FALSE; - RETURN (pending); -} - -int playlist_updated_range (int playlist_num, int * at, int * count) -{ - ENTER_GET_PLAYLIST (0); - - Update * u = & playlist->last_update; - - int level = u->level; - * at = u->before; - * count = index_count (playlist->entries) - u->before - u->after; - - RETURN (level); -} - -bool_t playlist_scan_in_progress (int playlist_num) -{ - if (playlist_num >= 0) - { - ENTER_GET_PLAYLIST (FALSE); - bool_t scanning = playlist->scanning || playlist->scan_ending; - RETURN (scanning); - } - else - { - ENTER; - - bool_t scanning = FALSE; - for (playlist_num = 0; playlist_num < index_count (playlists); playlist_num ++) - { - Playlist * playlist = index_get (playlists, playlist_num); - if (playlist->scanning || playlist->scan_ending) - scanning = TRUE; - } - - RETURN (scanning); - } -} - -static GList * scan_list_find_playlist (Playlist * playlist) -{ - for (GList * node = scan_list; node; node = node->next) - { - ScanItem * item = node->data; - if (item->playlist == playlist) - return node; - } - - return NULL; -} - -static GList * scan_list_find_entry (Entry * entry) -{ - for (GList * node = scan_list; node; node = node->next) - { - ScanItem * item = node->data; - if (item->entry == entry) - return node; - } - - return NULL; -} - -static GList * scan_list_find_request (ScanRequest * request) -{ - for (GList * node = scan_list; node; node = node->next) - { - ScanItem * item = node->data; - if (item->request == request) - return node; - } - - return NULL; -} - -static void scan_queue_entry (Playlist * playlist, Entry * entry) -{ - int flags = 0; - if (! entry->tuple) - flags |= SCAN_TUPLE; - - ScanItem * item = g_slice_new (ScanItem); - item->playlist = playlist; - item->entry = entry; - item->request = scan_request (entry->filename, flags, entry->decoder, scan_finish); - scan_list = g_list_prepend (scan_list, item); -} - -static void scan_check_complete (Playlist * playlist) -{ - if (! playlist->scan_ending || scan_list_find_playlist (playlist)) - return; - - playlist->scan_ending = FALSE; - event_queue_cancel ("playlist scan complete", NULL); - event_queue ("playlist scan complete", NULL); -} - -static bool_t scan_queue_next_entry (void) -{ - while (scan_playlist < index_count (playlists)) - { - Playlist * playlist = index_get (playlists, scan_playlist); - - if (playlist->scanning) - { - while (scan_row < index_count (playlist->entries)) - { - Entry * entry = index_get (playlist->entries, scan_row ++); - - if (! entry->tuple && ! scan_list_find_entry (entry)) - { - scan_queue_entry (playlist, entry); - return TRUE; - } - } - - playlist->scanning = FALSE; - playlist->scan_ending = TRUE; - scan_check_complete (playlist); - } - - scan_playlist ++; - scan_row = 0; - } - - return FALSE; -} - -static void scan_schedule (void) -{ - while (g_list_length (scan_list) < SCAN_THREADS) - { - if (! scan_queue_next_entry ()) - break; - } -} - -static void scan_finish (ScanRequest * request) -{ - ENTER; - - GList * node = scan_list_find_request (request); - if (! node) - RETURN (); - - ScanItem * item = node->data; - Playlist * playlist = item->playlist; - Entry * entry = item->entry; - bool_t changed = FALSE; - - scan_list = g_list_delete_link (scan_list, node); - g_slice_free (ScanItem, item); - - if (! entry->decoder) - entry->decoder = scan_request_get_decoder (request); - - if (! entry->tuple) - { - Tuple * tuple = scan_request_get_tuple (request); - if (tuple) - { - entry_set_tuple (playlist, entry, tuple); - changed = TRUE; - } - } - - if (! entry->decoder || ! entry->tuple) - entry_set_failed (playlist, entry); - - if (changed) - queue_update (PLAYLIST_UPDATE_METADATA, playlist->number, entry->number, 1); - - scan_check_complete (playlist); - scan_schedule (); - - pthread_cond_broadcast (& cond); - - LEAVE; -} - -static void scan_cancel (Entry * entry) -{ - GList * node = scan_list_find_entry (entry); - if (! node) - return; - - ScanItem * item = node->data; - scan_list = g_list_delete_link (scan_list, node); - g_slice_free (ScanItem, item); -} - -static void scan_restart (void) -{ - scan_playlist = 0; - scan_row = 0; - scan_schedule (); -} - -/* mutex may be unlocked during the call */ -static Entry * get_entry (int playlist_num, int entry_num, - bool_t need_decoder, bool_t need_tuple) -{ - while (1) - { - Playlist * playlist = lookup_playlist (playlist_num); - Entry * entry = playlist ? lookup_entry (playlist, entry_num) : NULL; - - if (! entry || entry->failed) - return entry; - - if ((need_decoder && ! entry->decoder) || (need_tuple && ! entry->tuple)) - { - if (! scan_list_find_entry (entry)) - scan_queue_entry (playlist, entry); - - pthread_cond_wait (& cond, & mutex); - continue; - } - - return entry; - } -} - -/* mutex may be unlocked during the call */ -static Entry * get_playback_entry (bool_t need_decoder, bool_t need_tuple) -{ - while (1) - { - Entry * entry = playing_playlist ? playing_playlist->position : NULL; - - if (! entry || entry->failed) - return entry; - - if ((need_decoder && ! entry->decoder) || (need_tuple && ! entry->tuple)) - { - if (! scan_list_find_entry (entry)) - scan_queue_entry (playing_playlist, entry); - - pthread_cond_wait (& cond, & mutex); - continue; - } - - return entry; - } -} - -void playlist_init (void) -{ - srand (time (NULL)); - - ENTER; - - unique_id_table = g_hash_table_new (g_direct_hash, g_direct_equal); - playlists = index_new (); - - update_level = 0; - scan_playlist = scan_row = 0; - - LEAVE; - - /* initialize title formatter */ - playlist_reformat_titles (); -} - -void playlist_end (void) -{ - ENTER; - - if (update_source) - { - g_source_remove (update_source); - update_source = 0; - } - - active_playlist = playing_playlist = NULL; - resume_playlist = -1; - - index_free_full (playlists, (IndexFreeFunc) playlist_free); - playlists = NULL; - - g_hash_table_destroy (unique_id_table); - unique_id_table = NULL; - - tuple_formatter_free (title_formatter); - title_formatter = NULL; - - LEAVE; -} - -int playlist_count (void) -{ - ENTER; - int count = index_count (playlists); - RETURN (count); -} - -void playlist_insert_with_id (int at, int id) -{ - ENTER; - - if (at < 0 || at > index_count (playlists)) - at = index_count (playlists); - - index_insert (playlists, at, playlist_new (id)); - number_playlists (at, index_count (playlists) - at); - - queue_update (PLAYLIST_UPDATE_STRUCTURE, -1, 0, 0); - LEAVE; -} - -void playlist_insert (int at) -{ - playlist_insert_with_id (at, -1); -} - -void playlist_reorder (int from, int to, int count) -{ - ENTER; - - if (from < 0 || from + count > index_count (playlists) || to < 0 || to + - count > index_count (playlists) || count < 0) - RETURN (); - - Index * displaced = index_new (); - - if (to < from) - index_copy_insert (playlists, to, displaced, -1, from - to); - else - index_copy_insert (playlists, from + count, displaced, -1, to - from); - - index_copy_set (playlists, from, playlists, to, count); - - if (to < from) - { - index_copy_set (displaced, 0, playlists, to + count, from - to); - number_playlists (to, from + count - to); - } - else - { - index_copy_set (displaced, 0, playlists, from, to - from); - number_playlists (from, to + count - from); - } - - index_free (displaced); - - queue_update (PLAYLIST_UPDATE_STRUCTURE, -1, 0, 0); - LEAVE; -} - -void playlist_delete (int playlist_num) -{ - ENTER_GET_PLAYLIST (); - - bool_t was_playing = (playlist == playing_playlist); - - index_delete_full (playlists, playlist_num, 1, (IndexFreeFunc) playlist_free); - - if (! index_count (playlists)) - index_insert (playlists, 0, playlist_new (-1)); - - number_playlists (playlist_num, index_count (playlists) - playlist_num); - - if (playlist == active_playlist) - active_playlist = index_get (playlists, MIN (playlist_num, index_count (playlists) - 1)); - if (playlist == playing_playlist) - playing_playlist = NULL; - - queue_update (PLAYLIST_UPDATE_STRUCTURE, -1, 0, 0); - LEAVE; - - if (was_playing) - playback_stop (); -} - -int playlist_get_unique_id (int playlist_num) -{ - ENTER_GET_PLAYLIST (-1); - int unique_id = playlist->unique_id; - RETURN (unique_id); -} - -int playlist_by_unique_id (int id) -{ - ENTER; - - Playlist * p = g_hash_table_lookup (unique_id_table, GINT_TO_POINTER (id)); - int num = p ? p->number : -1; - - RETURN (num); -} - -void playlist_set_filename (int playlist_num, const char * filename) -{ - ENTER_GET_PLAYLIST (); - - str_unref (playlist->filename); - playlist->filename = str_get (filename); - playlist->modified = TRUE; - - queue_update (PLAYLIST_UPDATE_METADATA, -1, 0, 0); - LEAVE; -} - -char * playlist_get_filename (int playlist_num) -{ - ENTER_GET_PLAYLIST (NULL); - char * filename = str_ref (playlist->filename); - RETURN (filename); -} - -void playlist_set_title (int playlist_num, const char * title) -{ - ENTER_GET_PLAYLIST (); - - str_unref (playlist->title); - playlist->title = str_get (title); - playlist->modified = TRUE; - - queue_update (PLAYLIST_UPDATE_METADATA, -1, 0, 0); - LEAVE; -} - -char * playlist_get_title (int playlist_num) -{ - ENTER_GET_PLAYLIST (NULL); - char * title = str_ref (playlist->title); - RETURN (title); -} - -void playlist_set_modified (int playlist_num, bool_t modified) -{ - ENTER_GET_PLAYLIST (); - playlist->modified = modified; - LEAVE; -} - -bool_t playlist_get_modified (int playlist_num) -{ - ENTER_GET_PLAYLIST (FALSE); - bool_t modified = playlist->modified; - RETURN (modified); -} - -void playlist_set_active (int playlist_num) -{ - ENTER_GET_PLAYLIST (); - - bool_t changed = FALSE; - - if (playlist != active_playlist) - { - changed = TRUE; - active_playlist = playlist; - } - - LEAVE; - - if (changed) - hook_call ("playlist activate", NULL); -} - -int playlist_get_active (void) -{ - ENTER; - int list = active_playlist ? active_playlist->number : -1; - RETURN (list); -} - -void playlist_set_playing (int playlist_num) -{ - /* get playback state before locking playlists */ - bool_t paused = drct_get_paused (); - int time = drct_get_time (); - - ENTER; - - Playlist * playlist = lookup_playlist (playlist_num); - bool_t can_play = FALSE; - bool_t position_changed = FALSE; - - if (playlist == playing_playlist) - RETURN (); - - if (playing_playlist) - { - playing_playlist->resume_paused = paused; - playing_playlist->resume_time = time; - } - - /* is there anything to play? */ - if (playlist && ! playlist->position) - { - if (next_song_locked (playlist, TRUE, 0)) - position_changed = TRUE; - else - playlist = NULL; - } - - if (playlist) - { - can_play = TRUE; - paused = playlist->resume_paused; - time = playlist->resume_time; - } - - playing_playlist = playlist; - - LEAVE; - - if (position_changed) - hook_call ("playlist position", GINT_TO_POINTER (playlist_num)); - - hook_call ("playlist set playing", NULL); - - /* start playback after unlocking playlists */ - if (can_play) - playback_play (time, paused); - else - playback_stop (); -} - -int playlist_get_playing (void) -{ - ENTER; - int list = playing_playlist ? playing_playlist->number: -1; - RETURN (list); -} - -int playlist_get_blank (void) -{ - int list = playlist_get_active (); - char * title = playlist_get_title (list); - - if (strcmp (title, _(default_title)) || playlist_entry_count (list) > 0) - { - list = playlist_count (); - playlist_insert (list); - } - - str_unref (title); - return list; -} - -int playlist_get_temporary (void) -{ - int list, count = playlist_count (); - bool_t found = FALSE; - - for (list = 0; list < count; list ++) - { - char * title = playlist_get_title (list); - found = ! strcmp (title, _(temp_title)); - str_unref (title); - - if (found) - break; - } - - if (! found) - { - list = playlist_get_blank (); - playlist_set_title (list, _(temp_title)); - } - - return list; -} - -static void set_position (Playlist * playlist, Entry * entry, bool_t update_shuffle) -{ - playlist->position = entry; - playlist->resume_time = 0; - - /* move entry to top of shuffle list */ - if (entry && update_shuffle) - entry->shuffle_num = ++ playlist->last_shuffle_num; -} - -/* unlocked */ -static void change_playback (bool_t can_play) -{ - if (can_play && drct_get_playing ()) - playback_play (0, drct_get_paused ()); - else - playlist_set_playing (-1); -} - -int playlist_entry_count (int playlist_num) -{ - ENTER_GET_PLAYLIST (0); - int count = index_count (playlist->entries); - RETURN (count); -} - -void playlist_entry_insert_batch_raw (int playlist_num, int at, - Index * filenames, Index * tuples, Index * decoders) -{ - ENTER_GET_PLAYLIST (); - - int entries = index_count (playlist->entries); - - if (at < 0 || at > entries) - at = entries; - - int number = index_count (filenames); - - Index * add = index_new (); - index_allocate (add, number); - - for (int i = 0; i < number; i ++) - { - char * filename = index_get (filenames, i); - Tuple * tuple = tuples ? index_get (tuples, i) : NULL; - PluginHandle * decoder = decoders ? index_get (decoders, i) : NULL; - index_insert (add, -1, entry_new (filename, tuple, decoder)); - } - - index_free (filenames); - if (decoders) - index_free (decoders); - if (tuples) - index_free (tuples); - - number = index_count (add); - index_copy_insert (add, 0, playlist->entries, at, -1); - index_free (add); - - number_entries (playlist, at, entries + number - at); - - for (int count = 0; count < number; count ++) - { - Entry * entry = index_get (playlist->entries, at + count); - playlist->total_length += entry->length; - } - - queue_update (PLAYLIST_UPDATE_STRUCTURE, playlist->number, at, number); - LEAVE; -} - -void playlist_entry_delete (int playlist_num, int at, int number) -{ - ENTER_GET_PLAYLIST (); - - int entries = index_count (playlist->entries); - bool_t position_changed = FALSE; - bool_t was_playing = FALSE; - bool_t can_play = FALSE; - - if (at < 0 || at > entries) - at = entries; - if (number < 0 || number > entries - at) - number = entries - at; - - if (playlist->position && playlist->position->number >= at && - playlist->position->number < at + number) - { - position_changed = TRUE; - was_playing = (playlist == playing_playlist); - - set_position (playlist, NULL, FALSE); - } - - if (playlist->focus && playlist->focus->number >= at && - playlist->focus->number < at + number) - { - if (at + number < entries) - playlist->focus = index_get (playlist->entries, at + number); - else if (at > 0) - playlist->focus = index_get (playlist->entries, at - 1); - else - playlist->focus = NULL; - } - - for (int count = 0; count < number; count ++) - { - Entry * entry = index_get (playlist->entries, at + count); - - if (entry->queued) - playlist->queued = g_list_remove (playlist->queued, entry); - - if (entry->selected) - { - playlist->selected_count --; - playlist->selected_length -= entry->length; - } - - playlist->total_length -= entry->length; - } - - index_delete_full (playlist->entries, at, number, (IndexFreeFunc) entry_free); - number_entries (playlist, at, entries - at - number); - - if (position_changed && get_bool (NULL, "advance_on_delete")) - can_play = next_song_locked (playlist, get_bool (NULL, "repeat"), at); - - queue_update (PLAYLIST_UPDATE_STRUCTURE, playlist->number, at, 0); - LEAVE; - - if (position_changed) - hook_call ("playlist position", GINT_TO_POINTER (playlist_num)); - if (was_playing) - change_playback (can_play); -} - -char * playlist_entry_get_filename (int playlist_num, int entry_num) -{ - ENTER_GET_ENTRY (NULL); - char * filename = str_ref (entry->filename); - RETURN (filename); -} - -PluginHandle * playlist_entry_get_decoder (int playlist_num, int entry_num, bool_t fast) -{ - ENTER; - - Entry * entry = get_entry (playlist_num, entry_num, ! fast, FALSE); - PluginHandle * decoder = entry ? entry->decoder : NULL; - - RETURN (decoder); -} - -Tuple * playlist_entry_get_tuple (int playlist_num, int entry_num, bool_t fast) -{ - ENTER; - - Entry * entry = get_entry (playlist_num, entry_num, FALSE, ! fast); - Tuple * tuple = entry ? entry->tuple : NULL; - - if (tuple) - tuple_ref (tuple); - - RETURN (tuple); -} - -char * playlist_entry_get_title (int playlist_num, int entry_num, bool_t fast) -{ - ENTER; - - Entry * entry = get_entry (playlist_num, entry_num, FALSE, ! fast); - char * title = entry ? str_ref (entry->formatted ? entry->formatted : entry->title) : NULL; - - RETURN (title); -} - -void playlist_entry_describe (int playlist_num, int entry_num, - char * * title, char * * artist, char * * album, bool_t fast) -{ - ENTER; - - Entry * entry = get_entry (playlist_num, entry_num, FALSE, ! fast); - - if (title) - * title = (entry && entry->title) ? str_ref (entry->title) : NULL; - if (artist) - * artist = (entry && entry->artist) ? str_ref (entry->artist) : NULL; - if (album) - * album = (entry && entry->album) ? str_ref (entry->album) : NULL; - - LEAVE; -} - -int playlist_entry_get_length (int playlist_num, int entry_num, bool_t fast) -{ - ENTER; - - Entry * entry = get_entry (playlist_num, entry_num, FALSE, ! fast); - int length = entry ? entry->length : 0; - - RETURN (length); -} - -void playlist_set_position (int playlist_num, int entry_num) -{ - ENTER_GET_PLAYLIST (); - - Entry * entry = lookup_entry (playlist, entry_num); - bool_t was_playing = (playlist == playing_playlist); - bool_t can_play = !! entry; - - set_position (playlist, entry, TRUE); - - LEAVE; - - hook_call ("playlist position", GINT_TO_POINTER (playlist_num)); - if (was_playing) - change_playback (can_play); -} - -int playlist_get_position (int playlist_num) -{ - ENTER_GET_PLAYLIST (-1); - int position = playlist->position ? playlist->position->number : -1; - RETURN (position); -} - -void playlist_set_focus (int playlist_num, int entry_num) -{ - ENTER_GET_PLAYLIST (); - - int first = INT_MAX; - int last = -1; - - if (playlist->focus) - { - first = MIN (first, playlist->focus->number); - last = MAX (last, playlist->focus->number); - } - - playlist->focus = lookup_entry (playlist, entry_num); - - if (playlist->focus) - { - first = MIN (first, playlist->focus->number); - last = MAX (last, playlist->focus->number); - } - - if (first <= last) - queue_update (PLAYLIST_UPDATE_SELECTION, playlist_num, first, last + 1 - first); - - LEAVE; -} - -int playlist_get_focus (int playlist_num) -{ - ENTER_GET_PLAYLIST (-1); - int focus = playlist->focus ? playlist->focus->number : -1; - RETURN (focus); -} - -void playlist_entry_set_selected (int playlist_num, int entry_num, - bool_t selected) -{ - ENTER_GET_ENTRY (); - - if (entry->selected == selected) - RETURN (); - - entry->selected = selected; - - if (selected) - { - playlist->selected_count++; - playlist->selected_length += entry->length; - } - else - { - playlist->selected_count--; - playlist->selected_length -= entry->length; - } - - queue_update (PLAYLIST_UPDATE_SELECTION, playlist->number, entry_num, 1); - LEAVE; -} - -bool_t playlist_entry_get_selected (int playlist_num, int entry_num) -{ - ENTER_GET_ENTRY (FALSE); - bool_t selected = entry->selected; - RETURN (selected); -} - -int playlist_selected_count (int playlist_num) -{ - ENTER_GET_PLAYLIST (0); - int selected_count = playlist->selected_count; - RETURN (selected_count); -} - -void playlist_select_all (int playlist_num, bool_t selected) -{ - ENTER_GET_PLAYLIST (); - - int entries = index_count (playlist->entries); - int first = entries, last = 0; - - for (int count = 0; count < entries; count ++) - { - Entry * entry = index_get (playlist->entries, count); - - if ((selected && ! entry->selected) || (entry->selected && ! selected)) - { - entry->selected = selected; - first = MIN (first, entry->number); - last = entry->number; - } - } - - if (selected) - { - playlist->selected_count = entries; - playlist->selected_length = playlist->total_length; - } - else - { - playlist->selected_count = 0; - playlist->selected_length = 0; - } - - if (first < entries) - queue_update (PLAYLIST_UPDATE_SELECTION, playlist->number, first, last + 1 - first); - - LEAVE; -} - -int playlist_shift (int playlist_num, int entry_num, int distance) -{ - ENTER_GET_ENTRY (0); - - if (! entry->selected || ! distance) - RETURN (0); - - int entries = index_count (playlist->entries); - int shift = 0, center, top, bottom; - - if (distance < 0) - { - for (center = entry_num; center > 0 && shift > distance; ) - { - entry = index_get (playlist->entries, -- center); - if (! entry->selected) - shift --; - } - } - else - { - for (center = entry_num + 1; center < entries && shift < distance; ) - { - entry = index_get (playlist->entries, center ++); - if (! entry->selected) - shift ++; - } - } - - top = bottom = center; - - for (int i = 0; i < top; i ++) - { - entry = index_get (playlist->entries, i); - if (entry->selected) - top = i; - } - - for (int i = entries; i > bottom; i --) - { - entry = index_get (playlist->entries, i - 1); - if (entry->selected) - bottom = i; - } - - Index * temp = index_new (); - - for (int i = top; i < center; i ++) - { - entry = index_get (playlist->entries, i); - if (! entry->selected) - index_insert (temp, -1, entry); - } - - for (int i = top; i < bottom; i ++) - { - entry = index_get (playlist->entries, i); - if (entry->selected) - index_insert (temp, -1, entry); - } - - for (int i = center; i < bottom; i ++) - { - entry = index_get (playlist->entries, i); - if (! entry->selected) - index_insert (temp, -1, entry); - } - - index_copy_set (temp, 0, playlist->entries, top, bottom - top); - - number_entries (playlist, top, bottom - top); - queue_update (PLAYLIST_UPDATE_STRUCTURE, playlist->number, top, bottom - top); - - RETURN (shift); -} - -static Entry * find_unselected_focus (Playlist * playlist) -{ - if (! playlist->focus || ! playlist->focus->selected) - return playlist->focus; - - int entries = index_count (playlist->entries); - - for (int search = playlist->focus->number + 1; search < entries; search ++) - { - Entry * entry = index_get (playlist->entries, search); - if (! entry->selected) - return entry; - } - - for (int search = playlist->focus->number; search --;) - { - Entry * entry = index_get (playlist->entries, search); - if (! entry->selected) - return entry; - } - - return NULL; -} - -void playlist_delete_selected (int playlist_num) -{ - ENTER_GET_PLAYLIST (); - - if (! playlist->selected_count) - RETURN (); - - int entries = index_count (playlist->entries); - bool_t position_changed = FALSE; - bool_t was_playing = FALSE; - bool_t can_play = FALSE; - - Index * others = index_new (); - index_allocate (others, entries - playlist->selected_count); - - if (playlist->position && playlist->position->selected) - { - position_changed = TRUE; - was_playing = (playlist == playing_playlist); - - set_position (playlist, NULL, FALSE); - } - - playlist->focus = find_unselected_focus (playlist); - - int before = 0, after = 0; - bool_t found = FALSE; - - for (int count = 0; count < entries; count++) - { - Entry * entry = index_get (playlist->entries, count); - - if (entry->selected) - { - if (entry->queued) - playlist->queued = g_list_remove (playlist->queued, entry); - - playlist->total_length -= entry->length; - entry_free (entry); - - found = TRUE; - after = 0; - } - else - { - index_insert (others, -1, entry); - - if (found) - after ++; - else - before ++; - } - } - - index_free (playlist->entries); - playlist->entries = others; - - playlist->selected_count = 0; - playlist->selected_length = 0; - - entries = index_count (playlist->entries); - number_entries (playlist, before, entries - before); - - if (position_changed && get_bool (NULL, "advance_on_delete")) - can_play = next_song_locked (playlist, get_bool (NULL, "repeat"), entries - after); - - queue_update (PLAYLIST_UPDATE_STRUCTURE, playlist->number, before, entries - after - before); - LEAVE; - - if (position_changed) - hook_call ("playlist position", GINT_TO_POINTER (playlist_num)); - if (was_playing) - change_playback (can_play); -} - -void playlist_reverse (int playlist_num) -{ - ENTER_GET_PLAYLIST (); - - int entries = index_count (playlist->entries); - - Index * reversed = index_new (); - index_allocate (reversed, entries); - - for (int count = entries; count --; ) - index_insert (reversed, -1, index_get (playlist->entries, count)); - - index_free (playlist->entries); - playlist->entries = reversed; - - number_entries (playlist, 0, entries); - queue_update (PLAYLIST_UPDATE_STRUCTURE, playlist->number, 0, entries); - LEAVE; -} - -void playlist_reverse_selected (int playlist_num) -{ - ENTER_GET_PLAYLIST (); - - int entries = index_count (playlist->entries); - - Index * reversed = index_new (); - index_allocate (reversed, playlist->selected_count); - - for (int count = entries; count --; ) - { - Entry * entry = index_get (playlist->entries, count); - if (entry->selected) - index_insert (reversed, -1, index_get (playlist->entries, count)); - } - - int count2 = 0; - for (int count = 0; count < entries; count++) - { - Entry * entry = index_get (playlist->entries, count); - if (entry->selected) - index_set (playlist->entries, count, index_get (reversed, count2 ++)); - } - - index_free (reversed); - - number_entries (playlist, 0, entries); - queue_update (PLAYLIST_UPDATE_STRUCTURE, playlist->number, 0, entries); - LEAVE; -} - -void playlist_randomize (int playlist_num) -{ - ENTER_GET_PLAYLIST (); - - int entries = index_count (playlist->entries); - - for (int i = 0; i < entries; i ++) - { - int j = i + rand () % (entries - i); - - Entry * entry = index_get (playlist->entries, j); - index_set (playlist->entries, j, index_get (playlist->entries, i)); - index_set (playlist->entries, i, entry); - } - - number_entries (playlist, 0, entries); - queue_update (PLAYLIST_UPDATE_STRUCTURE, playlist->number, 0, entries); - LEAVE; -} - -void playlist_randomize_selected (int playlist_num) -{ - ENTER_GET_PLAYLIST (); - - int entries = index_count (playlist->entries); - - Index * selected = index_new (); - index_allocate (selected, playlist->selected_count); - - for (int count = 0; count < entries; count++) - { - Entry * entry = index_get (playlist->entries, count); - if (entry->selected) - index_insert (selected, -1, entry); - } - - for (int i = 0; i < playlist->selected_count; i ++) - { - int j = i + rand () % (playlist->selected_count - i); - - Entry * entry = index_get (selected, j); - index_set (selected, j, index_get (selected, i)); - index_set (selected, i, entry); - } - - int count2 = 0; - for (int count = 0; count < entries; count++) - { - Entry * entry = index_get (playlist->entries, count); - if (entry->selected) - index_set (playlist->entries, count, index_get (selected, count2 ++)); - } - - index_free (selected); - - number_entries (playlist, 0, entries); - queue_update (PLAYLIST_UPDATE_STRUCTURE, playlist->number, 0, entries); - LEAVE; -} - -enum {COMPARE_TYPE_FILENAME, COMPARE_TYPE_TUPLE, COMPARE_TYPE_TITLE}; - -typedef int (* CompareFunc) (const void * a, const void * b); - -typedef struct { - int type; - CompareFunc func; -} CompareData; - -static int compare_cb (const void * _a, const void * _b, void * _data) -{ - const Entry * a = _a, * b = _b; - CompareData * data = _data; - - int diff = 0; - - if (data->type == COMPARE_TYPE_FILENAME) - diff = data->func (a->filename, b->filename); - else if (data->type == COMPARE_TYPE_TUPLE) - diff = data->func (a->tuple, b->tuple); - else if (data->type == COMPARE_TYPE_TITLE) - diff = data->func (a->formatted ? a->formatted : a->filename, - b->formatted ? b->formatted : b->filename); - - if (diff) - return diff; - - /* preserve order of "equal" entries */ - return a->number - b->number; -} - -static void sort (Playlist * playlist, CompareData * data) -{ - index_sort_with_data (playlist->entries, compare_cb, data); - number_entries (playlist, 0, index_count (playlist->entries)); - - queue_update (PLAYLIST_UPDATE_STRUCTURE, playlist->number, 0, index_count (playlist->entries)); -} - -static void sort_selected (Playlist * playlist, CompareData * data) -{ - int entries = index_count (playlist->entries); - - Index * selected = index_new (); - index_allocate (selected, playlist->selected_count); - - for (int count = 0; count < entries; count++) - { - Entry * entry = index_get (playlist->entries, count); - if (entry->selected) - index_insert (selected, -1, entry); - } - - index_sort_with_data (selected, compare_cb, data); - - int count2 = 0; - for (int count = 0; count < entries; count++) - { - Entry * entry = index_get (playlist->entries, count); - if (entry->selected) - index_set (playlist->entries, count, index_get (selected, count2 ++)); - } - - index_free (selected); - - number_entries (playlist, 0, entries); - queue_update (PLAYLIST_UPDATE_STRUCTURE, playlist->number, 0, entries); -} - -static bool_t entries_are_scanned (Playlist * playlist, bool_t selected) -{ - int entries = index_count (playlist->entries); - for (int count = 0; count < entries; count ++) - { - Entry * entry = index_get (playlist->entries, count); - if (selected && ! entry->selected) - continue; - - if (! entry->tuple) - { - interface_show_error (_("The playlist cannot be sorted because " - "metadata scanning is still in progress (or has been disabled).")); - return FALSE; - } - } - - return TRUE; -} - -void playlist_sort_by_filename (int playlist_num, int (* compare) - (const char * a, const char * b)) -{ - ENTER_GET_PLAYLIST (); - - CompareData data = {COMPARE_TYPE_FILENAME, (CompareFunc) compare}; - sort (playlist, & data); - - LEAVE; -} - -void playlist_sort_by_tuple (int playlist_num, int (* compare) - (const Tuple * a, const Tuple * b)) -{ - ENTER_GET_PLAYLIST (); - - CompareData data = {COMPARE_TYPE_TUPLE, (CompareFunc) compare}; - if (entries_are_scanned (playlist, FALSE)) - sort (playlist, & data); - - LEAVE; -} - -void playlist_sort_by_title (int playlist_num, int (* compare) (const char * - a, const char * b)) -{ - ENTER_GET_PLAYLIST (); - - CompareData data = {COMPARE_TYPE_TITLE, (CompareFunc) compare}; - if (entries_are_scanned (playlist, FALSE)) - sort (playlist, & data); - - LEAVE; -} - -void playlist_sort_selected_by_filename (int playlist_num, int (* compare) - (const char * a, const char * b)) -{ - ENTER_GET_PLAYLIST (); - - CompareData data = {COMPARE_TYPE_FILENAME, (CompareFunc) compare}; - sort_selected (playlist, & data); - - LEAVE; -} - -void playlist_sort_selected_by_tuple (int playlist_num, int (* compare) - (const Tuple * a, const Tuple * b)) -{ - ENTER_GET_PLAYLIST (); - - CompareData data = {COMPARE_TYPE_TUPLE, (CompareFunc) compare}; - if (entries_are_scanned (playlist, TRUE)) - sort_selected (playlist, & data); - - LEAVE; -} - -void playlist_sort_selected_by_title (int playlist_num, int (* compare) - (const char * a, const char * b)) -{ - ENTER_GET_PLAYLIST (); - - CompareData data = {COMPARE_TYPE_TITLE, (CompareFunc) compare}; - if (entries_are_scanned (playlist, TRUE)) - sort_selected (playlist, & data); - - LEAVE; -} - -void playlist_reformat_titles (void) -{ - ENTER; - - if (title_formatter) - tuple_formatter_free (title_formatter); - - char * format = get_str (NULL, "generic_title_format"); - title_formatter = tuple_formatter_new (format); - str_unref (format); - - for (int playlist_num = 0; playlist_num < index_count (playlists); playlist_num ++) - { - Playlist * playlist = index_get (playlists, playlist_num); - int entries = index_count (playlist->entries); - - for (int count = 0; count < entries; count++) - { - Entry * entry = index_get (playlist->entries, count); - str_unref (entry->formatted); - - if (entry->tuple) - entry->formatted = tuple_format_title (title_formatter, entry->tuple); - else - entry->formatted = NULL; - } - - queue_update (PLAYLIST_UPDATE_METADATA, playlist_num, 0, entries); - } - - LEAVE; -} - -void playlist_trigger_scan (void) -{ - ENTER; - - for (int i = 0; i < index_count (playlists); i ++) - { - Playlist * p = index_get (playlists, i); - p->scanning = TRUE; - } - - scan_restart (); - - LEAVE; -} - -static void playlist_rescan_real (int playlist_num, bool_t selected) -{ - ENTER_GET_PLAYLIST (); - - int entries = index_count (playlist->entries); - - for (int count = 0; count < entries; count ++) - { - Entry * entry = index_get (playlist->entries, count); - if (! selected || entry->selected) - entry_set_tuple (playlist, entry, NULL); - } - - queue_update (PLAYLIST_UPDATE_METADATA, playlist->number, 0, entries); - LEAVE; -} - -void playlist_rescan (int playlist_num) -{ - playlist_rescan_real (playlist_num, FALSE); -} - -void playlist_rescan_selected (int playlist_num) -{ - playlist_rescan_real (playlist_num, TRUE); -} - -void playlist_rescan_file (const char * filename) -{ - ENTER; - - int num_playlists = index_count (playlists); - - for (int playlist_num = 0; playlist_num < num_playlists; playlist_num ++) - { - Playlist * playlist = index_get (playlists, playlist_num); - int num_entries = index_count (playlist->entries); - - for (int entry_num = 0; entry_num < num_entries; entry_num ++) - { - Entry * entry = index_get (playlist->entries, entry_num); - - if (! strcmp (entry->filename, filename)) - { - entry_set_tuple (playlist, entry, NULL); - queue_update (PLAYLIST_UPDATE_METADATA, playlist_num, entry_num, 1); - } - } - } - - LEAVE; -} - -int64_t playlist_get_total_length (int playlist_num) -{ - ENTER_GET_PLAYLIST (0); - int64_t length = playlist->total_length; - RETURN (length); -} - -int64_t playlist_get_selected_length (int playlist_num) -{ - ENTER_GET_PLAYLIST (0); - int64_t length = playlist->selected_length; - RETURN (length); -} - -int playlist_queue_count (int playlist_num) -{ - ENTER_GET_PLAYLIST (0); - int count = g_list_length (playlist->queued); - RETURN (count); -} - -void playlist_queue_insert (int playlist_num, int at, int entry_num) -{ - ENTER_GET_ENTRY (); - - if (entry->queued) - RETURN (); - - if (at < 0) - playlist->queued = g_list_append (playlist->queued, entry); - else - playlist->queued = g_list_insert (playlist->queued, entry, at); - - entry->queued = TRUE; - - queue_update (PLAYLIST_UPDATE_SELECTION, playlist->number, entry_num, 1); - LEAVE; -} - -void playlist_queue_insert_selected (int playlist_num, int at) -{ - ENTER_GET_PLAYLIST (); - - int entries = index_count(playlist->entries); - int first = entries, last = 0; - - for (int count = 0; count < entries; count++) - { - Entry * entry = index_get (playlist->entries, count); - - if (! entry->selected || entry->queued) - continue; - - if (at < 0) - playlist->queued = g_list_append (playlist->queued, entry); - else - playlist->queued = g_list_insert (playlist->queued, entry, at++); - - entry->queued = TRUE; - first = MIN (first, entry->number); - last = entry->number; - } - - if (first < entries) - queue_update (PLAYLIST_UPDATE_SELECTION, playlist->number, first, last + 1 - first); - - LEAVE; -} - -int playlist_queue_get_entry (int playlist_num, int at) -{ - ENTER_GET_PLAYLIST (-1); - - GList * node = g_list_nth (playlist->queued, at); - int entry_num = node ? ((Entry *) node->data)->number : -1; - - RETURN (entry_num); -} - -int playlist_queue_find_entry (int playlist_num, int entry_num) -{ - ENTER_GET_ENTRY (-1); - int pos = entry->queued ? g_list_index (playlist->queued, entry) : -1; - RETURN (pos); -} - -void playlist_queue_delete (int playlist_num, int at, int number) -{ - ENTER_GET_PLAYLIST (); - - int entries = index_count (playlist->entries); - int first = entries, last = 0; - - if (at == 0) - { - while (playlist->queued && number --) - { - Entry * entry = playlist->queued->data; - entry->queued = FALSE; - first = MIN (first, entry->number); - last = entry->number; - - playlist->queued = g_list_delete_link (playlist->queued, playlist->queued); - } - } - else - { - GList * anchor = g_list_nth (playlist->queued, at - 1); - if (! anchor) - goto DONE; - - while (anchor->next && number --) - { - Entry * entry = anchor->next->data; - entry->queued = FALSE; - first = MIN (first, entry->number); - last = entry->number; - - playlist->queued = g_list_delete_link (playlist->queued, anchor->next); - } - } - -DONE: - if (first < entries) - queue_update (PLAYLIST_UPDATE_SELECTION, playlist->number, first, last + 1 - first); - - LEAVE; -} - -void playlist_queue_delete_selected (int playlist_num) -{ - ENTER_GET_PLAYLIST (); - - int entries = index_count (playlist->entries); - int first = entries, last = 0; - - for (GList * node = playlist->queued; node; ) - { - GList * next = node->next; - Entry * entry = node->data; - - if (entry->selected) - { - entry->queued = FALSE; - playlist->queued = g_list_delete_link (playlist->queued, node); - first = MIN (first, entry->number); - last = entry->number; - } - - node = next; - } - - if (first < entries) - queue_update (PLAYLIST_UPDATE_SELECTION, playlist->number, first, last + 1 - first); - - LEAVE; -} - -static bool_t shuffle_prev (Playlist * playlist) -{ - int entries = index_count (playlist->entries); - Entry * found = NULL; - - for (int count = 0; count < entries; count ++) - { - Entry * entry = index_get (playlist->entries, count); - - if (entry->shuffle_num && (! playlist->position || - entry->shuffle_num < playlist->position->shuffle_num) && (! found - || entry->shuffle_num > found->shuffle_num)) - found = entry; - } - - if (! found) - return FALSE; - - set_position (playlist, found, FALSE); - return TRUE; -} - -bool_t playlist_prev_song (int playlist_num) -{ - ENTER_GET_PLAYLIST (FALSE); - - bool_t was_playing = (playlist == playing_playlist); - - if (get_bool (NULL, "shuffle")) - { - if (! shuffle_prev (playlist)) - RETURN (FALSE); - } - else - { - if (! playlist->position || playlist->position->number == 0) - RETURN (FALSE); - - set_position (playlist, index_get (playlist->entries, - playlist->position->number - 1), TRUE); - } - - LEAVE; - - hook_call ("playlist position", GINT_TO_POINTER (playlist_num)); - if (was_playing) - change_playback (TRUE); - - return TRUE; -} - -static bool_t shuffle_next (Playlist * playlist) -{ - int entries = index_count (playlist->entries), choice = 0, count; - Entry * found = NULL; - - for (count = 0; count < entries; count ++) - { - Entry * entry = index_get (playlist->entries, count); - - if (! entry->shuffle_num) - choice ++; - else if (playlist->position && entry->shuffle_num > - playlist->position->shuffle_num && (! found || entry->shuffle_num - < found->shuffle_num)) - found = entry; - } - - if (found) - { - set_position (playlist, found, FALSE); - return TRUE; - } - - if (! choice) - return FALSE; - - choice = rand () % choice; - - for (count = 0; ; count ++) - { - Entry * entry = index_get (playlist->entries, count); - - if (! entry->shuffle_num) - { - if (! choice) - { - set_position (playlist, entry, TRUE); - return TRUE; - } - - choice --; - } - } -} - -static void shuffle_reset (Playlist * playlist) -{ - int entries = index_count (playlist->entries); - - playlist->last_shuffle_num = 0; - - for (int count = 0; count < entries; count ++) - { - Entry * entry = index_get (playlist->entries, count); - entry->shuffle_num = 0; - } -} - -static bool_t next_song_locked (Playlist * playlist, bool_t repeat, int hint) -{ - int entries = index_count (playlist->entries); - if (! entries) - return FALSE; - - if (playlist->queued) - { - set_position (playlist, playlist->queued->data, TRUE); - playlist->queued = g_list_remove (playlist->queued, playlist->position); - playlist->position->queued = FALSE; - } - else if (get_bool (NULL, "shuffle")) - { - if (! shuffle_next (playlist)) - { - if (! repeat) - return FALSE; - - shuffle_reset (playlist); - - if (! shuffle_next (playlist)) - return FALSE; - } - } - else - { - if (hint >= entries) - { - if (! repeat) - return FALSE; - - hint = 0; - } - - set_position (playlist, index_get (playlist->entries, hint), TRUE); - } - - return TRUE; -} - -bool_t playlist_next_song (int playlist_num, bool_t repeat) -{ - ENTER_GET_PLAYLIST (FALSE); - - int hint = playlist->position ? playlist->position->number + 1 : 0; - bool_t was_playing = (playlist == playing_playlist); - - if (! next_song_locked (playlist, repeat, hint)) - RETURN (FALSE); - - LEAVE; - - hook_call ("playlist position", GINT_TO_POINTER (playlist_num)); - if (was_playing) - change_playback (TRUE); - - return TRUE; -} - -int playback_entry_get_position (void) -{ - ENTER; - - Entry * entry = get_playback_entry (FALSE, FALSE); - int entry_num = entry ? entry->number : -1; - - RETURN (entry_num); -} - -char * playback_entry_get_filename (void) -{ - ENTER; - - Entry * entry = get_playback_entry (FALSE, FALSE); - char * filename = entry ? str_ref (entry->filename) : NULL; - - RETURN (filename); -} - -PluginHandle * playback_entry_get_decoder (void) -{ - ENTER; - - Entry * entry = get_playback_entry (TRUE, FALSE); - PluginHandle * decoder = entry ? entry->decoder : NULL; - - RETURN (decoder); -} - -Tuple * playback_entry_get_tuple (void) -{ - ENTER; - - Entry * entry = get_playback_entry (FALSE, TRUE); - Tuple * tuple = entry ? entry->tuple : NULL; - - if (tuple) - tuple_ref (tuple); - - RETURN (tuple); -} - -char * playback_entry_get_title (void) -{ - ENTER; - - Entry * entry = get_playback_entry (FALSE, TRUE); - char * title = entry ? str_ref (entry->formatted ? entry->formatted : entry->title) : NULL; - - RETURN (title); -} - -int playback_entry_get_length (void) -{ - ENTER; - - Entry * entry = get_playback_entry (FALSE, TRUE); - int length = entry ? entry->length : 0; - - RETURN (length); -} - -void playback_entry_set_tuple (Tuple * tuple) -{ - ENTER; - if (! playing_playlist || ! playing_playlist->position) - RETURN (); - - Entry * entry = playing_playlist->position; - entry_set_tuple (playing_playlist, entry, tuple); - - queue_update (PLAYLIST_UPDATE_METADATA, playing_playlist->number, entry->number, 1); - LEAVE; -} - -void playlist_save_state (void) -{ - /* get playback state before locking playlists */ - bool_t paused = drct_get_paused (); - int time = drct_get_time (); - - ENTER; - - const char * user_dir = get_path (AUD_PATH_USER_DIR); - SCONCAT2 (path, user_dir, "/" STATE_FILE); - - FILE * handle = g_fopen (path, "w"); - if (! handle) - RETURN (); - - fprintf (handle, "active %d\n", active_playlist ? active_playlist->number : -1); - fprintf (handle, "playing %d\n", playing_playlist ? playing_playlist->number : -1); - - for (int playlist_num = 0; playlist_num < index_count (playlists); - playlist_num ++) - { - Playlist * playlist = index_get (playlists, playlist_num); - - fprintf (handle, "playlist %d\n", playlist_num); - - if (playlist->filename) - fprintf (handle, "filename %s\n", playlist->filename); - - fprintf (handle, "position %d\n", playlist->position ? playlist->position->number : -1); - - if (playlist == playing_playlist) - { - playlist->resume_paused = paused; - playlist->resume_time = time; - } - - fprintf (handle, "resume-state %d\n", paused ? RESUME_PAUSE : RESUME_PLAY); - fprintf (handle, "resume-time %d\n", playlist->resume_time); - } - - fclose (handle); - LEAVE; -} - -static char parse_key[512]; -static char * parse_value; - -static void parse_next (FILE * handle) -{ - parse_value = NULL; - - if (! fgets (parse_key, sizeof parse_key, handle)) - return; - - char * space = strchr (parse_key, ' '); - if (! space) - return; - - * space = 0; - parse_value = space + 1; - - char * newline = strchr (parse_value, '\n'); - if (newline) - * newline = 0; -} - -static bool_t parse_integer (const char * key, int * value) -{ - return (parse_value && ! strcmp (parse_key, key) && sscanf (parse_value, "%d", value) == 1); -} - -static char * parse_string (const char * key) -{ - return (parse_value && ! strcmp (parse_key, key)) ? str_get (parse_value) : NULL; -} - -void playlist_load_state (void) -{ - ENTER; - int playlist_num; - - const char * user_dir = get_path (AUD_PATH_USER_DIR); - SCONCAT2 (path, user_dir, "/" STATE_FILE); - - FILE * handle = g_fopen (path, "r"); - if (! handle) - RETURN (); - - parse_next (handle); - - if (parse_integer ("active", & playlist_num)) - { - if (! (active_playlist = lookup_playlist (playlist_num))) - active_playlist = index_get (playlists, 0); - parse_next (handle); - } - - if (parse_integer ("playing", & resume_playlist)) - parse_next (handle); - - while (parse_integer ("playlist", & playlist_num) && playlist_num >= 0 && - playlist_num < index_count (playlists)) - { - Playlist * playlist = index_get (playlists, playlist_num); - int entries = index_count (playlist->entries); - - parse_next (handle); - - char * s; - if ((s = parse_string ("filename"))) - { - str_unref (playlist->filename); - playlist->filename = s; - parse_next (handle); - } - - int position = -1; - if (parse_integer ("position", & position)) - parse_next (handle); - - if (position >= 0 && position < entries) - set_position (playlist, index_get (playlist->entries, position), TRUE); - - int resume_state = RESUME_PLAY; - if (parse_integer ("resume-state", & resume_state)) - parse_next (handle); - - playlist->resume_paused = (resume_state == RESUME_PAUSE); - - if (parse_integer ("resume-time", & playlist->resume_time)) - parse_next (handle); - - /* compatibility with Audacious 3.3 */ - if (playlist_num == resume_playlist && resume_state == RESUME_STOP) - resume_playlist = -1; - } - - fclose (handle); - - /* clear updates queued during init sequence */ - - for (int i = 0; i < index_count (playlists); i ++) - { - Playlist * p = index_get (playlists, i); - memset (& p->last_update, 0, sizeof (Update)); - memset (& p->next_update, 0, sizeof (Update)); - } - - update_level = 0; - - if (update_source) - { - g_source_remove (update_source); - update_source = 0; - } - - LEAVE; -} - -void playlist_resume (void) -{ - playlist_set_playing (resume_playlist); -} diff --git a/src/audacious/playlist-utils.c b/src/audacious/playlist-utils.c deleted file mode 100644 index c51dfa2..0000000 --- a/src/audacious/playlist-utils.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * playlist-utils.c - * Copyright 2009-2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <glib.h> -#include <glib/gstdio.h> - -#include <libaudcore/audstrings.h> -#include <libaudcore/hook.h> - -#include "misc.h" -#include "playlist.h" - -static const char * get_basename (const char * filename) -{ - const char * slash = strrchr (filename, '/'); - - return (slash == NULL) ? filename : slash + 1; -} - -static int filename_compare_basename (const char * a, const char * b) -{ - return str_compare_encoded (get_basename (a), get_basename (b)); -} - -static int tuple_compare_string (const Tuple * a, const Tuple * b, int field) -{ - char * string_a = tuple_get_str (a, field); - char * string_b = tuple_get_str (b, field); - int ret; - - if (string_a == NULL) - ret = (string_b == NULL) ? 0 : -1; - else if (string_b == NULL) - ret = 1; - else - ret = str_compare (string_a, string_b); - - str_unref (string_a); - str_unref (string_b); - return ret; -} - -static int tuple_compare_int (const Tuple * a, const Tuple * b, int field) -{ - if (tuple_get_value_type (a, field) != TUPLE_INT) - return (tuple_get_value_type (b, field) != TUPLE_INT) ? 0 : -1; - if (tuple_get_value_type (b, field) != TUPLE_INT) - return 1; - - int int_a = tuple_get_int (a, field); - int int_b = tuple_get_int (b, field); - - return (int_a < int_b) ? -1 : (int_a > int_b); -} - -static int tuple_compare_title (const Tuple * a, const Tuple * b) -{ - return tuple_compare_string (a, b, FIELD_TITLE); -} - -static int tuple_compare_album (const Tuple * a, const Tuple * b) -{ - return tuple_compare_string (a, b, FIELD_ALBUM); -} - -static int tuple_compare_artist (const Tuple * a, const Tuple * b) -{ - return tuple_compare_string (a, b, FIELD_ARTIST); -} - -static int tuple_compare_date (const Tuple * a, const Tuple * b) -{ - return tuple_compare_int (a, b, FIELD_YEAR); -} - -static int tuple_compare_track (const Tuple * a, const Tuple * b) -{ - return tuple_compare_int (a, b, FIELD_TRACK_NUMBER); -} - -static int tuple_compare_length (const Tuple * a, const Tuple * b) -{ - return tuple_compare_int (a, b, FIELD_LENGTH); -} - -static const PlaylistStringCompareFunc filename_comparisons[] = { - [PLAYLIST_SORT_PATH] = str_compare_encoded, - [PLAYLIST_SORT_FILENAME] = filename_compare_basename, - [PLAYLIST_SORT_TITLE] = NULL, - [PLAYLIST_SORT_ALBUM] = NULL, - [PLAYLIST_SORT_ARTIST] = NULL, - [PLAYLIST_SORT_DATE] = NULL, - [PLAYLIST_SORT_TRACK] = NULL, - [PLAYLIST_SORT_FORMATTED_TITLE] = NULL, - [PLAYLIST_SORT_LENGTH] = NULL}; - -static const PlaylistTupleCompareFunc tuple_comparisons[] = { - [PLAYLIST_SORT_PATH] = NULL, - [PLAYLIST_SORT_FILENAME] = NULL, - [PLAYLIST_SORT_TITLE] = tuple_compare_title, - [PLAYLIST_SORT_ALBUM] = tuple_compare_album, - [PLAYLIST_SORT_ARTIST] = tuple_compare_artist, - [PLAYLIST_SORT_DATE] = tuple_compare_date, - [PLAYLIST_SORT_TRACK] = tuple_compare_track, - [PLAYLIST_SORT_FORMATTED_TITLE] = NULL, - [PLAYLIST_SORT_LENGTH] = tuple_compare_length}; - -static const PlaylistStringCompareFunc title_comparisons[] = { - [PLAYLIST_SORT_PATH] = NULL, - [PLAYLIST_SORT_FILENAME] = NULL, - [PLAYLIST_SORT_TITLE] = NULL, - [PLAYLIST_SORT_ALBUM] = NULL, - [PLAYLIST_SORT_ARTIST] = NULL, - [PLAYLIST_SORT_DATE] = NULL, - [PLAYLIST_SORT_TRACK] = NULL, - [PLAYLIST_SORT_FORMATTED_TITLE] = str_compare, - [PLAYLIST_SORT_LENGTH] = NULL}; - -void playlist_sort_by_scheme (int playlist, int scheme) -{ - if (filename_comparisons[scheme] != NULL) - playlist_sort_by_filename (playlist, filename_comparisons[scheme]); - else if (tuple_comparisons[scheme] != NULL) - playlist_sort_by_tuple (playlist, tuple_comparisons[scheme]); - else if (title_comparisons[scheme] != NULL) - playlist_sort_by_title (playlist, title_comparisons[scheme]); -} - -void playlist_sort_selected_by_scheme (int playlist, int scheme) -{ - if (filename_comparisons[scheme] != NULL) - playlist_sort_selected_by_filename (playlist, - filename_comparisons[scheme]); - else if (tuple_comparisons[scheme] != NULL) - playlist_sort_selected_by_tuple (playlist, tuple_comparisons[scheme]); - else if (title_comparisons[scheme] != NULL) - playlist_sort_selected_by_title (playlist, title_comparisons[scheme]); -} - -/* Fix me: This considers empty fields as duplicates. */ -void playlist_remove_duplicates_by_scheme (int playlist, int scheme) -{ - int entries = playlist_entry_count (playlist); - int count; - - if (entries < 1) - return; - - playlist_select_all (playlist, FALSE); - - if (filename_comparisons[scheme] != NULL) - { - int (* compare) (const char * a, const char * b) = - filename_comparisons[scheme]; - - playlist_sort_by_filename (playlist, compare); - char * last = playlist_entry_get_filename (playlist, 0); - - for (count = 1; count < entries; count ++) - { - char * current = playlist_entry_get_filename (playlist, count); - - if (compare (last, current) == 0) - playlist_entry_set_selected (playlist, count, TRUE); - - str_unref (last); - last = current; - } - - str_unref (last); - } - else if (tuple_comparisons[scheme] != NULL) - { - int (* compare) (const Tuple * a, const Tuple * b) = - tuple_comparisons[scheme]; - - playlist_sort_by_tuple (playlist, compare); - Tuple * last = playlist_entry_get_tuple (playlist, 0, FALSE); - - for (count = 1; count < entries; count ++) - { - Tuple * current = playlist_entry_get_tuple (playlist, count, FALSE); - - if (last != NULL && current != NULL && compare (last, current) == 0) - playlist_entry_set_selected (playlist, count, TRUE); - - if (last) - tuple_unref (last); - last = current; - } - - if (last) - tuple_unref (last); - } - - playlist_delete_selected (playlist); -} - -void playlist_remove_failed (int playlist) -{ - int entries = playlist_entry_count (playlist); - int count; - - playlist_select_all (playlist, FALSE); - - for (count = 0; count < entries; count ++) - { - char * filename = playlist_entry_get_filename (playlist, count); - - /* vfs_file_test() only works for file:// URIs currently */ - if (! strncmp (filename, "file://", 7) && ! vfs_file_test (filename, - G_FILE_TEST_EXISTS)) - playlist_entry_set_selected (playlist, count, TRUE); - - str_unref (filename); - } - - playlist_delete_selected (playlist); -} - -void playlist_select_by_patterns (int playlist, const Tuple * patterns) -{ - const int fields[] = {FIELD_TITLE, FIELD_ALBUM, FIELD_ARTIST, - FIELD_FILE_NAME}; - - int entries = playlist_entry_count (playlist); - int field, entry; - - playlist_select_all (playlist, TRUE); - - for (field = 0; field < ARRAY_LEN (fields); field ++) - { - char * pattern = tuple_get_str (patterns, fields[field]); - GRegex * regex; - - if (! pattern || ! pattern[0] || ! (regex = g_regex_new (pattern, - G_REGEX_CASELESS, 0, NULL))) - { - str_unref (pattern); - continue; - } - - for (entry = 0; entry < entries; entry ++) - { - if (! playlist_entry_get_selected (playlist, entry)) - continue; - - Tuple * tuple = playlist_entry_get_tuple (playlist, entry, FALSE); - char * string = tuple ? tuple_get_str (tuple, fields[field]) : NULL; - - if (! string || ! g_regex_match (regex, string, 0, NULL)) - playlist_entry_set_selected (playlist, entry, FALSE); - - str_unref (string); - if (tuple) - tuple_unref (tuple); - } - - g_regex_unref (regex); - str_unref (pattern); - } -} - -static char * make_playlist_path (int playlist) -{ - if (! playlist) - return filename_build (get_path (AUD_PATH_USER_DIR), "playlist.xspf"); - - SPRINTF (name, "playlist_%02d.xspf", 1 + playlist); - return filename_build (get_path (AUD_PATH_PLAYLISTS_DIR), name); -} - -static void load_playlists_real (void) -{ - const char * folder = get_path (AUD_PATH_PLAYLISTS_DIR); - - /* old (v3.1 and earlier) naming scheme */ - - int count; - for (count = 0; ; count ++) - { - char * path = make_playlist_path (count); - - if (! g_file_test (path, G_FILE_TEST_EXISTS)) - { - str_unref (path); - break; - } - - char * uri = filename_to_uri (path); - - playlist_insert (count); - playlist_insert_playlist_raw (count, 0, uri); - playlist_set_modified (count, TRUE); - - str_unref (path); - str_unref (uri); - } - - /* unique ID-based naming scheme */ - - char * order_path = filename_build (folder, "order"); - char * order_string; - g_file_get_contents (order_path, & order_string, NULL, NULL); - str_unref (order_path); - - if (! order_string) - goto DONE; - - Index * order = str_list_to_index (order_string, " "); - g_free (order_string); - - for (int i = 0; i < index_count (order); i ++) - { - char * number = index_get (order, i); - - SCONCAT2 (name, number, ".audpl"); - char * path = filename_build (folder, name); - - if (! g_file_test (path, G_FILE_TEST_EXISTS)) - { - str_unref (path); - - SCONCAT2 (name2, number, ".xspf"); - path = filename_build (folder, name2); - } - - char * uri = filename_to_uri (path); - - playlist_insert_with_id (count + i, atoi (number)); - playlist_insert_playlist_raw (count + i, 0, uri); - playlist_set_modified (count + i, FALSE); - - if (g_str_has_suffix (path, ".xspf")) - playlist_set_modified (count + i, TRUE); - - str_unref (path); - str_unref (uri); - } - - index_free_full (order, (IndexFreeFunc) str_unref); - -DONE: - if (! playlist_count ()) - playlist_insert (0); - - playlist_set_active (0); -} - -static void save_playlists_real (void) -{ - int lists = playlist_count (); - const char * folder = get_path (AUD_PATH_PLAYLISTS_DIR); - - /* save playlists */ - - Index * order = index_new (); - GHashTable * saved = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) str_unref, NULL); - - for (int i = 0; i < lists; i ++) - { - int id = playlist_get_unique_id (i); - char * number = int_to_str (id); - - SCONCAT2 (name, number, ".audpl"); - - if (playlist_get_modified (i)) - { - char * path = filename_build (folder, name); - char * uri = filename_to_uri (path); - - playlist_save (i, uri); - playlist_set_modified (i, FALSE); - - str_unref (path); - str_unref (uri); - } - - index_insert (order, -1, number); - g_hash_table_insert (saved, str_get (name), NULL); - } - - char * order_string = index_to_str_list (order, " "); - index_free_full (order, (IndexFreeFunc) str_unref); - - GError * error = NULL; - char * order_path = filename_build (folder, "order"); - - char * old_order_string; - g_file_get_contents (order_path, & old_order_string, NULL, NULL); - - if (! old_order_string || strcmp (old_order_string, order_string)) - { - if (! g_file_set_contents (order_path, order_string, -1, & error)) - { - fprintf (stderr, "Cannot write to %s: %s\n", order_path, error->message); - g_error_free (error); - } - } - - str_unref (order_string); - str_unref (order_path); - g_free (old_order_string); - - /* clean up deleted playlists and files from old naming scheme */ - - char * path = make_playlist_path (0); - g_unlink (path); - str_unref (path); - - GDir * dir = g_dir_open (folder, 0, NULL); - if (! dir) - goto DONE; - - const char * name; - while ((name = g_dir_read_name (dir))) - { - if (! g_str_has_suffix (name, ".audpl") && ! g_str_has_suffix (name, ".xspf")) - continue; - - if (! g_hash_table_contains (saved, name)) - { - char * path = filename_build (folder, name); - g_unlink (path); - str_unref (path); - } - } - - g_dir_close (dir); - -DONE: - g_hash_table_destroy (saved); -} - -static bool_t hooks_added, state_changed; - -static void update_cb (void * data, void * user) -{ - if (GPOINTER_TO_INT (data) < PLAYLIST_UPDATE_METADATA) - return; - - state_changed = TRUE; -} - -static void state_cb (void * data, void * user) -{ - state_changed = TRUE; -} - -void load_playlists (void) -{ - load_playlists_real (); - playlist_load_state (); - - state_changed = FALSE; - - if (! hooks_added) - { - hook_associate ("playlist update", update_cb, NULL); - hook_associate ("playlist activate", state_cb, NULL); - hook_associate ("playlist position", state_cb, NULL); - - hooks_added = TRUE; - } -} - -void save_playlists (bool_t exiting) -{ - save_playlists_real (); - - /* on exit, save resume states */ - if (state_changed || exiting) - { - playlist_save_state (); - state_changed = FALSE; - } - - if (exiting && hooks_added) - { - hook_dissociate ("playlist update", update_cb); - hook_dissociate ("playlist activate", state_cb); - hook_dissociate ("playlist position", state_cb); - - hooks_added = FALSE; - } -} diff --git a/src/audacious/playlist.h b/src/audacious/playlist.h deleted file mode 100644 index d457ea0..0000000 --- a/src/audacious/playlist.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * playlist.h - * Copyright 2010-2012 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_PLAYLIST_H -#define AUDACIOUS_PLAYLIST_H - -#include <stdint.h> - -#include <audacious/api.h> -#include <audacious/types.h> -#include <libaudcore/index.h> -#include <libaudcore/tuple.h> - -/* The values which can be passed (packed into a pointer) to the "playlist - * update" hook. PLAYLIST_UPDATE_SELECTION means that entries have been - * selected or unselected, or that entries have been added to or removed from - * the queue. PLAYLIST_UPDATE_METADATA means that new metadata has been read - * for some entries, or that the title or filename of a playlist has changed, - * and implies PLAYLIST_UPDATE_SELECTION. PLAYLIST_UPDATE_STRUCTURE covers any - * change not listed under the other types, and implies both - * PLAYLIST_UPDATE_SELECTION and PLAYLIST_UPDATE_METADATA. */ -enum { - PLAYLIST_UPDATE_SELECTION = 1, - PLAYLIST_UPDATE_METADATA, - PLAYLIST_UPDATE_STRUCTURE}; - -/* The values which can be passed to playlist_sort_by_scheme(), - * playlist_sort_selected_by_scheme(), and - * playlist_remove_duplicates_by_scheme(). PLAYLIST_SORT_PATH means the entire - * URI of a song file; PLAYLIST_SORT_FILENAME means the portion after the last - * "/" (forward slash). PLAYLIST_SORT_DATE means the song's release date (not - * the file's modification time). */ -enum { - PLAYLIST_SORT_PATH, - PLAYLIST_SORT_FILENAME, - PLAYLIST_SORT_TITLE, - PLAYLIST_SORT_ALBUM, - PLAYLIST_SORT_ARTIST, - PLAYLIST_SORT_DATE, - PLAYLIST_SORT_TRACK, - PLAYLIST_SORT_FORMATTED_TITLE, - PLAYLIST_SORT_LENGTH, - PLAYLIST_SORT_SCHEMES}; - -typedef bool_t (* PlaylistFilterFunc) (const char * filename, void * user); -typedef int (* PlaylistStringCompareFunc) (const char * a, const char * b); -typedef int (* PlaylistTupleCompareFunc) (const Tuple * a, const Tuple * b); - -#define AUD_API_NAME PlaylistAPI -#define AUD_API_SYMBOL playlist_api - -#ifdef _AUDACIOUS_CORE - -#include "api-local-begin.h" -#include "playlist-api.h" -#include "api-local-end.h" - -/* playlist-files.c */ -bool_t playlist_load (const char * filename, char * * title, - Index * * filenames, Index * * tuples); -bool_t playlist_insert_playlist_raw (int list, int at, - const char * filename); - -/* playlist-new.c */ -void playlist_init (void); -void playlist_end (void); - -void playlist_insert_with_id (int at, int id); -void playlist_set_modified (int playlist, bool_t modified); -bool_t playlist_get_modified (int playlist); - -void playlist_load_state (void); -void playlist_save_state (void); -void playlist_resume (void); - -void playlist_reformat_titles (void); -void playlist_trigger_scan (void); - -void playlist_entry_insert_batch_raw (int playlist, int at, - Index * filenames, Index * tuples, Index * decoders); - -bool_t playlist_prev_song (int playlist); -bool_t playlist_next_song (int playlist, bool_t repeat); - -int playback_entry_get_position (void); -char * playback_entry_get_filename (void); -PluginHandle * playback_entry_get_decoder (void); -Tuple * playback_entry_get_tuple (void); -char * playback_entry_get_title (void); -int playback_entry_get_length (void); - -void playback_entry_set_tuple (Tuple * tuple); - -/* playlist-utils.c */ -void load_playlists (void); -void save_playlists (bool_t exiting); - -#else - -#include <audacious/api-define-begin.h> -#include <audacious/playlist-api.h> -#include <audacious/api-define-end.h> - -#include <audacious/api-alias-begin.h> -#include <audacious/playlist-api.h> -#include <audacious/api-alias-end.h> - -#endif - -#undef AUD_API_NAME -#undef AUD_API_SYMBOL - -#endif - -#ifdef AUD_API_DECLARE - -#define AUD_API_NAME PlaylistAPI -#define AUD_API_SYMBOL playlist_api - -#include "api-define-begin.h" -#include "playlist-api.h" -#include "api-define-end.h" - -#include "api-declare-begin.h" -#include "playlist-api.h" -#include "api-declare-end.h" - -#undef AUD_API_NAME -#undef AUD_API_SYMBOL - -#endif diff --git a/src/audacious/plugin-init.c b/src/audacious/plugin-init.c deleted file mode 100644 index b7690e3..0000000 --- a/src/audacious/plugin-init.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * plugin-init.c - * Copyright 2010-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> - -#include <glib.h> - -#include "debug.h" -#include "effect.h" -#include "general.h" -#include "interface.h" -#include "misc.h" -#include "output.h" -#include "plugin.h" -#include "plugins.h" -#include "ui_preferences.h" -#include "visualization.h" - -static const struct { - const char * name; - bool_t is_single; - - union { - struct { - bool_t (* start) (PluginHandle * plugin); - void (* stop) (PluginHandle * plugin); - } m; - - struct { - PluginHandle * (* probe) (void); - PluginHandle * (* get_current) (void); - bool_t (* set_current) (PluginHandle * plugin); - } s; - } u; -} table[PLUGIN_TYPES] = { - [PLUGIN_TYPE_TRANSPORT] = {"transport", FALSE, .u.m = {NULL, NULL}}, - [PLUGIN_TYPE_PLAYLIST] = {"playlist", FALSE, .u.m = {NULL, NULL}}, - [PLUGIN_TYPE_INPUT] = {"input", FALSE, .u.m = {NULL, NULL}}, - [PLUGIN_TYPE_EFFECT] = {"effect", FALSE, .u.m = {effect_plugin_start, effect_plugin_stop}}, - [PLUGIN_TYPE_OUTPUT] = {"output", TRUE, .u.s = {output_plugin_probe, - output_plugin_get_current, output_plugin_set_current}}, - [PLUGIN_TYPE_VIS] = {"visualization", FALSE, .u.m = {vis_plugin_start, vis_plugin_stop}}, - [PLUGIN_TYPE_GENERAL] = {"general", FALSE, .u.m = {general_plugin_start, general_plugin_stop}}, - [PLUGIN_TYPE_IFACE] = {"interface", TRUE, .u.s = {iface_plugin_probe, - iface_plugin_get_current, iface_plugin_set_current}}}; - -static bool_t find_enabled_cb (PluginHandle * p, void * pp) -{ - * (PluginHandle * *) pp = p; - return FALSE; -} - -static PluginHandle * find_enabled (int type) -{ - PluginHandle * p = NULL; - plugin_for_enabled (type, find_enabled_cb, & p); - return p; -} - -static void start_single (int type) -{ - PluginHandle * p; - - if ((p = find_enabled (type)) != NULL) - { - AUDDBG ("Starting selected %s plugin %s.\n", table[type].name, - plugin_get_name (p)); - - if (table[type].u.s.set_current (p)) - return; - - AUDDBG ("%s failed to start.\n", plugin_get_name (p)); - plugin_set_enabled (p, FALSE); - } - - AUDDBG ("Probing for %s plugin.\n", table[type].name); - - if ((p = table[type].u.s.probe ()) == NULL) - { - fprintf (stderr, "FATAL: No %s plugin found.\n" - "(Did you forget to install audacious-plugins?)\n", table[type].name); - abort (); - } - - AUDDBG ("Starting %s.\n", plugin_get_name (p)); - plugin_set_enabled (p, TRUE); - - if (! table[type].u.s.set_current (p)) - { - fprintf (stderr, "FATAL: %s failed to start.\n", plugin_get_name (p)); - abort (); - } -} - -static bool_t start_multi_cb (PluginHandle * p, void * type) -{ - AUDDBG ("Starting %s.\n", plugin_get_name (p)); - - if (! table[GPOINTER_TO_INT (type)].u.m.start (p)) - { - AUDDBG ("%s failed to start; disabling.\n", plugin_get_name (p)); - plugin_set_enabled (p, FALSE); - } - - return TRUE; -} - -static void start_plugins (int type) -{ - if (type == PLUGIN_TYPE_IFACE && headless_mode ()) - return; - - if (table[type].is_single) - start_single (type); - else - { - if (table[type].u.m.start) - plugin_for_enabled (type, start_multi_cb, GINT_TO_POINTER (type)); - } -} - -static VFSConstructor * lookup_transport (const char * scheme) -{ - PluginHandle * plugin = transport_plugin_for_scheme (scheme); - if (! plugin) - return NULL; - - TransportPlugin * tp = plugin_get_header (plugin); - return tp ? tp->vtable : NULL; -} - -void start_plugins_one (void) -{ - plugin_system_init (); - vfs_set_lookup_func (lookup_transport); - - for (int i = 0; i < PLUGIN_TYPE_GENERAL; i ++) - start_plugins (i); -} - -void start_plugins_two (void) -{ - for (int i = PLUGIN_TYPE_GENERAL; i < PLUGIN_TYPES; i ++) - start_plugins (i); -} - -static bool_t misc_cleanup_cb (PluginHandle * p, void * unused) -{ - plugin_misc_cleanup (p); - return TRUE; -} - -static bool_t stop_multi_cb (PluginHandle * p, void * type) -{ - AUDDBG ("Shutting down %s.\n", plugin_get_name (p)); - table[GPOINTER_TO_INT (type)].u.m.stop (p); - return TRUE; -} - -static void stop_plugins (int type) -{ - if (type == PLUGIN_TYPE_IFACE && headless_mode ()) - return; - - plugin_for_enabled (type, misc_cleanup_cb, GINT_TO_POINTER (type)); - - if (table[type].is_single) - { - AUDDBG ("Shutting down %s.\n", plugin_get_name - (table[type].u.s.get_current ())); - table[type].u.s.set_current (NULL); - } - else - { - if (table[type].u.m.stop) - plugin_for_enabled (type, stop_multi_cb, GINT_TO_POINTER (type)); - } -} - -void stop_plugins_two (void) -{ - for (int i = PLUGIN_TYPES - 1; i >= PLUGIN_TYPE_GENERAL; i --) - stop_plugins (i); -} - -void stop_plugins_one (void) -{ - for (int i = PLUGIN_TYPE_GENERAL - 1; i >= 0; i --) - stop_plugins (i); - - vfs_set_lookup_func (NULL); - plugin_system_cleanup (); -} - -PluginHandle * plugin_get_current (int type) -{ - g_return_val_if_fail (table[type].is_single, NULL); - return table[type].u.s.get_current (); -} - -static bool_t enable_single (int type, PluginHandle * p) -{ - PluginHandle * old = table[type].u.s.get_current (); - - plugin_misc_cleanup (old); - - AUDDBG ("Switching from %s to %s.\n", plugin_get_name (old), - plugin_get_name (p)); - plugin_set_enabled (old, FALSE); - plugin_set_enabled (p, TRUE); - - if (table[type].u.s.set_current (p)) - return TRUE; - - fprintf (stderr, "%s failed to start; falling back to %s.\n", - plugin_get_name (p), plugin_get_name (old)); - plugin_set_enabled (p, FALSE); - plugin_set_enabled (old, TRUE); - - if (table[type].u.s.set_current (old)) - return FALSE; - - fprintf (stderr, "FATAL: %s failed to start.\n", plugin_get_name (old)); - abort (); -} - -static bool_t enable_multi (int type, PluginHandle * p, bool_t enable) -{ - if (! enable) - plugin_misc_cleanup (p); - - AUDDBG ("%sabling %s.\n", enable ? "En" : "Dis", plugin_get_name (p)); - plugin_set_enabled (p, enable); - - if (enable) - { - if (table[type].u.m.start && ! table[type].u.m.start (p)) - { - fprintf (stderr, "%s failed to start.\n", plugin_get_name (p)); - plugin_set_enabled (p, FALSE); - return FALSE; - } - } - else - { - if (table[type].u.m.stop) - table[type].u.m.stop (p); - } - - return TRUE; -} - -bool_t plugin_enable (PluginHandle * plugin, bool_t enable) -{ - if (! enable == ! plugin_get_enabled (plugin)) - return TRUE; - - int type = plugin_get_type (plugin); - - if (table[type].is_single) - { - g_return_val_if_fail (enable, FALSE); - return enable_single (type, plugin); - } - - return enable_multi (type, plugin, enable); -} - -/* Miscellaneous plugin-related functions ... */ - -PluginHandle * plugin_by_widget (/* GtkWidget * */ void * widget) -{ - PluginHandle * p; - if ((p = vis_plugin_by_widget (widget))) - return p; - if ((p = general_plugin_by_widget (widget))) - return p; - return NULL; -} - -int plugin_send_message (PluginHandle * plugin, const char * code, const void * data, int size) -{ - if (! plugin_get_enabled (plugin)) - return ENOSYS; - - Plugin * header = plugin_get_header (plugin); - if (! header || ! PLUGIN_HAS_FUNC (header, take_message)) - return ENOSYS; - - return header->take_message (code, data, size); -} - -void plugin_do_about (PluginHandle * plugin) -{ - g_return_if_fail (plugin_get_enabled (plugin)); - Plugin * header = plugin_get_header (plugin); - g_return_if_fail (header); - - if (PLUGIN_HAS_FUNC (header, about)) - header->about (); - else if (PLUGIN_HAS_FUNC (header, about_text)) - plugin_make_about_window (plugin); -} - -void plugin_do_configure (PluginHandle * plugin) -{ - g_return_if_fail (plugin_get_enabled (plugin)); - Plugin * header = plugin_get_header (plugin); - g_return_if_fail (header); - - if (PLUGIN_HAS_FUNC (header, configure)) - header->configure (); - else if (PLUGIN_HAS_FUNC (header, prefs)) - plugin_make_config_window (plugin); -} diff --git a/src/audacious/plugin-preferences.c b/src/audacious/plugin-preferences.c deleted file mode 100644 index 8a0bf81..0000000 --- a/src/audacious/plugin-preferences.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * plugin-preferences.c - * Copyright 2012-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <libaudcore/audstrings.h> -#include <libaudgui/libaudgui-gtk.h> - -#include "i18n.h" -#include "misc.h" -#include "plugin.h" -#include "plugins.h" -#include "preferences.h" -#include "ui_preferences.h" - -typedef struct { - GtkWidget * about_window; - GtkWidget * config_window; -} PluginMiscData; - -void plugin_make_about_window (PluginHandle * plugin) -{ - PluginMiscData * misc = plugin_get_misc_data (plugin, sizeof (PluginMiscData)); - Plugin * header = plugin_get_header (plugin); - - if (misc->about_window) - { - gtk_window_present ((GtkWindow *) misc->about_window); - return; - } - - const char * name = header->name; - const char * text = header->about_text; - - if (PLUGIN_HAS_FUNC (header, domain)) - { - name = dgettext (header->domain, name); - text = dgettext (header->domain, text); - } - - SCONCAT3 (title, _("About"), " ", name); - audgui_simple_message (& misc->about_window, GTK_MESSAGE_INFO, title, text); -} - -static void response_cb (GtkWidget * window, int response, const PluginPreferences * p) -{ - if (response == GTK_RESPONSE_OK && p->apply) - p->apply (); - - gtk_widget_destroy (window); -} - -static void destroy_cb (GtkWidget * window, const PluginPreferences * p) -{ - if (p->cleanup) - p->cleanup (); -} - -void plugin_make_config_window (PluginHandle * plugin) -{ - PluginMiscData * misc = plugin_get_misc_data (plugin, sizeof (PluginMiscData)); - Plugin * header = plugin_get_header (plugin); - const PluginPreferences * p = header->prefs; - - if (misc->config_window) - { - gtk_window_present ((GtkWindow *) misc->config_window); - return; - } - - if (p->init) - p->init (); - - const char * name = header->name; - if (PLUGIN_HAS_FUNC (header, domain)) - name = dgettext (header->domain, header->name); - - GtkWidget * window = gtk_dialog_new (); - - SCONCAT3 (title, name, " ", _("Settings")); - gtk_window_set_title ((GtkWindow *) window, title); - - if (p->apply) - { - GtkWidget * button1 = audgui_button_new (_("_Set"), "system-run", NULL, NULL); - GtkWidget * button2 = audgui_button_new (_("_Cancel"), "process-stop", NULL, NULL); - gtk_dialog_add_action_widget ((GtkDialog *) window, button2, GTK_RESPONSE_CANCEL); - gtk_dialog_add_action_widget ((GtkDialog *) window, button1, GTK_RESPONSE_OK); - } - else - { - GtkWidget * button = audgui_button_new (_("_Close"), "window-close", NULL, NULL); - gtk_dialog_add_action_widget ((GtkDialog *) window, button, GTK_RESPONSE_CLOSE); - } - - GtkWidget * content = gtk_dialog_get_content_area ((GtkDialog *) window); - GtkWidget * box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - create_widgets_with_domain (box, p->widgets, p->n_widgets, header->domain); - gtk_box_pack_start ((GtkBox *) content, box, TRUE, TRUE, 0); - - g_signal_connect (window, "response", (GCallback) response_cb, (void *) p); - g_signal_connect (window, "destroy", (GCallback) destroy_cb, (void *) p); - - misc->config_window = window; - g_signal_connect (window, "destroy", (GCallback) gtk_widget_destroyed, & misc->config_window); - - gtk_widget_show_all (window); -} - -void plugin_misc_cleanup (PluginHandle * plugin) -{ - PluginMiscData * misc = plugin_get_misc_data (plugin, sizeof (PluginMiscData)); - - if (misc->about_window) - gtk_widget_destroy (misc->about_window); - if (misc->config_window) - gtk_widget_destroy (misc->config_window); -} diff --git a/src/audacious/plugin-registry.c b/src/audacious/plugin-registry.c deleted file mode 100644 index bc0d441..0000000 --- a/src/audacious/plugin-registry.c +++ /dev/null @@ -1,871 +0,0 @@ -/* - * plugin-registry.c - * Copyright 2009-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -/* While the registry is being built (during early startup) or destroyed (during - * late shutdown), the registry_locked flag will be set. Once this flag is - * cleared, the registry will not be modified and can be read by concurrent - * threads. The one change that can happen during this time is that a plugin is - * loaded; hence the mutex must be locked before checking that a plugin is - * loaded and while loading it. */ - -#include <pthread.h> -#include <stdio.h> -#include <string.h> - -#include <glib.h> -#include <glib/gstdio.h> - -#include <libaudcore/audstrings.h> - -#include "debug.h" -#include "i18n.h" -#include "interface.h" -#include "misc.h" -#include "plugin.h" -#include "plugins.h" - -#define FILENAME "plugin-registry" -#define FORMAT 8 - -typedef struct { - GList * schemes; -} TransportPluginData; - -typedef struct { - GList * exts; -} PlaylistPluginData; - -typedef struct { - GList * keys[INPUT_KEYS]; - bool_t has_images, has_subtunes, can_write_tuple, has_infowin; -} InputPluginData; - -struct PluginHandle { - char * path; - bool_t confirmed, loaded; - int timestamp, type; - Plugin * header; - char * name, * domain; - int priority; - bool_t has_about, has_configure, enabled; - GList * watches; - void * misc; - - union { - TransportPluginData t; - PlaylistPluginData p; - InputPluginData i; - } u; -}; - -typedef struct { - PluginForEachFunc func; - void * data; -} PluginWatch; - -static const char * plugin_type_names[] = { - [PLUGIN_TYPE_TRANSPORT] = "transport", - [PLUGIN_TYPE_PLAYLIST] = "playlist", - [PLUGIN_TYPE_INPUT] = "input", - [PLUGIN_TYPE_EFFECT] = "effect", - [PLUGIN_TYPE_OUTPUT] = "output", - [PLUGIN_TYPE_VIS] = "vis", - [PLUGIN_TYPE_GENERAL] = "general", - [PLUGIN_TYPE_IFACE] = "iface"}; - -static const char * input_key_names[] = { - [INPUT_KEY_SCHEME] = "scheme", - [INPUT_KEY_EXTENSION] = "ext", - [INPUT_KEY_MIME] = "mime"}; - -static GList * plugin_list = NULL; -static bool_t registry_locked = TRUE; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - -static PluginHandle * plugin_new (char * path, bool_t confirmed, bool_t - loaded, int timestamp, int type, Plugin * header) -{ - PluginHandle * plugin = g_slice_new (PluginHandle); - - plugin->path = path; - plugin->confirmed = confirmed; - plugin->loaded = loaded; - plugin->timestamp = timestamp; - plugin->type = type; - plugin->header = header; - plugin->name = NULL; - plugin->domain = NULL; - plugin->priority = 0; - plugin->has_about = FALSE; - plugin->has_configure = FALSE; - plugin->enabled = FALSE; - plugin->watches = NULL; - plugin->misc = NULL; - - if (type == PLUGIN_TYPE_TRANSPORT) - { - plugin->enabled = TRUE; - plugin->u.t.schemes = NULL; - } - else if (type == PLUGIN_TYPE_PLAYLIST) - { - plugin->enabled = TRUE; - plugin->u.p.exts = NULL; - } - else if (type == PLUGIN_TYPE_INPUT) - { - plugin->enabled = TRUE; - memset (plugin->u.i.keys, 0, sizeof plugin->u.i.keys); - plugin->u.i.has_images = FALSE; - plugin->u.i.has_subtunes = FALSE; - plugin->u.i.can_write_tuple = FALSE; - plugin->u.i.has_infowin = FALSE; - } - - plugin_list = g_list_prepend (plugin_list, plugin); - return plugin; -} - -static void plugin_free (PluginHandle * plugin) -{ - plugin_list = g_list_remove (plugin_list, plugin); - - for (GList * node = plugin->watches; node; node = node->next) - g_slice_free (PluginWatch, node->data); - - if (plugin->type == PLUGIN_TYPE_TRANSPORT) - g_list_free_full (plugin->u.t.schemes, (GDestroyNotify) str_unref); - else if (plugin->type == PLUGIN_TYPE_PLAYLIST) - g_list_free_full (plugin->u.p.exts, (GDestroyNotify) str_unref); - else if (plugin->type == PLUGIN_TYPE_INPUT) - { - for (int key = 0; key < INPUT_KEYS; key ++) - g_list_free_full (plugin->u.i.keys[key], (GDestroyNotify) str_unref); - } - - str_unref (plugin->path); - str_unref (plugin->name); - str_unref (plugin->domain); - g_free (plugin->misc); - g_slice_free (PluginHandle, plugin); -} - -static FILE * open_registry_file (const char * mode) -{ - const char * user_dir = get_path (AUD_PATH_USER_DIR); - SCONCAT2 (path, user_dir, "/" FILENAME); - return g_fopen (path, mode); -} - -static void transport_plugin_save (PluginHandle * plugin, FILE * handle) -{ - for (GList * node = plugin->u.t.schemes; node; node = node->next) - fprintf (handle, "scheme %s\n", (const char *) node->data); -} - -static void playlist_plugin_save (PluginHandle * plugin, FILE * handle) -{ - for (GList * node = plugin->u.p.exts; node; node = node->next) - fprintf (handle, "ext %s\n", (const char *) node->data); -} - -static void input_plugin_save (PluginHandle * plugin, FILE * handle) -{ - for (int key = 0; key < INPUT_KEYS; key ++) - { - for (GList * node = plugin->u.i.keys[key]; node; node = node->next) - fprintf (handle, "%s %s\n", input_key_names[key], (const char *) - node->data); - } - - fprintf (handle, "images %d\n", plugin->u.i.has_images); - fprintf (handle, "subtunes %d\n", plugin->u.i.has_subtunes); - fprintf (handle, "writes %d\n", plugin->u.i.can_write_tuple); - fprintf (handle, "infowin %d\n", plugin->u.i.has_infowin); -} - -static void plugin_save (PluginHandle * plugin, FILE * handle) -{ - fprintf (handle, "%s %s\n", plugin_type_names[plugin->type], plugin->path); - fprintf (handle, "stamp %d\n", plugin->timestamp); - fprintf (handle, "name %s\n", plugin->name); - - if (plugin->domain) - fprintf (handle, "domain %s\n", plugin->domain); - - fprintf (handle, "priority %d\n", plugin->priority); - fprintf (handle, "about %d\n", plugin->has_about); - fprintf (handle, "config %d\n", plugin->has_configure); - fprintf (handle, "enabled %d\n", plugin->enabled); - - if (plugin->type == PLUGIN_TYPE_TRANSPORT) - transport_plugin_save (plugin, handle); - else if (plugin->type == PLUGIN_TYPE_PLAYLIST) - playlist_plugin_save (plugin, handle); - else if (plugin->type == PLUGIN_TYPE_INPUT) - input_plugin_save (plugin, handle); -} - -void plugin_registry_save (void) -{ - FILE * handle = open_registry_file ("w"); - g_return_if_fail (handle); - - fprintf (handle, "format %d\n", FORMAT); - - g_list_foreach (plugin_list, (GFunc) plugin_save, handle); - fclose (handle); - - g_list_foreach (plugin_list, (GFunc) plugin_free, NULL); - registry_locked = TRUE; -} - -static char parse_key[512]; -static char * parse_value; - -static void parse_next (FILE * handle) -{ - parse_value = NULL; - - if (! fgets (parse_key, sizeof parse_key, handle)) - return; - - char * space = strchr (parse_key, ' '); - if (! space) - return; - - * space = 0; - parse_value = space + 1; - - char * newline = strchr (parse_value, '\n'); - if (newline) - * newline = 0; -} - -static bool_t parse_integer (const char * key, int * value) -{ - return (parse_value && ! strcmp (parse_key, key) && sscanf (parse_value, - "%d", value) == 1); -} - -static char * parse_string (const char * key) -{ - return (parse_value && ! strcmp (parse_key, key)) ? str_get (parse_value) : NULL; -} - -static void transport_plugin_parse (PluginHandle * plugin, FILE * handle) -{ - char * value; - while ((value = parse_string ("scheme"))) - { - plugin->u.t.schemes = g_list_prepend (plugin->u.t.schemes, value); - parse_next (handle); - } -} - -static void playlist_plugin_parse (PluginHandle * plugin, FILE * handle) -{ - char * value; - while ((value = parse_string ("ext"))) - { - plugin->u.p.exts = g_list_prepend (plugin->u.p.exts, value); - parse_next (handle); - } -} - -static void input_plugin_parse (PluginHandle * plugin, FILE * handle) -{ - for (int key = 0; key < INPUT_KEYS; key ++) - { - char * value; - while ((value = parse_string (input_key_names[key]))) - { - plugin->u.i.keys[key] = g_list_prepend (plugin->u.i.keys[key], - value); - parse_next (handle); - } - } - - if (parse_integer ("images", & plugin->u.i.has_images)) - parse_next (handle); - if (parse_integer ("subtunes", & plugin->u.i.has_subtunes)) - parse_next (handle); - if (parse_integer ("writes", & plugin->u.i.can_write_tuple)) - parse_next (handle); - if (parse_integer ("infowin", & plugin->u.i.has_infowin)) - parse_next (handle); -} - -static bool_t plugin_parse (FILE * handle) -{ - char * path = NULL; - - int type; - for (type = 0; type < PLUGIN_TYPES; type ++) - { - if ((path = parse_string (plugin_type_names[type]))) - goto FOUND; - } - - return FALSE; - -FOUND: - parse_next (handle); - - int timestamp; - if (! parse_integer ("stamp", & timestamp)) - { - str_unref (path); - return FALSE; - } - - PluginHandle * plugin = plugin_new (path, FALSE, FALSE, timestamp, type, - NULL); - parse_next (handle); - - if ((plugin->name = parse_string ("name"))) - parse_next (handle); - if ((plugin->domain = parse_string ("domain"))) - parse_next (handle); - if (parse_integer ("priority", & plugin->priority)) - parse_next (handle); - if (parse_integer ("about", & plugin->has_about)) - parse_next (handle); - if (parse_integer ("config", & plugin->has_configure)) - parse_next (handle); - if (parse_integer ("enabled", & plugin->enabled)) - parse_next (handle); - - if (type == PLUGIN_TYPE_TRANSPORT) - transport_plugin_parse (plugin, handle); - else if (type == PLUGIN_TYPE_PLAYLIST) - playlist_plugin_parse (plugin, handle); - else if (type == PLUGIN_TYPE_INPUT) - input_plugin_parse (plugin, handle); - - return TRUE; -} - -void plugin_registry_load (void) -{ - FILE * handle = open_registry_file ("r"); - if (! handle) - goto UNLOCK; - - parse_next (handle); - - int format; - if (! parse_integer ("format", & format) || format != FORMAT) - goto ERR; - - parse_next (handle); - - while (plugin_parse (handle)) - ; - -ERR: - fclose (handle); -UNLOCK: - registry_locked = FALSE; -} - -static void plugin_prune (PluginHandle * plugin) -{ - if (plugin->confirmed) - return; - - AUDDBG ("Plugin not found: %s\n", plugin->path); - plugin_free (plugin); -} - -int plugin_compare (PluginHandle * a, PluginHandle * b) -{ - if (a->type < b->type) - return -1; - if (a->type > b->type) - return 1; - if (a->priority < b->priority) - return -1; - if (a->priority > b->priority) - return 1; - - int diff; - if ((diff = str_compare (dgettext (a->domain, a->name), dgettext (b->domain, b->name)))) - return diff; - - return str_compare (a->path, b->path); -} - -void plugin_registry_prune (void) -{ - g_list_foreach (plugin_list, (GFunc) plugin_prune, NULL); - plugin_list = g_list_sort (plugin_list, (GCompareFunc) plugin_compare); - registry_locked = TRUE; -} - -static int plugin_lookup_cb (PluginHandle * plugin, const char * path) -{ - return strcmp (plugin->path, path); -} - -PluginHandle * plugin_lookup (const char * path) -{ - GList * node = g_list_find_custom (plugin_list, path, (GCompareFunc) - plugin_lookup_cb); - return node ? node->data : NULL; -} - -static int plugin_lookup_basename_cb (PluginHandle * plugin, const char * basename) -{ - const char * slash = strrchr (plugin->path, G_DIR_SEPARATOR); - if (! slash) - return TRUE; - - const char * dot = strrchr (slash + 1, '.'); - if (! dot) - return TRUE; - - return strncmp (slash + 1, basename, dot - (slash + 1)); -} - -/* Note: If there are multiple plugins with the same basename, this returns only - * one of them. So give different plugins different basenames. --jlindgren */ -PluginHandle * plugin_lookup_basename (const char * basename) -{ - GList * node = g_list_find_custom (plugin_list, basename, (GCompareFunc) - plugin_lookup_basename_cb); - return node ? node->data : NULL; -} - -static void plugin_get_info (PluginHandle * plugin, bool_t new) -{ - Plugin * header = plugin->header; - - str_unref (plugin->name); - str_unref (plugin->domain); - plugin->name = str_get (header->name); - plugin->domain = PLUGIN_HAS_FUNC (header, domain) ? str_get (header->domain) : NULL; - plugin->has_about = PLUGIN_HAS_FUNC (header, about) || PLUGIN_HAS_FUNC (header, about_text); - plugin->has_configure = PLUGIN_HAS_FUNC (header, configure) || PLUGIN_HAS_FUNC (header, prefs); - - if (header->type == PLUGIN_TYPE_TRANSPORT) - { - TransportPlugin * tp = (TransportPlugin *) header; - - g_list_free_full (plugin->u.t.schemes, (GDestroyNotify) str_unref); - plugin->u.t.schemes = NULL; - - for (int i = 0; tp->schemes[i]; i ++) - plugin->u.t.schemes = g_list_prepend (plugin->u.t.schemes, str_get (tp->schemes[i])); - } - else if (header->type == PLUGIN_TYPE_PLAYLIST) - { - PlaylistPlugin * pp = (PlaylistPlugin *) header; - - g_list_free_full (plugin->u.p.exts, (GDestroyNotify) str_unref); - plugin->u.p.exts = NULL; - - for (int i = 0; pp->extensions[i]; i ++) - plugin->u.p.exts = g_list_prepend (plugin->u.p.exts, str_get (pp->extensions[i])); - } - else if (header->type == PLUGIN_TYPE_INPUT) - { - InputPlugin * ip = (InputPlugin *) header; - plugin->priority = ip->priority; - - for (int key = 0; key < INPUT_KEYS; key ++) - { - g_list_free_full (plugin->u.i.keys[key], (GDestroyNotify) str_unref); - plugin->u.i.keys[key] = NULL; - } - - if (PLUGIN_HAS_FUNC (ip, extensions)) - { - for (int i = 0; ip->extensions[i]; i ++) - plugin->u.i.keys[INPUT_KEY_EXTENSION] = g_list_prepend - (plugin->u.i.keys[INPUT_KEY_EXTENSION], - str_get (ip->extensions[i])); - } - - if (PLUGIN_HAS_FUNC (ip, mimes)) - { - for (int i = 0; ip->mimes[i]; i ++) - plugin->u.i.keys[INPUT_KEY_MIME] = g_list_prepend - (plugin->u.i.keys[INPUT_KEY_MIME], str_get (ip->mimes[i])); - } - - if (PLUGIN_HAS_FUNC (ip, schemes)) - { - for (int i = 0; ip->schemes[i]; i ++) - plugin->u.i.keys[INPUT_KEY_SCHEME] = g_list_prepend - (plugin->u.i.keys[INPUT_KEY_SCHEME], str_get (ip->schemes[i])); - } - - plugin->u.i.has_images = PLUGIN_HAS_FUNC (ip, get_song_image); - plugin->u.i.has_subtunes = ip->have_subtune; - plugin->u.i.can_write_tuple = PLUGIN_HAS_FUNC (ip, update_song_tuple); - plugin->u.i.has_infowin = PLUGIN_HAS_FUNC (ip, file_info_box); - } - else if (header->type == PLUGIN_TYPE_OUTPUT) - { - OutputPlugin * op = (OutputPlugin *) header; - plugin->priority = 10 - op->probe_priority; - } - else if (header->type == PLUGIN_TYPE_EFFECT) - { - EffectPlugin * ep = (EffectPlugin *) header; - plugin->priority = ep->order; - } - else if (header->type == PLUGIN_TYPE_GENERAL) - { - GeneralPlugin * gp = (GeneralPlugin *) header; - if (new) - plugin->enabled = gp->enabled_by_default; - } -} - -void plugin_register (const char * path, int timestamp) -{ - PluginHandle * plugin = plugin_lookup (path); - - if (plugin) - { - AUDDBG ("Register plugin: %s\n", path); - plugin->confirmed = TRUE; - - if (plugin->timestamp != timestamp) - { - AUDDBG ("Rescan plugin: %s\n", path); - Plugin * header = plugin_load (path); - if (! header || header->type != plugin->type) - return; - - plugin->loaded = TRUE; - plugin->header = header; - plugin->timestamp = timestamp; - - plugin_get_info (plugin, FALSE); - } - } - else - { - AUDDBG ("New plugin: %s\n", path); - Plugin * header = plugin_load (path); - if (! header) - return; - - plugin = plugin_new (str_get (path), TRUE, TRUE, timestamp, - header->type, header); - - plugin_get_info (plugin, TRUE); - } -} - -int plugin_get_type (PluginHandle * plugin) -{ - return plugin->type; -} - -const char * plugin_get_filename (PluginHandle * plugin) -{ - return plugin->path; -} - -const void * plugin_get_header (PluginHandle * plugin) -{ - pthread_mutex_lock (& mutex); - - if (! plugin->loaded) - { - Plugin * header = plugin_load (plugin->path); - if (! header || header->type != plugin->type) - goto DONE; - - plugin->loaded = TRUE; - plugin->header = header; - } - -DONE: - pthread_mutex_unlock (& mutex); - return plugin->header; -} - -static int plugin_by_header_cb (PluginHandle * plugin, const void * header) -{ - return (plugin->header == header) ? 0 : -1; -} - -PluginHandle * plugin_by_header (const void * header) -{ - GList * node = g_list_find_custom (plugin_list, header, (GCompareFunc) - plugin_by_header_cb); - return node ? node->data : NULL; -} - -int plugin_count (int type) -{ - int count = 0; - - for (GList * node = plugin_list; node; node = node->next) - { - PluginHandle * plugin = node->data; - if (plugin->type == type) - count ++; - } - - return count; -} - -int plugin_get_index (PluginHandle * plugin) -{ - int index = 0; - - for (GList * node = plugin_list; node; node = node->next) - { - PluginHandle * plugin2 = node->data; - if (plugin2->type == plugin->type) - { - if (plugin2 == plugin) - return index; - index ++; - } - } - - return -1; -} - -PluginHandle * plugin_by_index (int type, int index) -{ - for (GList * node = plugin_list; node; node = node->next) - { - PluginHandle * plugin = node->data; - if (plugin->type == type) - { - if (! index) - return plugin; - index --; - } - } - - return NULL; -} - -void plugin_for_each (int type, PluginForEachFunc func, void * data) -{ - for (GList * node = plugin_list; node; node = node->next) - { - if (((PluginHandle *) node->data)->type != type) - continue; - if (! func (node->data, data)) - break; - } -} - -const char * plugin_get_name (PluginHandle * plugin) -{ - return dgettext (plugin->domain, plugin->name); -} - -bool_t plugin_has_about (PluginHandle * plugin) -{ - return plugin->has_about; -} - -bool_t plugin_has_configure (PluginHandle * plugin) -{ - return plugin->has_configure; -} - -bool_t plugin_get_enabled (PluginHandle * plugin) -{ - return plugin->enabled; -} - -static void plugin_call_watches (PluginHandle * plugin) -{ - for (GList * node = plugin->watches; node; ) - { - GList * next = node->next; - PluginWatch * watch = node->data; - - if (! watch->func (plugin, watch->data)) - { - g_slice_free (PluginWatch, watch); - plugin->watches = g_list_delete_link (plugin->watches, node); - } - - node = next; - } -} - -void plugin_set_enabled (PluginHandle * plugin, bool_t enabled) -{ - plugin->enabled = enabled; - plugin_call_watches (plugin); -} - -typedef struct { - PluginForEachFunc func; - void * data; -} PluginForEnabledState; - -static bool_t plugin_for_enabled_cb (PluginHandle * plugin, - PluginForEnabledState * state) -{ - if (! plugin->enabled) - return TRUE; - return state->func (plugin, state->data); -} - -void plugin_for_enabled (int type, PluginForEachFunc func, void * data) -{ - PluginForEnabledState state = {func, data}; - plugin_for_each (type, (PluginForEachFunc) plugin_for_enabled_cb, & state); -} - -void plugin_add_watch (PluginHandle * plugin, PluginForEachFunc func, void * - data) -{ - PluginWatch * watch = g_slice_new (PluginWatch); - watch->func = func; - watch->data = data; - plugin->watches = g_list_prepend (plugin->watches, watch); -} - -void plugin_remove_watch (PluginHandle * plugin, PluginForEachFunc func, void * - data) -{ - for (GList * node = plugin->watches; node; ) - { - GList * next = node->next; - PluginWatch * watch = node->data; - - if (watch->func == func && watch->data == data) - { - g_slice_free (PluginWatch, watch); - plugin->watches = g_list_delete_link (plugin->watches, node); - } - - node = next; - } -} - -void * plugin_get_misc_data (PluginHandle * plugin, int size) -{ - if (! plugin->misc) - plugin->misc = g_malloc0 (size); - - return plugin->misc; -} - -typedef struct { - const char * scheme; - PluginHandle * plugin; -} TransportPluginForSchemeState; - -static bool_t transport_plugin_for_scheme_cb (PluginHandle * plugin, - TransportPluginForSchemeState * state) -{ - if (! g_list_find_custom (plugin->u.t.schemes, state->scheme, - (GCompareFunc) g_ascii_strcasecmp)) - return TRUE; - - state->plugin = plugin; - return FALSE; -} - -PluginHandle * transport_plugin_for_scheme (const char * scheme) -{ - TransportPluginForSchemeState state = {scheme, NULL}; - plugin_for_enabled (PLUGIN_TYPE_TRANSPORT, (PluginForEachFunc) - transport_plugin_for_scheme_cb, & state); - return state.plugin; -} - -typedef struct { - const char * ext; - PluginForEachFunc func; - void * data; -} PlaylistPluginForExtState; - -static bool_t playlist_plugin_for_ext_cb (PluginHandle * plugin, - PlaylistPluginForExtState * state) -{ - if (! g_list_find_custom (plugin->u.p.exts, state->ext, - (GCompareFunc) g_ascii_strcasecmp)) - return TRUE; - - return state->func (plugin, state->data); -} - -void playlist_plugin_for_ext (const char * ext, PluginForEachFunc func, void * data) -{ - PlaylistPluginForExtState state = {ext, func, data}; - plugin_for_enabled (PLUGIN_TYPE_PLAYLIST, (PluginForEachFunc) - playlist_plugin_for_ext_cb, & state); -} - -typedef struct { - int key; - const char * value; - PluginForEachFunc func; - void * data; -} InputPluginForKeyState; - -static bool_t input_plugin_for_key_cb (PluginHandle * plugin, - InputPluginForKeyState * state) -{ - if (! g_list_find_custom (plugin->u.i.keys[state->key], state->value, - (GCompareFunc) g_ascii_strcasecmp)) - return TRUE; - - return state->func (plugin, state->data); -} - -void input_plugin_for_key (int key, const char * value, PluginForEachFunc - func, void * data) -{ - InputPluginForKeyState state = {key, value, func, data}; - plugin_for_enabled (PLUGIN_TYPE_INPUT, (PluginForEachFunc) - input_plugin_for_key_cb, & state); -} - -bool_t input_plugin_has_images (PluginHandle * plugin) -{ - g_return_val_if_fail (plugin->type == PLUGIN_TYPE_INPUT, FALSE); - return plugin->u.i.has_images; -} - -bool_t input_plugin_has_subtunes (PluginHandle * plugin) -{ - g_return_val_if_fail (plugin->type == PLUGIN_TYPE_INPUT, FALSE); - return plugin->u.i.has_subtunes; -} - -bool_t input_plugin_can_write_tuple (PluginHandle * plugin) -{ - g_return_val_if_fail (plugin->type == PLUGIN_TYPE_INPUT, FALSE); - return plugin->u.i.can_write_tuple; -} - -bool_t input_plugin_has_infowin (PluginHandle * plugin) -{ - g_return_val_if_fail (plugin->type == PLUGIN_TYPE_INPUT, FALSE); - return plugin->u.i.has_infowin; -} diff --git a/src/audacious/plugin-view.c b/src/audacious/plugin-view.c deleted file mode 100644 index 36959af..0000000 --- a/src/audacious/plugin-view.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * plugin-view.c - * Copyright 2010-2012 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <gtk/gtk.h> - -#include <libaudgui/libaudgui-gtk.h> - -#include "i18n.h" -#include "plugin.h" -#include "plugins.h" -#include "ui_preferences.h" - -enum { - PVIEW_COL_NODE, - PVIEW_COL_ENABLED, - PVIEW_COL_NAME, - PVIEW_COLS -}; - -typedef struct { - PluginHandle * p; - GtkTreeModel * model; - GtkTreePath * path; -} Node; - -static PluginHandle * get_selected_plugin (GtkTreeView * tree) -{ - Node * n = NULL; - - GtkTreeSelection * sel = gtk_tree_view_get_selection (tree); - - /* the treeview may not have a model yet */ - if (! sel) - return NULL; - - GtkTreeModel * model; - GtkTreeIter iter; - if (gtk_tree_selection_get_selected (sel, & model, & iter)) - gtk_tree_model_get (model, & iter, PVIEW_COL_NODE, & n, -1); - - return n == NULL ? NULL : n->p; -} - -static void do_enable (GtkCellRendererToggle * cell, const char * path_str, - GtkTreeModel * model) -{ - GtkTreePath * path = gtk_tree_path_new_from_string (path_str); - GtkTreeIter iter; - gtk_tree_model_get_iter (model, & iter, path); - gtk_tree_path_free (path); - - Node * n = NULL; - bool_t enabled; - gtk_tree_model_get (model, & iter, PVIEW_COL_NODE, & n, - PVIEW_COL_ENABLED, & enabled, -1); - g_return_if_fail (n != NULL); - - plugin_enable (n->p, ! enabled); -} - -static bool_t list_watcher (PluginHandle * p, Node * n) -{ - GtkTreeIter iter; - gtk_tree_model_get_iter (n->model, & iter, n->path); - gtk_list_store_set ((GtkListStore *) n->model, & iter, PVIEW_COL_ENABLED, - plugin_get_enabled (n->p), -1); - return TRUE; -} - -static bool_t fill_cb (PluginHandle * p, GtkTreeModel * model) -{ - Node * n = g_slice_new (Node); - - GtkTreeIter iter; - gtk_list_store_append ((GtkListStore *) model, & iter); - gtk_list_store_set ((GtkListStore *) model, & iter, PVIEW_COL_NODE, n, - PVIEW_COL_ENABLED, plugin_get_enabled (p), PVIEW_COL_NAME, - plugin_get_name (p), -1); - - n->p = p; - n->model = model; - n->path = gtk_tree_model_get_path (model, & iter); - - plugin_add_watch (p, (PluginForEachFunc) list_watcher, n); - - return TRUE; -} - -static void list_fill (GtkTreeView * tree, void * type) -{ - GtkTreeModel * model = (GtkTreeModel *) gtk_list_store_new (PVIEW_COLS, - G_TYPE_POINTER, G_TYPE_BOOLEAN, G_TYPE_STRING); - gtk_tree_view_set_model (tree, model); - - GtkTreeViewColumn * col = gtk_tree_view_column_new (); - gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_GROW_ONLY); - gtk_tree_view_column_set_resizable (col, FALSE); - gtk_tree_view_append_column (tree, col); - - GtkCellRenderer * rend = gtk_cell_renderer_toggle_new (); - g_signal_connect (rend, "toggled", (GCallback) do_enable, model); - gtk_tree_view_column_pack_start (col, rend, FALSE); - gtk_tree_view_column_set_attributes (col, rend, "active", PVIEW_COL_ENABLED, - NULL); - - col = gtk_tree_view_column_new (); - gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED); - gtk_tree_view_column_set_expand (col, TRUE); - gtk_tree_view_column_set_resizable (col, FALSE); - gtk_tree_view_append_column (tree, col); - - rend = gtk_cell_renderer_text_new (); - gtk_tree_view_column_pack_start (col, rend, FALSE); - gtk_tree_view_column_set_attributes (col, rend, "text", PVIEW_COL_NAME, NULL); - - plugin_for_each (GPOINTER_TO_INT (type), (PluginForEachFunc) fill_cb, model); -} - -static void list_destroy (GtkTreeView * tree) -{ - GtkTreeModel * model = gtk_tree_view_get_model (tree); - if (model == NULL) - return; - - GtkTreeIter iter; - if (gtk_tree_model_get_iter_first (model, & iter)) - { - do - { - Node * n = NULL; - gtk_tree_model_get (model, & iter, PVIEW_COL_NODE, & n, -1); - g_return_if_fail (n != NULL); - - plugin_remove_watch (n->p, (PluginForEachFunc) list_watcher, n); - gtk_tree_path_free (n->path); - g_slice_free (Node, n); - } - while (gtk_tree_model_iter_next (model, & iter)); - } - - g_object_unref ((GObject *) model); -} - -static bool_t config_watcher (PluginHandle * p, GtkWidget * config) -{ - gtk_widget_set_sensitive (config, plugin_has_configure (p) && - plugin_get_enabled (p)); - return TRUE; -} - -static bool_t about_watcher (PluginHandle * p, GtkWidget * about) -{ - gtk_widget_set_sensitive (about, plugin_has_about (p) && plugin_get_enabled - (p)); - return TRUE; -} - -static void button_update (GtkTreeView * tree, GtkWidget * b) -{ - PluginForEachFunc watcher = (PluginForEachFunc) g_object_get_data - ((GObject *) b, "watcher"); - g_return_if_fail (watcher != NULL); - - PluginHandle * p = g_object_steal_data ((GObject *) b, "plugin"); - if (p != NULL) - plugin_remove_watch (p, watcher, b); - - p = get_selected_plugin (tree); - if (p != NULL) - { - g_object_set_data ((GObject *) b, "plugin", p); - watcher (p, b); - plugin_add_watch (p, watcher, b); - } - else - gtk_widget_set_sensitive (b, FALSE); -} - -static void do_config (void * tree) -{ - PluginHandle * plugin = get_selected_plugin (tree); - g_return_if_fail (plugin != NULL); - plugin_do_configure (plugin); -} - -static void do_about (void * tree) -{ - PluginHandle * plugin = get_selected_plugin (tree); - g_return_if_fail (plugin != NULL); - plugin_do_about (plugin); -} - -static void button_destroy (GtkWidget * b) -{ - PluginForEachFunc watcher = (PluginForEachFunc) g_object_get_data - ((GObject *) b, "watcher"); - g_return_if_fail (watcher != NULL); - - PluginHandle * p = g_object_steal_data ((GObject *) b, "plugin"); - if (p != NULL) - plugin_remove_watch (p, watcher, b); -} - -GtkWidget * plugin_view_new (int type) -{ - GtkWidget * vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); - gtk_container_set_border_width ((GtkContainer *) vbox, 6); - - GtkWidget * scrolled = gtk_scrolled_window_new (NULL, NULL); - gtk_box_pack_start ((GtkBox *) vbox, scrolled, TRUE, TRUE, 0); - gtk_scrolled_window_set_policy ((GtkScrolledWindow *) scrolled, - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type ((GtkScrolledWindow *) scrolled, - GTK_SHADOW_IN); - - GtkWidget * tree = gtk_tree_view_new (); - gtk_container_add ((GtkContainer *) scrolled, tree); - gtk_tree_view_set_headers_visible ((GtkTreeView *) tree, FALSE); - g_signal_connect (tree, "realize", (GCallback) list_fill, GINT_TO_POINTER - (type)); - g_signal_connect (tree, "destroy", (GCallback) list_destroy, NULL); - - GtkWidget * hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - gtk_box_pack_start ((GtkBox *) vbox, hbox, FALSE, FALSE, 0); - - GtkWidget * config = audgui_button_new (_("_Settings"), - "preferences-system", do_config, tree); - gtk_box_pack_start ((GtkBox *) hbox, config, FALSE, FALSE, 0); - gtk_widget_set_sensitive (config, FALSE); - g_object_set_data ((GObject *) config, "watcher", (void *) config_watcher); - g_signal_connect (tree, "cursor-changed", (GCallback) button_update, config); - g_signal_connect (config, "destroy", (GCallback) button_destroy, NULL); - - GtkWidget * about = audgui_button_new (_("_About"), "help-about", do_about, tree); - gtk_box_pack_start ((GtkBox *) hbox, about, FALSE, FALSE, 0); - gtk_widget_set_sensitive (about, FALSE); - g_object_set_data ((GObject *) about, "watcher", (void *) about_watcher); - g_signal_connect (tree, "cursor-changed", (GCallback) button_update, about); - g_signal_connect (about, "destroy", (GCallback) button_destroy, NULL); - - return vbox; -} diff --git a/src/audacious/plugin.h b/src/audacious/plugin.h deleted file mode 100644 index 49f5f27..0000000 --- a/src/audacious/plugin.h +++ /dev/null @@ -1,373 +0,0 @@ -/* - * plugin.h - * Copyright 2005-2013 William Pitcock, Yoshiki Yazawa, Eugene Zagidullin, and - * John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_PLUGIN_H -#define AUDACIOUS_PLUGIN_H - -#include <audacious/api.h> -#include <audacious/types.h> -#include <libaudcore/audio.h> -#include <libaudcore/index.h> -#include <libaudcore/tuple.h> -#include <libaudcore/vfs.h> - -/* "Magic" bytes identifying an Audacious plugin header. */ -#define _AUD_PLUGIN_MAGIC 0x8EAC8DE2 - -/* A NOTE ON THREADS - * - * How thread-safe a plugin must be depends on the type of plugin. Note that - * some parts of the Audacious API are *not* thread-safe and therefore cannot be - * used in some parts of some plugins; for example, input plugins cannot use - * GUI-related calls or access the playlist except in about() and configure(). - * - * Thread-safe plugins: transport, playlist, input, effect, and output. These - * must be mostly thread-safe. init() and cleanup() may be called from - * secondary threads; however, no other functions provided by the plugin will be - * called at the same time. about() and configure() will be called only from - * the main thread. All other functions provided by the plugin may be called - * from any thread and from multiple threads simultaneously. - * - * Exceptions: - * - Because many existing input plugins are not coded to handle simultaneous - * calls to play(), play() will only be called from one thread at a time. New - * plugins should not rely on this exception, though. - * - Some combinations of calls, especially for output and effect plugins, make - * no sense; for example, flush() in an output plugin will only be called - * after open_audio() and before close_audio(). - * - * Single-thread plugins: visualization, general, and interface. Functions - * provided by these plugins will only be called from the main thread. */ - -/* CROSS-PLUGIN MESSAGES - * - * Since 3.2, Audacious implements a basic messaging system between plugins. - * Messages are sent using aud_plugin_send_message() and received through the - * take_message() method specified in the header of the receiving plugin. - * Plugins that do not need to receive messages can set take_message() to NULL. - * - * Each message includes a code indicating the type of message, a pointer to - * some data, and a value indicating the size of that data. What the message - * data contains is entirely up to the two plugins involved. For this reason, it - * is crucial that both plugins agree on the meaning of the message codes used. - * - * Once the message is sent, an integer error code is returned. If the receiving - * plugin does not provide the take_message() method, ENOSYS is returned. If - * take_message() does not recognize the message code, it should ignore the - * message and return EINVAL. An error code of zero represents success. Other - * error codes may be used with more specific meanings. - * - * For the time being, aud_plugin_send_message() should only be called from the - * program's main thread. */ - -#define PLUGIN_COMMON_FIELDS \ - int magic; /* checked against _AUD_PLUGIN_MAGIC */ \ - int version; /* checked against _AUD_PLUGIN_VERSION */ \ - int type; /* PLUGIN_TYPE_XXX */ \ - int size; /* size in bytes of the struct */ \ - const char * name; \ - const char * domain; /* for gettext */ \ - const char * about_text; \ - const PluginPreferences * prefs; \ - bool_t (* init) (void); \ - void (* cleanup) (void); \ - int (* take_message) (const char * code, const void * data, int size); \ - void (* about) (void); /* use about_text instead if possible */ \ - void (* configure) (void); /* use prefs instead if possible */ \ - void * reserved1; \ - void * reserved2; \ - void * reserved3; \ - void * reserved4; - -struct _Plugin -{ - PLUGIN_COMMON_FIELDS -}; - -struct _TransportPlugin -{ - PLUGIN_COMMON_FIELDS - - /* supported URI schemes (without "://") - * (array terminated with null pointer) */ - const char * const * schemes; - - /* file operation implementations - * (struct of function pointers, may contain null pointers) */ - const VFSConstructor * vtable; -}; - -struct _PlaylistPlugin -{ - PLUGIN_COMMON_FIELDS - - /* supported file extensions (without periods) - * (array terminated with null pointer) */ - const char * const * extensions; - - /* path: URI of playlist file (in) - * file: VFS handle of playlist file (in, read-only file, not seekable) - * title: title of playlist (out, string-pooled) - * filenames: container to fill with URIs read from playlist file - * (in-out, list of (char *), string-pooled) - * tuples: container to fill with metadata read from playlist - * (in-out, list of (Tuple *), may contain null pointers) */ - bool_t (* load) (const char * path, VFSFile * file, char * * title, - Index * filenames, Index * tuples); - - /* path: URI of playlist file (in) - * file: VFS handle of playlist file (in, write-only file, not seekable) - * title: title of playlist (in) - * filenames: container filled with URIs to be written to playlist - * (in, list of (char *)) - * tuples: container filled with metadata to be written to playlist - * (in, list of (Tuple *), may contain null pointers) */ - bool_t (* save) (const char * path, VFSFile * file, const char * title, - Index * filenames, Index * tuples); -}; - -struct _OutputPlugin -{ - PLUGIN_COMMON_FIELDS - - /* During probing, plugins with higher priority (10 to 0) are tried first. */ - int probe_priority; - - /* Returns current volume for left and right channels (0 to 100). */ - void (* get_volume) (int * l, int * r); - - /* Changes volume for left and right channels (0 to 100). */ - void (* set_volume) (int l, int r); - - /* Begins playback of a PCM stream. <format> is one of the FMT_* - * enumeration values defined in libaudcore/audio.h. Returns nonzero on - * success. */ - bool_t (* open_audio) (int format, int rate, int chans); - - /* Ends playback. Any buffered audio data is discarded. */ - void (* close_audio) (void); - - /* Returns how many bytes of data may be passed to a following write_audio() - * call. NULL if the plugin supports only blocking writes (not recommended). */ - int (* buffer_free) (void); - - /* Waits until buffer_free() will return a size greater than zero. - * output_time(), pause(), and flush() may be called meanwhile; if flush() - * is called, period_wait() should return immediately. NULL if the plugin - * supports only blocking writes (not recommended). */ - void (* period_wait) (void); - - /* Buffers <size> bytes of data, in the format given to open_audio(). */ - void (* write_audio) (void * data, int size); - - /* Waits until all buffered data has been heard by the user. */ - void (* drain) (void); - - /* Returns time count (in milliseconds) of how much data has been heard by - * the user. */ - int (* output_time) (void); - - /* Pauses the stream if <p> is nonzero; otherwise unpauses it. - * write_audio() will not be called while the stream is paused. */ - void (* pause) (bool_t p); - - /* Discards any buffered audio data and sets the time counter (in - * milliseconds) of data written. */ - void (* flush) (int time); - - /* Whether close_audio() and open_audio() must always be called between - * songs, even if the audio format is the same. Note that this defeats - * gapless playback. */ - bool_t force_reopen; -}; - -struct _EffectPlugin -{ - PLUGIN_COMMON_FIELDS - - /* All processing is done in floating point. If the effect plugin wants to - * change the channel count or sample rate, it can change the parameters - * passed to start(). They cannot be changed in the middle of a song. */ - void (* start) (int * channels, int * rate); - - /* process() has two options: modify the samples in place and leave the data - * pointer unchanged or copy them into a buffer of its own. If it sets the - * pointer to dynamically allocated memory, it is the plugin's job to free - * that memory. process() may return different lengths of audio than it is - * passed, even a zero length. */ - void (* process) (float * * data, int * samples); - - /* Optional. A seek is taking place; any buffers should be discarded. */ - void (* flush) (void); - - /* Exactly like process() except that any buffers should be drained (i.e. - * the data processed and returned). finish() will be called a second time - * at the end of the last song in the playlist. */ - void (* finish) (float * * data, int * samples); - - /* Required only for plugins that change the time domain (e.g. a time - * stretch) or use read-ahead buffering. translate_delay() must do two - * things: first, translate <delay> (which is in milliseconds) from the - * output time domain back to the input time domain; second, increase - * <delay> by the size of the read-ahead buffer. It should return the - * adjusted delay. */ - int (* adjust_delay) (int delay); - - /* Effects with lowest order (0 to 9) are applied first. */ - int order; - - /* If the effect does not change the number of channels or the sampling - * rate, it can be enabled and disabled more smoothly. */ - bool_t preserves_format; -}; - -struct _InputPlugin -{ - PLUGIN_COMMON_FIELDS - - /* 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. - * - * 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. - */ - bool_t have_subtune; - - /* Pointer to an array (terminated with NULL) of file extensions associated - * with file types the plugin can handle. */ - const char * const * extensions; - /* Pointer to an array (terminated with NULL) of MIME types the plugin can - * handle. */ - const char * const * mimes; - - /* Pointer to an array (terminated with NULL) of custom URI schemes the - * plugin supports. Plugins using custom URI schemes are expected to - * handle their own I/O. Hence, any VFSFile pointers passed to play(), - * probe_for_tuple(), etc. will be NULL. */ - const char * const * schemes; - - /* 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. */ - int priority; - - /* Returns TRUE if the plugin can handle the file. */ - bool_t (* is_our_file_from_vfs) (const char * filename, VFSFile * file); - - /* Reads metadata from the file, returning a reference to the tuple produced. */ - Tuple * (* probe_for_tuple) (const char * filename, VFSFile * file); - - /* Plays the file. Returns FALSE on error. Also see input-api.h. */ - bool_t (* play) (const char * filename, VFSFile * file); - - /* Optional. Writes metadata to the file, returning FALSE on error. */ - bool_t (* update_song_tuple) (const char * filename, VFSFile * file, const Tuple * tuple); - - /* Optional. Reads an album art image (JPEG or PNG data) from the file. - * Returns a pointer to the data along with its size in bytes. The returned - * data will be freed when no longer needed. Returns FALSE on error. */ - bool_t (* get_song_image) (const char * filename, VFSFile * file, - void * * data, int64_t * size); - - /* Optional. Displays a window showing info about the file. In general, - * this function should be avoided since Audacious already provides a file - * info window. */ - void (* file_info_box) (const char * filename); -}; - -struct _GeneralPlugin -{ - PLUGIN_COMMON_FIELDS - - bool_t enabled_by_default; - - /* GtkWidget * (* get_widget) (void); */ - void * (* get_widget) (void); -}; - -struct _VisPlugin -{ - PLUGIN_COMMON_FIELDS - - /* reset internal state and clear display */ - void (* clear) (void); - - /* 512 frames of a single-channel PCM signal */ - void (* render_mono_pcm) (const float * pcm); - - /* 512 frames of an interleaved multi-channel PCM signal */ - void (* render_multi_pcm) (const float * pcm, int channels); - - /* intensity of frequencies 1/512, 2/512, ..., 256/512 of sample rate */ - void (* render_freq) (const float * freq); - - /* GtkWidget * (* get_widget) (void); */ - void * (* get_widget) (void); -}; - -struct _IfacePlugin -{ - PLUGIN_COMMON_FIELDS - - void (* show) (bool_t show); - - void (* run_gtk_plugin) (void /* GtkWidget */ * widget, const char * name); - void (* stop_gtk_plugin) (void /* GtkWidget */ * widget); -}; - -#undef PLUGIN_COMMON_FIELDS - -#define AUD_PLUGIN(stype, itype, ...) \ -AudAPITable * _aud_api_table = NULL; \ -stype _aud_plugin_self = { \ - .magic = _AUD_PLUGIN_MAGIC, \ - .version = _AUD_PLUGIN_VERSION, \ - .type = itype, \ - .size = sizeof (stype), \ - __VA_ARGS__}; \ -stype * get_plugin_info (AudAPITable * table) { \ - _aud_api_table = table; \ - return & _aud_plugin_self; \ -} - -#define AUD_TRANSPORT_PLUGIN(...) AUD_PLUGIN (TransportPlugin, PLUGIN_TYPE_TRANSPORT, __VA_ARGS__) -#define AUD_PLAYLIST_PLUGIN(...) AUD_PLUGIN (PlaylistPlugin, PLUGIN_TYPE_PLAYLIST, __VA_ARGS__) -#define AUD_INPUT_PLUGIN(...) AUD_PLUGIN (InputPlugin, PLUGIN_TYPE_INPUT, __VA_ARGS__) -#define AUD_EFFECT_PLUGIN(...) AUD_PLUGIN (EffectPlugin, PLUGIN_TYPE_EFFECT, __VA_ARGS__) -#define AUD_OUTPUT_PLUGIN(...) AUD_PLUGIN (OutputPlugin, PLUGIN_TYPE_OUTPUT, __VA_ARGS__) -#define AUD_VIS_PLUGIN(...) AUD_PLUGIN (VisPlugin, PLUGIN_TYPE_VIS, __VA_ARGS__) -#define AUD_GENERAL_PLUGIN(...) AUD_PLUGIN (GeneralPlugin, PLUGIN_TYPE_GENERAL, __VA_ARGS__) -#define AUD_IFACE_PLUGIN(...) AUD_PLUGIN (IfacePlugin, PLUGIN_TYPE_IFACE, __VA_ARGS__) - -#define PLUGIN_HAS_FUNC(p, func) \ - ((p)->size > (char *) & (p)->func - (char *) (p) && (p)->func) - -#endif /* AUDACIOUS_PLUGIN_H */ diff --git a/src/audacious/pluginenum.c b/src/audacious/pluginenum.c deleted file mode 100644 index 58216a5..0000000 --- a/src/audacious/pluginenum.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * pluginenum.c - * Copyright 2007-2013 William Pitcock and John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <assert.h> -#include <errno.h> -#include <pthread.h> -#include <string.h> -#include <sys/stat.h> - -#include <glib.h> -#include <glib/gstdio.h> -#include <gmodule.h> - -#include <libaudcore/audstrings.h> -#include <libaudgui/init.h> - -#include "debug.h" -#include "plugin.h" -#include "util.h" - -#define AUD_API_DECLARE -#include "drct.h" -#include "input.h" -#include "misc.h" -#include "playlist.h" -#include "plugins.h" -#undef AUD_API_DECLARE - -static const char * plugin_dir_list[] = { - "Transport", - "Container", - "Input", - "Output", - "Effect", - "General", - "Visualization" -}; - -char verbose = 0; - -AudAPITable api_table = { - .drct_api = & drct_api, - .input_api = & input_api, - .misc_api = & misc_api, - .playlist_api = & playlist_api, - .plugins_api = & plugins_api, - .verbose = & verbose}; - -typedef struct { - Plugin * header; - GModule * module; -} LoadedModule; - -static GList * loaded_modules = NULL; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - -Plugin * plugin_load (const char * filename) -{ - AUDDBG ("Loading plugin: %s.\n", filename); - - GModule * module = g_module_open (filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); - if (! module) - { - fprintf (stderr, " *** ERROR: %s could not be loaded: %s\n", filename, - g_module_error ()); - return NULL; - } - - void * ptr; - if (! g_module_symbol (module, "get_plugin_info", & ptr)) - ptr = NULL; - - Plugin * (* func) (AudAPITable * table) = ptr; - Plugin * header; - - if (! func || ! (header = func (& api_table)) || header->magic != _AUD_PLUGIN_MAGIC) - { - fprintf (stderr, " *** ERROR: %s is not a valid Audacious plugin.\n", filename); - g_module_close (module); - return NULL; - } - - if (header->version < _AUD_PLUGIN_VERSION_MIN || - header->version > _AUD_PLUGIN_VERSION) - { - fprintf (stderr, " *** ERROR: %s is not compatible with this version " - "of Audacious.\n", filename); - g_module_close (module); - return NULL; - } - - if (header->type == PLUGIN_TYPE_TRANSPORT || - header->type == PLUGIN_TYPE_PLAYLIST || - header->type == PLUGIN_TYPE_INPUT || - header->type == PLUGIN_TYPE_EFFECT) - { - if (PLUGIN_HAS_FUNC (header, init) && ! header->init ()) - { - fprintf (stderr, " *** ERROR: %s failed to initialize.\n", filename); - g_module_close (module); - return NULL; - } - } - - pthread_mutex_lock (& mutex); - LoadedModule * loaded = g_slice_new (LoadedModule); - loaded->header = header; - loaded->module = module; - loaded_modules = g_list_prepend (loaded_modules, loaded); - pthread_mutex_unlock (& mutex); - - return header; -} - -static void plugin2_unload (LoadedModule * loaded) -{ - Plugin * header = loaded->header; - - switch (header->type) - { - case PLUGIN_TYPE_TRANSPORT: - case PLUGIN_TYPE_PLAYLIST: - case PLUGIN_TYPE_INPUT: - case PLUGIN_TYPE_EFFECT: - if (PLUGIN_HAS_FUNC (header, cleanup)) - header->cleanup (); - break; - } - - pthread_mutex_lock (& mutex); -#ifndef VALGRIND_FRIENDLY - g_module_close (loaded->module); -#endif - g_slice_free (LoadedModule, loaded); - pthread_mutex_unlock (& mutex); -} - -/******************************************************************/ - -static bool_t scan_plugin_func(const char * path, const char * basename, void * data) -{ - if (!str_has_suffix_nocase(basename, PLUGIN_SUFFIX)) - return FALSE; - - GStatBuf st; - if (g_stat (path, & st) < 0) - { - fprintf (stderr, "Unable to stat %s: %s\n", path, strerror (errno)); - return FALSE; - } - - if (S_ISREG (st.st_mode)) - plugin_register (path, st.st_mtime); - - return FALSE; -} - -static void scan_plugins(const char * path) -{ - dir_foreach (path, scan_plugin_func, NULL); -} - -void plugin_system_init(void) -{ - assert (g_module_supported ()); - - audgui_init (& api_table, _AUD_PLUGIN_VERSION); - - plugin_registry_load (); - - const char * path = get_path (AUD_PATH_PLUGIN_DIR); - - for (int i = 0; i < ARRAY_LEN (plugin_dir_list); i ++) - { - char * dir = filename_build (path, plugin_dir_list[i]); - scan_plugins (dir); - str_unref (dir); - } - - plugin_registry_prune (); -} - -void plugin_system_cleanup(void) -{ - plugin_registry_save (); - - for (GList * node = loaded_modules; node != NULL; node = node->next) - plugin2_unload (node->data); - - g_list_free (loaded_modules); - loaded_modules = NULL; - - audgui_cleanup (); -} diff --git a/src/audacious/plugins-api.h b/src/audacious/plugins-api.h deleted file mode 100644 index af4c1b2..0000000 --- a/src/audacious/plugins-api.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * plugins-api.h - * Copyright 2010-2012 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -/* Do not include this file directly; use misc.h instead. */ - -/* CAUTION: These functions are not thread safe. */ - -/* plugin-init.c */ -AUD_FUNC1 (PluginHandle *, plugin_get_current, int, type) -AUD_FUNC2 (bool_t, plugin_enable, PluginHandle *, plugin, bool_t, enable) -AUD_FUNC1 (PluginHandle *, plugin_by_widget, void /* GtkWidget */ *, widget) -AUD_FUNC4 (int, plugin_send_message, PluginHandle *, plugin, - const char *, code, const void *, data, int, size) - -/* plugin-registry.c */ -AUD_FUNC1 (int, plugin_get_type, PluginHandle *, plugin) -AUD_FUNC1 (const char *, plugin_get_filename, PluginHandle *, plugin) -AUD_FUNC1 (PluginHandle *, plugin_lookup, const char *, filename) -AUD_FUNC1 (PluginHandle *, plugin_lookup_basename, const char *, basename) - -AUD_FUNC1 (const void *, plugin_get_header, PluginHandle *, plugin) -AUD_FUNC1 (PluginHandle *, plugin_by_header, const void *, header) - -AUD_FUNC1 (int, plugin_count, int, type) -AUD_FUNC1 (int, plugin_get_index, PluginHandle *, plugin) -AUD_FUNC2 (PluginHandle *, plugin_by_index, int, type, int, index) - -AUD_FUNC2 (int, plugin_compare, PluginHandle *, a, PluginHandle *, b) -AUD_VFUNC3 (plugin_for_each, int, type, PluginForEachFunc, func, void *, data) - -AUD_FUNC1 (bool_t, plugin_get_enabled, PluginHandle *, plugin) -AUD_VFUNC3 (plugin_for_enabled, int, type, PluginForEachFunc, func, - void *, data) - -AUD_FUNC1 (const char *, plugin_get_name, PluginHandle *, plugin) -AUD_FUNC1 (bool_t, plugin_has_about, PluginHandle *, plugin) -AUD_FUNC1 (bool_t, plugin_has_configure, PluginHandle *, plugin) -AUD_VFUNC1 (plugin_do_about, PluginHandle *, plugin) -AUD_VFUNC1 (plugin_do_configure, PluginHandle *, plugin) - -AUD_VFUNC3 (plugin_add_watch, PluginHandle *, plugin, PluginForEachFunc, - func, void *, data) -AUD_VFUNC3 (plugin_remove_watch, PluginHandle *, plugin, PluginForEachFunc, - func, void *, data) diff --git a/src/audacious/plugins.h b/src/audacious/plugins.h deleted file mode 100644 index ea956ee..0000000 --- a/src/audacious/plugins.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * plugins.h - * Copyright 2010-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_PLUGINS_H -#define AUDACIOUS_PLUGINS_H - -#include <audacious/api.h> -#include <audacious/types.h> -#include <libaudcore/core.h> - -/* returns TRUE to call again for the next plugin, FALSE to stop */ -typedef bool_t (* PluginForEachFunc) (PluginHandle * plugin, void * data); - -#define AUD_API_NAME PluginsAPI -#define AUD_API_SYMBOL plugins_api - -#ifdef _AUDACIOUS_CORE - -#include "api-local-begin.h" -#include "plugins-api.h" -#include "api-local-end.h" - -enum { - INPUT_KEY_SCHEME, - INPUT_KEY_EXTENSION, - INPUT_KEY_MIME, - INPUT_KEYS}; - -/* plugin-init.c */ -void start_plugins_one (void); -void start_plugins_two (void); -void stop_plugins_two (void); -void stop_plugins_one (void); - -/* plugin-registry.c */ -void plugin_registry_load (void); -void plugin_registry_prune (void); -void plugin_registry_save (void); - -void plugin_register (const char * path, int timestamp); - -void plugin_set_enabled (PluginHandle * plugin, bool_t enabled); -void * plugin_get_misc_data (PluginHandle * plugin, int size); - -PluginHandle * transport_plugin_for_scheme (const char * scheme); -void playlist_plugin_for_ext (const char * ext, PluginForEachFunc func, void * data); -void input_plugin_for_key (int key, const char * value, PluginForEachFunc func, void * data); -bool_t input_plugin_has_images (PluginHandle * plugin); -bool_t input_plugin_has_subtunes (PluginHandle * plugin); -bool_t input_plugin_can_write_tuple (PluginHandle * plugin); -bool_t input_plugin_has_infowin (PluginHandle * plugin); - -/* pluginenum.c */ -void plugin_system_init (void); -void plugin_system_cleanup (void); -Plugin * plugin_load (const char * path); - -#else - -#include <audacious/api-define-begin.h> -#include <audacious/plugins-api.h> -#include <audacious/api-define-end.h> - -#include <audacious/api-alias-begin.h> -#include <audacious/plugins-api.h> -#include <audacious/api-alias-end.h> - -#endif - -#undef AUD_API_NAME -#undef AUD_API_SYMBOL - -#endif - -#ifdef AUD_API_DECLARE - -#define AUD_API_NAME PluginsAPI -#define AUD_API_SYMBOL plugins_api - -#include "api-define-begin.h" -#include "plugins-api.h" -#include "api-define-end.h" - -#include "api-declare-begin.h" -#include "plugins-api.h" -#include "api-declare-end.h" - -#undef AUD_API_NAME -#undef AUD_API_SYMBOL - -#endif diff --git a/src/audacious/preferences.c b/src/audacious/preferences.c deleted file mode 100644 index eb1b651..0000000 --- a/src/audacious/preferences.c +++ /dev/null @@ -1,641 +0,0 @@ -/* - * preferences.c - * Copyright 2007-2012 Tomasz Moń, William Pitcock, and John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include "preferences.h" - -#include <string.h> -#include <gtk/gtk.h> - -#include "i18n.h" -#include "misc.h" - -/* HELPERS */ - -static bool_t widget_get_bool (const PreferencesWidget * widget) -{ - g_return_val_if_fail (widget->cfg_type == VALUE_BOOLEAN, FALSE); - - if (widget->cfg) - return * (bool_t *) widget->cfg; - else if (widget->cname) - return get_bool (widget->csect, widget->cname); - else - return FALSE; -} - -static void widget_set_bool (const PreferencesWidget * widget, bool_t value) -{ - g_return_if_fail (widget->cfg_type == VALUE_BOOLEAN); - - if (widget->cfg) - * (bool_t *) widget->cfg = value; - else if (widget->cname) - set_bool (widget->csect, widget->cname, value); - - if (widget->callback) - widget->callback (); -} - -static int widget_get_int (const PreferencesWidget * widget) -{ - g_return_val_if_fail (widget->cfg_type == VALUE_INT, 0); - - if (widget->cfg) - return * (int *) widget->cfg; - else if (widget->cname) - return get_int (widget->csect, widget->cname); - else - return 0; -} - -static void widget_set_int (const PreferencesWidget * widget, int value) -{ - g_return_if_fail (widget->cfg_type == VALUE_INT); - - if (widget->cfg) - * (int *) widget->cfg = value; - else if (widget->cname) - set_int (widget->csect, widget->cname, value); - - if (widget->callback) - widget->callback (); -} - -static double widget_get_double (const PreferencesWidget * widget) -{ - g_return_val_if_fail (widget->cfg_type == VALUE_FLOAT, 0); - - if (widget->cfg) - return * (float *) widget->cfg; - else if (widget->cname) - return get_double (widget->csect, widget->cname); - else - return 0; -} - -static void widget_set_double (const PreferencesWidget * widget, double value) -{ - g_return_if_fail (widget->cfg_type == VALUE_FLOAT); - - if (widget->cfg) - * (float *) widget->cfg = value; - else if (widget->cname) - set_double (widget->csect, widget->cname, value); - - if (widget->callback) - widget->callback (); -} - -static char * widget_get_string (const PreferencesWidget * widget) -{ - g_return_val_if_fail (widget->cfg_type == VALUE_STRING, NULL); - - if (widget->cfg) - return str_get (* (char * *) widget->cfg); - else if (widget->cname) - return get_str (widget->csect, widget->cname); - else - return NULL; -} - -static void widget_set_string (const PreferencesWidget * widget, const char * value) -{ - g_return_if_fail (widget->cfg_type == VALUE_STRING); - - if (widget->cfg) - { - g_free (* (char * *) widget->cfg); - * (char * *) widget->cfg = g_strdup (value); - } - else if (widget->cname) - set_str (widget->csect, widget->cname, value); - - if (widget->callback) - widget->callback (); -} - -/* WIDGET_CHK_BTN */ - -static void on_toggle_button_toggled (GtkToggleButton * button, const PreferencesWidget * widget) -{ - bool_t active = gtk_toggle_button_get_active (button); - widget_set_bool (widget, active); - - GtkWidget * child = g_object_get_data ((GObject *) button, "child"); - if (child) - gtk_widget_set_sensitive (child, active); -} - -static void init_toggle_button (GtkWidget * button, const PreferencesWidget * widget) -{ - if (widget->cfg_type != VALUE_BOOLEAN) - return; - - gtk_toggle_button_set_active ((GtkToggleButton *) button, widget_get_bool (widget)); - g_signal_connect (button, "toggled", (GCallback) on_toggle_button_toggled, (void *) widget); -} - -/* WIDGET_LABEL */ - -static void create_label (const PreferencesWidget * widget, GtkWidget * * label, - GtkWidget * * icon, const char * domain) -{ - if (widget->data.label.stock_id) - * icon = gtk_image_new_from_icon_name (widget->data.label.stock_id, GTK_ICON_SIZE_BUTTON); - - * label = gtk_label_new_with_mnemonic (dgettext (domain, widget->label)); - gtk_label_set_use_markup ((GtkLabel *) * label, TRUE); - - if (widget->data.label.single_line == FALSE) - gtk_label_set_line_wrap ((GtkLabel *) * label, TRUE); - - gtk_misc_set_alignment ((GtkMisc *) * label, 0, 0.5); -} - -/* WIDGET_RADIO_BTN */ - -static void on_radio_button_toggled (GtkWidget * button, const PreferencesWidget * widget) -{ - if (gtk_toggle_button_get_active ((GtkToggleButton *) button)) - widget_set_int (widget, widget->data.radio_btn.value); -} - -static void init_radio_button (GtkWidget * button, const PreferencesWidget * widget) -{ - if (widget->cfg_type != VALUE_INT) - return; - - if (widget_get_int (widget) == widget->data.radio_btn.value) - gtk_toggle_button_set_active ((GtkToggleButton *) button, TRUE); - - g_signal_connect (button, "toggled", (GCallback) on_radio_button_toggled, (void *) widget); -} - -/* WIDGET_SPIN_BTN */ - -static void on_spin_btn_changed_int (GtkSpinButton * button, const PreferencesWidget * widget) -{ - widget_set_int (widget, gtk_spin_button_get_value_as_int (button)); -} - -static void on_spin_btn_changed_float (GtkSpinButton * button, const PreferencesWidget * widget) -{ - widget_set_double (widget, gtk_spin_button_get_value (button)); -} - -static void create_spin_button (const PreferencesWidget * widget, - GtkWidget * * label_pre, GtkWidget * * spin_btn, GtkWidget * * label_past, - const char * domain) -{ - * label_pre = gtk_label_new (dgettext (domain, widget->label)); - * spin_btn = gtk_spin_button_new_with_range (widget->data.spin_btn.min, - widget->data.spin_btn.max, widget->data.spin_btn.step); - - if (widget->tooltip) - gtk_widget_set_tooltip_text (* spin_btn, dgettext (domain, widget->tooltip)); - - if (widget->data.spin_btn.right_label) - * label_past = gtk_label_new (dgettext (domain, widget->data.spin_btn.right_label)); - - switch (widget->cfg_type) - { - case VALUE_INT: - gtk_spin_button_set_value ((GtkSpinButton *) * spin_btn, widget_get_int (widget)); - g_signal_connect (* spin_btn, "value_changed", (GCallback) - on_spin_btn_changed_int, (void *) widget); - break; - - case VALUE_FLOAT: - gtk_spin_button_set_value ((GtkSpinButton *) * spin_btn, widget_get_double (widget)); - g_signal_connect (* spin_btn, "value_changed", (GCallback) - on_spin_btn_changed_float, (void *) widget); - break; - - default: - break; - } -} - -/* WIDGET_FONT_BTN */ - -static void on_font_btn_font_set (GtkFontButton * button, const PreferencesWidget * widget) -{ - widget_set_string (widget, gtk_font_button_get_font_name (button)); -} - -void create_font_btn (const PreferencesWidget * widget, GtkWidget * * label, - GtkWidget * * font_btn, const char * domain) -{ - * font_btn = gtk_font_button_new (); - gtk_font_button_set_use_font ((GtkFontButton *) * font_btn, TRUE); - gtk_font_button_set_use_size ((GtkFontButton *) * font_btn, TRUE); - gtk_widget_set_hexpand (* font_btn, TRUE); - - if (widget->label) - { - * label = gtk_label_new_with_mnemonic (dgettext (domain, widget->label)); - gtk_label_set_use_markup ((GtkLabel *) * label, TRUE); - gtk_misc_set_alignment ((GtkMisc *) * label, 1, 0.5); - gtk_label_set_justify ((GtkLabel *) * label, GTK_JUSTIFY_RIGHT); - gtk_label_set_mnemonic_widget ((GtkLabel *) * label, * font_btn); - } - - if (widget->data.font_btn.title) - gtk_font_button_set_title ((GtkFontButton *) * font_btn, - dgettext (domain, widget->data.font_btn.title)); - - char * name = widget_get_string (widget); - if (name) - { - gtk_font_button_set_font_name ((GtkFontButton *) * font_btn, name); - str_unref (name); - } - - g_signal_connect (* font_btn, "font_set", (GCallback) on_font_btn_font_set, (void *) widget); -} - -/* WIDGET_ENTRY */ - -static void on_entry_changed (GtkEntry * entry, const PreferencesWidget * widget) -{ - widget_set_string (widget, gtk_entry_get_text (entry)); -} - -static void create_entry (const PreferencesWidget * widget, GtkWidget * * label, - GtkWidget * * entry, const char * domain) -{ - * entry = gtk_entry_new (); - gtk_entry_set_visibility ((GtkEntry *) * entry, ! widget->data.entry.password); - gtk_widget_set_hexpand (* entry, TRUE); - - if (widget->label) - * label = gtk_label_new (dgettext (domain, widget->label)); - - if (widget->tooltip) - gtk_widget_set_tooltip_text (* entry, dgettext (domain, widget->tooltip)); - - if (widget->cfg_type == VALUE_STRING) - { - char * value = widget_get_string (widget); - if (value) - { - gtk_entry_set_text ((GtkEntry *) * entry, value); - str_unref (value); - } - - g_signal_connect (* entry, "changed", (GCallback) on_entry_changed, (void *) widget); - } -} - -/* WIDGET_COMBO_BOX */ - -static void on_cbox_changed_int (GtkComboBox * combobox, const PreferencesWidget * widget) -{ - int position = gtk_combo_box_get_active (combobox); - const ComboBoxElements * elements = g_object_get_data ((GObject *) combobox, "comboboxelements"); - widget_set_int (widget, GPOINTER_TO_INT (elements[position].value)); -} - -static void on_cbox_changed_string (GtkComboBox * combobox, const PreferencesWidget * widget) -{ - int position = gtk_combo_box_get_active (combobox); - const ComboBoxElements * elements = g_object_get_data ((GObject *) combobox, "comboboxelements"); - widget_set_string (widget, elements[position].value); -} - -static void fill_cbox (GtkWidget * combobox, const PreferencesWidget * widget, const char * domain) -{ - const ComboBoxElements * elements = widget->data.combo.elements; - int n_elements = widget->data.combo.n_elements; - - if (widget->data.combo.fill) - elements = widget->data.combo.fill (& n_elements); - - g_object_set_data ((GObject *) combobox, "comboboxelements", (void *) elements); - - for (int i = 0; i < n_elements; i ++) - gtk_combo_box_text_append_text ((GtkComboBoxText *) combobox, - dgettext (domain, elements[i].label)); - - switch (widget->cfg_type) - { - case VALUE_INT:; - int ivalue = widget_get_int (widget); - - for (int i = 0; i < n_elements; i++) - { - if (GPOINTER_TO_INT (elements[i].value) == ivalue) - { - gtk_combo_box_set_active ((GtkComboBox *) combobox, i); - break; - } - } - - g_signal_connect (combobox, "changed", (GCallback) on_cbox_changed_int, (void *) widget); - break; - - case VALUE_STRING:; - char * value = widget_get_string (widget); - - for(int i = 0; i < n_elements; i++) - { - if (value && ! strcmp (elements[i].value, value)) - { - gtk_combo_box_set_active ((GtkComboBox *) combobox, i); - break; - } - } - - str_unref (value); - - g_signal_connect (combobox, "changed", (GCallback) on_cbox_changed_string, (void *) widget); - break; - - default: - break; - } -} - -static void create_cbox (const PreferencesWidget * widget, GtkWidget * * label, - GtkWidget * * combobox, const char * domain) -{ - * combobox = gtk_combo_box_text_new (); - - if (widget->label) - * label = gtk_label_new (dgettext (domain, widget->label)); - - fill_cbox (* combobox, widget, domain); -} - -/* WIDGET_TABLE */ - -static void fill_grid (GtkWidget * grid, const PreferencesWidget * elements, - int n_elements, const char * domain) -{ - for (int i = 0; i < n_elements; i ++) - { - GtkWidget * widget_left = NULL, * widget_middle = NULL, * widget_right = NULL; - - switch (elements[i].type) - { - case WIDGET_SPIN_BTN: - create_spin_button (& elements[i], & widget_left, - & widget_middle, & widget_right, domain); - break; - - case WIDGET_LABEL: - create_label (& elements[i], & widget_middle, & widget_left, domain); - break; - - case WIDGET_FONT_BTN: - create_font_btn (& elements[i], & widget_left, & widget_middle, domain); - break; - - case WIDGET_ENTRY: - create_entry (& elements[i], & widget_left, & widget_middle, domain); - break; - - case WIDGET_COMBO_BOX: - create_cbox (& elements[i], & widget_left, & widget_middle, domain); - break; - - default: - break; - } - - if (widget_left) - gtk_grid_attach ((GtkGrid *) grid, widget_left, 0, i, 1, 1); - - if (widget_middle) - gtk_grid_attach ((GtkGrid *) grid, widget_middle, 1, i, 1, 1); - - if (widget_right) - gtk_grid_attach ((GtkGrid *) grid, widget_right, 2, i, 1, 1); - } -} - -/* ALL WIDGETS */ - -/* box: a GtkBox */ -void create_widgets_with_domain (void * box, const PreferencesWidget * widgets, - int n_widgets, const char * domain) -{ - GtkWidget * widget = NULL, * child_box = NULL; - GSList * radio_btn_group = NULL; - - for (int i = 0; i < n_widgets; i ++) - { - GtkWidget * label = NULL; - - if (widget && widgets[i].child) - { - if (! child_box) - { - child_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - g_object_set_data ((GObject *) widget, "child", child_box); - - GtkWidget * alignment = gtk_alignment_new (0.5, 0.5, 1, 1); - gtk_box_pack_start (box, alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding ((GtkAlignment *) alignment, 0, 0, 12, 0); - gtk_container_add ((GtkContainer *) alignment, child_box); - - if (GTK_IS_TOGGLE_BUTTON (widget)) - gtk_widget_set_sensitive (child_box, - gtk_toggle_button_get_active ((GtkToggleButton *) widget)); - } - } - else - child_box = NULL; - - GtkWidget * alignment = gtk_alignment_new (0.5, 0.5, 1, 1); - gtk_alignment_set_padding ((GtkAlignment *) alignment, 6, 0, 12, 0); - gtk_box_pack_start (child_box ? (GtkBox *) child_box : box, alignment, FALSE, FALSE, 0); - - widget = NULL; - - if (radio_btn_group && widgets[i].type != WIDGET_RADIO_BTN) - radio_btn_group = NULL; - - switch (widgets[i].type) - { - case WIDGET_CHK_BTN: - widget = gtk_check_button_new_with_mnemonic (dgettext (domain, widgets[i].label)); - init_toggle_button (widget, & widgets[i]); - break; - - case WIDGET_LABEL: - if (strstr (widgets[i].label, "<b>")) - gtk_alignment_set_padding ((GtkAlignment *) alignment, - (i == 0) ? 0 : 12, 0, 0, 0); - - GtkWidget * icon = NULL; - create_label (& widgets[i], & label, & icon, domain); - - if (icon) - { - widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - gtk_box_pack_start ((GtkBox *) widget, icon, FALSE, FALSE, 0); - gtk_box_pack_start ((GtkBox *) widget, label, FALSE, FALSE, 0); - } - else - widget = label; - - break; - - case WIDGET_RADIO_BTN: - widget = gtk_radio_button_new_with_mnemonic (radio_btn_group, - dgettext (domain, widgets[i].label)); - radio_btn_group = gtk_radio_button_get_group ((GtkRadioButton *) widget); - init_radio_button (widget, & widgets[i]); - break; - - case WIDGET_SPIN_BTN: - widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - - GtkWidget * label_pre = NULL, * spin_btn = NULL, * label_past = NULL; - create_spin_button (& widgets[i], & label_pre, & spin_btn, & label_past, domain); - - if (label_pre) - gtk_box_pack_start ((GtkBox *) widget, label_pre, FALSE, FALSE, 0); - if (spin_btn) - gtk_box_pack_start ((GtkBox *) widget, spin_btn, FALSE, FALSE, 0); - if (label_past) - gtk_box_pack_start ((GtkBox *) widget, label_past, FALSE, FALSE, 0); - - break; - - case WIDGET_CUSTOM: - if (widgets[i].data.populate) - widget = widgets[i].data.populate (); - - break; - - case WIDGET_FONT_BTN: - widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - - GtkWidget * font_btn = NULL; - create_font_btn (& widgets[i], & label, & font_btn, domain); - - if (label) - gtk_box_pack_start ((GtkBox *) widget, label, FALSE, FALSE, 0); - if (font_btn) - gtk_box_pack_start ((GtkBox *) widget, font_btn, FALSE, FALSE, 0); - - break; - - case WIDGET_TABLE: - widget = gtk_grid_new (); - gtk_grid_set_column_spacing ((GtkGrid *) widget, 6); - gtk_grid_set_row_spacing ((GtkGrid *) widget, 6); - - fill_grid (widget, widgets[i].data.table.elem, widgets[i].data.table.rows, domain); - - break; - - case WIDGET_ENTRY: - widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - - GtkWidget * entry = NULL; - create_entry (& widgets[i], & label, & entry, domain); - - if (label) - gtk_box_pack_start ((GtkBox *) widget, label, FALSE, FALSE, 0); - if (entry) - gtk_box_pack_start ((GtkBox *) widget, entry, TRUE, TRUE, 0); - - break; - - case WIDGET_COMBO_BOX: - widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - - GtkWidget * combo = NULL; - create_cbox (& widgets[i], & label, & combo, domain); - - if (label) - gtk_box_pack_start ((GtkBox *) widget, label, FALSE, FALSE, 0); - if (combo) - gtk_box_pack_start ((GtkBox *) widget, combo, FALSE, FALSE, 0); - - break; - - case WIDGET_BOX: - if (widgets[i].data.box.horizontal) - widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - else - widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - - create_widgets_with_domain ((GtkBox *) widget, - widgets[i].data.box.elem, widgets[i].data.box.n_elem, domain); - - if (widgets[i].data.box.frame) - { - GtkWidget * frame = gtk_frame_new (dgettext (domain, widgets[i].label)); - gtk_container_add ((GtkContainer *) frame, widget); - widget = frame; - } - - break; - - case WIDGET_NOTEBOOK: - gtk_alignment_set_padding ((GtkAlignment *) alignment, 0, 0, 0, 0); - - widget = gtk_notebook_new (); - - for (int j = 0; j < widgets[i].data.notebook.n_tabs; j ++) - { - GtkWidget * vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_container_set_border_width ((GtkContainer *) vbox, 6); - - create_widgets_with_domain ((GtkBox *) vbox, - widgets[i].data.notebook.tabs[j].widgets, - widgets[i].data.notebook.tabs[j].n_widgets, domain); - - gtk_notebook_append_page ((GtkNotebook *) widget, vbox, - gtk_label_new (dgettext (domain, - widgets[i].data.notebook.tabs[j].name))); - } - - break; - - case WIDGET_SEPARATOR: - gtk_alignment_set_padding ((GtkAlignment *) alignment, 6, 6, 0, 0); - - widget = gtk_separator_new (widgets[i].data.separator.horizontal - ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL); - break; - - default: - break; - } - - if (widget) - { - /* use uniform spacing for horizontal boxes */ - if (gtk_orientable_get_orientation ((GtkOrientable *) box) == - GTK_ORIENTATION_HORIZONTAL) - gtk_alignment_set_padding ((GtkAlignment *) alignment, 0, 0, 0, 0); - - gtk_container_add ((GtkContainer *) alignment, widget); - - if (widgets[i].tooltip && widgets[i].type != WIDGET_SPIN_BTN) - gtk_widget_set_tooltip_text (widget, dgettext (domain, - widgets[i].tooltip)); - } - } -} diff --git a/src/audacious/preferences.h b/src/audacious/preferences.h deleted file mode 100644 index af58567..0000000 --- a/src/audacious/preferences.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * preferences.h - * Copyright 2007-2012 Tomasz Moń, William Pitcock, and John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_PREFERENCES_H -#define AUDACIOUS_PREFERENCES_H - -#include <audacious/types.h> - -typedef enum { - WIDGET_NONE, - WIDGET_CHK_BTN, - WIDGET_LABEL, - WIDGET_RADIO_BTN, - WIDGET_SPIN_BTN, - WIDGET_CUSTOM, /* 'custom' widget, you hand back the widget you want to add --nenolod */ - WIDGET_FONT_BTN, - WIDGET_TABLE, - WIDGET_ENTRY, - WIDGET_COMBO_BOX, - WIDGET_BOX, - WIDGET_NOTEBOOK, - WIDGET_SEPARATOR, -} WidgetType; - -typedef enum { - VALUE_INT, - VALUE_FLOAT, - VALUE_BOOLEAN, - VALUE_STRING, - VALUE_NULL, -} ValueType; - -typedef struct { - void * value; - const char * label; -} ComboBoxElements; - -struct _NotebookTab; - -struct _PreferencesWidget { - WidgetType type; /* widget type */ - const char * label; /* widget title (for SPIN_BTN it's text left to widget) */ - void * cfg; /* connected config value */ - void (* callback) (void); /* this func will be called after value change, can be NULL */ - const char * tooltip; /* widget tooltip, can be NULL */ - bool_t child; - ValueType cfg_type; /* connected value type */ - const char * csect; /* config file section */ - const char * cname; /* config file key name */ - - union { - struct { - int value; - } radio_btn; - - struct { - double min, max, step; - const char * right_label; /* text right to widget */ - } spin_btn; - - struct { - struct _PreferencesWidget *elem; - int rows; - } table; - - struct { - const char * stock_id; - bool_t single_line; /* FALSE to enable line wrap */ - } label; - - struct { - const char * title; - } font_btn; - - struct { - bool_t password; - } entry; - - struct { - /* static init */ - const ComboBoxElements * elements; - int n_elements; - - /* runtime init */ - const ComboBoxElements * (* fill) (int * n_elements); - } combo; - - struct { - const struct _PreferencesWidget * elem; - int n_elem; - - bool_t horizontal; /* FALSE gives vertical, TRUE gives horizontal aligment of child widgets */ - bool_t frame; /* whether to draw frame around box */ - } box; - - struct { - const struct _NotebookTab * tabs; - int n_tabs; - } notebook; - - struct { - bool_t horizontal; /* FALSE gives vertical, TRUE gives horizontal separator */ - } separator; - - /* for WIDGET_CUSTOM --nenolod */ - /* GtkWidget * (* populate) (void); */ - void * (* populate) (void); - } data; -}; - -typedef struct _NotebookTab { - const char * name; - const PreferencesWidget * widgets; - int n_widgets; -} NotebookTab; - -struct _PluginPreferences { - const PreferencesWidget * widgets; - int n_widgets; - - void (*init)(void); - void (*apply)(void); - void (*cleanup)(void); -}; - -#endif /* AUDACIOUS_PREFERENCES_H */ diff --git a/src/audacious/probe-buffer.c b/src/audacious/probe-buffer.c deleted file mode 100644 index c27995b..0000000 --- a/src/audacious/probe-buffer.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * probe-buffer.c - * Copyright 2010-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <string.h> - -#include <glib.h> - -#include "debug.h" -#include "probe-buffer.h" - -#define BUFSIZE (256 * 1024) - -typedef struct -{ - VFSFile * file; - int filled, at; - unsigned char buffer[BUFSIZE]; -} -ProbeBuffer; - -static int probe_buffer_fclose (VFSFile * file) -{ - ProbeBuffer * p = vfs_get_handle (file); - - int ret = vfs_fclose (p->file); - g_free (p); - return ret; -} - -static void increase_buffer (ProbeBuffer * p, int64_t size) -{ - size = (size + 0xFF) & ~0xFF; - - if (size > sizeof p->buffer) - size = sizeof p->buffer; - - if (p->filled < size) - p->filled += vfs_fread (p->buffer + p->filled, 1, size - p->filled, - p->file); -} - -static int64_t probe_buffer_fread (void * buffer, int64_t size, int64_t count, - VFSFile * file) -{ - ProbeBuffer * p = vfs_get_handle (file); - - increase_buffer (p, p->at + size * count); - int readed = (size > 0) ? MIN (count, (p->filled - p->at) / size) : 0; - memcpy (buffer, p->buffer + p->at, size * readed); - - p->at += size * readed; - return readed; -} - -static int64_t probe_buffer_fwrite (const void * data, int64_t size, int64_t count, - VFSFile * file) -{ - return 0; /* not allowed */ -} - -static int probe_buffer_fseek (VFSFile * file, int64_t offset, int whence) -{ - ProbeBuffer * p = vfs_get_handle (file); - - if (whence == SEEK_END) - return -1; /* not allowed */ - - if (whence == SEEK_CUR) - offset += p->at; - - if (offset < 0 || offset > sizeof p->buffer) - return -1; - - increase_buffer (p, offset); - - if (offset > p->filled) - return -1; - - p->at = offset; - return 0; -} - -static int64_t probe_buffer_ftell (VFSFile * file) -{ - return ((ProbeBuffer *) vfs_get_handle (file))->at; -} - -static bool_t probe_buffer_feof (VFSFile * file) -{ - ProbeBuffer * p = vfs_get_handle (file); - - if (p->at < p->filled) - return FALSE; - if (p->at == sizeof p->buffer) - return TRUE; - - return vfs_feof (p->file); -} - -static int probe_buffer_ftruncate (VFSFile * file, int64_t size) -{ - return -1; /* not allowed */ -} - -static int64_t probe_buffer_fsize (VFSFile * file) -{ - ProbeBuffer * p = vfs_get_handle (file); - - int64_t size = vfs_fsize (p->file); - return MIN (size, sizeof p->buffer); -} - -static char * probe_buffer_get_metadata (VFSFile * file, const char * field) -{ - return vfs_get_metadata (((ProbeBuffer *) vfs_get_handle (file))->file, field); -} - -static VFSConstructor probe_buffer_table = -{ - .vfs_fopen_impl = NULL, - .vfs_fclose_impl = probe_buffer_fclose, - .vfs_fread_impl = probe_buffer_fread, - .vfs_fwrite_impl = probe_buffer_fwrite, - .vfs_fseek_impl = probe_buffer_fseek, - .vfs_ftell_impl = probe_buffer_ftell, - .vfs_feof_impl = probe_buffer_feof, - .vfs_ftruncate_impl = probe_buffer_ftruncate, - .vfs_fsize_impl = probe_buffer_fsize, - .vfs_get_metadata_impl = probe_buffer_get_metadata, -}; - -VFSFile * probe_buffer_new (const char * filename) -{ - VFSFile * file = vfs_fopen (filename, "r"); - - if (! file) - return NULL; - - ProbeBuffer * p = g_new (ProbeBuffer, 1); - p->file = file; - p->filled = 0; - p->at = 0; - - return vfs_new (filename, & probe_buffer_table, p); -} diff --git a/src/audacious/probe-buffer.h b/src/audacious/probe-buffer.h deleted file mode 100644 index d1abf96..0000000 --- a/src/audacious/probe-buffer.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * probe-buffer.h - * Copyright 2010 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_PROBE_BUFFER_H -#define AUDACIOUS_PROBE_BUFFER_H - -#include <libaudcore/vfs.h> - -VFSFile * probe_buffer_new (const char * filename); - -#endif diff --git a/src/audacious/probe.c b/src/audacious/probe.c deleted file mode 100644 index c627abe..0000000 --- a/src/audacious/probe.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * probe.c - * Copyright 2009-2013 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <glib.h> -#include <stdio.h> -#include <string.h> - -#include <libaudcore/audstrings.h> - -#include "debug.h" -#include "misc.h" -#include "playlist.h" -#include "plugin.h" -#include "plugins.h" -#include "probe-buffer.h" - -typedef struct -{ - const char * filename; - VFSFile * handle; - bool_t failed; - PluginHandle * plugin; -} -ProbeState; - -static bool_t check_opened (ProbeState * state) -{ - if (state->handle != NULL) - return TRUE; - if (state->failed) - return FALSE; - - AUDDBG ("Opening %s.\n", state->filename); - state->handle = probe_buffer_new (state->filename); - - if (state->handle != NULL) - return TRUE; - - AUDDBG ("FAILED.\n"); - state->failed = TRUE; - return FALSE; -} - -static bool_t probe_func (PluginHandle * plugin, ProbeState * state) -{ - AUDDBG ("Trying %s.\n", plugin_get_name (plugin)); - InputPlugin * decoder = plugin_get_header (plugin); - if (decoder == NULL) - return TRUE; - - if (decoder->is_our_file_from_vfs != NULL) - { - if (! check_opened (state)) - return FALSE; - - if (decoder->is_our_file_from_vfs (state->filename, state->handle)) - { - state->plugin = plugin; - return FALSE; - } - - if (vfs_fseek (state->handle, 0, SEEK_SET) < 0) - return FALSE; - } - - return TRUE; -} - -/* Optimization: If we have found plugins with a key match, assume that at least - * one of them will succeed. This means that we need not check the very last - * plugin. (If there is only one, we do not need to check it at all.) This is - * implemented as follows: - * - * 1. On the first call, assume until further notice the plugin passed is the - * last one and will therefore succeed. - * 2. On a subsequent call, think twice and probe the plugin we assumed would - * succeed. If it does in fact succeed, then we are done. If not, assume - * similarly that the plugin passed in this call is the last one. - */ - -static bool_t probe_func_fast (PluginHandle * plugin, ProbeState * state) -{ - if (state->plugin != NULL) - { - PluginHandle * prev = state->plugin; - state->plugin = NULL; - - if (! probe_func (prev, state)) - return FALSE; - } - - AUDDBG ("Guessing %s.\n", plugin_get_name (plugin)); - state->plugin = plugin; - return TRUE; -} - -static void probe_by_scheme (ProbeState * state) -{ - const char * s = strstr (state->filename, "://"); - if (s == NULL) - return; - - AUDDBG ("Probing by scheme.\n"); - SNCOPY (buf, state->filename, s - state->filename); - input_plugin_for_key (INPUT_KEY_SCHEME, buf, (PluginForEachFunc) probe_func_fast, state); -} - -static void probe_by_extension (ProbeState * state) -{ - char buf[32]; - if (! uri_get_extension (state->filename, buf, sizeof buf)) - return; - - AUDDBG ("Probing by extension.\n"); - input_plugin_for_key (INPUT_KEY_EXTENSION, buf, (PluginForEachFunc) probe_func_fast, state); -} - -static void probe_by_mime (ProbeState * state) -{ - char * mime; - - if (! check_opened (state)) - return; - - if ((mime = vfs_get_metadata (state->handle, "content-type")) == NULL) - return; - - AUDDBG ("Probing by MIME type.\n"); - input_plugin_for_key (INPUT_KEY_MIME, mime, (PluginForEachFunc) - probe_func_fast, state); - str_unref (mime); -} - -static void probe_by_content (ProbeState * state) -{ - AUDDBG ("Probing by content.\n"); - plugin_for_enabled (PLUGIN_TYPE_INPUT, (PluginForEachFunc) probe_func, state); -} - -PluginHandle * file_find_decoder (const char * filename, bool_t fast) -{ - ProbeState state; - - AUDDBG ("Probing %s.\n", filename); - state.plugin = NULL; - state.filename = filename; - state.handle = NULL; - state.failed = FALSE; - - probe_by_scheme (& state); - - if (state.plugin != NULL) - goto DONE; - - probe_by_extension (& state); - - if (state.plugin != NULL || fast) - goto DONE; - - probe_by_mime (& state); - - if (state.plugin != NULL) - goto DONE; - - probe_by_content (& state); - -DONE: - if (state.handle != NULL) - vfs_fclose (state.handle); - - if (state.plugin != NULL) - AUDDBG ("Probe succeeded: %s\n", plugin_get_name (state.plugin)); - else - AUDDBG ("Probe failed.\n"); - - return state.plugin; -} - -static bool_t open_file (const char * filename, InputPlugin * ip, - const char * mode, VFSFile * * handle) -{ - /* no need to open a handle for custom URI schemes */ - if (ip->schemes && ip->schemes[0]) - return TRUE; - - * handle = vfs_fopen (filename, mode); - return (* handle != NULL); -} - -Tuple * file_read_tuple (const char * filename, PluginHandle * decoder) -{ - InputPlugin * ip = plugin_get_header (decoder); - g_return_val_if_fail (ip, NULL); - g_return_val_if_fail (ip->probe_for_tuple, NULL); - - VFSFile * handle = NULL; - if (! open_file (filename, ip, "r", & handle)) - return FALSE; - - Tuple * tuple = ip->probe_for_tuple (filename, handle); - - if (handle) - vfs_fclose (handle); - - return tuple; -} - -bool_t file_read_image (const char * filename, PluginHandle * decoder, - void * * data, int64_t * size) -{ - * data = NULL; - * size = 0; - - if (! input_plugin_has_images (decoder)) - return FALSE; - - InputPlugin * ip = plugin_get_header (decoder); - g_return_val_if_fail (ip, FALSE); - g_return_val_if_fail (ip->get_song_image, FALSE); - - VFSFile * handle = NULL; - if (! open_file (filename, ip, "r", & handle)) - return FALSE; - - bool_t success = ip->get_song_image (filename, handle, data, size); - - if (handle) - vfs_fclose (handle); - - return success; -} - -bool_t file_can_write_tuple (const char * filename, PluginHandle * decoder) -{ - return input_plugin_can_write_tuple (decoder); -} - -bool_t file_write_tuple (const char * filename, PluginHandle * decoder, - const Tuple * tuple) -{ - InputPlugin * ip = plugin_get_header (decoder); - g_return_val_if_fail (ip, FALSE); - g_return_val_if_fail (ip->update_song_tuple, FALSE); - - VFSFile * handle = NULL; - if (! open_file (filename, ip, "r+", & handle)) - return FALSE; - - bool_t success = ip->update_song_tuple (filename, handle, tuple); - - if (handle) - vfs_fclose (handle); - - if (success) - playlist_rescan_file (filename); - - return success; -} - -bool_t custom_infowin (const char * filename, PluginHandle * decoder) -{ - if (! input_plugin_has_infowin (decoder)) - return FALSE; - - InputPlugin * ip = plugin_get_header (decoder); - g_return_val_if_fail (ip, FALSE); - g_return_val_if_fail (ip->file_info_box, FALSE); - - ip->file_info_box (filename); - return TRUE; -} diff --git a/src/audacious/scanner.c b/src/audacious/scanner.c deleted file mode 100644 index e3257da..0000000 --- a/src/audacious/scanner.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * scanner.c - * Copyright 2012 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <glib.h> -#include <pthread.h> -#include <stdlib.h> -#include <string.h> - -#include <libaudcore/audstrings.h> - -#include "main.h" -#include "misc.h" -#include "scanner.h" - -struct _ScanRequest { - char * filename; /* pooled */ - int flags; - PluginHandle * decoder; - ScanCallback callback; - Tuple * tuple; - void * image_data; - int64_t image_len; - char * image_file; /* pooled */ -}; - -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; - -static GQueue requests = G_QUEUE_INIT; - -static pthread_t scan_threads[SCAN_THREADS]; - -static bool_t quit_flag = FALSE; - -ScanRequest * scan_request (const char * filename, int flags, - PluginHandle * decoder, ScanCallback callback) -{ - ScanRequest * request = g_slice_new0 (ScanRequest); - - request->filename = str_get (filename); - request->flags = flags; - request->decoder = decoder; - request->callback = callback; - - pthread_mutex_lock (& mutex); - - g_queue_push_tail (& requests, request); - pthread_cond_signal (& cond); - - pthread_mutex_unlock (& mutex); - return request; -} - -static void scan_request_free (ScanRequest * request) -{ - if (request->tuple) - tuple_unref (request->tuple); - - str_unref (request->filename); - g_free (request->image_data); - str_unref (request->image_file); - g_slice_free (ScanRequest, request); -} - -static void * scan_worker (void * unused) -{ - pthread_mutex_lock (& mutex); - - while (! quit_flag) - { - ScanRequest * request = g_queue_pop_head (& requests); - - if (! request) - { - pthread_cond_wait (& cond, & mutex); - continue; - } - - pthread_mutex_unlock (& mutex); - - if (! request->decoder) - request->decoder = file_find_decoder (request->filename, FALSE); - - if (request->decoder && (request->flags & SCAN_TUPLE)) - request->tuple = file_read_tuple (request->filename, request->decoder); - - if (request->decoder && (request->flags & SCAN_IMAGE)) - { - file_read_image (request->filename, request->decoder, - & request->image_data, & request->image_len); - - if (! request->image_data) - request->image_file = get_associated_image_file (request->filename); - } - - request->callback (request); - scan_request_free (request); - - pthread_mutex_lock (& mutex); - } - - pthread_mutex_unlock (& mutex); - return NULL; -} - -const char * scan_request_get_filename (ScanRequest * request) -{ - return request->filename; -} - -PluginHandle * scan_request_get_decoder (ScanRequest * request) -{ - return request->decoder; -} - -Tuple * scan_request_get_tuple (ScanRequest * request) -{ - Tuple * tuple = request->tuple; - request->tuple = NULL; - return tuple; -} - -void scan_request_get_image_data (ScanRequest * request, void * * data, int64_t * len) -{ - * data = request->image_data; - * len = request->image_len; - request->image_data = NULL; - request->image_len = 0; -} - -const char * scan_request_get_image_file (ScanRequest * request) -{ - return request->image_file; -} - -void scanner_init (void) -{ - for (int i = 0; i < SCAN_THREADS; i ++) - pthread_create (& scan_threads[i], 0, scan_worker, NULL); -} - -void scanner_cleanup (void) -{ - pthread_mutex_lock (& mutex); - - quit_flag = TRUE; - pthread_cond_broadcast (& cond); - - pthread_mutex_unlock (& mutex); - - for (int i = 0; i < SCAN_THREADS; i ++) - pthread_join (scan_threads[i], NULL); - - ScanRequest * request; - while ((request = g_queue_pop_head (& requests))) - scan_request_free (request); - - quit_flag = FALSE; -} diff --git a/src/audacious/scanner.h b/src/audacious/scanner.h deleted file mode 100644 index 3eee728..0000000 --- a/src/audacious/scanner.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * scanner.h - * Copyright 2012 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_SCANNER_H -#define AUDACIOUS_SCANNER_H - -#include <audacious/types.h> -#include <libaudcore/tuple.h> - -#define SCAN_TUPLE (1 << 0) -#define SCAN_IMAGE (1 << 1) - -#define SCAN_THREADS 2 - -struct _ScanRequest; -typedef struct _ScanRequest ScanRequest; - -typedef void (* ScanCallback) (ScanRequest * request); - -ScanRequest * scan_request (const char * filename, int flags, - PluginHandle * decoder, ScanCallback callback); - -const char * scan_request_get_filename (ScanRequest * request); -PluginHandle * scan_request_get_decoder (ScanRequest * request); -Tuple * scan_request_get_tuple (ScanRequest * request); -void scan_request_get_image_data (ScanRequest * request, void * * data, int64_t * len); -const char * scan_request_get_image_file (ScanRequest * request); - -void scanner_init (void); -void scanner_cleanup (void); - -#endif diff --git a/src/audacious/signals.c b/src/audacious/signals.cc index 2b5515e..0a6f216 100644 --- a/src/audacious/signals.c +++ b/src/audacious/signals.cc @@ -22,7 +22,8 @@ #include <pthread.h> #include <signal.h> -#include "drct.h" +#include <libaudcore/hook.h> + #include "main.h" static sigset_t signal_set; @@ -32,9 +33,9 @@ static void * signal_thread (void * data) int signal; while (! sigwait (& signal_set, & signal)) - drct_quit (); + event_queue ("quit", nullptr); - return NULL; + return nullptr; } /* Must be called before any threads are created. */ @@ -46,13 +47,13 @@ void signals_init_one (void) sigaddset (& signal_set, SIGQUIT); sigaddset (& signal_set, SIGTERM); - sigprocmask (SIG_BLOCK, & signal_set, NULL); + sigprocmask (SIG_BLOCK, & signal_set, nullptr); } void signals_init_two (void) { pthread_t thread; - pthread_create (& thread, NULL, signal_thread, NULL); + pthread_create (& thread, nullptr, signal_thread, nullptr); } #endif /* HAVE_SIGWAIT */ diff --git a/src/audacious/types.h b/src/audacious/types.h deleted file mode 100644 index d160bab..0000000 --- a/src/audacious/types.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * types.h - * Copyright 2010-2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_TYPES_H -#define AUDACIOUS_TYPES_H - -#include <libaudcore/core.h> - -#define AUD_EQUALIZER_NBANDS 10 -#define EQUALIZER_MAX_GAIN 12 - -enum { - PLUGIN_TYPE_TRANSPORT, - PLUGIN_TYPE_PLAYLIST, - PLUGIN_TYPE_INPUT, - PLUGIN_TYPE_EFFECT, - PLUGIN_TYPE_OUTPUT, - PLUGIN_TYPE_VIS, - PLUGIN_TYPE_GENERAL, - PLUGIN_TYPE_IFACE, - PLUGIN_TYPES}; - -typedef struct PluginHandle PluginHandle; - -typedef const struct _Plugin Plugin; -typedef const struct _TransportPlugin TransportPlugin; -typedef const struct _PlaylistPlugin PlaylistPlugin; -typedef const struct _InputPlugin InputPlugin; -typedef const struct _EffectPlugin EffectPlugin; -typedef const struct _OutputPlugin OutputPlugin; -typedef const struct _VisPlugin VisPlugin; -typedef const struct _GeneralPlugin GeneralPlugin; -typedef const struct _IfacePlugin IfacePlugin; - -typedef struct _PluginPreferences PluginPreferences; -typedef struct _PreferencesWidget PreferencesWidget; - -typedef struct { - char * name; - float preamp; - float bands[AUD_EQUALIZER_NBANDS]; -} EqualizerPreset; - -typedef struct { - float track_gain; /* dB */ - float track_peak; /* 0-1 */ - float album_gain; /* dB */ - float album_peak; /* 0-1 */ -} ReplayGainInfo; - -#endif diff --git a/src/audacious/ui_albumart.c b/src/audacious/ui_albumart.c deleted file mode 100644 index a3f14a4..0000000 --- a/src/audacious/ui_albumart.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * ui_albumart.c - * Copyright 2006-2013 Michael Hanselmann, Yoshiki Yazawa, and John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <glib.h> -#include <string.h> - -#include <libaudcore/audstrings.h> - -#include "i18n.h" -#include "main.h" -#include "misc.h" -#include "util.h" - -typedef struct { - const char * basename; - Index * include, * exclude; -} SearchParams; - -static bool_t has_front_cover_extension (const char * name) -{ - char * ext = strrchr (name, '.'); - if (! ext) - return FALSE; - - return ! g_ascii_strcasecmp (ext, ".jpg") || - ! g_ascii_strcasecmp (ext, ".jpeg") || ! g_ascii_strcasecmp (ext, ".png"); -} - -static bool_t cover_name_filter (const char * name, Index * keywords, bool_t ret_on_empty) -{ - int count = index_count (keywords); - if (! count) - return ret_on_empty; - - for (int i = 0; i < count; i ++) - { - if (strstr_nocase (name, index_get (keywords, i))) - return TRUE; - } - - return FALSE; -} - -static bool_t is_file_image (const char * imgfile, const char * file_name) -{ - char * imgfile_ext = strrchr (imgfile, '.'); - if (! imgfile_ext) - return FALSE; - - char * file_name_ext = strrchr (file_name, '.'); - if (! file_name_ext) - return FALSE; - - size_t imgfile_len = imgfile_ext - imgfile; - size_t file_name_len = file_name_ext - file_name; - - return imgfile_len == file_name_len && ! g_ascii_strncasecmp (imgfile, file_name, imgfile_len); -} - -static char * fileinfo_recursive_get_image (const char * path, - const SearchParams * params, int depth) -{ - GDir * d = g_dir_open (path, 0, NULL); - if (! d) - return NULL; - - const char * name; - - if (get_bool (NULL, "use_file_cover") && ! depth) - { - /* Look for images matching file name */ - while ((name = g_dir_read_name (d))) - { - char * newpath = filename_build (path, name); - - if (! g_file_test (newpath, G_FILE_TEST_IS_DIR) && - has_front_cover_extension (name) && - is_file_image (name, params->basename)) - { - g_dir_close (d); - return newpath; - } - - str_unref (newpath); - } - - g_dir_rewind (d); - } - - /* Search for files using filter */ - while ((name = g_dir_read_name (d))) - { - char * newpath = filename_build (path, name); - - if (! g_file_test (newpath, G_FILE_TEST_IS_DIR) && - has_front_cover_extension (name) && - cover_name_filter (name, params->include, TRUE) && - ! cover_name_filter (name, params->exclude, FALSE)) - { - g_dir_close (d); - return newpath; - } - - str_unref (newpath); - } - - g_dir_rewind (d); - - if (get_bool (NULL, "recurse_for_cover") && depth < get_int (NULL, "recurse_for_cover_depth")) - { - /* Descend into directories recursively. */ - while ((name = g_dir_read_name (d))) - { - char * newpath = filename_build (path, name); - - if (g_file_test (newpath, G_FILE_TEST_IS_DIR)) - { - char * tmp = fileinfo_recursive_get_image (newpath, params, depth + 1); - - if (tmp) - { - str_unref (newpath); - g_dir_close (d); - return tmp; - } - } - - str_unref (newpath); - } - } - - g_dir_close (d); - return NULL; -} - -char * get_associated_image_file (const char * filename) -{ - char * image_uri = NULL; - - char * local = uri_to_filename (filename); - char * base = local ? last_path_element (local) : NULL; - - if (local && base) - { - char * include = get_str (NULL, "cover_name_include"); - char * exclude = get_str (NULL, "cover_name_exclude"); - - SearchParams params = { - .basename = base, - .include = str_list_to_index (include, ", "), - .exclude = str_list_to_index (exclude, ", ") - }; - - str_unref (include); - str_unref (exclude); - - SNCOPY (path, local, base - 1 - local); - - char * image_local = fileinfo_recursive_get_image (path, & params, 0); - if (image_local) - image_uri = filename_to_uri (image_local); - - str_unref (image_local); - - index_free_full (params.include, (IndexFreeFunc) str_unref); - index_free_full (params.exclude, (IndexFreeFunc) str_unref); - } - - str_unref (local); - - return image_uri; -} diff --git a/src/audacious/ui_plugin_menu.c b/src/audacious/ui_plugin_menu.c deleted file mode 100644 index 9d81b65..0000000 --- a/src/audacious/ui_plugin_menu.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * ui_plugin_menu.c - * Copyright 2009-2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <glib.h> -#include <gtk/gtk.h> - -#include <libaudgui/menu.h> - -#include "i18n.h" -#include "misc.h" - -static GList * items[AUD_MENU_COUNT]; /* of AudguiMenuItem */ -static GtkWidget * menus[AUD_MENU_COUNT]; - -static void configure_plugins (void) -{ - show_prefs_for_plugin_type (PLUGIN_TYPE_GENERAL); -} - -static const AudguiMenuItem main_items[] = { - {N_("_Plugins ..."), .func = configure_plugins}, - {.sep = TRUE} -}; - -static void add_to_menu (GtkWidget * menu, const AudguiMenuItem * item) -{ - GtkWidget * widget = audgui_menu_item_new_with_domain (item, NULL, NULL); - g_object_set_data ((GObject *) widget, "func", (void *) item->func); - gtk_widget_show (widget); - gtk_menu_shell_append ((GtkMenuShell *) menu, widget); -} - -/* GtkWidget * get_plugin_menu (int id) */ -void * get_plugin_menu (int id) -{ - if (! menus[id]) - { - menus[id] = gtk_menu_new (); - g_signal_connect (menus[id], "destroy", (GCallback) - gtk_widget_destroyed, & menus[id]); - - if (id == AUD_MENU_MAIN) - audgui_menu_init (menus[id], main_items, ARRAY_LEN (main_items), NULL); - - for (GList * node = items[id]; node; node = node->next) - add_to_menu (menus[id], node->data); - } - - return menus[id]; -} - -void plugin_menu_add (int id, MenuFunc func, const char * name, - const char * icon) -{ - AudguiMenuItem * item = g_slice_new0 (AudguiMenuItem); - item->name = name; - item->icon = icon; - item->func = func; - - items[id] = g_list_append (items[id], item); - - if (menus[id]) - add_to_menu (menus[id], item); -} - -static void remove_cb (GtkWidget * widget, MenuFunc func) -{ - if ((MenuFunc) g_object_get_data ((GObject *) widget, "func") == func) - gtk_widget_destroy (widget); -} - -void plugin_menu_remove (int id, MenuFunc func) -{ - if (menus[id]) - gtk_container_foreach ((GtkContainer *) menus[id], (GtkCallback) - remove_cb, (void *) func); - - GList * next; - for (GList * node = items[id]; node; node = next) - { - next = node->next; - - if (((AudguiMenuItem *) node->data)->func == func) - { - g_slice_free (AudguiMenuItem, node->data); - items[id] = g_list_delete_link (items[id], node); - } - } -} diff --git a/src/audacious/ui_preferences.c b/src/audacious/ui_preferences.c deleted file mode 100644 index 2949fdc..0000000 --- a/src/audacious/ui_preferences.c +++ /dev/null @@ -1,814 +0,0 @@ -/* - * ui_preferences.c - * Copyright 2006-2012 William Pitcock, Tomasz Moń, Michael Färber, and - * John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <string.h> - -#include <gdk/gdkkeysyms.h> -#include <gtk/gtk.h> - -#include <libaudcore/audstrings.h> -#include <libaudcore/hook.h> -#include <libaudgui/libaudgui-gtk.h> - -#include "debug.h" -#include "i18n.h" -#include "misc.h" -#include "output.h" -#include "playlist.h" -#include "plugin.h" -#include "plugins.h" -#include "preferences.h" -#include "ui_preferences.h" - -#ifdef USE_CHARDET -#include <libguess.h> -#endif - -enum CategoryViewCols { - CATEGORY_VIEW_COL_ICON, - CATEGORY_VIEW_COL_NAME, - CATEGORY_VIEW_N_COLS -}; - -typedef struct { - const char * icon_path; - const char * name; -} Category; - -typedef struct { - int type; - const char * name; -} PluginCategory; - -typedef struct { - const char * name; - const char * tag; -} TitleFieldTag; - -static const char aud_version_string[] = - "<span size='small'>Audacious " VERSION " (" BUILDSTAMP ")</span>"; - -static GtkWidget * prefswin; -static GtkWidget * category_treeview, * category_notebook, * plugin_notebook; -static GtkWidget * titlestring_entry; - -enum { - CATEGORY_APPEARANCE = 0, - CATEGORY_AUDIO, - CATEGORY_NETWORK, - CATEGORY_PLAYLIST, - CATEGORY_SONG_INFO, - CATEGORY_PLUGINS -}; - -static const Category categories[] = { - { "appearance.png", N_("Appearance") }, - { "audio.png", N_("Audio") }, - { "connectivity.png", N_("Network") }, - { "playlist.png", N_("Playlist")} , - { "info.png", N_("Song Info") }, - { "plugins.png", N_("Plugins") } -}; - -static const PluginCategory plugin_categories[] = { - { PLUGIN_TYPE_GENERAL, N_("General") }, - { PLUGIN_TYPE_EFFECT, N_("Effect") }, - { PLUGIN_TYPE_VIS, N_("Visualization") }, - { PLUGIN_TYPE_INPUT, N_("Input") }, - { PLUGIN_TYPE_PLAYLIST, N_("Playlist") }, - { PLUGIN_TYPE_TRANSPORT, N_("Transport") } -}; - -static TitleFieldTag title_field_tags[] = { - { N_("Artist") , "${artist}" }, - { N_("Album") , "${album}" }, - { N_("Title") , "${title}" }, - { N_("Tracknumber"), "${track-number}" }, - { N_("Genre") , "${genre}" }, - { N_("Filename") , "${file-name}" }, - { N_("Filepath") , "${file-path}" }, - { N_("Date") , "${date}" }, - { N_("Year") , "${year}" }, - { N_("Comment") , "${comment}" }, - { N_("Codec") , "${codec}" }, - { N_("Quality") , "${quality}" } -}; - -#ifdef USE_CHARDET -static ComboBoxElements chardet_detector_presets[] = { - { "", N_("None")}, - { GUESS_REGION_AR, N_("Arabic") }, - { GUESS_REGION_BL, N_("Baltic") }, - { GUESS_REGION_CN, N_("Chinese") }, - { GUESS_REGION_GR, N_("Greek") }, - { GUESS_REGION_HW, N_("Hebrew") }, - { GUESS_REGION_JP, N_("Japanese") }, - { GUESS_REGION_KR, N_("Korean") }, - { GUESS_REGION_PL, N_("Polish") }, - { GUESS_REGION_RU, N_("Russian") }, - { GUESS_REGION_TW, N_("Taiwanese") }, - { GUESS_REGION_TR, N_("Turkish") } -}; -#endif - -static ComboBoxElements bitdepth_elements[] = { - { GINT_TO_POINTER (16), "16" }, - { GINT_TO_POINTER (24), "24" }, - { GINT_TO_POINTER (32), "32" }, - { GINT_TO_POINTER (0), N_("Floating point") } -}; - -static GArray * iface_combo_elements; -static int iface_combo_selected; -static GtkWidget * iface_prefs_box; - -static const ComboBoxElements * iface_combo_fill (int * n_elements); -static void iface_combo_changed (void); -static void * iface_create_prefs_box (void); - -static PreferencesWidget appearance_page_widgets[] = { - {WIDGET_LABEL, N_("<b>Interface Settings</b>")}, - {WIDGET_COMBO_BOX, N_("Interface plugin:"), - .cfg_type = VALUE_INT, .cfg = & iface_combo_selected, - .data.combo.fill = iface_combo_fill, .callback = iface_combo_changed}, - {WIDGET_CUSTOM, .data.populate = iface_create_prefs_box}}; - -static GArray * output_combo_elements; -static int output_combo_selected; -static GtkWidget * output_config_button; -static GtkWidget * output_about_button; - -static const ComboBoxElements * output_combo_fill (int * n_elements); -static void output_combo_changed (void); -static void * output_create_config_button (void); -static void * output_create_about_button (void); -static void output_bit_depth_changed (void); - -static PreferencesWidget output_combo_widgets[] = { - {WIDGET_COMBO_BOX, N_("Output plugin:"), - .cfg_type = VALUE_INT, .cfg = & output_combo_selected, - .data.combo.fill = output_combo_fill, .callback = output_combo_changed}, - {WIDGET_CUSTOM, .data.populate = output_create_config_button}, - {WIDGET_CUSTOM, .data.populate = output_create_about_button}}; - -static PreferencesWidget audio_page_widgets[] = { - {WIDGET_LABEL, N_("<b>Output Settings</b>")}, - {WIDGET_BOX, .data.box = {.elem = output_combo_widgets, - .n_elem = ARRAY_LEN (output_combo_widgets), .horizontal = TRUE}}, - {WIDGET_COMBO_BOX, N_("Bit depth:"), - .cfg_type = VALUE_INT, .cname = "output_bit_depth", .callback = output_bit_depth_changed, - .data.combo = {bitdepth_elements, ARRAY_LEN (bitdepth_elements)}}, - {WIDGET_SPIN_BTN, N_("Buffer size:"), - .cfg_type = VALUE_INT, .cname = "output_buffer_size", - .data.spin_btn = {100, 10000, 1000, N_("ms")}}, - {WIDGET_CHK_BTN, N_("Soft clipping"), - .cfg_type = VALUE_BOOLEAN, .cname = "soft_clipping"}, - {WIDGET_CHK_BTN, N_("Use software volume control (not recommended)"), - .cfg_type = VALUE_BOOLEAN, .cname = "software_volume_control"}, - {WIDGET_LABEL, N_("<b>Replay Gain</b>")}, - {WIDGET_CHK_BTN, N_("Enable Replay Gain"), - .cfg_type = VALUE_BOOLEAN, .cname = "enable_replay_gain"}, - {WIDGET_CHK_BTN, N_("Album mode"), .child = TRUE, - .cfg_type = VALUE_BOOLEAN, .cname = "replay_gain_album"}, - {WIDGET_CHK_BTN, N_("Prevent clipping (recommended)"), .child = TRUE, - .cfg_type = VALUE_BOOLEAN, .cname = "enable_clipping_prevention"}, - {WIDGET_LABEL, N_("<b>Adjust Levels</b>"), .child = TRUE}, - {WIDGET_SPIN_BTN, N_("Amplify all files:"), .child = TRUE, - .cfg_type = VALUE_FLOAT, .cname = "replay_gain_preamp", - .data.spin_btn = {-15, 15, 0.1, N_("dB")}}, - {WIDGET_SPIN_BTN, N_("Amplify untagged files:"), .child = TRUE, - .cfg_type = VALUE_FLOAT, .cname = "default_gain", - .data.spin_btn = {-15, 15, 0.1, N_("dB")}}}; - -static PreferencesWidget proxy_host_port_elements[] = { - {WIDGET_ENTRY, N_("Proxy hostname:"), .cfg_type = VALUE_STRING, .cname = "proxy_host"}, - {WIDGET_ENTRY, N_("Proxy port:"), .cfg_type = VALUE_STRING, .cname = "proxy_port"}}; - -static PreferencesWidget proxy_auth_elements[] = { - {WIDGET_ENTRY, N_("Proxy username:"), .cfg_type = VALUE_STRING, .cname = "proxy_user"}, - {WIDGET_ENTRY, N_("Proxy password:"), .cfg_type = VALUE_STRING, .cname = "proxy_pass", - .data.entry.password = TRUE}}; - -static PreferencesWidget connectivity_page_widgets[] = { - {WIDGET_LABEL, N_("<b>Proxy Configuration</b>"), NULL, NULL, NULL, FALSE}, - {WIDGET_CHK_BTN, N_("Enable proxy usage"), .cfg_type = VALUE_BOOLEAN, .cname = "use_proxy"}, - {WIDGET_TABLE, .child = TRUE, .data.table = {proxy_host_port_elements, - ARRAY_LEN (proxy_host_port_elements)}}, - {WIDGET_CHK_BTN, N_("Use authentication with proxy"), - .cfg_type = VALUE_BOOLEAN, .cname = "use_proxy_auth"}, - {WIDGET_TABLE, .child = TRUE, .data.table = {proxy_auth_elements, - ARRAY_LEN (proxy_auth_elements)}}}; - -static PreferencesWidget chardet_elements[] = { -#ifdef USE_CHARDET - {WIDGET_COMBO_BOX, N_("Auto character encoding detector for:"), - .cfg_type = VALUE_STRING, .cname = "chardet_detector", .child = TRUE, - .data.combo = {chardet_detector_presets, ARRAY_LEN (chardet_detector_presets)}}, -#endif - {WIDGET_ENTRY, N_("Fallback character encodings:"), .cfg_type = VALUE_STRING, - .cname = "chardet_fallback", .child = TRUE}}; - -static PreferencesWidget playlist_page_widgets[] = { - {WIDGET_LABEL, N_("<b>Behavior</b>"), NULL, NULL, NULL, FALSE}, - {WIDGET_CHK_BTN, N_("Continue playback on startup"), - .cfg_type = VALUE_BOOLEAN, .cname = "resume_playback_on_startup"}, - {WIDGET_CHK_BTN, N_("Advance when the current song is deleted"), - .cfg_type = VALUE_BOOLEAN, .cname = "advance_on_delete"}, - {WIDGET_CHK_BTN, N_("Clear the playlist when opening files"), - .cfg_type = VALUE_BOOLEAN, .cname = "clear_playlist"}, - {WIDGET_CHK_BTN, N_("Open files in a temporary playlist"), - .cfg_type = VALUE_BOOLEAN, .cname = "open_to_temporary"}, - {WIDGET_CHK_BTN, N_("Do not load metadata for songs until played"), - .cfg_type = VALUE_BOOLEAN, .cname = "metadata_on_play", - .callback = playlist_trigger_scan}, - {WIDGET_LABEL, N_("<b>Compatibility</b>"), NULL, NULL, NULL, FALSE}, - {WIDGET_CHK_BTN, N_("Interpret \\ (backward slash) as a folder delimiter"), - .cfg_type = VALUE_BOOLEAN, .cname = "convert_backslash"}, - {WIDGET_TABLE, .data.table = {chardet_elements, ARRAY_LEN (chardet_elements)}}}; - -static PreferencesWidget song_info_page_widgets[] = { - {WIDGET_LABEL, N_("<b>Album Art</b>")}, - {WIDGET_LABEL, N_("Search for images matching these words (comma-separated):")}, - {WIDGET_ENTRY, .cfg_type = VALUE_STRING, .cname = "cover_name_include"}, - {WIDGET_LABEL, N_("Exclude images matching these words (comma-separated):")}, - {WIDGET_ENTRY, .cfg_type = VALUE_STRING, .cname = "cover_name_exclude"}, - {WIDGET_CHK_BTN, N_("Search for images matching song file name"), - .cfg_type = VALUE_BOOLEAN, .cname = "use_file_cover"}, - {WIDGET_CHK_BTN, N_("Search recursively"), - .cfg_type = VALUE_BOOLEAN, .cname = "recurse_for_cover"}, - {WIDGET_SPIN_BTN, N_("Search depth:"), .child = TRUE, - .cfg_type = VALUE_INT, .cname = "recurse_for_cover_depth", - .data.spin_btn = {0, 100, 1}}, - {WIDGET_LABEL, N_("<b>Popup Information</b>")}, - {WIDGET_CHK_BTN, N_("Show popup information"), - .cfg_type = VALUE_BOOLEAN, .cname = "show_filepopup_for_tuple"}, - {WIDGET_SPIN_BTN, N_("Popup delay (tenths of a second):"), .child = TRUE, - .cfg_type = VALUE_INT, .cname = "filepopup_delay", - .data.spin_btn = {0, 100, 1}}, - {WIDGET_CHK_BTN, N_("Show time scale for current song"), .child = TRUE, - .cfg_type = VALUE_BOOLEAN, .cname = "filepopup_showprogressbar"}}; - -#define TITLESTRING_NPRESETS 6 - -static const char * const titlestring_presets[TITLESTRING_NPRESETS] = { - "${title}", - "${?artist:${artist} - }${title}", - "${?artist:${artist} - }${?album:${album} - }${title}", - "${?artist:${artist} - }${?album:${album} - }${?track-number:${track-number}. }${title}", - "${?artist:${artist} }${?album:[ ${album} ] }${?artist:- }${?track-number:${track-number}. }${title}", - "${?album:${album} - }${title}" -}; - -static const char * const titlestring_preset_names[TITLESTRING_NPRESETS] = { - N_("TITLE"), - N_("ARTIST - TITLE"), - N_("ARTIST - ALBUM - TITLE"), - N_("ARTIST - ALBUM - TRACK. TITLE"), - N_("ARTIST [ ALBUM ] - TRACK. TITLE"), - N_("ALBUM - TITLE") -}; - -static GArray * fill_plugin_combo (int type) -{ - GArray * array = g_array_new (FALSE, FALSE, sizeof (ComboBoxElements)); - g_array_set_size (array, plugin_count (type)); - - for (int i = 0; i < array->len; i ++) - { - ComboBoxElements * elem = & g_array_index (array, ComboBoxElements, i); - elem->label = plugin_get_name (plugin_by_index (type, i)); - elem->value = GINT_TO_POINTER (i); - } - - return array; -} - -static void change_category (int category) -{ - GtkTreeSelection * selection = gtk_tree_view_get_selection ((GtkTreeView *) category_treeview); - GtkTreePath * path = gtk_tree_path_new_from_indices (category, -1); - gtk_tree_selection_select_path (selection, path); - gtk_tree_path_free (path); -} - -static void category_changed (GtkTreeSelection * selection) -{ - GtkTreeModel * model; - GtkTreeIter iter; - - if (gtk_tree_selection_get_selected (selection, & model, & iter)) - { - GtkTreePath * path = gtk_tree_model_get_path (model, & iter); - int category = gtk_tree_path_get_indices (path)[0]; - gtk_notebook_set_current_page ((GtkNotebook *) category_notebook, category); - gtk_tree_path_free (path); - } -} - -static void titlestring_tag_menu_cb (GtkMenuItem * menuitem, void * data) -{ - const char * separator = " - "; - int item = GPOINTER_TO_INT (data); - int pos = gtk_editable_get_position ((GtkEditable *) titlestring_entry); - - /* insert separator as needed */ - if (gtk_entry_get_text ((GtkEntry *) titlestring_entry)[0]) - gtk_editable_insert_text ((GtkEditable *) titlestring_entry, separator, -1, & pos); - - gtk_editable_insert_text ((GtkEditable *) titlestring_entry, _(title_field_tags[item].tag), -1, & pos); - gtk_editable_set_position ((GtkEditable *) titlestring_entry, pos); -} - -static void on_titlestring_help_button_clicked (GtkButton * button, void * menu) -{ - gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME); -} - -static void update_titlestring_cbox (GtkComboBox * cbox, const char * format) -{ - int preset; - for (preset = 0; preset < TITLESTRING_NPRESETS; preset ++) - { - if (! strcmp (titlestring_presets[preset], format)) - break; - } - - if (gtk_combo_box_get_active (cbox) != preset) - gtk_combo_box_set_active (cbox, preset); -} - -static void on_titlestring_entry_changed (GtkEntry * entry, GtkComboBox * cbox) -{ - const char * format = gtk_entry_get_text (entry); - set_str (NULL, "generic_title_format", format); - update_titlestring_cbox (cbox, format); - playlist_reformat_titles (); -} - -static void on_titlestring_cbox_changed (GtkComboBox * cbox, GtkEntry * entry) -{ - int preset = gtk_combo_box_get_active (cbox); - if (preset < TITLESTRING_NPRESETS) - gtk_entry_set_text (entry, titlestring_presets[preset]); -} - -static void fill_category_list (GtkTreeView * treeview, GtkNotebook * notebook) -{ - GtkTreeViewColumn * column = gtk_tree_view_column_new (); - gtk_tree_view_column_set_title (column, _("Category")); - gtk_tree_view_append_column (treeview, column); - gtk_tree_view_column_set_spacing (column, 2); - - GtkCellRenderer * renderer = gtk_cell_renderer_pixbuf_new (); - gtk_tree_view_column_pack_start (column, renderer, FALSE); - gtk_tree_view_column_set_attributes (column, renderer, "pixbuf", 0, NULL); - - renderer = gtk_cell_renderer_text_new (); - gtk_tree_view_column_pack_start (column, renderer, FALSE); - gtk_tree_view_column_set_attributes (column, renderer, "text", 1, NULL); - - g_object_set ((GObject *) renderer, "wrap-width", 96, "wrap-mode", - PANGO_WRAP_WORD_CHAR, NULL); - - GtkListStore * store = gtk_list_store_new (CATEGORY_VIEW_N_COLS, - GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT); - gtk_tree_view_set_model (treeview, (GtkTreeModel *) store); - - const char * data_dir = get_path (AUD_PATH_DATA_DIR); - - for (int i = 0; i < ARRAY_LEN (categories); i ++) - { - SCONCAT3 (path, data_dir, "/images/", categories[i].icon_path); - - GtkTreeIter iter; - - gtk_list_store_append (store, & iter); - gtk_list_store_set (store, & iter, CATEGORY_VIEW_COL_NAME, - gettext (categories[i].name), -1); - - GdkPixbuf * img = gdk_pixbuf_new_from_file (path, NULL); - - if (img) - { - gtk_list_store_set (store, & iter, CATEGORY_VIEW_COL_ICON, img, -1); - g_object_unref (img); - } - } - - g_object_unref (store); - - GtkTreeSelection * selection = gtk_tree_view_get_selection (treeview); - g_signal_connect (selection, "changed", (GCallback) category_changed, NULL); -} - -static GtkWidget * create_titlestring_tag_menu (void) -{ - GtkWidget * titlestring_tag_menu = gtk_menu_new (); - - for (int i = 0; i < ARRAY_LEN (title_field_tags); i ++) - { - GtkWidget * menu_item = gtk_menu_item_new_with_label (_(title_field_tags[i].name)); - gtk_menu_shell_append ((GtkMenuShell *) titlestring_tag_menu, menu_item); - g_signal_connect(menu_item, "activate", - (GCallback) titlestring_tag_menu_cb, GINT_TO_POINTER (i)); - }; - - gtk_widget_show_all (titlestring_tag_menu); - - return titlestring_tag_menu; -} - -static void show_numbers_cb (GtkToggleButton * numbers, void * unused) -{ - set_bool (NULL, "show_numbers_in_pl", gtk_toggle_button_get_active (numbers)); - playlist_reformat_titles (); - hook_call ("title change", NULL); -} - -static void leading_zero_cb (GtkToggleButton * leading) -{ - set_bool (NULL, "leading_zero", gtk_toggle_button_get_active (leading)); - playlist_reformat_titles (); - hook_call ("title change", NULL); -} - -static void create_titlestring_widgets (GtkWidget * * cbox, GtkWidget * * entry) -{ - * cbox = gtk_combo_box_text_new (); - for (int i = 0; i < TITLESTRING_NPRESETS; i ++) - gtk_combo_box_text_append_text ((GtkComboBoxText *) * cbox, _(titlestring_preset_names[i])); - gtk_combo_box_text_append_text ((GtkComboBoxText *) * cbox, _("Custom")); - - * entry = gtk_entry_new (); - - char * format = get_str (NULL, "generic_title_format"); - update_titlestring_cbox ((GtkComboBox *) * cbox, format); - gtk_entry_set_text ((GtkEntry *) * entry, format); - str_unref (format); - - g_signal_connect (* cbox, "changed", (GCallback) on_titlestring_cbox_changed, * entry); - g_signal_connect (* entry, "changed", (GCallback) on_titlestring_entry_changed, * cbox); -} - -static void create_playlist_category (void) -{ - GtkWidget * vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_container_add ((GtkContainer *) category_notebook, vbox); - - create_widgets ((GtkBox *) vbox, playlist_page_widgets, ARRAY_LEN (playlist_page_widgets)); - - GtkWidget * alignment = gtk_alignment_new (0.5, 0.5, 1, 1); - gtk_box_pack_start ((GtkBox *) vbox, alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding ((GtkAlignment *) alignment, 12, 3, 0, 0); - - GtkWidget * label = gtk_label_new (_("<b>Song Display</b>")); - gtk_container_add ((GtkContainer *) alignment, label); - gtk_label_set_use_markup ((GtkLabel *) label, TRUE); - gtk_misc_set_alignment ((GtkMisc *) label, 0, 0.5); - - GtkWidget * numbers_alignment = gtk_alignment_new (0, 0, 0, 0); - gtk_alignment_set_padding ((GtkAlignment *) numbers_alignment, 0, 0, 12, 0); - gtk_box_pack_start ((GtkBox *) vbox, numbers_alignment, 0, 0, 3); - - GtkWidget * numbers = gtk_check_button_new_with_label (_("Show song numbers")); - gtk_toggle_button_set_active ((GtkToggleButton *) numbers, - get_bool (NULL, "show_numbers_in_pl")); - g_signal_connect (numbers, "toggled", (GCallback) show_numbers_cb, 0); - gtk_container_add ((GtkContainer *) numbers_alignment, numbers); - - numbers_alignment = gtk_alignment_new (0, 0, 0, 0); - gtk_alignment_set_padding ((GtkAlignment *) numbers_alignment, 0, 0, 12, 0); - gtk_box_pack_start ((GtkBox *) vbox, numbers_alignment, 0, 0, 3); - - numbers = gtk_check_button_new_with_label ( - _("Show leading zeroes (02:00 instead of 2:00)")); - gtk_toggle_button_set_active ((GtkToggleButton *) numbers, get_bool (NULL, "leading_zero")); - g_signal_connect (numbers, "toggled", (GCallback) leading_zero_cb, 0); - gtk_container_add ((GtkContainer *) numbers_alignment, numbers); - - alignment = gtk_alignment_new (0.5, 0.5, 1, 1); - gtk_box_pack_start ((GtkBox *) vbox, alignment, FALSE, FALSE, 0); - gtk_alignment_set_padding ((GtkAlignment *) alignment, 0, 0, 12, 0); - - GtkWidget * grid = gtk_grid_new (); - gtk_container_add ((GtkContainer *) alignment, grid); - gtk_grid_set_row_spacing ((GtkGrid *) grid, 4); - gtk_grid_set_column_spacing ((GtkGrid *) grid, 12); - - label = gtk_label_new (_("Title format:")); - gtk_grid_attach ((GtkGrid *) grid, label, 0, 0, 1, 1); - gtk_label_set_justify ((GtkLabel *) label, GTK_JUSTIFY_RIGHT); - gtk_misc_set_alignment ((GtkMisc *) label, 1, 0.5); - - label = gtk_label_new (_("Custom string:")); - gtk_grid_attach ((GtkGrid *) grid, label, 0, 1, 1, 1); - gtk_label_set_justify ((GtkLabel *) label, GTK_JUSTIFY_RIGHT); - gtk_misc_set_alignment ((GtkMisc *) label, 1, 0.5); - - GtkWidget * titlestring_cbox; - create_titlestring_widgets (& titlestring_cbox, & titlestring_entry); - gtk_widget_set_hexpand (titlestring_cbox, TRUE); - gtk_widget_set_hexpand (titlestring_entry, TRUE); - gtk_grid_attach ((GtkGrid *) grid, titlestring_cbox, 1, 0, 1, 1); - gtk_grid_attach ((GtkGrid *) grid, titlestring_entry, 1, 1, 1, 1); - - GtkWidget * titlestring_help_button = gtk_button_new (); - gtk_widget_set_can_focus (titlestring_help_button, FALSE); - gtk_button_set_focus_on_click ((GtkButton *) titlestring_help_button, FALSE); - gtk_button_set_relief ((GtkButton *) titlestring_help_button, GTK_RELIEF_HALF); - gtk_grid_attach ((GtkGrid *) grid, titlestring_help_button, 2, 1, 1, 1); - - GtkWidget * titlestring_tag_menu = create_titlestring_tag_menu (); - - g_signal_connect (titlestring_help_button, "clicked", - (GCallback) on_titlestring_help_button_clicked, titlestring_tag_menu); - - GtkWidget * image = gtk_image_new_from_icon_name ("list-add", GTK_ICON_SIZE_BUTTON); - gtk_container_add ((GtkContainer *) titlestring_help_button, image); -} - -static void create_song_info_category (void) -{ - GtkWidget * vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_container_add ((GtkContainer *) category_notebook, vbox); - create_widgets ((GtkBox *) vbox, song_info_page_widgets, - ARRAY_LEN (song_info_page_widgets)); -} - -static void iface_fill_prefs_box (void) -{ - Plugin * header = plugin_get_header (plugin_get_current (PLUGIN_TYPE_IFACE)); - if (header && header->prefs) - create_widgets_with_domain (iface_prefs_box, header->prefs->widgets, - header->prefs->n_widgets, header->domain); -} - -static void iface_combo_changed (void) -{ - gtk_container_foreach ((GtkContainer *) iface_prefs_box, (GtkCallback) gtk_widget_destroy, NULL); - - plugin_enable (plugin_by_index (PLUGIN_TYPE_IFACE, iface_combo_selected), TRUE); - - iface_fill_prefs_box (); - gtk_widget_show_all (iface_prefs_box); -} - -static const ComboBoxElements * iface_combo_fill (int * n_elements) -{ - if (! iface_combo_elements) - { - iface_combo_elements = fill_plugin_combo (PLUGIN_TYPE_IFACE); - iface_combo_selected = plugin_get_index (plugin_get_current (PLUGIN_TYPE_IFACE)); - } - - * n_elements = iface_combo_elements->len; - return (const ComboBoxElements *) iface_combo_elements->data; -} - -static void * iface_create_prefs_box (void) -{ - iface_prefs_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - iface_fill_prefs_box (); - return iface_prefs_box; -} - -static void create_appearance_category (void) -{ - GtkWidget * vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_container_add ((GtkContainer *) category_notebook, vbox); - create_widgets ((GtkBox *) vbox, appearance_page_widgets, ARRAY_LEN (appearance_page_widgets)); -} - -static void output_combo_changed (void) -{ - PluginHandle * plugin = plugin_by_index (PLUGIN_TYPE_OUTPUT, output_combo_selected); - - if (plugin_enable (plugin, TRUE)) - { - gtk_widget_set_sensitive (output_config_button, plugin_has_configure (plugin)); - gtk_widget_set_sensitive (output_about_button, plugin_has_about (plugin)); - } -} - -static const ComboBoxElements * output_combo_fill (int * n_elements) -{ - if (! output_combo_elements) - { - output_combo_elements = fill_plugin_combo (PLUGIN_TYPE_OUTPUT); - output_combo_selected = plugin_get_index (output_plugin_get_current ()); - } - - * n_elements = output_combo_elements->len; - return (const ComboBoxElements *) output_combo_elements->data; -} - -static void output_bit_depth_changed (void) -{ - output_reset (OUTPUT_RESET_SOFT); -} - -static void output_do_config (void * unused) -{ - plugin_do_configure (output_plugin_get_current ()); -} - -static void output_do_about (void * unused) -{ - plugin_do_about (output_plugin_get_current ()); -} - -static void * output_create_config_button (void) -{ - bool_t enabled = plugin_has_configure (output_plugin_get_current ()); - - output_config_button = audgui_button_new (_("_Settings"), - "preferences-system", output_do_config, NULL); - gtk_widget_set_sensitive (output_config_button, enabled); - - return output_config_button; -} - -static void * output_create_about_button (void) -{ - bool_t enabled = plugin_has_about (output_plugin_get_current ()); - - output_about_button = audgui_button_new (_("_About"), "help-about", output_do_about, NULL); - gtk_widget_set_sensitive (output_about_button, enabled); - - return output_about_button; -} - -static void create_audio_category (void) -{ - GtkWidget * audio_page_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - create_widgets ((GtkBox *) audio_page_vbox, audio_page_widgets, ARRAY_LEN (audio_page_widgets)); - gtk_container_add ((GtkContainer *) category_notebook, audio_page_vbox); -} - -static void create_connectivity_category (void) -{ - GtkWidget * connectivity_page_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_container_add ((GtkContainer *) category_notebook, connectivity_page_vbox); - - GtkWidget * vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_box_pack_start ((GtkBox *) connectivity_page_vbox, vbox, TRUE, TRUE, 0); - - create_widgets ((GtkBox *) vbox, connectivity_page_widgets, ARRAY_LEN (connectivity_page_widgets)); -} - -static void create_plugin_category (void) -{ - plugin_notebook = gtk_notebook_new (); - gtk_container_add ((GtkContainer *) category_notebook, plugin_notebook); - - for (int i = 0; i < ARRAY_LEN (plugin_categories); i ++) - { - const PluginCategory * cat = & plugin_categories[i]; - gtk_notebook_append_page ((GtkNotebook *) plugin_notebook, - plugin_view_new (cat->type), gtk_label_new (_(cat->name))); - } -} - -static void destroy_cb (void) -{ - prefswin = NULL; - category_treeview = NULL; - category_notebook = NULL; - titlestring_entry = NULL; - - if (iface_combo_elements) - { - g_array_free (iface_combo_elements, TRUE); - iface_combo_elements = NULL; - } - - if (output_combo_elements) - { - g_array_free (output_combo_elements, TRUE); - output_combo_elements = NULL; - } -} - -static void create_prefs_window (void) -{ - prefswin = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_type_hint ((GtkWindow *) prefswin, GDK_WINDOW_TYPE_HINT_DIALOG); - gtk_container_set_border_width ((GtkContainer *) prefswin, 12); - gtk_window_set_title ((GtkWindow *) prefswin, _("Audacious Settings")); - gtk_window_set_default_size ((GtkWindow *) prefswin, 680, 400); - - GtkWidget * vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_container_add ((GtkContainer *) prefswin, vbox); - - GtkWidget * hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8); - gtk_box_pack_start ((GtkBox *) vbox, hbox, TRUE, TRUE, 0); - - GtkWidget * scrolledwindow = gtk_scrolled_window_new (NULL, NULL); - gtk_box_pack_start ((GtkBox *) hbox, scrolledwindow, FALSE, FALSE, 0); - gtk_scrolled_window_set_policy ((GtkScrolledWindow *) scrolledwindow, - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type ((GtkScrolledWindow *) scrolledwindow, GTK_SHADOW_IN); - - category_treeview = gtk_tree_view_new (); - gtk_container_add ((GtkContainer *) scrolledwindow, category_treeview); - gtk_widget_set_size_request (scrolledwindow, 168, -1); - gtk_tree_view_set_headers_visible ((GtkTreeView *) category_treeview, FALSE); - - category_notebook = gtk_notebook_new (); - gtk_box_pack_start ((GtkBox *) hbox, category_notebook, TRUE, TRUE, 0); - - gtk_widget_set_can_focus (category_notebook, FALSE); - gtk_notebook_set_show_tabs ((GtkNotebook *) category_notebook, FALSE); - gtk_notebook_set_show_border ((GtkNotebook *) category_notebook, FALSE); - - create_appearance_category (); - create_audio_category (); - create_connectivity_category (); - create_playlist_category (); - create_song_info_category (); - create_plugin_category (); - - GtkWidget * hseparator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); - gtk_box_pack_start ((GtkBox *) vbox, hseparator, FALSE, FALSE, 6); - - hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - gtk_box_pack_start ((GtkBox *) vbox, hbox, FALSE, FALSE, 0); - - GtkWidget * audversionlabel = gtk_label_new (aud_version_string); - gtk_box_pack_start ((GtkBox *) hbox, audversionlabel, FALSE, FALSE, 0); - gtk_label_set_use_markup ((GtkLabel *) audversionlabel, TRUE); - - GtkWidget * prefswin_button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); - gtk_box_pack_start ((GtkBox *) hbox, prefswin_button_box, TRUE, TRUE, 0); - gtk_button_box_set_layout ((GtkButtonBox *) prefswin_button_box, GTK_BUTTONBOX_END); - gtk_box_set_spacing ((GtkBox *) prefswin_button_box, 6); - - GtkWidget * close = audgui_button_new (_("_Close"), "window-close", - (AudguiCallback) gtk_widget_destroy, prefswin); - gtk_container_add ((GtkContainer *) prefswin_button_box, close); - gtk_widget_set_can_default (close, TRUE); - - fill_category_list ((GtkTreeView *) category_treeview, (GtkNotebook *) category_notebook); - - gtk_widget_show_all (vbox); - - g_signal_connect (prefswin, "destroy", (GCallback) destroy_cb, NULL); - - audgui_destroy_on_escape (prefswin); -} - -void show_prefs_window (void) -{ - if (! prefswin) - create_prefs_window (); - - change_category (CATEGORY_APPEARANCE); - - gtk_window_present ((GtkWindow *) prefswin); -} - -void show_prefs_for_plugin_type (int type) -{ - if (! prefswin) - create_prefs_window (); - - if (type == PLUGIN_TYPE_IFACE) - change_category (CATEGORY_APPEARANCE); - else if (type == PLUGIN_TYPE_OUTPUT) - change_category (CATEGORY_AUDIO); - else - { - change_category (CATEGORY_PLUGINS); - - for (int i = 0; i < ARRAY_LEN (plugin_categories); i ++) - { - if (plugin_categories[i].type == type) - gtk_notebook_set_current_page ((GtkNotebook *) plugin_notebook, i); - } - } - - gtk_window_present ((GtkWindow *) prefswin); -} - -void hide_prefs_window (void) -{ - if (prefswin) - gtk_widget_destroy (prefswin); -} diff --git a/src/audacious/ui_preferences.h b/src/audacious/ui_preferences.h deleted file mode 100644 index b9b2707..0000000 --- a/src/audacious/ui_preferences.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * ui_preferences.h - * Copyright 2006-2012 William Pitcock, Tomasz Moń, and John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_UI_PREFERENCES_H -#define AUDACIOUS_UI_PREFERENCES_H - -#include <gtk/gtk.h> - -#include "types.h" - -void show_prefs_window(void); -void hide_prefs_window(void); - -/* plugin-preferences.c */ -void plugin_make_about_window (PluginHandle * plugin); -void plugin_make_config_window (PluginHandle * plugin); -void plugin_misc_cleanup (PluginHandle * plugin); - -/* plugin-view.c */ -GtkWidget * plugin_view_new (int type); - -#endif /* AUDACIOUS_UI_PREFERENCES_H */ diff --git a/src/audacious/util.c b/src/audacious/util.c deleted file mode 100644 index 3556e68..0000000 --- a/src/audacious/util.c +++ /dev/null @@ -1,474 +0,0 @@ -/* - * util.c - * Copyright 2009-2013 John Lindgren and Michał Lipski - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <ctype.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#ifdef _WIN32 -#include <windows.h> -#endif - -#ifdef __APPLE__ -#include <mach-o/dyld.h> -#endif - -#include <glib.h> - -#include <libaudcore/audstrings.h> - -#include "debug.h" -#include "i18n.h" -#include "misc.h" -#include "plugins.h" -#include "util.h" - -bool_t dir_foreach (const char * path, DirForeachFunc func, void * user) -{ - GDir * dir = g_dir_open (path, 0, NULL); - if (! dir) - return FALSE; - - const char * name; - while ((name = g_dir_read_name (dir))) - { - char * full = filename_build (path, name); - bool_t stop = func (full, name, user); - str_unref (full); - - if (stop) - break; - } - - g_dir_close (dir); - return TRUE; -} - -char * construct_uri (const char * path, const char * reference) -{ - /* URI */ - if (strstr (path, "://")) - return str_get (path); - - /* absolute filename */ -#ifdef _WIN32 - if (path[0] && path[1] == ':' && path[2] == '\\') -#else - if (path[0] == '/') -#endif - return filename_to_uri (path); - - /* relative path */ - const char * slash = strrchr (reference, '/'); - if (! slash) - return NULL; - - char * utf8 = str_to_utf8 (path, -1); - if (! utf8) - return NULL; - - int pathlen = slash + 1 - reference; - - char buf[pathlen + 3 * strlen (utf8) + 1]; - memcpy (buf, reference, pathlen); - - if (get_bool (NULL, "convert_backslash")) - { - SCOPY (tmp, utf8); - str_replace_char (tmp, '\\', '/'); - str_encode_percent (tmp, -1, buf + pathlen); - } - else - str_encode_percent (utf8, -1, buf + pathlen); - - str_unref (utf8); - return str_get (buf); -} - -void -make_directory(const char * path, mode_t mode) -{ - if (g_mkdir_with_parents(path, mode) == 0) - return; - - g_printerr(_("Could not create directory (%s): %s\n"), path, - g_strerror(errno)); -} - -char * write_temp_file (void * data, int64_t len) -{ - char * temp = filename_build (g_get_tmp_dir (), "audacious-temp-XXXXXX"); - SCOPY (name, temp); - str_unref (temp); - - int handle = g_mkstemp (name); - if (handle < 0) - { - fprintf (stderr, "Error creating temporary file: %s\n", strerror (errno)); - return NULL; - } - - while (len) - { - int64_t written = write (handle, data, len); - if (written < 0) - { - fprintf (stderr, "Error writing %s: %s\n", name, strerror (errno)); - close (handle); - return NULL; - } - - data = (char *) data + written; - len -= written; - } - - if (close (handle) < 0) - { - fprintf (stderr, "Error closing %s: %s\n", name, strerror (errno)); - return NULL; - } - - return str_get (name); -} - -char * get_path_to_self (void) -{ -#ifdef HAVE_PROC_SELF_EXE - int size = 256; - - while (1) - { - char buf[size]; - int len; - - if ((len = readlink ("/proc/self/exe", buf, size)) < 0) - { - fprintf (stderr, "Cannot access /proc/self/exe: %s.\n", strerror (errno)); - return NULL; - } - - if (len < size) - { - buf[len] = 0; - return str_get (buf); - } - - size += size; - } -#elif defined _WIN32 - int size = 256; - - while (1) - { - wchar_t buf[size]; - int len; - - if (! (len = GetModuleFileNameW (NULL, buf, size))) - { - fprintf (stderr, "GetModuleFileName failed.\n"); - return NULL; - } - - if (len < size) - { - char * temp = g_utf16_to_utf8 (buf, len, NULL, NULL, NULL); - char * path = str_get (temp); - g_free (temp); - return path; - } - - size += size; - } -#elif defined __APPLE__ - unsigned int size = 256; - - while (1) - { - char buf[size]; - int res; - - if (! (res = _NSGetExecutablePath (buf, &size))) - return str_get (buf); - - if (res != -1) - return NULL; - } -#else - return NULL; -#endif -} - -#ifdef _WIN32 -void get_argv_utf8 (int * argc, char * * * argv) -{ - wchar_t * combined = GetCommandLineW (); - wchar_t * * split = CommandLineToArgvW (combined, argc); - - * argv = g_new (char *, argc + 1); - - for (int i = 0; i < * argc; i ++) - (* argv)[i] = g_utf16_to_utf8 (split[i], -1, NULL, NULL, NULL); - - (* argv)[* argc] = 0; - - LocalFree (split); -} - -void free_argv_utf8 (int * argc, char * * * argv) -{ - g_strfreev (* argv); - * argc = 0; - * argv = NULL; -} -#endif - -/* Strips various common top-level folders from a filename. The string passed - * will not be modified, but the string returned will share the same memory. - * Examples: - * "/home/john/folder/file.mp3" -> "folder/file.mp3" - * "/folder/file.mp3" -> "folder/file.mp3" */ - -static char * skip_top_folders (char * name) -{ - static const char * home; - static int len; - - if (! home) - { - home = g_get_home_dir (); - len = strlen (home); - - if (len > 0 && home[len - 1] == G_DIR_SEPARATOR) - len --; - } - -#ifdef _WIN32 - if (! g_ascii_strncasecmp (name, home, len) && name[len] == '\\') -#else - if (! strncmp (name, home, len) && name[len] == '/') -#endif - return name + len + 1; - -#ifdef _WIN32 - if (g_ascii_isalpha (name[0]) && name[1] == ':' && name[2] == '\\') - return name + 3; -#else - if (name[0] == '/') - return name + 1; -#endif - - return name; -} - -/* Divides a filename into the base name, the lowest folder, and the - * second lowest folder. The string passed will be modified, and the strings - * returned will use the same memory. May return NULL for <first> and <second>. - * Examples: - * "a/b/c/d/e.mp3" -> "e", "d", "c" - * "d/e.mp3" -> "e", "d", NULL - * "e.mp3" -> "e", NULL, NULL */ - -static void split_filename (char * name, char * * base, char * * first, - char * * second) -{ - * first = * second = NULL; - - char * c; - - if ((c = strrchr (name, G_DIR_SEPARATOR))) - { - * base = c + 1; - * c = 0; - } - else - { - * base = name; - goto DONE; - } - - if ((c = strrchr (name, G_DIR_SEPARATOR))) - { - * first = c + 1; - * c = 0; - } - else - { - * first = name; - goto DONE; - } - - if ((c = strrchr (name, G_DIR_SEPARATOR))) - * second = c + 1; - else - * second = name; - -DONE: - if ((c = strrchr (* base, '.'))) - * c = 0; -} - -/* Separates the domain name from an internet URI. The string passed will be - * modified, and the string returned will share the same memory. May return - * NULL. Examples: - * "http://some.domain.org/folder/file.mp3" -> "some.domain.org" - * "http://some.stream.fm:8000" -> "some.stream.fm" */ - -static char * stream_name (char * name) -{ - if (! strncmp (name, "http://", 7)) - name += 7; - else if (! strncmp (name, "https://", 8)) - name += 8; - else if (! strncmp (name, "mms://", 6)) - name += 6; - else - return NULL; - - char * c; - - if ((c = strchr (name, '/'))) - * c = 0; - if ((c = strchr (name, ':'))) - * c = 0; - if ((c = strchr (name, '?'))) - * c = 0; - - return name; -} - -static char * get_nonblank_field (const Tuple * tuple, int field) -{ - char * str = tuple ? tuple_get_str (tuple, field) : NULL; - - if (str && ! str[0]) - { - str_unref (str); - str = NULL; - } - - return str; -} - -static char * str_get_decoded (char * str) -{ - if (! str) - return NULL; - - str_decode_percent (str, -1, str); - return str_get (str); -} - -/* Derives best guesses of title, artist, and album from a file name (URI) and - * tuple (which may be NULL). The returned strings are stringpooled or NULL. */ - -void describe_song (const char * name, const Tuple * tuple, char * * _title, - char * * _artist, char * * _album) -{ - /* Common folder names to skip */ - static const char * const skip[] = {"music"}; - - char * title = get_nonblank_field (tuple, FIELD_TITLE); - char * artist = get_nonblank_field (tuple, FIELD_ARTIST); - char * album = get_nonblank_field (tuple, FIELD_ALBUM); - - if (title && artist && album) - { -DONE: - * _title = title; - * _artist = artist; - * _album = album; - return; - } - - if (! strncmp (name, "file:///", 8)) - { - char * filename = uri_to_display (name); - if (! filename) - goto DONE; - - SCOPY (buf, filename); - - char * base, * first, * second; - split_filename (skip_top_folders (buf), & base, & first, & second); - - if (! title) - title = str_get (base); - - for (int i = 0; i < ARRAY_LEN (skip); i ++) - { - if (first && ! g_ascii_strcasecmp (first, skip[i])) - first = NULL; - if (second && ! g_ascii_strcasecmp (second, skip[i])) - second = NULL; - } - - if (first) - { - if (second && ! artist && ! album) - { - artist = str_get (second); - album = str_get (first); - } - else if (! artist) - artist = str_get (first); - else if (! album) - album = str_get (first); - } - - str_unref (filename); - } - else - { - SCOPY (buf, name); - - if (! title) - { - title = str_get_decoded (stream_name (buf)); - - if (! title) - title = str_get_decoded (buf); - } - else if (! artist) - artist = str_get_decoded (stream_name (buf)); - else if (! album) - album = str_get_decoded (stream_name (buf)); - } - - goto DONE; -} - -char * last_path_element (char * path) -{ - char * slash = strrchr (path, G_DIR_SEPARATOR); - return (slash && slash[1]) ? slash + 1 : NULL; -} - -void cut_path_element (char * path, char * elem) -{ -#ifdef _WIN32 - if (elem > path + 3) -#else - if (elem > path + 1) -#endif - elem[-1] = 0; /* overwrite slash */ - else - elem[0] = 0; /* leave [drive letter and] leading slash */ -} diff --git a/src/audacious/debug.h b/src/audacious/util.cc index 2b372ad..c4449de 100644 --- a/src/audacious/debug.h +++ b/src/audacious/util.cc @@ -1,6 +1,6 @@ /* - * debug.h - * Copyright 2010-2011 John Lindgren + * util.c + * Copyright 2009-2013 John Lindgren and Michał Lipski * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -17,17 +17,32 @@ * the use of this software. */ -#ifndef AUDACIOUS_DEBUG_H -#define AUDACIOUS_DEBUG_H +#include "util.h" -#include <stdio.h> +#ifdef _WIN32 +#include <windows.h> -#include <audacious/api.h> - -#ifdef _AUDACIOUS_CORE -#define AUDDBG(...) do {if (verbose) {printf ("%s:%d [%s]: ", __FILE__, __LINE__, __FUNCTION__); printf (__VA_ARGS__);}} while (0) +#ifdef WORDS_BIGENDIAN +#define UTF16_NATIVE "UTF-16BE" #else -#define AUDDBG(...) do {if (* _aud_api_table->verbose) {printf ("%s:%d [%s]: ", __FILE__, __LINE__, __FUNCTION__); printf (__VA_ARGS__);}} while (0) +#define UTF16_NATIVE "UTF-16LE" #endif +Index<String> get_argv_utf8 () +{ + int argc; + wchar_t * combined = GetCommandLineW (); + wchar_t * * split = CommandLineToArgvW (combined, & argc); + + Index<String> argv; + argv.insert (0, argc); + + for (int i = 0; i < argc; i ++) + argv[i] = String (str_convert ((char *) split[i], + wcslen (split[i]) * sizeof (wchar_t), UTF16_NATIVE, "UTF-8")); + + LocalFree (split); + return argv; +} + #endif diff --git a/src/audacious/util.h b/src/audacious/util.h index 7f92cb3..55bfd6b 100644 --- a/src/audacious/util.h +++ b/src/audacious/util.h @@ -1,6 +1,6 @@ /* * util.h - * Copyright 2009-2013 John Lindgren + * Copyright 2014 John Lindgren * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -20,29 +20,10 @@ #ifndef AUDACIOUS_UTIL_H #define AUDACIOUS_UTIL_H -#include <sys/types.h> -#include <libaudcore/core.h> - -typedef bool_t(*DirForeachFunc) (const char * path, - const char * basename, - void * user_data); - -bool_t dir_foreach (const char * path, DirForeachFunc func, void * user_data); - -void make_directory(const char * path, mode_t mode); -char * write_temp_file (void * data, int64_t len); /* pooled */ - -char * get_path_to_self (void); /* pooled */ +#include <libaudcore/audstrings.h> #ifdef _WIN32 -void get_argv_utf8 (int * argc, char * * * argv); -void free_argv_utf8 (int * argc, char * * * argv); +Index<String> get_argv_utf8 (); #endif -void describe_song (const char * filename, const Tuple * tuple, - char * * title, char * * artist, char * * album); - -char * last_path_element (char * path); -void cut_path_element (char * path, char * elem); - #endif /* AUDACIOUS_UTIL_H */ diff --git a/src/audacious/vis_runner.c b/src/audacious/vis_runner.c deleted file mode 100644 index ba8390c..0000000 --- a/src/audacious/vis_runner.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - * vis_runner.c - * Copyright 2009-2012 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <assert.h> -#include <pthread.h> -#include <stdint.h> -#include <string.h> - -#include <glib.h> - -#include "output.h" -#include "vis_runner.h" -#include "visualization.h" - -#define INTERVAL 30 /* milliseconds */ -#define FRAMES_PER_NODE 512 - -struct _VisNode { - struct _VisNode * next; - int channels; - int time; - float data[]; -}; - -typedef struct _VisNode VisNode; - -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -static bool_t enabled = FALSE; -static bool_t playing = FALSE, paused = FALSE, active = FALSE; -static VisNode * current_node = NULL; -static int current_frames; -static VisNode * vis_list = NULL; -static VisNode * vis_list_tail = NULL; -static VisNode * vis_pool = NULL; -static int send_source = 0, clear_source = 0; - -static VisNode * alloc_node_locked (int channels) -{ - VisNode * node; - - if (vis_pool) - { - node = vis_pool; - assert (node->channels == channels); - vis_pool = node->next; - } - else - { - node = g_malloc (offsetof (VisNode, data) + sizeof (float) * channels * FRAMES_PER_NODE); - node->channels = channels; - } - - node->next = NULL; - return node; -} - -static void free_node_locked (VisNode * node) -{ - node->next = vis_pool; - vis_pool = node; -} - -static void push_node_locked (VisNode * node) -{ - if (vis_list) - vis_list_tail->next = node; - else - vis_list = node; - - vis_list_tail = node; -} - -static VisNode * pop_node_locked (void) -{ - VisNode * node = vis_list; - vis_list = node->next; - node->next = NULL; - - if (vis_list_tail == node) - vis_list_tail = NULL; - - return node; -} - -static bool_t send_audio (void * unused) -{ - /* call before locking mutex to avoid deadlock */ - int outputted = output_get_raw_time (); - - pthread_mutex_lock (& mutex); - - if (! send_source) - { - pthread_mutex_unlock (& mutex); - return FALSE; - } - - VisNode * vis_node = NULL; - - while (vis_list) - { - /* If we are considering a node, stop searching and use it if it is the - * most recent (that is, the next one is in the future). Otherwise, - * consider the next node if it is not in the future by more than the - * length of an interval. */ - if (vis_list->time > outputted + (vis_node ? 0 : INTERVAL)) - break; - - if (vis_node) - free_node_locked (vis_node); - - vis_node = pop_node_locked (); - } - - pthread_mutex_unlock (& mutex); - - if (! vis_node) - return TRUE; - - vis_send_audio (vis_node->data, vis_node->channels); - - pthread_mutex_lock (& mutex); - free_node_locked (vis_node); - pthread_mutex_unlock (& mutex); - - return TRUE; -} - -static bool_t send_clear (void * unused) -{ - pthread_mutex_lock (& mutex); - clear_source = 0; - pthread_mutex_unlock (& mutex); - - vis_send_clear (); - - return FALSE; -} - -static void flush_locked (void) -{ - g_free (current_node); - current_node = NULL; - - while (vis_list) - { - VisNode * node = vis_list; - vis_list = node->next; - g_free (node); - } - - vis_list_tail = NULL; - - while (vis_pool) - { - VisNode * node = vis_pool; - vis_pool = node->next; - g_free (node); - } - - if (! clear_source) - clear_source = g_timeout_add (0, send_clear, NULL); -} - -void vis_runner_flush (void) -{ - pthread_mutex_lock (& mutex); - flush_locked (); - pthread_mutex_unlock (& mutex); -} - -static void start_stop_locked (bool_t new_playing, bool_t new_paused) -{ - playing = new_playing; - paused = new_paused; - active = playing && enabled; - - if (send_source) - { - g_source_remove (send_source); - send_source = 0; - } - - if (clear_source) - { - g_source_remove (clear_source); - clear_source = 0; - } - - if (! active) - flush_locked (); - else if (! paused) - send_source = g_timeout_add (INTERVAL, send_audio, NULL); -} - -void vis_runner_start_stop (bool_t new_playing, bool_t new_paused) -{ - pthread_mutex_lock (& mutex); - start_stop_locked (new_playing, new_paused); - pthread_mutex_unlock (& mutex); -} - -void vis_runner_pass_audio (int time, float * data, int samples, int - channels, int rate) -{ - pthread_mutex_lock (& mutex); - - if (! active) - goto UNLOCK; - - /* We can build a single node from multiple calls; we can also build - * multiple nodes from the same call. If current_node is present, it was - * partly built in the last call and needs to be finished. */ - - int at = 0; - - while (1) - { - if (current_node) - assert (current_node->channels == channels); - else - { - int node_time = time; - - /* There is no partly-built node, so start a new one. Normally - * there will be nodes in the queue already; if so, we want to copy - * audio data from the signal starting at 30 milliseconds after the - * beginning of the most recent node. If there are no nodes in the - * queue, we are at the beginning of the song or had an underrun, - * and we want to copy the earliest audio data we have. */ - - if (vis_list_tail) - node_time = vis_list_tail->time + INTERVAL; - - at = channels * (int) ((int64_t) (node_time - time) * rate / 1000); - - if (at < 0) - at = 0; - if (at >= samples) - break; - - current_node = alloc_node_locked (channels); - current_node->time = node_time; - current_frames = 0; - } - - /* Copy as much data as we can, limited by how much we have and how much - * space is left in the node. If we cannot fill the node, we return and - * wait for more data to be passed in the next call. If we do fill the - * node, we loop and start building a new one. */ - - int copy = MIN (samples - at, channels * (FRAMES_PER_NODE - current_frames)); - memcpy (current_node->data + channels * current_frames, data + at, sizeof (float) * copy); - current_frames += copy / channels; - - if (current_frames < FRAMES_PER_NODE) - break; - - push_node_locked (current_node); - current_node = NULL; - } - -UNLOCK: - pthread_mutex_unlock (& mutex); -} - -void vis_runner_enable (bool_t enable) -{ - pthread_mutex_lock (& mutex); - enabled = enable; - start_stop_locked (playing, paused); - pthread_mutex_unlock (& mutex); -} diff --git a/src/audacious/vis_runner.h b/src/audacious/vis_runner.h deleted file mode 100644 index 4b08c5b..0000000 --- a/src/audacious/vis_runner.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * vis_runner.h - * Copyright 2009-2010 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUD_VIS_RUNNER_H -#define AUD_VIS_RUNNER_H - -#include <libaudcore/core.h> - -void vis_runner_start_stop (bool_t playing, bool_t paused); -void vis_runner_pass_audio (int time, float * data, int samples, int channels, int rate); -void vis_runner_flush (void); -void vis_runner_enable (bool_t enable); - -#endif diff --git a/src/audacious/visualization.c b/src/audacious/visualization.c deleted file mode 100644 index 85ef430..0000000 --- a/src/audacious/visualization.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * visualization.c - * Copyright 2010-2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#include <glib.h> -#include <gtk/gtk.h> -#include <string.h> - -#include "debug.h" -#include "fft.h" -#include "interface.h" -#include "misc.h" -#include "plugin.h" -#include "plugins.h" -#include "ui_preferences.h" -#include "visualization.h" -#include "vis_runner.h" - -static GList * vis_funcs[AUD_VIS_TYPES]; - -typedef struct { - PluginHandle * plugin; - VisPlugin * header; - GtkWidget * widget; -} LoadedVis; - -static int running = FALSE; -static GList * loaded_vis_plugins = NULL; - -void vis_func_add (int type, GCallback func) -{ - g_return_if_fail (type >= 0 && type < AUD_VIS_TYPES); - vis_funcs[type] = g_list_prepend (vis_funcs[type], (void *) func); - - vis_runner_enable (TRUE); -} - -void vis_func_remove (GCallback func) -{ - bool_t disable = TRUE; - - for (int i = 0; i < AUD_VIS_TYPES; i ++) - { - vis_funcs[i] = g_list_remove_all (vis_funcs[i], (void *) func); - if (vis_funcs[i]) - disable = FALSE; - } - - if (disable) - vis_runner_enable (FALSE); -} - -void vis_send_clear (void) -{ - for (GList * node = vis_funcs[AUD_VIS_TYPE_CLEAR]; node; node = node->next) - { - void (* func) (void) = (void (*) (void)) node->data; - func (); - } -} - -static void pcm_to_mono (const float * data, float * mono, int channels) -{ - if (channels == 1) - memcpy (mono, data, sizeof (float) * 512); - else - { - float * set = mono; - while (set < & mono[512]) - { - * set ++ = (data[0] + data[1]) / 2; - data += channels; - } - } -} - -void vis_send_audio (const float * data, int channels) -{ - float mono[512]; - float freq[256]; - - if (vis_funcs[AUD_VIS_TYPE_MONO_PCM] || vis_funcs[AUD_VIS_TYPE_FREQ]) - pcm_to_mono (data, mono, channels); - if (vis_funcs[AUD_VIS_TYPE_FREQ]) - calc_freq (mono, freq); - - for (GList * node = vis_funcs[AUD_VIS_TYPE_MONO_PCM]; node; node = node->next) - { - void (* func) (const float *) = (void (*) (const float *)) node->data; - func (mono); - } - - for (GList * node = vis_funcs[AUD_VIS_TYPE_MULTI_PCM]; node; node = node->next) - { - void (* func) (const float *, int) = (void (*) (const float *, int)) node->data; - func (data, channels); - } - - for (GList * node = vis_funcs[AUD_VIS_TYPE_FREQ]; node; node = node->next) - { - void (* func) (const float *) = (void (*) (const float *)) node->data; - func (freq); - } -} - -static int vis_find_cb (LoadedVis * vis, PluginHandle * plugin) -{ - return (vis->plugin == plugin) ? 0 : -1; -} - -static void vis_load (PluginHandle * plugin) -{ - GList * node = g_list_find_custom (loaded_vis_plugins, plugin, - (GCompareFunc) vis_find_cb); - if (node != NULL) - return; - - AUDDBG ("Loading %s.\n", plugin_get_name (plugin)); - VisPlugin * header = plugin_get_header (plugin); - g_return_if_fail (header != NULL); - - LoadedVis * vis = g_slice_new (LoadedVis); - vis->plugin = plugin; - vis->header = header; - vis->widget = NULL; - - if (header->get_widget != NULL) - vis->widget = header->get_widget (); - - if (vis->widget != NULL) - { - AUDDBG ("Adding %s to interface.\n", plugin_get_name (plugin)); - g_signal_connect (vis->widget, "destroy", (GCallback) - gtk_widget_destroyed, & vis->widget); - interface_add_plugin_widget (plugin, vis->widget); - } - - if (PLUGIN_HAS_FUNC (header, clear)) - vis_func_add (AUD_VIS_TYPE_CLEAR, (GCallback) header->clear); - if (PLUGIN_HAS_FUNC (header, render_mono_pcm)) - vis_func_add (AUD_VIS_TYPE_MONO_PCM, (GCallback) header->render_mono_pcm); - if (PLUGIN_HAS_FUNC (header, render_multi_pcm)) - vis_func_add (AUD_VIS_TYPE_MULTI_PCM, (GCallback) header->render_multi_pcm); - if (PLUGIN_HAS_FUNC (header, render_freq)) - vis_func_add (AUD_VIS_TYPE_FREQ, (GCallback) header->render_freq); - - loaded_vis_plugins = g_list_prepend (loaded_vis_plugins, vis); -} - -static void vis_unload (PluginHandle * plugin) -{ - GList * node = g_list_find_custom (loaded_vis_plugins, plugin, - (GCompareFunc) vis_find_cb); - if (node == NULL) - return; - - AUDDBG ("Unloading %s.\n", plugin_get_name (plugin)); - LoadedVis * vis = node->data; - loaded_vis_plugins = g_list_delete_link (loaded_vis_plugins, node); - - VisPlugin * header = vis->header; - if (PLUGIN_HAS_FUNC (header, clear)) - vis_func_remove ((GCallback) header->clear); - if (PLUGIN_HAS_FUNC (header, render_mono_pcm)) - vis_func_remove ((GCallback) header->render_mono_pcm); - if (PLUGIN_HAS_FUNC (header, render_multi_pcm)) - vis_func_remove ((GCallback) header->render_multi_pcm); - if (PLUGIN_HAS_FUNC (header, render_freq)) - vis_func_remove ((GCallback) header->render_freq); - - if (vis->widget != NULL) - { - AUDDBG ("Removing %s from interface.\n", plugin_get_name (plugin)); - interface_remove_plugin_widget (plugin, vis->widget); - g_return_if_fail (vis->widget == NULL); /* not destroyed? */ - } - - g_slice_free (LoadedVis, vis); -} - -static bool_t vis_init_cb (PluginHandle * plugin) -{ - vis_load (plugin); - return TRUE; -} - -void vis_init (void) -{ - g_return_if_fail (! running); - running = TRUE; - - plugin_for_enabled (PLUGIN_TYPE_VIS, (PluginForEachFunc) vis_init_cb, NULL); -} - -static void vis_cleanup_cb (LoadedVis * vis) -{ - vis_unload (vis->plugin); -} - -void vis_cleanup (void) -{ - g_return_if_fail (running); - running = FALSE; - - g_list_foreach (loaded_vis_plugins, (GFunc) vis_cleanup_cb, NULL); -} - -bool_t vis_plugin_start (PluginHandle * plugin) -{ - VisPlugin * vp = plugin_get_header (plugin); - g_return_val_if_fail (vp != NULL, FALSE); - - if (vp->init != NULL && ! vp->init ()) - return FALSE; - - if (running) - vis_load (plugin); - - return TRUE; -} - -void vis_plugin_stop (PluginHandle * plugin) -{ - VisPlugin * vp = plugin_get_header (plugin); - g_return_if_fail (vp != NULL); - - if (running) - vis_unload (plugin); - - if (vp->cleanup != NULL) - vp->cleanup (); -} - -PluginHandle * vis_plugin_by_widget (/* GtkWidget * */ void * widget) -{ - g_return_val_if_fail (widget, NULL); - - for (GList * node = loaded_vis_plugins; node; node = node->next) - { - LoadedVis * vis = node->data; - if (vis->widget == widget) - return vis->plugin; - } - - return NULL; -} diff --git a/src/audacious/visualization.h b/src/audacious/visualization.h deleted file mode 100644 index f57e86e..0000000 --- a/src/audacious/visualization.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * visualization.h - * Copyright 2010-2011 John Lindgren - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions, and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions, and the following disclaimer in the documentation - * provided with the distribution. - * - * This software is provided "as is" and without any warranty, express or - * implied. In no event shall the authors be liable for any damages arising from - * the use of this software. - */ - -#ifndef AUDACIOUS_VISUALIZATION_H -#define AUDACIOUS_VISUALIZATION_H - -#include "plugins.h" - -void vis_send_clear (void); -void vis_send_audio (const float * data, int channels); - -void vis_init (void); -void vis_cleanup (void); - -bool_t vis_plugin_start (PluginHandle * plugin); -void vis_plugin_stop (PluginHandle * plugin); - -PluginHandle * vis_plugin_by_widget (/* GtkWidget * */ void * widget); - -#endif |