Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
pluginenum.c
Go to the documentation of this file.
00001 /*  Audacious - Cross-platform multimedia player
00002  *  Copyright (C) 2005-2009  Audacious development team
00003  *
00004  *  Based on BMP:
00005  *  Copyright (C) 2003-2004  BMP development team
00006  *
00007  *  Based on XMMS:
00008  *  Copyright (C) 1998-2003  XMMS development team
00009  *
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; under version 3 of the License.
00013  *
00014  *  This program is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public License
00020  *  along with this program.  If not, see <http://www.gnu.org/licenses>.
00021  *
00022  *  The Audacious team does not consider modular code linking to
00023  *  Audacious or using our public API to be a derived work.
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 (); /* FIXME: Pay attention to the return value. */
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 (); /* FIXME: Pay attention to the return value. */
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 (); /* FIXME: Pay attention to the return value. */
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 (); /* FIXME: Pay attention to the return value. */
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     /* v2 plugin loading */
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      * This is in a separate loop so if the user puts them in the
00287      * wrong dir we'll still get them in the right order (home dir
00288      * first)                                                - Zinx
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 }