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