1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3
* Plugin manager for Rhythmbox, based heavily on the code from gedit.
5
* Copyright (C) 2002-2005 Paolo Maggi
6
* 2006 James Livingston <doclivingston@gmail.com>
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.
39
#include <glib/gi18n.h>
41
#include "eel-gconf-extensions.h"
42
#include "rb-file-helpers.h"
43
#include "rb-preferences.h"
45
#include "rb-plugin.h"
47
#include "rb-dialog.h"
49
#include "rb-module.h"
51
#include "rb-python-module.h"
54
#include "rb-plugins-engine.h"
56
#define PLUGIN_EXT ".rb-plugin"
79
GdkPixbuf *icon_pixbuf;
85
guint active_notification_id;
86
guint visible_notification_id;
89
static void rb_plugin_info_free (RBPluginInfo *info);
90
static void rb_plugins_engine_plugin_active_cb (GConfClient *client,
94
static void rb_plugins_engine_plugin_visible_cb (GConfClient *client,
98
static gboolean rb_plugins_engine_activate_plugin_real (RBPluginInfo *info,
100
static void rb_plugins_engine_deactivate_plugin_real (RBPluginInfo *info,
103
static GHashTable *rb_plugins = NULL;
104
guint garbage_collect_id = 0;
105
RBShell *rb_plugins_shell = NULL;
107
static RBPluginInfo *
108
rb_plugins_engine_load (const gchar *file)
111
GKeyFile *plugin_file = NULL;
114
g_return_val_if_fail (file != NULL, NULL);
116
rb_debug ("Loading plugin: %s", file);
118
info = g_new0 (RBPluginInfo, 1);
119
info->file = g_strdup (file);
121
plugin_file = g_key_file_new ();
122
if (!g_key_file_load_from_file (plugin_file, file, G_KEY_FILE_NONE, NULL)) {
123
g_warning ("Bad plugin file: %s", file);
127
if (!g_key_file_has_key (plugin_file,
131
rb_debug ("IAge key does not exist in file: %s", file);
136
if (g_key_file_get_integer (plugin_file,
140
rb_debug ("Wrong IAge in file: %s", file);
145
str = g_key_file_get_string (plugin_file,
150
info->location = str;
153
* Blacklist a few plugins that we know not to work,
154
* and cause crashes */
155
if (g_str_equal (str, "upnp_coherence"))
158
g_warning ("Could not find 'Module' in %s", file);
162
/* Get the loader for this plugin */
163
str = g_key_file_get_string (plugin_file,
167
if (str && strcmp(str, "python") == 0) {
168
info->lang = RB_PLUGIN_LOADER_PY;
169
#ifndef ENABLE_PYTHON
170
rb_debug ("Cannot load python extension '%s', Rhythmbox was not "
171
"compiled with python support", file);
176
info->lang = RB_PLUGIN_LOADER_C;
181
str = g_key_file_get_locale_string (plugin_file,
188
g_warning ("Could not find 'Name' in %s", file);
192
/* Get Description */
193
str = g_key_file_get_locale_string (plugin_file,
200
rb_debug ("Could not find 'Description' in %s", file);
201
info->desc = g_strdup ("");
205
str = g_key_file_get_string (plugin_file,
210
info->icon_name = str;
212
rb_debug ("Could not find 'Icon' in %s", file);
213
info->icon_name = g_strdup ("");
217
info->authors = g_key_file_get_string_list (plugin_file,
221
if (info->authors == NULL)
222
rb_debug ("Could not find 'Authors' in %s", file);
225
str = g_key_file_get_string (plugin_file,
230
info->copyright = str;
232
rb_debug ("Could not find 'Copyright' in %s", file);
233
info->copyright = g_strdup ("");
237
str = g_key_file_get_string (plugin_file,
244
rb_debug ("Could not find 'Website' in %s", file);
245
info->website = g_strdup ("");
248
g_key_file_free (plugin_file);
254
g_free (info->location);
257
g_key_file_free (plugin_file);
263
rb_plugins_engine_load_cb (GFile *file, gboolean dir, gpointer userdata)
271
plugin_path = g_file_get_path (file);
273
sep = strrchr (plugin_path, G_DIR_SEPARATOR);
279
/* don't look inside version control system directories.
280
* most are already covered by excluding hidden files/directories.
282
if (dir && (g_str_has_prefix (sep, "_darcs") || g_str_has_prefix (sep, "CVS"))) {
283
rb_debug ("not loading plugin from hidden/VCS directory %s", plugin_path);
284
g_free (plugin_path);
288
if (dir || !g_str_has_suffix (plugin_path, PLUGIN_EXT)) {
289
g_free (plugin_path);
293
info = rb_plugins_engine_load (plugin_path);
294
g_free (plugin_path);
299
if (g_hash_table_lookup (rb_plugins, info->location)) {
300
rb_plugin_info_free (info);
304
g_hash_table_insert (rb_plugins, info->location, info);
305
rb_debug ("Plugin %s loaded", info->name);
307
key_name = g_strdup_printf (CONF_PLUGIN_ACTIVE_KEY, info->location);
308
info->active_notification_id = eel_gconf_notification_add (key_name,
309
(GConfClientNotifyFunc)rb_plugins_engine_plugin_active_cb,
311
activate = eel_gconf_get_boolean (key_name);
314
key_name = g_strdup_printf (CONF_PLUGIN_HIDDEN_KEY, info->location);
315
info->visible_notification_id = eel_gconf_notification_add (key_name,
316
(GConfClientNotifyFunc)rb_plugins_engine_plugin_visible_cb,
318
info->visible = !eel_gconf_get_boolean (key_name);
322
rb_plugins_engine_activate_plugin (info);
327
rb_plugins_engine_load_dir (const char *path)
332
plugindir = g_file_new_for_commandline_arg (path);
333
plugin_uri = g_file_get_uri (plugindir);
335
rb_uri_handle_recursively (plugin_uri, NULL, (RBUriRecurseFunc) rb_plugins_engine_load_cb, NULL);
337
g_object_unref (plugindir);
342
rb_plugins_engine_load_all (void)
346
paths = rb_get_plugin_paths ();
347
while (paths != NULL) {
348
rb_plugins_engine_load_dir (paths->data);
349
g_free (paths->data);
350
paths = g_list_delete_link (paths, paths);
355
garbage_collect_cb (gpointer data)
357
rb_plugins_engine_garbage_collect ();
362
rb_plugins_engine_init (RBShell *shell)
364
g_return_val_if_fail (rb_plugins == NULL, FALSE);
366
if (!g_module_supported ())
368
g_warning ("rb is not able to initialize the plugins engine.");
371
rb_profile_start ("plugins engine init");
373
rb_plugins = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)rb_plugin_info_free);
375
rb_plugins_shell = shell;
376
g_object_ref (G_OBJECT (rb_plugins_shell));
378
rb_python_module_init_python ();
381
rb_plugins_engine_load_all ();
383
garbage_collect_id = g_timeout_add_seconds_full (G_PRIORITY_LOW, 20, garbage_collect_cb, NULL, NULL);
385
rb_profile_end ("plugins engine init");
391
rb_plugins_engine_garbage_collect (void)
394
rb_python_garbage_collect ();
399
rb_plugin_info_free (RBPluginInfo *info)
402
rb_plugins_engine_deactivate_plugin_real (info, rb_plugins_shell);
404
if (info->plugin != NULL) {
405
rb_debug ("Unref plugin %s", info->name);
407
g_object_unref (info->plugin);
409
/* info->module must not be unref since it is not possible to finalize
413
eel_gconf_notification_remove (info->active_notification_id);
414
eel_gconf_notification_remove (info->visible_notification_id);
417
g_free (info->location);
420
g_free (info->website);
421
g_free (info->copyright);
422
g_free (info->icon_name);
424
if (info->icon_pixbuf)
425
g_object_unref (info->icon_pixbuf);
426
g_strfreev (info->authors);
432
rb_plugins_engine_shutdown (void)
434
g_hash_table_destroy (rb_plugins);
437
g_object_unref (rb_plugins_shell);
438
rb_plugins_shell = NULL;
440
g_source_remove (garbage_collect_id);
441
rb_plugins_engine_garbage_collect ();
444
rb_python_shutdown ();
449
rb_plugins_engine_get_plugins_list (void)
451
return rb_collate_hash_table_values (rb_plugins);
455
load_plugin_module (RBPluginInfo *info)
460
g_return_val_if_fail (info != NULL, FALSE);
461
g_return_val_if_fail (info->file != NULL, FALSE);
462
g_return_val_if_fail (info->location != NULL, FALSE);
463
g_return_val_if_fail (info->plugin == NULL, FALSE);
465
switch (info->lang) {
466
case RB_PLUGIN_LOADER_C:
467
dirname = g_path_get_dirname (info->file);
468
g_return_val_if_fail (dirname != NULL, FALSE);
470
path = g_module_build_path (dirname, info->location);
471
#ifdef USE_UNINSTALLED_DIRS
472
if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
476
temp = g_build_filename (dirname, ".libs", NULL);
478
path = g_module_build_path (temp, info->location);
484
g_return_val_if_fail (path != NULL, FALSE);
486
info->module = G_TYPE_MODULE (rb_module_new (path, info->location));
489
case RB_PLUGIN_LOADER_PY:
491
info->module = G_TYPE_MODULE (rb_python_module_new (info->file, info->location));
493
rb_debug ("cannot load plugin %s, python plugin support is disabled", info->location);
498
if (g_type_module_use (info->module) == FALSE) {
499
g_warning ("Could not load plugin %s\n", info->location);
501
g_object_unref (G_OBJECT (info->module));
507
switch (info->lang) {
508
case RB_PLUGIN_LOADER_C:
509
info->plugin = RB_PLUGIN (rb_module_new_object (RB_MODULE (info->module)));
511
case RB_PLUGIN_LOADER_PY:
513
info->plugin = RB_PLUGIN (rb_python_module_new_object (RB_PYTHON_MODULE (info->module)));
522
rb_plugins_engine_activate_plugin_real (RBPluginInfo *info, RBShell *shell)
526
if (info->plugin == NULL)
527
res = load_plugin_module (info);
530
rb_plugin_activate (info->plugin, shell);
532
g_warning ("Error, impossible to activate plugin '%s'", info->name);
538
rb_plugins_engine_activate_plugin (RBPluginInfo *info)
542
g_return_val_if_fail (info != NULL, FALSE);
547
ret = rb_plugins_engine_activate_plugin_real (info, rb_plugins_shell);
549
if (info->visible != FALSE || ret != FALSE) {
552
key_name = g_strdup_printf (CONF_PLUGIN_ACTIVE_KEY, info->location);
553
eel_gconf_set_boolean (key_name, ret);
562
rb_error_dialog (NULL, _("Plugin Error"), _("Unable to activate plugin %s"), info->name);
568
rb_plugins_engine_deactivate_plugin_real (RBPluginInfo *info, RBShell *shell)
570
rb_plugin_deactivate (info->plugin, rb_plugins_shell);
574
rb_plugins_engine_deactivate_plugin (RBPluginInfo *info)
578
g_return_val_if_fail (info != NULL, FALSE);
583
rb_plugins_engine_deactivate_plugin_real (info, rb_plugins_shell);
585
/* Update plugin state */
586
info->active = FALSE;
588
key_name = g_strdup_printf (CONF_PLUGIN_ACTIVE_KEY, info->location);
589
eel_gconf_set_boolean (key_name, FALSE);
596
rb_plugins_engine_plugin_is_active (RBPluginInfo *info)
598
g_return_val_if_fail (info != NULL, FALSE);
604
rb_plugins_engine_plugin_is_visible (RBPluginInfo *info)
606
g_return_val_if_fail (info != NULL, FALSE);
608
return info->visible;
612
rb_plugins_engine_plugin_is_configurable (RBPluginInfo *info)
614
g_return_val_if_fail (info != NULL, FALSE);
616
if ((info->plugin == NULL) || !info->active)
619
return rb_plugin_is_configurable (info->plugin);
623
rb_plugins_engine_configure_plugin (RBPluginInfo *info,
630
g_return_if_fail (info != NULL);
632
conf_dlg = rb_plugin_create_configure_dialog (info->plugin);
633
g_return_if_fail (conf_dlg != NULL);
634
gtk_window_set_transient_for (GTK_WINDOW (conf_dlg),
636
gtk_window_set_modal (GTK_WINDOW (conf_dlg), TRUE);
638
if (!gtk_widget_get_mapped (conf_dlg))
639
gtk_window_set_type_hint (GTK_WINDOW (conf_dlg), GDK_WINDOW_TYPE_HINT_DIALOG);
641
wg = gtk_window_get_group (parent);
644
wg = gtk_window_group_new ();
645
gtk_window_group_add_window (wg, parent);
648
gtk_window_group_add_window (wg,
649
GTK_WINDOW (conf_dlg));
650
gtk_widget_show (conf_dlg);
654
rb_plugins_engine_plugin_active_cb (GConfClient *client,
659
if (gconf_value_get_bool (entry->value)) {
660
rb_plugins_engine_activate_plugin (info);
662
rb_plugins_engine_deactivate_plugin (info);
667
rb_plugins_engine_plugin_visible_cb (GConfClient *client,
672
info->visible = !gconf_value_get_bool (entry->value);
676
rb_plugins_engine_get_plugin_name (RBPluginInfo *info)
678
g_return_val_if_fail (info != NULL, NULL);
684
rb_plugins_engine_get_plugin_description (RBPluginInfo *info)
686
g_return_val_if_fail (info != NULL, NULL);
692
rb_plugins_engine_get_plugin_authors (RBPluginInfo *info)
694
g_return_val_if_fail (info != NULL, (const gchar **)NULL);
696
return (const gchar **)info->authors;
700
rb_plugins_engine_get_plugin_website (RBPluginInfo *info)
702
g_return_val_if_fail (info != NULL, NULL);
704
return info->website;
708
rb_plugins_engine_get_plugin_copyright (RBPluginInfo *info)
710
g_return_val_if_fail (info != NULL, NULL);
712
return info->copyright;
716
rb_plugins_engine_get_plugin_icon (RBPluginInfo *info)
718
g_return_val_if_fail (info != NULL, NULL);
720
if (info->icon_name == NULL)
723
if (info->icon_pixbuf == NULL) {
724
char *filename = NULL;
727
dirname = g_path_get_dirname (info->file);
728
filename = g_build_filename (dirname, info->icon_name, NULL);
731
info->icon_pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
735
return info->icon_pixbuf;