Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
pluginenum.c
Go to the documentation of this file.
1 /*
2  * pluginenum.c
3  * Copyright 2007-2011 William Pitcock and John Lindgren
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions, and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions, and the following disclaimer in the documentation
13  * provided with the distribution.
14  *
15  * This software is provided "as is" and without any warranty, express or
16  * implied. In no event shall the authors be liable for any damages arising from
17  * the use of this software.
18  */
19 
20 #include <assert.h>
21 #include <glib.h>
22 #include <gmodule.h>
23 #include <pthread.h>
24 
25 #include <libaudcore/audstrings.h>
26 #include <libaudgui/init.h>
27 
28 #include "config.h"
29 
30 #include "debug.h"
31 #include "plugin.h"
32 #include "util.h"
33 
34 #define AUD_API_DECLARE
35 #include "drct.h"
36 #include "misc.h"
37 #include "playlist.h"
38 #include "plugins.h"
39 #undef AUD_API_DECLARE
40 
41 static const char * plugin_dir_list[] = {PLUGINSUBS, NULL};
42 
43 char verbose = 0;
44 
46  .drct_api = & drct_api,
47  .misc_api = & misc_api,
48  .playlist_api = & playlist_api,
49  .plugins_api = & plugins_api,
50  .verbose = & verbose};
51 
52 typedef struct {
53  Plugin * header;
54  GModule * module;
55 } LoadedModule;
56 
57 static GList * loaded_modules = NULL;
58 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
59 
60 static void plugin2_process (Plugin * header, GModule * module, const char * filename)
61 {
62  if (header->magic != _AUD_PLUGIN_MAGIC)
63  {
64  fprintf (stderr, " *** ERROR: %s is not a valid Audacious plugin.\n", filename);
65  g_module_close (module);
66  return;
67  }
68 
69  if (header->version < _AUD_PLUGIN_VERSION_MIN || header->version > _AUD_PLUGIN_VERSION)
70  {
71  fprintf (stderr, " *** ERROR: %s is not compatible with this version of Audacious.\n", filename);
72  g_module_close (module);
73  return;
74  }
75 
76  switch (header->type)
77  {
80  case PLUGIN_TYPE_INPUT:
81  case PLUGIN_TYPE_EFFECT:
82  if (PLUGIN_HAS_FUNC (header, init) && ! header->init ())
83  {
84  fprintf (stderr, " *** ERROR: %s failed to initialize.\n", filename);
85  g_module_close (module);
86  return;
87  }
88  break;
89  }
90 
91  pthread_mutex_lock (& mutex);
92  LoadedModule * loaded = g_slice_new (LoadedModule);
93  loaded->header = header;
94  loaded->module = module;
95  loaded_modules = g_list_prepend (loaded_modules, loaded);
96  pthread_mutex_unlock (& mutex);
97 
98  plugin_register_loaded (filename, header);
99 }
100 
102 {
103  Plugin * header = loaded->header;
104 
105  switch (header->type)
106  {
109  case PLUGIN_TYPE_INPUT:
110  case PLUGIN_TYPE_EFFECT:
111  if (PLUGIN_HAS_FUNC (header, cleanup))
112  header->cleanup ();
113  break;
114  }
115 
116  pthread_mutex_lock (& mutex);
117  g_module_close (loaded->module);
118  g_slice_free (LoadedModule, loaded);
119  pthread_mutex_unlock (& mutex);
120 }
121 
122 /******************************************************************/
123 
124 void plugin_load (const char * filename)
125 {
126  GModule *module;
127  Plugin * (* func) (AudAPITable * table);
128 
129  AUDDBG ("Loading plugin: %s.\n", filename);
130 
131  if (!(module = g_module_open(filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL)))
132  {
133  printf("Failed to load plugin (%s): %s\n", filename, g_module_error());
134  return;
135  }
136 
137  /* v2 plugin loading */
138  if (g_module_symbol (module, "get_plugin_info", (void *) & func))
139  {
140  Plugin * header = func (& api_table);
141  g_return_if_fail (header != NULL);
142  plugin2_process(header, module, filename);
143  return;
144  }
145 
146  printf("Invalid plugin (%s)\n", filename);
147  g_module_close(module);
148 }
149 
150 static bool_t scan_plugin_func(const char * path, const char * basename, void * data)
151 {
152  if (!str_has_suffix_nocase(basename, PLUGIN_SUFFIX))
153  return FALSE;
154 
155  if (!g_file_test(path, G_FILE_TEST_IS_REGULAR))
156  return FALSE;
157 
158  plugin_register (path);
159 
160  return FALSE;
161 }
162 
163 static void scan_plugins(const char * path)
164 {
166 }
167 
169 {
170  assert (g_module_supported ());
171 
172  char *dir;
173  int dirsel = 0;
174 
175  audgui_init (& api_table);
176 
178 
179 #ifndef DISABLE_USER_PLUGIN_DIR
181  /*
182  * This is in a separate loop so if the user puts them in the
183  * wrong dir we'll still get them in the right order (home dir
184  * first) - Zinx
185  */
186  while (plugin_dir_list[dirsel])
187  {
188  dir = g_build_filename (get_path (AUD_PATH_USER_PLUGIN_DIR),
189  plugin_dir_list[dirsel ++], NULL);
190  scan_plugins(dir);
191  g_free(dir);
192  }
193  dirsel = 0;
194 #endif
195 
196  while (plugin_dir_list[dirsel])
197  {
198  dir = g_build_filename (get_path (AUD_PATH_PLUGIN_DIR),
199  plugin_dir_list[dirsel ++], NULL);
200  scan_plugins(dir);
201  g_free(dir);
202  }
203 
205 }
206 
208 {
210 
211  for (GList * node = loaded_modules; node != NULL; node = node->next)
212  plugin2_unload (node->data);
213 
214  g_list_free (loaded_modules);
216 
217  audgui_cleanup ();
218 }