2
* Plugin manager for Rhythmbox, based heavily on the code from gedit.
4
* Copyright (C) 2002-2005 Paolo Maggi
5
* 2006 James Livingston <jrl@ids.org.au>
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin St, Fifth Floor,
20
* Boston, MA 02110-1301 USA.
30
#include <glib/gi18n.h>
31
#include <glib/gkeyfile.h>
32
#include <libgnome/gnome-util.h>
34
#include "eel-gconf-extensions.h"
35
#include "rb-file-helpers.h"
36
#include "rb-preferences.h"
38
#include "rb-plugin.h"
40
#include "rb-dialog.h"
42
#include "rb-module.h"
44
#include "rb-python-module.h"
47
#include "rb-plugins-engine.h"
49
#define USER_RB_PLUGINS_LOCATION "rhythmbox/plugins/"
50
#define UNINSTALLED_PLUGINS_LOCATION "plugins"
52
#define RB_PLUGINS_ENGINE_BASE_KEY CONF_PREFIX "/plugins"
53
#define RB_PLUGINS_ENGINE_KEY RB_PLUGINS_ENGINE_BASE_KEY "/active-plugins"
55
#define PLUGIN_EXT ".rb-plugin"
78
GdkPixbuf *icon_pixbuf;
83
guint notification_id;
86
static void rb_plugin_info_free (RBPluginInfo *info);
87
static void rb_plugins_engine_plugin_active_cb (GConfClient *client,
91
static gboolean rb_plugins_engine_activate_plugin_real (RBPluginInfo *info,
93
static void rb_plugins_engine_deactivate_plugin_real (RBPluginInfo *info,
97
static GHashTable *rb_plugins = NULL;
98
guint garbage_collect_id = 0;
99
RBShell *rb_plugins_shell = NULL;
101
static RBPluginInfo *
102
rb_plugins_engine_load (const gchar *file)
105
GKeyFile *plugin_file = NULL;
108
g_return_val_if_fail (file != NULL, NULL);
110
rb_debug ("Loading plugin: %s", file);
112
info = g_new0 (RBPluginInfo, 1);
113
info->file = g_strdup (file);
115
plugin_file = g_key_file_new ();
116
if (!g_key_file_load_from_file (plugin_file, file, G_KEY_FILE_NONE, NULL))
118
g_warning ("Bad plugin file: %s", file);
122
if (!g_key_file_has_key (plugin_file,
127
rb_debug ("IAge key does not exist in file: %s", file);
132
if (g_key_file_get_integer (plugin_file,
137
rb_debug ("Wrong IAge in file: %s", file);
142
str = g_key_file_get_string (plugin_file,
148
info->location = str;
152
g_warning ("Could not find 'Module' in %s", file);
156
/* Get the loader for this plugin */
157
str = g_key_file_get_string (plugin_file,
161
if (str && strcmp(str, "python") == 0)
163
info->lang = RB_PLUGIN_LOADER_PY;
164
#ifndef ENABLE_PYTHON
165
rb_debug ("Cannot load python extension '%s', Rhythmbox was not "
166
"compiled with python support", file);
172
info->lang = RB_PLUGIN_LOADER_C;
177
str = g_key_file_get_locale_string (plugin_file,
185
g_warning ("Could not find 'Name' in %s", file);
189
/* Get Description */
190
str = g_key_file_get_locale_string (plugin_file,
197
rb_debug ("Could not find 'Description' in %s", file);
200
str = g_key_file_get_string (plugin_file,
205
info->icon_name = str;
207
rb_debug ("Could not find 'Description' in %s", file);
211
info->authors = g_key_file_get_string_list (plugin_file,
215
if (info->authors == NULL)
216
rb_debug ("Could not find 'Authors' in %s", file);
220
str = g_key_file_get_string (plugin_file,
225
info->copyright = str;
227
rb_debug ("Could not find 'Copyright' in %s", file);
230
str = g_key_file_get_string (plugin_file,
237
rb_debug ("Could not find 'Website' in %s", file);
239
g_key_file_free (plugin_file);
245
g_free (info->location);
248
g_key_file_free (plugin_file);
254
rb_plugins_engine_load_cb (const char *uri, gpointer userdata)
261
if (!g_str_has_suffix (uri, PLUGIN_EXT))
264
plugin_file = gnome_vfs_get_local_path_from_uri (uri);
265
info = rb_plugins_engine_load (plugin_file);
266
g_free (plugin_file);
271
if (g_hash_table_lookup (rb_plugins, info->location)) {
272
rb_plugin_info_free (info);
276
g_hash_table_insert (rb_plugins, info->location, info);
277
rb_debug ("Plugin %s loaded", info->name);
279
key_name = g_strdup_printf (CONF_PLUGIN_ACTIVE_KEY, info->location);
280
info->notification_id = eel_gconf_notification_add (key_name,
281
(GConfClientNotifyFunc)rb_plugins_engine_plugin_active_cb,
283
activate = eel_gconf_get_boolean (key_name);
287
rb_plugins_engine_activate_plugin (info);
291
rb_plugins_engine_load_dir (const gchar *path)
295
uri = rb_uri_resolve_relative (path);
296
rb_uri_handle_recursively (uri, (GFunc)rb_plugins_engine_load_cb, NULL, NULL);
301
rb_plugins_engine_load_all (void)
305
/* load user's plugins */
306
pdir = gnome_util_home_file (USER_RB_PLUGINS_LOCATION);
307
rb_plugins_engine_load_dir (pdir);
310
#ifdef SHARE_UNINSTALLED_DIR
311
/* load plugins when running uninstalled */
312
rb_plugins_engine_load_dir (UNINSTALLED_PLUGINS_LOCATION);
313
rb_plugins_engine_load_dir ("../" UNINSTALLED_PLUGINS_LOCATION);
316
/* load system-wide plugins */
317
rb_plugins_engine_load_dir (RB_PLUGIN_DIR);
321
garbage_collect_cb (gpointer data)
323
rb_plugins_engine_garbage_collect ();
328
rb_plugins_engine_init (RBShell *shell)
330
g_return_val_if_fail (rb_plugins == NULL, FALSE);
332
if (!g_module_supported ())
334
g_warning ("rb is not able to initialize the plugins engine.");
337
rb_profile_start ("plugins engine init");
339
rb_plugins = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)rb_plugin_info_free);
341
rb_plugins_shell = shell;
342
g_object_ref (G_OBJECT (rb_plugins_shell));
344
rb_plugins_engine_load_all ();
346
garbage_collect_id = g_timeout_add_full (G_PRIORITY_LOW, 20000, garbage_collect_cb, NULL, NULL);
348
rb_profile_end ("plugins engine init");
355
rb_plugins_engine_garbage_collect (void)
358
rb_python_garbage_collect ();
363
rb_plugin_info_free (RBPluginInfo *info)
366
rb_plugins_engine_deactivate_plugin_real (info, rb_plugins_shell);
368
if (info->plugin != NULL) {
369
rb_debug ("Unref plugin %s", info->name);
371
g_object_unref (info->plugin);
373
/* info->module must not be unref since it is not possible to finalize
377
eel_gconf_notification_remove (info->notification_id);
380
g_free (info->location);
383
g_free (info->website);
384
g_free (info->copyright);
385
g_free (info->icon_name);
387
if (info->icon_pixbuf)
388
g_object_unref (info->icon_pixbuf);
389
g_strfreev (info->authors);
395
rb_plugins_engine_shutdown (void)
397
g_hash_table_destroy (rb_plugins);
400
g_object_unref (rb_plugins_shell);
401
rb_plugins_shell = NULL;
403
g_source_remove (garbage_collect_id);
404
rb_plugins_engine_garbage_collect ();
407
rb_python_shutdown ();
412
rb_plugins_engine_get_plugins_list (void)
414
return rb_collate_hash_table_values (rb_plugins);
418
load_plugin_module (RBPluginInfo *info)
423
g_return_val_if_fail (info != NULL, FALSE);
424
g_return_val_if_fail (info->file != NULL, FALSE);
425
g_return_val_if_fail (info->location != NULL, FALSE);
426
g_return_val_if_fail (info->plugin == NULL, FALSE);
430
case RB_PLUGIN_LOADER_C:
431
dirname = g_path_get_dirname (info->file);
432
g_return_val_if_fail (dirname != NULL, FALSE);
434
path = g_module_build_path (dirname, info->location);
435
#ifdef SHARE_UNINSTALLED_DIR
436
if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
440
temp = g_build_filename (dirname, ".libs", NULL);
442
path = g_module_build_path (temp, info->location);
448
g_return_val_if_fail (path != NULL, FALSE);
450
info->module = G_TYPE_MODULE (rb_module_new (path));
453
case RB_PLUGIN_LOADER_PY:
456
gchar *dir = g_path_get_dirname (info->file);
458
info->module = G_TYPE_MODULE (
459
rb_python_module_new (dir, info->location));
468
if (g_type_module_use (info->module) == FALSE)
472
case RB_PLUGIN_LOADER_C:
473
g_warning ("Could not load plugin file at %s\n",
474
rb_module_get_path (RB_MODULE (info->module)));
476
case RB_PLUGIN_LOADER_PY:
477
g_warning ("Could not load python module %s\n", info->location);
481
g_object_unref (G_OBJECT (info->module));
489
case RB_PLUGIN_LOADER_C:
490
info->plugin = RB_PLUGIN (rb_module_new_object (RB_MODULE (info->module)));
492
case RB_PLUGIN_LOADER_PY:
494
info->plugin = RB_PLUGIN (rb_python_module_new_object (RB_PYTHON_MODULE (info->module)));
499
g_type_module_unuse (info->module);
507
rb_plugins_engine_activate_plugin_real (RBPluginInfo *info, RBShell *shell)
511
if (info->plugin == NULL)
512
res = load_plugin_module (info);
515
rb_plugin_activate (info->plugin, shell);
517
g_warning ("Error, impossible to activate plugin '%s'", info->name);
523
rb_plugins_engine_activate_plugin (RBPluginInfo *info)
525
g_return_val_if_fail (info != NULL, FALSE);
530
if (rb_plugins_engine_activate_plugin_real (info, rb_plugins_shell)) {
533
key_name = g_strdup_printf (CONF_PLUGIN_ACTIVE_KEY, info->location);
534
eel_gconf_set_boolean (key_name, TRUE);
542
rb_error_dialog (NULL, _("Plugin Error"), _("Unable to activate plugin %s"), info->name);
548
rb_plugins_engine_deactivate_plugin_real (RBPluginInfo *info, RBShell *shell)
550
rb_plugin_deactivate (info->plugin, rb_plugins_shell);
554
rb_plugins_engine_deactivate_plugin (RBPluginInfo *info)
558
g_return_val_if_fail (info != NULL, FALSE);
563
rb_plugins_engine_deactivate_plugin_real (info, rb_plugins_shell);
565
/* Update plugin state */
566
info->active = FALSE;
568
key_name = g_strdup_printf (CONF_PLUGIN_ACTIVE_KEY, info->location);
569
eel_gconf_set_boolean (key_name, FALSE);
576
rb_plugins_engine_plugin_is_active (RBPluginInfo *info)
578
g_return_val_if_fail (info != NULL, FALSE);
585
rb_plugins_engine_plugin_is_configurable (RBPluginInfo *info)
587
g_return_val_if_fail (info != NULL, FALSE);
589
if ((info->plugin == NULL) || !info->active)
592
return rb_plugin_is_configurable (info->plugin);
596
rb_plugins_engine_configure_plugin (RBPluginInfo *info,
603
g_return_if_fail (info != NULL);
605
conf_dlg = rb_plugin_create_configure_dialog (info->plugin);
606
g_return_if_fail (conf_dlg != NULL);
607
gtk_window_set_transient_for (GTK_WINDOW (conf_dlg),
613
wg = gtk_window_group_new ();
614
gtk_window_group_add_window (wg, parent);
617
gtk_window_group_add_window (wg,
618
GTK_WINDOW (conf_dlg));
620
gtk_window_set_modal (GTK_WINDOW (conf_dlg), TRUE);
621
gtk_widget_show (conf_dlg);
625
rb_plugins_engine_plugin_active_cb (GConfClient *client,
630
if (gconf_value_get_bool (entry->value)) {
631
rb_plugins_engine_activate_plugin (info);
633
rb_plugins_engine_deactivate_plugin (info);
638
rb_plugins_engine_get_plugin_name (RBPluginInfo *info)
640
g_return_val_if_fail (info != NULL, NULL);
646
rb_plugins_engine_get_plugin_description (RBPluginInfo *info)
648
g_return_val_if_fail (info != NULL, NULL);
654
rb_plugins_engine_get_plugin_authors (RBPluginInfo *info)
656
g_return_val_if_fail (info != NULL, (const gchar **)NULL);
658
return (const gchar **)info->authors;
662
rb_plugins_engine_get_plugin_website (RBPluginInfo *info)
664
g_return_val_if_fail (info != NULL, NULL);
666
return info->website;
670
rb_plugins_engine_get_plugin_copyright (RBPluginInfo *info)
672
g_return_val_if_fail (info != NULL, NULL);
674
return info->copyright;
678
rb_plugins_engine_get_plugin_icon (RBPluginInfo *info)
680
if (info->icon_name == NULL)
683
if (info->icon_pixbuf == NULL) {
684
char *filename = NULL;
687
dirname = g_path_get_dirname (info->file);
688
filename = g_build_filename (dirname, info->icon_name, NULL);
691
info->icon_pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
695
return info->icon_pixbuf;