Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$
|
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 }