[vinagre/plugin] Vinagre Plugin Support
- From: Jorge Pereira <jpereira src gnome org>
- To: svn-commits-list gnome org
- Subject: [vinagre/plugin] Vinagre Plugin Support
- Date: Tue, 7 Jul 2009 04:39:12 +0000 (UTC)
commit 1218ff62fb51df1b63cb181b06e9c987920a925c
Author: Jorge Pereira <jpereira gnome org>
Date: Mon Jul 6 23:10:19 2009 -0300
Vinagre Plugin Support
src/Makefile.am | 11 +-
src/vinagre-commands.c | 14 +-
src/vinagre-commands.h | 2 +
src/vinagre-debug.c | 131 ++++++
src/vinagre-debug.h | 66 +++
src/vinagre-dirs.c | 238 +++++++++++
src/vinagre-dirs.h | 50 +++
src/vinagre-plugin-info-priv.h | 58 +++
src/vinagre-plugin-info.c | 383 +++++++++++++++++
src/vinagre-plugin-loader.c | 131 ++++++
src/vinagre-plugin-loader.h | 106 +++++
src/vinagre-plugin-manager.c | 886 ++++++++++++++++++++++++++++++++++++++++
src/vinagre-plugin-manager.h | 74 ++++
src/vinagre-plugin-prefs.c | 474 +++++++++++++++++++++
src/vinagre-plugin-prefs.h | 59 +++
src/vinagre-plugin.c | 324 +++++++++++++++
src/vinagre-plugins-engine.c | 847 ++++++++++++++++++++++++++++++++++++++
src/vinagre-plugins-engine.h | 97 +++++
src/vinagre-ui.h | 4 +-
19 files changed, 3952 insertions(+), 3 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index f9a4b15..d961aee 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,6 +21,7 @@ INCLUDES = \
noinst_LTLIBRARIES = libvinagre.la
libvinagre_la_SOURCES = \
+ bacon-message-connection.h bacon-message-connection.c \
vinagre-commands.c vinagre-commands.h \
vinagre-connect.c vinagre-connect.h \
vinagre-connection.c vinagre-connection.h \
@@ -35,7 +36,15 @@ libvinagre_la_SOURCES = \
vinagre-ui.h vinagre-window-private.h \
vinagre-enums.h vinagre-enums.c \
vinagre-prefs.h vinagre-prefs.c \
- bacon-message-connection.h bacon-message-connection.c \
+ \
+ vinagre-debug.h vinagre-debug.c \
+ vinagre-dirs.h vinagre-dirs.c \
+ vinagre-plugin.h vinagre-plugin.c \
+ vinagre-plugin-manager.h vinagre-plugin-manager.c \
+ vinagre-plugin-info.h vinagre-plugin-info-priv.h vinagre-plugin-info.c \
+ vinagre-plugin-loader.h vinagre-plugin-loader.c \
+ vinagre-plugins-engine.h vinagre-plugins-engine.c \
+ \
vinagre-app.h vinagre-app.c \
vinagre-bacon.h vinagre-bacon.c \
vinagre-bookmarks-entry.h vinagre-bookmarks-entry.c \
diff --git a/src/vinagre-commands.c b/src/vinagre-commands.c
index 82a2a38..2bf278f 100644
--- a/src/vinagre-commands.c
+++ b/src/vinagre-commands.c
@@ -38,7 +38,7 @@
#include "vinagre-fav.h"
#include "vinagre-window-private.h"
#include "vinagre-prefs.h"
-
+#include "vinagre-plugin-manager.h"
void
vinagre_cmd_direct_connect (VinagreConnection *conn,
VinagreWindow *window)
@@ -204,6 +204,18 @@ vinagre_cmd_edit_preferences (GtkAction *action,
vinagre_prefs_dialog_show (window);
}
+void
+vinagre_cmd_edit_plugins (GtkAction *action,
+ VinagreWindow *window)
+{
+ g_return_if_fail (VINAGRE_IS_WINDOW (window));
+ GtkWidget *widget;
+
+ widget = vinagre_plugin_manager_new ();
+
+ gtk_widget_show_all (widget);
+}
+
/* View Menu */
void
vinagre_cmd_view_show_toolbar (GtkAction *action,
diff --git a/src/vinagre-commands.h b/src/vinagre-commands.h
index 8683e41..c87e6f6 100644
--- a/src/vinagre-commands.h
+++ b/src/vinagre-commands.h
@@ -46,6 +46,8 @@ void vinagre_cmd_machine_quit (GtkAction *action,
void vinagre_cmd_edit_preferences (GtkAction *action,
VinagreWindow *window);
+void vinagre_cmd_edit_plugins (GtkAction *action,
+ VinagreWindow *window);
void vinagre_cmd_view_show_toolbar (GtkAction *action,
VinagreWindow *window);
diff --git a/src/vinagre-debug.c b/src/vinagre-debug.c
new file mode 100644
index 0000000..6e228d9
--- /dev/null
+++ b/src/vinagre-debug.c
@@ -0,0 +1,131 @@
+/*
+ * vinagre-debug.c
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jorge Pereira <jorge jorgepereira com br>
+ *
+ * vinagre-debug.c is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * vinagre-debug.c is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include "vinagre-debug.h"
+
+#define ENABLE_PROFILING
+
+#ifdef ENABLE_PROFILING
+static GTimer *timer = NULL;
+static gdouble last = 0.0;
+#endif
+
+static VinagreDebugSection debug = VINAGRE_NO_DEBUG;
+
+void
+vinagre_debug_init ()
+{
+ if (g_getenv ("VINAGRE_DEBUG") != NULL)
+ {
+ /* enable all debugging */
+ debug = ~VINAGRE_NO_DEBUG;
+ goto out;
+ }
+
+ if (g_getenv ("VINAGRE_DEBUG_VIEW") != NULL)
+ debug = debug | VINAGRE_DEBUG_VIEW;
+ if (g_getenv ("VINAGRE_DEBUG_PREFS") != NULL)
+ debug = debug | VINAGRE_DEBUG_PREFS;
+ if (g_getenv ("VINAGRE_DEBUG_PRINT") != NULL)
+ debug = debug | VINAGRE_DEBUG_PRINT;
+ if (g_getenv ("VINAGRE_DEBUG_PLUGINS") != NULL)
+ debug = debug | VINAGRE_DEBUG_PLUGINS;
+ if (g_getenv ("VINAGRE_DEBUG_UTILS") != NULL)
+ debug = debug | VINAGRE_DEBUG_UTILS;
+ if (g_getenv ("VINAGRE_DEBUG_WINDOW") != NULL)
+ debug = debug | VINAGRE_DEBUG_WINDOW;
+ if (g_getenv ("VINAGRE_DEBUG_LOADER") != NULL)
+ debug = debug | VINAGRE_DEBUG_LOADER;
+
+out:
+
+#ifdef ENABLE_PROFILING
+ if (debug != VINAGRE_NO_DEBUG)
+ timer = g_timer_new ();
+#endif
+ return;
+}
+
+void
+vinagre_debug_message (VinagreDebugSection section,
+ const gchar *file,
+ gint line,
+ const gchar *function,
+ const gchar *format, ...)
+{
+ if (G_UNLIKELY (debug & section))
+ {
+#ifdef ENABLE_PROFILING
+ gdouble seconds;
+#endif
+
+ va_list args;
+ gchar *msg;
+
+ g_return_if_fail (format != NULL);
+
+ va_start (args, format);
+ msg = g_strdup_vprintf (format, args);
+ va_end (args);
+
+#ifdef ENABLE_PROFILING
+ g_return_if_fail (timer != NULL);
+
+ seconds = g_timer_elapsed (timer, NULL);
+ g_print ("[%f (%f)] %s:%d (%s) %s\n",
+ seconds, seconds - last, file, line, function, msg);
+ last = seconds;
+#else
+ g_print ("%s:%d (%s) %s\n", file, line, function, msg);
+#endif
+
+ fflush (stdout);
+
+ g_free (msg);
+ }
+}
+
+void vinagre_debug (VinagreDebugSection section,
+ const gchar *file,
+ gint line,
+ const gchar *function)
+{
+ if (G_UNLIKELY (debug & section))
+ {
+#ifdef ENABLE_PROFILING
+ gdouble seconds;
+
+ g_return_if_fail (timer != NULL);
+
+ seconds = g_timer_elapsed (timer, NULL);
+ g_print ("[%f (%f)] %s:%d (%s)\n",
+ seconds, seconds - last, file, line, function);
+ last = seconds;
+#else
+ g_print ("%s:%d (%s)\n", file, line, function);
+#endif
+ fflush (stdout);
+ }
+}
diff --git a/src/vinagre-debug.h b/src/vinagre-debug.h
new file mode 100644
index 0000000..360e268
--- /dev/null
+++ b/src/vinagre-debug.h
@@ -0,0 +1,66 @@
+/*
+ * vinagre-debug.h
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jorge Pereira <jorge jorgepereira com br>
+ *
+ * vinagre-debug.h is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * vinagre-debug.h is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __VINAGRE_DEBUG_H__
+#define __VINAGRE_DEBUG_H__
+
+#include <glib.h>
+
+/*
+ * Set an environmental var of the same name to turn on
+ * debugging output. Setting VINAGRE_DEBUG will turn on all
+ * sections.
+ */
+typedef enum {
+ VINAGRE_NO_DEBUG = 0,
+ VINAGRE_DEBUG_VIEW = 1 << 0,
+ VINAGRE_DEBUG_PRINT = 1 << 1,
+ VINAGRE_DEBUG_PREFS = 1 << 2,
+ VINAGRE_DEBUG_PLUGINS = 1 << 3,
+ VINAGRE_DEBUG_UTILS = 1 << 4,
+ VINAGRE_DEBUG_WINDOW = 1 << 5,
+ VINAGRE_DEBUG_LOADER = 1 << 6,
+} VinagreDebugSection;
+
+
+#define DEBUG_VIEW VINAGRE_DEBUG_VIEW, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_PRINT VINAGRE_DEBUG_PRINT, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_PREFS VINAGRE_DEBUG_PREFS, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_PLUGINS VINAGRE_DEBUG_PLUGINS, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_UTILS VINAGRE_DEBUG_UTILS, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_WINDOW VINAGRE_DEBUG_WINDOW, __FILE__, __LINE__, G_STRFUNC
+#define DEBUG_LOADER VINAGRE_DEBUG_LOADER, __FILE__, __LINE__, G_STRFUNC
+
+void vinagre_debug_init (void);
+
+void vinagre_debug (VinagreDebugSection section,
+ const gchar *file,
+ gint line,
+ const gchar *function);
+
+void vinagre_debug_message (VinagreDebugSection section,
+ const gchar *file,
+ gint line,
+ const gchar *function,
+ const gchar *format, ...) G_GNUC_PRINTF(5, 6);
+
+
+#endif /* __VINAGRE_DEBUG_H__ */
+
diff --git a/src/vinagre-dirs.c b/src/vinagre-dirs.c
new file mode 100644
index 0000000..6a93747
--- /dev/null
+++ b/src/vinagre-dirs.c
@@ -0,0 +1,238 @@
+/*
+ * vinagre-dirs.c
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jorge Pereira <jorge jorgepereira com br>
+ *
+ * vinagre-dirs.c is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * vinagre-dirs.c is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "vinagre-dirs.h"
+
+gchar *
+vinagre_dirs_get_user_config_dir ()
+{
+ gchar *config_dir = NULL;
+
+#ifndef G_OS_WIN32
+ const gchar *home;
+
+ home = g_get_home_dir ();
+
+ if (home != NULL)
+ {
+ config_dir = g_build_filename (home,
+ ".gnome2",
+ "vinagre",
+ NULL);
+ }
+#else
+ config_dir = g_build_filename (g_get_user_config_dir (),
+ "vinagre",
+ NULL);
+#endif
+
+ return config_dir;
+}
+
+gchar *
+vinagre_dirs_get_user_cache_dir ()
+{
+ const gchar *cache_dir;
+
+ cache_dir = g_get_user_cache_dir ();
+
+ return g_build_filename (cache_dir,
+ "vinagre",
+ NULL);
+}
+
+gchar *
+vinagre_dirs_get_user_plugins_dir (void)
+{
+ gchar *config_dir;
+ gchar *plugin_dir;
+
+ config_dir = vinagre_dirs_get_user_config_dir ();
+
+ plugin_dir = g_build_filename (config_dir,
+ "plugins",
+ NULL);
+ g_free (config_dir);
+
+ return plugin_dir;
+}
+
+gchar *
+vinagre_dirs_get_user_accels_file ()
+{
+ gchar *accels = NULL;
+
+#ifndef G_OS_WIN32
+ const gchar *home;
+
+ home = g_get_home_dir ();
+
+ if (home != NULL)
+ {
+ /* on linux accels are stored in .gnome2/accels
+ * for historic reasons (backward compat with the
+ * old libgnome that took care of saving them */
+ accels = g_build_filename (home,
+ ".gnome2",
+ "accels",
+ "vinagre",
+ NULL);
+ }
+#else
+ {
+ gchar *config_dir = NULL;
+
+ config_dir = vinagre_dirs_get_user_config_dir ();
+ accels = g_build_filename (config_dir,
+ "accels",
+ "vinagre",
+ NULL);
+
+ g_free (config_dir);
+ }
+#endif
+
+ return accels;
+}
+
+gchar *
+vinagre_dirs_get_vinagre_data_dir (void)
+{
+ gchar *data_dir;
+
+#ifndef G_OS_WIN32
+ data_dir = g_build_filename (DATADIR,
+ "vinagre",
+ NULL);
+#else
+ gchar *win32_dir;
+
+ win32_dir = g_win32_get_package_installation_directory_of_module (NULL);
+
+ data_dir = g_build_filename (win32_dir,
+ "share",
+ "vinagre",
+ NULL);
+
+ g_free (win32_dir);
+#endif
+
+ return data_dir;
+}
+
+gchar *
+vinagre_dirs_get_vinagre_locale_dir (void)
+{
+ gchar *locale_dir;
+
+#ifndef G_OS_WIN32
+ locale_dir = g_build_filename (DATADIR,
+ "locale",
+ NULL);
+#else
+ gchar *win32_dir;
+
+ win32_dir = g_win32_get_package_installation_directory_of_module (NULL);
+
+ locale_dir = g_build_filename (win32_dir,
+ "share",
+ "locale",
+ NULL);
+
+ g_free (win32_dir);
+#endif
+
+ return locale_dir;
+}
+
+gchar *
+vinagre_dirs_get_vinagre_lib_dir (void)
+{
+ gchar *lib_dir;
+
+#ifndef G_OS_WIN32
+ lib_dir = g_build_filename (LIBDIR,
+ "vinagre",
+ NULL);
+#else
+ gchar *win32_dir;
+
+ win32_dir = g_win32_get_package_installation_directory_of_module (NULL);
+
+ lib_dir = g_build_filename (win32_dir,
+ "lib",
+ "vinagre",
+ NULL);
+
+ g_free (win32_dir);
+#endif
+
+ return lib_dir;
+}
+
+gchar *
+vinagre_dirs_get_vinagre_plugins_dir (void)
+{
+ gchar *lib_dir;
+ gchar *plugin_dir;
+
+ lib_dir = vinagre_dirs_get_vinagre_lib_dir ();
+
+ plugin_dir = g_build_filename (lib_dir,
+ "plugins",
+ NULL);
+ g_free (lib_dir);
+
+ return plugin_dir;
+}
+
+gchar *
+vinagre_dirs_get_vinagre_plugin_loaders_dir (void)
+{
+ gchar *lib_dir;
+ gchar *loader_dir;
+
+ lib_dir = vinagre_dirs_get_vinagre_lib_dir ();
+
+ loader_dir = g_build_filename (lib_dir,
+ "plugin-loaders",
+ NULL);
+ g_free (lib_dir);
+
+ return loader_dir;
+}
+
+gchar *
+vinagre_dirs_get_ui_file (const gchar *file)
+{
+ gchar *datadir;
+ gchar *ui_file;
+
+ g_return_val_if_fail (file != NULL, NULL);
+
+ datadir = vinagre_dirs_get_vinagre_data_dir ();
+ ui_file = g_build_filename (datadir,
+ "ui",
+ file,
+ NULL);
+ g_free (datadir);
+
+ return ui_file;
+}
diff --git a/src/vinagre-dirs.h b/src/vinagre-dirs.h
new file mode 100644
index 0000000..0b1414c
--- /dev/null
+++ b/src/vinagre-dirs.h
@@ -0,0 +1,50 @@
+/*
+ * vinagre-dirs.h
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jorge Pereira <jorge jorgepereira com br>
+ *
+ * vinagre-dirs.h is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * vinagre-dirs.h is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __VINAGRE_DIRS_H__
+#define __VINAGRE_DIRS_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+gchar *vinagre_dirs_get_user_config_dir (void);
+
+gchar *vinagre_dirs_get_user_cache_dir (void);
+
+gchar *vinagre_dirs_get_user_plugins_dir (void);
+
+gchar *vinagre_dirs_get_user_accels_file (void);
+
+gchar *vinagre_dirs_get_vinagre_data_dir (void);
+
+gchar *vinagre_dirs_get_vinagre_locale_dir (void);
+
+gchar *vinagre_dirs_get_vinagre_lib_dir (void);
+
+gchar *vinagre_dirs_get_vinagre_plugins_dir (void);
+
+gchar *vinagre_dirs_get_vinagre_plugin_loaders_dir (void);
+
+gchar *vinagre_dirs_get_ui_file (const gchar *file);
+
+G_END_DECLS
+
+#endif /* __VINAGRE_DIRS_H__ */
diff --git a/src/vinagre-plugin-info-priv.h b/src/vinagre-plugin-info-priv.h
new file mode 100644
index 0000000..b3ed18e
--- /dev/null
+++ b/src/vinagre-plugin-info-priv.h
@@ -0,0 +1,58 @@
+/*
+ * vinagre-plugin-info-priv.h
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jorge Pereira <jorge jorgepereira com br>
+ *
+ * vinagre-plugin-info-priv.h is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * vinagre-plugin-info-priv.h is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __VINAGRE_PLUGIN_INFO_PRIV_H__
+#define __VINAGRE_PLUGIN_INFO_PRIV_H__
+
+#include "vinagre-plugin-info.h"
+#include "vinagre-plugin.h"
+
+struct _VinagrePluginInfo
+{
+ gint refcount;
+
+ VinagrePlugin *plugin;
+ gchar *file;
+
+ gchar *module_name;
+ gchar *loader;
+ gchar **dependencies;
+
+ gchar *name;
+ gchar *desc;
+ gchar *icon_name;
+ gchar **authors;
+ gchar *copyright;
+ gchar *website;
+ gchar *version;
+
+ /* A plugin is unavailable if it is not possible to activate it
+ due to an error loading the plugin module (e.g. for Python plugins
+ when the interpreter has not been correctly initializated) */
+ gint available : 1;
+};
+
+VinagrePluginInfo *_vinagre_plugin_info_new (const gchar *file);
+void _vinagre_plugin_info_ref (VinagrePluginInfo *info);
+void _vinagre_plugin_info_unref (VinagrePluginInfo *info);
+
+
+#endif /* __VINAGRE_PLUGIN_INFO_PRIV_H__ */
+
diff --git a/src/vinagre-plugin-info.c b/src/vinagre-plugin-info.c
new file mode 100644
index 0000000..0c4a3bf
--- /dev/null
+++ b/src/vinagre-plugin-info.c
@@ -0,0 +1,383 @@
+/*
+ * vinagre-plugin-info.c
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jorge Pereira <jorge jorgepereira com br>
+ *
+ * vinagre-plugin-info.c is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * vinagre-plugin-info.c is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <glib.h>
+
+#include "vinagre-debug.h"
+#include "vinagre-plugin.h"
+#include "vinagre-plugin-info.h"
+#include "vinagre-plugin-info-priv.h"
+
+void
+_vinagre_plugin_info_ref (VinagrePluginInfo *info)
+{
+ g_atomic_int_inc (&info->refcount);
+}
+
+static VinagrePluginInfo *
+vinagre_plugin_info_copy (VinagrePluginInfo *info)
+{
+ _vinagre_plugin_info_ref (info);
+ return info;
+}
+
+void
+_vinagre_plugin_info_unref (VinagrePluginInfo *info)
+{
+ if (!g_atomic_int_dec_and_test (&info->refcount))
+ return;
+
+ if (info->plugin != NULL)
+ {
+ vinagre_debug_message (DEBUG_PLUGINS, "Unref plugin %s", info->name);
+
+ g_object_unref (info->plugin);
+ }
+
+ g_free (info->file);
+ g_free (info->module_name);
+ g_strfreev (info->dependencies);
+ g_free (info->name);
+ g_free (info->desc);
+ g_free (info->icon_name);
+ g_free (info->website);
+ g_free (info->copyright);
+ g_free (info->loader);
+ g_free (info->version);
+ g_strfreev (info->authors);
+
+ g_free (info);
+}
+
+/**
+ * vinagre_plugin_info_get_type:
+ *
+ * Retrieves the #GType object which is associated with the #VinagrePluginInfo
+ * class.
+ *
+ * Return value: the GType associated with #VinagrePluginInfo.
+ **/
+GType
+vinagre_plugin_info_get_type (void)
+{
+ static GType the_type = 0;
+
+ if (G_UNLIKELY (!the_type))
+ the_type = g_boxed_type_register_static (
+ "VinagrePluginInfo",
+ (GBoxedCopyFunc) vinagre_plugin_info_copy,
+ (GBoxedFreeFunc) _vinagre_plugin_info_unref);
+
+ return the_type;
+}
+
+/**
+ * vinagre_plugin_info_new:
+ * @filename: the filename where to read the plugin information
+ *
+ * Creates a new #VinagrePluginInfo from a file on the disk.
+ *
+ * Return value: a newly created #VinagrePluginInfo.
+ */
+VinagrePluginInfo *
+_vinagre_plugin_info_new (const gchar *file)
+{
+ VinagrePluginInfo *info;
+ GKeyFile *plugin_file = NULL;
+ gchar *str;
+
+ g_return_val_if_fail (file != NULL, NULL);
+
+ vinagre_debug_message (DEBUG_PLUGINS, "Loading plugin: %s", file);
+
+ info = g_new0 (VinagrePluginInfo, 1);
+ info->refcount = 1;
+ info->file = g_strdup (file);
+
+ plugin_file = g_key_file_new ();
+ if (!g_key_file_load_from_file (plugin_file, file, G_KEY_FILE_NONE, NULL))
+ {
+ g_warning ("Bad plugin file: %s", file);
+ goto error;
+ }
+
+ if (!g_key_file_has_key (plugin_file,
+ "Vinagre Plugin",
+ "IAge",
+ NULL))
+ {
+ vinagre_debug_message (DEBUG_PLUGINS,
+ "IAge key does not exist in file: %s", file);
+ goto error;
+ }
+
+ /* Check IAge=2 */
+ if (g_key_file_get_integer (plugin_file,
+ "Vinagre Plugin",
+ "IAge",
+ NULL) != 2)
+ {
+ vinagre_debug_message (DEBUG_PLUGINS,
+ "Wrong IAge in file: %s", file);
+ goto error;
+ }
+
+ /* Get module name */
+ str = g_key_file_get_string (plugin_file,
+ "Vinagre Plugin",
+ "Module",
+ NULL);
+
+ if ((str != NULL) && (*str != '\0'))
+ {
+ info->module_name = str;
+ }
+ else
+ {
+ g_warning ("Could not find 'Module' in %s", file);
+ goto error;
+ }
+
+ /* Get the dependency list */
+ info->dependencies = g_key_file_get_string_list (plugin_file,
+ "Vinagre Plugin",
+ "Depends",
+ NULL,
+ NULL);
+ if (info->dependencies == NULL)
+ {
+ vinagre_debug_message (DEBUG_PLUGINS, "Could not find 'Depends' in %s", file);
+ info->dependencies = g_new0 (gchar *, 1);
+ }
+
+ /* Get the loader for this plugin */
+ str = g_key_file_get_string (plugin_file,
+ "Vinagre Plugin",
+ "Loader",
+ NULL);
+
+ if ((str != NULL) && (*str != '\0'))
+ {
+ info->loader = str;
+ }
+ else
+ {
+ /* default to the C loader */
+ info->loader = g_strdup("c");
+ }
+
+ /* Get Name */
+ str = g_key_file_get_locale_string (plugin_file,
+ "Vinagre Plugin",
+ "Name",
+ NULL, NULL);
+ if (str)
+ info->name = str;
+ else
+ {
+ g_warning ("Could not find 'Name' in %s", file);
+ goto error;
+ }
+
+ /* Get Description */
+ str = g_key_file_get_locale_string (plugin_file,
+ "Vinagre Plugin",
+ "Description",
+ NULL, NULL);
+ if (str)
+ info->desc = str;
+ else
+ vinagre_debug_message (DEBUG_PLUGINS, "Could not find 'Description' in %s", file);
+
+ /* Get Icon */
+ str = g_key_file_get_locale_string (plugin_file,
+ "Vinagre Plugin",
+ "Icon",
+ NULL, NULL);
+ if (str)
+ info->icon_name = str;
+ else
+ vinagre_debug_message (DEBUG_PLUGINS, "Could not find 'Icon' in %s, using 'vinagre-plugin'", file);
+
+
+ /* Get Authors */
+ info->authors = g_key_file_get_string_list (plugin_file,
+ "Vinagre Plugin",
+ "Authors",
+ NULL,
+ NULL);
+ if (info->authors == NULL)
+ vinagre_debug_message (DEBUG_PLUGINS, "Could not find 'Authors' in %s", file);
+
+
+ /* Get Copyright */
+ str = g_key_file_get_string (plugin_file,
+ "Vinagre Plugin",
+ "Copyright",
+ NULL);
+ if (str)
+ info->copyright = str;
+ else
+ vinagre_debug_message (DEBUG_PLUGINS, "Could not find 'Copyright' in %s", file);
+
+ /* Get Website */
+ str = g_key_file_get_string (plugin_file,
+ "Vinagre Plugin",
+ "Website",
+ NULL);
+ if (str)
+ info->website = str;
+ else
+ vinagre_debug_message (DEBUG_PLUGINS, "Could not find 'Website' in %s", file);
+
+ /* Get Version */
+ str = g_key_file_get_string (plugin_file,
+ "Vinagre Plugin",
+ "Version",
+ NULL);
+ if (str)
+ info->version = str;
+ else
+ vinagre_debug_message (DEBUG_PLUGINS, "Could not find 'Version' in %s", file);
+
+ g_key_file_free (plugin_file);
+
+ /* If we know nothing about the availability of the plugin,
+ set it as available */
+ info->available = TRUE;
+
+ return info;
+
+error:
+ g_free (info->file);
+ g_free (info->module_name);
+ g_free (info->name);
+ g_free (info->loader);
+ g_free (info);
+ g_key_file_free (plugin_file);
+
+ return NULL;
+}
+
+gboolean
+vinagre_plugin_info_is_active (VinagrePluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ return info->available && info->plugin != NULL;
+}
+
+gboolean
+vinagre_plugin_info_is_available (VinagrePluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ return info->available != FALSE;
+}
+
+gboolean
+vinagre_plugin_info_is_configurable (VinagrePluginInfo *info)
+{
+ vinagre_debug_message (DEBUG_PLUGINS, "Is '%s' configurable?", info->name);
+
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ if (info->plugin == NULL || !info->available)
+ return FALSE;
+
+ return vinagre_plugin_is_configurable (info->plugin);
+}
+
+const gchar *
+vinagre_plugin_info_get_module_name (VinagrePluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->module_name;
+}
+
+const gchar *
+vinagre_plugin_info_get_name (VinagrePluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->name;
+}
+
+const gchar *
+vinagre_plugin_info_get_description (VinagrePluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->desc;
+}
+
+const gchar *
+vinagre_plugin_info_get_icon_name (VinagrePluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ /* use the vinagre-plugin icon as a default if the plugin does not
+ have its own */
+ if (info->icon_name != NULL &&
+ gtk_icon_theme_has_icon (gtk_icon_theme_get_default (),
+ info->icon_name))
+ return info->icon_name;
+ else
+ return "vinagre-plugin";
+}
+
+const gchar **
+vinagre_plugin_info_get_authors (VinagrePluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, (const gchar **)NULL);
+
+ return (const gchar **) info->authors;
+}
+
+const gchar *
+vinagre_plugin_info_get_website (VinagrePluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->website;
+}
+
+const gchar *
+vinagre_plugin_info_get_copyright (VinagrePluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->copyright;
+}
+
+const gchar *
+vinagre_plugin_info_get_version (VinagrePluginInfo *info)
+{
+ g_return_val_if_fail (info != NULL, NULL);
+
+ return info->version;
+}
diff --git a/src/vinagre-plugin-loader.c b/src/vinagre-plugin-loader.c
new file mode 100644
index 0000000..e7f1af4
--- /dev/null
+++ b/src/vinagre-plugin-loader.c
@@ -0,0 +1,131 @@
+/*
+ * vinagre-plugin-loader.c
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2008 - Jesse van den Kieboom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "vinagre-plugin-loader.h"
+
+static void
+vinagre_plugin_loader_base_init (gpointer g_class)
+{
+ static gboolean initialized = FALSE;
+
+ if (G_UNLIKELY (!initialized))
+ {
+ /* create interface signals here. */
+ initialized = TRUE;
+ }
+}
+
+GType
+vinagre_plugin_loader_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0))
+ {
+ static const GTypeInfo info =
+ {
+ sizeof (VinagrePluginLoaderInterface),
+ vinagre_plugin_loader_base_init, /* base_init */
+ NULL, /* base_finalize */
+ NULL, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0, /* n_preallocs */
+ NULL /* instance_init */
+ };
+
+ type = g_type_register_static (G_TYPE_INTERFACE, "VinagrePluginLoader", &info, 0);
+ }
+
+ return type;
+}
+
+const gchar *
+vinagre_plugin_loader_type_get_id (GType type)
+{
+ GTypeClass *klass;
+ VinagrePluginLoaderInterface *iface;
+
+ klass = g_type_class_ref (type);
+
+ if (klass == NULL)
+ {
+ g_warning ("Could not get class info for plugin loader");
+ return NULL;
+ }
+
+ iface = g_type_interface_peek (klass, VINAGRE_TYPE_PLUGIN_LOADER);
+
+ if (iface == NULL)
+ {
+ g_warning ("Could not get plugin loader interface");
+ g_type_class_unref (klass);
+
+ return NULL;
+ }
+
+ g_return_val_if_fail (iface->get_id != NULL, NULL);
+ return iface->get_id ();
+}
+
+VinagrePlugin *
+vinagre_plugin_loader_load (VinagrePluginLoader *loader,
+ VinagrePluginInfo *info,
+ const gchar *path)
+{
+ VinagrePluginLoaderInterface *iface;
+
+ g_return_val_if_fail (VINAGRE_IS_PLUGIN_LOADER (loader), NULL);
+
+ iface = VINAGRE_PLUGIN_LOADER_GET_INTERFACE (loader);
+ g_return_val_if_fail (iface->load != NULL, NULL);
+
+ return iface->load (loader, info, path);
+}
+
+void
+vinagre_plugin_loader_unload (VinagrePluginLoader *loader,
+ VinagrePluginInfo *info)
+{
+ VinagrePluginLoaderInterface *iface;
+
+ g_return_if_fail (VINAGRE_IS_PLUGIN_LOADER (loader));
+
+ iface = VINAGRE_PLUGIN_LOADER_GET_INTERFACE (loader);
+ g_return_if_fail (iface->unload != NULL);
+
+ iface->unload (loader, info);
+}
+
+void
+vinagre_plugin_loader_garbage_collect (VinagrePluginLoader *loader)
+{
+ VinagrePluginLoaderInterface *iface;
+
+ g_return_if_fail (VINAGRE_IS_PLUGIN_LOADER (loader));
+
+ iface = VINAGRE_PLUGIN_LOADER_GET_INTERFACE (loader);
+
+ if (iface->garbage_collect != NULL)
+ iface->garbage_collect (loader);
+}
diff --git a/src/vinagre-plugin-loader.h b/src/vinagre-plugin-loader.h
new file mode 100644
index 0000000..838aac6
--- /dev/null
+++ b/src/vinagre-plugin-loader.h
@@ -0,0 +1,106 @@
+/*
+ * vinagre-plugin-loader.h
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2008 - Jesse van den Kieboom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __VINAGRE_PLUGIN_LOADER_H__
+#define __VINAGRE_PLUGIN_LOADER_H__
+
+#include <glib-object.h>
+#include <vinagre/vinagre-plugin.h>
+#include <vinagre/vinagre-plugin-info.h>
+
+G_BEGIN_DECLS
+
+#define VINAGRE_TYPE_PLUGIN_LOADER (vinagre_plugin_loader_get_type ())
+#define VINAGRE_PLUGIN_LOADER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VINAGRE_TYPE_PLUGIN_LOADER, VinagrePluginLoader))
+#define VINAGRE_IS_PLUGIN_LOADER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VINAGRE_TYPE_PLUGIN_LOADER))
+#define VINAGRE_PLUGIN_LOADER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), VINAGRE_TYPE_PLUGIN_LOADER, VinagrePluginLoaderInterface))
+
+typedef struct _VinagrePluginLoader VinagrePluginLoader; /* dummy object */
+typedef struct _VinagrePluginLoaderInterface VinagrePluginLoaderInterface;
+
+struct _VinagrePluginLoaderInterface {
+ GTypeInterface parent;
+
+ const gchar *(*get_id) (void);
+
+ VinagrePlugin *(*load) (VinagrePluginLoader *loader,
+ VinagrePluginInfo *info,
+ const gchar *path);
+
+ void (*unload) (VinagrePluginLoader *loader,
+ VinagrePluginInfo *info);
+
+ void (*garbage_collect) (VinagrePluginLoader *loader);
+};
+
+GType vinagre_plugin_loader_get_type (void);
+
+const gchar *vinagre_plugin_loader_type_get_id (GType type);
+VinagrePlugin *vinagre_plugin_loader_load (VinagrePluginLoader *loader,
+ VinagrePluginInfo *info,
+ const gchar *path);
+void vinagre_plugin_loader_unload (VinagrePluginLoader *loader,
+ VinagrePluginInfo *info);
+void vinagre_plugin_loader_garbage_collect (VinagrePluginLoader *loader);
+
+/**
+ * VINAGRE_PLUGIN_LOADER_IMPLEMENT_INTERFACE(TYPE_IFACE, iface_init):
+ *
+ * Utility macro used to register interfaces for gobject types in plugin loaders.
+ */
+#define VINAGRE_PLUGIN_LOADER_IMPLEMENT_INTERFACE(TYPE_IFACE, iface_init) \
+ const GInterfaceInfo g_implement_interface_info = \
+ { \
+ (GInterfaceInitFunc) iface_init, \
+ NULL, \
+ NULL \
+ }; \
+ \
+ g_type_module_add_interface (type_module, \
+ g_define_type_id, \
+ TYPE_IFACE, \
+ &g_implement_interface_info);
+
+/**
+ * VINAGRE_PLUGIN_LOADER_REGISTER_TYPE(PluginLoaderName, plugin_loader_name, PARENT_TYPE, loader_interface_init):
+ *
+ * Utility macro used to register plugin loaders.
+ */
+#define VINAGRE_PLUGIN_LOADER_REGISTER_TYPE(PluginLoaderName, plugin_loader_name, PARENT_TYPE, loader_iface_init) \
+ G_DEFINE_DYNAMIC_TYPE_EXTENDED (PluginLoaderName, \
+ plugin_loader_name, \
+ PARENT_TYPE, \
+ 0, \
+ VINAGRE_PLUGIN_LOADER_IMPLEMENT_INTERFACE(VINAGRE_TYPE_PLUGIN_LOADER, loader_iface_init)); \
+ \
+ \
+G_MODULE_EXPORT GType \
+register_vinagre_plugin_loader (GTypeModule *type_module) \
+{ \
+ plugin_loader_name##_register_type (type_module); \
+ \
+ return plugin_loader_name##_get_type(); \
+}
+
+G_END_DECLS
+
+#endif /* __VINAGRE_PLUGIN_LOADER_H__ */
diff --git a/src/vinagre-plugin-manager.c b/src/vinagre-plugin-manager.c
new file mode 100644
index 0000000..7531a50
--- /dev/null
+++ b/src/vinagre-plugin-manager.c
@@ -0,0 +1,886 @@
+/*
+ * vinagre-plugins-manager.c
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jorge Pereira <jorge jorgepereira com br>
+ *
+ * vinagre-plugins-manager.c is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * vinagre-plugins-manager.c is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+
+#include "vinagre-plugin-manager.h"
+#include "vinagre-utils.h"
+#include "vinagre-plugins-engine.h"
+#include "vinagre-plugin.h"
+#include "vinagre-debug.h"
+
+enum
+{
+ ACTIVE_COLUMN,
+ AVAILABLE_COLUMN,
+ INFO_COLUMN,
+ N_COLUMNS
+};
+
+#define PLUGIN_MANAGER_NAME_TITLE _("Plugin")
+#define PLUGIN_MANAGER_ACTIVE_TITLE _("Enabled")
+
+#define VINAGRE_PLUGIN_MANAGER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), VINAGRE_TYPE_PLUGIN_MANAGER, VinagrePluginManagerPrivate))
+
+struct _VinagrePluginManagerPrivate
+{
+ GtkWidget *tree;
+
+ GtkWidget *about_button;
+ GtkWidget *configure_button;
+
+ VinagrePluginsEngine *engine;
+
+ GtkWidget *about;
+
+ GtkWidget *popup_menu;
+};
+
+G_DEFINE_TYPE(VinagrePluginManager, vinagre_plugin_manager, GTK_TYPE_VBOX)
+
+static VinagrePluginInfo *plugin_manager_get_selected_plugin (VinagrePluginManager *pm);
+static void plugin_manager_toggle_active (VinagrePluginManager *pm, GtkTreeIter *iter, GtkTreeModel *model);
+static void vinagre_plugin_manager_finalize (GObject *object);
+
+static void
+vinagre_plugin_manager_class_init (VinagrePluginManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = vinagre_plugin_manager_finalize;
+
+ g_type_class_add_private (object_class, sizeof (VinagrePluginManagerPrivate));
+}
+
+static void
+about_button_cb (GtkWidget *button,
+ VinagrePluginManager *pm)
+{
+ VinagrePluginInfo *info;
+
+ vinagre_debug (DEBUG_PLUGINS);
+
+ info = plugin_manager_get_selected_plugin (pm);
+
+ g_return_if_fail (info != NULL);
+
+ /* if there is another about dialog already open destroy it */
+ if (pm->priv->about)
+ gtk_widget_destroy (pm->priv->about);
+
+ pm->priv->about = g_object_new (GTK_TYPE_ABOUT_DIALOG,
+ "program-name", vinagre_plugin_info_get_name (info),
+ "copyright", vinagre_plugin_info_get_copyright (info),
+ "authors", vinagre_plugin_info_get_authors (info),
+ "comments", vinagre_plugin_info_get_description (info),
+ "website", vinagre_plugin_info_get_website (info),
+ "logo-icon-name", vinagre_plugin_info_get_icon_name (info),
+ "version", vinagre_plugin_info_get_version (info),
+ NULL);
+
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (pm->priv->about),
+ TRUE);
+
+ g_signal_connect (pm->priv->about,
+ "response",
+ G_CALLBACK (gtk_widget_destroy),
+ NULL);
+ g_signal_connect (pm->priv->about,
+ "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &pm->priv->about);
+
+ gtk_window_set_transient_for (GTK_WINDOW (pm->priv->about),
+ GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET(pm))));
+ gtk_widget_show (pm->priv->about);
+}
+
+static void
+configure_button_cb (GtkWidget *button,
+ VinagrePluginManager *pm)
+{
+ VinagrePluginInfo *info;
+ GtkWindow *toplevel;
+
+ vinagre_debug (DEBUG_PLUGINS);
+
+ info = plugin_manager_get_selected_plugin (pm);
+
+ g_return_if_fail (info != NULL);
+
+ vinagre_debug_message (DEBUG_PLUGINS, "Configuring: %s\n",
+ vinagre_plugin_info_get_name (info));
+
+ toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET(pm)));
+
+ vinagre_plugins_engine_configure_plugin (pm->priv->engine,
+ info, toplevel);
+
+ vinagre_debug_message (DEBUG_PLUGINS, "Done");
+}
+
+static void
+plugin_manager_view_info_cell_cb (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ VinagrePluginInfo *info;
+ gchar *text;
+
+ g_return_if_fail (tree_model != NULL);
+ g_return_if_fail (tree_column != NULL);
+
+ gtk_tree_model_get (tree_model, iter, INFO_COLUMN, &info, -1);
+
+ if (info == NULL)
+ return;
+
+ text = g_markup_printf_escaped ("<b>%s</b>\n%s",
+ vinagre_plugin_info_get_name (info),
+ vinagre_plugin_info_get_description (info));
+ g_object_set (G_OBJECT (cell),
+ "markup", text,
+ "sensitive", vinagre_plugin_info_is_available (info),
+ NULL);
+
+ g_free (text);
+}
+
+static void
+plugin_manager_view_icon_cell_cb (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ VinagrePluginInfo *info;
+
+ g_return_if_fail (tree_model != NULL);
+ g_return_if_fail (tree_column != NULL);
+
+ gtk_tree_model_get (tree_model, iter, INFO_COLUMN, &info, -1);
+
+ if (info == NULL)
+ return;
+
+ g_object_set (G_OBJECT (cell),
+ "icon-name", vinagre_plugin_info_get_icon_name (info),
+ "sensitive", vinagre_plugin_info_is_available (info),
+ NULL);
+}
+
+
+static void
+active_toggled_cb (GtkCellRendererToggle *cell,
+ gchar *path_str,
+ VinagrePluginManager *pm)
+{
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GtkTreeModel *model;
+
+ vinagre_debug (DEBUG_PLUGINS);
+
+ path = gtk_tree_path_new_from_string (path_str);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
+ g_return_if_fail (model != NULL);
+
+ gtk_tree_model_get_iter (model, &iter, path);
+
+ if (&iter != NULL)
+ plugin_manager_toggle_active (pm, &iter, model);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+cursor_changed_cb (GtkTreeView *view,
+ gpointer data)
+{
+ VinagrePluginManager *pm = data;
+ VinagrePluginInfo *info;
+
+ vinagre_debug (DEBUG_PLUGINS);
+
+ info = plugin_manager_get_selected_plugin (pm);
+
+ gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->about_button),
+ info != NULL);
+ gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->configure_button),
+ (info != NULL) &&
+ vinagre_plugin_info_is_configurable (info));
+}
+
+static void
+row_activated_cb (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ gpointer data)
+{
+ VinagrePluginManager *pm = data;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ vinagre_debug (DEBUG_PLUGINS);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
+
+ g_return_if_fail (model != NULL);
+
+ gtk_tree_model_get_iter (model, &iter, path);
+
+ g_return_if_fail (&iter != NULL);
+
+ plugin_manager_toggle_active (pm, &iter, model);
+}
+
+static void
+plugin_manager_populate_lists (VinagrePluginManager *pm)
+{
+ const GList *plugins;
+ GtkListStore *model;
+ GtkTreeIter iter;
+
+ vinagre_debug (DEBUG_PLUGINS);
+
+ plugins = vinagre_plugins_engine_get_plugin_list (pm->priv->engine);
+
+ model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree)));
+
+ while (plugins)
+ {
+ VinagrePluginInfo *info;
+ info = (VinagrePluginInfo *)plugins->data;
+
+ gtk_list_store_append (model, &iter);
+ gtk_list_store_set (model, &iter,
+ ACTIVE_COLUMN, vinagre_plugin_info_is_active (info),
+ AVAILABLE_COLUMN, vinagre_plugin_info_is_available (info),
+ INFO_COLUMN, info,
+ -1);
+
+ plugins = plugins->next;
+ }
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter))
+ {
+ GtkTreeSelection *selection;
+ VinagrePluginInfo* info;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
+ g_return_if_fail (selection != NULL);
+
+ gtk_tree_selection_select_iter (selection, &iter);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
+ INFO_COLUMN, &info, -1);
+
+ gtk_widget_set_sensitive (GTK_WIDGET (pm->priv->configure_button),
+ vinagre_plugin_info_is_configurable (info));
+ }
+}
+
+static gboolean
+plugin_manager_set_active (VinagrePluginManager *pm,
+ GtkTreeIter *iter,
+ GtkTreeModel *model,
+ gboolean active)
+{
+ VinagrePluginInfo *info;
+ gboolean res = TRUE;
+
+ vinagre_debug (DEBUG_PLUGINS);
+
+ gtk_tree_model_get (model, iter, INFO_COLUMN, &info, -1);
+
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ if (active)
+ {
+ /* activate the plugin */
+ if (!vinagre_plugins_engine_activate_plugin (pm->priv->engine, info)) {
+ vinagre_debug_message (DEBUG_PLUGINS, "Could not activate %s.\n",
+ vinagre_plugin_info_get_name (info));
+
+ res = FALSE;
+ }
+ }
+ else
+ {
+ /* deactivate the plugin */
+ if (!vinagre_plugins_engine_deactivate_plugin (pm->priv->engine, info)) {
+ vinagre_debug_message (DEBUG_PLUGINS, "Could not deactivate %s.\n",
+ vinagre_plugin_info_get_name (info));
+
+ res = FALSE;
+ }
+ }
+
+ return res;
+}
+
+static void
+plugin_manager_toggle_active (VinagrePluginManager *pm,
+ GtkTreeIter *iter,
+ GtkTreeModel *model)
+{
+ gboolean active;
+
+ vinagre_debug (DEBUG_PLUGINS);
+
+ gtk_tree_model_get (model, iter, ACTIVE_COLUMN, &active, -1);
+
+ active ^= 1;
+
+ plugin_manager_set_active (pm, iter, model, active);
+}
+
+static VinagrePluginInfo *
+plugin_manager_get_selected_plugin (VinagrePluginManager *pm)
+{
+ VinagrePluginInfo *info = NULL;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+
+ vinagre_debug (DEBUG_PLUGINS);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
+ g_return_val_if_fail (model != NULL, NULL);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
+ g_return_val_if_fail (selection != NULL, NULL);
+
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter))
+ {
+ gtk_tree_model_get (model, &iter, INFO_COLUMN, &info, -1);
+ }
+
+ return info;
+}
+
+static void
+plugin_manager_set_active_all (VinagrePluginManager *pm,
+ gboolean active)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ vinagre_debug (DEBUG_PLUGINS);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
+
+ g_return_if_fail (model != NULL);
+
+ gtk_tree_model_get_iter_first (model, &iter);
+
+ do {
+ plugin_manager_set_active (pm, &iter, model, active);
+ }
+ while (gtk_tree_model_iter_next (model, &iter));
+}
+
+/* Callback used as the interactive search comparison function */
+static gboolean
+name_search_cb (GtkTreeModel *model,
+ gint column,
+ const gchar *key,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ VinagrePluginInfo *info;
+ gchar *normalized_string;
+ gchar *normalized_key;
+ gchar *case_normalized_string;
+ gchar *case_normalized_key;
+ gint key_len;
+ gboolean retval;
+
+ gtk_tree_model_get (model, iter, INFO_COLUMN, &info, -1);
+ if (!info)
+ return FALSE;
+
+ normalized_string = g_utf8_normalize (vinagre_plugin_info_get_name (info), -1, G_NORMALIZE_ALL);
+ normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
+ case_normalized_string = g_utf8_casefold (normalized_string, -1);
+ case_normalized_key = g_utf8_casefold (normalized_key, -1);
+
+ key_len = strlen (case_normalized_key);
+
+ /* Oddly enough, this callback must return whether to stop the search
+ * because we found a match, not whether we actually matched.
+ */
+ retval = (strncmp (case_normalized_key, case_normalized_string, key_len) != 0);
+
+ g_free (normalized_key);
+ g_free (normalized_string);
+ g_free (case_normalized_key);
+ g_free (case_normalized_string);
+
+ return retval;
+}
+
+static void
+enable_plugin_menu_cb (GtkMenu *menu,
+ VinagrePluginManager *pm)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree));
+ g_return_if_fail (model != NULL);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
+ g_return_if_fail (selection != NULL);
+
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter))
+ plugin_manager_toggle_active (pm, &iter, model);
+}
+
+static void
+enable_all_menu_cb (GtkMenu *menu,
+ VinagrePluginManager *pm)
+{
+ plugin_manager_set_active_all (pm, TRUE);
+}
+
+static void
+disable_all_menu_cb (GtkMenu *menu,
+ VinagrePluginManager *pm)
+{
+ plugin_manager_set_active_all (pm, FALSE);
+}
+
+static GtkWidget *
+create_tree_popup_menu (VinagrePluginManager *pm)
+{
+ GtkWidget *menu;
+ GtkWidget *item;
+ GtkWidget *image;
+ VinagrePluginInfo *info;
+
+ info = plugin_manager_get_selected_plugin (pm);
+
+ menu = gtk_menu_new ();
+
+ item = gtk_image_menu_item_new_with_mnemonic (_("_About"));
+ image = gtk_image_new_from_stock (GTK_STOCK_ABOUT,
+ GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ g_signal_connect (item, "activate",
+ G_CALLBACK (about_button_cb), pm);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_image_menu_item_new_with_mnemonic (_("C_onfigure"));
+ image = gtk_image_new_from_stock (GTK_STOCK_PREFERENCES,
+ GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ g_signal_connect (item, "activate",
+ G_CALLBACK (configure_button_cb), pm);
+ gtk_widget_set_sensitive (item, vinagre_plugin_info_is_configurable (info));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_check_menu_item_new_with_mnemonic (_("A_ctivate"));
+ gtk_widget_set_sensitive (item, vinagre_plugin_info_is_available (info));
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
+ vinagre_plugin_info_is_active (info));
+ g_signal_connect (item, "toggled",
+ G_CALLBACK (enable_plugin_menu_cb), pm);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_separator_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_menu_item_new_with_mnemonic (_("Ac_tivate All"));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (enable_all_menu_cb), pm);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ item = gtk_menu_item_new_with_mnemonic (_("_Deactivate All"));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (disable_all_menu_cb), pm);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ gtk_widget_show_all (menu);
+
+ return menu;
+}
+
+static void
+tree_popup_menu_detach (VinagrePluginManager *pm,
+ GtkMenu *menu)
+{
+ pm->priv->popup_menu = NULL;
+}
+
+static void
+show_tree_popup_menu (GtkTreeView *tree,
+ VinagrePluginManager *pm,
+ GdkEventButton *event)
+{
+ if (pm->priv->popup_menu)
+ gtk_widget_destroy (pm->priv->popup_menu);
+
+ pm->priv->popup_menu = create_tree_popup_menu (pm);
+
+ gtk_menu_attach_to_widget (GTK_MENU (pm->priv->popup_menu),
+ GTK_WIDGET (pm),
+ (GtkMenuDetachFunc) tree_popup_menu_detach);
+
+ if (event != NULL)
+ {
+ gtk_menu_popup (GTK_MENU (pm->priv->popup_menu), NULL, NULL,
+ NULL, NULL,
+ event->button, event->time);
+ }
+ else
+ {/*AQUI
+ gtk_menu_popup (GTK_MENU (pm->priv->popup_menu), NULL, NULL,
+ vinagre_utils_menu_position_under_tree_view, tree,
+ 0, gtk_get_current_event_time ());
+*/
+ gtk_menu_shell_select_first (GTK_MENU_SHELL (pm->priv->popup_menu),
+ FALSE);
+ }
+}
+
+static gboolean
+button_press_event_cb (GtkWidget *tree,
+ GdkEventButton *event,
+ VinagrePluginManager *pm)
+{
+ /* We want the treeview selection to be updated before showing the menu.
+ * This code is evil, thanks to Federico Mena Quintero's black magic.
+ * See: http://mail.gnome.org/archives/gtk-devel-list/2006-February/msg00168.html
+ * FIXME: Let's remove it asap.
+ */
+
+ static gboolean in_press = FALSE;
+ gboolean handled;
+
+ if (in_press)
+ return FALSE; /* we re-entered */
+
+ if (GDK_BUTTON_PRESS != event->type || 3 != event->button)
+ return FALSE; /* let the normal handler run */
+
+ in_press = TRUE;
+ handled = gtk_widget_event (tree, (GdkEvent *) event);
+ in_press = FALSE;
+
+ if (!handled)
+ return FALSE;
+
+ /* The selection is fully updated by now */
+ show_tree_popup_menu (GTK_TREE_VIEW (tree), pm, event);
+ return TRUE;
+}
+
+static gboolean
+popup_menu_cb (GtkTreeView *tree,
+ VinagrePluginManager *pm)
+{
+ show_tree_popup_menu (tree, pm, NULL);
+ return TRUE;
+}
+
+static gint
+model_name_sort_func (GtkTreeModel *model,
+ GtkTreeIter *iter1,
+ GtkTreeIter *iter2,
+ gpointer user_data)
+{
+ VinagrePluginInfo *info1, *info2;
+
+ gtk_tree_model_get (model, iter1, INFO_COLUMN, &info1, -1);
+ gtk_tree_model_get (model, iter2, INFO_COLUMN, &info2, -1);
+
+ return g_utf8_collate (vinagre_plugin_info_get_name (info1),
+ vinagre_plugin_info_get_name (info2));
+}
+
+static void
+plugin_manager_construct_tree (VinagrePluginManager *pm)
+{
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *cell;
+ GtkListStore *model;
+
+ vinagre_debug (DEBUG_PLUGINS);
+
+ model = gtk_list_store_new (N_COLUMNS,
+ G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN,
+ G_TYPE_POINTER);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (pm->priv->tree),
+ GTK_TREE_MODEL (model));
+ g_object_unref (model);
+
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (pm->priv->tree), TRUE);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (pm->priv->tree), FALSE);
+
+ /* first column */
+ cell = gtk_cell_renderer_toggle_new ();
+ g_object_set (cell, "xpad", 6, NULL);
+ g_signal_connect (cell,
+ "toggled",
+ G_CALLBACK (active_toggled_cb),
+ pm);
+ column = gtk_tree_view_column_new_with_attributes (PLUGIN_MANAGER_ACTIVE_TITLE,
+ cell,
+ "active",
+ ACTIVE_COLUMN,
+ "activatable",
+ AVAILABLE_COLUMN,
+ "sensitive",
+ AVAILABLE_COLUMN,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (pm->priv->tree), column);
+
+ /* second column */
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, PLUGIN_MANAGER_NAME_TITLE);
+ gtk_tree_view_column_set_resizable (column, TRUE);
+
+ cell = gtk_cell_renderer_pixbuf_new ();
+ gtk_tree_view_column_pack_start (column, cell, FALSE);
+ g_object_set (cell, "stock-size", GTK_ICON_SIZE_SMALL_TOOLBAR, NULL);
+ gtk_tree_view_column_set_cell_data_func (column, cell,
+ plugin_manager_view_icon_cell_cb,
+ pm, NULL);
+
+ cell = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, cell, TRUE);
+ g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+ gtk_tree_view_column_set_cell_data_func (column, cell,
+ plugin_manager_view_info_cell_cb,
+ pm, NULL);
+
+
+ gtk_tree_view_column_set_spacing (column, 6);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (pm->priv->tree), column);
+
+ /* Sort on the plugin names */
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model),
+ model_name_sort_func,
+ NULL,
+ NULL);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+ GTK_SORT_ASCENDING);
+
+ /* Enable search for our non-string column */
+ gtk_tree_view_set_search_column (GTK_TREE_VIEW (pm->priv->tree),
+ INFO_COLUMN);
+ gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (pm->priv->tree),
+ name_search_cb,
+ NULL,
+ NULL);
+
+ g_signal_connect (pm->priv->tree,
+ "cursor_changed",
+ G_CALLBACK (cursor_changed_cb),
+ pm);
+ g_signal_connect (pm->priv->tree,
+ "row_activated",
+ G_CALLBACK (row_activated_cb),
+ pm);
+
+ g_signal_connect (pm->priv->tree,
+ "button-press-event",
+ G_CALLBACK (button_press_event_cb),
+ pm);
+ g_signal_connect (pm->priv->tree,
+ "popup-menu",
+ G_CALLBACK (popup_menu_cb),
+ pm);
+ gtk_widget_show (pm->priv->tree);
+}
+
+static void
+plugin_toggled_cb (VinagrePluginsEngine *engine,
+ VinagrePluginInfo *info,
+ VinagrePluginManager *pm)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean info_found = FALSE;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (pm->priv->tree));
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter))
+ {
+ /* There is an item selected: it's probably the one we want! */
+ VinagrePluginInfo *tinfo;
+ gtk_tree_model_get (model, &iter, INFO_COLUMN, &tinfo, -1);
+ info_found = info == tinfo;
+ }
+
+ if (!info_found)
+ {
+ gtk_tree_model_get_iter_first (model, &iter);
+
+ do
+ {
+ VinagrePluginInfo *tinfo;
+ gtk_tree_model_get (model, &iter, INFO_COLUMN, &tinfo, -1);
+ info_found = info == tinfo;
+ }
+ while (!info_found && gtk_tree_model_iter_next (model, &iter));
+ }
+
+ if (!info_found)
+ {
+ g_warning ("VinagrePluginManager: plugin '%s' not found in the tree model",
+ vinagre_plugin_info_get_name (info));
+ return;
+ }
+
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, ACTIVE_COLUMN, vinagre_plugin_info_is_active (info), -1);
+}
+
+static void
+vinagre_plugin_manager_init (VinagrePluginManager *pm)
+{
+ GtkWidget *label;
+ GtkWidget *alignment;
+ GtkWidget *viewport;
+ GtkWidget *hbuttonbox;
+ gchar *markup;
+
+ vinagre_debug (DEBUG_PLUGINS);
+
+ pm->priv = VINAGRE_PLUGIN_MANAGER_GET_PRIVATE (pm);
+
+ /*
+ * Always we create the manager, firstly we rescan the plugins directory
+ */
+ vinagre_plugins_engine_rescan_plugins (vinagre_plugins_engine_get_default ());
+
+ gtk_box_set_spacing (GTK_BOX (pm), 6);
+
+ label = gtk_label_new (NULL);
+ markup = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>",
+ _("Active plugins"));
+ gtk_label_set_markup (GTK_LABEL (label), markup);
+ g_free (markup);
+ gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+
+ gtk_box_pack_start (GTK_BOX (pm), label, FALSE, TRUE, 0);
+
+ alignment = gtk_alignment_new (0., 0., 1., 1.);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 12, 0);
+ gtk_box_pack_start (GTK_BOX (pm), alignment, TRUE, TRUE, 0);
+
+ viewport = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (viewport),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (viewport),
+ GTK_SHADOW_IN);
+
+ gtk_container_add (GTK_CONTAINER (alignment), viewport);
+
+ pm->priv->tree = gtk_tree_view_new ();
+ gtk_container_add (GTK_CONTAINER (viewport), pm->priv->tree);
+
+ hbuttonbox = gtk_hbutton_box_new ();
+ gtk_box_pack_start (GTK_BOX (pm), hbuttonbox, FALSE, FALSE, 0);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_END);
+ gtk_box_set_spacing (GTK_BOX (hbuttonbox), 8);
+
+ pm->priv->about_button = vinagre_gtk_button_new_with_stock_icon (_("_About Plugin"),
+ GTK_STOCK_ABOUT);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox), pm->priv->about_button);
+
+ pm->priv->configure_button = vinagre_gtk_button_new_with_stock_icon (_("C_onfigure Plugin"),
+ GTK_STOCK_PREFERENCES);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox), pm->priv->configure_button);
+
+ /* setup a window of a sane size. */
+ gtk_widget_set_size_request (GTK_WIDGET (viewport), 270, 100);
+
+ g_signal_connect (pm->priv->about_button,
+ "clicked",
+ G_CALLBACK (about_button_cb),
+ pm);
+ g_signal_connect (pm->priv->configure_button,
+ "clicked",
+ G_CALLBACK (configure_button_cb),
+ pm);
+
+ plugin_manager_construct_tree (pm);
+
+ /* get the plugin engine and populate the treeview */
+ pm->priv->engine = vinagre_plugins_engine_get_default ();
+
+ g_signal_connect_after (pm->priv->engine,
+ "activate-plugin",
+ G_CALLBACK (plugin_toggled_cb),
+ pm);
+ g_signal_connect_after (pm->priv->engine,
+ "deactivate-plugin",
+ G_CALLBACK (plugin_toggled_cb),
+ pm);
+
+ if (vinagre_plugins_engine_get_plugin_list (pm->priv->engine) != NULL)
+ {
+ plugin_manager_populate_lists (pm);
+ }
+ else
+ {
+ gtk_widget_set_sensitive (pm->priv->about_button, FALSE);
+ gtk_widget_set_sensitive (pm->priv->configure_button, FALSE);
+ }
+}
+
+static void
+vinagre_plugin_manager_finalize (GObject *object)
+{
+ VinagrePluginManager *pm = VINAGRE_PLUGIN_MANAGER (object);
+
+ g_signal_handlers_disconnect_by_func (pm->priv->engine,
+ plugin_toggled_cb,
+ pm);
+
+ if (pm->priv->popup_menu)
+ gtk_widget_destroy (pm->priv->popup_menu);
+
+ G_OBJECT_CLASS (vinagre_plugin_manager_parent_class)->finalize (object);
+
+}
+
+GtkWidget *vinagre_plugin_manager_new (void)
+{
+ return g_object_new (VINAGRE_TYPE_PLUGIN_MANAGER,0);
+}
diff --git a/src/vinagre-plugin-manager.h b/src/vinagre-plugin-manager.h
new file mode 100644
index 0000000..aa97d9e
--- /dev/null
+++ b/src/vinagre-plugin-manager.h
@@ -0,0 +1,74 @@
+/*
+ * vinagre-plugins-manager.h
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jorge Pereira <jorge jorgepereira com br>
+ *
+ * vinagre-plugins-manager.h is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * vinagre-plugins-manager.h is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __VINAGRE_PLUGIN_MANAGER_H__
+#define __VINAGRE_PLUGIN_MANAGER_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+/*
+ * Type checking and casting macros
+ */
+#define VINAGRE_TYPE_PLUGIN_MANAGER (vinagre_plugin_manager_get_type())
+#define VINAGRE_PLUGIN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VINAGRE_TYPE_PLUGIN_MANAGER, VinagrePluginManager))
+#define VINAGRE_PLUGIN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), VINAGRE_TYPE_PLUGIN_MANAGER, VinagrePluginManagerClass))
+#define VINAGRE_IS_PLUGIN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VINAGRE_TYPE_PLUGIN_MANAGER))
+#define VINAGRE_IS_PLUGIN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VINAGRE_TYPE_PLUGIN_MANAGER))
+#define VINAGRE_PLUGIN_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), VINAGRE_TYPE_PLUGIN_MANAGER, VinagrePluginManagerClass))
+
+/* Private structure type */
+typedef struct _VinagrePluginManagerPrivate VinagrePluginManagerPrivate;
+
+/*
+ * Main object structure
+ */
+typedef struct _VinagrePluginManager VinagrePluginManager;
+
+struct _VinagrePluginManager
+{
+ GtkVBox vbox;
+
+ /*< private > */
+ VinagrePluginManagerPrivate *priv;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _VinagrePluginManagerClass VinagrePluginManagerClass;
+
+struct _VinagrePluginManagerClass
+{
+ GtkVBoxClass parent_class;
+};
+
+/*
+ * Public methods
+ */
+GType vinagre_plugin_manager_get_type (void) G_GNUC_CONST;
+
+GtkWidget *vinagre_plugin_manager_new (void);
+
+G_END_DECLS
+
+#endif /* __VINAGRE_PLUGIN_MANAGER_H__ */
+
diff --git a/src/vinagre-plugin-prefs.c b/src/vinagre-plugin-prefs.c
new file mode 100644
index 0000000..7372979
--- /dev/null
+++ b/src/vinagre-plugin-prefs.c
@@ -0,0 +1,474 @@
+/*
+ * vinagre-plugin-prefs.c
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jorge Pereira <jorge jorgepereira com br>
+ *
+ * vinagre-plugin-prefs.c is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * vinagre-plugin-prefs.c is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gconf/gconf-client.h>
+#include <glib/gi18n.h>
+#include <glade/glade.h>
+#include "vinagre-plugin-prefs.h"
+#include "vinagre-utils.h"
+
+#define VINAGRE_BASE_KEY "/apps/vinagre"
+#define VM_ALWAYS_SHOW_TABS VINAGRE_BASE_KEY "/always_show_tabs"
+#define VM_SHARED_FLAG VINAGRE_BASE_KEY "/shared_flag"
+#define VM_TOOLBAR_VISIBLE VINAGRE_BASE_KEY "/toolbar_visible"
+#define VM_STATUSBAR_VISIBLE VINAGRE_BASE_KEY "/statusbar_visible"
+#define VM_SIDE_PANEL_VISIBLE VINAGRE_BASE_KEY "/side_pane_visible"
+#define VM_SHOW_ACCELS VINAGRE_BASE_KEY "/show_accels"
+#define VM_HISTORY_SIZE VINAGRE_BASE_KEY "/history_size"
+
+#define VM_WINDOW_STATE VINAGRE_BASE_KEY "/window_state"
+#define VM_WINDOW_WIDTH VINAGRE_BASE_KEY "/window_width"
+#define VM_WINDOW_HEIGHT VINAGRE_BASE_KEY "/window_height"
+#define VM_SIDE_PANEL_SIZE VINAGRE_BASE_KEY "/side_panel_size"
+
+struct _VinagrePluginPrefsPrivate
+{
+ GConfClient *gconf_client;
+};
+
+/* Properties */
+enum
+{
+ PROP_0,
+ PROP_SHARED_FLAG,
+ PROP_ALWAYS_SHOW_TABS,
+ PROP_TOOLBAR_VISIBLE,
+ PROP_STATUSBAR_VISIBLE,
+ PROP_SIDE_PANEL_VISIBLE,
+ PROP_WINDOW_STATE,
+ PROP_WINDOW_WIDTH,
+ PROP_WINDOW_HEIGHT,
+ PROP_SIDE_PANEL_SIZE,
+ PROP_SHOW_ACCELS,
+ PROP_HISTORY_SIZE
+};
+
+G_DEFINE_TYPE (VinagrePluginPrefs, vinagre_plugin_prefs, G_TYPE_OBJECT);
+
+static VinagrePluginPrefs *prefs_singleton = NULL;
+
+VinagrePluginPrefs *
+vinagre_plugin_prefs_get_default (void)
+{
+ if (G_UNLIKELY (!prefs_singleton))
+ prefs_singleton = VINAGRE_PLUGIN_PREFS (g_object_new (VINAGRE_TYPE_PLUGIN_PREFS,
+ NULL));
+ return prefs_singleton;
+}
+
+static gboolean
+vinagre_plugin_prefs_get_bool (VinagrePluginPrefs *prefs,
+ const gchar* key, gboolean def)
+{
+ GError* error = NULL;
+ GConfValue* val;
+
+ val = gconf_client_get (prefs->priv->gconf_client, key, &error);
+
+ if (val != NULL)
+ {
+ gboolean retval = def;
+
+ g_return_val_if_fail (error == NULL, retval);
+
+ if (val->type == GCONF_VALUE_BOOL)
+ retval = gconf_value_get_bool (val);
+
+ gconf_value_free (val);
+
+ return retval;
+ }
+ else
+ return def;
+}
+
+static gboolean
+vinagre_plugin_prefs_get_int (VinagrePluginPrefs *prefs,
+ const gchar* key, gint def)
+{
+ GError* error = NULL;
+ GConfValue* val;
+
+ val = gconf_client_get (prefs->priv->gconf_client, key, &error);
+
+ if (val != NULL)
+ {
+ gint retval = def;
+
+ g_return_val_if_fail (error == NULL, retval);
+
+ if (val->type == GCONF_VALUE_INT)
+ retval = gconf_value_get_int (val);
+
+ gconf_value_free (val);
+
+ return retval;
+ }
+ else
+ return def;
+}
+
+static void
+vinagre_plugin_prefs_set_bool (VinagrePluginPrefs *prefs, const gchar* key, gboolean value)
+{
+ g_return_if_fail (gconf_client_key_is_writable (
+ prefs->priv->gconf_client, key, NULL));
+
+ gconf_client_set_bool (prefs->priv->gconf_client, key, value, NULL);
+}
+
+static void
+vinagre_plugin_prefs_set_int (VinagrePluginPrefs *prefs, const gchar* key, gint value)
+{
+ g_return_if_fail (gconf_client_key_is_writable (
+ prefs->priv->gconf_client, key, NULL));
+
+ gconf_client_set_int (prefs->priv->gconf_client, key, value, NULL);
+}
+
+static void
+vinagre_plugin_prefs_always_show_tabs_notify (GConfClient *client,
+ guint cnx_id,
+ GConfEntry *entry,
+ VinagrePluginPrefs *prefs)
+{
+ g_object_notify (G_OBJECT (prefs), "always-show-tabs");
+}
+
+static void
+vinagre_plugin_prefs_show_accels_notify (GConfClient *client,
+ guint cnx_id,
+ GConfEntry *entry,
+ VinagrePluginPrefs *prefs)
+{
+ g_object_notify (G_OBJECT (prefs), "show-accels");
+}
+
+static void
+vinagre_plugin_prefs_init (VinagrePluginPrefs *prefs)
+{
+ prefs->priv = G_TYPE_INSTANCE_GET_PRIVATE (prefs, VINAGRE_TYPE_PLUGIN_PREFS, VinagrePluginPrefsPrivate);
+
+ prefs->priv->gconf_client = gconf_client_get_default ();
+ if (prefs->priv->gconf_client == NULL)
+ g_critical (_("Cannot initialize preferences manager."));
+
+ gconf_client_add_dir (prefs->priv->gconf_client,
+ VINAGRE_BASE_KEY,
+ GCONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+
+ gconf_client_notify_add (prefs->priv->gconf_client,
+ VM_ALWAYS_SHOW_TABS,
+ (GConfClientNotifyFunc) vinagre_plugin_prefs_always_show_tabs_notify,
+ prefs, NULL, NULL);
+ gconf_client_notify_add (prefs->priv->gconf_client,
+ VM_SHOW_ACCELS,
+ (GConfClientNotifyFunc) vinagre_plugin_prefs_show_accels_notify,
+ prefs, NULL, NULL);
+
+}
+
+static void
+vinagre_plugin_prefs_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ VinagrePluginPrefs *prefs = VINAGRE_PLUGIN_PREFS (object);
+
+ switch (prop_id)
+ {
+ case PROP_SHARED_FLAG:
+ vinagre_plugin_prefs_set_bool (prefs, VM_SHARED_FLAG, g_value_get_boolean (value));
+ break;
+ case PROP_ALWAYS_SHOW_TABS:
+ vinagre_plugin_prefs_set_bool (prefs, VM_ALWAYS_SHOW_TABS, g_value_get_boolean (value));
+ break;
+ case PROP_TOOLBAR_VISIBLE:
+ vinagre_plugin_prefs_set_bool (prefs, VM_TOOLBAR_VISIBLE, g_value_get_boolean (value));
+ break;
+ case PROP_STATUSBAR_VISIBLE:
+ vinagre_plugin_prefs_set_bool (prefs, VM_STATUSBAR_VISIBLE, g_value_get_boolean (value));
+ break;
+ case PROP_SIDE_PANEL_VISIBLE:
+ vinagre_plugin_prefs_set_bool (prefs, VM_SIDE_PANEL_VISIBLE, g_value_get_boolean (value));
+ break;
+ case PROP_WINDOW_STATE:
+ vinagre_plugin_prefs_set_int (prefs, VM_WINDOW_STATE, g_value_get_int (value));
+ break;
+ case PROP_WINDOW_WIDTH:
+ vinagre_plugin_prefs_set_int (prefs, VM_WINDOW_WIDTH, g_value_get_int (value));
+ break;
+ case PROP_WINDOW_HEIGHT:
+ vinagre_plugin_prefs_set_int (prefs, VM_WINDOW_HEIGHT, g_value_get_int (value));
+ break;
+ case PROP_SIDE_PANEL_SIZE:
+ vinagre_plugin_prefs_set_int (prefs, VM_SIDE_PANEL_SIZE, g_value_get_int (value));
+ break;
+ case PROP_SHOW_ACCELS:
+ vinagre_plugin_prefs_set_bool (prefs, VM_SHOW_ACCELS, g_value_get_boolean (value));
+ break;
+ case PROP_HISTORY_SIZE:
+ vinagre_plugin_prefs_set_int (prefs, VM_HISTORY_SIZE, g_value_get_int (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+vinagre_plugin_prefs_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ VinagrePluginPrefs *prefs = VINAGRE_PLUGIN_PREFS (object);
+
+ switch (prop_id)
+ {
+ case PROP_SHARED_FLAG:
+ g_value_set_boolean (value, vinagre_plugin_prefs_get_bool (prefs, VM_SHARED_FLAG, TRUE));
+ break;
+ case PROP_ALWAYS_SHOW_TABS:
+ g_value_set_boolean (value, vinagre_plugin_prefs_get_bool (prefs, VM_ALWAYS_SHOW_TABS, FALSE));
+ break;
+ case PROP_TOOLBAR_VISIBLE:
+ g_value_set_boolean (value, vinagre_plugin_prefs_get_bool (prefs, VM_TOOLBAR_VISIBLE, TRUE));
+ break;
+ case PROP_STATUSBAR_VISIBLE:
+ g_value_set_boolean (value, vinagre_plugin_prefs_get_bool (prefs, VM_STATUSBAR_VISIBLE, TRUE));
+ break;
+ case PROP_SIDE_PANEL_VISIBLE:
+ g_value_set_boolean (value, vinagre_plugin_prefs_get_bool (prefs, VM_SIDE_PANEL_VISIBLE, TRUE));
+ break;
+ case PROP_WINDOW_STATE:
+ g_value_set_int (value, vinagre_plugin_prefs_get_int (prefs, VM_WINDOW_STATE, 0));
+ break;
+ case PROP_WINDOW_WIDTH:
+ g_value_set_int (value, vinagre_plugin_prefs_get_int (prefs, VM_WINDOW_WIDTH, 650));
+ break;
+ case PROP_WINDOW_HEIGHT:
+ g_value_set_int (value, vinagre_plugin_prefs_get_int (prefs, VM_WINDOW_HEIGHT, 500));
+ break;
+ case PROP_SIDE_PANEL_SIZE:
+ g_value_set_int (value, vinagre_plugin_prefs_get_int (prefs, VM_SIDE_PANEL_SIZE, 200));
+ break;
+ case PROP_SHOW_ACCELS:
+ g_value_set_boolean (value, vinagre_plugin_prefs_get_bool (prefs, VM_SHOW_ACCELS, TRUE));
+ break;
+ case PROP_HISTORY_SIZE:
+ g_value_set_int (value, vinagre_plugin_prefs_get_int (prefs, VM_HISTORY_SIZE, 15));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+vinagre_plugin_prefs_dispose (GObject *object)
+{
+ VinagrePluginPrefs *prefs = VINAGRE_PLUGIN_PREFS (object);
+
+ if (prefs->priv->gconf_client)
+ {
+ gconf_client_remove_dir (prefs->priv->gconf_client,
+ VINAGRE_BASE_KEY,
+ NULL);
+ g_object_unref (prefs->priv->gconf_client);
+ prefs->priv->gconf_client = NULL;
+ }
+
+ G_OBJECT_CLASS (vinagre_plugin_prefs_parent_class)->dispose (object);
+}
+
+
+static void
+vinagre_plugin_prefs_class_init (VinagrePluginPrefsClass *klass)
+{
+ GObjectClass* object_class = G_OBJECT_CLASS (klass);
+ GObjectClass* parent_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (VinagrePluginPrefsPrivate));
+
+ object_class->dispose = vinagre_plugin_prefs_dispose;
+ object_class->set_property = vinagre_plugin_prefs_set_property;
+ object_class->get_property = vinagre_plugin_prefs_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_SHARED_FLAG,
+ g_param_spec_boolean ("shared-flag",
+ "Shared Flag",
+ "Whether we should share the remote connection",
+ TRUE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_ALWAYS_SHOW_TABS,
+ g_param_spec_boolean ("always-show-tabs",
+ "Always show tabs",
+ "Whether we should show the tabs even when there is ony one active connection",
+ FALSE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_TOOLBAR_VISIBLE,
+ g_param_spec_boolean ("toolbar-visible",
+ "Toolbar Visibility",
+ "Whether the toolbar is visible",
+ TRUE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_STATUSBAR_VISIBLE,
+ g_param_spec_boolean ("statusbar-visible",
+ "Statusbar Visibility",
+ "Whether the statusbar is visible",
+ TRUE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_SIDE_PANEL_VISIBLE,
+ g_param_spec_boolean ("side-panel-visible",
+ "Side Panel Visibility",
+ "Whether the side panel is visible",
+ TRUE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_WINDOW_STATE,
+ g_param_spec_int ("window-state",
+ "Window State",
+ "Whether the window is maximised",
+ G_MININT, G_MAXINT, 0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_WINDOW_WIDTH,
+ g_param_spec_int ("window-width",
+ "Window Width",
+ "The width of window",
+ 100, G_MAXINT, 650,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_WINDOW_HEIGHT,
+ g_param_spec_int ("window-height",
+ "Window Height",
+ "The height of window",
+ 100, G_MAXINT, 500,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_SIDE_PANEL_SIZE,
+ g_param_spec_int ("side-panel-size",
+ "Side Panel Width",
+ "The width of side panel",
+ 100, G_MAXINT, 200,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_SHOW_ACCELS,
+ g_param_spec_boolean ("show-accels",
+ "Show menu accelerators",
+ "Whether we should show the menu accelerators (keyboard shortcuts)",
+ FALSE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_HISTORY_SIZE,
+ g_param_spec_int ("history-size",
+ "History size",
+ "Max number of items in history dropdown entry",
+ 0, G_MAXINT, 15,
+ G_PARAM_READWRITE));
+
+}
+
+/* Preferences dialog */
+
+typedef struct {
+ GladeXML *xml;
+ GtkWidget *dialog;
+ GtkWidget *show_tabs;
+ GtkWidget *show_accels;
+} VinagrePluginPrefsDialog;
+
+static void
+vinagre_plugin_prefs_dialog_setup (VinagrePluginPrefsDialog *dialog)
+{
+ gboolean show_accels, show_tabs;
+
+ g_object_get (vinagre_plugin_prefs_get_default (),
+ "show-accels", &show_accels,
+ "always-show-tabs", &show_tabs,
+ NULL);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->show_accels), show_accels);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->show_tabs), show_tabs);
+}
+
+static void
+vinagre_plugin_prefs_dialog_quit (VinagrePluginPrefsDialog *dialog)
+{
+ gtk_widget_destroy (dialog->dialog);
+ g_object_unref (dialog->xml);
+ g_free (dialog);
+ dialog = NULL;
+}
+
+static void
+vinagre_plugin_prefs_dialog_show_tabs_cb (VinagrePluginPrefsDialog *dialog)
+{
+ g_object_set (vinagre_plugin_prefs_get_default (),
+ "always-show-tabs", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->show_tabs)),
+ NULL);
+}
+
+static void
+vinagre_plugin_prefs_dialog_show_accels_cb (VinagrePluginPrefsDialog *dialog)
+{
+ g_object_set (vinagre_plugin_prefs_get_default (),
+ "show-accels", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->show_accels)),
+ NULL);
+}
+
+void
+vinagre_plugin_prefs_dialog_show (VinagreWindow *window)
+{
+ VinagrePluginPrefsDialog *dialog;
+
+#if 0
+ dialog = g_new (VinagrePluginPrefsDialog, 1);
+
+ dialog->xml = glade_xml_new (vinagre_utils_get_glade_filename (), NULL, NULL);
+ dialog->dialog = glade_xml_get_widget (dialog->xml, "preferences_dialog");
+ gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog), GTK_WINDOW (window));
+
+ dialog->show_tabs = glade_xml_get_widget (dialog->xml, "always_show_tabs_check");
+ dialog->show_accels = glade_xml_get_widget (dialog->xml, "show_accels_check");
+
+ vinagre_plugin_prefs_dialog_setup (dialog);
+
+ g_signal_connect_swapped (dialog->dialog,
+ "response",
+ G_CALLBACK (vinagre_plugin_prefs_dialog_quit),
+ dialog);
+
+ g_signal_connect_swapped (dialog->show_tabs,
+ "toggled",
+ G_CALLBACK (vinagre_plugin_prefs_dialog_show_tabs_cb),
+ dialog);
+
+ g_signal_connect_swapped (dialog->show_accels,
+ "toggled",
+ G_CALLBACK (vinagre_plugin_prefs_dialog_show_accels_cb),
+ dialog);
+
+ gtk_widget_show_all (dialog->dialog);
+#endif
+}
+/* vim: set ts=8: */
diff --git a/src/vinagre-plugin-prefs.h b/src/vinagre-plugin-prefs.h
new file mode 100644
index 0000000..8f9c6e8
--- /dev/null
+++ b/src/vinagre-plugin-prefs.h
@@ -0,0 +1,59 @@
+/*
+ * vinagre-plugin-prefs.h
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jorge Pereira <jorge jorgepereira com br>
+ *
+ * vinagre-plugin-prefs.h is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * vinagre-plugin-prefs.h is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _VINAGRE_PLUGIN_PREFS_H_
+#define _VINAGRE_PLUGIN_PREFS_H_
+
+#include <glib-object.h>
+#include "vinagre-window.h"
+
+G_BEGIN_DECLS
+
+#define VINAGRE_TYPE_PLUGIN_PREFS (vinagre_plugin_prefs_get_type ())
+#define VINAGRE_PLUGIN_PREFS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VINAGRE_TYPE_PLUGIN_PREFS, VinagrePluginPrefs))
+#define VINAGRE_PLUGIN_PREFS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VINAGRE_TYPE_PLUGIN_PREFS, VinagrePluginPrefsClass))
+#define VINAGRE_IS_PLUGIN_PREFS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VINAGRE_TYPE_PLUGIN_PREFS))
+#define VINAGRE_IS_PLUGIN_PREFS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VINAGRE_TYPE_PLUGIN_PREFS))
+#define VINAGRE_PLUGIN_PREFS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VINAGRE_TYPE_PLUGIN_PREFS, VinagrePluginPrefsClass))
+
+typedef struct _VinagrePluginPrefsClass VinagrePluginPrefsClass;
+typedef struct _VinagrePluginPrefs VinagrePluginPrefs;
+typedef struct _VinagrePluginPrefsPrivate VinagrePluginPrefsPrivate;
+
+struct _VinagrePluginPrefsClass
+{
+ GObjectClass parent_class;
+};
+
+struct _VinagrePluginPrefs
+{
+ GObject parent_instance;
+ VinagrePluginPrefsPrivate *priv;
+};
+
+GType vinagre_plugin_prefs_get_type (void) G_GNUC_CONST;
+
+VinagrePluginPrefs *vinagre_plugin_prefs_get_default (void);
+
+void vinagre_plugin_prefs_dialog_show (VinagreWindow *window);
+G_END_DECLS
+
+#endif /* _VINAGRE_PLUGIN_PREFS_H_ */
+/* vim: set ts=8: */
diff --git a/src/vinagre-plugin.c b/src/vinagre-plugin.c
new file mode 100644
index 0000000..426afd5
--- /dev/null
+++ b/src/vinagre-plugin.c
@@ -0,0 +1,324 @@
+/*
+ * vinagre-plugin.c
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jorge Pereira <jorge jorgepereira com br>
+ *
+ * vinagre-plugin.c is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * vinagre-plugin.c is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "vinagre-plugin.h"
+#include "vinagre-dirs.h"
+
+/* properties */
+enum {
+ PROP_0,
+ PROP_INSTALL_DIR,
+ PROP_DATA_DIR_NAME,
+ PROP_DATA_DIR
+};
+
+typedef struct _VinagrePluginPrivate VinagrePluginPrivate;
+
+struct _VinagrePluginPrivate
+{
+ gchar *install_dir;
+ gchar *data_dir_name;
+};
+
+#define VINAGRE_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), VINAGRE_TYPE_PLUGIN, VinagrePluginPrivate))
+
+G_DEFINE_TYPE(VinagrePlugin, vinagre_plugin, G_TYPE_OBJECT)
+
+static void
+dummy (VinagrePlugin *plugin, VinagreWindow *window)
+{
+ /* Empty */
+}
+
+static GtkWidget *
+create_configure_dialog (VinagrePlugin *plugin)
+{
+ return NULL;
+}
+
+static gboolean
+is_configurable (VinagrePlugin *plugin)
+{
+ return (VINAGRE_PLUGIN_GET_CLASS (plugin)->create_configure_dialog !=
+ create_configure_dialog);
+}
+
+static void
+vinagre_plugin_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ case PROP_INSTALL_DIR:
+ g_value_take_string (value, vinagre_plugin_get_install_dir (VINAGRE_PLUGIN (object)));
+ break;
+ case PROP_DATA_DIR:
+ g_value_take_string (value, vinagre_plugin_get_data_dir (VINAGRE_PLUGIN (object)));
+ break;
+ default:
+ g_return_if_reached ();
+ }
+}
+
+static void
+vinagre_plugin_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ VinagrePluginPrivate *priv = VINAGRE_PLUGIN_GET_PRIVATE (object);
+
+ switch (prop_id)
+ {
+ case PROP_INSTALL_DIR:
+ priv->install_dir = g_value_dup_string (value);
+ break;
+ case PROP_DATA_DIR_NAME:
+ priv->data_dir_name = g_value_dup_string (value);
+ break;
+ default:
+ g_return_if_reached ();
+ }
+}
+
+static void
+vinagre_plugin_finalize (GObject *object)
+{
+ VinagrePluginPrivate *priv = VINAGRE_PLUGIN_GET_PRIVATE (object);
+
+ g_free (priv->install_dir);
+ g_free (priv->data_dir_name);
+
+ G_OBJECT_CLASS (vinagre_plugin_parent_class)->finalize (object);
+}
+
+static void
+vinagre_plugin_class_init (VinagrePluginClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ klass->activate = dummy;
+ klass->deactivate = dummy;
+ klass->update_ui = dummy;
+
+ klass->create_configure_dialog = create_configure_dialog;
+ klass->is_configurable = is_configurable;
+
+ object_class->get_property = vinagre_plugin_get_property;
+ object_class->set_property = vinagre_plugin_set_property;
+ object_class->finalize = vinagre_plugin_finalize;
+
+ g_object_class_install_property (object_class,
+ PROP_INSTALL_DIR,
+ g_param_spec_string ("install-dir",
+ "Install Directory",
+ "The directory where the plugin is installed",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ /* the basename of the data dir is set at construction time by the plugin loader
+ * while the full path is constructed on the fly to take into account relocability
+ * that's why we have a writeonly prop and a readonly prop */
+ g_object_class_install_property (object_class,
+ PROP_DATA_DIR_NAME,
+ g_param_spec_string ("data-dir-name",
+ "Basename of the data directory",
+ "The basename of the directory where the plugin should look for its data files",
+ NULL,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_DATA_DIR,
+ g_param_spec_string ("data-dir",
+ "Data Directory",
+ "The full path of the directory where the plugin should look for its data files",
+ NULL,
+ G_PARAM_READABLE));
+
+ g_type_class_add_private (klass, sizeof (VinagrePluginPrivate));
+}
+
+static void
+vinagre_plugin_init (VinagrePlugin *plugin)
+{
+ /* Empty */
+}
+
+/**
+ * vinagre_plugin_get_install_dir:
+ * @plugin: a #VinagrePlugin
+ *
+ * Get the path of the directory where the plugin is installed.
+ *
+ * Return value: a newly allocated string with the path of the
+ * directory where the plugin is installed
+ */
+gchar *
+vinagre_plugin_get_install_dir (VinagrePlugin *plugin)
+{
+ g_return_val_if_fail (VINAGRE_IS_PLUGIN (plugin), NULL);
+
+ return g_strdup (VINAGRE_PLUGIN_GET_PRIVATE (plugin)->install_dir);
+}
+
+/**
+ * vinagre_plugin_get_data_dir:
+ * @plugin: a #VinagrePlugin
+ *
+ * Get the path of the directory where the plugin should look for
+ * its data files.
+ *
+ * Return value: a newly allocated string with the path of the
+ * directory where the plugin should look for its data files
+ */
+gchar *
+vinagre_plugin_get_data_dir (VinagrePlugin *plugin)
+{
+ VinagrePluginPrivate *priv;
+ gchar *vinagre_lib_dir;
+ gchar *data_dir;
+
+ g_return_val_if_fail (VINAGRE_IS_PLUGIN (plugin), NULL);
+
+ priv = VINAGRE_PLUGIN_GET_PRIVATE (plugin);
+
+ /* If it's a "user" plugin the data dir is
+ * install_dir/data_dir_name if instead it's a
+ * "system" plugin the data dir is under vinagre_data_dir,
+ * so it's under $prefix/share/vinagre-2/plugins/data_dir_name
+ * where data_dir_name usually it's the name of the plugin
+ */
+// vinagre_lib_dir = vinagre_dirs_get_vinagre_lib_dir ();
+
+ /* CHECK: is checking the prefix enough or should we be more
+ * careful about normalizing paths etc? */
+ if (g_str_has_prefix (priv->install_dir, vinagre_lib_dir))
+ {
+ gchar *vinagre_data_dir;
+
+// vinagre_data_dir = vinagre_dirs_get_vinagre_data_dir ();
+
+ data_dir = g_build_filename (vinagre_data_dir,
+ "plugins",
+ priv->data_dir_name,
+ NULL);
+
+ g_free (vinagre_data_dir);
+ }
+ else
+ {
+ data_dir = g_build_filename (priv->install_dir,
+ priv->data_dir_name,
+ NULL);
+ }
+
+ g_free (vinagre_lib_dir);
+
+ return data_dir;
+}
+
+/**
+ * vinagre_plugin_activate:
+ * @plugin: a #VinagrePlugin
+ * @window: a #VinagreWindow
+ *
+ * Activates the plugin.
+ */
+void
+vinagre_plugin_activate (VinagrePlugin *plugin,
+ VinagreWindow *window)
+{
+ g_return_if_fail (VINAGRE_IS_PLUGIN (plugin));
+ g_return_if_fail (VINAGRE_IS_WINDOW (window));
+
+ VINAGRE_PLUGIN_GET_CLASS (plugin)->activate (plugin, window);
+}
+
+/**
+ * vinagre_plugin_deactivate:
+ * @plugin: a #VinagrePlugin
+ * @window: a #VinagreWindow
+ *
+ * Deactivates the plugin.
+ */
+void
+vinagre_plugin_deactivate (VinagrePlugin *plugin,
+ VinagreWindow *window)
+{
+ g_return_if_fail (VINAGRE_IS_PLUGIN (plugin));
+ g_return_if_fail (VINAGRE_IS_WINDOW (window));
+
+ VINAGRE_PLUGIN_GET_CLASS (plugin)->deactivate (plugin, window);
+}
+
+/**
+ * vinagre_plugin_update_ui:
+ * @plugin: a #VinagrePlugin
+ * @window: a #VinagreWindow
+ *
+ * Triggers an update of the user interface to take into account state changes
+ * caused by the plugin.
+ */
+void
+vinagre_plugin_update_ui (VinagrePlugin *plugin,
+ VinagreWindow *window)
+{
+ g_return_if_fail (VINAGRE_IS_PLUGIN (plugin));
+ g_return_if_fail (VINAGRE_IS_WINDOW (window));
+
+ VINAGRE_PLUGIN_GET_CLASS (plugin)->update_ui (plugin, window);
+}
+
+/**
+ * vinagre_plugin_is_configurable:
+ * @plugin: a #VinagrePlugin
+ *
+ * Whether the plugin is configurable.
+ *
+ * Returns: TRUE if the plugin is configurable:
+ */
+gboolean
+vinagre_plugin_is_configurable (VinagrePlugin *plugin)
+{
+ g_return_val_if_fail (VINAGRE_IS_PLUGIN (plugin), FALSE);
+
+ return VINAGRE_PLUGIN_GET_CLASS (plugin)->is_configurable (plugin);
+}
+
+/**
+ * vinagre_plugin_create_configure_dialog:
+ * @plugin: a #VinagrePlugin
+ *
+ * Creates the configure dialog widget for the plugin.
+ *
+ * Returns: the configure dialog widget for the plugin.
+ */
+GtkWidget *
+vinagre_plugin_create_configure_dialog (VinagrePlugin *plugin)
+{
+ g_return_val_if_fail (VINAGRE_IS_PLUGIN (plugin), NULL);
+
+ return VINAGRE_PLUGIN_GET_CLASS (plugin)->create_configure_dialog (plugin);
+}
diff --git a/src/vinagre-plugins-engine.c b/src/vinagre-plugins-engine.c
new file mode 100644
index 0000000..dc10499
--- /dev/null
+++ b/src/vinagre-plugins-engine.c
@@ -0,0 +1,847 @@
+/*
+ * vinagre-plugins-engine.c
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jorge Pereira <jorge jorgepereira com br>
+ *
+ * vinagre-plugins-engine.c is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * vinagre-plugins-engine.c is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+
+#include "vinagre-plugins-engine.h"
+#include "vinagre-plugin-info-priv.h"
+#include "vinagre-plugin.h"
+#include "vinagre-debug.h"
+#include "vinagre-app.h"
+#include "vinagre-prefs-manager.h"
+#include "vinagre-plugin-loader.h"
+#include "vinagre-object-module.h"
+#include "vinagre-dirs.h"
+
+#define VINAGRE_PLUGINS_ENGINE_BASE_KEY "/apps/vinagre-2/plugins"
+#define VINAGRE_PLUGINS_ENGINE_KEY VINAGRE_PLUGINS_ENGINE_BASE_KEY "/active-plugins"
+
+#define PLUGIN_EXT ".vinagre-plugin"
+#define LOADER_EXT G_MODULE_SUFFIX
+
+typedef struct
+{
+ VinagrePluginLoader *loader;
+ VinagreObjectModule *module;
+} LoaderInfo;
+
+/* Signals */
+enum
+{
+ ACTIVATE_PLUGIN,
+ DEACTIVATE_PLUGIN,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE(VinagrePluginsEngine, vinagre_plugins_engine, G_TYPE_OBJECT)
+
+struct _VinagrePluginsEnginePrivate
+{
+ GList *plugin_list;
+ GHashTable *loaders;
+
+ gboolean activate_from_prefs;
+};
+
+VinagrePluginsEngine *default_engine = NULL;
+
+static void vinagre_plugins_engine_activate_plugin_real (VinagrePluginsEngine *engine,
+ VinagrePluginInfo *info);
+static void vinagre_plugins_engine_deactivate_plugin_real (VinagrePluginsEngine *engine,
+ VinagrePluginInfo *info);
+
+typedef gboolean (*LoadDirCallback)(VinagrePluginsEngine *engine, const gchar *filename, gpointer userdata);
+
+static gboolean
+load_dir_real (VinagrePluginsEngine *engine,
+ const gchar *dir,
+ const gchar *suffix,
+ LoadDirCallback callback,
+ gpointer userdata)
+{
+ GError *error = NULL;
+ GDir *d;
+ const gchar *dirent;
+ gboolean ret = TRUE;
+
+ g_return_val_if_fail (dir != NULL, TRUE);
+
+ gedit_debug_message (DEBUG_PLUGINS, "DIR: %s", dir);
+
+ d = g_dir_open (dir, 0, &error);
+ if (!d)
+ {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ return TRUE;
+ }
+
+ while ((dirent = g_dir_read_name (d)))
+ {
+ gchar *filename;
+
+ if (!g_str_has_suffix (dirent, suffix))
+ continue;
+
+ filename = g_build_filename (dir, dirent, NULL);
+
+ ret = callback (engine, filename, userdata);
+
+ g_free (filename);
+
+ if (!ret)
+ break;
+ }
+
+ g_dir_close (d);
+ return ret;
+}
+
+static gboolean
+load_plugin_info (VinagrePluginsEngine *engine,
+ const gchar *filename,
+ gpointer userdata)
+{
+ VinagrePluginInfo *info;
+
+ info = _gedit_plugin_info_new (filename);
+
+ if (info == NULL)
+ return TRUE;
+
+ /* If a plugin with this name has already been loaded
+ * drop this one (user plugins override system plugins) */
+ if (vinagre_plugins_engine_get_plugin_info (engine, gedit_plugin_info_get_module_name (info)) != NULL)
+ {
+ gedit_debug_message (DEBUG_PLUGINS, "Two or more plugins named '%s'. "
+ "Only the first will be considered.\n",
+ gedit_plugin_info_get_module_name (info));
+
+ _gedit_plugin_info_unref (info);
+
+ return TRUE;
+ }
+
+ engine->priv->plugin_list = g_list_prepend (engine->priv->plugin_list, info);
+
+ gedit_debug_message (DEBUG_PLUGINS, "Plugin %s loaded", info->name);
+ return TRUE;
+}
+
+static void
+load_all_plugins (VinagrePluginsEngine *engine)
+{
+ gchar *plugin_dir;
+ const gchar *pdirs_env = NULL;
+
+ /* load user plugins */
+ plugin_dir = gedit_dirs_get_user_plugins_dir ();
+ if (g_file_test (plugin_dir, G_FILE_TEST_IS_DIR))
+ {
+ load_dir_real (engine,
+ plugin_dir,
+ PLUGIN_EXT,
+ load_plugin_info,
+ NULL);
+
+ }
+ g_free (plugin_dir);
+
+ /* load system plugins */
+ pdirs_env = g_getenv ("VINAGRE_PLUGINS_PATH");
+
+ gedit_debug_message (DEBUG_PLUGINS, "VINAGRE_PLUGINS_PATH=%s", pdirs_env);
+
+ if (pdirs_env != NULL)
+ {
+ gchar **pdirs;
+ gint i;
+
+ pdirs = g_strsplit (pdirs_env, G_SEARCHPATH_SEPARATOR_S, 0);
+
+ for (i = 0; pdirs[i] != NULL; i++)
+ {
+ if (!load_dir_real (engine,
+ pdirs[i],
+ PLUGIN_EXT,
+ load_plugin_info,
+ NULL))
+ {
+ break;
+ }
+ }
+
+ g_strfreev (pdirs);
+ }
+ else
+ {
+ plugin_dir = gedit_dirs_get_vinagre_plugins_dir ();
+
+ load_dir_real (engine,
+ plugin_dir,
+ PLUGIN_EXT,
+ load_plugin_info,
+ NULL);
+
+ g_free (plugin_dir);
+ }
+}
+
+static guint
+hash_lowercase (gconstpointer data)
+{
+ gchar *lowercase;
+ guint ret;
+
+ lowercase = g_ascii_strdown ((const gchar *)data, -1);
+ ret = g_str_hash (lowercase);
+ g_free (lowercase);
+
+ return ret;
+}
+
+static gboolean
+equal_lowercase (gconstpointer a, gconstpointer b)
+{
+ return g_ascii_strcasecmp ((const gchar *)a, (const gchar *)b) == 0;
+}
+
+static void
+loader_destroy (LoaderInfo *info)
+{
+ if (!info)
+ return;
+
+ if (info->loader)
+ g_object_unref (info->loader);
+
+ g_free (info);
+}
+
+static void
+add_loader (VinagrePluginsEngine *engine,
+ const gchar *loader_id,
+ VinagreObjectModule *module)
+{
+ LoaderInfo *info;
+
+ info = g_new (LoaderInfo, 1);
+ info->loader = NULL;
+ info->module = module;
+
+ g_hash_table_insert (engine->priv->loaders, g_strdup (loader_id), info);
+}
+
+static void
+vinagre_plugins_engine_init (VinagrePluginsEngine *engine)
+{
+ gedit_debug (DEBUG_PLUGINS);
+
+ if (!g_module_supported ())
+ {
+ g_warning ("gedit is not able to initialize the plugins engine.");
+ return;
+ }
+
+ engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine,
+ VINAGRE_TYPE_PLUGINS_ENGINE,
+ VinagrePluginsEnginePrivate);
+
+ load_all_plugins (engine);
+
+ /* make sure that the first reactivation will read active plugins
+ from the prefs */
+ engine->priv->activate_from_prefs = TRUE;
+
+ /* mapping from loadername -> loader object */
+ engine->priv->loaders = g_hash_table_new_full (hash_lowercase,
+ equal_lowercase,
+ (GDestroyNotify)g_free,
+ (GDestroyNotify)loader_destroy);
+}
+
+static void
+loader_garbage_collect (const char *id,
+ LoaderInfo *info)
+{
+ if (info->loader)
+ gedit_plugin_loader_garbage_collect (info->loader);
+}
+
+void
+vinagre_plugins_engine_garbage_collect (VinagrePluginsEngine *engine)
+{
+ g_hash_table_foreach (engine->priv->loaders,
+ (GHFunc) loader_garbage_collect,
+ NULL);
+}
+
+static void
+vinagre_plugins_engine_finalize (GObject *object)
+{
+ VinagrePluginsEngine *engine = VINAGRE_PLUGINS_ENGINE (object);
+ GList *item;
+
+ gedit_debug (DEBUG_PLUGINS);
+
+ /* Firs deactivate all plugins */
+ for (item = engine->priv->plugin_list; item; item = item->next)
+ {
+ VinagrePluginInfo *info = VINAGRE_PLUGIN_INFO (item->data);
+
+ if (gedit_plugin_info_is_active (info))
+ vinagre_plugins_engine_deactivate_plugin_real (engine, info);
+ }
+
+ /* unref the loaders */
+ g_hash_table_destroy (engine->priv->loaders);
+
+ /* and finally free the infos */
+ for (item = engine->priv->plugin_list; item; item = item->next)
+ {
+ VinagrePluginInfo *info = VINAGRE_PLUGIN_INFO (item->data);
+
+ _gedit_plugin_info_unref (info);
+ }
+
+ g_list_free (engine->priv->plugin_list);
+
+ G_OBJECT_CLASS (vinagre_plugins_engine_parent_class)->finalize (object);
+}
+
+static void
+vinagre_plugins_engine_class_init (VinagrePluginsEngineClass *klass)
+{
+ GType the_type = G_TYPE_FROM_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = vinagre_plugins_engine_finalize;
+ klass->activate_plugin = vinagre_plugins_engine_activate_plugin_real;
+ klass->deactivate_plugin = vinagre_plugins_engine_deactivate_plugin_real;
+
+ signals[ACTIVATE_PLUGIN] =
+ g_signal_new ("activate-plugin",
+ the_type,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (VinagrePluginsEngineClass, activate_plugin),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE,
+ 1,
+ VINAGRE_TYPE_PLUGIN_INFO | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+ signals[DEACTIVATE_PLUGIN] =
+ g_signal_new ("deactivate-plugin",
+ the_type,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (VinagrePluginsEngineClass, deactivate_plugin),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE,
+ 1,
+ VINAGRE_TYPE_PLUGIN_INFO | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+ g_type_class_add_private (klass, sizeof (VinagrePluginsEnginePrivate));
+}
+
+static gboolean
+load_loader (VinagrePluginsEngine *engine,
+ const gchar *filename,
+ gpointer data)
+{
+ VinagreObjectModule *module;
+ gchar *base;
+ gchar *path;
+ const gchar *id;
+ GType type;
+
+ /* try to load in the module */
+ path = g_path_get_dirname (filename);
+ base = g_path_get_basename (filename);
+
+ /* for now they are all resident */
+ module = gedit_object_module_new (base,
+ path,
+ "register_gedit_plugin_loader",
+ TRUE);
+
+ g_free (base);
+ g_free (path);
+
+ /* make sure to load the type definition */
+ if (!g_type_module_use (G_TYPE_MODULE (module)))
+ {
+ g_object_unref (module);
+ g_warning ("Plugin loader module `%s' could not be loaded", filename);
+
+ return TRUE;
+ }
+
+ /* get the exported type and check the name as exported by the
+ * loader interface */
+ type = gedit_object_module_get_object_type (module);
+ id = gedit_plugin_loader_type_get_id (type);
+
+ add_loader (engine, id, module);
+ g_type_module_unuse (G_TYPE_MODULE (module));
+
+ return TRUE;
+}
+
+static void
+ensure_loader (LoaderInfo *info)
+{
+ if (info->loader == NULL && info->module != NULL)
+ {
+ /* create a new loader object */
+ VinagrePluginLoader *loader;
+ loader = (VinagrePluginLoader *)gedit_object_module_new_object (info->module, NULL);
+
+ if (loader == NULL || !VINAGRE_IS_PLUGIN_LOADER (loader))
+ {
+ g_warning ("Loader object is not a valid VinagrePluginLoader instance");
+
+ if (loader != NULL && G_IS_OBJECT (loader))
+ g_object_unref (loader);
+ }
+ else
+ {
+ info->loader = loader;
+ }
+ }
+}
+
+static VinagrePluginLoader *
+get_plugin_loader (VinagrePluginsEngine *engine,
+ VinagrePluginInfo *info)
+{
+ const gchar *loader_id;
+ LoaderInfo *loader_info;
+
+ loader_id = info->loader;
+
+ loader_info = (LoaderInfo *)g_hash_table_lookup (
+ engine->priv->loaders,
+ loader_id);
+
+ if (loader_info == NULL)
+ {
+ gchar *loader_dir;
+
+ loader_dir = gedit_dirs_get_gedit_plugin_loaders_dir ();
+
+ /* loader could not be found in the hash, try to find it by
+ scanning */
+ load_dir_real (engine,
+ loader_dir,
+ LOADER_EXT,
+ (LoadDirCallback)load_loader,
+ NULL);
+ g_free (loader_dir);
+
+ loader_info = (LoaderInfo *)g_hash_table_lookup (
+ engine->priv->loaders,
+ loader_id);
+ }
+
+ if (loader_info == NULL)
+ {
+ /* cache non-existent so we don't scan again */
+ add_loader (engine, loader_id, NULL);
+ return NULL;
+ }
+
+ ensure_loader (loader_info);
+ return loader_info->loader;
+}
+
+VinagrePluginsEngine *
+vinagre_plugins_engine_get_default (void)
+{
+ if (default_engine != NULL)
+ return default_engine;
+
+ default_engine = VINAGRE_PLUGINS_ENGINE (g_object_new (VINAGRE_TYPE_PLUGINS_ENGINE, NULL));
+ g_object_add_weak_pointer (G_OBJECT (default_engine),
+ (gpointer) &default_engine);
+ return default_engine;
+}
+
+const GList *
+vinagre_plugins_engine_get_plugin_list (VinagrePluginsEngine *engine)
+{
+ gedit_debug (DEBUG_PLUGINS);
+
+ return engine->priv->plugin_list;
+}
+
+static gint
+compare_plugin_info_and_name (VinagrePluginInfo *info,
+ const gchar *module_name)
+{
+ return strcmp (gedit_plugin_info_get_module_name (info), module_name);
+}
+
+VinagrePluginInfo *
+vinagre_plugins_engine_get_plugin_info (VinagrePluginsEngine *engine,
+ const gchar *name)
+{
+ GList *l = g_list_find_custom (engine->priv->plugin_list,
+ name,
+ (GCompareFunc) compare_plugin_info_and_name);
+
+ return l == NULL ? NULL : (VinagrePluginInfo *) l->data;
+}
+
+static void
+save_active_plugin_list (VinagrePluginsEngine *engine)
+{
+ GSList *active_plugins = NULL;
+ GList *l;
+
+ for (l = engine->priv->plugin_list; l != NULL; l = l->next)
+ {
+ VinagrePluginInfo *info = (VinagrePluginInfo *) l->data;
+
+ if (gedit_plugin_info_is_active (info))
+ {
+ active_plugins = g_slist_prepend (active_plugins,
+ (gpointer)gedit_plugin_info_get_module_name (info));
+ }
+ }
+
+ gedit_prefs_manager_set_active_plugins (active_plugins);
+
+ g_slist_free (active_plugins);
+}
+
+static gboolean
+load_plugin (VinagrePluginsEngine *engine,
+ VinagrePluginInfo *info)
+{
+ VinagrePluginLoader *loader;
+ gchar *path;
+
+ if (gedit_plugin_info_is_active (info))
+ return TRUE;
+
+ if (!gedit_plugin_info_is_available (info))
+ return FALSE;
+
+ loader = get_plugin_loader (engine, info);
+
+ if (loader == NULL)
+ {
+ g_warning ("Could not find loader `%s' for plugin `%s'", info->loader, info->name);
+ info->available = FALSE;
+ return FALSE;
+ }
+
+ path = g_path_get_dirname (info->file);
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ info->plugin = gedit_plugin_loader_load (loader, info, path);
+
+ g_free (path);
+
+ if (info->plugin == NULL)
+ {
+ g_warning ("Error loading plugin '%s'", info->name);
+ info->available = FALSE;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+vinagre_plugins_engine_activate_plugin_real (VinagrePluginsEngine *engine,
+ VinagrePluginInfo *info)
+{
+ if (!load_plugin (engine, info))
+ return;
+
+ /* activate plugin for all windows */
+ const GList *wins = gedit_app_get_windows (gedit_app_get_default ());
+ for (; wins != NULL; wins = wins->next)
+ gedit_plugin_activate (info->plugin, VINAGRE_WINDOW (wins->data));
+}
+
+gboolean
+vinagre_plugins_engine_activate_plugin (VinagrePluginsEngine *engine,
+ VinagrePluginInfo *info)
+{
+ gedit_debug (DEBUG_PLUGINS);
+
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ if (!gedit_plugin_info_is_available (info))
+ return FALSE;
+
+ if (gedit_plugin_info_is_active (info))
+ return TRUE;
+
+ g_signal_emit (engine, signals[ACTIVATE_PLUGIN], 0, info);
+
+ if (gedit_plugin_info_is_active (info))
+ save_active_plugin_list (engine);
+
+ return gedit_plugin_info_is_active (info);
+}
+
+static void
+call_plugin_deactivate (VinagrePlugin *plugin,
+ VinagreWindow *window)
+{
+ gedit_plugin_deactivate (plugin, window);
+
+ /* ensure update of ui manager, because we suspect it does something
+ with expected static strings in the type module (when unloaded the
+ strings don't exist anymore, and ui manager updates in an idle
+ func) */
+ gtk_ui_manager_ensure_update (gedit_window_get_ui_manager (window));
+}
+
+static void
+vinagre_plugins_engine_deactivate_plugin_real (VinagrePluginsEngine *engine,
+ VinagrePluginInfo *info)
+{
+ const GList *wins;
+ VinagrePluginLoader *loader;
+
+ if (!gedit_plugin_info_is_active (info) ||
+ !gedit_plugin_info_is_available (info))
+ return;
+
+ wins = gedit_app_get_windows (gedit_app_get_default ());
+ for (; wins != NULL; wins = wins->next)
+ call_plugin_deactivate (info->plugin, VINAGRE_WINDOW (wins->data));
+
+ /* first unref the plugin (the loader still has one) */
+ g_object_unref (info->plugin);
+
+ /* find the loader and tell it to gc and unload the plugin */
+ loader = get_plugin_loader (engine, info);
+
+ gedit_plugin_loader_garbage_collect (loader);
+ gedit_plugin_loader_unload (loader, info);
+
+ info->plugin = NULL;
+}
+
+gboolean
+vinagre_plugins_engine_deactivate_plugin (VinagrePluginsEngine *engine,
+ VinagrePluginInfo *info)
+{
+ gedit_debug (DEBUG_PLUGINS);
+
+ g_return_val_if_fail (info != NULL, FALSE);
+
+ if (!gedit_plugin_info_is_active (info))
+ return TRUE;
+
+ g_signal_emit (engine, signals[DEACTIVATE_PLUGIN], 0, info);
+ if (!gedit_plugin_info_is_active (info))
+ save_active_plugin_list (engine);
+
+ return !gedit_plugin_info_is_active (info);
+}
+
+void
+vinagre_plugins_engine_activate_plugins (VinagrePluginsEngine *engine,
+ VinagreWindow *window)
+{
+ GSList *active_plugins = NULL;
+ GList *pl;
+
+ gedit_debug (DEBUG_PLUGINS);
+
+ g_return_if_fail (VINAGRE_IS_PLUGINS_ENGINE (engine));
+ g_return_if_fail (VINAGRE_IS_WINDOW (window));
+
+ /* the first time, we get the 'active' plugins from gconf */
+ if (engine->priv->activate_from_prefs)
+ {
+ active_plugins = gedit_prefs_manager_get_active_plugins ();
+ }
+
+ for (pl = engine->priv->plugin_list; pl; pl = pl->next)
+ {
+ VinagrePluginInfo *info = (VinagrePluginInfo*)pl->data;
+
+ if (engine->priv->activate_from_prefs &&
+ g_slist_find_custom (active_plugins,
+ gedit_plugin_info_get_module_name (info),
+ (GCompareFunc)strcmp) == NULL)
+ continue;
+
+ /* If plugin is not active, don't try to activate/load it */
+ if (!engine->priv->activate_from_prefs &&
+ !gedit_plugin_info_is_active (info))
+ continue;
+
+ if (load_plugin (engine, info))
+ gedit_plugin_activate (info->plugin,
+ window);
+ }
+
+ if (engine->priv->activate_from_prefs)
+ {
+ g_slist_foreach (active_plugins, (GFunc) g_free, NULL);
+ g_slist_free (active_plugins);
+ engine->priv->activate_from_prefs = FALSE;
+ }
+
+ gedit_debug_message (DEBUG_PLUGINS, "End");
+
+ /* also call update_ui after activation */
+ vinagre_plugins_engine_update_plugins_ui (engine, window);
+}
+
+void
+vinagre_plugins_engine_deactivate_plugins (VinagrePluginsEngine *engine,
+ VinagreWindow *window)
+{
+ GList *pl;
+
+ gedit_debug (DEBUG_PLUGINS);
+
+ g_return_if_fail (VINAGRE_IS_PLUGINS_ENGINE (engine));
+ g_return_if_fail (VINAGRE_IS_WINDOW (window));
+
+ for (pl = engine->priv->plugin_list; pl; pl = pl->next)
+ {
+ VinagrePluginInfo *info = (VinagrePluginInfo*)pl->data;
+
+ /* check if the plugin is actually active */
+ if (!gedit_plugin_info_is_active (info))
+ continue;
+
+ /* call deactivate for the plugin for this window */
+ gedit_plugin_deactivate (info->plugin, window);
+ }
+
+ gedit_debug_message (DEBUG_PLUGINS, "End");
+}
+
+void
+vinagre_plugins_engine_update_plugins_ui (VinagrePluginsEngine *engine,
+ VinagreWindow *window)
+{
+ GList *pl;
+
+ gedit_debug (DEBUG_PLUGINS);
+
+ g_return_if_fail (VINAGRE_IS_PLUGINS_ENGINE (engine));
+ g_return_if_fail (VINAGRE_IS_WINDOW (window));
+
+ /* call update_ui for all active plugins */
+ for (pl = engine->priv->plugin_list; pl; pl = pl->next)
+ {
+ VinagrePluginInfo *info = (VinagrePluginInfo*)pl->data;
+
+ if (!gedit_plugin_info_is_active (info))
+ continue;
+
+ gedit_debug_message (DEBUG_PLUGINS, "Updating UI of %s", info->name);
+ gedit_plugin_update_ui (info->plugin, window);
+ }
+}
+
+void
+vinagre_plugins_engine_configure_plugin (VinagrePluginsEngine *engine,
+ VinagrePluginInfo *info,
+ GtkWindow *parent)
+{
+ GtkWidget *conf_dlg;
+
+ GtkWindowGroup *wg;
+
+ gedit_debug (DEBUG_PLUGINS);
+
+ g_return_if_fail (info != NULL);
+
+ conf_dlg = gedit_plugin_create_configure_dialog (info->plugin);
+ g_return_if_fail (conf_dlg != NULL);
+ gtk_window_set_transient_for (GTK_WINDOW (conf_dlg),
+ parent);
+
+ wg = parent->group;
+ if (wg == NULL)
+ {
+ wg = gtk_window_group_new ();
+ gtk_window_group_add_window (wg, parent);
+ }
+
+ gtk_window_group_add_window (wg,
+ GTK_WINDOW (conf_dlg));
+
+ gtk_window_set_modal (GTK_WINDOW (conf_dlg), TRUE);
+ gtk_widget_show (conf_dlg);
+}
+
+void
+vinagre_plugins_engine_active_plugins_changed (VinagrePluginsEngine *engine)
+{
+ gboolean to_activate;
+ GSList *active_plugins;
+ GList *pl;
+
+ gedit_debug (DEBUG_PLUGINS);
+
+ active_plugins = gedit_prefs_manager_get_active_plugins ();
+
+ for (pl = engine->priv->plugin_list; pl; pl = pl->next)
+ {
+ VinagrePluginInfo *info = (VinagrePluginInfo*)pl->data;
+
+ if (!gedit_plugin_info_is_available (info))
+ continue;
+
+ to_activate = (g_slist_find_custom (active_plugins,
+ gedit_plugin_info_get_module_name (info),
+ (GCompareFunc)strcmp) != NULL);
+
+ if (!gedit_plugin_info_is_active (info) && to_activate)
+ g_signal_emit (engine, signals[ACTIVATE_PLUGIN], 0, info);
+ else if (gedit_plugin_info_is_active (info) && !to_activate)
+ g_signal_emit (engine, signals[DEACTIVATE_PLUGIN], 0, info);
+ }
+
+ g_slist_foreach (active_plugins, (GFunc) g_free, NULL);
+ g_slist_free (active_plugins);
+}
+
+void
+vinagre_plugins_engine_rescan_plugins (VinagrePluginsEngine *engine)
+{
+ gedit_debug (DEBUG_PLUGINS);
+
+ load_all_plugins (engine);
+}
+
diff --git a/src/vinagre-plugins-engine.h b/src/vinagre-plugins-engine.h
new file mode 100644
index 0000000..d6c9572
--- /dev/null
+++ b/src/vinagre-plugins-engine.h
@@ -0,0 +1,97 @@
+/*
+ * vinagre-plugins-engine.h
+ * This file is part of vinagre
+ *
+ * Copyright (C) 2009 Jorge Pereira <jorge jorgepereira com br>
+ *
+ * vinagre-plugins-engine.h is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * vinagre-plugins-engine.h is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __VINAGRE_PLUGINS_ENGINE_H__
+#define __VINAGRE_PLUGINS_ENGINE_H__
+
+#include <glib.h>
+#include "vinagre-window.h"
+#include "vinagre-plugin-info.h"
+#include "vinagre-plugin.h"
+
+G_BEGIN_DECLS
+
+#define VINAGRE_TYPE_PLUGINS_ENGINE (vinagre_plugins_engine_get_type ())
+#define VINAGRE_PLUGINS_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), VINAGRE_TYPE_PLUGINS_ENGINE, VinagrePluginsEngine))
+#define VINAGRE_PLUGINS_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), VINAGRE_TYPE_PLUGINS_ENGINE, VinagrePluginsEngineClass))
+#define VINAGRE_IS_PLUGINS_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), VINAGRE_TYPE_PLUGINS_ENGINE))
+#define VINAGRE_IS_PLUGINS_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VINAGRE_TYPE_PLUGINS_ENGINE))
+#define VINAGRE_PLUGINS_ENGINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), VINAGRE_TYPE_PLUGINS_ENGINE, VinagrePluginsEngineClass))
+
+typedef struct _VinagrePluginsEngine VinagrePluginsEngine;
+typedef struct _VinagrePluginsEnginePrivate VinagrePluginsEnginePrivate;
+
+struct _VinagrePluginsEngine
+{
+ GObject parent;
+ VinagrePluginsEnginePrivate *priv;
+};
+
+typedef struct _VinagrePluginsEngineClass VinagrePluginsEngineClass;
+
+struct _VinagrePluginsEngineClass
+{
+ GObjectClass parent_class;
+
+ void (* activate_plugin) (VinagrePluginsEngine *engine,
+ VinagrePluginInfo *info);
+
+ void (* deactivate_plugin) (VinagrePluginsEngine *engine,
+ VinagrePluginInfo *info);
+};
+
+GType vinagre_plugins_engine_get_type (void) G_GNUC_CONST;
+
+VinagrePluginsEngine *vinagre_plugins_engine_get_default (void);
+
+void vinagre_plugins_engine_garbage_collect (VinagrePluginsEngine *engine);
+
+const GList *vinagre_plugins_engine_get_plugin_list (VinagrePluginsEngine *engine);
+
+VinagrePluginInfo *vinagre_plugins_engine_get_plugin_info (VinagrePluginsEngine *engine,
+ const gchar *name);
+
+/* plugin load and unloading (overall, for all windows) */
+gboolean vinagre_plugins_engine_activate_plugin (VinagrePluginsEngine *engine,
+ VinagrePluginInfo *info);
+gboolean vinagre_plugins_engine_deactivate_plugin (VinagrePluginsEngine *engine,
+ VinagrePluginInfo *info);
+
+void vinagre_plugins_engine_configure_plugin (VinagrePluginsEngine *engine,
+ VinagrePluginInfo *info,
+ GtkWindow *parent);
+
+/* plugin activation/deactivation per window, private to VinagreWindow */
+void vinagre_plugins_engine_activate_plugins (VinagrePluginsEngine *engine,
+ VinagreWindow *window);
+void vinagre_plugins_engine_deactivate_plugins (VinagrePluginsEngine *engine,
+ VinagreWindow *window);
+void vinagre_plugins_engine_update_plugins_ui (VinagrePluginsEngine *engine,
+ VinagreWindow *window);
+
+/* private for gconf notification */
+void vinagre_plugins_engine_active_plugins_changed
+ (VinagrePluginsEngine *engine);
+
+void vinagre_plugins_engine_rescan_plugins (VinagrePluginsEngine *engine);
+
+G_END_DECLS
+
+#endif /* __VINAGRE_PLUGINS_ENGINE_H__ */
diff --git a/src/vinagre-ui.h b/src/vinagre-ui.h
index 964c186..2317a11 100644
--- a/src/vinagre-ui.h
+++ b/src/vinagre-ui.h
@@ -47,7 +47,9 @@ static const GtkActionEntry vinagre_always_sensitive_entries[] =
/* Edit menu */
{ "EditPreferences", GTK_STOCK_PREFERENCES, NULL, NULL,
N_("Edit the application preferences"), G_CALLBACK (vinagre_cmd_edit_preferences) },
-
+ { "EditPlugins", GTK_STOCK_EXECUTE, N_("_Plugins"), NULL,
+ N_("Select plugins"), G_CALLBACK (vinagre_cmd_edit_plugins) },
+
/* Bookmarks menu */
{ "BookmarksOpen", GTK_STOCK_CONNECT, N_("_Open bookmark"), NULL,
N_("Connect to this machine"), G_CALLBACK (vinagre_cmd_bookmarks_open) },
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]