[gedit] Revert the three previous commits.



commit e9d4234f729147c1ecf69a6595ac91d67f52d15c
Author: Steve Frécinaux <code istique net>
Date:   Sun Jun 13 22:08:29 2010 +0200

    Revert the three previous commits.
    
    Those were pushed by mistake.
    
    This reverts commit 2786eba0d2a333b9e4d5675be410b4c42d48addd.
    This reverts commit cae391accd5f15a34902a60b0f3eb5e130b0031a.
    This reverts commit c7f9f4aa8a0ee1f81ec33c9c3488a838c529a101.

 Makefile.am                               |    2 +-
 configure.ac                              |    7 +-
 gedit/Makefile.am                         |   10 +
 gedit/dialogs/gedit-preferences-dialog.c  |    8 +-
 gedit/gedit-dirs.c                        |   30 +-
 gedit/gedit-dirs.h                        |    5 +-
 gedit/gedit-metadata-manager.h            |    1 -
 gedit/gedit-plugin-info-priv.h            |   69 +++
 gedit/gedit-plugin-info.c                 |  402 +++++++++++++
 gedit/gedit-plugin-info.h                 |   64 ++
 gedit/gedit-plugin-loader.c               |  132 +++++
 gedit/gedit-plugin-loader.h               |  108 ++++
 gedit/gedit-plugin-manager.c              |  895 +++++++++++++++++++++++++++++
 gedit/gedit-plugin-manager.h              |   85 +++
 gedit/gedit-plugin.c                      |  339 +++++++++++
 gedit/gedit-plugin.h                      |  242 ++++++++
 gedit/gedit-plugins-engine.c              |  862 +++++++++++++++++++++++++---
 gedit/gedit-plugins-engine.h              |   43 ++-
 gedit/gedit-window-private.h              |    3 -
 gedit/gedit-window.c                      |   82 +--
 plugin-loaders/Makefile.am                |    3 +
 plugin-loaders/c/Makefile.am              |   24 +
 plugin-loaders/c/gedit-plugin-loader-c.c  |  183 ++++++
 plugin-loaders/c/gedit-plugin-loader-c.h  |   61 ++
 plugins/Makefile.am                       |   53 +-
 plugins/modelines/gedit-modeline-plugin.c |   89 ++--
 plugins/modelines/gedit-modeline-plugin.h |   22 +-
 plugins/pysample/Makefile.am              |   15 -
 plugins/pysample/pysample.gedit-plugin.in |    9 -
 plugins/pysample/pysample.py              |   15 -
 30 files changed, 3552 insertions(+), 311 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 122a88b..e57b203 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
 ## Process this file with automake to produce Makefile.in
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = gedit pixmaps po plugins data docs tests win32 osx
+SUBDIRS = gedit pixmaps po data plugin-loaders plugins docs tests win32 osx
 
 if !OS_OSX
 SUBDIRS += help
diff --git a/configure.ac b/configure.ac
index 8fe0f25..e07fa4b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -274,8 +274,6 @@ PKG_CHECK_MODULES(GEDIT, [
 	gtk+-3.0 >= 2.90.0
 	gtksourceview-3.0 >= 2.11.2
 	gconf-2.0 >= 2.31.1
-	libpeas-1.0
-	libpeasui-1.0
 ])
 
 if test "$os_osx" = "no" &&
@@ -372,8 +370,6 @@ AC_SUBST(GEDIT_IMPLIB)
 AC_SUBST(PLUGIN_LIBTOOL_FLAGS)
 AC_SUBST(LOADER_LIBTOOL_FLAGS)
 
-AM_PATH_PYTHON(2.6)
-
 GEDIT_PLUGINS_DATA_DIR="$datadir/gedit-2/plugins"
 AC_SUBST(GEDIT_PLUGINS_DATA_DIR)
 
@@ -397,6 +393,8 @@ gedit/smclient/Makefile
 gedit/Makefile
 help/Makefile
 pixmaps/Makefile
+plugin-loaders/Makefile
+plugin-loaders/c/Makefile
 plugins/Makefile
 plugins/changecase/Makefile
 plugins/checkupdate/org.gnome.gedit.checkupdate.gschema.xml.in
@@ -405,7 +403,6 @@ plugins/docinfo/Makefile
 plugins/filebrowser/org.gnome.gedit.file-browser.gschema.xml.in
 plugins/filebrowser/Makefile
 plugins/modelines/Makefile
-plugins/pysample/Makefile
 plugins/sort/Makefile
 plugins/spell/Makefile
 plugins/taglist/Makefile
diff --git a/gedit/Makefile.am b/gedit/Makefile.am
index 72c8074..6bf6894 100644
--- a/gedit/Makefile.am
+++ b/gedit/Makefile.am
@@ -105,6 +105,11 @@ NOINST_H_FILES =			\
 	gedit-language-manager.h	\
 	gedit-multi-notebook.h		\
 	gedit-notebook.h		\
+	gedit-object-module.h		\
+	gedit-plugin-info.h		\
+	gedit-plugin-info-priv.h	\
+	gedit-plugin-loader.h		\
+	gedit-plugin-manager.h		\
 	gedit-plugins-engine.h		\
 	gedit-print-job.h		\
 	gedit-print-preview.h		\
@@ -129,6 +134,7 @@ INST_H_FILES =				\
 	gedit-message-type.h		\
 	gedit-message.h			\
 	gedit-panel.h			\
+	gedit-plugin.h			\
 	gedit-progress-info-bar.h	\
 	gedit-statusbar.h		\
 	gedit-status-combo-box.h	\
@@ -180,6 +186,10 @@ libgedit_la_SOURCES = 			\
 	gedit-object-module.c		\
 	gedit-notebook.c		\
 	gedit-panel.c			\
+	gedit-plugin-info.c		\
+	gedit-plugin.c			\
+	gedit-plugin-loader.c		\
+	gedit-plugin-manager.c		\
 	gedit-plugins-engine.c		\
 	gedit-print-job.c		\
 	gedit-print-preview.c		\
diff --git a/gedit/dialogs/gedit-preferences-dialog.c b/gedit/dialogs/gedit-preferences-dialog.c
index 593a53d..2cbbce4 100644
--- a/gedit/dialogs/gedit-preferences-dialog.c
+++ b/gedit/dialogs/gedit-preferences-dialog.c
@@ -39,15 +39,14 @@
 #include <string.h>
 
 #include <glib/gi18n.h>
-#include <libpeasui/peas-ui-plugin-manager.h>
 
 #include "gedit-preferences-dialog.h"
 #include "gedit-utils.h"
 #include "gedit-debug.h"
 #include "gedit-document.h"
 #include "gedit-style-scheme-manager.h"
+#include "gedit-plugin-manager.h"
 #include "gedit-dirs.h"
-#include "gedit-plugins-engine.h"
 #include "gedit-settings.h"
 #include "gedit-utils.h"
 
