Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
plugin-view.c
Go to the documentation of this file.
00001 /*
00002  * plugin-view.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 <gtk/gtk.h>
00023 
00024 #include "plugin.h"
00025 #include "plugins.h"
00026 #include "ui_preferences.h"
00027 
00028 enum {
00029  PVIEW_COL_NODE,
00030  PVIEW_COL_ENABLED,
00031  PVIEW_COL_NAME,
00032  PVIEW_COL_PATH,
00033  PVIEW_COLS
00034 };
00035 
00036 typedef struct {
00037     PluginHandle * p;
00038     GtkTreeModel * model;
00039     GtkTreePath * path;
00040 } Node;
00041 
00042 static PluginHandle * get_selected_plugin (GtkTreeView * tree)
00043 {
00044     Node * n = NULL;
00045 
00046     GtkTreeSelection * sel = gtk_tree_view_get_selection (tree);
00047     GtkTreeModel * model;
00048     GtkTreeIter iter;
00049     if (gtk_tree_selection_get_selected (sel, & model, & iter))
00050         gtk_tree_model_get (model, & iter, PVIEW_COL_NODE, & n, -1);
00051 
00052     return n == NULL ? NULL : n->p;
00053 }
00054 
00055 static Plugin * get_selected_header (GtkTreeView * tree)
00056 {
00057     PluginHandle * p = get_selected_plugin (tree);
00058     g_return_val_if_fail (p != NULL, NULL);
00059     g_return_val_if_fail (plugin_get_enabled (p), NULL);
00060     return plugin_get_header (p);
00061 }
00062 
00063 static void do_enable (GtkCellRendererToggle * cell, const char * path_str,
00064  GtkTreeModel * model)
00065 {
00066     GtkTreePath * path = gtk_tree_path_new_from_string (path_str);
00067     GtkTreeIter iter;
00068     gtk_tree_model_get_iter (model, & iter, path);
00069     gtk_tree_path_free (path);
00070 
00071     Node * n = NULL;
00072     bool_t enabled;
00073     gtk_tree_model_get (model, & iter, PVIEW_COL_NODE, & n,
00074      PVIEW_COL_ENABLED, & enabled, -1);
00075     g_return_if_fail (n != NULL);
00076 
00077     plugin_enable (n->p, ! enabled);
00078 }
00079 
00080 static bool_t list_watcher (PluginHandle * p, Node * n)
00081 {
00082     GtkTreeIter iter;
00083     gtk_tree_model_get_iter (n->model, & iter, n->path);
00084     gtk_list_store_set ((GtkListStore *) n->model, & iter, PVIEW_COL_ENABLED,
00085      plugin_get_enabled (n->p), -1);
00086     return TRUE;
00087 }
00088 
00089 static bool_t fill_cb (PluginHandle * p, GtkTreeModel * model)
00090 {
00091     Node * n = g_slice_new (Node);
00092 
00093     GtkTreeIter iter;
00094     gtk_list_store_append ((GtkListStore *) model, & iter);
00095     gtk_list_store_set ((GtkListStore *) model, & iter, PVIEW_COL_NODE, n,
00096      PVIEW_COL_ENABLED, plugin_get_enabled (p), PVIEW_COL_NAME, plugin_get_name
00097      (p), PVIEW_COL_PATH, plugin_get_filename (p), -1);
00098 
00099     n->p = p;
00100     n->model = model;
00101     n->path = gtk_tree_model_get_path (model, & iter);
00102 
00103     plugin_add_watch (p, (PluginForEachFunc) list_watcher, n);
00104 
00105     return TRUE;
00106 }
00107 
00108 static void list_fill (GtkTreeView * tree, void * type)
00109 {
00110     GtkTreeModel * model = (GtkTreeModel *) gtk_list_store_new (PVIEW_COLS,
00111      G_TYPE_POINTER, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING);
00112     gtk_tree_view_set_model (tree, model);
00113 
00114     GtkTreeViewColumn * col = gtk_tree_view_column_new ();
00115     gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
00116     gtk_tree_view_column_set_resizable (col, FALSE);
00117     gtk_tree_view_append_column (tree, col);
00118 
00119     GtkCellRenderer * rend = gtk_cell_renderer_toggle_new ();
00120     g_signal_connect (rend, "toggled", (GCallback) do_enable, model);
00121     gtk_tree_view_column_pack_start (col, rend, FALSE);
00122     gtk_tree_view_column_set_attributes (col, rend, "active", PVIEW_COL_ENABLED,
00123      NULL);
00124 
00125     for (int i = PVIEW_COL_NAME; i <= PVIEW_COL_PATH; i ++)
00126     {
00127         col = gtk_tree_view_column_new ();
00128         gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
00129         gtk_tree_view_column_set_resizable (col, FALSE);
00130         gtk_tree_view_append_column (tree, col);
00131 
00132         rend = gtk_cell_renderer_text_new ();
00133         gtk_tree_view_column_pack_start (col, rend, FALSE);
00134         gtk_tree_view_column_set_attributes (col, rend, "text", i, NULL);
00135     }
00136 
00137     plugin_for_each (GPOINTER_TO_INT (type), (PluginForEachFunc) fill_cb, model);
00138 }
00139 
00140 static void list_destroy (GtkTreeView * tree)
00141 {
00142     GtkTreeModel * model = gtk_tree_view_get_model (tree);
00143     if (model == NULL)
00144         return;
00145 
00146     GtkTreeIter iter;
00147     if (gtk_tree_model_get_iter_first (model, & iter))
00148     {
00149         do
00150         {
00151             Node * n = NULL;
00152             gtk_tree_model_get (model, & iter, PVIEW_COL_NODE, & n, -1);
00153             g_return_if_fail (n != NULL);
00154 
00155             plugin_remove_watch (n->p, (PluginForEachFunc) list_watcher, n);
00156             gtk_tree_path_free (n->path);
00157             g_slice_free (Node, n);
00158         }
00159         while (gtk_tree_model_iter_next (model, & iter));
00160     }
00161 
00162     g_object_unref ((GObject *) model);
00163 }
00164 
00165 static bool_t config_watcher (PluginHandle * p, GtkWidget * config)
00166 {
00167     gtk_widget_set_sensitive (config, plugin_has_configure (p) &&
00168      plugin_get_enabled (p));
00169     return TRUE;
00170 }
00171 
00172 static bool_t about_watcher (PluginHandle * p, GtkWidget * about)
00173 {
00174     gtk_widget_set_sensitive (about, plugin_has_about (p) && plugin_get_enabled
00175      (p));
00176     return TRUE;
00177 }
00178 
00179 static void button_update (GtkTreeView * tree, GtkWidget * b)
00180 {
00181     PluginForEachFunc watcher = (PluginForEachFunc) g_object_get_data
00182      ((GObject *) b, "watcher");
00183     g_return_if_fail (watcher != NULL);
00184 
00185     PluginHandle * p = g_object_steal_data ((GObject *) b, "plugin");
00186     if (p != NULL)
00187         plugin_remove_watch (p, watcher, b);
00188 
00189     p = get_selected_plugin (tree);
00190     if (p != NULL)
00191     {
00192         g_object_set_data ((GObject *) b, "plugin", p);
00193         watcher (p, b);
00194         plugin_add_watch (p, watcher, b);
00195     }
00196     else
00197         gtk_widget_set_sensitive (b, FALSE);
00198 }
00199 
00200 static void do_config (GtkTreeView * tree)
00201 {
00202     Plugin * header = get_selected_header (tree);
00203     g_return_if_fail (header != NULL);
00204 
00205     if (header->configure != NULL)
00206         header->configure ();
00207     else if (header->settings != NULL)
00208         plugin_preferences_show (header->settings);
00209 }
00210 
00211 static void do_about (GtkTreeView * tree)
00212 {
00213     Plugin * header = get_selected_header (tree);
00214     g_return_if_fail (header != NULL);
00215 
00216     if (header->about != NULL)
00217         header->about ();
00218 }
00219 
00220 static void button_destroy (GtkWidget * b)
00221 {
00222     PluginForEachFunc watcher = (PluginForEachFunc) g_object_get_data
00223      ((GObject *) b, "watcher");
00224     g_return_if_fail (watcher != NULL);
00225 
00226     PluginHandle * p = g_object_steal_data ((GObject *) b, "plugin");
00227     if (p != NULL)
00228         plugin_remove_watch (p, watcher, b);
00229 }
00230 
00231 GtkWidget * plugin_view_new (int type)
00232 {
00233     GtkWidget * vbox = gtk_vbox_new (FALSE, 6);
00234     gtk_container_set_border_width ((GtkContainer *) vbox, 6);
00235 
00236     GtkWidget * scrolled = gtk_scrolled_window_new (NULL, NULL);
00237     gtk_box_pack_start ((GtkBox *) vbox, scrolled, TRUE, TRUE, 0);
00238     gtk_scrolled_window_set_policy ((GtkScrolledWindow *) scrolled,
00239      GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
00240     gtk_scrolled_window_set_shadow_type ((GtkScrolledWindow *) scrolled,
00241      GTK_SHADOW_IN);
00242 
00243     GtkWidget * tree = gtk_tree_view_new ();
00244     gtk_container_add ((GtkContainer *) scrolled, tree);
00245     gtk_tree_view_set_headers_visible ((GtkTreeView *) tree, FALSE);
00246     g_signal_connect (tree, "realize", (GCallback) list_fill, GINT_TO_POINTER
00247      (type));
00248     g_signal_connect (tree, "destroy", (GCallback) list_destroy, NULL);
00249 
00250     GtkWidget * hbox = gtk_hbox_new (FALSE, 6);
00251     gtk_box_pack_start ((GtkBox *) vbox, hbox, FALSE, FALSE, 0);
00252 
00253     GtkWidget * config = gtk_button_new_from_stock (GTK_STOCK_PREFERENCES);
00254     gtk_box_pack_start ((GtkBox *) hbox, config, FALSE, FALSE, 0);
00255     gtk_widget_set_sensitive (config, FALSE);
00256     g_object_set_data ((GObject *) config, "watcher", (void *) config_watcher);
00257     g_signal_connect (tree, "cursor-changed", (GCallback) button_update, config);
00258     g_signal_connect_swapped (config, "clicked", (GCallback)
00259      do_config, tree);
00260     g_signal_connect (config, "destroy", (GCallback) button_destroy, NULL);
00261 
00262     GtkWidget * about = gtk_button_new_from_stock (GTK_STOCK_ABOUT);
00263     gtk_box_pack_start ((GtkBox *) hbox, about, FALSE, FALSE, 0);
00264     gtk_widget_set_sensitive (about, FALSE);
00265     g_object_set_data ((GObject *) about, "watcher", (void *) about_watcher);
00266     g_signal_connect (tree, "cursor-changed", (GCallback) button_update, about);
00267     g_signal_connect_swapped (about, "clicked", (GCallback) do_about, tree);
00268     g_signal_connect (about, "destroy", (GCallback) button_destroy, NULL);
00269 
00270     return vbox;
00271 }