00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <assert.h>
00027
00028 #include <glib.h>
00029 #include <gmodule.h>
00030
00031 #include <libaudcore/audstrings.h>
00032 #include <libaudgui/init.h>
00033
00034 #include "config.h"
00035
00036 #ifndef SHARED_SUFFIX
00037 # define SHARED_SUFFIX G_MODULE_SUFFIX
00038 #endif
00039
00040 #include "audconfig.h"
00041 #include "debug.h"
00042 #include "plugin.h"
00043 #include "ui_preferences.h"
00044 #include "util.h"
00045
00046 #define AUD_API_DECLARE
00047 #include "configdb.h"
00048 #include "drct.h"
00049 #include "misc.h"
00050 #include "playlist.h"
00051 #include "plugins.h"
00052 #undef AUD_API_DECLARE
00053
00054 static const gchar * plugin_dir_list[] = {PLUGINSUBS, NULL};
00055
00056 static AudAPITable api_table = {
00057 .configdb_api = & configdb_api,
00058 .drct_api = & drct_api,
00059 .misc_api = & misc_api,
00060 .playlist_api = & playlist_api,
00061 .plugins_api = & plugins_api,
00062 .cfg = & cfg};
00063
00064 typedef struct {
00065 Plugin * header;
00066 GModule * module;
00067 } LoadedModule;
00068
00069 static GList * loaded_modules = NULL;
00070 static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
00071
00072 static void plugin2_process (Plugin * header, GModule * module, const gchar * filename)
00073 {
00074 if (header->magic != _AUD_PLUGIN_MAGIC)
00075 {
00076 fprintf (stderr, " *** ERROR: %s is not a valid Audacious plugin.\n", filename);
00077 g_module_close (module);
00078 return;
00079 }
00080
00081 if (header->version < _AUD_PLUGIN_VERSION_MIN || header->version > _AUD_PLUGIN_VERSION)
00082 {
00083 fprintf (stderr, " *** ERROR: %s is not compatible with this version of Audacious.\n", filename);
00084 g_module_close (module);
00085 return;
00086 }
00087
00088 switch (header->type)
00089 {
00090 case PLUGIN_TYPE_TRANSPORT:
00091 case PLUGIN_TYPE_PLAYLIST:
00092 case PLUGIN_TYPE_INPUT:
00093 case PLUGIN_TYPE_EFFECT:
00094 if (PLUGIN_HAS_FUNC (header, init) && ! header->init ())
00095 {
00096 fprintf (stderr, " *** ERROR: %s failed to initialize.\n", filename);
00097 g_module_close (module);
00098 return;
00099 }
00100 break;
00101 }
00102
00103 g_static_mutex_lock (& mutex);
00104 LoadedModule * loaded = g_slice_new (LoadedModule);
00105 loaded->header = header;
00106 loaded->module = module;
00107 loaded_modules = g_list_prepend (loaded_modules, loaded);
00108 g_static_mutex_unlock (& mutex);
00109
00110 plugin_register_loaded (filename, header);
00111 }
00112
00113 static void plugin2_unload (LoadedModule * loaded)
00114 {
00115 Plugin * header = loaded->header;
00116
00117 switch (header->type)
00118 {
00119 case PLUGIN_TYPE_TRANSPORT:
00120 case PLUGIN_TYPE_PLAYLIST:
00121 case PLUGIN_TYPE_INPUT:
00122 case PLUGIN_TYPE_EFFECT:
00123 if (PLUGIN_HAS_FUNC (header, settings))
00124 plugin_preferences_cleanup (header->settings);
00125 if (PLUGIN_HAS_FUNC (header, cleanup))
00126 header->cleanup ();
00127 break;
00128 }
00129
00130 g_static_mutex_lock (& mutex);
00131 g_module_close (loaded->module);
00132 g_slice_free (LoadedModule, loaded);
00133 g_static_mutex_unlock (& mutex);
00134 }
00135
00136
00137
00138 void plugin_load (const gchar * filename)
00139 {
00140 GModule *module;
00141 Plugin * (* func) (AudAPITable * table);
00142
00143 AUDDBG ("Loading plugin: %s.\n", filename);
00144
00145 if (!(module = g_module_open(filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL)))
00146 {
00147 printf("Failed to load plugin (%s): %s\n", filename, g_module_error());
00148 return;
00149 }
00150
00151
00152 if (g_module_symbol (module, "get_plugin_info", (void *) & func))
00153 {
00154 Plugin * header = func (& api_table);
00155 g_return_if_fail (header != NULL);
00156 plugin2_process(header, module, filename);
00157 return;
00158 }
00159
00160 printf("Invalid plugin (%s)\n", filename);
00161 g_module_close(module);
00162 }
00163
00164 static gboolean scan_plugin_func(const gchar * path, const gchar * basename, gpointer data)
00165 {
00166 if (!str_has_suffix_nocase(basename, SHARED_SUFFIX))
00167 return FALSE;
00168
00169 if (!g_file_test(path, G_FILE_TEST_IS_REGULAR))
00170 return FALSE;
00171
00172 plugin_register (path);
00173
00174 return FALSE;
00175 }
00176
00177 static void scan_plugins(const gchar * path)
00178 {
00179 dir_foreach (path, scan_plugin_func, NULL);
00180 }
00181
00182 void plugin_system_init(void)
00183 {
00184 assert (g_module_supported ());
00185
00186 gchar *dir;
00187 gint dirsel = 0;
00188
00189 audgui_init (& api_table);
00190
00191 plugin_registry_load ();
00192
00193 #ifndef DISABLE_USER_PLUGIN_DIR
00194 scan_plugins (get_path (AUD_PATH_USER_PLUGIN_DIR));
00195
00196
00197
00198
00199
00200 while (plugin_dir_list[dirsel])
00201 {
00202 dir = g_build_filename (get_path (AUD_PATH_USER_PLUGIN_DIR),
00203 plugin_dir_list[dirsel ++], NULL);
00204 scan_plugins(dir);
00205 g_free(dir);
00206 }
00207 dirsel = 0;
00208 #endif
00209
00210 while (plugin_dir_list[dirsel])
00211 {
00212 dir = g_build_filename (get_path (AUD_PATH_PLUGIN_DIR),
00213 plugin_dir_list[dirsel ++], NULL);
00214 scan_plugins(dir);
00215 g_free(dir);
00216 }
00217
00218 plugin_registry_prune ();
00219 }
00220
00221 void plugin_system_cleanup(void)
00222 {
00223 plugin_registry_save ();
00224
00225 for (GList * node = loaded_modules; node != NULL; node = node->next)
00226 plugin2_unload (node->data);
00227
00228 g_list_free (loaded_modules);
00229 loaded_modules = NULL;
00230 }