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 #include <glib.h>
00028 #include <gmodule.h>
00029 #include <pthread.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 char * plugin_dir_list[] = {PLUGINSUBS, NULL};
00053 
00054 char 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 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
00070 
00071 static void plugin2_process (Plugin * header, GModule * module, const char * 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     pthread_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     pthread_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     pthread_mutex_lock (& mutex);
00130     g_module_close (loaded->module);
00131     g_slice_free (LoadedModule, loaded);
00132     pthread_mutex_unlock (& mutex);
00133 }
00134 
00135 /******************************************************************/
00136 
00137 void plugin_load (const char * 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     /* v2 plugin loading */
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 bool_t scan_plugin_func(const char * path, const char * 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 char * 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     char *dir;
00186     int 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      * This is in a separate loop so if the user puts them in the
00196      * wrong dir we'll still get them in the right order (home dir
00197      * first)                                                - Zinx
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 
00230     audgui_cleanup ();
00231 }