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