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  * 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 <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 
24 #include <glib.h>
25 
26 #include "debug.h"
27 #include "effect.h"
28 #include "general.h"
29 #include "interface.h"
30 #include "main.h"
31 #include "output.h"
32 #include "plugin.h"
33 #include "plugins.h"
34 #include "ui_preferences.h"
35 #include "visualization.h"
36 
37 static const struct {
38  const char * name;
40 
41  union {
42  struct {
44  void (* stop) (PluginHandle * plugin);
45  } m;
46 
47  struct {
48  PluginHandle * (* probe) (void);
49  PluginHandle * (* get_current) (void);
51  } s;
52  } u;
53 } table[PLUGIN_TYPES] = {
54  [PLUGIN_TYPE_TRANSPORT] = {"transport", FALSE, .u.m = {NULL, NULL}},
55  [PLUGIN_TYPE_PLAYLIST] = {"playlist", FALSE, .u.m = {NULL, NULL}},
56  [PLUGIN_TYPE_INPUT] = {"input", FALSE, .u.m = {NULL, NULL}},
58  [PLUGIN_TYPE_OUTPUT] = {"output", TRUE, .u.s = {output_plugin_probe,
60  [PLUGIN_TYPE_VIS] = {"visualization", FALSE, .u.m = {vis_plugin_start, vis_plugin_stop}},
62  [PLUGIN_TYPE_IFACE] = {"interface", TRUE, .u.s = {iface_plugin_probe,
64 
65 static bool_t find_enabled_cb (PluginHandle * p, void * pp)
66 {
67  * (PluginHandle * *) pp = p;
68  return FALSE;
69 }
70 
72 {
73  PluginHandle * p = NULL;
75  return p;
76 }
77 
78 static void start_single (int type)
79 {
80  PluginHandle * p;
81 
82  if ((p = find_enabled (type)) != NULL)
83  {
84  AUDDBG ("Starting selected %s plugin %s.\n", table[type].name,
85  plugin_get_name (p));
86 
87  if (table[type].u.s.set_current (p))
88  return;
89 
90  AUDDBG ("%s failed to start.\n", plugin_get_name (p));
92  }
93 
94  AUDDBG ("Probing for %s plugin.\n", table[type].name);
95 
96  if ((p = table[type].u.s.probe ()) == NULL)
97  {
98  fprintf (stderr, "FATAL: No %s plugin found.\n", table[type].name);
99  exit (EXIT_FAILURE);
100  }
101 
102  AUDDBG ("Starting %s.\n", plugin_get_name (p));
104 
105  if (! table[type].u.s.set_current (p))
106  {
107  fprintf (stderr, "FATAL: %s failed to start.\n", plugin_get_name (p));
109  exit (EXIT_FAILURE);
110  }
111 }
112 
114 {
115  AUDDBG ("Starting %s.\n", plugin_get_name (p));
116 
117  if (! table[GPOINTER_TO_INT (type)].u.m.start (p))
118  {
119  AUDDBG ("%s failed to start; disabling.\n", plugin_get_name (p));
121  }
122 
123  return TRUE;
124 }
125 
126 static void start_plugins (int type)
127 {
128  if (headless && type == PLUGIN_TYPE_IFACE)
129  return;
130 
131  if (table[type].is_single)
132  start_single (type);
133  else
134  {
135  if (table[type].u.m.start)
136  plugin_for_enabled (type, start_multi_cb, GINT_TO_POINTER (type));
137  }
138 }
139 
140 static VFSConstructor * lookup_transport (const char * scheme)
141 {
143  if (! plugin)
144  return NULL;
145 
146  TransportPlugin * tp = plugin_get_header (plugin);
147  return tp ? tp->vtable : NULL;
148 }
149 
150 void start_plugins_one (void)
151 {
154 
155  for (int i = 0; i < PLUGIN_TYPE_GENERAL; i ++)
156  start_plugins (i);
157 }
158 
159 void start_plugins_two (void)
160 {
161  for (int i = PLUGIN_TYPE_GENERAL; i < PLUGIN_TYPES; i ++)
162  start_plugins (i);
163 }
164 
165 static bool_t misc_cleanup_cb (PluginHandle * p, void * unused)
166 {
168  return TRUE;
169 }
170 
171 static bool_t stop_multi_cb (PluginHandle * p, void * type)
172 {
173  AUDDBG ("Shutting down %s.\n", plugin_get_name (p));
174  table[GPOINTER_TO_INT (type)].u.m.stop (p);
175  return TRUE;
176 }
177 
178 static void stop_plugins (int type)
179 {
180  if (headless && type == PLUGIN_TYPE_IFACE)
181  return;
182 
183  plugin_for_enabled (type, misc_cleanup_cb, GINT_TO_POINTER (type));
184 
185  if (table[type].is_single)
186  {
187  AUDDBG ("Shutting down %s.\n", plugin_get_name
188  (table[type].u.s.get_current ()));
189  table[type].u.s.set_current (NULL);
190  }
191  else
192  {
193  if (table[type].u.m.stop)
194  plugin_for_enabled (type, stop_multi_cb, GINT_TO_POINTER (type));
195  }
196 }
197 
198 void stop_plugins_two (void)
199 {
200  for (int i = PLUGIN_TYPES - 1; i >= PLUGIN_TYPE_GENERAL; i --)
201  stop_plugins (i);
202 }
203 
204 void stop_plugins_one (void)
205 {
206  for (int i = PLUGIN_TYPE_GENERAL - 1; i >= 0; i --)
207  stop_plugins (i);
208 
211 }
212 
214 {
215  g_return_val_if_fail (table[type].is_single, NULL);
216  return table[type].u.s.get_current ();
217 }
218 
220 {
221  PluginHandle * old = table[type].u.s.get_current ();
222 
223  AUDDBG ("Switching from %s to %s.\n", plugin_get_name (old),
224  plugin_get_name (p));
225  plugin_set_enabled (old, FALSE);
227 
228  if (table[type].u.s.set_current (p))
229  return TRUE;
230 
231  fprintf (stderr, "%s failed to start; falling back to %s.\n",
232  plugin_get_name (p), plugin_get_name (old));
234  plugin_set_enabled (old, TRUE);
235 
236  if (table[type].u.s.set_current (old))
237  return FALSE;
238 
239  fprintf (stderr, "FATAL: %s failed to start.\n", plugin_get_name (old));
240  plugin_set_enabled (old, FALSE);
241  exit (EXIT_FAILURE);
242 }
243 
244 static bool_t enable_multi (int type, PluginHandle * p, bool_t enable)
245 {
246  AUDDBG ("%sabling %s.\n", enable ? "En" : "Dis", plugin_get_name (p));
247  plugin_set_enabled (p, enable);
248 
249  if (enable)
250  {
251  if (table[type].u.m.start && ! table[type].u.m.start (p))
252  {
253  fprintf (stderr, "%s failed to start.\n", plugin_get_name (p));
255  return FALSE;
256  }
257  }
258  else
259  {
260  if (table[type].u.m.stop)
261  table[type].u.m.stop (p);
262  }
263 
264  return TRUE;
265 }
266 
268 {
269  if (! enable == ! plugin_get_enabled (plugin))
270  return TRUE;
271 
272  if (! enable)
273  plugin_misc_cleanup (plugin);
274 
275  int type = plugin_get_type (plugin);
276 
277  if (table[type].is_single)
278  {
279  g_return_val_if_fail (enable, FALSE);
280  return enable_single (type, plugin);
281  }
282 
283  return enable_multi (type, plugin, enable);
284 }
285 
286 /* Miscellaneous plugin-related functions ... */
287 
288 PluginHandle * plugin_by_widget (/* GtkWidget * */ void * widget)
289 {
290  PluginHandle * p;
291  if ((p = vis_plugin_by_widget (widget)))
292  return p;
293  if ((p = general_plugin_by_widget (widget)))
294  return p;
295  return NULL;
296 }
297 
298 int plugin_send_message (PluginHandle * plugin, const char * code, const void * data, int size)
299 {
300  if (! plugin_get_enabled (plugin))
301  return ENOSYS;
302 
303  Plugin * header = plugin_get_header (plugin);
304  if (! header || ! PLUGIN_HAS_FUNC (header, take_message))
305  return ENOSYS;
306 
307  return header->take_message (code, data, size);
308 }
309 
311 {
312  g_return_if_fail (plugin_get_enabled (plugin));
313  Plugin * header = plugin_get_header (plugin);
314  g_return_if_fail (header);
315 
316  if (PLUGIN_HAS_FUNC (header, about))
317  header->about ();
318  else if (PLUGIN_HAS_FUNC (header, about_text))
319  plugin_make_about_window (plugin);
320 }
321 
323 {
324  g_return_if_fail (plugin_get_enabled (plugin));
325  Plugin * header = plugin_get_header (plugin);
326  g_return_if_fail (header);
327 
328  if (PLUGIN_HAS_FUNC (header, configure))
329  header->configure ();
330  else if (PLUGIN_HAS_FUNC (header, prefs))
331  plugin_make_config_window (plugin);
332 }