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 <jrl@ids.org.au>
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 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301 USA.
30 #include <glib/gi18n.h>
31 #include <glib/gkeyfile.h>
33 #include "eel-gconf-extensions.h"
34 #include "rb-file-helpers.h"
35 #include "rb-preferences.h"
37 #include "rb-plugin.h"
39 #include "rb-dialog.h"
41 #include "rb-module.h"
43 #include "rb-python-module.h"
46 #include "rb-plugins-engine.h"
48 #define PLUGIN_EXT ".rb-plugin"
71 GdkPixbuf
*icon_pixbuf
;
77 guint active_notification_id
;
78 guint visible_notification_id
;
81 static void rb_plugin_info_free (RBPluginInfo
*info
);
82 static void rb_plugins_engine_plugin_active_cb (GConfClient
*client
,
86 static void rb_plugins_engine_plugin_visible_cb (GConfClient
*client
,
90 static gboolean
rb_plugins_engine_activate_plugin_real (RBPluginInfo
*info
,
92 static void rb_plugins_engine_deactivate_plugin_real (RBPluginInfo
*info
,
95 static GHashTable
*rb_plugins
= NULL
;
96 guint garbage_collect_id
= 0;
97 RBShell
*rb_plugins_shell
= NULL
;
100 rb_plugins_engine_load (const gchar
*file
)
103 GKeyFile
*plugin_file
= NULL
;
106 g_return_val_if_fail (file
!= NULL
, NULL
);
108 rb_debug ("Loading plugin: %s", file
);
110 info
= g_new0 (RBPluginInfo
, 1);
111 info
->file
= g_strdup (file
);
113 plugin_file
= g_key_file_new ();
114 if (!g_key_file_load_from_file (plugin_file
, file
, G_KEY_FILE_NONE
, NULL
))
116 g_warning ("Bad plugin file: %s", file
);
120 if (!g_key_file_has_key (plugin_file
,
125 rb_debug ("IAge key does not exist in file: %s", file
);
130 if (g_key_file_get_integer (plugin_file
,
135 rb_debug ("Wrong IAge in file: %s", file
);
140 str
= g_key_file_get_string (plugin_file
,
146 info
->location
= str
;
150 g_warning ("Could not find 'Module' in %s", file
);
154 /* Get the loader for this plugin */
155 str
= g_key_file_get_string (plugin_file
,
159 if (str
&& strcmp(str
, "python") == 0)
161 info
->lang
= RB_PLUGIN_LOADER_PY
;
162 #ifndef ENABLE_PYTHON
163 rb_debug ("Cannot load python extension '%s', Rhythmbox was not "
164 "compiled with python support", file
);
170 info
->lang
= RB_PLUGIN_LOADER_C
;
175 str
= g_key_file_get_locale_string (plugin_file
,
183 g_warning ("Could not find 'Name' in %s", file
);
187 /* Get Description */
188 str
= g_key_file_get_locale_string (plugin_file
,
195 rb_debug ("Could not find 'Description' in %s", file
);
198 str
= g_key_file_get_string (plugin_file
,
203 info
->icon_name
= str
;
205 rb_debug ("Could not find 'Description' in %s", file
);
208 info
->authors
= g_key_file_get_string_list (plugin_file
,
212 if (info
->authors
== NULL
)
213 rb_debug ("Could not find 'Authors' in %s", file
);
216 str
= g_key_file_get_string (plugin_file
,
221 info
->copyright
= str
;
223 rb_debug ("Could not find 'Copyright' in %s", file
);
226 str
= g_key_file_get_string (plugin_file
,
233 rb_debug ("Could not find 'Website' in %s", file
);
235 g_key_file_free (plugin_file
);
241 g_free (info
->location
);
244 g_key_file_free (plugin_file
);
250 rb_plugins_engine_load_cb (const char *uri
, gpointer userdata
)
257 if (!g_str_has_suffix (uri
, PLUGIN_EXT
))
260 plugin_file
= gnome_vfs_get_local_path_from_uri (uri
);
261 info
= rb_plugins_engine_load (plugin_file
);
262 g_free (plugin_file
);
267 if (g_hash_table_lookup (rb_plugins
, info
->location
)) {
268 rb_plugin_info_free (info
);
272 g_hash_table_insert (rb_plugins
, info
->location
, info
);
273 rb_debug ("Plugin %s loaded", info
->name
);
275 key_name
= g_strdup_printf (CONF_PLUGIN_ACTIVE_KEY
, info
->location
);
276 info
->active_notification_id
= eel_gconf_notification_add (key_name
,
277 (GConfClientNotifyFunc
)rb_plugins_engine_plugin_active_cb
,
279 activate
= eel_gconf_get_boolean (key_name
);
282 key_name
= g_strdup_printf (CONF_PLUGIN_HIDDEN_KEY
, info
->location
);
283 info
->visible_notification_id
= eel_gconf_notification_add (key_name
,
284 (GConfClientNotifyFunc
)rb_plugins_engine_plugin_visible_cb
,
286 info
->visible
= !eel_gconf_get_boolean (key_name
);
290 rb_plugins_engine_activate_plugin (info
);
294 rb_plugins_engine_load_dir (const gchar
*path
)
298 uri
= rb_uri_resolve_relative (path
);
299 rb_uri_handle_recursively (uri
, (GFunc
)rb_plugins_engine_load_cb
, NULL
, NULL
);
304 rb_plugins_engine_load_all (void)
308 paths
= rb_get_plugin_paths ();
309 while (paths
!= NULL
) {
310 rb_plugins_engine_load_dir (paths
->data
);
311 g_free (paths
->data
);
312 paths
= g_list_delete_link (paths
, paths
);
317 garbage_collect_cb (gpointer data
)
319 rb_plugins_engine_garbage_collect ();
324 rb_plugins_engine_init (RBShell
*shell
)
326 g_return_val_if_fail (rb_plugins
== NULL
, FALSE
);
328 if (!g_module_supported ())
330 g_warning ("rb is not able to initialize the plugins engine.");
333 rb_profile_start ("plugins engine init");
335 rb_plugins
= g_hash_table_new_full (g_str_hash
, g_str_equal
, NULL
, (GDestroyNotify
)rb_plugin_info_free
);
337 rb_plugins_shell
= shell
;
338 g_object_ref (G_OBJECT (rb_plugins_shell
));
340 rb_plugins_engine_load_all ();
342 garbage_collect_id
= g_timeout_add_full (G_PRIORITY_LOW
, 20000, garbage_collect_cb
, NULL
, NULL
);
344 rb_profile_end ("plugins engine init");
350 rb_plugins_engine_garbage_collect (void)
353 rb_python_garbage_collect ();
358 rb_plugin_info_free (RBPluginInfo
*info
)
361 rb_plugins_engine_deactivate_plugin_real (info
, rb_plugins_shell
);
363 if (info
->plugin
!= NULL
) {
364 rb_debug ("Unref plugin %s", info
->name
);
366 g_object_unref (info
->plugin
);
368 /* info->module must not be unref since it is not possible to finalize
372 eel_gconf_notification_remove (info
->active_notification_id
);
373 eel_gconf_notification_remove (info
->visible_notification_id
);
376 g_free (info
->location
);
379 g_free (info
->website
);
380 g_free (info
->copyright
);
381 g_free (info
->icon_name
);
383 if (info
->icon_pixbuf
)
384 g_object_unref (info
->icon_pixbuf
);
385 g_strfreev (info
->authors
);
391 rb_plugins_engine_shutdown (void)
393 g_hash_table_destroy (rb_plugins
);
396 g_object_unref (rb_plugins_shell
);
397 rb_plugins_shell
= NULL
;
399 g_source_remove (garbage_collect_id
);
400 rb_plugins_engine_garbage_collect ();
403 rb_python_shutdown ();
408 rb_plugins_engine_get_plugins_list (void)
410 return rb_collate_hash_table_values (rb_plugins
);
414 load_plugin_module (RBPluginInfo
*info
)
419 g_return_val_if_fail (info
!= NULL
, FALSE
);
420 g_return_val_if_fail (info
->file
!= NULL
, FALSE
);
421 g_return_val_if_fail (info
->location
!= NULL
, FALSE
);
422 g_return_val_if_fail (info
->plugin
== NULL
, FALSE
);
424 switch (info
->lang
) {
425 case RB_PLUGIN_LOADER_C
:
426 dirname
= g_path_get_dirname (info
->file
);
427 g_return_val_if_fail (dirname
!= NULL
, FALSE
);
429 path
= g_module_build_path (dirname
, info
->location
);
430 #ifdef SHARE_UNINSTALLED_DIR
431 if (!g_file_test (path
, G_FILE_TEST_EXISTS
)) {
435 temp
= g_build_filename (dirname
, ".libs", NULL
);
437 path
= g_module_build_path (temp
, info
->location
);
443 g_return_val_if_fail (path
!= NULL
, FALSE
);
445 info
->module
= G_TYPE_MODULE (rb_module_new (path
, info
->location
));
448 case RB_PLUGIN_LOADER_PY
:
450 info
->module
= G_TYPE_MODULE (rb_python_module_new (info
->file
, info
->location
));
452 rb_debug ("cannot load plugin %s, python plugin support is disabled", info
->location
);
457 if (g_type_module_use (info
->module
) == FALSE
) {
458 g_warning ("Could not load plugin %s\n", info
->location
);
460 g_object_unref (G_OBJECT (info
->module
));
466 switch (info
->lang
) {
467 case RB_PLUGIN_LOADER_C
:
468 info
->plugin
= RB_PLUGIN (rb_module_new_object (RB_MODULE (info
->module
)));
470 case RB_PLUGIN_LOADER_PY
:
472 info
->plugin
= RB_PLUGIN (rb_python_module_new_object (RB_PYTHON_MODULE (info
->module
)));
481 rb_plugins_engine_activate_plugin_real (RBPluginInfo
*info
, RBShell
*shell
)
485 if (info
->plugin
== NULL
)
486 res
= load_plugin_module (info
);
489 rb_plugin_activate (info
->plugin
, shell
);
491 g_warning ("Error, impossible to activate plugin '%s'", info
->name
);
497 rb_plugins_engine_activate_plugin (RBPluginInfo
*info
)
499 g_return_val_if_fail (info
!= NULL
, FALSE
);
504 if (rb_plugins_engine_activate_plugin_real (info
, rb_plugins_shell
)) {
507 key_name
= g_strdup_printf (CONF_PLUGIN_ACTIVE_KEY
, info
->location
);
508 eel_gconf_set_boolean (key_name
, TRUE
);
516 rb_error_dialog (NULL
, _("Plugin Error"), _("Unable to activate plugin %s"), info
->name
);
522 rb_plugins_engine_deactivate_plugin_real (RBPluginInfo
*info
, RBShell
*shell
)
524 rb_plugin_deactivate (info
->plugin
, rb_plugins_shell
);
528 rb_plugins_engine_deactivate_plugin (RBPluginInfo
*info
)
532 g_return_val_if_fail (info
!= NULL
, FALSE
);
537 rb_plugins_engine_deactivate_plugin_real (info
, rb_plugins_shell
);
539 /* Update plugin state */
540 info
->active
= FALSE
;
542 key_name
= g_strdup_printf (CONF_PLUGIN_ACTIVE_KEY
, info
->location
);
543 eel_gconf_set_boolean (key_name
, FALSE
);
550 rb_plugins_engine_plugin_is_active (RBPluginInfo
*info
)
552 g_return_val_if_fail (info
!= NULL
, FALSE
);
558 rb_plugins_engine_plugin_is_visible (RBPluginInfo
*info
)
560 g_return_val_if_fail (info
!= NULL
, FALSE
);
562 return info
->visible
;
566 rb_plugins_engine_plugin_is_configurable (RBPluginInfo
*info
)
568 g_return_val_if_fail (info
!= NULL
, FALSE
);
570 if ((info
->plugin
== NULL
) || !info
->active
)
573 return rb_plugin_is_configurable (info
->plugin
);
577 rb_plugins_engine_configure_plugin (RBPluginInfo
*info
,
584 g_return_if_fail (info
!= NULL
);
586 conf_dlg
= rb_plugin_create_configure_dialog (info
->plugin
);
587 g_return_if_fail (conf_dlg
!= NULL
);
588 gtk_window_set_transient_for (GTK_WINDOW (conf_dlg
),
594 wg
= gtk_window_group_new ();
595 gtk_window_group_add_window (wg
, parent
);
598 gtk_window_group_add_window (wg
,
599 GTK_WINDOW (conf_dlg
));
601 gtk_window_set_modal (GTK_WINDOW (conf_dlg
), TRUE
);
602 gtk_widget_show (conf_dlg
);
606 rb_plugins_engine_plugin_active_cb (GConfClient
*client
,
611 if (gconf_value_get_bool (entry
->value
)) {
612 rb_plugins_engine_activate_plugin (info
);
614 rb_plugins_engine_deactivate_plugin (info
);
619 rb_plugins_engine_plugin_visible_cb (GConfClient
*client
,
624 info
->visible
= !gconf_value_get_bool (entry
->value
);
628 rb_plugins_engine_get_plugin_name (RBPluginInfo
*info
)
630 g_return_val_if_fail (info
!= NULL
, NULL
);
636 rb_plugins_engine_get_plugin_description (RBPluginInfo
*info
)
638 g_return_val_if_fail (info
!= NULL
, NULL
);
644 rb_plugins_engine_get_plugin_authors (RBPluginInfo
*info
)
646 g_return_val_if_fail (info
!= NULL
, (const gchar
**)NULL
);
648 return (const gchar
**)info
->authors
;
652 rb_plugins_engine_get_plugin_website (RBPluginInfo
*info
)
654 g_return_val_if_fail (info
!= NULL
, NULL
);
656 return info
->website
;
660 rb_plugins_engine_get_plugin_copyright (RBPluginInfo
*info
)
662 g_return_val_if_fail (info
!= NULL
, NULL
);
664 return info
->copyright
;
668 rb_plugins_engine_get_plugin_icon (RBPluginInfo
*info
)
670 if (info
->icon_name
== NULL
)
673 if (info
->icon_pixbuf
== NULL
) {
674 char *filename
= NULL
;
677 dirname
= g_path_get_dirname (info
->file
);
678 filename
= g_build_filename (dirname
, info
->icon_name
, NULL
);
681 info
->icon_pixbuf
= gdk_pixbuf_new_from_file (filename
, NULL
);
685 return info
->icon_pixbuf
;