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 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 <stdio.h>
00023 #include <stdlib.h>
00024 
00025 #include <glib.h>
00026 
00027 #include "debug.h"
00028 #include "effect.h"
00029 #include "general.h"
00030 #include "interface.h"
00031 #include "output.h"
00032 #include "plugin.h"
00033 #include "plugins.h"
00034 #include "ui_preferences.h"
00035 #include "visualization.h"
00036 
00037 static gboolean dummy_plugin_start (PluginHandle * p)
00038 {
00039     return TRUE;
00040 }
00041 
00042 static void dummy_plugin_stop (PluginHandle * p)
00043 {
00044 }
00045 
00046 static const struct {
00047     const gchar * name;
00048     gboolean is_managed, is_single;
00049 
00050     union {
00051         struct {
00052             gboolean (* start) (PluginHandle * plugin);
00053             void (* stop) (PluginHandle * plugin);
00054         } m;
00055 
00056         struct {
00057             PluginHandle * (* probe) (void);
00058             PluginHandle * (* get_current) (void);
00059             gboolean (* set_current) (PluginHandle * plugin);
00060         } s;
00061     } u;
00062 } table[PLUGIN_TYPES] = {
00063  [PLUGIN_TYPE_TRANSPORT] = {"transport",  TRUE, FALSE, .u.m =
00064   {dummy_plugin_start, dummy_plugin_stop}},
00065  [PLUGIN_TYPE_PLAYLIST] = {"playlist",  TRUE, FALSE, .u.m = {dummy_plugin_start,
00066   dummy_plugin_stop}},
00067  [PLUGIN_TYPE_INPUT] = {"input", TRUE, FALSE, .u.m = {dummy_plugin_start,
00068   dummy_plugin_stop}},
00069  [PLUGIN_TYPE_EFFECT] = {"effect", TRUE, FALSE, .u.m = {effect_plugin_start,
00070   effect_plugin_stop}},
00071  [PLUGIN_TYPE_OUTPUT] = {"output", TRUE, TRUE, .u.s = {output_plugin_probe,
00072   output_plugin_get_current, output_plugin_set_current}},
00073  [PLUGIN_TYPE_VIS] = {"visualization", TRUE, FALSE, .u.m = {vis_plugin_start,
00074   vis_plugin_stop}},
00075  [PLUGIN_TYPE_GENERAL] = {"general", TRUE, FALSE, .u.m = {general_plugin_start,
00076   general_plugin_stop}},
00077  [PLUGIN_TYPE_IFACE] = {"interface", TRUE, TRUE, .u.s = {iface_plugin_probe,
00078   iface_plugin_get_current, iface_plugin_set_current}}};
00079 
00080 static gboolean find_enabled_cb (PluginHandle * p, PluginHandle * * pp)
00081 {
00082     * pp = p;
00083     return FALSE;
00084 }
00085 
00086 static PluginHandle * find_enabled (gint type)
00087 {
00088     PluginHandle * p = NULL;
00089     plugin_for_enabled (type, (PluginForEachFunc) find_enabled_cb, & p);
00090     return p;
00091 }
00092 
00093 static void start_single (gint type)
00094 {
00095     PluginHandle * p;
00096 
00097     if ((p = find_enabled (type)) != NULL)
00098     {
00099         AUDDBG ("Starting selected %s plugin %s.\n", table[type].name,
00100          plugin_get_name (p));
00101 
00102         if (table[type].u.s.set_current (p))
00103             return;
00104 
00105         AUDDBG ("%s failed to start.\n", plugin_get_name (p));
00106         plugin_set_enabled (p, FALSE);
00107     }
00108 
00109     AUDDBG ("Probing for %s plugin.\n", table[type].name);
00110 
00111     if ((p = table[type].u.s.probe ()) == NULL)
00112     {
00113         fprintf (stderr, "FATAL: No %s plugin found.\n", table[type].name);
00114         exit (EXIT_FAILURE);
00115     }
00116 
00117     AUDDBG ("Starting %s.\n", plugin_get_name (p));
00118     plugin_set_enabled (p, TRUE);
00119 
00120     if (! table[type].u.s.set_current (p))
00121     {
00122         fprintf (stderr, "FATAL: %s failed to start.\n", plugin_get_name (p));
00123         plugin_set_enabled (p, FALSE);
00124         exit (EXIT_FAILURE);
00125     }
00126 }
00127 
00128 static gboolean start_multi_cb (PluginHandle * p, void * type)
00129 {
00130     AUDDBG ("Starting %s.\n", plugin_get_name (p));
00131 
00132     if (! table[GPOINTER_TO_INT (type)].u.m.start (p))
00133     {
00134         AUDDBG ("%s failed to start; disabling.\n", plugin_get_name (p));
00135         plugin_set_enabled (p, FALSE);
00136     }
00137 
00138     return TRUE;
00139 }
00140 
00141 static void start_plugins (gint type)
00142 {
00143     if (! table[type].is_managed)
00144         return;
00145 
00146     if (table[type].is_single)
00147         start_single (type);
00148     else
00149         plugin_for_enabled (type, (PluginForEachFunc) start_multi_cb,
00150          GINT_TO_POINTER (type));
00151 }
00152 
00153 static VFSConstructor * lookup_transport (const gchar * scheme)
00154 {
00155     PluginHandle * plugin = transport_plugin_for_scheme (scheme);
00156     if (! plugin)
00157         return NULL;
00158 
00159     TransportPlugin * tp = plugin_get_header (plugin);
00160     return tp->vtable;
00161 }
00162 
00163 void start_plugins_one (void)
00164 {
00165     plugin_system_init ();
00166     vfs_set_lookup_func (lookup_transport);
00167 
00168     for (gint i = 0; i < PLUGIN_TYPE_GENERAL; i ++)
00169         start_plugins (i);
00170 }
00171 
00172 void start_plugins_two (void)
00173 {
00174     for (gint i = PLUGIN_TYPE_GENERAL; i < PLUGIN_TYPES; i ++)
00175         start_plugins (i);
00176 }
00177 
00178 static gboolean stop_multi_cb (PluginHandle * p, void * type)
00179 {
00180     AUDDBG ("Shutting down %s.\n", plugin_get_name (p));
00181     table[GPOINTER_TO_INT (type)].u.m.stop (p);
00182     return TRUE;
00183 }
00184 
00185 static void stop_plugins (gint type)
00186 {
00187     if (! table[type].is_managed)
00188         return;
00189 
00190     if (table[type].is_single)
00191     {
00192         AUDDBG ("Shutting down %s.\n", plugin_get_name
00193          (table[type].u.s.get_current ()));
00194         table[type].u.s.set_current (NULL);
00195     }
00196     else
00197         plugin_for_enabled (type, (PluginForEachFunc) stop_multi_cb,
00198          GINT_TO_POINTER (type));
00199 }
00200 
00201 void stop_plugins_two (void)
00202 {
00203     for (gint i = PLUGIN_TYPES - 1; i >= PLUGIN_TYPE_GENERAL; i --)
00204         stop_plugins (i);
00205 }
00206 
00207 void stop_plugins_one (void)
00208 {
00209     for (gint i = PLUGIN_TYPE_GENERAL - 1; i >= 0; i --)
00210         stop_plugins (i);
00211 
00212     vfs_set_lookup_func (NULL);
00213     plugin_system_cleanup ();
00214 }
00215 
00216 PluginHandle * plugin_get_current (gint type)
00217 {
00218     g_return_val_if_fail (table[type].is_managed && table[type].is_single, NULL);
00219     return table[type].u.s.get_current ();
00220 }
00221 
00222 static gboolean enable_single (gint type, PluginHandle * p)
00223 {
00224     PluginHandle * old = table[type].u.s.get_current ();
00225 
00226     AUDDBG ("Switching from %s to %s.\n", plugin_get_name (old),
00227      plugin_get_name (p));
00228     plugin_set_enabled (old, FALSE);
00229     plugin_set_enabled (p, TRUE);
00230 
00231     if (table[type].u.s.set_current (p))
00232         return TRUE;
00233 
00234     fprintf (stderr, "%s failed to start; falling back to %s.\n",
00235      plugin_get_name (p), plugin_get_name (old));
00236     plugin_set_enabled (p, FALSE);
00237     plugin_set_enabled (old, TRUE);
00238 
00239     if (table[type].u.s.set_current (old))
00240         return FALSE;
00241 
00242     fprintf (stderr, "FATAL: %s failed to start.\n", plugin_get_name (old));
00243     plugin_set_enabled (old, FALSE);
00244     exit (EXIT_FAILURE);
00245 }
00246 
00247 static gboolean enable_multi (gint type, PluginHandle * p, gboolean enable)
00248 {
00249     AUDDBG ("%sabling %s.\n", enable ? "En" : "Dis", plugin_get_name (p));
00250     plugin_set_enabled (p, enable);
00251 
00252     if (enable)
00253     {
00254         if (! table[type].u.m.start (p))
00255         {
00256             fprintf (stderr, "%s failed to start.\n", plugin_get_name (p));
00257             plugin_set_enabled (p, FALSE);
00258             return FALSE;
00259         }
00260     }
00261     else
00262         table[type].u.m.stop (p);
00263 
00264     return TRUE;
00265 }
00266 
00267 gboolean plugin_enable (PluginHandle * plugin, gboolean enable)
00268 {
00269     if (! enable == ! plugin_get_enabled (plugin))
00270     {
00271         AUDDBG ("%s is already %sabled.\n", plugin_get_name (plugin), enable ?
00272          "en" : "dis");
00273         return TRUE;
00274     }
00275 
00276     gint type = plugin_get_type (plugin);
00277     g_return_val_if_fail (table[type].is_managed, FALSE);
00278 
00279     if (table[type].is_single)
00280     {
00281         g_return_val_if_fail (enable, FALSE);
00282         return enable_single (type, plugin);
00283     }
00284 
00285     return enable_multi (type, plugin, enable);
00286 }
00287 
00288 /* This doesn't really belong here, but it's a bit of an oddball. */
00289 PluginHandle * plugin_by_widget (/* GtkWidget * */ void * widget)
00290 {
00291     PluginHandle * p;
00292     if ((p = vis_plugin_by_widget (widget)))
00293         return p;
00294     if ((p = general_plugin_by_widget (widget)))
00295         return p;
00296     return NULL;
00297 }