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 PluginHeader * header;
00066 GModule * module;
00067 } LoadedModule;
00068
00069 static GList * loaded_modules = NULL;
00070
00071 static void plugin2_process (PluginHeader * 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 LoadedModule * loaded = g_slice_new (LoadedModule);
00088 loaded->header = header;
00089 loaded->module = module;
00090 loaded_modules = g_list_prepend (loaded_modules, loaded);
00091
00092 if (header->init != NULL)
00093 {
00094 plugin_register (PLUGIN_TYPE_LOWLEVEL, filename, 0, NULL);
00095 header->init ();
00096 }
00097
00098 if (header->tp_list)
00099 {
00100 TransportPlugin * tp;
00101 for (gint i = 0; (tp = header->tp_list[i]); i ++)
00102 {
00103 plugin_register (PLUGIN_TYPE_TRANSPORT, filename, i, tp);
00104 if (tp->init != NULL)
00105 tp->init ();
00106 }
00107 }
00108
00109 if (header->pp_list)
00110 {
00111 PlaylistPlugin * pp;
00112 for (gint i = 0; (pp = header->pp_list[i]); i ++)
00113 {
00114 plugin_register (PLUGIN_TYPE_PLAYLIST, filename, i, pp);
00115 if (pp->init != NULL)
00116 pp->init ();
00117 }
00118 }
00119
00120 if (header->ip_list != NULL)
00121 {
00122 InputPlugin * ip;
00123 for (gint i = 0; (ip = header->ip_list[i]) != NULL; i ++)
00124 {
00125 plugin_register (PLUGIN_TYPE_INPUT, filename, i, ip);
00126 if (ip->init != NULL)
00127 ip->init ();
00128 }
00129 }
00130
00131 if (header->ep_list != NULL)
00132 {
00133 EffectPlugin * ep;
00134 for (gint i = 0; (ep = header->ep_list[i]) != NULL; i ++)
00135 {
00136 plugin_register (PLUGIN_TYPE_EFFECT, filename, i, ep);
00137 if (ep->init != NULL)
00138 ep->init ();
00139 }
00140 }
00141
00142 if (header->op_list != NULL)
00143 {
00144 OutputPlugin * op;
00145 for (gint i = 0; (op = header->op_list[i]) != NULL; i ++)
00146 plugin_register (PLUGIN_TYPE_OUTPUT, filename, i, op);
00147 }
00148
00149 if (header->vp_list != NULL)
00150 {
00151 VisPlugin * vp;
00152 for (gint i = 0; (vp = header->vp_list[i]) != NULL; i ++)
00153 plugin_register (PLUGIN_TYPE_VIS, filename, i, vp);
00154 }
00155
00156 if (header->gp_list != NULL)
00157 {
00158 GeneralPlugin * gp;
00159 for (gint i = 0; (gp = header->gp_list[i]) != NULL; i ++)
00160 plugin_register (PLUGIN_TYPE_GENERAL, filename, i, gp);
00161 }
00162
00163 if (header->iface != NULL)
00164 plugin_register (PLUGIN_TYPE_IFACE, filename, 0, header->iface);
00165 }
00166
00167 static void plugin2_unload (LoadedModule * loaded)
00168 {
00169 PluginHeader * header = loaded->header;
00170
00171 if (header->ip_list != NULL)
00172 {
00173 InputPlugin * ip;
00174 for (gint i = 0; (ip = header->ip_list[i]) != NULL; i ++)
00175 {
00176 if (ip->settings != NULL)
00177 plugin_preferences_cleanup (ip->settings);
00178 if (ip->cleanup != NULL)
00179 ip->cleanup ();
00180 }
00181 }
00182
00183 if (header->ep_list != NULL)
00184 {
00185 EffectPlugin * ep;
00186 for (gint i = 0; (ep = header->ep_list[i]) != NULL; i ++)
00187 {
00188 if (ep->settings != NULL)
00189 plugin_preferences_cleanup (ep->settings);
00190 if (ep->cleanup != NULL)
00191 ep->cleanup ();
00192 }
00193 }
00194
00195 if (header->pp_list != NULL)
00196 {
00197 PlaylistPlugin * pp;
00198 for (gint i = 0; (pp = header->pp_list[i]) != NULL; i ++)
00199 {
00200 if (pp->settings != NULL)
00201 plugin_preferences_cleanup (pp->settings);
00202 if (pp->cleanup != NULL)
00203 pp->cleanup ();
00204 }
00205 }
00206
00207 if (header->tp_list != NULL)
00208 {
00209 TransportPlugin * tp;
00210 for (gint i = 0; (tp = header->tp_list[i]) != NULL; i ++)
00211 {
00212 if (tp->settings != NULL)
00213 plugin_preferences_cleanup (tp->settings);
00214 if (tp->cleanup != NULL)
00215 tp->cleanup ();
00216 }
00217 }
00218
00219 if (header->fini != NULL)
00220 header->fini ();
00221
00222 g_module_close (loaded->module);
00223 g_slice_free (LoadedModule, loaded);
00224 }
00225
00226
00227
00228 void module_load (const gchar * filename)
00229 {
00230 GModule *module;
00231 PluginHeader * (* func) (AudAPITable * table);
00232
00233 AUDDBG ("Loading plugin: %s.\n", filename);
00234
00235 if (!(module = g_module_open(filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL)))
00236 {
00237 printf("Failed to load plugin (%s): %s\n", filename, g_module_error());
00238 return;
00239 }
00240
00241
00242 if (g_module_symbol (module, "get_plugin_info", (void *) & func))
00243 {
00244 PluginHeader * header = func (& api_table);
00245 g_return_if_fail (header != NULL);
00246 plugin2_process(header, module, filename);
00247 return;
00248 }
00249
00250 printf("Invalid plugin (%s)\n", filename);
00251 g_module_close(module);
00252 }
00253
00254 static gboolean scan_plugin_func(const gchar * path, const gchar * basename, gpointer data)
00255 {
00256 if (!str_has_suffix_nocase(basename, SHARED_SUFFIX))
00257 return FALSE;
00258
00259 if (!g_file_test(path, G_FILE_TEST_IS_REGULAR))
00260 return FALSE;
00261
00262 module_register (path);
00263
00264 return FALSE;
00265 }
00266
00267 static void scan_plugins(const gchar * path)
00268 {
00269 dir_foreach(path, scan_plugin_func, NULL, NULL);
00270 }
00271
00272 void plugin_system_init(void)
00273 {
00274 assert (g_module_supported ());
00275
00276 gchar *dir;
00277 gint dirsel = 0;
00278
00279 audgui_init (& api_table);
00280
00281 plugin_registry_load ();
00282
00283 #ifndef DISABLE_USER_PLUGIN_DIR
00284 scan_plugins (get_path (AUD_PATH_USER_PLUGIN_DIR));
00285
00286
00287
00288
00289
00290 while (plugin_dir_list[dirsel])
00291 {
00292 dir = g_build_filename (get_path (AUD_PATH_USER_PLUGIN_DIR),
00293 plugin_dir_list[dirsel ++], NULL);
00294 scan_plugins(dir);
00295 g_free(dir);
00296 }
00297 dirsel = 0;
00298 #endif
00299
00300 while (plugin_dir_list[dirsel])
00301 {
00302 dir = g_build_filename (get_path (AUD_PATH_PLUGIN_DIR),
00303 plugin_dir_list[dirsel ++], NULL);
00304 scan_plugins(dir);
00305 g_free(dir);
00306 }
00307
00308 plugin_registry_prune ();
00309 }
00310
00311 void plugin_system_cleanup(void)
00312 {
00313 plugin_registry_save ();
00314
00315 for (GList * node = loaded_modules; node != NULL; node = node->next)
00316 plugin2_unload (node->data);
00317
00318 g_list_free (loaded_modules);
00319 loaded_modules = NULL;
00320 }