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 #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 }