@@ -906,14 +905,11 @@ setup_font_colors_page (GeditPreferencesDialog *dlg)
 static void
 setup_plugins_page (GeditPreferencesDialog *dlg)
 {
-	GeditPluginsEngine *engine;
 	GtkWidget *page_content;
 
 	gedit_debug (DEBUG_PREFS);
 
-	engine = gedit_plugins_engine_get_default ();
-
-	page_content = peas_ui_plugin_manager_new (PEAS_ENGINE (engine));
+	page_content = gedit_plugin_manager_new ();
 	g_return_if_fail (page_content != NULL);
 
 	gtk_box_pack_start (GTK_BOX (dlg->priv->plugin_manager_place_holder),
diff --git a/gedit/gedit-dirs.c b/gedit/gedit-dirs.c
index 5dac9b7..c3aae39 100644
--- a/gedit/gedit-dirs.c
+++ b/gedit/gedit-dirs.c
@@ -286,25 +286,19 @@ gedit_dirs_get_gedit_plugins_dir (void)
 }
 
 gchar *
-gedit_dirs_get_gedit_plugins_data_dir (void)
+gedit_dirs_get_gedit_plugin_loaders_dir (void)
 {
-	gchar *data_dir;
-	gchar *plugin_data_dir;
-
-	data_dir = gedit_dirs_get_gedit_data_dir ();
-
-	plugin_data_dir = g_build_filename (data_dir,
-					    "plugins",
-					    NULL);
-	g_free (data_dir);
-
-	return plugin_data_dir;
-}
-
-gchar *
-gedit_dirs_get_binding_modules_dir (void)
-{
-	return gedit_dirs_get_gedit_lib_dir ();
+	gchar *lib_dir;
+	gchar *loader_dir;
+	
+	lib_dir = gedit_dirs_get_gedit_lib_dir ();
+	
+	loader_dir = g_build_filename (lib_dir,
+				       "plugin-loaders",
+				       NULL);
+	g_free (lib_dir);
+	
+	return loader_dir;
 }
 
 gchar *
diff --git a/gedit/gedit-dirs.h b/gedit/gedit-dirs.h
index e0be2f9..ba79cee 100644
--- a/gedit/gedit-dirs.h
+++ b/gedit/gedit-dirs.h
@@ -44,9 +44,8 @@ gchar		*gedit_dirs_get_gedit_lib_dir		(void);
 
 gchar		*gedit_dirs_get_gedit_plugins_dir	(void);
 
-gchar		*gedit_dirs_get_gedit_plugins_data_dir	(void);
-
-gchar		*gedit_dirs_get_binding_modules_dir	(void);
+gchar		*gedit_dirs_get_gedit_plugin_loaders_dir
+							(void);
 
 gchar		*gedit_dirs_get_ui_file			(const gchar *file);
 
diff --git a/gedit/gedit-metadata-manager.h b/gedit/gedit-metadata-manager.h
index cdb28b4..b055c55 100644
--- a/gedit/gedit-metadata-manager.h
+++ b/gedit/gedit-metadata-manager.h
@@ -31,7 +31,6 @@
 #define __GEDIT_METADATA_MANAGER_H__
 
 #include <glib.h>
-#include <gio/gio.h>
 
 G_BEGIN_DECLS
 
diff --git a/gedit/gedit-plugin-info-priv.h b/gedit/gedit-plugin-info-priv.h
new file mode 100644
index 0000000..14c6100
--- /dev/null
+++ b/gedit/gedit-plugin-info-priv.h
@@ -0,0 +1,69 @@
+/*
+ * gedit-plugin-info-priv.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2002-2005 - Paolo Maggi 
+ * Copyright (C) 2007 - Paolo Maggi, Steve Frécinaux
+ *
+ * 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. 
+ */
+ 
+/*
+ * Modified by the gedit Team, 2002-2007. See the AUTHORS file for a
+ * list of people on the gedit Team.
+ * See the ChangeLog files for a list of changes.
+ *
+ * $Id$
+ */
+
+#ifndef __GEDIT_PLUGIN_INFO_PRIV_H__
+#define __GEDIT_PLUGIN_INFO_PRIV_H__
+
+#include "gedit-plugin-info.h"
+#include "gedit-plugin.h"
+
+struct _GeditPluginInfo
+{
+	gint               refcount;
+
+	GeditPlugin       *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;
+};
+
+GeditPluginInfo		*_gedit_plugin_info_new		(const gchar *file);
+void			 _gedit_plugin_info_ref		(GeditPluginInfo *info);
+void			 _gedit_plugin_info_unref	(GeditPluginInfo *info);
+
+
+#endif /* __GEDIT_PLUGIN_INFO_PRIV_H__ */
+/* ex:ts=8:noet: */
diff --git a/gedit/gedit-plugin-info.c b/gedit/gedit-plugin-info.c
new file mode 100644
index 0000000..b7f0ac4
--- /dev/null
+++ b/gedit/gedit-plugin-info.c
@@ -0,0 +1,402 @@
+/*
+ * gedit-plugin-info.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2002-2005 - Paolo Maggi 
+ * Copyright (C) 2007 - Paolo Maggi, Steve Frécinaux
+ *
+ * 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. 
+ */
+ 
+/*
+ * Modified by the gedit Team, 2002-2007. See the AUTHORS file for a
+ * list of people on the gedit Team.
+ * See the ChangeLog files for a list of changes.
+ *
+ * $Id$
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <glib.h>
+
+#include "gedit-plugin-info.h"
+#include "gedit-plugin-info-priv.h"
+#include "gedit-debug.h"
+#include "gedit-plugin.h"
+
+#define GEDIT_PLUGIN_IAGE 3
+
+void
+_gedit_plugin_info_ref (GeditPluginInfo *info)
+{
+	g_atomic_int_inc (&info->refcount);
+}
+
+static GeditPluginInfo *
+gedit_plugin_info_copy (GeditPluginInfo *info)
+{
+	_gedit_plugin_info_ref (info);
+	return info;
+}
+
+void
+_gedit_plugin_info_unref (GeditPluginInfo *info)
+{
+	if (!g_atomic_int_dec_and_test (&info->refcount))
+		return;
+
+	if (info->plugin != NULL)
+	{
+		gedit_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);
+}
+
+/**
+ * gedit_plugin_info_get_type:
+ *
+ * Retrieves the #GType object which is associated with the #GeditPluginInfo
+ * class.
+ *
+ * Return value: the GType associated with #GeditPluginInfo.
+ **/
+GType
+gedit_plugin_info_get_type (void)
+{
+	static GType the_type = 0;
+
+	if (G_UNLIKELY (!the_type))
+		the_type = g_boxed_type_register_static (
+					"GeditPluginInfo",
+					(GBoxedCopyFunc) gedit_plugin_info_copy,
+					(GBoxedFreeFunc) _gedit_plugin_info_unref);
+
+	return the_type;
+} 
+
+/**
+ * gedit_plugin_info_new:
+ * @filename: the filename where to read the plugin information
+ *
+ * Creates a new #GeditPluginInfo from a file on the disk.
+ *
+ * Return value: a newly created #GeditPluginInfo.
+ */
+GeditPluginInfo *
+_gedit_plugin_info_new (const gchar *file)
+{
+	GeditPluginInfo *info;
+	GKeyFile *plugin_file = NULL;
+	gchar *str;
+
+	g_return_val_if_fail (file != NULL, NULL);
+
+	gedit_debug_message (DEBUG_PLUGINS, "Loading plugin: %s", file);
+
+	info = g_new0 (GeditPluginInfo, 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,
+			   	 "Gedit Plugin",
+				 "IAge",
+				 NULL))
+	{
+		gedit_debug_message (DEBUG_PLUGINS,
+				     "IAge key does not exist in file: %s", file);
+		goto error;
+	}
+	
+	/* Check IAge=GEDIT_PLUGIN_IAGE */
+	if (g_key_file_get_integer (plugin_file,
+				    "Gedit Plugin",
+				    "IAge",
+				    NULL) != GEDIT_PLUGIN_IAGE)
+	{
+		gedit_debug_message (DEBUG_PLUGINS,
+				     "Wrong IAge in file: %s", file);
+		goto error;
+	}
+				    
+	/* Get module name */
+	str = g_key_file_get_string (plugin_file,
+				     "Gedit 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,
+							 "Gedit Plugin",
+							 "Depends",
+							 NULL,
+							 NULL);
+	if (info->dependencies == NULL)
+	{
+		gedit_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,
+				     "Gedit 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,
+					    "Gedit 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,
+					    "Gedit Plugin",
+					    "Description",
+					    NULL, NULL);
+	if (str)
+		info->desc = str;
+	else
+		gedit_debug_message (DEBUG_PLUGINS, "Could not find 'Description' in %s", file);
+
+	/* Get Icon */
+	str = g_key_file_get_locale_string (plugin_file,
+					    "Gedit Plugin",
+					    "Icon",
+					    NULL, NULL);
+	if (str)
+		info->icon_name = str;
+	else
+		gedit_debug_message (DEBUG_PLUGINS, "Could not find 'Icon' in %s, using 'gedit-plugin'", file);
+	
+
+	/* Get Authors */
+	info->authors = g_key_file_get_string_list (plugin_file,
+						    "Gedit Plugin",
+						    "Authors",
+						    NULL,
+						    NULL);
+	if (info->authors == NULL)
+		gedit_debug_message (DEBUG_PLUGINS, "Could not find 'Authors' in %s", file);
+
+
+	/* Get Copyright */
+	str = g_key_file_get_string (plugin_file,
+				     "Gedit Plugin",
+				     "Copyright",
+				     NULL);
+	if (str)
+		info->copyright = str;
+	else
+		gedit_debug_message (DEBUG_PLUGINS, "Could not find 'Copyright' in %s", file);
+
+	/* Get Website */
+	str = g_key_file_get_string (plugin_file,
+				     "Gedit Plugin",
+				     "Website",
+				     NULL);
+	if (str)
+		info->website = str;
+	else
+		gedit_debug_message (DEBUG_PLUGINS, "Could not find 'Website' in %s", file);
+	
+	/* Get Version */
+	str = g_key_file_get_string (plugin_file,
+				     "Gedit Plugin",
+				     "Version",
+				     NULL);
+	if (str)
+		info->version = str;
+	else
+		gedit_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
+gedit_plugin_info_is_active (GeditPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, FALSE);
+
+	return info->available && info->plugin != NULL;
+}
+
+gboolean
+gedit_plugin_info_is_available (GeditPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, FALSE);
+
+	return info->available != FALSE;
+}
+
+gboolean
+gedit_plugin_info_is_configurable (GeditPluginInfo *info)
+{
+	gedit_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 gedit_plugin_is_configurable (info->plugin);
+}
+
+const gchar *
+gedit_plugin_info_get_module_name (GeditPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, NULL);
+
+	return info->module_name;
+}
+
+const gchar *
+gedit_plugin_info_get_name (GeditPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, NULL);
+
+	return info->name;
+}
+
+const gchar *
+gedit_plugin_info_get_description (GeditPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, NULL);
+
+	return info->desc;
+}
+
+const gchar *
+gedit_plugin_info_get_icon_name (GeditPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, NULL);
+
+	/* use the gedit-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 "gedit-plugin";
+	}
+}
+
+const gchar **
+gedit_plugin_info_get_authors (GeditPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, (const gchar **)NULL);
+
+	return (const gchar **) info->authors;
+}
+
+const gchar *
+gedit_plugin_info_get_website (GeditPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, NULL);
+
+	return info->website;
+}
+
+const gchar *
+gedit_plugin_info_get_copyright (GeditPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, NULL);
+
+	return info->copyright;
+}
+
+const gchar *
+gedit_plugin_info_get_version (GeditPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, NULL);
+
+	return info->version;
+}
+
+/* ex:ts=8:noet: */
diff --git a/gedit/gedit-plugin-info.h b/gedit/gedit-plugin-info.h
new file mode 100644
index 0000000..cc39a55
--- /dev/null
+++ b/gedit/gedit-plugin-info.h
@@ -0,0 +1,64 @@
+/*
+ * gedit-plugin-info.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2002-2005 - Paolo Maggi 
+ * Copyright (C) 2007 - Paolo Maggi, Steve Frécinaux
+ *
+ * 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.
+ */
+ 
+/*
+ * Modified by the gedit Team, 2002-2007. See the AUTHORS file for a
+ * list of people on the gedit Team.
+ * See the ChangeLog files for a list of changes.
+ *
+ * $Id$
+ */
+
+#ifndef __GEDIT_PLUGIN_INFO_H__
+#define __GEDIT_PLUGIN_INFO_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_PLUGIN_INFO			(gedit_plugin_info_get_type ())
+#define GEDIT_PLUGIN_INFO(obj)			((GeditPluginInfo *) (obj))
+
+typedef struct _GeditPluginInfo			GeditPluginInfo;
+
+GType		 gedit_plugin_info_get_type		(void) G_GNUC_CONST;
+
+gboolean 	 gedit_plugin_info_is_active		(GeditPluginInfo *info);
+gboolean 	 gedit_plugin_info_is_available		(GeditPluginInfo *info);
+gboolean	 gedit_plugin_info_is_configurable	(GeditPluginInfo *info);
+
+const gchar	*gedit_plugin_info_get_module_name	(GeditPluginInfo *info);
+
+const gchar	*gedit_plugin_info_get_name		(GeditPluginInfo *info);
+const gchar	*gedit_plugin_info_get_description	(GeditPluginInfo *info);
+const gchar	*gedit_plugin_info_get_icon_name	(GeditPluginInfo *info);
+const gchar    **gedit_plugin_info_get_authors		(GeditPluginInfo *info);
+const gchar	*gedit_plugin_info_get_website		(GeditPluginInfo *info);
+const gchar	*gedit_plugin_info_get_copyright	(GeditPluginInfo *info);
+const gchar	*gedit_plugin_info_get_version		(GeditPluginInfo *info);
+
+G_END_DECLS
+
+#endif /* __GEDIT_PLUGIN_INFO_H__ */
+
+/* ex:ts=8:noet: */
diff --git a/gedit/gedit-plugin-loader.c b/gedit/gedit-plugin-loader.c
new file mode 100644
index 0000000..9f23521
--- /dev/null
+++ b/gedit/gedit-plugin-loader.c
@@ -0,0 +1,132 @@
+/*
+ * gedit-plugin-loader.c
+ * This file is part of gedit
+ *
+ * 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 "gedit-plugin-loader.h"
+
+static void
+gedit_plugin_loader_base_init (gpointer g_class)
+{
+	static gboolean initialized = FALSE;
+
+	if (G_UNLIKELY (!initialized))
+	{
+		/* create interface signals here. */
+		initialized = TRUE;
+	}
+}
+
+GType
+gedit_plugin_loader_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0))
+	{
+		static const GTypeInfo info =
+		{
+			sizeof (GeditPluginLoaderInterface),
+			gedit_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, "GeditPluginLoader", &info, 0);
+	}
+
+	return type;
+}
+
+const gchar *
+gedit_plugin_loader_type_get_id (GType type)
+{
+	GTypeClass *klass;
+	GeditPluginLoaderInterface *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, GEDIT_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 ();
+}
+
+GeditPlugin *
+gedit_plugin_loader_load (GeditPluginLoader *loader,
+			  GeditPluginInfo   *info,
+			  const gchar       *path)
+{
+	GeditPluginLoaderInterface *iface;
+	
+	g_return_val_if_fail (GEDIT_IS_PLUGIN_LOADER (loader), NULL);
+	
+	iface = GEDIT_PLUGIN_LOADER_GET_INTERFACE (loader);
+	g_return_val_if_fail (iface->load != NULL, NULL);
+	
+	return iface->load (loader, info, path);
+}
+
+void
+gedit_plugin_loader_unload (GeditPluginLoader *loader,
+			    GeditPluginInfo   *info)
+{
+	GeditPluginLoaderInterface *iface;
+	
+	g_return_if_fail (GEDIT_IS_PLUGIN_LOADER (loader));
+	
+	iface = GEDIT_PLUGIN_LOADER_GET_INTERFACE (loader);
+	g_return_if_fail (iface->unload != NULL);
+	
+	iface->unload (loader, info);
+}
+
+void
+gedit_plugin_loader_garbage_collect (GeditPluginLoader *loader)
+{
+	GeditPluginLoaderInterface *iface;
+	
+	g_return_if_fail (GEDIT_IS_PLUGIN_LOADER (loader));
+	
+	iface = GEDIT_PLUGIN_LOADER_GET_INTERFACE (loader);
+	
+	if (iface->garbage_collect != NULL)
+		iface->garbage_collect (loader);
+}
+/* ex:ts=8:noet: */
diff --git a/gedit/gedit-plugin-loader.h b/gedit/gedit-plugin-loader.h
new file mode 100644
index 0000000..4e0c4b2
--- /dev/null
+++ b/gedit/gedit-plugin-loader.h
@@ -0,0 +1,108 @@
+/*
+ * gedit-plugin-loader.h
+ * This file is part of gedit
+ *
+ * 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 __GEDIT_PLUGIN_LOADER_H__
+#define __GEDIT_PLUGIN_LOADER_H__
+
+#include <glib-object.h>
+#include <gedit/gedit-plugin.h>
+#include <gedit/gedit-plugin-info.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_PLUGIN_LOADER                (gedit_plugin_loader_get_type ())
+#define GEDIT_PLUGIN_LOADER(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_PLUGIN_LOADER, GeditPluginLoader))
+#define GEDIT_IS_PLUGIN_LOADER(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_PLUGIN_LOADER))
+#define GEDIT_PLUGIN_LOADER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GEDIT_TYPE_PLUGIN_LOADER, GeditPluginLoaderInterface))
+
+typedef struct _GeditPluginLoader GeditPluginLoader; /* dummy object */
+typedef struct _GeditPluginLoaderInterface GeditPluginLoaderInterface;
+
+struct _GeditPluginLoaderInterface {
+	GTypeInterface parent;
+
+	const gchar *(*get_id)		(void);
+
+	GeditPlugin *(*load) 		(GeditPluginLoader 	*loader,
+			     		 GeditPluginInfo	*info,
+			      		 const gchar       	*path);
+
+	void 	     (*unload)		(GeditPluginLoader 	*loader,
+					 GeditPluginInfo       	*info);
+
+	void         (*garbage_collect)	(GeditPluginLoader	*loader);
+};
+
+GType gedit_plugin_loader_get_type (void);
+
+const gchar *gedit_plugin_loader_type_get_id	(GType 			 type);
+GeditPlugin *gedit_plugin_loader_load		(GeditPluginLoader 	*loader,
+						 GeditPluginInfo 	*info,
+						 const gchar		*path);
+void gedit_plugin_loader_unload			(GeditPluginLoader 	*loader,
+						 GeditPluginInfo	*info);
+void gedit_plugin_loader_garbage_collect	(GeditPluginLoader 	*loader);
+
+/**
+ * GEDIT_PLUGIN_LOADER_IMPLEMENT_INTERFACE(TYPE_IFACE, iface_init):
+ *
+ * Utility macro used to register interfaces for gobject types in plugin loaders.
+ */
+#define GEDIT_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);
+
+/**
+ * GEDIT_PLUGIN_LOADER_REGISTER_TYPE(PluginLoaderName, plugin_loader_name, PARENT_TYPE, loader_interface_init):
+ *
+ * Utility macro used to register plugin loaders.
+ */
+#define GEDIT_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,					\
+					GEDIT_PLUGIN_LOADER_IMPLEMENT_INTERFACE(GEDIT_TYPE_PLUGIN_LOADER, loader_iface_init));	\
+										\
+										\
+G_MODULE_EXPORT GType								\
+register_gedit_plugin_loader (GTypeModule *type_module)				\
+{										\
+	plugin_loader_name##_register_type (type_module);			\
+										\
+	return plugin_loader_name##_get_type();					\
+}
+
+G_END_DECLS
+
+#endif /* __GEDIT_PLUGIN_LOADER_H__ */
+
+/* ex:ts=8:noet: */
diff --git a/gedit/gedit-plugin-manager.c b/gedit/gedit-plugin-manager.c
new file mode 100644
index 0000000..2071332
--- /dev/null
+++ b/gedit/gedit-plugin-manager.c
@@ -0,0 +1,895 @@
+/*
+ * gedit-plugin-manager.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2002 Paolo Maggi and James Willcox
+ * Copyright (C) 2003-2006 Paolo Maggi
+ *
+ * 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. 
+ */
+
+/*
+ * Modified by the gedit Team, 1998-2006. See the AUTHORS file for a 
+ * list of people on the gedit Team.  
+ * See the ChangeLog files for a list of changes. 
+ *
+ * $Id$
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+
+#include "gedit-plugin-manager.h"
+#include "gedit-utils.h"
+#include "gedit-plugins-engine.h"
+#include "gedit-plugin.h"
+#include "gedit-debug.h"
+
+enum
+{
+	ACTIVE_COLUMN,
+	AVAILABLE_COLUMN,
+	INFO_COLUMN,
+	N_COLUMNS
+};
+
+#define PLUGIN_MANAGER_NAME_TITLE _("Plugin")
+#define PLUGIN_MANAGER_ACTIVE_TITLE _("Enabled")
+
+#define GEDIT_PLUGIN_MANAGER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GEDIT_TYPE_PLUGIN_MANAGER, GeditPluginManagerPrivate))
+
+struct _GeditPluginManagerPrivate
+{
+	GeditPluginsEngine *engine;
+
+	GtkWidget          *tree;
+
+	GtkWidget          *about_button;
+	GtkWidget          *configure_button;
+
+	GtkWidget          *about;
+	
+	GtkWidget          *popup_menu;
+};
+
+G_DEFINE_TYPE(GeditPluginManager, gedit_plugin_manager, GTK_TYPE_VBOX)
+
+static GeditPluginInfo	*plugin_manager_get_selected_plugin	(GeditPluginManager *pm); 
+static void		 plugin_manager_toggle_active		(GeditPluginManager *pm,
+								 GtkTreeIter        *iter,
+								 GtkTreeModel       *model);
+static void		 gedit_plugin_manager_finalize		(GObject            *object);
+
+static void 
+gedit_plugin_manager_class_init (GeditPluginManagerClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = gedit_plugin_manager_finalize;
+
+	g_type_class_add_private (object_class, sizeof (GeditPluginManagerPrivate));
+}
+
+static void
+about_button_cb (GtkWidget          *button,
+		 GeditPluginManager *pm)
+{
+	GeditPluginInfo *info;
+
+	gedit_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", gedit_plugin_info_get_name (info),
+		"copyright", gedit_plugin_info_get_copyright (info),
+		"authors", gedit_plugin_info_get_authors (info),
+		"comments", gedit_plugin_info_get_description (info),
+		"website", gedit_plugin_info_get_website (info),
+		"logo-icon-name", gedit_plugin_info_get_icon_name (info),
+		"version", gedit_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,
+		     GeditPluginManager *pm)
+{
+	GeditPluginInfo *info;
+	GtkWindow *toplevel;
+
+	gedit_debug (DEBUG_PLUGINS);
+
+	info = plugin_manager_get_selected_plugin (pm);
+
+	g_return_if_fail (info != NULL);
+
+	gedit_debug_message (DEBUG_PLUGINS, "Configuring: %s\n", 
+			     gedit_plugin_info_get_name (info));
+
+	toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET(pm)));
+
+	gedit_plugins_engine_configure_plugin (pm->priv->engine,
+					       info, toplevel);
+
+	gedit_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)
+{
+	GeditPluginInfo *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",
+					gedit_plugin_info_get_name (info),
+					gedit_plugin_info_get_description (info));
+	g_object_set (G_OBJECT (cell),
+		      "markup", text,
+		      "sensitive", gedit_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)
+{
+	GeditPluginInfo *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", gedit_plugin_info_get_icon_name (info),
+		      "sensitive", gedit_plugin_info_is_available (info),
+		      NULL);
+}
+
+
+static void
+active_toggled_cb (GtkCellRendererToggle *cell,
+		   gchar                 *path_str,
+		   GeditPluginManager    *pm)
+{
+	GtkTreeIter iter;
+	GtkTreePath *path;
+	GtkTreeModel *model;
+
+	gedit_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,
+		   GeditPluginManager *pm)
+{
+	GeditPluginInfo *info;
+
+	gedit_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) && 
+				   gedit_plugin_info_is_configurable (info));
+}
+
+static void
+row_activated_cb (GtkTreeView        *tree_view,
+		  GtkTreePath        *path,
+		  GtkTreeViewColumn  *column,
+		  GeditPluginManager *pm)
+{
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+
+	gedit_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 (GeditPluginManager *pm)
+{
+	const GList *plugins;
+	GtkListStore *model;
+	GtkTreeIter iter;
+
+	gedit_debug (DEBUG_PLUGINS);
+
+	plugins = gedit_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)
+	{
+		GeditPluginInfo *info;
+		info = (GeditPluginInfo *)plugins->data;
+
+		gtk_list_store_append (model, &iter);
+		gtk_list_store_set (model, &iter,
+				    ACTIVE_COLUMN, gedit_plugin_info_is_active (info),
+				    AVAILABLE_COLUMN, gedit_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;
+		GeditPluginInfo* 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),
+					  gedit_plugin_info_is_configurable (info));
+	}
+}
+
+static gboolean
+plugin_manager_set_active (GeditPluginManager *pm,
+			   GtkTreeIter        *iter,
+			   GtkTreeModel       *model,
+			   gboolean            active)
+{
+	GeditPluginInfo *info;
+	gboolean res = TRUE;
+	
+	gedit_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 (!gedit_plugins_engine_activate_plugin (pm->priv->engine, info))
+		{
+			gedit_debug_message (DEBUG_PLUGINS, "Could not activate %s.\n", 
+					     gedit_plugin_info_get_name (info));
+
+			res = FALSE;
+		}
+	}
+	else
+	{
+		/* deactivate the plugin */
+		if (!gedit_plugins_engine_deactivate_plugin (pm->priv->engine, info))
+		{
+			gedit_debug_message (DEBUG_PLUGINS, "Could not deactivate %s.\n", 
+					     gedit_plugin_info_get_name (info));
+
+			res = FALSE;
+		}
+	}
+
+	/* cause the configure button sensitivity to be updated */
+	cursor_changed_cb (GTK_TREE_VIEW (pm->priv->tree), pm);
+
+	return res;
+}
+
+static void
+plugin_manager_toggle_active (GeditPluginManager *pm,
+			      GtkTreeIter        *iter,
+			      GtkTreeModel       *model)
+{
+	gboolean active;
+	
+	gedit_debug (DEBUG_PLUGINS);
+
+	gtk_tree_model_get (model, iter, ACTIVE_COLUMN, &active, -1);
+
+	active ^= 1;
+
+	plugin_manager_set_active (pm, iter, model, active);
+}
+
+static GeditPluginInfo *
+plugin_manager_get_selected_plugin (GeditPluginManager *pm)
+{
+	GeditPluginInfo *info = NULL;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	GtkTreeSelection *selection;
+
+	gedit_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 (GeditPluginManager *pm,
+			       gboolean            active)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+
+	gedit_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)
+{
+	GeditPluginInfo *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 (gedit_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,
+		       GeditPluginManager *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,
+		    GeditPluginManager *pm)
+{
+	plugin_manager_set_active_all (pm, TRUE);
+}
+
+static void
+disable_all_menu_cb (GtkMenu            *menu,
+		     GeditPluginManager *pm)
+{
+	plugin_manager_set_active_all (pm, FALSE);
+}
+
+static GtkWidget *
+create_tree_popup_menu (GeditPluginManager *pm)
+{
+	GtkWidget *menu;
+	GtkWidget *item;
+	GtkWidget *image;
+	GeditPluginInfo *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, gedit_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, gedit_plugin_info_is_available (info));
+	gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
+					gedit_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 (GeditPluginManager *pm,
+			GtkMenu            *menu)
+{
+	pm->priv->popup_menu = NULL;
+}
+
+static void
+show_tree_popup_menu (GtkTreeView        *tree,
+		      GeditPluginManager *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
+	{
+		gtk_menu_popup (GTK_MENU (pm->priv->popup_menu), NULL, NULL,
+				gedit_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,
+		       GeditPluginManager *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,
+	       GeditPluginManager *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)
+{
+	GeditPluginInfo *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 (gedit_plugin_info_get_name (info1),
+			       gedit_plugin_info_get_name (info2));
+}
+
+static void
+plugin_manager_construct_tree (GeditPluginManager *pm)
+{
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *cell;
+	GtkListStore *model;
+
+	gedit_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 (GeditPluginsEngine *engine,
+		   GeditPluginInfo    *info,
+		   GeditPluginManager *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! */
+		GeditPluginInfo *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
+		{
+			GeditPluginInfo *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 ("GeditPluginManager: plugin '%s' not found in the tree model",
+			   gedit_plugin_info_get_name (info));
+		return;
+	}
+
+	gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+			    ACTIVE_COLUMN, gedit_plugin_info_is_active (info),
+			    -1);
+}
+
+static void
+gedit_plugin_manager_init (GeditPluginManager *pm)
+{
+	GtkWidget *label;
+	GtkWidget *viewport;
+	GtkWidget *hbuttonbox;
+
+	gedit_debug (DEBUG_PLUGINS);
+
+	pm->priv = GEDIT_PLUGIN_MANAGER_GET_PRIVATE (pm);
+
+	/* Before we create the manager, we rescan the plugins directory */
+	gedit_plugins_engine_rescan_plugins (gedit_plugins_engine_get_default ());
+
+	gtk_box_set_spacing (GTK_BOX (pm), 6);
+
+	label = gtk_label_new_with_mnemonic (_("Active _Plugins:"));
+	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);
+	
+	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_box_pack_start (GTK_BOX (pm), viewport, TRUE, TRUE, 0);
+
+	pm->priv->tree = gtk_tree_view_new ();
+	gtk_container_add (GTK_CONTAINER (viewport), pm->priv->tree);
+
+	gtk_label_set_mnemonic_widget (GTK_LABEL (label), 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 = gedit_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 = gedit_gtk_button_new_with_stock_icon (_("C_onfigure Plugin"),
+									   GTK_STOCK_PREFERENCES);
+	gtk_container_add (GTK_CONTAINER (hbuttonbox), pm->priv->configure_button);
+
+	/* Set a sane size for the window */
+	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 = gedit_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 (gedit_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
+gedit_plugin_manager_finalize (GObject *object)
+{
+	GeditPluginManager *pm = GEDIT_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 (gedit_plugin_manager_parent_class)->finalize (object);
+
+}
+
+GtkWidget *gedit_plugin_manager_new (void)
+{
+	return g_object_new (GEDIT_TYPE_PLUGIN_MANAGER,0);
+}
+
+/* ex:ts=8:noet: */
diff --git a/gedit/gedit-plugin-manager.h b/gedit/gedit-plugin-manager.h
new file mode 100644
index 0000000..00963b2
--- /dev/null
+++ b/gedit/gedit-plugin-manager.h
@@ -0,0 +1,85 @@
+/*
+ * gedit-plugin-manager.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2002-2005 Paolo Maggi
+ *
+ * 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. 
+ */
+
+/*
+ * Modified by the gedit Team, 2002-2005. See the AUTHORS file for a 
+ * list of people on the gedit Team.  
+ * See the ChangeLog files for a list of changes. 
+ *
+ * $Id$
+ */
+
+#ifndef __GEDIT_PLUGIN_MANAGER_H__
+#define __GEDIT_PLUGIN_MANAGER_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+/*
+ * Type checking and casting macros
+ */
+#define GEDIT_TYPE_PLUGIN_MANAGER              (gedit_plugin_manager_get_type())
+#define GEDIT_PLUGIN_MANAGER(obj)              (G_TYPE_CHECK_INSTANCE_CAST((obj), GEDIT_TYPE_PLUGIN_MANAGER, GeditPluginManager))
+#define GEDIT_PLUGIN_MANAGER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), GEDIT_TYPE_PLUGIN_MANAGER, GeditPluginManagerClass))
+#define GEDIT_IS_PLUGIN_MANAGER(obj)           (G_TYPE_CHECK_INSTANCE_TYPE((obj), GEDIT_TYPE_PLUGIN_MANAGER))
+#define GEDIT_IS_PLUGIN_MANAGER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_PLUGIN_MANAGER))
+#define GEDIT_PLUGIN_MANAGER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS((obj), GEDIT_TYPE_PLUGIN_MANAGER, GeditPluginManagerClass))
+
+/* Private structure type */
+typedef struct _GeditPluginManagerPrivate GeditPluginManagerPrivate;
+
+/*
+ * Main object structure
+ */
+typedef struct _GeditPluginManager GeditPluginManager;
+
+struct _GeditPluginManager 
+{
+	GtkVBox vbox;
+
+	/*< private > */
+	GeditPluginManagerPrivate *priv;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _GeditPluginManagerClass GeditPluginManagerClass;
+
+struct _GeditPluginManagerClass 
+{
+	GtkVBoxClass parent_class;
+};
+
+/*
+ * Public methods
+ */
+GType		 gedit_plugin_manager_get_type		(void) G_GNUC_CONST;
+
+GtkWidget	*gedit_plugin_manager_new		(void);
+   
+G_END_DECLS
+
+#endif  /* __GEDIT_PLUGIN_MANAGER_H__  */
+
+/* ex:ts=8:noet: */
diff --git a/gedit/gedit-plugin.c b/gedit/gedit-plugin.c
new file mode 100644
index 0000000..d27896c
--- /dev/null
+++ b/gedit/gedit-plugin.c
@@ -0,0 +1,339 @@
+/*
+ * gedit-plugin.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2002-2005 Paolo Maggi 
+ *
+ * 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. 
+ */
+ 
+/*
+ * Modified by the gedit Team, 2002-2005. See the AUTHORS file for a 
+ * list of people on the gedit Team.  
+ * See the ChangeLog files for a list of changes. 
+ *
+ * $Id$
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gedit-plugin.h"
+#include "gedit-dirs.h"
+
+/* properties */
+enum {
+	PROP_0,
+	PROP_INSTALL_DIR,
+	PROP_DATA_DIR_NAME,
+	PROP_DATA_DIR
+};
+
+typedef struct _GeditPluginPrivate GeditPluginPrivate;
+
+struct _GeditPluginPrivate
+{
+	gchar *install_dir;
+	gchar *data_dir_name;
+};
+
+#define GEDIT_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GEDIT_TYPE_PLUGIN, GeditPluginPrivate))
+
+G_DEFINE_TYPE(GeditPlugin, gedit_plugin, G_TYPE_OBJECT)
+
+static void
+dummy (GeditPlugin *plugin,
+       GeditWindow *window)
+{
+	/* Empty */
+}
+
+static GtkWidget *
+create_configure_dialog	(GeditPlugin *plugin)
+{
+	return NULL;
+}
+
+static gboolean
+is_configurable (GeditPlugin *plugin)
+{
+	return (GEDIT_PLUGIN_GET_CLASS (plugin)->create_configure_dialog !=
+		create_configure_dialog);
+}
+
+static void
+gedit_plugin_get_property (GObject    *object,
+			   guint       prop_id,
+			   GValue     *value,
+			   GParamSpec *pspec)
+{
+	switch (prop_id)
+	{
+		case PROP_INSTALL_DIR:
+			g_value_take_string (value, gedit_plugin_get_install_dir (GEDIT_PLUGIN (object)));
+			break;
+		case PROP_DATA_DIR:
+			g_value_take_string (value, gedit_plugin_get_data_dir (GEDIT_PLUGIN (object)));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+gedit_plugin_set_property (GObject      *object,
+			   guint         prop_id,
+			   const GValue *value,
+			   GParamSpec   *pspec)
+{
+	GeditPluginPrivate *priv = GEDIT_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_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+gedit_plugin_finalize (GObject *object)
+{
+	GeditPluginPrivate *priv = GEDIT_PLUGIN_GET_PRIVATE (object);
+
+	g_free (priv->install_dir);
+	g_free (priv->data_dir_name);
+
+	G_OBJECT_CLASS (gedit_plugin_parent_class)->finalize (object);
+}
+
+static void 
+gedit_plugin_class_init (GeditPluginClass *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 = gedit_plugin_get_property;
+	object_class->set_property = gedit_plugin_set_property;
+	object_class->finalize = gedit_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 (GeditPluginPrivate));
+}
+
+static void
+gedit_plugin_init (GeditPlugin *plugin)
+{
+	/* Empty */
+}
+
+/**
+ * gedit_plugin_get_install_dir:
+ * @plugin: a #GeditPlugin
+ *
+ * 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 *
+gedit_plugin_get_install_dir (GeditPlugin *plugin)
+{
+	g_return_val_if_fail (GEDIT_IS_PLUGIN (plugin), NULL);
+
+	return g_strdup (GEDIT_PLUGIN_GET_PRIVATE (plugin)->install_dir);
+}
+
+/**
+ * gedit_plugin_get_data_dir:
+ * @plugin: a #GeditPlugin
+ *
+ * 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 *
+gedit_plugin_get_data_dir (GeditPlugin *plugin)
+{
+	GeditPluginPrivate *priv;
+	gchar *gedit_lib_dir;
+	gchar *data_dir;
+
+	g_return_val_if_fail (GEDIT_IS_PLUGIN (plugin), NULL);
+
+	priv = GEDIT_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 gedit_data_dir,
+	 * so it's under $prefix/share/gedit-2/plugins/data_dir_name
+	 * where data_dir_name usually it's the name of the plugin
+	 */
+	gedit_lib_dir = gedit_dirs_get_gedit_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, gedit_lib_dir))
+	{
+		gchar *gedit_data_dir;
+
+		gedit_data_dir = gedit_dirs_get_gedit_data_dir ();
+
+		data_dir = g_build_filename (gedit_data_dir,
+					     "plugins",
+					     priv->data_dir_name,
+					     NULL);
+
+		g_free (gedit_data_dir);
+	}
+	else
+	{
+		data_dir = g_build_filename (priv->install_dir,
+					     priv->data_dir_name,
+					     NULL);
+	}
+
+	g_free (gedit_lib_dir);
+
+	return data_dir;
+}
+
+/**
+ * gedit_plugin_activate:
+ * @plugin: a #GeditPlugin
+ * @window: a #GeditWindow
+ * 
+ * Activates the plugin.
+ */
+void
+gedit_plugin_activate (GeditPlugin *plugin,
+		       GeditWindow *window)
+{
+	g_return_if_fail (GEDIT_IS_PLUGIN (plugin));
+	g_return_if_fail (GEDIT_IS_WINDOW (window));
+	
+	GEDIT_PLUGIN_GET_CLASS (plugin)->activate (plugin, window);
+}
+
+/**
+ * gedit_plugin_deactivate:
+ * @plugin: a #GeditPlugin
+ * @window: a #GeditWindow
+ * 
+ * Deactivates the plugin.
+ */
+void
+gedit_plugin_deactivate	(GeditPlugin *plugin,
+			 GeditWindow *window)
+{
+	g_return_if_fail (GEDIT_IS_PLUGIN (plugin));
+	g_return_if_fail (GEDIT_IS_WINDOW (window));
+
+	GEDIT_PLUGIN_GET_CLASS (plugin)->deactivate (plugin, window);
+}
+
+/**
+ * gedit_plugin_update_ui:
+ * @plugin: a #GeditPlugin
+ * @window: a #GeditWindow
+ *
+ * Triggers an update of the user interface to take into account state changes
+ * caused by the plugin.
+ */		 
+void
+gedit_plugin_update_ui	(GeditPlugin *plugin,
+			 GeditWindow *window)
+{
+	g_return_if_fail (GEDIT_IS_PLUGIN (plugin));
+	g_return_if_fail (GEDIT_IS_WINDOW (window));
+
+	GEDIT_PLUGIN_GET_CLASS (plugin)->update_ui (plugin, window);
+}
+
+/**
+ * gedit_plugin_is_configurable:
+ * @plugin: a #GeditPlugin
+ *
+ * Whether the plugin is configurable.
+ *
+ * Returns: TRUE if the plugin is configurable:
+ */
+gboolean
+gedit_plugin_is_configurable (GeditPlugin *plugin)
+{
+	g_return_val_if_fail (GEDIT_IS_PLUGIN (plugin), FALSE);
+
+	return GEDIT_PLUGIN_GET_CLASS (plugin)->is_configurable (plugin);
+}
+
+/**
+ * gedit_plugin_create_configure_dialog:
+ * @plugin: a #GeditPlugin
+ *
+ * Creates the configure dialog widget for the plugin.
+ *
+ * Returns: the configure dialog widget for the plugin.
+ */
+GtkWidget *
+gedit_plugin_create_configure_dialog (GeditPlugin *plugin)
+{
+	g_return_val_if_fail (GEDIT_IS_PLUGIN (plugin), NULL);
+	
+	return GEDIT_PLUGIN_GET_CLASS (plugin)->create_configure_dialog (plugin);
+}
+
+/* ex:ts=8:noet: */
diff --git a/gedit/gedit-plugin.h b/gedit/gedit-plugin.h
new file mode 100644
index 0000000..87f06d3
--- /dev/null
+++ b/gedit/gedit-plugin.h
@@ -0,0 +1,242 @@
+/*
+ * gedit-plugin.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2002-2005 - Paolo Maggi 
+ *
+ * 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. 
+ */
+ 
+/*
+ * Modified by the gedit Team, 2002-2005. See the AUTHORS file for a 
+ * list of people on the gedit Team.  
+ * See the ChangeLog files for a list of changes. 
+ *
+ * $Id$
+ */
+
+#ifndef __GEDIT_PLUGIN_H__
+#define __GEDIT_PLUGIN_H__
+
+#include <glib-object.h>
+
+#include <gedit/gedit-window.h>
+#include <gedit/gedit-debug.h>
+
+/* TODO: add a .h file that includes all the .h files normally needed to
+ * develop a plugin */ 
+
+G_BEGIN_DECLS
+
+/*
+ * Type checking and casting macros
+ */
+#define GEDIT_TYPE_PLUGIN              (gedit_plugin_get_type())
+#define GEDIT_PLUGIN(obj)              (G_TYPE_CHECK_INSTANCE_CAST((obj), GEDIT_TYPE_PLUGIN, GeditPlugin))
+#define GEDIT_PLUGIN_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), GEDIT_TYPE_PLUGIN, GeditPluginClass))
+#define GEDIT_IS_PLUGIN(obj)           (G_TYPE_CHECK_INSTANCE_TYPE((obj), GEDIT_TYPE_PLUGIN))
+#define GEDIT_IS_PLUGIN_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_PLUGIN))
+#define GEDIT_PLUGIN_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS((obj), GEDIT_TYPE_PLUGIN, GeditPluginClass))
+
+/*
+ * Main object structure
+ */
+typedef struct _GeditPlugin GeditPlugin;
+
+struct _GeditPlugin 
+{
+	GObject parent;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _GeditPluginClass GeditPluginClass;
+
+struct _GeditPluginClass 
+{
+	GObjectClass parent_class;
+
+	/* Virtual public methods */
+	
+	void 		(*activate)		(GeditPlugin *plugin,
+						 GeditWindow *window);
+	void 		(*deactivate)		(GeditPlugin *plugin,
+						 GeditWindow *window);
+
+	void 		(*update_ui)		(GeditPlugin *plugin,
+						 GeditWindow *window);
+
+	GtkWidget 	*(*create_configure_dialog)
+						(GeditPlugin *plugin);
+
+	/* Plugins should not override this, it's handled automatically by
+	   the GeditPluginClass */
+	gboolean 	(*is_configurable)
+						(GeditPlugin *plugin);
+
+	/* Padding for future expansion */
+	void		(*_gedit_reserved1)	(void);
+	void		(*_gedit_reserved2)	(void);
+	void		(*_gedit_reserved3)	(void);
+	void		(*_gedit_reserved4)	(void);
+};
+
+/*
+ * Public methods
+ */
+GType 		 gedit_plugin_get_type 		(void) G_GNUC_CONST;
+
+gchar 		*gedit_plugin_get_install_dir	(GeditPlugin *plugin);
+gchar 		*gedit_plugin_get_data_dir	(GeditPlugin *plugin);
+
+void 		 gedit_plugin_activate		(GeditPlugin *plugin,
+						 GeditWindow *window);
+void 		 gedit_plugin_deactivate	(GeditPlugin *plugin,
+						 GeditWindow *window);
+				 
+void 		 gedit_plugin_update_ui		(GeditPlugin *plugin,
+						 GeditWindow *window);
+
+gboolean	 gedit_plugin_is_configurable	(GeditPlugin *plugin);
+GtkWidget	*gedit_plugin_create_configure_dialog		
+						(GeditPlugin *plugin);
+
+/**
+ * GEDIT_PLUGIN_REGISTER_TYPE_WITH_CODE(PluginName, plugin_name, CODE):
+ *
+ * Utility macro used to register plugins with additional code.
+ */
+#define GEDIT_PLUGIN_REGISTER_TYPE_WITH_CODE(PluginName, plugin_name, CODE) 	\
+	G_DEFINE_DYNAMIC_TYPE_EXTENDED (PluginName,				\
+					plugin_name,				\
+					GEDIT_TYPE_PLUGIN,			\
+					0,					\
+					GTypeModule *module G_GNUC_UNUSED = type_module; /* back compat */	\
+					CODE)					\
+										\
+/* This is not very nice, but G_DEFINE_DYNAMIC wants it and our old macro	\
+ * did not support it */							\
+static void									\
+plugin_name##_class_finalize (PluginName##Class *klass)				\
+{										\
+}										\
+										\
+										\
+G_MODULE_EXPORT GType								\
+register_gedit_plugin (GTypeModule *type_module)				\
+{										\
+	plugin_name##_register_type (type_module);				\
+										\
+	return plugin_name##_get_type();					\
+}
+
+/**
+ * GEDIT_PLUGIN_REGISTER_TYPE(PluginName, plugin_name):
+ * 
+ * Utility macro used to register plugins.
+ */
+#define GEDIT_PLUGIN_REGISTER_TYPE(PluginName, plugin_name)			\
+	GEDIT_PLUGIN_REGISTER_TYPE_WITH_CODE(PluginName, plugin_name, ;)
+
+/**
+ * GEDIT_PLUGIN_DEFINE_TYPE_WITH_CODE(ObjectName, object_name, PARENT_TYPE, CODE):
+ *
+ * Utility macro used to register gobject types in plugins with additional code.
+ *
+ * Deprecated: use G_DEFINE_DYNAMIC_TYPE_EXTENDED instead
+ */
+#define GEDIT_PLUGIN_DEFINE_TYPE_WITH_CODE(ObjectName, object_name, PARENT_TYPE, CODE) \
+										\
+static GType g_define_type_id = 0;						\
+										\
+GType										\
+object_name##_get_type (void)							\
+{										\
+	return g_define_type_id;						\
+}										\
+										\
+static void     object_name##_init              (ObjectName        *self);	\
+static void     object_name##_class_init        (ObjectName##Class *klass);	\
+static gpointer object_name##_parent_class = NULL;				\
+static void     object_name##_class_intern_init (gpointer klass)		\
+{										\
+	object_name##_parent_class = g_type_class_peek_parent (klass);		\
+	object_name##_class_init ((ObjectName##Class *) klass);			\
+}										\
+										\
+GType										\
+object_name##_register_type (GTypeModule *type_module)				\
+{										\
+	GTypeModule *module G_GNUC_UNUSED = type_module; /* back compat */			\
+	static const GTypeInfo our_info =					\
+	{									\
+		sizeof (ObjectName##Class),					\
+		NULL, /* base_init */						\
+		NULL, /* base_finalize */					\
+		(GClassInitFunc) object_name##_class_intern_init,		\
+		NULL,								\
+		NULL, /* class_data */						\
+		sizeof (ObjectName),						\
+		0, /* n_preallocs */						\
+		(GInstanceInitFunc) object_name##_init				\
+	};									\
+										\
+	g_define_type_id = g_type_module_register_type (type_module,		\
+					   	        PARENT_TYPE,		\
+					                #ObjectName,		\
+					                &our_info,		\
+					                0);			\
+										\
+	CODE									\
+										\
+	return g_define_type_id;						\
+}
+
+
+/**
+ * GEDIT_PLUGIN_DEFINE_TYPE(ObjectName, object_name, PARENT_TYPE):
+ *
+ * Utility macro used to register gobject types in plugins.
+ *
+ * Deprecated: use G_DEFINE_DYNAMIC instead
+ */
+#define GEDIT_PLUGIN_DEFINE_TYPE(ObjectName, object_name, PARENT_TYPE)		\
+	GEDIT_PLUGIN_DEFINE_TYPE_WITH_CODE(ObjectName, object_name, PARENT_TYPE, ;)
+
+/**
+ * GEDIT_PLUGIN_IMPLEMENT_INTERFACE(TYPE_IFACE, iface_init):
+ *
+ * Utility macro used to register interfaces for gobject types in plugins.
+ */
+#define GEDIT_PLUGIN_IMPLEMENT_INTERFACE(object_name, TYPE_IFACE, iface_init)	\
+	const GInterfaceInfo object_name##_interface_info = 			\
+	{ 									\
+		(GInterfaceInitFunc) iface_init,				\
+		NULL, 								\
+		NULL								\
+	};									\
+										\
+	g_type_module_add_interface (type_module, 					\
+				     g_define_type_id, 				\
+				     TYPE_IFACE, 				\
+				     &object_name##_interface_info);
+
+G_END_DECLS
+
+#endif  /* __GEDIT_PLUGIN_H__ */
+
+/* ex:ts=8:noet: */
diff --git a/gedit/gedit-plugins-engine.c b/gedit/gedit-plugins-engine.c
index 3d9a6e2..8902662 100644
--- a/gedit/gedit-plugins-engine.c
+++ b/gedit/gedit-plugins-engine.c
@@ -3,7 +3,6 @@
  * This file is part of gedit
  *
  * Copyright (C) 2002-2005 Paolo Maggi 
- * Copyright (C) 2010 Steve Frécinaux
  *
  * 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
@@ -36,11 +35,14 @@
 #include <string.h>
 
 #include <glib/gi18n.h>
-#include <girepository.h>
 
 #include "gedit-plugins-engine.h"
+#include "gedit-plugin-info-priv.h"
+#include "gedit-plugin.h"
 #include "gedit-debug.h"
 #include "gedit-app.h"
+#include "gedit-plugin-loader.h"
+#include "gedit-object-module.h"
 #include "gedit-dirs.h"
 #include "gedit-settings.h"
 #include "gedit-utils.h"
@@ -48,152 +50,852 @@
 #define GEDIT_PLUGINS_ENGINE_BASE_KEY "/apps/gedit-2/plugins"
 #define GEDIT_PLUGINS_ENGINE_KEY GEDIT_PLUGINS_ENGINE_BASE_KEY "/active-plugins"
 
-G_DEFINE_TYPE(GeditPluginsEngine, gedit_plugins_engine, PEAS_TYPE_ENGINE)
+#define PLUGIN_EXT	".gedit-plugin"
+#define LOADER_EXT	G_MODULE_SUFFIX
+
+typedef struct
+{
+	GeditPluginLoader *loader;
+	GeditObjectModule *module;
+} LoaderInfo;
+
+/* Signals */
+enum
+{
+	ACTIVATE_PLUGIN,
+	DEACTIVATE_PLUGIN,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE(GeditPluginsEngine, gedit_plugins_engine, G_TYPE_OBJECT)
 
 struct _GeditPluginsEnginePrivate
 {
 	GSettings *plugin_settings;
-	gboolean setting_active_plugins;
+
+	GList *plugin_list;
+	GHashTable *loaders;
+
+	gboolean activate_from_prefs;
+	
+	guint scanned : 1;
 };
 
 GeditPluginsEngine *default_engine = NULL;
 
-static void
-gedit_plugins_engine_init (GeditPluginsEngine *engine)
+static void	gedit_plugins_engine_activate_plugin_real	(GeditPluginsEngine *engine,
+								 GeditPluginInfo    *info);
+static void	gedit_plugins_engine_deactivate_plugin_real	(GeditPluginsEngine *engine,
+								 GeditPluginInfo    *info);
+
+typedef gboolean (*LoadDirCallback)(GeditPluginsEngine *engine, const gchar *filename, gpointer userdata);
+
+static gboolean
+load_dir_real (GeditPluginsEngine *engine,
+	       const gchar        *dir,
+	       const gchar        *suffix,
+	       LoadDirCallback     callback,
+	       gpointer            userdata)
 {
-	gedit_debug (DEBUG_PLUGINS);
+	GError *error = NULL;
+	GDir *d;
+	const gchar *dirent;
+	gboolean ret = TRUE;
 
-	engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine,
-						    GEDIT_TYPE_PLUGINS_ENGINE,
-						    GeditPluginsEnginePrivate);
+	g_return_val_if_fail (dir != NULL, TRUE);
 
-	engine->priv->plugin_settings = g_settings_new ("org.gnome.gedit.plugins");
+	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);
 
-	engine->priv->setting_active_plugins = FALSE;
+		if (!ret)
+			break;
+	}
+
+	g_dir_close (d);
+	return ret;
 }
 
-static void
-save_active_plugin_list (PeasEngine *engine)
+static gboolean
+load_plugin_info (GeditPluginsEngine *engine,
+		  const gchar        *filename,
+		  gpointer            userdata)
 {
-	GeditPluginsEngine *gengine = GEDIT_PLUGINS_ENGINE (engine);
-	gchar **active_plugins;
+	GeditPluginInfo *info;
+	
+	info = _gedit_plugin_info_new (filename);
+
+	if (info == NULL)
+		return TRUE;
 
-	active_plugins = peas_engine_get_active_plugins (engine);
+	/* If a plugin with this name has already been loaded
+	 * drop this one (user plugins override system plugins) */
+	if (gedit_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));
 
-	g_settings_set_strv (gengine->priv->plugin_settings,
-			     GEDIT_SETTINGS_ACTIVE_PLUGINS,
-			     (const gchar * const *) active_plugins);
+		_gedit_plugin_info_unref (info);
 
-	g_strfreev (active_plugins);
+		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
-gedit_plugins_engine_activate_plugin (PeasEngine     *engine,
-				      PeasPluginInfo *info)
+load_all_plugins (GeditPluginsEngine *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 ("GEDIT_PLUGINS_PATH");
+
+	gedit_debug_message (DEBUG_PLUGINS, "GEDIT_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_gedit_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)
 {
-	PEAS_ENGINE_CLASS (gedit_plugins_engine_parent_class)->activate_plugin (engine, info);
+	return g_ascii_strcasecmp ((const gchar *)a, (const gchar *)b) == 0;
+}
 
-	/* We won't save the plugin list if we are currently activating the
-	 * plugins from the saved list */
-	if (GEDIT_PLUGINS_ENGINE (engine)->priv->setting_active_plugins)
+static void
+loader_destroy (LoaderInfo *info)
+{
+	if (!info)
 		return;
+	
+	if (info->loader)
+		g_object_unref (info->loader);
+	
+	g_free (info);
+}
 
-	if (peas_plugin_info_is_active (info))
-		save_active_plugin_list (engine);
+static void
+add_loader (GeditPluginsEngine *engine,
+	    const gchar        *loader_id,
+	    GeditObjectModule  *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
-gedit_plugins_engine_deactivate_plugin (PeasEngine     *engine,
-					PeasPluginInfo *info)
+gedit_plugins_engine_init (GeditPluginsEngine *engine)
 {
-	PEAS_ENGINE_CLASS (gedit_plugins_engine_parent_class)->deactivate_plugin (engine, info);
+	gedit_debug (DEBUG_PLUGINS);
 
-	/* We won't save the plugin list if we are currently deactivating the
-	 * plugins from the saved list */
-	if (GEDIT_PLUGINS_ENGINE (engine)->priv->setting_active_plugins)
+	if (!g_module_supported ())
+	{
+		g_warning ("gedit is not able to initialize the plugins engine.");
 		return;
+	}
 
-	if (!peas_plugin_info_is_active (info))
-		save_active_plugin_list (engine);
+	engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine,
+						    GEDIT_TYPE_PLUGINS_ENGINE,
+						    GeditPluginsEnginePrivate);
+
+	engine->priv->plugin_settings = g_settings_new ("org.gnome.gedit.plugins");
+
+	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
+gedit_plugins_engine_garbage_collect (GeditPluginsEngine *engine)
+{
+	g_hash_table_foreach (engine->priv->loaders,
+			      (GHFunc) loader_garbage_collect,
+			      NULL);
 }
 
 static void
 gedit_plugins_engine_finalize (GObject *object)
 {
+	GeditPluginsEngine *engine = GEDIT_PLUGINS_ENGINE (object);
+	GList *item;
+	
 	gedit_debug (DEBUG_PLUGINS);
 
+	/* Firs deactivate all plugins */
+	for (item = engine->priv->plugin_list; item; item = item->next)
+	{
+		GeditPluginInfo *info = GEDIT_PLUGIN_INFO (item->data);
+		
+		if (gedit_plugin_info_is_active (info))
+			gedit_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)
+	{
+		GeditPluginInfo *info = GEDIT_PLUGIN_INFO (item->data);
+
+		_gedit_plugin_info_unref (info);
+	}
+
+	g_list_free (engine->priv->plugin_list);
+
 	G_OBJECT_CLASS (gedit_plugins_engine_parent_class)->finalize (object);
 }
 
 static void
+gedit_plugins_engine_dispose (GObject *object)
+{
+	GeditPluginsEngine *engine = GEDIT_PLUGINS_ENGINE (object);
+	
+	if (engine->priv->plugin_settings != NULL)
+	{
+		g_object_unref (engine->priv->plugin_settings);
+		engine->priv->plugin_settings = NULL;
+	}
+	
+	G_OBJECT_CLASS (gedit_plugins_engine_parent_class)->dispose (object);
+}
+
+static void
 gedit_plugins_engine_class_init (GeditPluginsEngineClass *klass)
 {
+	GType the_type = G_TYPE_FROM_CLASS (klass);
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-	PeasEngineClass *engine_class = PEAS_ENGINE_CLASS (klass);
 
 	object_class->finalize = gedit_plugins_engine_finalize;
-	engine_class->activate_plugin = gedit_plugins_engine_activate_plugin;
-	engine_class->deactivate_plugin = gedit_plugins_engine_deactivate_plugin;
+	object_class->dispose = gedit_plugins_engine_dispose;
+	klass->activate_plugin = gedit_plugins_engine_activate_plugin_real;
+	klass->deactivate_plugin = gedit_plugins_engine_deactivate_plugin_real;
+
+	signals[ACTIVATE_PLUGIN] =
+		g_signal_new ("activate-plugin",
+			      the_type,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GeditPluginsEngineClass, activate_plugin),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__BOXED,
+			      G_TYPE_NONE,
+			      1,
+			      GEDIT_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 (GeditPluginsEngineClass, deactivate_plugin),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__BOXED,
+			      G_TYPE_NONE,
+			      1,
+			      GEDIT_TYPE_PLUGIN_INFO | G_SIGNAL_TYPE_STATIC_SCOPE);
 
 	g_type_class_add_private (klass, sizeof (GeditPluginsEnginePrivate));
 }
 
+static gboolean
+load_loader (GeditPluginsEngine *engine,
+	     const gchar        *filename,
+	     gpointer		 data)
+{
+	GeditObjectModule *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 */
+		GeditPluginLoader *loader;
+		loader = (GeditPluginLoader *)gedit_object_module_new_object (info->module, NULL);
+	
+		if (loader == NULL || !GEDIT_IS_PLUGIN_LOADER (loader))
+		{
+			g_warning ("Loader object is not a valid GeditPluginLoader instance");
+		
+			if (loader != NULL && G_IS_OBJECT (loader))
+				g_object_unref (loader);
+		}
+		else
+		{
+			info->loader = loader;
+		}
+	}
+}
+
+static GeditPluginLoader *
+get_plugin_loader (GeditPluginsEngine *engine,
+		   GeditPluginInfo    *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 && !engine->priv->scanned)
+	{
+		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);
+
+		engine->priv->scanned = TRUE;
+	}
+
+	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;
+}
+
 GeditPluginsEngine *
 gedit_plugins_engine_get_default (void)
 {
-	gchar *modules_dir;
-	gchar **search_paths;
-
 	if (default_engine != NULL)
 		return default_engine;
 
-	/* This should be moved to libpeas */
-	g_irepository_require (g_irepository_get_default (),
-			       "Peas", "1.0", 0, NULL);
-	g_irepository_require (g_irepository_get_default (),
-			       "PeasUI", "1.0", 0, NULL);
-
-	modules_dir = gedit_dirs_get_binding_modules_dir ();
-	search_paths = g_new (gchar *, 5);
-	/* Add the user plugins dir in ~ */
-	search_paths[0] = gedit_dirs_get_user_plugins_dir ();
-	search_paths[1] = gedit_dirs_get_user_plugins_dir ();
-	/* Add the system plugins dir */
-	search_paths[2] = gedit_dirs_get_gedit_plugins_dir ();
-	search_paths[3] = gedit_dirs_get_gedit_plugins_data_dir ();
-	/* Add the trailing NULL */
-	search_paths[4] = NULL;
-
-	default_engine = GEDIT_PLUGINS_ENGINE (g_object_new (GEDIT_TYPE_PLUGINS_ENGINE,
-							     "app-name", "Gedit",
-							     "base-module-dir", modules_dir,
-							     "search-paths", search_paths,
-							     NULL));
-
-	g_strfreev (search_paths);
-	g_free (modules_dir);
-
+	default_engine = GEDIT_PLUGINS_ENGINE (g_object_new (GEDIT_TYPE_PLUGINS_ENGINE, NULL));
 	g_object_add_weak_pointer (G_OBJECT (default_engine),
 				   (gpointer) &default_engine);
+	return default_engine;
+}
 
-	gedit_plugins_engine_active_plugins_changed (default_engine);
+const GList *
+gedit_plugins_engine_get_plugin_list (GeditPluginsEngine *engine)
+{
+	gedit_debug (DEBUG_PLUGINS);
 
-	return default_engine;
+	return engine->priv->plugin_list;
+}
+
+static gint
+compare_plugin_info_and_name (GeditPluginInfo *info,
+			      const gchar     *module_name)
+{
+	return strcmp (gedit_plugin_info_get_module_name (info), module_name);
+}
+
+GeditPluginInfo *
+gedit_plugins_engine_get_plugin_info (GeditPluginsEngine *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 : (GeditPluginInfo *) l->data;
+}
+
+static void
+save_active_plugin_list (GeditPluginsEngine *engine)
+{
+	GSList *active_plugins = NULL;
+	GList *l;
+
+	for (l = engine->priv->plugin_list; l != NULL; l = l->next)
+	{
+		GeditPluginInfo *info = (GeditPluginInfo *) 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_settings_set_list (engine->priv->plugin_settings,
+				 GEDIT_SETTINGS_ACTIVE_PLUGINS,
+				 active_plugins);
+
+	g_slist_free (active_plugins);
+}
+
+static gboolean
+load_plugin (GeditPluginsEngine *engine,
+	     GeditPluginInfo    *info)
+{
+	GeditPluginLoader *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
+gedit_plugins_engine_activate_plugin_real (GeditPluginsEngine *engine,
+					   GeditPluginInfo    *info)
+{
+	const GList *wins;
+
+	if (!load_plugin (engine, info))
+		return;
+
+	for (wins = gedit_app_get_windows (gedit_app_get_default ());
+	     wins != NULL;
+	     wins = wins->next)
+	{
+		gedit_plugin_activate (info->plugin, GEDIT_WINDOW (wins->data));
+	}
+}
+
+gboolean
+gedit_plugins_engine_activate_plugin (GeditPluginsEngine *engine,
+				      GeditPluginInfo    *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 (GeditPlugin *plugin, 
+			GeditWindow *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
+gedit_plugins_engine_deactivate_plugin_real (GeditPluginsEngine *engine,
+					     GeditPluginInfo    *info)
+{
+	const GList *wins;
+	GeditPluginLoader *loader;
+
+	if (!gedit_plugin_info_is_active (info) || 
+	    !gedit_plugin_info_is_available (info))
+		return;
+
+	for (wins = gedit_app_get_windows (gedit_app_get_default ());
+	     wins != NULL;
+	     wins = wins->next)
+	{
+		call_plugin_deactivate (info->plugin, GEDIT_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
+gedit_plugins_engine_deactivate_plugin (GeditPluginsEngine *engine,
+					GeditPluginInfo    *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
+gedit_plugins_engine_activate_plugins (GeditPluginsEngine *engine,
+					GeditWindow       *window)
+{
+	GSList *active_plugins = NULL;
+	GList *pl;
+
+	gedit_debug (DEBUG_PLUGINS);
+
+	g_return_if_fail (GEDIT_IS_PLUGINS_ENGINE (engine));
+	g_return_if_fail (GEDIT_IS_WINDOW (window));
+
+	/* the first time, we get the 'active' plugins from gconf */
+	if (engine->priv->activate_from_prefs)
+	{
+		active_plugins = gedit_settings_get_list (engine->priv->plugin_settings,
+							  GEDIT_SETTINGS_ACTIVE_PLUGINS);
+	}
+
+	for (pl = engine->priv->plugin_list; pl; pl = pl->next)
+	{
+		GeditPluginInfo *info = (GeditPluginInfo*)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 */
+	gedit_plugins_engine_update_plugins_ui (engine, window);
+}
+
+void
+gedit_plugins_engine_deactivate_plugins (GeditPluginsEngine *engine,
+					  GeditWindow       *window)
+{
+	GList *pl;
+	
+	gedit_debug (DEBUG_PLUGINS);
+
+	g_return_if_fail (GEDIT_IS_PLUGINS_ENGINE (engine));
+	g_return_if_fail (GEDIT_IS_WINDOW (window));
+	
+	for (pl = engine->priv->plugin_list; pl; pl = pl->next)
+	{
+		GeditPluginInfo *info = (GeditPluginInfo*)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
+gedit_plugins_engine_update_plugins_ui (GeditPluginsEngine *engine,
+					 GeditWindow       *window)
+{
+	GList *pl;
+
+	gedit_debug (DEBUG_PLUGINS);
+
+	g_return_if_fail (GEDIT_IS_PLUGINS_ENGINE (engine));
+	g_return_if_fail (GEDIT_IS_WINDOW (window));
+
+	/* call update_ui for all active plugins */
+	for (pl = engine->priv->plugin_list; pl; pl = pl->next)
+	{
+		GeditPluginInfo *info = (GeditPluginInfo*)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 	 
+gedit_plugins_engine_configure_plugin (GeditPluginsEngine *engine,
+				       GeditPluginInfo    *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);
+
+	if (gtk_window_has_group (parent))
+	{
+		wg = gtk_window_get_group (parent);
+	}
+	else
+	{
+		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 
 gedit_plugins_engine_active_plugins_changed (GeditPluginsEngine *engine)
 {
-	gchar **active_plugins;
+	gboolean to_activate;
+	GSList *active_plugins;
+	GList *pl;
 
-        active_plugins = g_settings_get_strv (engine->priv->plugin_settings,
-					      GEDIT_SETTINGS_ACTIVE_PLUGINS);
+	gedit_debug (DEBUG_PLUGINS);
+
+	active_plugins = gedit_settings_get_list (engine->priv->plugin_settings,
+						  GEDIT_SETTINGS_ACTIVE_PLUGINS);
+
+	for (pl = engine->priv->plugin_list; pl; pl = pl->next)
+	{
+		GeditPluginInfo *info = (GeditPluginInfo*)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);
+	}
 
-	engine->priv->setting_active_plugins = TRUE;
-	peas_engine_set_active_plugins (PEAS_ENGINE (engine),
-					(const gchar **) active_plugins);
-	engine->priv->setting_active_plugins = FALSE;
-	g_strfreev (active_plugins);
+	g_slist_foreach (active_plugins, (GFunc) g_free, NULL);
+	g_slist_free (active_plugins);
+}
+
+void
+gedit_plugins_engine_rescan_plugins (GeditPluginsEngine *engine)
+{
+	gedit_debug (DEBUG_PLUGINS);
+	
+	load_all_plugins (engine);
 }
 
-/* ex:set ts=8 noet: */
+/* ex:ts=8:noet: */
diff --git a/gedit/gedit-plugins-engine.h b/gedit/gedit-plugins-engine.h
index dba35f4..0ebb7f2 100644
--- a/gedit/gedit-plugins-engine.h
+++ b/gedit/gedit-plugins-engine.h
@@ -3,7 +3,6 @@
  * This file is part of gedit
  *
  * Copyright (C) 2002-2005 - Paolo Maggi 
- * Copyright (C) 2010 - Steve Frécinaux
  *
  * 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
@@ -33,7 +32,9 @@
 #define __GEDIT_PLUGINS_ENGINE_H__
 
 #include <glib.h>
-#include <libpeas/peas-engine.h>
+#include "gedit-window.h"
+#include "gedit-plugin-info.h"
+#include "gedit-plugin.h"
 
 G_BEGIN_DECLS
 
@@ -49,7 +50,7 @@ typedef struct _GeditPluginsEnginePrivate	GeditPluginsEnginePrivate;
 
 struct _GeditPluginsEngine
 {
-	PeasEngine parent;
+	GObject parent;
 	GeditPluginsEnginePrivate *priv;
 };
 
@@ -57,16 +58,50 @@ typedef struct _GeditPluginsEngineClass		GeditPluginsEngineClass;
 
 struct _GeditPluginsEngineClass
 {
-	PeasEngineClass parent_class;
+	GObjectClass parent_class;
+
+	void	 (* activate_plugin)		(GeditPluginsEngine *engine,
+						 GeditPluginInfo    *info);
+
+	void	 (* deactivate_plugin)		(GeditPluginsEngine *engine,
+						 GeditPluginInfo    *info);
 };
 
 GType			 gedit_plugins_engine_get_type		(void) G_GNUC_CONST;
 
 GeditPluginsEngine	*gedit_plugins_engine_get_default	(void);
 
+void			 gedit_plugins_engine_garbage_collect	(GeditPluginsEngine *engine);
+
+const GList		*gedit_plugins_engine_get_plugin_list 	(GeditPluginsEngine *engine);
+
+GeditPluginInfo		*gedit_plugins_engine_get_plugin_info	(GeditPluginsEngine *engine,
+								 const gchar        *name);
+
+/* plugin load and unloading (overall, for all windows) */
+gboolean 		 gedit_plugins_engine_activate_plugin 	(GeditPluginsEngine *engine,
+								 GeditPluginInfo    *info);
+gboolean 		 gedit_plugins_engine_deactivate_plugin	(GeditPluginsEngine *engine,
+								 GeditPluginInfo    *info);
+
+void	 		 gedit_plugins_engine_configure_plugin	(GeditPluginsEngine *engine,
+								 GeditPluginInfo    *info,
+								 GtkWindow          *parent);
+
+/* plugin activation/deactivation per window, private to GeditWindow */
+void 			 gedit_plugins_engine_activate_plugins	(GeditPluginsEngine *engine,
+								  GeditWindow        *window);
+void 			 gedit_plugins_engine_deactivate_plugins
+								(GeditPluginsEngine *engine,
+								  GeditWindow        *window);
+void			 gedit_plugins_engine_update_plugins_ui	(GeditPluginsEngine *engine,
+								  GeditWindow        *window);
+
 /* private for gconf notification */
 void		 gedit_plugins_engine_active_plugins_changed	(GeditPluginsEngine *engine);
 
+void		 gedit_plugins_engine_rescan_plugins		(GeditPluginsEngine *engine);
+
 G_END_DECLS
 
 #endif  /* __GEDIT_PLUGINS_ENGINE_H__ */
diff --git a/gedit/gedit-window-private.h b/gedit/gedit-window-private.h
index b3dac50..9f02055 100644
--- a/gedit/gedit-window-private.h
+++ b/gedit/gedit-window-private.h
@@ -31,8 +31,6 @@
 #ifndef __GEDIT_WINDOW_PRIVATE_H__
 #define __GEDIT_WINDOW_PRIVATE_H__
 
-#include <libpeas/peas-extension-set.h>
-
 #include "gedit/gedit-window.h"
 #include "gedit-message-bus.h"
 #include "gedit-settings.h"
@@ -64,7 +62,6 @@ struct _GeditWindowPrivate
 	GtkWidget      *language_combo;
 	
 	GeditMessageBus *message_bus;	
-	PeasExtensionSet *extensions;
 
 	/* Widgets for fullscreen mode */
 	GtkWidget      *fullscreen_controls;
diff --git a/gedit/gedit-window.c b/gedit/gedit-window.c
index 3fea97e..0d43819 100644
--- a/gedit/gedit-window.c
+++ b/gedit/gedit-window.c
@@ -38,8 +38,6 @@
 
 #include <glib/gi18n.h>
 #include <gio/gio.h>
-#include <libpeas/peas-activatable.h>
-#include <libpeas/peas-extension-set.h>
 
 #include "gedit-ui.h"
 #include "gedit-window.h"
@@ -244,15 +242,6 @@ gedit_window_dispose (GObject *object)
 
 	window = GEDIT_WINDOW (object);
 
-	if (!window->priv->dispose_has_run)
-	{
-		peas_extension_set_call (window->priv->extensions,
-					 "deactivate",
-					 window);
-
-		peas_engine_garbage_collect (PEAS_ENGINE (gedit_plugins_engine_get_default ()));
-	}
-
 	/* Stop tracking removal of panes otherwise we always
 	 * end up with thinking we had no pane active, since they
 	 * should all be removed below */
@@ -263,6 +252,11 @@ gedit_window_dispose (GObject *object)
 		window->priv->bottom_panel_item_removed_handler_id = 0;
 	}
 
+	/* First of all, force collection so that plugins
+	 * really drop some of the references.
+	 */
+	gedit_plugins_engine_garbage_collect (gedit_plugins_engine_get_default ());
+
 	/* save the panes position and make sure to deactivate plugins
 	 * for this window, but only once */
 	if (!window->priv->dispose_has_run)
@@ -270,6 +264,8 @@ gedit_window_dispose (GObject *object)
 		save_window_state (GTK_WIDGET (window));
 		save_panes_state (window);
 
+		gedit_plugins_engine_deactivate_plugins (gedit_plugins_engine_get_default (),
+					                  window);
 		window->priv->dispose_has_run = TRUE;
 	}
 
@@ -336,7 +332,7 @@ gedit_window_dispose (GObject *object)
 	/* Now that there have broken some reference loops,
 	 * force collection again.
 	 */
-	peas_engine_garbage_collect (PEAS_ENGINE (gedit_plugins_engine_get_default ()));
+	gedit_plugins_engine_garbage_collect (gedit_plugins_engine_get_default ());
 
 #ifdef OS_OSX
 	remove_mac_root_menu (window);
@@ -354,8 +350,6 @@ gedit_window_finalize (GObject *object)
 
 	window = GEDIT_WINDOW (object);
 
-	g_object_unref (window->priv->extensions);
-
 	if (window->priv->default_location != NULL)
 		g_object_unref (window->priv->default_location);
 
@@ -445,7 +439,7 @@ static void
 gedit_window_tab_removed (GeditWindow *window,
 			  GeditTab    *tab)
 {
-	peas_engine_garbage_collect (PEAS_ENGINE (gedit_plugins_engine_get_default ()));
+	gedit_plugins_engine_garbage_collect (gedit_plugins_engine_get_default ());
 }
 
 static void
@@ -970,7 +964,8 @@ set_sensitivity_according_to_tab (GeditWindow *window,
 
 	update_next_prev_doc_sensitivity (window, tab);
 
-	peas_extension_set_call (window->priv->extensions, "update_state", window);
+	gedit_plugins_engine_update_plugins_ui (gedit_plugins_engine_get_default (),
+						window);
 }
 
 static void
@@ -2973,7 +2968,8 @@ sync_name (GeditTab    *tab,
 	g_free (escaped_name);
 	g_free (tip);
 
-	peas_extension_set_call (window->priv->extensions, "update_state", window);
+	gedit_plugins_engine_update_plugins_ui (gedit_plugins_engine_get_default (),
+						 window);
 }
 
 static GeditWindow *
@@ -3375,7 +3371,8 @@ selection_changed (GeditDocument *doc,
 				  editable &&
 				  gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc)));
 
-	peas_extension_set_call (window->priv->extensions, "update_state", window);
+	gedit_plugins_engine_update_plugins_ui (gedit_plugins_engine_get_default (),
+						 window);
 }
 
 static void
@@ -3384,7 +3381,8 @@ sync_languages_menu (GeditDocument *doc,
 		     GeditWindow   *window)
 {
 	update_languages_menu (window);
-	peas_extension_set_call (window->priv->extensions, "update_state", window);
+	gedit_plugins_engine_update_plugins_ui (gedit_plugins_engine_get_default (),
+						 window);
 }
 
 static void
@@ -3397,7 +3395,8 @@ readonly_changed (GeditDocument *doc,
 
 	sync_name (gedit_window_get_active_tab (window), NULL, window);
 
-	peas_extension_set_call (window->priv->extensions, "update_state", window);
+	gedit_plugins_engine_update_plugins_ui (gedit_plugins_engine_get_default (),
+						window);
 }
 
 static void
@@ -3405,7 +3404,8 @@ editable_changed (GeditView  *view,
                   GParamSpec  *arg1,
                   GeditWindow *window)
 {
-	peas_extension_set_call (window->priv->extensions, "update_state", window);
+	gedit_plugins_engine_update_plugins_ui (gedit_plugins_engine_get_default (),
+						 window);
 }
 
 static void
@@ -3634,7 +3634,8 @@ on_tab_removed (GeditMultiNotebook *multi,
 
 		if (num_tabs == 0)
 		{
-			peas_extension_set_call (window->priv->extensions, "update_state", window);
+			gedit_plugins_engine_update_plugins_ui (gedit_plugins_engine_get_default (),
+								window);
 		}
 	}
 
@@ -4056,29 +4057,6 @@ setup_mac_menu (GeditWindow *window)
 #endif
 
 static void
-extension_added (PeasExtensionSet *extensions,
-		 PeasPluginInfo   *info,
-		 PeasExtension    *exten,
-		 GeditWindow      *window)
-{
-	peas_extension_call (exten, "activate", window);
-}
-
-static void
-extension_removed (PeasExtensionSet *extensions,
-		   PeasPluginInfo   *info,
-		   PeasExtension    *exten,
-		   GeditWindow      *window)
-{
-	peas_extension_call (exten, "deactivate", 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 (window->priv->manager);
-}
-
-static void
 gedit_window_init (GeditWindow *window)
 {
 	GtkWidget *main_box;
@@ -4245,18 +4223,8 @@ gedit_window_init (GeditWindow *window)
 
 	gedit_debug_message (DEBUG_WINDOW, "Update plugins ui");
 	
-	window->priv->extensions = peas_extension_set_new (PEAS_ENGINE (gedit_plugins_engine_get_default ()),
-							   PEAS_TYPE_ACTIVATABLE);
-	g_signal_connect (window->priv->extensions,
-			  "extension-added",
-			  G_CALLBACK (extension_added),
-			  window);
-	g_signal_connect (window->priv->extensions,
-			  "extension-removed",
-			  G_CALLBACK (extension_removed),
-			  window);
-	peas_extension_set_call (window->priv->extensions, "activate", window);
-
+	gedit_plugins_engine_activate_plugins (gedit_plugins_engine_get_default (),
+					        window);
 
 	/* set visibility of panes.
 	 * This needs to be done after plugins activatation */
diff --git a/plugin-loaders/Makefile.am b/plugin-loaders/Makefile.am
new file mode 100644
index 0000000..2573ec3
--- /dev/null
+++ b/plugin-loaders/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = c
+
+-include $(top_srcdir)/git.mk
diff --git a/plugin-loaders/c/Makefile.am b/plugin-loaders/c/Makefile.am
new file mode 100644
index 0000000..7760aef
--- /dev/null
+++ b/plugin-loaders/c/Makefile.am
@@ -0,0 +1,24 @@
+# C plugin loader
+
+loaderdir = $(libdir)/gedit-2/plugin-loaders
+
+INCLUDES = \
+	-I$(top_srcdir) 						\
+	$(GEDIT_CFLAGS) 						\
+	$(WARN_CFLAGS)							\
+	$(DISABLE_DEPRECATED_CFLAGS)					\
+	-DGEDIT_LOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\"
+
+loader_LTLIBRARIES = libcloader.la
+
+NOINST_H_FILES = \
+	gedit-plugin-loader-c.h
+
+libcloader_la_SOURCES = \
+	gedit-plugin-loader-c.c 	\
+	$(NOINST_H_FILES)
+
+libcloader_la_LDFLAGS = $(LOADER_LIBTOOL_FLAGS)
+libcloader_la_LIBADD = $(GEDIT_LIBS)
+
+-include $(top_srcdir)/git.mk
diff --git a/plugin-loaders/c/gedit-plugin-loader-c.c b/plugin-loaders/c/gedit-plugin-loader-c.c
new file mode 100644
index 0000000..add817e
--- /dev/null
+++ b/plugin-loaders/c/gedit-plugin-loader-c.c
@@ -0,0 +1,183 @@
+/*
+ * gedit-plugin-loader-c.c
+ * This file is part of gedit
+ *
+ * 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 "gedit-plugin-loader-c.h"
+#include <gedit/gedit-object-module.h>
+
+#define GEDIT_PLUGIN_LOADER_C_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_PLUGIN_LOADER_C, GeditPluginLoaderCPrivate))
+
+struct _GeditPluginLoaderCPrivate
+{
+	GHashTable *loaded_plugins;
+};
+
+static void gedit_plugin_loader_iface_init (gpointer g_iface, gpointer iface_data);
+
+GEDIT_PLUGIN_LOADER_REGISTER_TYPE (GeditPluginLoaderC, gedit_plugin_loader_c, G_TYPE_OBJECT, gedit_plugin_loader_iface_init);
+
+
+static const gchar *
+gedit_plugin_loader_iface_get_id (void)
+{
+	return "C";
+}
+
+static GeditPlugin *
+gedit_plugin_loader_iface_load (GeditPluginLoader *loader,
+				GeditPluginInfo   *info,
+				const gchar       *path)
+{
+	GeditPluginLoaderC *cloader = GEDIT_PLUGIN_LOADER_C (loader);
+	GeditObjectModule *module;
+	const gchar *module_name;
+	GeditPlugin *result;
+
+	module = (GeditObjectModule *)g_hash_table_lookup (cloader->priv->loaded_plugins, info);
+	module_name = gedit_plugin_info_get_module_name (info);
+
+	if (module == NULL)
+	{
+		/* For now we force all modules to be resident */
+		module = gedit_object_module_new (module_name,
+						  path,
+						  "register_gedit_plugin",
+						  TRUE);
+
+		/* Infos are available for all the lifetime of the loader.
+		 * If this changes, we should use weak refs or something */
+
+		g_hash_table_insert (cloader->priv->loaded_plugins, info, module);
+	}
+
+	if (!g_type_module_use (G_TYPE_MODULE (module)))
+	{
+		g_warning ("Could not load plugin module: %s", gedit_plugin_info_get_name (info));
+
+		return NULL;
+	}
+
+	/* TODO: for now we force data-dir-name = module-name... if needed we can
+	 * add a datadir field to the plugin descriptor file.
+	 */
+	result = (GeditPlugin *)gedit_object_module_new_object (module,
+								"install-dir", path,
+								"data-dir-name", module_name,
+								NULL);
+
+	if (!result)
+	{
+		g_warning ("Could not create plugin object: %s", gedit_plugin_info_get_name (info));
+		g_type_module_unuse (G_TYPE_MODULE (module));
+		
+		return NULL;
+	}
+
+	g_type_module_unuse (G_TYPE_MODULE (module));
+	
+	return result;
+}
+
+static void
+gedit_plugin_loader_iface_unload (GeditPluginLoader *loader,
+				  GeditPluginInfo   *info)
+{
+	//GeditPluginLoaderC *cloader = GEDIT_PLUGIN_LOADER_C (loader);
+	
+	/* this is a no-op, since the type module will be properly unused as
+	   the last reference to the plugin dies. When the plugin is activated
+	   again, the library will be reloaded */
+}
+
+static void
+gedit_plugin_loader_iface_init (gpointer g_iface, 
+				gpointer iface_data)
+{
+	GeditPluginLoaderInterface *iface = (GeditPluginLoaderInterface *)g_iface;
+	
+	iface->get_id = gedit_plugin_loader_iface_get_id;
+	iface->load = gedit_plugin_loader_iface_load;
+	iface->unload = gedit_plugin_loader_iface_unload;
+}
+
+static void
+gedit_plugin_loader_c_finalize (GObject *object)
+{
+	GeditPluginLoaderC *cloader = GEDIT_PLUGIN_LOADER_C (object);
+	GList *infos;
+	GList *item;
+
+	/* FIXME: this sanity check it's not efficient. Let's remove it
+	 * once we are confident with the code */
+
+	infos = g_hash_table_get_keys (cloader->priv->loaded_plugins);
+	
+	for (item = infos; item; item = item->next)
+	{
+		GeditPluginInfo *info = (GeditPluginInfo *)item->data;
+
+		if (gedit_plugin_info_is_active (info))
+		{
+			g_warning ("There are still C plugins loaded during destruction");
+			break;
+		}
+	}
+
+	g_list_free (infos);	
+
+	g_hash_table_destroy (cloader->priv->loaded_plugins);
+	
+	G_OBJECT_CLASS (gedit_plugin_loader_c_parent_class)->finalize (object);
+}
+
+static void
+gedit_plugin_loader_c_class_init (GeditPluginLoaderCClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	
+	object_class->finalize = gedit_plugin_loader_c_finalize;
+
+	g_type_class_add_private (object_class, sizeof (GeditPluginLoaderCPrivate));
+}
+
+static void
+gedit_plugin_loader_c_class_finalize (GeditPluginLoaderCClass *klass)
+{
+}
+
+static void
+gedit_plugin_loader_c_init (GeditPluginLoaderC *self)
+{
+	self->priv = GEDIT_PLUGIN_LOADER_C_GET_PRIVATE (self);
+	
+	/* loaded_plugins maps GeditPluginInfo to a GeditObjectModule */
+	self->priv->loaded_plugins = g_hash_table_new (g_direct_hash,
+						       g_direct_equal);
+}
+
+GeditPluginLoaderC *
+gedit_plugin_loader_c_new ()
+{
+	GObject *loader = g_object_new (GEDIT_TYPE_PLUGIN_LOADER_C, NULL);
+
+	return GEDIT_PLUGIN_LOADER_C (loader);
+}
+/* ex:ts=8:noet: */
diff --git a/plugin-loaders/c/gedit-plugin-loader-c.h b/plugin-loaders/c/gedit-plugin-loader-c.h
new file mode 100644
index 0000000..dcf4f2d
--- /dev/null
+++ b/plugin-loaders/c/gedit-plugin-loader-c.h
@@ -0,0 +1,61 @@
+/*
+ * gedit-plugin-loader-c.h
+ * This file is part of gedit
+ *
+ * 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 __GEDIT_PLUGIN_LOADER_C_H__
+#define __GEDIT_PLUGIN_LOADER_C_H__
+
+#include <gedit/gedit-plugin-loader.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_PLUGIN_LOADER_C		(gedit_plugin_loader_c_get_type ())
+#define GEDIT_PLUGIN_LOADER_C(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_PLUGIN_LOADER_C, GeditPluginLoaderC))
+#define GEDIT_PLUGIN_LOADER_C_CONST(obj)	(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_PLUGIN_LOADER_C, GeditPluginLoaderC const))
+#define GEDIT_PLUGIN_LOADER_C_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_PLUGIN_LOADER_C, GeditPluginLoaderCClass))
+#define GEDIT_IS_PLUGIN_LOADER_C(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_PLUGIN_LOADER_C))
+#define GEDIT_IS_PLUGIN_LOADER_C_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_PLUGIN_LOADER_C))
+#define GEDIT_PLUGIN_LOADER_C_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_PLUGIN_LOADER_C, GeditPluginLoaderCClass))
+
+typedef struct _GeditPluginLoaderC		GeditPluginLoaderC;
+typedef struct _GeditPluginLoaderCClass		GeditPluginLoaderCClass;
+typedef struct _GeditPluginLoaderCPrivate	GeditPluginLoaderCPrivate;
+
+struct _GeditPluginLoaderC {
+	GObject parent;
+	
+	GeditPluginLoaderCPrivate *priv;
+};
+
+struct _GeditPluginLoaderCClass {
+	GObjectClass parent_class;
+};
+
+GType gedit_plugin_loader_c_get_type (void) G_GNUC_CONST;
+GeditPluginLoaderC *gedit_plugin_loader_c_new(void);
+
+/* All the loaders must implement this function */
+G_MODULE_EXPORT GType register_gedit_plugin_loader (GTypeModule * module);
+
+G_END_DECLS
+
+#endif /* __GEDIT_PLUGIN_LOADER_C_H__ */
+/* ex:ts=8:noet: */
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 6fbac4b..ec1df43 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -1,30 +1,28 @@
-DIST_SUBDIRS = \
-	modelines
+DIST_SUBDIRS =		\
+	changecase 	\
+	checkupdate	\
+	docinfo 	\
+	filebrowser 	\
+	modelines	\
+	sort 		\
+	spell 		\
+	taglist 	\
+	time
 
-#	changecase 	\
-#	checkupdate	\
-#	docinfo 	\
-#	filebrowser 	\
-#	modelines	\
-#	sort 		\
-#	spell 		\
-#	taglist 	\
-#	time
 #	externaltools
 #	pythonconsole
 #	quickopen
 #	snippets
 
-SUBDIRS = \
-	modelines
+SUBDIRS = 		\
+	changecase	\
+	docinfo		\
+	filebrowser	\
+	modelines	\
+	sort		\
+	taglist		\
+	time
 
-#	changecase
-#	docinfo
-#	filebrowser
-#	modelines
-#	sort
-#	taglist
-#	time
 #	pythonconsole
 #	quickopen
 #	snippets
@@ -33,15 +31,12 @@ SUBDIRS = \
 #SUBDIRS      += externaltools
 #endif
 
-#if ENABLE_ENCHANT
-#SUBDIRS      += spell
-#endif
-
-#if ENABLE_UPDATER
-#SUBDIRS      += checkupdate
-#endif
+if ENABLE_ENCHANT
+SUBDIRS      += spell
+endif
 
-DIST_SUBDIRS += pysample
-SUBDIRS += pysample
+if ENABLE_UPDATER
+SUBDIRS      += checkupdate
+endif
 
 -include $(top_srcdir)/git.mk
diff --git a/plugins/modelines/gedit-modeline-plugin.c b/plugins/modelines/gedit-modeline-plugin.c
index 93ae710..b6bd4e3 100644
--- a/plugins/modelines/gedit-modeline-plugin.c
+++ b/plugins/modelines/gedit-modeline-plugin.c
@@ -2,7 +2,7 @@
  * gedit-modeline-plugin.c
  * Emacs, Kate and Vim-style modelines support for gedit.
  * 
- * Copyright (C) 2005-2010 - Steve Frécinaux <code istique net>
+ * Copyright (C) 2005-2007 - Steve Frécinaux <code istique net>
  *
  * 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
@@ -25,34 +25,39 @@
 
 #include <glib/gi18n-lib.h>
 #include <gmodule.h>
-#include <libpeas/peas-activatable.h>
 #include "gedit-modeline-plugin.h"
 #include "modeline-parser.h"
 
 #include <gedit/gedit-debug.h>
-#include <gedit/gedit-window.h>
 #include <gedit/gedit-utils.h>
 
+#define WINDOW_DATA_KEY "GeditModelinePluginWindowData"
 #define DOCUMENT_DATA_KEY "GeditModelinePluginDocumentData"
 
 typedef struct
 {
+	gulong tab_added_handler_id;
+	gulong tab_removed_handler_id;
+} WindowData;
+
+typedef struct
+{
 	gulong document_loaded_handler_id;
 	gulong document_saved_handler_id;
 } DocumentData;
 
-static void	peas_activatable_iface_init (PeasActivatableInterface *iface);
-static void	gedit_modeline_plugin_activate (PeasActivatable *activatable, GObject *object);
-static void	gedit_modeline_plugin_deactivate (PeasActivatable *activatable, GObject *object);
+static void	gedit_modeline_plugin_activate (GeditPlugin *plugin, GeditWindow *window);
+static void	gedit_modeline_plugin_deactivate (GeditPlugin *plugin, GeditWindow *window);
 static GObject	*gedit_modeline_plugin_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_param);
 static void	gedit_modeline_plugin_finalize (GObject *object);
 
-G_DEFINE_DYNAMIC_TYPE_EXTENDED (GeditModelinePlugin,
-				gedit_modeline_plugin,
-				PEAS_TYPE_EXTENSION_BASE,
-				0,
-				G_IMPLEMENT_INTERFACE_DYNAMIC (PEAS_TYPE_ACTIVATABLE,
-							       peas_activatable_iface_init))
+GEDIT_PLUGIN_REGISTER_TYPE(GeditModelinePlugin, gedit_modeline_plugin)
+
+static void
+window_data_free (WindowData *wdata)
+{
+	g_slice_free (WindowData, wdata);
+}
 
 static void
 document_data_free (DocumentData *ddata)
@@ -64,21 +69,13 @@ static void
 gedit_modeline_plugin_class_init (GeditModelinePluginClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GeditPluginClass *plugin_class = GEDIT_PLUGIN_CLASS (klass);
 
 	object_class->constructor = gedit_modeline_plugin_constructor;
 	object_class->finalize = gedit_modeline_plugin_finalize;
-}
 
-static void
-peas_activatable_iface_init (PeasActivatableInterface *iface)
-{
-	iface->activate = gedit_modeline_plugin_activate;
-	iface->deactivate = gedit_modeline_plugin_deactivate;
-}
-
-static void
-gedit_modeline_plugin_class_finalize (GeditModelinePluginClass *klass)
-{
+	plugin_class->activate = gedit_modeline_plugin_activate;
+	plugin_class->deactivate = gedit_modeline_plugin_deactivate;
 }
 
 static GObject *
@@ -93,7 +90,7 @@ gedit_modeline_plugin_constructor (GType                  type,
 										   n_construct_properties,
 										   construct_param);
 
-	data_dir = peas_extension_base_get_data_dir (PEAS_EXTENSION_BASE (object));
+	data_dir = gedit_plugin_get_data_dir (GEDIT_PLUGIN (object));
 
 	modeline_parser_init (data_dir);
 
@@ -189,12 +186,10 @@ on_window_tab_removed (GeditWindow *window,
 }
 
 static void
-gedit_modeline_plugin_activate (PeasActivatable *activatable,
-				GObject         *object)
+gedit_modeline_plugin_activate (GeditPlugin *plugin,
+				GeditWindow *window)
 {
-	GeditModelinePlugin *plugin = GEDIT_MODELINE_PLUGIN (activatable);
-	GeditWindow *window = GEDIT_WINDOW (object);
-
+	WindowData *wdata;
 	GList *views;
 	GList *l;
 
@@ -208,28 +203,36 @@ gedit_modeline_plugin_activate (PeasActivatable *activatable,
 	}
 	g_list_free (views);
 
-	plugin->tab_added_handler_id =
+	wdata = g_slice_new (WindowData);
+
+	wdata->tab_added_handler_id =
 		g_signal_connect (window, "tab-added",
 				  G_CALLBACK (on_window_tab_added), NULL);
 
-	plugin->tab_removed_handler_id =
+	wdata->tab_removed_handler_id =
 		g_signal_connect (window, "tab-removed",
 				  G_CALLBACK (on_window_tab_removed), NULL);
+
+	g_object_set_data_full (G_OBJECT (window), WINDOW_DATA_KEY,
+				wdata, (GDestroyNotify) window_data_free);
 }
 
 static void
-gedit_modeline_plugin_deactivate (PeasActivatable *activatable,
-				  GObject         *object)
+gedit_modeline_plugin_deactivate (GeditPlugin *plugin,
+				  GeditWindow *window)
 {
-	GeditModelinePlugin *plugin = GEDIT_MODELINE_PLUGIN (activatable);
-	GeditWindow *window = GEDIT_WINDOW (object);
+	WindowData *wdata;
 	GList *views;
 	GList *l;
 
 	gedit_debug (DEBUG_PLUGINS);
 
-	g_signal_handler_disconnect (window, plugin->tab_added_handler_id);
-	g_signal_handler_disconnect (window, plugin->tab_removed_handler_id);
+	wdata = g_object_steal_data (G_OBJECT (window), WINDOW_DATA_KEY);
+
+	g_signal_handler_disconnect (window, wdata->tab_added_handler_id);
+	g_signal_handler_disconnect (window, wdata->tab_removed_handler_id);
+
+	window_data_free (wdata);
 
 	views = gedit_window_get_views (window);
 
@@ -243,14 +246,4 @@ gedit_modeline_plugin_deactivate (PeasActivatable *activatable,
 	g_list_free (views);
 }
 
-G_MODULE_EXPORT void
-peas_register_types (PeasObjectModule *module)
-{
-	gedit_modeline_plugin_register_type (G_TYPE_MODULE (module));
-
-	peas_object_module_register_extension_type (module,
-						    PEAS_TYPE_ACTIVATABLE,
-						    GEDIT_TYPE_MODELINE_PLUGIN);
-}
-
-/* ex:set ts=8 noet: */
+/* ex:ts=8:noet: */
diff --git a/plugins/modelines/gedit-modeline-plugin.h b/plugins/modelines/gedit-modeline-plugin.h
index 3f7a764..a5ff1da 100644
--- a/plugins/modelines/gedit-modeline-plugin.h
+++ b/plugins/modelines/gedit-modeline-plugin.h
@@ -24,8 +24,7 @@
 
 #include <glib.h>
 #include <glib-object.h>
-#include <libpeas/peas-extension-base.h>
-#include <libpeas/peas-object-module.h>
+#include <gedit/gedit-plugin.h>
 
 G_BEGIN_DECLS
 
@@ -36,24 +35,13 @@ G_BEGIN_DECLS
 #define GEDIT_IS_MODELINE_PLUGIN_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GEDIT_TYPE_MODELINE_PLUGIN))
 #define GEDIT_MODELINE_PLUGIN_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GEDIT_TYPE_MODELINE_PLUGIN, GeditModelinePluginClass))
 
-typedef struct _GeditModelinePlugin		GeditModelinePlugin;
-typedef struct _GeditModelinePluginClass	GeditModelinePluginClass;
-
-struct _GeditModelinePlugin {
-	PeasExtensionBase parent;
-
-	/*< private >*/
-	gulong tab_added_handler_id;
-	gulong tab_removed_handler_id;
-};
-
-struct _GeditModelinePluginClass {
-	PeasExtensionBaseClass parent_class;
-};
+/* Private structure type */
+typedef GeditPluginClass	GeditModelinePluginClass;
+typedef GeditPlugin		GeditModelinePlugin;
 
 GType	gedit_modeline_plugin_get_type		(void) G_GNUC_CONST;
 
-G_MODULE_EXPORT void peas_register_types (PeasObjectModule *module);
+G_MODULE_EXPORT GType register_gedit_plugin (GTypeModule *module);
 
 G_END_DECLS
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]