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