Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
pluginenum.c
Go to the documentation of this file.
1 /* Audacious - Cross-platform multimedia player
2  * Copyright (C) 2005-2011 Audacious development team
3  *
4  * Based on BMP:
5  * Copyright (C) 2003-2004 BMP development team
6  *
7  * Based on XMMS:
8  * Copyright (C) 1998-2003 XMMS development team
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; under version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses>.
21  *
22  * The Audacious team does not consider modular code linking to
23  * Audacious or using our public API to be a derived work.
24  */
25 
26 #include <assert.h>
27 #include <glib.h>
28 #include <gmodule.h>
29 #include <pthread.h>
30 
31 #include <libaudcore/audstrings.h>
32 #include <libaudgui/init.h>
33 
34 #include "config.h"
35 
36 #ifndef SHARED_SUFFIX
37 # define SHARED_SUFFIX G_MODULE_SUFFIX
38 #endif
39 
40 #include "debug.h"
41 #include "plugin.h"
42 #include "ui_preferences.h"
43 #include "util.h"
44 
45 #define AUD_API_DECLARE
46 #include "drct.h"
47 #include "misc.h"
48 #include "playlist.h"
49 #include "plugins.h"
50 #undef AUD_API_DECLARE
51 
52 static const char * plugin_dir_list[] = {PLUGINSUBS, NULL};
53 
54 char verbose = 0;
55 
57  .drct_api = & drct_api,
58  .misc_api = & misc_api,
59  .playlist_api = & playlist_api,
60  .plugins_api = & plugins_api,
61  .verbose = & verbose};
62 
63 typedef struct {
64  Plugin * header;
65  GModule * module;
66 } LoadedModule;
67 
68 static GList * loaded_modules = NULL;
69 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
70 
71 static void plugin2_process (Plugin * header, GModule * module, const char * filename)
72 {
73  if (header->magic != _AUD_PLUGIN_MAGIC)
74  {
75  fprintf (stderr, " *** ERROR: %s is not a valid Audacious plugin.\n", filename);
76  g_module_close (module);
77  return;
78  }
79 
80  if (header->version < _AUD_PLUGIN_VERSION_MIN || header->version > _AUD_PLUGIN_VERSION)
81  {
82  fprintf (stderr, " *** ERROR: %s is not compatible with this version of Audacious.\n", filename);
83  g_module_close (module);
84  return;
85  }
86 
87  switch (header->type)
88  {
91  case PLUGIN_TYPE_INPUT:
92  case PLUGIN_TYPE_EFFECT:
93  if (PLUGIN_HAS_FUNC (header, init) && ! header->init ())
94  {
95  fprintf (stderr, " *** ERROR: %s failed to initialize.\n", filename);
96  g_module_close (module);
97  return;
98  }
99  break;
100  }
101 
102  pthread_mutex_lock (& mutex);
103  LoadedModule * loaded = g_slice_new (LoadedModule);
104  loaded->header = header;
105  loaded->module = module;
106  loaded_modules = g_list_prepend (loaded_modules, loaded);
107  pthread_mutex_unlock (& mutex);
108 
109  plugin_register_loaded (filename, header);
110 }
111 
113 {
114  Plugin * header = loaded->header;
115 
116  switch (header->type)
117  {
120  case PLUGIN_TYPE_INPUT:
121  case PLUGIN_TYPE_EFFECT:
122  if (PLUGIN_HAS_FUNC (header, settings))
123  plugin_preferences_cleanup (header->settings);
124  if (PLUGIN_HAS_FUNC (header, cleanup))
125  header->cleanup ();
126  break;
127  }
128 
129  pthread_mutex_lock (& mutex);
130  g_module_close (loaded->module);
131  g_slice_free (LoadedModule, loaded);
132  pthread_mutex_unlock (& mutex);
133 }
134 
135 /******************************************************************/
136 
137 void plugin_load (const char * filename)
138 {
139  GModule *module;
140  Plugin * (* func) (AudAPITable * table);
141 
142  AUDDBG ("Loading plugin: %s.\n", filename);
143 
144  if (!(module = g_module_open(filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL)))
145  {
146  printf("Failed to load plugin (%s): %s\n", filename, g_module_error());
147  return;
148  }
149 
150  /* v2 plugin loading */
151  if (g_module_symbol (module, "get_plugin_info", (void *) & func))
152  {
153  Plugin * header = func (& api_table);
154  g_return_if_fail (header != NULL);
155  plugin2_process(header, module, filename);
156  return;
157  }
158 
159  printf("Invalid plugin (%s)\n", filename);
160  g_module_close(module);
161 }
162 
163 static bool_t scan_plugin_func(const char * path, const char * basename, gpointer data)
164 {
165  if (!str_has_suffix_nocase(basename, SHARED_SUFFIX))
166  return FALSE;
167 
168  if (!g_file_test(path, G_FILE_TEST_IS_REGULAR))
169  return FALSE;
170 
171  plugin_register (path);
172 
173  return FALSE;
174 }
175 
176 static void scan_plugins(const char * path)
177 {
179 }
180 
182 {
183  assert (g_module_supported ());
184 
185  char *dir;
186  int dirsel = 0;
187 
188  audgui_init (& api_table);
189 
191 
192 #ifndef DISABLE_USER_PLUGIN_DIR
194  /*
195  * This is in a separate loop so if the user puts them in the
196  * wrong dir we'll still get them in the right order (home dir
197  * first) - Zinx
198  */
199  while (plugin_dir_list[dirsel])
200  {
201  dir = g_build_filename (get_path (AUD_PATH_USER_PLUGIN_DIR),
202  plugin_dir_list[dirsel ++], NULL);
203  scan_plugins(dir);
204  g_free(dir);
205  }
206  dirsel = 0;
207 #endif
208 
209  while (plugin_dir_list[dirsel])
210  {
211  dir = g_build_filename (get_path (AUD_PATH_PLUGIN_DIR),
212  plugin_dir_list[dirsel ++], NULL);
213  scan_plugins(dir);
214  g_free(dir);
215  }
216 
218 }
219 
221 {
223 
224  for (GList * node = loaded_modules; node != NULL; node = node->next)
225  plugin2_unload (node->data);
226 
227  g_list_free (loaded_modules);
229 
230  audgui_cleanup ();
231 }