Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$
plugin-init.c
Go to the documentation of this file.
00001 /*
00002  * plugin-init.c
00003  * Copyright 2010-2011 John Lindgren
00004  *
00005  * This file is part of Audacious.
00006  *
00007  * Audacious is free software: you can redistribute it and/or modify it under
00008  * the terms of the GNU General Public License as published by the Free Software
00009  * Foundation, version 2 or version 3 of the License.
00010  *
00011  * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
00012  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
00013  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License along with
00016  * Audacious. If not, see <http://www.gnu.org/licenses/>.
00017  *
00018  * The Audacious team does not consider modular code linking to Audacious or
00019  * using our public API to be a derived work.
00020  */
00021 
00022 #include <errno.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 
00026 #include <glib.h>
00027 
00028 #include "debug.h"
00029 #include "effect.h"
00030 #include "general.h"
00031 #include "interface.h"
00032 #include "main.h"
00033 #include "output.h"
00034 #include "plugin.h"
00035 #include "plugins.h"
00036 #include "ui_preferences.h"
00037 #include "visualization.h"
00038 
00039 static bool_t dummy_plugin_start (PluginHandle * p)
00040 {
00041     return TRUE;
00042 }
00043 
00044 static void dummy_plugin_stop (PluginHandle * p)
00045 {
00046 }
00047 
00048 static const struct {
00049     const char * name;
00050     bool_t is_managed, is_single;
00051 
00052     union {
00053         struct {
00054             bool_t (* start) (PluginHandle * plugin);
00055             void (* stop) (PluginHandle * plugin);
00056         } m;
00057 
00058         struct {
00059             PluginHandle * (* probe) (void);
00060             PluginHandle * (* get_current) (void);
00061             bool_t (* set_current) (PluginHandle * plugin);
00062         } s;
00063     } u;
00064 } table[PLUGIN_TYPES] = {
00065  [PLUGIN_TYPE_TRANSPORT] = {"transport",  TRUE, FALSE, .u.m =
00066   {dummy_plugin_start, dummy_plugin_stop}},
00067  [PLUGIN_TYPE_PLAYLIST] = {"playlist",  TRUE, FALSE, .u.m = {dummy_plugin_start,
00068   dummy_plugin_stop}},
00069  [PLUGIN_TYPE_INPUT] = {"input", TRUE, FALSE, .u.m = {dummy_plugin_start,
00070   dummy_plugin_stop}},
00071  [PLUGIN_TYPE_EFFECT] = {"effect", TRUE, FALSE, .u.m = {effect_plugin_start,
00072   effect_plugin_stop}},
00073  [PLUGIN_TYPE_OUTPUT] = {"output", TRUE, TRUE, .u.s = {output_plugin_probe,
00074   output_plugin_get_current, output_plugin_set_current}},
00075  [PLUGIN_TYPE_VIS] = {"visualization", TRUE, FALSE, .u.m = {vis_plugin_start,
00076   vis_plugin_stop}},
00077  [PLUGIN_TYPE_GENERAL] = {"general", TRUE, FALSE, .u.m = {general_plugin_start,
00078   general_plugin_stop}},
00079  [PLUGIN_TYPE_IFACE] = {"interface", TRUE, TRUE, .u.s = {iface_plugin_probe,
00080   iface_plugin_get_current, iface_plugin_set_current}}};
00081 
00082 static bool_t find_enabled_cb (PluginHandle * p, PluginHandle * * pp)
00083 {
00084     * pp = p;
00085     return FALSE;
00086 }
00087 
00088 static PluginHandle * find_enabled (int type)
00089 {
00090     PluginHandle * p = NULL;
00091     plugin_for_enabled (type, (PluginForEachFunc) find_enabled_cb, & p);
00092     return p;
00093 }
00094 
00095 static void start_single (int type)
00096 {
00097     PluginHandle * p;
00098 
00099     if ((p = find_enabled (type)) != NULL)
00100     {
00101         AUDDBG ("Starting selected %s plugin %s.\n", table[type].name,
00102          plugin_get_name (p));
00103 
00104         if (table[type].u.s.set_current (p))
00105             return;
00106 
00107         AUDDBG ("%s failed to start.\n", plugin_get_name (p));
00108         plugin_set_enabled (p, FALSE);
00109     }
00110 
00111     AUDDBG ("Probing for %s plugin.\n", table[type].name);
00112 
00113     if ((p = table[type].u.s.probe ()) == NULL)
00114     {
00115         fprintf (stderr, "FATAL: No %s plugin found.\n", table[type].name);
00116         exit (EXIT_FAILURE);
00117     }
00118 
00119     AUDDBG ("Starting %s.\n", plugin_get_name (p));
00120     plugin_set_enabled (p, TRUE);
00121 
00122     if (! table[type].u.s.set_current (p))
00123     {
00124         fprintf (stderr, "FATAL: %s failed to start.\n", plugin_get_name (p));
00125         plugin_set_enabled (p, FALSE);
00126         exit (EXIT_FAILURE);
00127     }
00128 }
00129 
00130 static bool_t start_multi_cb (PluginHandle * p, void * type)
00131 {
00132     AUDDBG ("Starting %s.\n", plugin_get_name (p));
00133 
00134     if (! table[GPOINTER_TO_INT (type)].u.m.start (p))
00135     {
00136         AUDDBG ("%s failed to start; disabling.\n", plugin_get_name (p));
00137         plugin_set_enabled (p, FALSE);
00138     }
00139 
00140     return TRUE;
00141 }
00142 
00143 static void start_plugins (int type)
00144 {
00145     if (! table[type].is_managed)
00146         return;
00147     if (headless && type == PLUGIN_TYPE_IFACE)
00148         return;
00149 
00150     if (table[type].is_single)
00151         start_single (type);
00152     else
00153         plugin_for_enabled (type, (PluginForEachFunc) start_multi_cb,
00154          GINT_TO_POINTER (type));
00155 }
00156 
00157 static VFSConstructor * lookup_transport (const char * scheme)
00158 {
00159     PluginHandle * plugin = transport_plugin_for_scheme (scheme);
00160     if (! plugin)
00161         return NULL;
00162 
00163     TransportPlugin * tp = plugin_get_header (plugin);
00164     return tp ? tp->vtable : NULL;
00165 }
00166 
00167 void start_plugins_one (void)
00168 {
00169     plugin_system_init ();
00170     vfs_set_lookup_func (lookup_transport);
00171 
00172     for (int i = 0; i < PLUGIN_TYPE_GENERAL; i ++)
00173         start_plugins (i);
00174 }
00175 
00176 void start_plugins_two (void)
00177 {
00178     for (int i = PLUGIN_TYPE_GENERAL; i < PLUGIN_TYPES; i ++)
00179         start_plugins (i);
00180 }
00181 
00182 static bool_t stop_multi_cb (PluginHandle * p, void * type)
00183 {
00184     AUDDBG ("Shutting down %s.\n", plugin_get_name (p));
00185     table[GPOINTER_TO_INT (type)].u.m.stop (p);
00186     return TRUE;
00187 }
00188 
00189 static void stop_plugins (int type)
00190 {
00191     if (! table[type].is_managed)
00192         return;
00193     if (headless && type == PLUGIN_TYPE_IFACE)
00194         return;
00195 
00196     if (table[type].is_single)
00197     {
00198         AUDDBG ("Shutting down %s.\n", plugin_get_name
00199          (table[type].u.s.get_current ()));
00200         table[type].u.s.set_current (NULL);
00201     }
00202     else
00203         plugin_for_enabled (type, (PluginForEachFunc) stop_multi_cb,
00204          GINT_TO_POINTER (type));
00205 }
00206 
00207 void stop_plugins_two (void)
00208 {
00209     for (int i = PLUGIN_TYPES - 1; i >= PLUGIN_TYPE_GENERAL; i --)
00210         stop_plugins (i);
00211 }
00212 
00213 void stop_plugins_one (void)
00214 {
00215     for (int i = PLUGIN_TYPE_GENERAL - 1; i >= 0; i --)
00216         stop_plugins (i);
00217 
00218     vfs_set_lookup_func (NULL);
00219     plugin_system_cleanup ();
00220 }
00221 
00222 PluginHandle * plugin_get_current (int type)
00223 {
00224     g_return_val_if_fail (table[type].is_managed && table[type].is_single, NULL);
00225     return table[type].u.s.get_current ();
00226 }
00227 
00228 static bool_t enable_single (int type, PluginHandle * p)
00229 {
00230     PluginHandle * old = table[type].u.s.get_current ();
00231 
00232     AUDDBG ("Switching from %s to %s.\n", plugin_get_name (old),
00233      plugin_get_name (p));
00234     plugin_set_enabled (old, FALSE);
00235     plugin_set_enabled (p, TRUE);
00236 
00237     if (table[type].u.s.set_current (p))
00238         return TRUE;
00239 
00240     fprintf (stderr, "%s failed to start; falling back to %s.\n",
00241      plugin_get_name (p), plugin_get_name (old));
00242     plugin_set_enabled (p, FALSE);
00243     plugin_set_enabled (old, TRUE);
00244 
00245     if (table[type].u.s.set_current (old))
00246         return FALSE;
00247 
00248     fprintf (stderr, "FATAL: %s failed to start.\n", plugin_get_name (old));
00249     plugin_set_enabled (old, FALSE);
00250     exit (EXIT_FAILURE);
00251 }
00252 
00253 static bool_t enable_multi (int type, PluginHandle * p, bool_t enable)
00254 {
00255     AUDDBG ("%sabling %s.\n", enable ? "En" : "Dis", plugin_get_name (p));
00256     plugin_set_enabled (p, enable);
00257 
00258     if (enable)
00259     {
00260         if (! table[type].u.m.start (p))
00261         {
00262             fprintf (stderr, "%s failed to start.\n", plugin_get_name (p));
00263             plugin_set_enabled (p, FALSE);
00264             return FALSE;
00265         }
00266     }
00267     else
00268         table[type].u.m.stop (p);
00269 
00270     return TRUE;
00271 }
00272 
00273 bool_t plugin_enable (PluginHandle * plugin, bool_t enable)
00274 {
00275     if (! enable == ! plugin_get_enabled (plugin))
00276     {
00277         AUDDBG ("%s is already %sabled.\n", plugin_get_name (plugin), enable ?
00278          "en" : "dis");
00279         return TRUE;
00280     }
00281 
00282     int type = plugin_get_type (plugin);
00283     g_return_val_if_fail (table[type].is_managed, FALSE);
00284 
00285     if (table[type].is_single)
00286     {
00287         g_return_val_if_fail (enable, FALSE);
00288         return enable_single (type, plugin);
00289     }
00290 
00291     return enable_multi (type, plugin, enable);
00292 }
00293 
00294 /* Miscellaneous plugin-related functions ... */
00295 
00296 PluginHandle * plugin_by_widget (/* GtkWidget * */ void * widget)
00297 {
00298     PluginHandle * p;
00299     if ((p = vis_plugin_by_widget (widget)))
00300         return p;
00301     if ((p = general_plugin_by_widget (widget)))
00302         return p;
00303     return NULL;
00304 }
00305 
00306 int plugin_send_message (PluginHandle * plugin, const char * code, const void * data, int size)
00307 {
00308     if (! plugin_get_enabled (plugin))
00309         return ENOSYS;
00310 
00311     Plugin * header = plugin_get_header (plugin);
00312     if (! header || ! PLUGIN_HAS_FUNC (header, take_message))
00313         return ENOSYS;
00314 
00315     return header->take_message (code, data, size);
00316 }