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 #ifdef HAVE_CONFIG_H 00027 # include "config.h" 00028 #endif 00029 00030 #ifndef SHARED_SUFFIX 00031 # define SHARED_SUFFIX G_MODULE_SUFFIX 00032 #endif 00033 00034 #include <glib.h> 00035 #include <gmodule.h> 00036 #include <gtk/gtk.h> 00037 #include <string.h> 00038 00039 #include <libaudcore/audstrings.h> 00040 #include <libaudgui/init.h> 00041 00042 #include "pluginenum.h" 00043 #include "plugins.h" 00044 00045 #include "audconfig.h" 00046 #include "debug.h" 00047 #include "effect.h" 00048 #include "general.h" 00049 #include "i18n.h" 00050 #include "interface.h" 00051 #include "main.h" 00052 #include "output.h" 00053 #include "playback.h" 00054 #include "util.h" 00055 #include "visualization.h" 00056 00057 #define AUD_API_DECLARE 00058 #include "configdb.h" 00059 #include "drct.h" 00060 #include "misc.h" 00061 #include "playlist.h" 00062 #include "plugins.h" 00063 #undef AUD_API_DECLARE 00064 00065 const gchar *plugin_dir_list[] = { 00066 PLUGINSUBS, 00067 NULL 00068 }; 00069 00070 static AudAPITable api_table = { 00071 .configdb_api = & configdb_api, 00072 .drct_api = & drct_api, 00073 .misc_api = & misc_api, 00074 .playlist_api = & playlist_api, 00075 .plugins_api = & plugins_api, 00076 .cfg = & cfg}; 00077 00078 extern GList *vfs_transports; 00079 static mowgli_list_t *headers_list = NULL; 00080 00081 static void input_plugin_init(Plugin * plugin) 00082 { 00083 InputPlugin *p = INPUT_PLUGIN(plugin); 00084 00085 if (p->init != NULL) 00086 p->init (); 00087 } 00088 00089 static void effect_plugin_init(Plugin * plugin) 00090 { 00091 EffectPlugin *p = EFFECT_PLUGIN(plugin); 00092 00093 if (p->init != NULL) 00094 p->init (); 00095 } 00096 00097 static void vis_plugin_disable_by_header (VisPlugin * header) 00098 { 00099 vis_plugin_enable (plugin_by_header (header), FALSE); 00100 } 00101 00102 static void vis_plugin_init(Plugin * plugin) 00103 { 00104 ((VisPlugin *) plugin)->disable_plugin = vis_plugin_disable_by_header; 00105 } 00106 00107 /*******************************************************************/ 00108 00109 static void plugin2_dispose(GModule * module, const gchar * str, ...) 00110 { 00111 gchar *buf; 00112 va_list va; 00113 00114 va_start(va, str); 00115 buf = g_strdup_vprintf(str, va); 00116 va_end(va); 00117 00118 AUDDBG ("*** %s\n", buf); 00119 g_free(buf); 00120 00121 g_module_close(module); 00122 } 00123 00124 void plugin2_process(PluginHeader * header, GModule * module, const gchar * filename) 00125 { 00126 gint i, n; 00127 mowgli_node_t *hlist_node; 00128 00129 if (header->magic != PLUGIN_MAGIC) 00130 { 00131 plugin2_dispose (module, "plugin <%s> discarded, invalid module magic", 00132 filename); 00133 return; 00134 } 00135 00136 if (header->api_version != __AUDACIOUS_PLUGIN_API__) 00137 { 00138 plugin2_dispose (module, "plugin <%s> discarded, wanting API version " 00139 "%d, we implement API version %d", filename, header->api_version, 00140 __AUDACIOUS_PLUGIN_API__); 00141 return; 00142 } 00143 00144 hlist_node = mowgli_node_create(); 00145 mowgli_node_add(header, hlist_node, headers_list); 00146 00147 if (header->init) 00148 { 00149 plugin_register (filename, PLUGIN_TYPE_BASIC, 0, NULL); 00150 header->init(); 00151 } 00152 00153 header->priv_assoc = g_new0(Plugin, 1); 00154 header->priv_assoc->handle = module; 00155 header->priv_assoc->filename = g_strdup(filename); 00156 00157 n = 0; 00158 00159 if (header->ip_list) 00160 { 00161 for (i = 0; (header->ip_list)[i] != NULL; i++, n++) 00162 { 00163 plugin_register (filename, PLUGIN_TYPE_INPUT, i, header->ip_list[i]); 00164 PLUGIN((header->ip_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n); 00165 input_plugin_init(PLUGIN((header->ip_list)[i])); 00166 } 00167 } 00168 00169 if (header->op_list) 00170 { 00171 for (i = 0; (header->op_list)[i] != NULL; i++, n++) 00172 { 00173 OutputPlugin * plugin = header->op_list[i]; 00174 00175 plugin->filename = g_strdup_printf ("%s (#%d)", filename, n); 00176 plugin_register (filename, PLUGIN_TYPE_OUTPUT, i, plugin); 00177 } 00178 } 00179 00180 if (header->ep_list) 00181 { 00182 for (i = 0; (header->ep_list)[i] != NULL; i++, n++) 00183 { 00184 plugin_register (filename, PLUGIN_TYPE_EFFECT, i, header->ep_list[i]); 00185 PLUGIN((header->ep_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n); 00186 effect_plugin_init(PLUGIN((header->ep_list)[i])); 00187 } 00188 } 00189 00190 00191 if (header->gp_list) 00192 { 00193 for (i = 0; (header->gp_list)[i] != NULL; i++, n++) 00194 { 00195 plugin_register (filename, PLUGIN_TYPE_GENERAL, i, header->gp_list[i]); 00196 PLUGIN((header->gp_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n); 00197 } 00198 } 00199 00200 if (header->vp_list) 00201 { 00202 for (i = 0; (header->vp_list)[i] != NULL; i++, n++) 00203 { 00204 plugin_register (filename, PLUGIN_TYPE_VIS, i, header->vp_list[i]); 00205 PLUGIN((header->vp_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n); 00206 vis_plugin_init(PLUGIN((header->vp_list)[i])); 00207 } 00208 } 00209 00210 if (header->interface) 00211 plugin_register (filename, PLUGIN_TYPE_IFACE, 0, header->interface); 00212 } 00213 00214 void plugin2_unload(PluginHeader * header, mowgli_node_t * hlist_node) 00215 { 00216 GModule *module; 00217 00218 g_return_if_fail(header->priv_assoc != NULL); 00219 00220 if (header->ip_list != NULL) 00221 { 00222 for (gint i = 0; header->ip_list[i] != NULL; i ++) 00223 { 00224 if (header->ip_list[i]->cleanup != NULL) 00225 header->ip_list[i]->cleanup (); 00226 00227 g_free (header->ip_list[i]->filename); 00228 } 00229 } 00230 00231 if (header->op_list != NULL) 00232 { 00233 for (gint i = 0; header->op_list[i] != NULL; i ++) 00234 g_free (header->op_list[i]->filename); 00235 } 00236 00237 if (header->ep_list != NULL) 00238 { 00239 for (gint i = 0; header->ep_list[i] != NULL; i ++) 00240 { 00241 if (header->ep_list[i]->cleanup != NULL) 00242 header->ep_list[i]->cleanup (); 00243 00244 g_free (header->ep_list[i]->filename); 00245 } 00246 } 00247 00248 if (header->vp_list != NULL) 00249 { 00250 for (gint i = 0; header->vp_list[i] != NULL; i ++) 00251 g_free (header->vp_list[i]->filename); 00252 } 00253 00254 if (header->gp_list != NULL) 00255 { 00256 for (gint i = 0; header->gp_list[i] != NULL; i ++) 00257 g_free (header->gp_list[i]->filename); 00258 } 00259 00260 module = header->priv_assoc->handle; 00261 00262 g_free(header->priv_assoc->filename); 00263 g_free(header->priv_assoc); 00264 00265 if (header->fini) 00266 header->fini(); 00267 00268 mowgli_node_delete(hlist_node, headers_list); 00269 mowgli_node_free(hlist_node); 00270 00271 g_module_close(module); 00272 } 00273 00274 /******************************************************************/ 00275 00276 void module_load (const gchar * filename) 00277 { 00278 GModule *module; 00279 PluginHeader * (* func) (AudAPITable * table); 00280 00281 AUDDBG ("Loading plugin: %s.\n", filename); 00282 00283 if (!(module = g_module_open(filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL))) 00284 { 00285 printf("Failed to load plugin (%s): %s\n", filename, g_module_error()); 00286 return; 00287 } 00288 00289 /* v2 plugin loading */ 00290 if (g_module_symbol (module, "get_plugin_info", (void *) & func)) 00291 { 00292 PluginHeader * header = func (& api_table); 00293 g_return_if_fail (header != NULL); 00294 plugin2_process(header, module, filename); 00295 return; 00296 } 00297 00298 printf("Invalid plugin (%s)\n", filename); 00299 g_module_close(module); 00300 } 00301 00302 static gboolean scan_plugin_func(const gchar * path, const gchar * basename, gpointer data) 00303 { 00304 if (!str_has_suffix_nocase(basename, SHARED_SUFFIX)) 00305 return FALSE; 00306 00307 if (!g_file_test(path, G_FILE_TEST_IS_REGULAR)) 00308 return FALSE; 00309 00310 module_register (path); 00311 00312 return FALSE; 00313 } 00314 00315 static void scan_plugins(const gchar * path) 00316 { 00317 dir_foreach(path, scan_plugin_func, NULL, NULL); 00318 } 00319 00320 static OutputPlugin * output_load_selected (void) 00321 { 00322 if (cfg.output_path == NULL) 00323 return NULL; 00324 00325 PluginHandle * handle = plugin_by_path (cfg.output_path, PLUGIN_TYPE_OUTPUT, 00326 cfg.output_number); 00327 if (handle == NULL) 00328 return NULL; 00329 00330 OutputPlugin * plugin = plugin_get_header (handle); 00331 if (plugin == NULL || plugin->init () != OUTPUT_PLUGIN_INIT_FOUND_DEVICES) 00332 return NULL; 00333 00334 return plugin; 00335 } 00336 00337 static gboolean output_probe_func (PluginHandle * handle, OutputPlugin * * result) 00338 { 00339 AUDDBG ("Probing output plugin %s.\n", plugin_get_name (handle)); 00340 OutputPlugin * plugin = plugin_get_header (handle); 00341 00342 if (plugin == NULL || plugin->init == NULL || plugin->init () != 00343 OUTPUT_PLUGIN_INIT_FOUND_DEVICES) 00344 return TRUE; 00345 00346 * result = plugin; 00347 return FALSE; 00348 } 00349 00350 static OutputPlugin * output_probe (void) 00351 { 00352 OutputPlugin * plugin = NULL; 00353 plugin_for_each (PLUGIN_TYPE_OUTPUT, (PluginForEachFunc) output_probe_func, 00354 & plugin); 00355 00356 if (plugin == NULL) 00357 fprintf (stderr, "ALL OUTPUT PLUGINS FAILED TO INITIALIZE.\n"); 00358 00359 return plugin; 00360 } 00361 00362 void plugin_system_init(void) 00363 { 00364 gchar *dir; 00365 GtkWidget *dialog; 00366 gint dirsel = 0; 00367 00368 audgui_init (& api_table); 00369 00370 if (!g_module_supported()) 00371 { 00372 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Module loading not supported! Plugins will not be loaded.\n")); 00373 gtk_dialog_run(GTK_DIALOG(dialog)); 00374 gtk_widget_destroy(dialog); 00375 return; 00376 } 00377 00378 plugin_registry_load (); 00379 00380 headers_list = mowgli_list_create(); 00381 00382 #ifndef DISABLE_USER_PLUGIN_DIR 00383 scan_plugins(aud_paths[BMP_PATH_USER_PLUGIN_DIR]); 00384 /* 00385 * This is in a separate loop so if the user puts them in the 00386 * wrong dir we'll still get them in the right order (home dir 00387 * first) - Zinx 00388 */ 00389 while (plugin_dir_list[dirsel]) 00390 { 00391 dir = g_build_filename(aud_paths[BMP_PATH_USER_PLUGIN_DIR], plugin_dir_list[dirsel++], NULL); 00392 scan_plugins(dir); 00393 g_free(dir); 00394 } 00395 dirsel = 0; 00396 #endif 00397 00398 while (plugin_dir_list[dirsel]) 00399 { 00400 dir = g_build_filename(PLUGIN_DIR, plugin_dir_list[dirsel++], NULL); 00401 scan_plugins(dir); 00402 g_free(dir); 00403 } 00404 00405 plugin_registry_prune (); 00406 00407 current_output_plugin = output_load_selected (); 00408 00409 if (current_output_plugin == NULL) 00410 current_output_plugin = output_probe (); 00411 00412 general_init (); 00413 } 00414 00415 void plugin_system_cleanup(void) 00416 { 00417 mowgli_node_t *hlist_node; 00418 00419 AUDDBG ("Shutting down plugin system.\n"); 00420 00421 if (current_output_plugin != NULL) 00422 { 00423 if (current_output_plugin->cleanup != NULL) 00424 current_output_plugin->cleanup (); 00425 00426 current_output_plugin = NULL; 00427 } 00428 00429 general_cleanup (); 00430 00431 plugin_registry_save (); 00432 00433 /* XXX: vfs will crash otherwise. -nenolod */ 00434 if (vfs_transports != NULL) 00435 { 00436 g_list_free(vfs_transports); 00437 vfs_transports = NULL; 00438 } 00439 00440 MOWGLI_LIST_FOREACH(hlist_node, headers_list->head) plugin2_unload(hlist_node->data, hlist_node); 00441 00442 mowgli_list_free(headers_list); 00443 }