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