1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3
* heavily based on code from Gedit
5
* Copyright (C) 2002 Paolo Maggi and James Willcox
6
* Copyright (C) 2003-2005 Paolo Maggi
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
13
* The Rhythmbox authors hereby grant permission for non-GPL compatible
14
* GStreamer plugins to be used and distributed together with GStreamer
15
* and Rhythmbox. This permission is above and beyond the permissions granted
16
* by the GPL license by which Rhythmbox is covered. If you modify this code
17
* you may extend this exception to your version of the code, but you are not
18
* obligated to do so. If you do not wish to do so, delete this exception
19
* statement from your version.
21
* This program is distributed in the hope that it will be useful,
22
* but WITHOUT ANY WARRANTY; without even the implied warranty of
23
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
* GNU General Public License for more details.
26
* You should have received a copy of the GNU General Public License
27
* along with this program; if not, write to the Free Software
28
* Foundation, Inc., 51 Franklin St, Fifth Floor,
29
* Boston, MA 02110-1301 USA.
38
#include <glib/gi18n.h>
40
#include "rb-plugin-manager.h"
41
#include "rb-plugins-engine.h"
42
#include "rb-plugin.h"
44
#include "rb-builder-helpers.h"
54
#define PLUGIN_MANAGER_NAME_TITLE _("Plugin")
55
#define PLUGIN_MANAGER_ACTIVE_TITLE _("Enabled")
57
#define RB_PLUGIN_MANAGER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), RB_TYPE_PLUGIN_MANAGER, RBPluginManagerPrivate))
59
struct _RBPluginManagerPrivate
63
GtkTreeModel *plugin_model;
65
GtkWidget *configure_button;
66
GtkWidget *site_label;
67
GtkWidget *copyright_label;
68
GtkWidget *authors_label;
69
GtkWidget *description_label;
70
GtkWidget *header_hbox;
71
GtkWidget *plugin_icon;
73
GtkWidget *copyright_text;
74
GtkWidget *authors_text;
75
GtkWidget *description_text;
76
GtkWidget *plugin_title;
79
G_DEFINE_TYPE(RBPluginManager, rb_plugin_manager, GTK_TYPE_VBOX)
81
static void rb_plugin_manager_finalize (GObject *o);
82
static RBPluginInfo *plugin_manager_get_selected_plugin (RBPluginManager *pm);
83
static void plugin_manager_toggle_active (GtkTreeIter *iter, GtkTreeModel *model, RBPluginManager *pm);
84
static void plugin_manager_toggle_all (RBPluginManager *pm);
87
rb_plugin_manager_class_init (RBPluginManagerClass *klass)
89
GObjectClass *object_class = G_OBJECT_CLASS (klass);
91
object_class->finalize = rb_plugin_manager_finalize;
93
g_type_class_add_private (object_class, sizeof (RBPluginManagerPrivate));
97
configure_button_cb (GtkWidget *button,
103
info = plugin_manager_get_selected_plugin (pm);
105
g_return_if_fail (info != NULL);
107
rb_debug ("Configuring: %s", rb_plugins_engine_get_plugin_name (info));
109
toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (pm)));
111
rb_plugins_engine_configure_plugin (info, toplevel);
113
rb_debug ("Done configuring plugin");
117
plugin_manager_view_cell_cb (GtkTreeViewColumn *tree_column,
118
GtkCellRenderer *cell,
119
GtkTreeModel *tree_model,
125
g_return_if_fail (tree_model != NULL);
126
g_return_if_fail (tree_column != NULL);
128
gtk_tree_model_get (tree_model, iter, INFO_COLUMN, &info, -1);
133
g_return_if_fail (rb_plugins_engine_get_plugin_name (info) != NULL);
135
g_object_set (G_OBJECT (cell),
137
rb_plugins_engine_get_plugin_name (info),
142
active_toggled_cb (GtkCellRendererToggle *cell,
150
path = gtk_tree_path_new_from_string (path_str);
152
model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
153
g_return_if_fail (model != NULL);
155
if (gtk_tree_model_get_iter (model, &iter, path))
156
plugin_manager_toggle_active (&iter, model, pm);
158
gtk_tree_path_free (path);
162
cursor_changed_cb (GtkTreeSelection *selection,
165
RBPluginManager *pm = data;
169
const gchar **authors;
171
info = plugin_manager_get_selected_plugin (pm);
176
/* update info widgets */
177
string = g_strdup_printf ("<span size=\"x-large\">%s</span>",
178
rb_plugins_engine_get_plugin_name (info));
179
gtk_label_set_markup (GTK_LABEL (pm->priv->plugin_title), string);
181
gtk_label_set_text (GTK_LABEL (pm->priv->description_text),
182
rb_plugins_engine_get_plugin_description (info));
183
gtk_label_set_text (GTK_LABEL (pm->priv->copyright_text),
184
rb_plugins_engine_get_plugin_copyright (info));
185
gtk_label_set_text (GTK_LABEL (pm->priv->site_text),
186
rb_plugins_engine_get_plugin_website (info));
188
authors = rb_plugins_engine_get_plugin_authors (info);
189
if (authors != NULL) {
190
string = g_strjoinv ("\n", (gchar **)authors);
191
gtk_label_set_text (GTK_LABEL (pm->priv->authors_text), string);
194
gtk_label_set_text (GTK_LABEL (pm->priv->authors_text), NULL);
197
icon = rb_plugins_engine_get_plugin_icon (info);
199
/* rescale icon to fit header if needed */
200
GtkAllocation allocation;
201
GdkPixbuf *icon_scaled;
202
gint width, height, header_height;
204
gtk_widget_get_allocation (pm->priv->header_hbox, &allocation);
206
width = gdk_pixbuf_get_width (icon);
207
height = gdk_pixbuf_get_height (icon);
208
header_height = allocation.height;
209
if (height > header_height) {
210
icon_scaled = gdk_pixbuf_scale_simple (icon,
211
(gfloat)width/height*header_height, header_height,
212
GDK_INTERP_BILINEAR);
213
gtk_image_set_from_pixbuf (GTK_IMAGE (pm->priv->plugin_icon), icon_scaled);
214
g_object_unref (G_OBJECT (icon_scaled));
216
gtk_image_set_from_pixbuf (GTK_IMAGE (pm->priv->plugin_icon), icon);
219
gtk_image_set_from_pixbuf (GTK_IMAGE (pm->priv->plugin_icon), NULL);
222
gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->configure_button),
224
rb_plugins_engine_plugin_is_configurable (info));
228
row_activated_cb (GtkTreeView *tree_view,
230
GtkTreeViewColumn *column,
233
RBPluginManager *pm = data;
238
model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
239
g_return_if_fail (model != NULL);
241
found = gtk_tree_model_get_iter (model, &iter, path);
242
g_return_if_fail (found);
244
plugin_manager_toggle_active (&iter, model, pm);
248
column_clicked_cb (GtkTreeViewColumn *tree_column,
251
RBPluginManager *pm = RB_PLUGIN_MANAGER (data);
253
plugin_manager_toggle_all (pm);
257
plugin_manager_populate_lists (RBPluginManager *pm)
263
for (p = pm->priv->plugins; p != NULL; p = g_list_next (p)) {
265
info = (RBPluginInfo *)p->data;
267
gtk_list_store_append (GTK_LIST_STORE (pm->priv->plugin_model), &iter);
268
gtk_list_store_set (GTK_LIST_STORE (pm->priv->plugin_model), &iter,
269
ACTIVE_COLUMN, rb_plugins_engine_plugin_is_active (info),
270
VISIBLE_COLUMN, rb_plugins_engine_plugin_is_visible (info),
275
model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
276
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter)) {
277
GtkTreeSelection *selection;
279
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
280
g_return_if_fail (selection != NULL);
282
gtk_tree_selection_select_iter (selection, &iter);
287
plugin_manager_set_active (GtkTreeIter *iter,
293
GtkTreeIter child_iter;
295
gtk_tree_model_get (model, iter, INFO_COLUMN, &info, -1);
297
g_return_if_fail (info != NULL);
300
/* activate the plugin */
301
if (!rb_plugins_engine_activate_plugin (info)) {
302
rb_debug ("Could not activate %s.", rb_plugins_engine_get_plugin_name (info));
306
/* deactivate the plugin */
307
if (!rb_plugins_engine_deactivate_plugin (info)) {
308
rb_debug ("Could not deactivate %s.", rb_plugins_engine_get_plugin_name (info));
314
gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
316
gtk_list_store_set (GTK_LIST_STORE (pm->priv->plugin_model),
319
rb_plugins_engine_plugin_is_active (info),
322
/* cause the configure button sensitivity to be updated */
323
cursor_changed_cb (gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree)), pm);
327
plugin_manager_toggle_active (GtkTreeIter *iter,
331
gboolean active, visible;
333
gtk_tree_model_get (model, iter,
334
ACTIVE_COLUMN, &active,
335
VISIBLE_COLUMN, &visible,
340
plugin_manager_set_active (iter, model, active, pm);
344
static RBPluginInfo *
345
plugin_manager_get_selected_plugin (RBPluginManager *pm)
347
RBPluginInfo *info = NULL;
350
GtkTreeSelection *selection;
352
model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
353
g_return_val_if_fail (model != NULL, NULL);
355
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
356
g_return_val_if_fail (selection != NULL, NULL);
358
if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
359
gtk_tree_model_get (model, &iter, INFO_COLUMN, &info, -1);
366
plugin_manager_toggle_all (RBPluginManager *pm)
370
static gboolean active;
374
model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
376
g_return_if_fail (model != NULL);
378
if (gtk_tree_model_get_iter_first (model, &iter)) {
380
plugin_manager_set_active (&iter, model, active, pm);
381
} while (gtk_tree_model_iter_next (model, &iter));
385
/* Callback used as the interactive search comparison function */
387
name_search_cb (GtkTreeModel *model,
394
gchar *normalized_string;
395
gchar *normalized_key;
396
gchar *case_normalized_string;
397
gchar *case_normalized_key;
401
gtk_tree_model_get (model, iter, INFO_COLUMN, &info, -1);
405
normalized_string = g_utf8_normalize (rb_plugins_engine_get_plugin_name (info), -1, G_NORMALIZE_ALL);
406
normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
407
case_normalized_string = g_utf8_casefold (normalized_string, -1);
408
case_normalized_key = g_utf8_casefold (normalized_key, -1);
410
key_len = strlen (case_normalized_key);
412
/* Oddly enough, this callback must return whether to stop the search
413
* because we found a match, not whether we actually matched.
415
retval = (strncmp (case_normalized_key, case_normalized_string, key_len) != 0);
417
g_free (normalized_key);
418
g_free (normalized_string);
419
g_free (case_normalized_key);
420
g_free (case_normalized_string);
426
plugin_manager_construct_tree (RBPluginManager *pm)
428
GtkTreeViewColumn *column;
429
GtkCellRenderer *cell;
430
GtkTreeModel *filter;
431
GtkTreeSelection *selection;
433
pm->priv->plugin_model = GTK_TREE_MODEL (gtk_list_store_new (N_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_POINTER));
434
filter = gtk_tree_model_filter_new (pm->priv->plugin_model, NULL);
435
gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter), VISIBLE_COLUMN);
436
gtk_tree_view_set_model (GTK_TREE_VIEW (pm->priv->tree), filter);
437
g_object_unref (filter);
439
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (pm->priv->tree), TRUE);
440
gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW (pm->priv->tree), TRUE);
442
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
443
gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
446
cell = gtk_cell_renderer_toggle_new ();
447
g_signal_connect (cell,
449
G_CALLBACK (active_toggled_cb),
451
column = gtk_tree_view_column_new_with_attributes (PLUGIN_MANAGER_ACTIVE_TITLE,
456
gtk_tree_view_column_set_clickable (column, TRUE);
457
gtk_tree_view_column_set_resizable (column, TRUE);
458
g_signal_connect (column, "clicked", G_CALLBACK (column_clicked_cb), pm);
459
gtk_tree_view_append_column (GTK_TREE_VIEW (pm->priv->tree), column);
462
cell = gtk_cell_renderer_text_new ();
463
column = gtk_tree_view_column_new_with_attributes (PLUGIN_MANAGER_NAME_TITLE, cell, NULL);
464
gtk_tree_view_column_set_resizable (column, TRUE);
465
gtk_tree_view_column_set_cell_data_func (column, cell, plugin_manager_view_cell_cb,
467
gtk_tree_view_append_column (GTK_TREE_VIEW (pm->priv->tree), column);
469
/* Enable search for our non-string column */
470
gtk_tree_view_set_search_column (GTK_TREE_VIEW (pm->priv->tree), INFO_COLUMN);
471
gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (pm->priv->tree),
476
g_signal_connect (selection,
478
G_CALLBACK (cursor_changed_cb),
480
g_signal_connect (pm->priv->tree,
482
G_CALLBACK (row_activated_cb),
485
gtk_widget_show (pm->priv->tree);
489
plugin_name_cmp (gconstpointer a, gconstpointer b)
491
RBPluginInfo *lhs = (RBPluginInfo*)a;
492
RBPluginInfo *rhs = (RBPluginInfo*)b;
493
return strcmp (rb_plugins_engine_get_plugin_name (lhs),
494
rb_plugins_engine_get_plugin_name (rhs));
498
rb_plugin_manager_init (RBPluginManager *pm)
501
GtkWidget *plugins_window;
503
pm->priv = RB_PLUGIN_MANAGER_GET_PRIVATE (pm);
505
builder = rb_builder_load ("plugins.ui", pm);
506
gtk_container_add (GTK_CONTAINER (pm), GTK_WIDGET (gtk_builder_get_object (builder, "edit_plugins")));
508
gtk_box_set_spacing (GTK_BOX (pm), 6);
510
pm->priv->tree = gtk_tree_view_new ();
511
plugins_window = GTK_WIDGET (gtk_builder_get_object (builder, "plugins_list_window"));
512
gtk_container_add (GTK_CONTAINER (plugins_window), pm->priv->tree);
514
pm->priv->configure_button = GTK_WIDGET (gtk_builder_get_object (builder, "configure_button"));
515
g_signal_connect (pm->priv->configure_button,
517
G_CALLBACK (configure_button_cb),
520
pm->priv->header_hbox = GTK_WIDGET (gtk_builder_get_object (builder, "header_hbox"));
522
pm->priv->plugin_title = GTK_WIDGET (gtk_builder_get_object (builder, "plugin_title"));
524
pm->priv->site_label = GTK_WIDGET (gtk_builder_get_object (builder, "site_label"));
525
rb_builder_boldify_label (builder, "site_label");
526
pm->priv->copyright_label = GTK_WIDGET (gtk_builder_get_object (builder, "copyright_label"));
527
rb_builder_boldify_label (builder, "copyright_label");
528
pm->priv->authors_label = GTK_WIDGET (gtk_builder_get_object (builder, "authors_label"));
529
rb_builder_boldify_label (builder, "authors_label");
530
pm->priv->description_label = GTK_WIDGET (gtk_builder_get_object (builder, "description_label"));
531
rb_builder_boldify_label (builder, "description_label");
533
pm->priv->plugin_icon = GTK_WIDGET (gtk_builder_get_object (builder, "plugin_icon"));
534
pm->priv->site_text = GTK_WIDGET (gtk_builder_get_object (builder, "site_text"));
535
pm->priv->copyright_text = GTK_WIDGET (gtk_builder_get_object (builder, "copyright_text"));
536
pm->priv->authors_text = GTK_WIDGET (gtk_builder_get_object (builder, "authors_text"));
537
pm->priv->description_text = GTK_WIDGET (gtk_builder_get_object (builder, "description_text"));
539
plugin_manager_construct_tree (pm);
541
/* get the list of available plugins (or installed) */
542
pm->priv->plugins = rb_plugins_engine_get_plugins_list ();
543
pm->priv->plugins = g_list_sort (pm->priv->plugins, plugin_name_cmp);
544
plugin_manager_populate_lists (pm);
545
g_object_unref (builder);
549
rb_plugin_manager_new (void)
551
return g_object_new (RB_TYPE_PLUGIN_MANAGER, 0);
555
rb_plugin_manager_finalize (GObject *o)
557
RBPluginManager *pm = RB_PLUGIN_MANAGER (o);
559
g_list_free (pm->priv->plugins);
561
G_OBJECT_CLASS(rb_plugin_manager_parent_class)->finalize (o);