Mercurial > audlegacy
view src/audacious/pluginenum.c @ 4768:d470630b8cea
The famed "multiple plugins in one module" feature didn't actually work,
because structure indices were being indexed by same variable (which was
never reset for different plugin structs.) Fixed.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Wed, 13 Aug 2008 21:33:54 +0300 |
parents | f084f639e962 |
children | c2dc7a3a7240 |
line wrap: on
line source
/* Audacious - Cross-platform multimedia player * Copyright (C) 2005-2007 Audacious development team * * Based on BMP: * Copyright (C) 2003-2004 BMP development team * * Based on XMMS: * Copyright (C) 1998-2003 XMMS development team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; under version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses>. * * The Audacious team does not consider modular code linking to * Audacious or using our public API to be a derived work. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifndef SHARED_SUFFIX # define SHARED_SUFFIX G_MODULE_SUFFIX #endif #include <glib.h> #include <glib/gi18n.h> #include <glib/gprintf.h> #include <gmodule.h> #include <string.h> #include "pluginenum.h" #include "discovery.h" #include "effect.h" #include "general.h" #include "input.h" #include "main.h" #include "output.h" #include "playback.h" #include "playlist.h" #include "strings.h" #include "util.h" #include "visualization.h" #include "preferences.h" #include "vfs_buffer.h" #include "vfs_buffered_file.h" #include "volumecontrol.h" #include "equalizer_preset.h" #include "ui_fileinfo.h" #include "ui_fileinfopopup.h" #include "ui_plugin_menu.h" #include "ui_preferences.h" const gchar *plugin_dir_list[] = { PLUGINSUBS, NULL }; GHashTable *ext_hash = NULL; static void set_pvt_data(Plugin * plugin, gpointer data); static gpointer get_pvt_data(void); /*****************************************************************/ static struct _AudaciousFuncTableV1 _aud_papi_v1 = { .vfs_fopen = vfs_fopen, .vfs_fclose = vfs_fclose, .vfs_dup = vfs_dup, .vfs_fread = vfs_fread, .vfs_fwrite = vfs_fwrite, .vfs_getc = vfs_getc, .vfs_ungetc = vfs_ungetc, .vfs_fgets = vfs_fgets, .vfs_fseek = vfs_fseek, .vfs_rewind = vfs_rewind, .vfs_ftell = vfs_ftell, .vfs_feof = vfs_feof, .vfs_file_test = vfs_file_test, .vfs_is_writeable = vfs_is_writeable, .vfs_truncate = vfs_truncate, .vfs_fsize = vfs_fsize, .vfs_get_metadata = vfs_get_metadata, .vfs_fprintf = vfs_fprintf, .vfs_register_transport = vfs_register_transport, .vfs_file_get_contents = vfs_file_get_contents, .vfs_is_remote = vfs_is_remote, .vfs_is_streaming = vfs_is_streaming, .vfs_buffer_new = vfs_buffer_new, .vfs_buffer_new_from_string = vfs_buffer_new_from_string, .vfs_buffered_file_new_from_uri = vfs_buffered_file_new_from_uri, .vfs_buffered_file_release_live_fd = vfs_buffered_file_release_live_fd, .vfs_fget_le16 = vfs_fget_le16, .vfs_fget_le32 = vfs_fget_le32, .vfs_fget_le64 = vfs_fget_le64, .vfs_fget_be16 = vfs_fget_be16, .vfs_fget_be32 = vfs_fget_be32, .vfs_fget_be64 = vfs_fget_be64, .cfg_db_open = cfg_db_open, .cfg_db_close = cfg_db_close, .cfg_db_get_string = cfg_db_get_string, .cfg_db_get_int = cfg_db_get_int, .cfg_db_get_bool = cfg_db_get_bool, .cfg_db_get_float = cfg_db_get_float, .cfg_db_get_double = cfg_db_get_double, .cfg_db_set_string = cfg_db_set_string, .cfg_db_set_int = cfg_db_set_int, .cfg_db_set_bool = cfg_db_set_bool, .cfg_db_set_float = cfg_db_set_float, .cfg_db_set_double = cfg_db_set_double, .cfg_db_unset_key = cfg_db_unset_key, .tuple_new = tuple_new, .tuple_new_from_filename = tuple_new_from_filename, .tuple_associate_string = tuple_associate_string, .tuple_associate_int = tuple_associate_int, .tuple_disassociate = tuple_disassociate, .tuple_get_value_type = tuple_get_value_type, .tuple_get_string = tuple_get_string, .tuple_get_int = tuple_get_int, .tuple_formatter_process_string = tuple_formatter_process_string, .tuple_formatter_process_function = tuple_formatter_process_function, .tuple_formatter_process_construct = tuple_formatter_process_construct, .tuple_formatter_process_expr = tuple_formatter_process_expr, .tuple_formatter_register_function = tuple_formatter_register_function, .tuple_formatter_register_expression = tuple_formatter_register_expression, .tuple_formatter_make_title_string = tuple_formatter_make_title_string, .mime_get_plugin = mime_get_plugin, .mime_set_plugin = mime_set_plugin, .uri_get_plugin = uri_get_plugin, .uri_set_plugin = uri_set_plugin, .util_info_dialog = util_info_dialog, .get_gentitle_format = get_gentitle_format, .smart_realloc = smart_realloc, .sadfmt_from_afmt = sadfmt_from_afmt, .escape_shell_chars = escape_shell_chars, .str_append = str_append, .str_replace = str_replace, .str_replace_in = str_replace_in, .str_has_prefix_nocase = str_has_prefix_nocase, .str_has_suffix_nocase = str_has_suffix_nocase, .str_has_suffixes_nocase = str_has_suffixes_nocase, .str_to_utf8_fallback = str_to_utf8_fallback, .str_to_utf8 = str_to_utf8, .filename_to_utf8 = filename_to_utf8, .str_skip_chars = str_skip_chars, .convert_title_text = convert_title_text, .chardet_to_utf8 = chardet_to_utf8, .playlist_container_register = playlist_container_register, .playlist_container_unregister = playlist_container_unregister, .playlist_container_read = playlist_container_read, .playlist_container_write = playlist_container_write, .playlist_container_find = playlist_container_find, .playlist_entry_new = playlist_entry_new, .playlist_entry_free = playlist_entry_free, .playlist_add_playlist = playlist_add_playlist, .playlist_remove_playlist = playlist_remove_playlist, .playlist_select_playlist = playlist_select_playlist, .playlist_select_next = playlist_select_next, .playlist_select_prev = playlist_select_prev, .playlist_get_playlists = playlist_get_playlists, .playlist_clear_only = playlist_clear_only, .playlist_clear = playlist_clear, .playlist_delete = playlist_delete, .playlist_add = playlist_add, .playlist_ins = playlist_ins, .playlist_add_dir = playlist_add_dir, .playlist_ins_dir = playlist_ins_dir, .playlist_add_url = playlist_add_url, .playlist_ins_url = playlist_ins_url, .playlist_check_pos_current = playlist_check_pos_current, .playlist_next = playlist_next, .playlist_prev = playlist_prev, .playlist_queue = playlist_queue, .playlist_queue_position = playlist_queue_position, .playlist_queue_remove = playlist_queue_remove, .playlist_queue_get_length = playlist_queue_get_length, .playlist_is_position_queued = playlist_is_position_queued, .playlist_clear_queue = playlist_clear_queue, .playlist_get_queue_position = playlist_get_queue_position, .playlist_get_queue_position_number = playlist_get_queue_position_number, .playlist_get_queue_qposition_number = playlist_get_queue_qposition_number, .playlist_eof_reached = playlist_eof_reached, .playlist_set_position = playlist_set_position, .playlist_get_length = playlist_get_length, .playlist_get_position = playlist_get_position, .playlist_get_position_nolock = playlist_get_position_nolock, .playlist_get_info_text = playlist_get_info_text, .playlist_get_current_length = playlist_get_current_length, .playlist_save = playlist_save, .playlist_load = playlist_load, .playlist_sort = playlist_sort, .playlist_sort_selected = playlist_sort_selected, .playlist_reverse = playlist_reverse, .playlist_random = playlist_random, .playlist_remove_duplicates = playlist_remove_duplicates, .playlist_remove_dead_files = playlist_remove_dead_files, .playlist_fileinfo_current = ui_fileinfo_show_current, .playlist_fileinfo = ui_fileinfo_show, .playlist_delete_index = playlist_delete_index, .playlist_get_entry_to_play = playlist_get_entry_to_play, .playlist_get_filename = playlist_get_filename, .playlist_get_songtitle = playlist_get_songtitle, .playlist_get_tuple = playlist_get_tuple, .playlist_get_songtime = playlist_get_songtime, .playlist_get_selected = playlist_get_selected, .playlist_get_num_selected = playlist_get_num_selected, .playlist_get_total_time = playlist_get_total_time, .playlist_select_search = playlist_select_search, .playlist_select_all = playlist_select_all, .playlist_select_range = playlist_select_range, .playlist_select_invert_all = playlist_select_invert_all, .playlist_select_invert = playlist_select_invert, .playlist_read_info_selection = playlist_read_info_selection, .playlist_read_info = playlist_read_info, .playlist_set_shuffle = playlist_set_shuffle, .playlist_clear_selected = playlist_clear_selected, .get_playlist_nth = get_playlist_nth, .playlist_set_current_name = playlist_set_current_name, .playlist_get_current_name = playlist_get_current_name, .playlist_filename_set = playlist_filename_set, .playlist_filename_get = playlist_filename_get, .playlist_new = playlist_new, .playlist_free = playlist_free, .playlist_new_from_selected = playlist_new_from_selected, .is_playlist_name = is_playlist_name, .playlist_load_ins_file = playlist_load_ins_file, .playlist_load_ins_file_tuple = playlist_load_ins_file_tuple, .playlist_get_active = playlist_get_active, .playlist_playlists_equal = playlist_playlists_equal, .ip_state = &ip_data, ._cfg = &cfg, .hook_associate = hook_associate, .hook_dissociate = hook_dissociate, .hook_register = hook_register, .hook_call = hook_call, .open_ini_file = open_ini_file, .close_ini_file = close_ini_file, .read_ini_string = read_ini_string, .read_ini_array = read_ini_array, .menu_plugin_item_add = menu_plugin_item_add, .menu_plugin_item_remove = menu_plugin_item_remove, .drct_quit = drct_quit, .drct_eject = drct_eject, .drct_jtf_show = drct_jtf_show, .drct_main_win_is_visible = drct_main_win_is_visible, .drct_main_win_toggle = drct_main_win_toggle, .drct_eq_win_is_visible = drct_eq_win_is_visible, .drct_eq_win_toggle = drct_eq_win_toggle, .drct_pl_win_is_visible = drct_pl_win_is_visible, .drct_pl_win_toggle = drct_pl_win_toggle, .drct_activate = drct_activate, .drct_initiate = drct_initiate, .drct_play = drct_play, .drct_pause = drct_pause, .drct_stop = drct_stop, .drct_get_playing = drct_get_playing, .drct_get_paused = drct_get_paused, .drct_get_stopped = drct_get_stopped, .drct_get_info = drct_get_info, .drct_get_time = drct_get_time, .drct_get_length = drct_get_length, .drct_seek = drct_seek, .drct_get_volume = drct_get_volume, .drct_set_volume = drct_set_volume, .drct_get_volume_main = drct_get_volume_main, .drct_set_volume_main = drct_set_volume_main, .drct_get_volume_balance = drct_get_volume_balance, .drct_set_volume_balance = drct_set_volume_balance, .drct_pl_next = drct_pl_next, .drct_pl_prev = drct_pl_prev, .drct_pl_repeat_is_enabled = drct_pl_repeat_is_enabled, .drct_pl_repeat_toggle = drct_pl_repeat_toggle, .drct_pl_repeat_is_shuffled = drct_pl_repeat_is_shuffled, .drct_pl_shuffle_toggle = drct_pl_shuffle_toggle, .drct_pl_get_title = drct_pl_get_title, .drct_pl_get_time = drct_pl_get_time, .drct_pl_get_pos = drct_pl_get_pos, .drct_pl_get_file = drct_pl_get_file, .drct_pl_add = drct_pl_add, .drct_pl_clear = drct_pl_clear, .drct_pl_get_length = drct_pl_get_length, .drct_pl_delete = drct_pl_delete, .drct_pl_set_pos = drct_pl_set_pos, .drct_pl_ins_url_string = drct_pl_ins_url_string, .drct_pl_add_url_string = drct_pl_add_url_string, .drct_pl_enqueue_to_temp = drct_pl_enqueue_to_temp, .drct_pq_get_length = drct_pq_get_length, .drct_pq_add = drct_pq_add, .drct_pq_remove = drct_pq_remove, .drct_pq_clear = drct_pq_clear, .drct_pq_is_queued = drct_pq_is_queued, .drct_pq_get_position = drct_pq_get_position, .drct_pq_get_queue_position = drct_pq_get_queue_position, .prefswin_page_new = prefswin_page_new, .prefswin_page_destroy = prefswin_page_destroy, .fileinfopopup_create = fileinfopopup_create, .fileinfopopup_destroy = fileinfopopup_destroy, .fileinfopopup_show_from_title = fileinfopopup_show_from_title, .fileinfopopup_show_from_tuple = fileinfopopup_show_from_tuple, .fileinfopopup_hide = fileinfopopup_hide, .util_get_localdir = util_get_localdir, .input_check_file = input_check_file, .flow_new = flow_new, .flow_execute = flow_execute, .flow_link_element = flow_link_element, .flow_unlink_element = flow_unlink_element, .effect_flow = effect_flow, .volumecontrol_flow = volumecontrol_flow, .util_menu_main_show = util_menu_main_show, .get_output_list = get_output_list, .input_get_volume = input_get_volume, .construct_uri = construct_uri, .uri_to_display_basename = uri_to_display_basename, .uri_to_display_dirname = uri_to_display_dirname, .get_pvt_data = get_pvt_data, .set_pvt_data = set_pvt_data, .event_queue = event_queue, .calc_mono_freq = calc_mono_freq, .calc_mono_pcm = calc_mono_pcm, .calc_stereo_pcm = calc_stereo_pcm, .create_widgets = create_widgets, .equalizer_read_presets = equalizer_read_presets, .equalizer_write_preset_file = equalizer_write_preset_file, .import_winamp_eqf = import_winamp_eqf, .save_preset_file = save_preset_file, .equalizer_read_aud_preset = equalizer_read_aud_preset, .load_preset_file = load_preset_file, .output_plugin_cleanup = output_plugin_cleanup, .output_plugin_reinit = output_plugin_reinit, }; /*****************************************************************/ GList *lowlevel_list = NULL; extern GList *vfs_transports; static mowgli_dictionary_t *plugin_dict = NULL; static GStaticPrivate cur_plugin_key = G_STATIC_PRIVATE_INIT; static mowgli_dictionary_t *pvt_data_dict = NULL; static mowgli_list_t *headers_list = NULL; void plugin_set_current(Plugin *plugin) { g_static_private_set(&cur_plugin_key, plugin, NULL); } static Plugin *plugin_get_current(void) { return g_static_private_get(&cur_plugin_key); } static void set_pvt_data(Plugin * plugin, gpointer data) { mowgli_dictionary_elem_t *elem; elem = mowgli_dictionary_find(pvt_data_dict, g_basename(plugin->filename)); if (elem == NULL) mowgli_dictionary_add(pvt_data_dict, g_basename(plugin->filename), data); else elem->data = data; } static gpointer get_pvt_data(void) { Plugin *cur_p = plugin_get_current(); return mowgli_dictionary_retrieve(pvt_data_dict, g_basename(cur_p->filename)); } static gint inputlist_compare_func(gconstpointer a, gconstpointer b) { const InputPlugin *ap = a, *bp = b; if(ap->description && bp->description) return strcasecmp(ap->description, bp->description); else return 0; } static gint outputlist_compare_func(gconstpointer a, gconstpointer b) { const OutputPlugin *ap = a, *bp = b; if(ap->description && bp->description) return strcasecmp(ap->description, bp->description); else return 0; } static gint effectlist_compare_func(gconstpointer a, gconstpointer b) { const EffectPlugin *ap = a, *bp = b; if(ap->description && bp->description) return strcasecmp(ap->description, bp->description); else return 0; } static gint generallist_compare_func(gconstpointer a, gconstpointer b) { const GeneralPlugin *ap = a, *bp = b; if(ap->description && bp->description) return strcasecmp(ap->description, bp->description); else return 0; } static gint vislist_compare_func(gconstpointer a, gconstpointer b) { const VisPlugin *ap = a, *bp = b; if(ap->description && bp->description) return strcasecmp(ap->description, bp->description); else return 0; } static gint discoverylist_compare_func(gconstpointer a, gconstpointer b) { const DiscoveryPlugin *ap = a, *bp = b; if(ap->description && bp->description) return strcasecmp(ap->description, bp->description); else return 0; } static gboolean plugin_is_duplicate(const gchar * filename) { gchar *base_filename = g_path_get_basename(filename); if (mowgli_dictionary_retrieve(plugin_dict, base_filename) != NULL) { g_free(base_filename); return TRUE; } g_free(base_filename); return FALSE; } gboolean plugin_is_enabled(const gchar *filename) { Plugin *plugin = mowgli_dictionary_retrieve(plugin_dict, filename); if (!plugin) return FALSE; return plugin->enabled; } void plugin_set_enabled(const gchar *filename, gboolean enabled) { Plugin *plugin = mowgli_dictionary_retrieve(plugin_dict, filename); if (!plugin) return; plugin->enabled = enabled; } Plugin * plugin_get_plugin(const gchar *filename) { return mowgli_dictionary_retrieve(plugin_dict, filename); } static void input_plugin_init(Plugin * plugin) { InputPlugin *p = INPUT_PLUGIN(plugin); p->get_vis_type = input_get_vis_type; p->add_vis_pcm = input_add_vis_pcm; /* Pretty const casts courtesy of XMMS's plugin.h legacy. Anyone else thinks we could use a CONST macro to solve the warnings? - descender */ p->set_info = (void (*)(gchar *, gint, gint, gint, gint)) playlist_set_info_old_abi; p->set_info_text = input_set_info_text; ip_data.input_list = g_list_append(ip_data.input_list, p); p->enabled = TRUE; /* XXX: we need something better than p->filename if plugins will eventually provide multiple plugins --nenolod */ mowgli_dictionary_add(plugin_dict, g_basename(p->filename), p); /* build the extension hash table */ gint i; if(p->vfs_extensions) { for(i = 0; p->vfs_extensions[i] != NULL; i++) { GList *hdr = NULL; GList **handle = NULL; //allocated as auto in stack. GList **handle2 = g_malloc(sizeof(GList **)); handle = g_hash_table_lookup(ext_hash, p->vfs_extensions[i]); if(handle) hdr = *handle; hdr = g_list_append(hdr, p); //returned hdr is non-volatile *handle2 = hdr; g_hash_table_replace(ext_hash, g_strdup(p->vfs_extensions[i]), handle2); } } } static void output_plugin_init(Plugin * plugin) { OutputPlugin *p = OUTPUT_PLUGIN(plugin); op_data.output_list = g_list_append(op_data.output_list, p); mowgli_dictionary_add(plugin_dict, g_basename(p->filename), p); } static void effect_plugin_init(Plugin * plugin) { EffectPlugin *p = EFFECT_PLUGIN(plugin); ep_data.effect_list = g_list_append(ep_data.effect_list, p); mowgli_dictionary_add(plugin_dict, g_basename(p->filename), p); } static void general_plugin_init(Plugin * plugin) { GeneralPlugin *p = GENERAL_PLUGIN(plugin); gp_data.general_list = g_list_append(gp_data.general_list, p); mowgli_dictionary_add(plugin_dict, g_basename(p->filename), p); } static void vis_plugin_init(Plugin * plugin) { VisPlugin *p = VIS_PLUGIN(plugin); p->disable_plugin = vis_disable_plugin; vp_data.vis_list = g_list_append(vp_data.vis_list, p); mowgli_dictionary_add(plugin_dict, g_basename(p->filename), p); } static void discovery_plugin_init(Plugin * plugin) { DiscoveryPlugin *p = DISCOVERY_PLUGIN(plugin); dp_data.discovery_list = g_list_append(dp_data.discovery_list, p); mowgli_dictionary_add(plugin_dict, g_basename(p->filename), p); } /*******************************************************************/ static void plugin2_dispose(GModule *module, const gchar *str, ...) { gchar *buf; va_list va; va_start(va, str); buf = g_strdup_vprintf(str, va); va_end(va); g_message("*** %s\n", buf); g_free(buf); g_module_close(module); } void plugin2_process(PluginHeader *header, GModule *module, const gchar *filename) { gint i, n; mowgli_node_t *hlist_node; if (header->magic != PLUGIN_MAGIC) return plugin2_dispose(module, "plugin <%s> discarded, invalid module magic", filename); if (header->api_version != __AUDACIOUS_PLUGIN_API__) return plugin2_dispose(module, "plugin <%s> discarded, wanting API version %d, we implement API version %d", filename, header->api_version, __AUDACIOUS_PLUGIN_API__); hlist_node = mowgli_node_create(); mowgli_node_add(header, hlist_node, headers_list); if (header->init) header->init(); header->priv_assoc = g_new0(Plugin, 1); header->priv_assoc->handle = module; header->priv_assoc->filename = g_strdup(filename); n = 0; if (header->ip_list) { for (i = 0; (header->ip_list)[i] != NULL; i++, n++) { PLUGIN((header->ip_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n); input_plugin_init(PLUGIN((header->ip_list)[i])); } } if (header->op_list) { for (i = 0; (header->op_list)[i] != NULL; i++, n++) { PLUGIN((header->op_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n); output_plugin_init(PLUGIN((header->op_list)[i])); } } if (header->ep_list) { for (i = 0; (header->ep_list)[i] != NULL; i++, n++) { PLUGIN((header->ep_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n); effect_plugin_init(PLUGIN((header->ep_list)[i])); } } if (header->gp_list) { for (i = 0; (header->gp_list)[i] != NULL; i++, n++) { PLUGIN((header->gp_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n); general_plugin_init(PLUGIN((header->gp_list)[i])); } } if (header->vp_list) { for (i = 0; (header->vp_list)[i] != NULL; i++, n++) { PLUGIN((header->vp_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n); vis_plugin_init(PLUGIN((header->vp_list)[i])); } } if (header->dp_list) { for (i = 0; (header->dp_list)[i] != NULL; i++, n++) { PLUGIN((header->dp_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n); discovery_plugin_init(PLUGIN((header->dp_list)[i])); } } if (header->interface) interface_register(header->interface); } void plugin2_unload(PluginHeader *header, mowgli_node_t *hlist_node) { GModule *module; g_return_if_fail(header->priv_assoc != NULL); if (header->interface) interface_deregister(header->interface); module = header->priv_assoc->handle; g_free(header->priv_assoc->filename); g_free(header->priv_assoc); if (header->fini) header->fini(); mowgli_node_delete(hlist_node, headers_list); mowgli_node_free(hlist_node); g_module_close(module); } /******************************************************************/ static void add_plugin(const gchar * filename) { GModule *module; gpointer func; if (plugin_is_duplicate(filename)) return; g_message("Loaded plugin (%s)", filename); if (!(module = g_module_open(filename, G_MODULE_BIND_LOCAL))) { printf("Failed to load plugin (%s): %s\n", filename, g_module_error()); return; } /* v2 plugin loading */ if (g_module_symbol(module, "get_plugin_info", &func)) { PluginHeader *(*header_func_p)(struct _AudaciousFuncTableV1 *) = func; PluginHeader *header; /* this should never happen. */ g_return_if_fail((header = header_func_p(&_aud_papi_v1)) != NULL); plugin2_process(header, module, filename); return; } printf("Invalid plugin (%s)\n", filename); g_module_close(module); } static gboolean scan_plugin_func(const gchar * path, const gchar * basename, gpointer data) { if (!str_has_suffix_nocase(basename, SHARED_SUFFIX)) return FALSE; if (!g_file_test(path, G_FILE_TEST_IS_REGULAR)) return FALSE; add_plugin(path); return FALSE; } static void scan_plugins(const gchar * path) { dir_foreach(path, scan_plugin_func, NULL, NULL); } void plugin_system_init(void) { gchar *dir, **disabled; GList *node; OutputPlugin *op; InputPlugin *ip; LowlevelPlugin *lp; DiscoveryPlugin *dp; GtkWidget *dialog; gint dirsel = 0, i = 0; if (!g_module_supported()) { dialog = gtk_message_dialog_new (GTK_WINDOW (mainwin), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Module loading not supported! Plugins will not be loaded.\n")); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); return; } plugin_dict = mowgli_dictionary_create(g_ascii_strcasecmp); pvt_data_dict = mowgli_dictionary_create(g_ascii_strcasecmp); headers_list = mowgli_list_create(); /* make extension hash */ ext_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); #ifndef DISABLE_USER_PLUGIN_DIR scan_plugins(aud_paths[BMP_PATH_USER_PLUGIN_DIR]); /* * This is in a separate lo * DiscoveryPlugin *dpop so if the user puts them in the * wrong dir we'll still get them in the right order (home dir * first) - Zinx */ while (plugin_dir_list[dirsel]) { dir = g_build_filename(aud_paths[BMP_PATH_USER_PLUGIN_DIR], plugin_dir_list[dirsel++], NULL); scan_plugins(dir); g_free(dir); } dirsel = 0; #endif while (plugin_dir_list[dirsel]) { dir = g_build_filename(PLUGIN_DIR, plugin_dir_list[dirsel++], NULL); scan_plugins(dir); g_free(dir); } op_data.output_list = g_list_sort(op_data.output_list, outputlist_compare_func); if (!op_data.current_output_plugin && g_list_length(op_data.output_list)) { op_data.current_output_plugin = op_data.output_list->data; } ip_data.input_list = g_list_sort(ip_data.input_list, inputlist_compare_func); ep_data.effect_list = g_list_sort(ep_data.effect_list, effectlist_compare_func); ep_data.enabled_list = NULL; gp_data.general_list = g_list_sort(gp_data.general_list, generallist_compare_func); gp_data.enabled_list = NULL; vp_data.vis_list = g_list_sort(vp_data.vis_list, vislist_compare_func); vp_data.enabled_list = NULL; dp_data.discovery_list = g_list_sort(dp_data.discovery_list, discoverylist_compare_func); dp_data.enabled_list = NULL; general_enable_from_stringified_list(cfg.enabled_gplugins); vis_enable_from_stringified_list(cfg.enabled_vplugins); effect_enable_from_stringified_list(cfg.enabled_eplugins); discovery_enable_from_stringified_list(cfg.enabled_dplugins); g_free(cfg.enabled_gplugins); cfg.enabled_gplugins = NULL; g_free(cfg.enabled_vplugins); cfg.enabled_vplugins = NULL; g_free(cfg.enabled_eplugins); cfg.enabled_eplugins = NULL; g_free(cfg.enabled_dplugins); cfg.enabled_dplugins = NULL; for (node = op_data.output_list; node; node = g_list_next(node)) { op = OUTPUT_PLUGIN(node->data); /* * Only test basename to avoid problems when changing * prefix. We will only see one plugin with the same * basename, so this is usually what the user want. */ if (cfg.outputplugin && !strcmp(g_basename(cfg.outputplugin), g_basename(op->filename))) op_data.current_output_plugin = op; if (op->init) { plugin_set_current((Plugin *)op); op->init(); } } for (node = ip_data.input_list; node; node = g_list_next(node)) { ip = INPUT_PLUGIN(node->data); if (ip->init) { plugin_set_current((Plugin *)ip); ip->init(); } } for (node = dp_data.discovery_list; node; node = g_list_next(node)) { dp = DISCOVERY_PLUGIN(node->data); if (dp->init) { plugin_set_current((Plugin *)dp); dp->init(); } } for (node = lowlevel_list; node; node = g_list_next(node)) { lp = LOWLEVEL_PLUGIN(node->data); if (lp->init) { plugin_set_current((Plugin *)lp); lp->init(); } } if (cfg.disabled_iplugins) { disabled = g_strsplit(cfg.disabled_iplugins, ":", 0); while (disabled[i]) { Plugin *plugintmp = plugin_get_plugin(disabled[i]); g_free(disabled[i]); if (plugintmp) INPUT_PLUGIN(plugintmp)->enabled = FALSE; i++; } g_free(disabled); g_free(cfg.disabled_iplugins); cfg.disabled_iplugins = NULL; } } static void remove_list(gpointer key, gpointer value, gpointer data) { g_list_free(*(GList **)value); } void plugin_system_cleanup(void) { InputPlugin *ip; OutputPlugin *op; EffectPlugin *ep; GeneralPlugin *gp; VisPlugin *vp; LowlevelPlugin *lp; DiscoveryPlugin *dp; GList *node; mowgli_node_t *hlist_node; g_message("Shutting down plugin system"); if (playback_get_playing()) { ip_data.stop = TRUE; playback_stop(); ip_data.stop = FALSE; } /* FIXME: race condition -nenolod */ op_data.current_output_plugin = NULL; for (node = get_input_list(); node; node = g_list_next(node)) { ip = INPUT_PLUGIN(node->data); if (ip && ip->cleanup) { plugin_set_current((Plugin *)ip); ip->cleanup(); GDK_THREADS_LEAVE(); while (g_main_context_iteration(NULL, FALSE)); GDK_THREADS_ENTER(); } if (ip->handle) g_module_close(ip->handle); } if (ip_data.input_list != NULL) { g_list_free(ip_data.input_list); ip_data.input_list = NULL; } for (node = get_output_list(); node; node = g_list_next(node)) { op = OUTPUT_PLUGIN(node->data); if (op && op->cleanup) { plugin_set_current((Plugin *)op); op->cleanup(); GDK_THREADS_LEAVE(); while (g_main_context_iteration(NULL, FALSE)); GDK_THREADS_ENTER(); } if (op->handle) g_module_close(op->handle); } if (op_data.output_list != NULL) { g_list_free(op_data.output_list); op_data.output_list = NULL; } for (node = get_effect_list(); node; node = g_list_next(node)) { ep = EFFECT_PLUGIN(node->data); if (ep && ep->cleanup) { plugin_set_current((Plugin *)ep); ep->cleanup(); GDK_THREADS_LEAVE(); while (g_main_context_iteration(NULL, FALSE)); GDK_THREADS_ENTER(); } if (ep->handle) g_module_close(ep->handle); } if (ep_data.effect_list != NULL) { g_list_free(ep_data.effect_list); ep_data.effect_list = NULL; } for (node = get_general_list(); node; node = g_list_next(node)) { gp = GENERAL_PLUGIN(node->data); if (gp && gp->cleanup) { plugin_set_current((Plugin *)gp); gp->cleanup(); GDK_THREADS_LEAVE(); while (g_main_context_iteration(NULL, FALSE)); GDK_THREADS_ENTER(); } if (gp->handle) g_module_close(gp->handle); } if (gp_data.general_list != NULL) { g_list_free(gp_data.general_list); gp_data.general_list = NULL; } for (node = get_vis_list(); node; node = g_list_next(node)) { vp = VIS_PLUGIN(node->data); if (vp && vp->cleanup) { plugin_set_current((Plugin *)vp); vp->cleanup(); GDK_THREADS_LEAVE(); while (g_main_context_iteration(NULL, FALSE)); GDK_THREADS_ENTER(); } if (vp->handle) g_module_close(vp->handle); } if (vp_data.vis_list != NULL) { g_list_free(vp_data.vis_list); vp_data.vis_list = NULL; } for (node = get_discovery_list(); node; node = g_list_next(node)) { dp = DISCOVERY_PLUGIN(node->data); if (dp && dp->cleanup) { plugin_set_current((Plugin *)dp); dp->cleanup(); GDK_THREADS_LEAVE(); while (g_main_context_iteration(NULL, FALSE)); GDK_THREADS_ENTER(); } if (dp->handle) g_module_close(dp->handle); } if (dp_data.discovery_list != NULL) { g_list_free(dp_data.discovery_list); dp_data.discovery_list = NULL; } for (node = lowlevel_list; node; node = g_list_next(node)) { lp = LOWLEVEL_PLUGIN(node->data); if (lp && lp->cleanup) { plugin_set_current((Plugin *)lp); lp->cleanup(); GDK_THREADS_LEAVE(); while (g_main_context_iteration(NULL, FALSE)); GDK_THREADS_ENTER(); } if (lp->handle) g_module_close(lp->handle); } if (lowlevel_list != NULL) { g_list_free(lowlevel_list); lowlevel_list = NULL; } /* XXX: vfs will crash otherwise. -nenolod */ if (vfs_transports != NULL) { g_list_free(vfs_transports); vfs_transports = NULL; } MOWGLI_LIST_FOREACH(hlist_node, headers_list->head) plugin2_unload(hlist_node->data, hlist_node); mowgli_dictionary_destroy(plugin_dict, NULL, NULL); mowgli_dictionary_destroy(pvt_data_dict, NULL, NULL); mowgli_list_free(headers_list); g_hash_table_foreach(ext_hash, remove_list, NULL); g_hash_table_remove_all(ext_hash); }