[vinagre] Vinagre Plugin Support



commit d1487145bc9c7cb40ca1cbabf0527b4d2bcfa5ab
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]