Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
plugin-init.c
Go to the documentation of this file.
1 /*
2  * plugin-init.c
3  * Copyright 2010-2011 John Lindgren
4  *
5  * This file is part of Audacious.
6  *
7  * Audacious is free software: you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License as published by the Free Software
9  * Foundation, version 2 or version 3 of the License.
10  *
11  * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * Audacious. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * The Audacious team does not consider modular code linking to Audacious or
19  * using our public API to be a derived work.
20  */
21 
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 
26 #include <glib.h>
27 
28 #include "debug.h"
29 #include "effect.h"
30 #include "general.h"
31 #include "interface.h"
32 #include "main.h"
33 #include "output.h"
34 #include "plugin.h"
35 #include "plugins.h"
36 #include "ui_preferences.h"
37 #include "visualization.h"
38 
40 {
41  return TRUE;
42 }
43 
45 {
46 }
47 
48 static const struct {
49  const char * name;
51 
52  union {
53  struct {
55  void (* stop) (PluginHandle * plugin);
56  } m;
57 
58  struct {
59  PluginHandle * (* probe) (void);
60  PluginHandle * (* get_current) (void);
62  } s;
63  } u;
64 } table[PLUGIN_TYPES] = {
65  [PLUGIN_TYPE_TRANSPORT] = {"transport", TRUE, FALSE, .u.m =
67  [PLUGIN_TYPE_PLAYLIST] = {"playlist", TRUE, FALSE, .u.m = {dummy_plugin_start,
69  [PLUGIN_TYPE_INPUT] = {"input", TRUE, FALSE, .u.m = {dummy_plugin_start,
71  [PLUGIN_TYPE_EFFECT] = {"effect", TRUE, FALSE, .u.m = {effect_plugin_start,
73  [PLUGIN_TYPE_OUTPUT] = {"output", TRUE, TRUE, .u.s = {output_plugin_probe,
75  [PLUGIN_TYPE_VIS] = {"visualization", TRUE, FALSE, .u.m = {vis_plugin_start,
77  [PLUGIN_TYPE_GENERAL] = {"general", TRUE, FALSE, .u.m = {general_plugin_start,
79  [PLUGIN_TYPE_IFACE] = {"interface", TRUE, TRUE, .u.s = {iface_plugin_probe,
81 
83 {
84  * pp = p;
85  return FALSE;
86 }
87 
89 {
90  PluginHandle * p = NULL;
92  return p;
93 }
94 
95 static void start_single (int type)
96 {
97  PluginHandle * p;
98 
99  if ((p = find_enabled (type)) != NULL)
100  {
101  AUDDBG ("Starting selected %s plugin %s.\n", table[type].name,
102  plugin_get_name (p));
103 
104  if (table[type].u.s.set_current (p))
105  return;
106 
107  AUDDBG ("%s failed to start.\n", plugin_get_name (p));
109  }
110 
111  AUDDBG ("Probing for %s plugin.\n", table[type].name);
112 
113  if ((p = table[type].u.s.probe ()) == NULL)
114  {
115  fprintf (stderr, "FATAL: No %s plugin found.\n", table[type].name);
116  exit (EXIT_FAILURE);
117  }
118 
119  AUDDBG ("Starting %s.\n", plugin_get_name (p));
121 
122  if (! table[type].u.s.set_current (p))
123  {
124  fprintf (stderr, "FATAL: %s failed to start.\n", plugin_get_name (p));
126  exit (EXIT_FAILURE);
127  }
128 }
129 
131 {
132  AUDDBG ("Starting %s.\n", plugin_get_name (p));
133 
134  if (! table[GPOINTER_TO_INT (type)].u.m.start (p))
135  {
136  AUDDBG ("%s failed to start; disabling.\n", plugin_get_name (p));
138  }
139 
140  return TRUE;
141 }
142 
143 static void start_plugins (int type)
144 {
145  if (! table[type].is_managed)
146  return;
147  if (headless && type == PLUGIN_TYPE_IFACE)
148  return;
149 
150  if (table[type].is_single)
151  start_single (type);
152  else
154  GINT_TO_POINTER (type));
155 }
156 
157 static VFSConstructor * lookup_transport (const char * scheme)
158 {
160  if (! plugin)
161  return NULL;
162 
163  TransportPlugin * tp = plugin_get_header (plugin);
164  return tp ? tp->vtable : NULL;
165 }
166 
167 void start_plugins_one (void)
168 {
171 
172  for (int i = 0; i < PLUGIN_TYPE_GENERAL; i ++)
173  start_plugins (i);
174 }
175 
176 void start_plugins_two (void)
177 {
178  for (int i = PLUGIN_TYPE_GENERAL; i < PLUGIN_TYPES; i ++)
179  start_plugins (i);
180 }
181 
182 static bool_t stop_multi_cb (PluginHandle * p, void * type)
183 {
184  AUDDBG ("Shutting down %s.\n", plugin_get_name (p));
185  table[GPOINTER_TO_INT (type)].u.m.stop (p);
186  return TRUE;
187 }
188 
189 static void stop_plugins (int type)
190 {
191  if (! table[type].is_managed)
192  return;
193  if (headless && type == PLUGIN_TYPE_IFACE)
194  return;
195 
196  if (table[type].is_single)
197  {
198  AUDDBG ("Shutting down %s.\n", plugin_get_name
199  (table[type].u.s.get_current ()));
200  table[type].u.s.set_current (NULL);
201  }
202  else
204  GINT_TO_POINTER (type));
205 }
206 
207 void stop_plugins_two (void)
208 {
209  for (int i = PLUGIN_TYPES - 1; i >= PLUGIN_TYPE_GENERAL; i --)
210  stop_plugins (i);
211 }
212 
213 void stop_plugins_one (void)
214 {
215  for (int i = PLUGIN_TYPE_GENERAL - 1; i >= 0; i --)
216  stop_plugins (i);
217 
220 }
221 
223 {
224  g_return_val_if_fail (table[type].is_managed && table[type].is_single, NULL);
225  return table[type].u.s.get_current ();
226 }
227 
229 {
230  PluginHandle * old = table[type].u.s.get_current ();
231 
232  AUDDBG ("Switching from %s to %s.\n", plugin_get_name (old),
233  plugin_get_name (p));
234  plugin_set_enabled (old, FALSE);
236 
237  if (table[type].u.s.set_current (p))
238  return TRUE;
239 
240  fprintf (stderr, "%s failed to start; falling back to %s.\n",
241  plugin_get_name (p), plugin_get_name (old));
243  plugin_set_enabled (old, TRUE);
244 
245  if (table[type].u.s.set_current (old))
246  return FALSE;
247 
248  fprintf (stderr, "FATAL: %s failed to start.\n", plugin_get_name (old));
249  plugin_set_enabled (old, FALSE);
250  exit (EXIT_FAILURE);
251 }
252 
253 static bool_t enable_multi (int type, PluginHandle * p, bool_t enable)
254 {
255  AUDDBG ("%sabling %s.\n", enable ? "En" : "Dis", plugin_get_name (p));
256  plugin_set_enabled (p, enable);
257 
258  if (enable)
259  {
260  if (! table[type].u.m.start (p))
261  {
262  fprintf (stderr, "%s failed to start.\n", plugin_get_name (p));
264  return FALSE;
265  }
266  }
267  else
268  table[type].u.m.stop (p);
269 
270  return TRUE;
271 }
272 
274 {
275  if (! enable == ! plugin_get_enabled (plugin))
276  {
277  AUDDBG ("%s is already %sabled.\n", plugin_get_name (plugin), enable ?
278  "en" : "dis");
279  return TRUE;
280  }
281 
282  int type = plugin_get_type (plugin);
283  g_return_val_if_fail (table[type].is_managed, FALSE);
284 
285  if (table[type].is_single)
286  {
287  g_return_val_if_fail (enable, FALSE);
288  return enable_single (type, plugin);
289  }
290 
291  return enable_multi (type, plugin, enable);
292 }
293 
294 /* Miscellaneous plugin-related functions ... */
295 
296 PluginHandle * plugin_by_widget (/* GtkWidget * */ void * widget)
297 {
298  PluginHandle * p;
299  if ((p = vis_plugin_by_widget (widget)))
300  return p;
301  if ((p = general_plugin_by_widget (widget)))
302  return p;
303  return NULL;
304 }
305 
306 int plugin_send_message (PluginHandle * plugin, const char * code, const void * data, int size)
307 {
308  if (! plugin_get_enabled (plugin))
309  return ENOSYS;
310 
311  Plugin * header = plugin_get_header (plugin);
312  if (! header || ! PLUGIN_HAS_FUNC (header, take_message))
313  return ENOSYS;
314 
315  return header->take_message (code, data, size);
316 }