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-2011  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     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     /* v2 plugin loading */
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      * This is in a separate loop so if the user puts them in the
00197      * wrong dir we'll still get them in the right order (home dir
00198      * first)                                                - Zinx
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 }