Index: plugins/sample/sample.sj-plugin.desktop.in
===================================================================
--- plugins/sample/sample.sj-plugin.desktop.in	(revision 0)
+++ plugins/sample/sample.sj-plugin.desktop.in	(revision 0)
@@ -0,0 +1,9 @@
+[Sound Juicer Plugin]
+Module=sample
+IAge=1
+_Name=Sample Plugin
+_Description=It does nothing.
+Authors=Paolo Maggi <paolo@gnome.org>;Luca Cavalli <lcavalli@cvs.gnome.org>
+Copyright=Copyright © 2002-2007 Paolo Maggi and Luca Cavalli
+Website=http://www.gnome.org
+Icon=im-yahoo
Index: plugins/sample/sj-sample-plugin.c
===================================================================
--- plugins/sample/sj-sample-plugin.c	(revision 0)
+++ plugins/sample/sj-sample-plugin.c	(revision 0)
@@ -0,0 +1,93 @@
+/*
+ * Sound Juicer - sj-sample-plugin.c
+ *
+ * Based on gedit code
+ * Copyright (C) 2002-2005 - Paolo Maggi
+ * Copyright (C) 2007 - The Free Software Foundation
+ *
+ * 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 "sj-sample-plugin.h"
+
+#include <gmodule.h>
+#include <gtk/gtk.h>
+
+#include <sound-juicer.h>
+
+#define SJ_SAMPLE_PLUGIN_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), SJ_TYPE_SAMPLE_PLUGIN, SjSamplePluginPrivate))
+
+struct _SjSamplePluginPrivate
+{
+	gpointer dummy;
+};
+
+SJ_PLUGIN_REGISTER_TYPE(SjSamplePlugin, sj_sample_plugin)
+
+static void
+sj_sample_plugin_init (SjSamplePlugin *plugin)
+{
+	plugin->priv = SJ_SAMPLE_PLUGIN_GET_PRIVATE (plugin);
+
+	sj_debug (DEBUG_PLUGINS, "SjSamplePlugin initialising");
+}
+
+static void
+sj_sample_plugin_finalize (GObject *object)
+{
+/*
+	SjSamplePlugin *plugin = SJ_SAMPLE_PLUGIN (object);
+*/
+	sj_debug (DEBUG_PLUGINS, "SjSamplePlugin finalising");
+
+	G_OBJECT_CLASS (sj_sample_plugin_parent_class)->finalize (object);
+}
+
+static void
+impl_activate (SjPlugin *plugin,
+	       SjWindow *window)
+{
+	GtkWidget *sample_window;
+	GtkWidget *label;
+
+	sample_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	label = gtk_label_new ("Hey, I'm a plugin!");
+
+	gtk_container_set_border_width (GTK_CONTAINER (sample_window), 20);
+	gtk_container_add (GTK_CONTAINER (sample_window), label);
+
+	gtk_widget_show_all (sample_window);
+}
+
+static void
+impl_deactivate	(SjPlugin *plugin,
+		 SjWindow *window)
+{
+}
+
+static void
+sj_sample_plugin_class_init (SjSamplePluginClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	SjPluginClass *plugin_class = SJ_PLUGIN_CLASS (klass);
+
+	object_class->finalize = sj_sample_plugin_finalize;
+
+	plugin_class->activate = impl_activate;
+	plugin_class->deactivate = impl_deactivate;
+
+	g_type_class_add_private (object_class, sizeof (SjSamplePluginPrivate));
+}
Index: plugins/sample/Makefile.am
===================================================================
--- plugins/sample/Makefile.am	(revision 0)
+++ plugins/sample/Makefile.am	(revision 0)
@@ -0,0 +1,37 @@
+# Sample plugin
+plugindir = $(libdir)/sound-juicer/plugins
+
+INCLUDES = \
+	-I$(top_srcdir) 		\
+	-I$(top_srcdir)/src		\
+	-I$(top_srcdir)/libjuicer	\
+	$(GSTREAMER_CFLAGS)		\
+	$(MEDIA_PROFILES_CFLAGS)	\
+	$(BURN_CFLAGS)			\
+	$(UI_CFLAGS)			\
+	$(WARN_CFLAGS)			\
+	$(DISABLE_DEPRECATED_CFLAGS)	\
+	-DGNOMELOCALEDIR=\""$(datadir)/locale"\"
+
+plugin_LTLIBRARIES = libsample.la
+
+libsample_la_SOURCES = \
+	sj-sample-plugin.h	\
+	sj-sample-plugin.c
+
+libsample_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
+libsample_la_LIBADD  = $(UI_LIBS)
+
+gladedir = $(datadir)/sound-juicer/glade
+glade_DATA =
+
+plugin_in_files = sample.sj-plugin.desktop.in
+
+%.sj-plugin: %.sj-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache
+
+plugin_DATA = $(plugin_in_files:.sj-plugin.desktop.in=.sj-plugin)
+
+EXTRA_DIST = $(glade_DATA) $(plugin_in_files)
+
+CLEANFILES = $(plugin_DATA)
+DISTCLEANFILES = $(plugin_DATA)
Index: plugins/sample/sj-sample-plugin.h
===================================================================
--- plugins/sample/sj-sample-plugin.h	(revision 0)
+++ plugins/sample/sj-sample-plugin.h	(revision 0)
@@ -0,0 +1,80 @@
+/*
+ * Sound Juicer - sj-sample-plugin.h
+ *
+ * Based on sj code
+ * Copyright (C) 2002-2005 - Paolo Maggi
+ * Copyright (C) 2007 - The Free Software Foundation
+ *
+ * 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 __SJ_SAMPLE_PLUGIN_H__
+#define __SJ_SAMPLE_PLUGIN_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <sj-plugin.h>
+
+G_BEGIN_DECLS
+
+/*
+ * Type checking and casting macros
+ */
+#define SJ_TYPE_SAMPLE_PLUGIN			(sj_sample_plugin_get_type())
+#define SJ_SAMPLE_PLUGIN(obj)			(G_TYPE_CHECK_INSTANCE_CAST((obj), SJ_TYPE_SAMPLE_PLUGIN, SjSamplePlugin))
+#define SJ_SAMPLE_PLUGIN_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass),  SJ_TYPE_SAMPLE_PLUGIN, SjSamplePluginClass))
+#define SJ_IS_SAMPLE_PLUGIN(obj)		(G_TYPE_CHECK_INSTANCE_TYPE((obj), SJ_TYPE_SAMPLE_PLUGIN))
+#define SJ_IS_SAMPLE_PLUGIN_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass),  SJ_TYPE_SAMPLE_PLUGIN))
+#define SJ_SAMPLE_PLUGIN_GET_CLASS(obj)		(G_TYPE_INSTANCE_GET_CLASS((obj),  SJ_TYPE_SAMPLE_PLUGIN, SjSamplePluginClass))
+
+/* Private structure type */
+typedef struct _SjSamplePluginPrivate	SjSamplePluginPrivate;
+
+/*
+ * Main object structure
+ */
+typedef struct _SjSamplePlugin		SjSamplePlugin;
+
+struct _SjSamplePlugin
+{
+	SjPlugin parent_instance;
+
+	/*< private >*/
+	SjSamplePluginPrivate *priv;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _SjSamplePluginClass	SjSamplePluginClass;
+
+struct _SjSamplePluginClass
+{
+	SjPluginClass parent_class;
+};
+
+/*
+ * Public methods
+ */
+GType	sj_sample_plugin_get_type		(void) G_GNUC_CONST;
+
+/* All the plugins must implement this function */
+G_MODULE_EXPORT GType register_sj_plugin (GTypeModule *module);
+
+G_END_DECLS
+
+#endif /* __SJ_SAMPLE_PLUGIN_H__ */
Index: plugins/Makefile.am
===================================================================
--- plugins/Makefile.am	(revision 0)
+++ plugins/Makefile.am	(revision 0)
@@ -0,0 +1,8 @@
+DIST_SUBDIRS = sample
+
+SUBDIRS = sample
+
+# if ENABLE_PYTHON
+# DIST_SUBDIRS += externaltools modelines pythonconsole snippets
+# SUBDIRS      += externaltools modelines pythonconsole snippets
+# endif
Index: configure.in
===================================================================
--- configure.in	(revision 1798)
+++ configure.in	(working copy)
@@ -126,6 +126,9 @@
 AC_SUBST([AM_CXXFLAGS])
 AC_SUBST([AM_LDFLAGS])
 
+PLUGIN_LIBTOOL_FLAGS="-module -avoid-version"
+AC_SUBST(PLUGIN_LIBTOOL_FLAGS)
+
 # Finally, generate the files
 AC_CONFIG_FILES([
 sound-juicer.spec
@@ -137,6 +140,8 @@
 libjuicer/Makefile
 po/Makefile.in
 src/Makefile
+plugins/Makefile
+plugins/sample/Makefile
 tests/Makefile
 ])
 
Index: src/sj-main.c
===================================================================
--- src/sj-main.c	(revision 1798)
+++ src/sj-main.c	(working copy)
@@ -52,6 +52,7 @@
 #include "sj-main.h"
 #include "sj-prefs.h"
 #include "sj-play.h"
+#include "sj-plugins-engine.h"
 #include "bacon-volume.h"
 
 gboolean on_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data);
@@ -1360,6 +1361,8 @@
 
   nautilus_burn_init ();
 
+  sj_plugins_engine_init ();
+
   gtk_window_set_default_icon_name ("sound-juicer");
   
   connection = bacon_message_connection_new ("sound-juicer");
@@ -1532,6 +1535,8 @@
     exit (1);
   }
 
+  sj_plugins_engine_update_plugins_ui (SJ_WINDOW (main_window), TRUE);
+
   update_ui_for_album (NULL);
 
   sj_play_init ();
@@ -1571,6 +1576,8 @@
 
   nautilus_burn_shutdown ();
 
+  sj_plugins_engine_shutdown ();
+
   g_free (base_uri);
   g_object_unref (metadata);
   g_object_unref (extractor);
Index: src/sj-module.c
===================================================================
--- src/sj-module.c	(revision 0)
+++ src/sj-module.c	(revision 0)
@@ -0,0 +1,162 @@
+/*
+ * Sound Juicer - sj-module.c
+ *
+ * Based on eog code (derived from gedit and epyphany)
+ * Copyright (C) 2003 - Marco Pesenti Gritti
+ * Copyright (C) 2003, 2004 - Christian Persch
+ * Copyright (C) 2005 - Paolo Maggi
+ * Copyright (C) 2007 - The Free Software Foundation
+ *
+ * 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 "sound-juicer.h"
+#include "sj-module.h"
+
+#include <gmodule.h>
+
+#define SJ_MODULE_GET_PRIVATE(object) \
+    (G_TYPE_INSTANCE_GET_PRIVATE ((object), SJ_TYPE_MODULE, SjModulePrivate))
+
+G_DEFINE_TYPE (SjModule, sj_module, G_TYPE_TYPE_MODULE);
+
+typedef GType (*SjModuleRegisterFunc) (GTypeModule *);
+
+static gboolean
+sj_module_load (GTypeModule *gmodule)
+{
+	SjModule *module = SJ_MODULE (gmodule);
+	SjModuleRegisterFunc register_func;
+
+	sj_debug (DEBUG_PLUGINS, "Loading %s", module->path);
+
+	module->library = g_module_open (module->path, 0);
+
+	if (module->library == NULL) {
+		g_warning (g_module_error());
+
+		return FALSE;
+	}
+
+	/* Extract symbols from the lib */
+	if (!g_module_symbol (module->library, 
+			      "register_sj_plugin",
+			      (void *) &register_func)) {
+		g_warning (g_module_error());
+		g_module_close (module->library);
+
+		return FALSE;
+	}
+
+	/* Symbol can still be NULL even though g_module_symbol
+	 * returned TRUE */
+	if (register_func == NULL) {
+		g_warning ("Symbol 'register_sj_plugin' should not be NULL");
+		g_module_close (module->library);
+
+		return FALSE;
+	}
+
+	module->type = register_func (gmodule);
+
+	if (module->type == 0) {
+		g_warning ("Invalid Sound Juicer plugin contained by module %s", module->path);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void
+sj_module_unload (GTypeModule *gmodule)
+{
+	SjModule *module = SJ_MODULE (gmodule);
+
+	sj_debug (DEBUG_PLUGINS, "Unloading %s", module->path);
+
+	g_module_close (module->library);
+
+	module->library = NULL;
+	module->type = 0;
+}
+
+const gchar *
+sj_module_get_path (SjModule *module)
+{
+	g_return_val_if_fail (SJ_IS_MODULE (module), NULL);
+
+	return module->path;
+}
+
+GObject *
+sj_module_new_object (SjModule *module)
+{
+	sj_debug (DEBUG_PLUGINS, "Creating object of type %s", g_type_name (module->type));
+
+	if (module->type == 0) {
+		return NULL;
+	}
+
+	return g_object_new (module->type, NULL);
+}
+
+static void
+sj_module_init (SjModule *module)
+{
+	sj_debug (DEBUG_PLUGINS, "SjModule %p initialising", module);
+}
+
+static void
+sj_module_finalize (GObject *object)
+{
+	SjModule *module = SJ_MODULE (object);
+
+	sj_debug (DEBUG_PLUGINS, "SjModule %p finalising", module);
+
+	g_free (module->path);
+
+	G_OBJECT_CLASS (sj_module_parent_class)->finalize (object);
+}
+
+static void
+sj_module_class_init (SjModuleClass *class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (class);
+	GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
+
+	object_class->finalize = sj_module_finalize;
+
+	module_class->load = sj_module_load;
+	module_class->unload = sj_module_unload;
+}
+
+SjModule *
+sj_module_new (const gchar *path)
+{
+	SjModule *module;
+
+	if (path == NULL || path[0] == '\0') {
+		return NULL;
+	}
+
+	module = g_object_new (SJ_TYPE_MODULE, NULL);
+
+	g_type_module_set_name (G_TYPE_MODULE (module), path);
+
+	module->path = g_strdup (path);
+
+	return module;
+}
Index: src/sj-module.h
===================================================================
--- src/sj-module.h	(revision 0)
+++ src/sj-module.h	(revision 0)
@@ -0,0 +1,67 @@
+/*
+ * Sound Juicer - sj-module.h
+ *
+ * Based on eog code (derived from gedit and epyphany)
+ * Copyright (C) 2003 - Marco Pesenti Gritti
+ * Copyright (C) 2003, 2004 - Christian Persch
+ * Copyright (C) 2005 - Paolo Maggi
+ * Copyright (C) 2007 - The Free Software Foundation
+ *
+ * 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 SJ_MODULE_H
+#define SJ_MODULE_H
+
+#include <glib-object.h>
+#include <gmodule.h>
+
+G_BEGIN_DECLS
+
+typedef struct _SjModule SjModule;
+typedef struct _SjModuleClass SjModuleClass;
+typedef struct _SjModulePrivate SjModulePrivate;
+
+#define SJ_TYPE_MODULE			(sj_module_get_type())
+#define SJ_MODULE(obj)			(G_TYPE_CHECK_INSTANCE_CAST((obj), SJ_TYPE_MODULE, SjModule))
+#define SJ_MODULE_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass),  SJ_TYPE_MODULE, SjModuleClass))
+#define SJ_IS_MODULE(obj)		(G_TYPE_CHECK_INSTANCE_TYPE((obj), SJ_TYPE_MODULE))
+#define SJ_IS_MODULE_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((obj),    SJ_TYPE_MODULE))
+#define SJ_MODULE_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj),  SJ_TYPE_MODULE, SjModuleClass))
+
+struct _SjModule {
+	GTypeModule parent_instance;
+
+	GModule *library;
+	gchar   *path;
+	GType    type;
+};
+
+struct _SjModuleClass {
+        GTypeModuleClass parent_class;
+};
+
+GType		 sj_module_get_type	(void) G_GNUC_CONST;
+
+SjModule	*sj_module_new		(const gchar *path);
+
+const gchar	*sj_module_get_path	(SjModule *module);
+
+GObject		*sj_module_new_object	(SjModule *module);
+
+G_END_DECLS
+
+#endif
Index: src/sj-plugins-engine.c
===================================================================
--- src/sj-plugins-engine.c	(revision 0)
+++ src/sj-plugins-engine.c	(revision 0)
@@ -0,0 +1,894 @@
+/*
+ * Sound Juicer - sj-plugins-engine.c
+ *
+ * Based on eog code (derived from gedit)
+ * Copyright (C) 2002-2005 - Paolo Maggi
+ * Copyright (C) 2007 - The Free Software Foundation
+ *
+ * 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 <string.h>
+
+#include "sound-juicer.h"
+#include "sj-plugins-engine.h"
+#include "sj-plugin.h"
+#include "sj-module.h"
+
+#include <glib/gi18n.h>
+#include <glib/gkeyfile.h>
+#include <libgnome/gnome-util.h>
+#include <gconf/gconf-client.h>
+
+#ifdef ENABLE_PYTHON
+#include "sj-python-module.h"
+#endif
+
+#define USER_SJ_PLUGINS_LOCATION "sound-juicer/plugins/"
+
+#define PLUGIN_EXT ".sj-plugin"
+
+typedef enum {
+	SJ_PLUGIN_LOADER_C,
+	SJ_PLUGIN_LOADER_PY,
+} SjPluginLoader;
+
+struct _SjPluginInfo
+{
+	gchar             *file;
+
+	gchar             *location;
+	SjPluginLoader     loader;
+	GTypeModule       *module;
+
+	gchar             *name;
+	gchar             *desc;
+	gchar             *icon_name;
+	gchar            **authors;
+	gchar             *copyright;
+	gchar             *website;
+
+	SjPlugin          *plugin;
+
+	gint               active : 1;
+	
+	/* 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;
+};
+
+static void	    sj_plugins_engine_active_plugins_changed (GConfClient *client,
+							     guint cnxn_id, 
+							     GConfEntry *entry, 
+							     gpointer user_data);
+
+static GList       *sj_plugins_list = NULL;
+
+static GConfClient *sj_plugins_engine_gconf_client = NULL;
+
+static GSList      *active_plugins = NULL;
+
+static void
+sj_plugin_info_free (SjPluginInfo *info)
+{
+	if (info->plugin != NULL) {
+	       	sj_debug (DEBUG_PLUGINS, "Unref plugin %s", info->name);
+
+		g_object_unref (info->plugin);
+	}
+
+	g_free (info->file);
+	g_free (info->location);
+	g_free (info->name);
+	g_free (info->desc);
+	g_free (info->icon_name);
+	g_free (info->website);
+	g_free (info->copyright);
+	g_strfreev (info->authors);
+
+	g_free (info);
+}
+
+static SjPluginInfo *
+sj_plugins_engine_load (const gchar *file)
+{
+	SjPluginInfo *info;
+	GKeyFile *plugin_file = NULL;
+	gchar *str;
+
+	g_return_val_if_fail (file != NULL, NULL);
+
+	sj_debug (DEBUG_PLUGINS, "Loading plugin: %s", file);
+
+	info = g_new0 (SjPluginInfo, 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,
+			   	 "Sound Juicer Plugin",
+				 "IAge",
+				 NULL))	{
+	        sj_debug (DEBUG_PLUGINS,
+				  "IAge key does not exist in file: %s", file);
+
+		goto error;
+	}
+	
+	/* Check IAge=1 */
+	if (g_key_file_get_integer (plugin_file,
+				    "Sound Juicer Plugin",
+				    "IAge",
+				    NULL) != 1) {
+		sj_debug (DEBUG_PLUGINS,
+				  "Wrong IAge in file: %s", file);
+
+		goto error;
+	}
+
+	/* Get Location */
+	str = g_key_file_get_string (plugin_file,
+				     "Sound Juicer Plugin",
+				     "Module",
+				     NULL);
+
+	if ((str != NULL) && (*str != '\0')) {
+		info->location = str;
+	} else {
+		g_warning ("Could not find 'Module' in %s", file);
+
+		goto error;
+	}
+
+	/* Get the loader for this plugin */
+	str = g_key_file_get_string (plugin_file,
+				     "Sound Juicer Plugin",
+				     "Loader",
+				     NULL);
+
+	if (str && strcmp(str, "python") == 0) {
+		info->loader = SJ_PLUGIN_LOADER_PY;
+
+#ifndef ENABLE_PYTHON
+		g_warning ("Cannot load Python plugin '%s' since sj was not "
+			   "compiled with Python support.", file);
+
+		goto error;
+#endif
+
+	} else {
+		info->loader = SJ_PLUGIN_LOADER_C;
+	}
+
+	g_free (str);
+
+	/* Get Name */
+	str = g_key_file_get_locale_string (plugin_file,
+					    "Sound Juicer 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,
+					    "Sound Juicer Plugin",
+					    "Description",
+					    NULL, NULL);
+	if (str) {
+		info->desc = str;
+	} else {
+		sj_debug (DEBUG_PLUGINS, "Could not find 'Description' in %s", file);
+ 	}
+
+	/* Get Icon */
+	str = g_key_file_get_locale_string (plugin_file,
+					    "Sound Juicer Plugin",
+					    "Icon",
+					    NULL, NULL);
+	if (str) {
+		info->icon_name = str;
+	} else {
+		sj_debug (DEBUG_PLUGINS, "Could not find 'Icon' in %s, "
+				  "using 'sj-plugin'", file);
+	}
+
+	/* Get Authors */
+	info->authors = g_key_file_get_string_list (plugin_file,
+						    "Sound Juicer Plugin",
+						    "Authors",
+						    NULL,
+						    NULL);
+
+	if (info->authors == NULL)
+		sj_debug (DEBUG_PLUGINS, "Could not find 'Authors' in %s", file);
+
+	/* Get Copyright */
+	str = g_key_file_get_string (plugin_file,
+				     "Sound Juicer Plugin",
+				     "Copyright",
+				     NULL);
+	if (str) {
+		info->copyright = str;
+	} else {
+		sj_debug (DEBUG_PLUGINS, "Could not find 'Copyright' in %s", file);
+	}
+
+	/* Get Website */
+	str = g_key_file_get_string (plugin_file,
+				     "Sound Juicer Plugin",
+				     "Website",
+				     NULL);
+	if (str) {
+		info->website = str;
+	} else {
+		sj_debug (DEBUG_PLUGINS, "Could not find 'Website' 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->location);
+	g_free (info->name);
+	g_free (info);
+	g_key_file_free (plugin_file);
+
+	return NULL;
+}
+
+static gint
+compare_plugin_info (SjPluginInfo *info1,
+		     SjPluginInfo *info2)
+{
+	return strcmp (info1->location, info2->location);
+}
+
+static void
+sj_plugins_engine_load_dir (const gchar *dir)
+{
+	GError *error = NULL;
+	GDir *d;
+	const gchar *dirent;
+
+	g_return_if_fail (sj_plugins_engine_gconf_client != NULL);
+
+	sj_debug (DEBUG_PLUGINS, "DIR: %s", dir);
+
+	d = g_dir_open (dir, 0, &error);
+
+	if (!d)	{
+		g_warning (error->message);
+		g_error_free (error);
+
+		return;
+	}
+
+	while ((dirent = g_dir_read_name (d))) {
+		if (g_str_has_suffix (dirent, PLUGIN_EXT)) {
+			gchar *plugin_file;
+			SjPluginInfo *info;
+			
+			plugin_file = g_build_filename (dir, dirent, NULL);
+			info = sj_plugins_engine_load (plugin_file);
+			g_free (plugin_file);
+
+			if (info == NULL)
+				continue;
+
+			/* If a plugin with this name has already been loaded
+			 * drop this one (user plugins override system plugins) */
+			if (g_list_find_custom (sj_plugins_list,
+						info,
+						(GCompareFunc)compare_plugin_info) != NULL) {
+				g_warning ("Two or more plugins named '%s'. "
+					   "Only the first will be considered.\n",
+					   info->location);
+
+				sj_plugin_info_free (info);
+
+				continue;
+			}
+
+			/* Actually, the plugin will be activated when reactivate_all
+			 * will be called for the first time. */
+			info->active = (g_slist_find_custom (active_plugins,
+							     info->location,
+							     (GCompareFunc)strcmp) != NULL);
+
+			sj_plugins_list = g_list_prepend (sj_plugins_list, info);
+
+			sj_debug (DEBUG_PLUGINS, "Plugin %s loaded", info->name);
+		}
+	}
+
+	sj_plugins_list = g_list_reverse (sj_plugins_list);
+
+	g_dir_close (d);
+}
+
+static void
+sj_plugins_engine_load_all (void)
+{
+	gchar *pdir;
+
+	pdir = gnome_util_home_file (USER_SJ_PLUGINS_LOCATION);
+
+	/* Load user's plugins */
+	if (g_file_test (pdir, G_FILE_TEST_IS_DIR))
+		sj_plugins_engine_load_dir (pdir);
+
+	g_free (pdir);
+
+	/* Load system plugins */
+	sj_plugins_engine_load_dir (PLUGINDIR "/");
+}
+
+gboolean
+sj_plugins_engine_init (void)
+{
+	g_return_val_if_fail (sj_plugins_list == NULL, FALSE);
+	
+	if (!g_module_supported ()) {
+		g_warning ("sj is not able to initialize the plugins engine.");
+
+		return FALSE;
+	}
+
+	sj_plugins_engine_gconf_client = gconf_client_get_default ();
+
+	g_return_val_if_fail (sj_plugins_engine_gconf_client != NULL, FALSE);
+
+	gconf_client_add_dir (sj_plugins_engine_gconf_client,
+			      GCONF_PLUGINS_ROOT,
+			      GCONF_CLIENT_PRELOAD_ONELEVEL,
+			      NULL);
+
+	gconf_client_notify_add (sj_plugins_engine_gconf_client,
+				 GCONF_PLUGINS_ACTIVE_PLUGINS,
+				 sj_plugins_engine_active_plugins_changed,
+				 NULL, NULL, NULL);
+
+	active_plugins = gconf_client_get_list (sj_plugins_engine_gconf_client,
+						GCONF_PLUGINS_ACTIVE_PLUGINS,
+						GCONF_VALUE_STRING,
+						NULL);
+
+	sj_plugins_engine_load_all ();
+
+	return TRUE;
+}
+
+void
+sj_plugins_engine_garbage_collect (void)
+{
+#ifdef ENABLE_PYTHON
+	sj_python_garbage_collect ();
+#endif
+}
+
+void
+sj_plugins_engine_shutdown (void)
+{
+	GList *pl;
+
+#ifdef ENABLE_PYTHON
+	/* Note: that this may cause finalization of objects (typically
+	 * the SjWindow) by running the garbage collector. Since some
+	 * of the plugin may have installed callbacks upon object
+	 * finalization (typically they need to free the WindowData)
+	 * it must run before we get rid of the plugins.
+	 */
+	sj_python_shutdown ();
+#endif
+
+	g_return_if_fail (sj_plugins_engine_gconf_client != NULL);
+
+	for (pl = sj_plugins_list; pl; pl = pl->next) {
+		SjPluginInfo *info = (SjPluginInfo*) pl->data;
+
+		sj_plugin_info_free (info);
+	}
+
+	g_slist_foreach (active_plugins, (GFunc)g_free, NULL);
+	g_slist_free (active_plugins);
+
+	active_plugins = NULL;
+
+	g_list_free (sj_plugins_list);
+	sj_plugins_list = NULL;
+
+	g_object_unref (sj_plugins_engine_gconf_client);
+	sj_plugins_engine_gconf_client = NULL;
+}
+
+const GList *
+sj_plugins_engine_get_plugins_list (void)
+{
+	return sj_plugins_list;
+}
+
+static gboolean
+load_plugin_module (SjPluginInfo *info)
+{
+	gchar *path;
+	gchar *dirname;
+
+	g_return_val_if_fail (info != NULL, FALSE);
+	g_return_val_if_fail (info->file != NULL, FALSE);
+	g_return_val_if_fail (info->location != NULL, FALSE);
+	g_return_val_if_fail (info->plugin == NULL, FALSE);
+	g_return_val_if_fail (info->available, FALSE);
+
+	switch (info->loader) {
+	case SJ_PLUGIN_LOADER_C:
+		dirname = g_path_get_dirname (info->file);	
+		g_return_val_if_fail (dirname != NULL, FALSE);
+
+		path = g_module_build_path (dirname, info->location);
+
+		g_free (dirname);
+
+		g_return_val_if_fail (path != NULL, FALSE);
+
+		info->module = G_TYPE_MODULE (sj_module_new (path));
+
+		g_free (path);
+
+		break;
+
+#ifdef ENABLE_PYTHON
+	case SJ_PLUGIN_LOADER_PY:
+	{
+		gchar *dir;
+
+		if (!sj_python_init ()) {
+			/* Mark plugin as unavailable and fails */
+			info->available = FALSE;
+
+			g_warning ("Cannot load Python plugin '%s' since sj "
+			           "was not able to initialize the Python interpreter.",
+			           info->name);
+
+			return FALSE;
+		}
+
+		dir = g_path_get_dirname (info->file);
+
+		g_return_val_if_fail ((info->location != NULL) &&
+		                      (info->location[0] != '\0'),
+		                      FALSE);
+
+		info->module = G_TYPE_MODULE (
+				sj_python_module_new (dir, info->location));
+
+		g_free (dir);
+
+		break;
+	}
+#endif
+	default:
+		g_return_val_if_reached (FALSE);
+	}
+
+	if (!g_type_module_use (info->module)) {
+		switch (info->loader) {
+		case SJ_PLUGIN_LOADER_C:
+			g_warning ("Cannot load plugin '%s' since file '%s' cannot be read.",
+				   info->name,
+				   sj_module_get_path (SJ_MODULE (info->module)));
+			break;
+
+		case SJ_PLUGIN_LOADER_PY:
+			g_warning ("Cannot load Python plugin '%s' since file '%s' cannot be read.",
+				   info->name,
+				   info->location);
+			break;
+
+		default:
+			g_return_val_if_reached (FALSE);
+		}
+
+		g_object_unref (G_OBJECT (info->module));
+
+		info->module = NULL;
+
+		/* Mark plugin as unavailable and fails */
+		info->available = FALSE;
+
+		return FALSE;
+	}
+
+	switch (info->loader) {
+	case SJ_PLUGIN_LOADER_C:
+		info->plugin = 
+			SJ_PLUGIN (sj_module_new_object (SJ_MODULE (info->module)));
+		break;
+
+#ifdef ENABLE_PYTHON
+	case SJ_PLUGIN_LOADER_PY:
+		info->plugin = 
+			SJ_PLUGIN (sj_python_module_new_object (SJ_PYTHON_MODULE (info->module)));
+		break;
+#endif
+
+	default:
+		g_return_val_if_reached (FALSE);
+	}
+
+	g_type_module_unuse (info->module);
+
+	sj_debug (DEBUG_PLUGINS, "End");
+
+	return TRUE;
+}
+
+static gboolean 	 
+sj_plugins_engine_activate_plugin_real (SjPluginInfo *info)
+{
+	gboolean res = TRUE;
+
+	/* Plugin is not available, don't try to activate/load it */
+	if (!info->available) {
+		return FALSE;
+	}
+
+	if (info->plugin == NULL)
+		res = load_plugin_module (info);
+
+	if (res) {
+	        sj_plugin_activate (info->plugin, SJ_WINDOW (main_window));
+	} else {
+		g_warning ("Error activating plugin '%s'", info->name);
+	}
+
+	return res;
+}
+
+gboolean 	 
+sj_plugins_engine_activate_plugin (SjPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, FALSE);
+
+	if (!info->available)
+		return FALSE;
+
+	if (info->active)
+		return TRUE;
+
+	if (sj_plugins_engine_activate_plugin_real (info)) {
+		gboolean res;
+		GSList *list;
+
+		/* Update plugin state */
+		info->active = TRUE;
+
+		list = active_plugins;
+
+		while (list != NULL) {
+			if (strcmp (info->location, (gchar *)list->data) == 0) {
+				g_warning ("Plugin '%s' is already active.", info->name);
+
+				return TRUE;
+			}
+
+			list = g_slist_next (list);
+		}
+
+		active_plugins = g_slist_insert_sorted (active_plugins, 
+						        g_strdup (info->location), 
+						        (GCompareFunc)strcmp);
+
+		res = gconf_client_set_list (sj_plugins_engine_gconf_client,
+		    			     GCONF_PLUGINS_ACTIVE_PLUGINS,
+					     GCONF_VALUE_STRING,
+					     active_plugins,
+					     NULL);
+
+		if (!res)
+			g_warning ("Error saving the list of active plugins.");
+
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void
+sj_plugins_engine_deactivate_plugin_real (SjPluginInfo *info)
+{
+	sj_plugin_deactivate (info->plugin, SJ_WINDOW (main_window));
+}
+
+gboolean
+sj_plugins_engine_deactivate_plugin (SjPluginInfo *info)
+{
+	gboolean res;
+	GSList *list;
+
+	g_return_val_if_fail (info != NULL, FALSE);
+
+	if (!info->active || !info->available)
+		return TRUE;
+
+	sj_plugins_engine_deactivate_plugin_real (info);
+
+	/* Update plugin state */
+	info->active = FALSE;
+
+	list = active_plugins;
+	res = (list == NULL);
+
+	while (list != NULL) {
+		if (strcmp (info->location, (gchar *)list->data) == 0) {
+			g_free (list->data);
+			active_plugins = g_slist_delete_link (active_plugins, list);
+			list = NULL;
+			res = TRUE;
+		} else {
+			list = g_slist_next (list);
+		}
+	}
+
+	if (!res) {
+		g_warning ("Plugin '%s' is already deactivated.", info->name);
+
+		return TRUE;
+	}
+
+	res = gconf_client_set_list (sj_plugins_engine_gconf_client,
+	    			     GCONF_PLUGINS_ACTIVE_PLUGINS,
+				     GCONF_VALUE_STRING,
+				     active_plugins,
+				     NULL);
+
+	if (!res)
+		g_warning ("Error saving the list of active plugins.");
+
+	return TRUE;
+}
+
+gboolean
+sj_plugins_engine_plugin_is_active (SjPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, FALSE);
+
+	return (info->available && info->active);
+}
+
+gboolean
+sj_plugins_engine_plugin_is_available (SjPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, FALSE);
+
+	return (info->available != FALSE);
+}
+
+static void
+reactivate_all (SjWindow *window)
+{
+	GList *pl;
+
+	for (pl = sj_plugins_list; pl; pl = pl->next) {
+		gboolean res = TRUE;
+
+		SjPluginInfo *info = (SjPluginInfo*)pl->data;
+
+		/* If plugin is not available, don't try to activate/load it */
+		if (info->available && info->active) {
+			if (info->plugin == NULL)
+				res = load_plugin_module (info);
+
+			if (res)
+				sj_plugin_activate (info->plugin,
+						     window);	
+		}
+	}
+
+	sj_debug (DEBUG_PLUGINS, "End");
+}
+
+void
+sj_plugins_engine_update_plugins_ui (SjWindow *window,
+				     gboolean  new_window)
+{
+	GList *pl;
+
+/* TODO: enable when a real SjWindow will be implemented */
+#if 0
+	g_return_if_fail (SJ_IS_WINDOW (window));
+#endif
+
+	if (new_window)
+		reactivate_all (window);
+
+	/* Updated ui of all the plugins that implement update_ui */
+	for (pl = sj_plugins_list; pl; pl = pl->next) {
+		SjPluginInfo *info = (SjPluginInfo*)pl->data;
+
+		if (!info->available || !info->active)
+			continue;
+
+	       	sj_debug (DEBUG_PLUGINS, "Updating UI of %s", info->name);
+
+		sj_plugin_update_ui (info->plugin, window);
+	}
+}
+
+gboolean
+sj_plugins_engine_plugin_is_configurable (SjPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, FALSE);
+
+	if ((info->plugin == NULL) || !info->active || !info->available)
+		return FALSE;
+
+	return sj_plugin_is_configurable (info->plugin);
+}
+
+void 	 
+sj_plugins_engine_configure_plugin (SjPluginInfo *info, 
+				    GtkWindow   *parent)
+{
+	GtkWidget *conf_dlg;
+
+	GtkWindowGroup *wg;
+
+	g_return_if_fail (info != NULL);
+
+	conf_dlg = sj_plugin_create_configure_dialog (info->plugin);
+
+	g_return_if_fail (conf_dlg != NULL);
+
+	gtk_window_set_transient_for (GTK_WINDOW (conf_dlg),
+				      parent);
+
+	wg = parent->group;
+
+	if (wg == NULL) {
+		wg = gtk_window_group_new ();
+		gtk_window_group_add_window (wg, parent);
+	}
+
+	gtk_window_group_add_window (wg,
+				     GTK_WINDOW (conf_dlg));
+
+	gtk_window_set_modal (GTK_WINDOW (conf_dlg), TRUE);
+
+	gtk_widget_show (conf_dlg);
+}
+
+static void 
+sj_plugins_engine_active_plugins_changed (GConfClient *client,
+					  guint cnxn_id,
+					  GConfEntry *entry,
+					  gpointer user_data)
+{
+	GList *pl;
+	gboolean to_activate;
+
+	g_return_if_fail (entry->key != NULL);
+	g_return_if_fail (entry->value != NULL);
+
+	if (!((entry->value->type == GCONF_VALUE_LIST) &&
+	      (gconf_value_get_list_type (entry->value) == GCONF_VALUE_STRING))) {
+		g_warning ("The gconf key '%s' may be corrupted.", GCONF_PLUGINS_ACTIVE_PLUGINS);
+		return;
+	}
+
+	active_plugins = gconf_client_get_list (sj_plugins_engine_gconf_client,
+						GCONF_PLUGINS_ACTIVE_PLUGINS,
+						GCONF_VALUE_STRING,
+						NULL);
+
+	for (pl = sj_plugins_list; pl; pl = pl->next) {
+		SjPluginInfo *info = (SjPluginInfo*)pl->data;
+
+		if (!info->available)
+			continue;
+
+		to_activate = (g_slist_find_custom (active_plugins,
+						    info->location,
+						    (GCompareFunc)strcmp) != NULL);
+
+		if (!info->active && to_activate) {
+			/* Activate plugin */
+			if (sj_plugins_engine_activate_plugin_real (info))
+				/* Update plugin state */
+				info->active = TRUE;
+		} else {
+			if (info->active && !to_activate) {
+				sj_plugins_engine_deactivate_plugin_real (info);
+
+				/* Update plugin state */
+				info->active = FALSE;
+			}
+		}
+	}
+}
+
+const gchar *
+sj_plugins_engine_get_plugin_name (SjPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, NULL);
+
+	return info->name;
+}
+
+const gchar *
+sj_plugins_engine_get_plugin_description (SjPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, NULL);
+
+	return info->desc;
+}
+
+const gchar *
+sj_plugins_engine_get_plugin_icon_name (SjPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, NULL);
+
+	/* Use the sj-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 "sj-plugin";
+}
+
+const gchar **
+sj_plugins_engine_get_plugin_authors (SjPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, (const gchar **)NULL);
+
+	return (const gchar **) info->authors;
+}
+
+const gchar *
+sj_plugins_engine_get_plugin_website (SjPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, NULL);
+
+	return info->website;
+}
+
+const gchar *
+sj_plugins_engine_get_plugin_copyright (SjPluginInfo *info)
+{
+	g_return_val_if_fail (info != NULL, NULL);
+
+	return info->copyright;
+}
Index: src/sj-plugins-engine.h
===================================================================
--- src/sj-plugins-engine.h	(revision 0)
+++ src/sj-plugins-engine.h	(revision 0)
@@ -0,0 +1,71 @@
+/*
+ * Sound Juicer - sj-plugins-engine.h
+ *
+ * Based on eog code (derived from gedit)
+ * Copyright (C) 2002-2005 - Paolo Maggi
+ * Copyright (C) 2007 - The Free Software Foundation
+ *
+ * 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 __SJ_PLUGINS_ENGINE_H__
+#define __SJ_PLUGINS_ENGINE_H__
+
+#include "sound-juicer.h"
+
+#include <glib.h>
+
+typedef struct _SjPluginInfo SjPluginInfo;
+
+gboolean	 sj_plugins_engine_init 		(void);
+
+void		 sj_plugins_engine_shutdown 		(void);
+
+void		 sj_plugins_engine_garbage_collect	(void);
+
+const GList	*sj_plugins_engine_get_plugins_list	(void);
+
+gboolean 	 sj_plugins_engine_activate_plugin 	(SjPluginInfo *info);
+
+gboolean 	 sj_plugins_engine_deactivate_plugin	(SjPluginInfo *info);
+
+gboolean 	 sj_plugins_engine_plugin_is_active 	(SjPluginInfo *info);
+
+gboolean 	 sj_plugins_engine_plugin_is_available	(SjPluginInfo *info);
+
+gboolean	 sj_plugins_engine_plugin_is_configurable 
+			       				(SjPluginInfo *info);
+
+void	 	 sj_plugins_engine_configure_plugin	(SjPluginInfo *info, 
+			       			 	 GtkWindow    *parent);
+
+void		 sj_plugins_engine_update_plugins_ui	(SjWindow     *window, 
+			       			 	 gboolean      new_window);
+
+const gchar	*sj_plugins_engine_get_plugin_name	(SjPluginInfo *info);
+
+const gchar	*sj_plugins_engine_get_plugin_description
+			       				(SjPluginInfo *info);
+
+const gchar	*sj_plugins_engine_get_plugin_icon_name	(SjPluginInfo *info);
+
+const gchar    **sj_plugins_engine_get_plugin_authors	(SjPluginInfo *info);
+
+const gchar	*sj_plugins_engine_get_plugin_website	(SjPluginInfo *info);
+
+const gchar	*sj_plugins_engine_get_plugin_copyright	(SjPluginInfo *info);
+
+#endif  /* __SJ_PLUGINS_ENGINE_H__ */
Index: src/sj-plugin.c
===================================================================
--- src/sj-plugin.c	(revision 0)
+++ src/sj-plugin.c	(revision 0)
@@ -0,0 +1,113 @@
+/*
+ * Sound Juicer - sj-plugin.c
+ *
+ * Based on eog code (derived from gedit)
+ * Copyright (C) 2002-2005 - Paolo Maggi
+ * Copyright (C) 2007 - The Free Software Foundation
+ *
+ * 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 "sound-juicer.h"
+#include "sj-plugin.h"
+
+G_DEFINE_TYPE (SjPlugin, sj_plugin, G_TYPE_OBJECT)
+
+static void
+dummy (SjPlugin *plugin, SjWindow *window)
+{
+}
+
+static GtkWidget *
+create_configure_dialog	(SjPlugin *plugin)
+{
+	return NULL;
+}
+
+static gboolean
+is_configurable (SjPlugin *plugin)
+{
+	return (SJ_PLUGIN_GET_CLASS (plugin)->create_configure_dialog !=
+		create_configure_dialog);
+}
+
+static void 
+sj_plugin_class_init (SjPluginClass *klass)
+{
+	klass->activate = dummy;
+	klass->deactivate = dummy;
+	klass->update_ui = dummy;
+	
+	klass->create_configure_dialog = create_configure_dialog;
+	klass->is_configurable = is_configurable;
+}
+
+static void
+sj_plugin_init (SjPlugin *plugin)
+{
+}
+
+void
+sj_plugin_activate (SjPlugin *plugin, SjWindow *window)
+{
+	g_return_if_fail (SJ_IS_PLUGIN (plugin));
+/* TODO: enable when a real SjWindow will be implemented */
+#if 0
+	g_return_if_fail (SJ_IS_WINDOW (window));
+#endif
+
+	SJ_PLUGIN_GET_CLASS (plugin)->activate (plugin, window);
+}
+
+void
+sj_plugin_deactivate (SjPlugin *plugin, SjWindow *window)
+{
+	g_return_if_fail (SJ_IS_PLUGIN (plugin));
+/* TODO: enable when a real SjWindow will be implemented */
+#if 0
+	g_return_if_fail (SJ_IS_WINDOW (window));
+#endif
+
+	SJ_PLUGIN_GET_CLASS (plugin)->deactivate (plugin, window);
+}
+				 
+void
+sj_plugin_update_ui (SjPlugin *plugin, SjWindow *window)
+{
+	g_return_if_fail (SJ_IS_PLUGIN (plugin));
+/* TODO: enable when a real SjWindow will be implemented */
+#if 0
+	g_return_if_fail (SJ_IS_WINDOW (window));
+#endif
+
+	SJ_PLUGIN_GET_CLASS (plugin)->update_ui (plugin, window);
+}
+
+gboolean
+sj_plugin_is_configurable (SjPlugin *plugin)
+{
+	g_return_val_if_fail (SJ_IS_PLUGIN (plugin), FALSE);
+
+	return SJ_PLUGIN_GET_CLASS (plugin)->is_configurable (plugin);
+}
+
+GtkWidget *
+sj_plugin_create_configure_dialog (SjPlugin *plugin)
+{
+	g_return_val_if_fail (SJ_IS_PLUGIN (plugin), NULL);
+	
+	return SJ_PLUGIN_GET_CLASS (plugin)->create_configure_dialog (plugin);
+}
Index: src/sound-juicer.h
===================================================================
--- src/sound-juicer.h	(revision 1798)
+++ src/sound-juicer.h	(working copy)
@@ -87,6 +87,7 @@
   DEBUG_METADATA = 1 << 2,
   DEBUG_EXTRACTING = 1 << 3,
   DEBUG_PLAYING = 1 << 4,
+  DEBUG_PLUGINS = 1 << 5
 } SjDebugDomain;
 
 /**
@@ -160,6 +161,9 @@
 #define GCONF_HTTP_PROXY GCONF_PROXY_ROOT "/host"
 #define GCONF_HTTP_PROXY_PORT GCONF_PROXY_ROOT "/port"
 
+#define GCONF_PLUGINS_ROOT GCONF_ROOT "/plugins"
+#define GCONF_PLUGINS_ACTIVE_PLUGINS GCONF_PLUGINS_ROOT "/active-plugins"
+
 /**
  * Custom stock icons
  */
@@ -170,4 +174,11 @@
 /* TODO: need to add a SjWindow object or something */
 void sj_main_set_title (const char* detail);
 
+/**
+ * TODO: remove as soon as possible
+ * added for making plugin system happy
+*/
+typedef GtkWindow SjWindow;
+#define SJ_WINDOW(win) ((SjWindow *)win)
+
 #endif /* SOUND_JUICER_H */
Index: src/sj-plugin.h
===================================================================
--- src/sj-plugin.h	(revision 0)
+++ src/sj-plugin.h	(revision 0)
@@ -0,0 +1,220 @@
+/*
+ * Sound Juicer - sj-plugin.h
+ *
+ * Based on eog code (derived from gedit)
+ * Copyright (C) 2002-2005 - Paolo Maggi
+ * Copyright (C) 2007 - The Free Software Foundation
+ *
+ * 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 __SJ_PLUGIN_H__
+#define __SJ_PLUGIN_H__
+
+#include "sound-juicer.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _SjPlugin SjPlugin;
+typedef struct _SjPluginClass SjPluginClass;
+typedef struct _SjPluginPrivate SjPluginPrivate;
+
+#define SJ_TYPE_PLUGIN            (sj_plugin_get_type())
+#define SJ_PLUGIN(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), SJ_TYPE_PLUGIN, SjPlugin))
+#define SJ_PLUGIN_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST((obj), SJ_TYPE_PLUGIN, SjPlugin const))
+#define SJ_PLUGIN_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  SJ_TYPE_PLUGIN, SjPluginClass))
+#define SJ_IS_PLUGIN(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), SJ_TYPE_PLUGIN))
+#define SJ_IS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SJ_TYPE_PLUGIN))
+#define SJ_PLUGIN_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  SJ_TYPE_PLUGIN, SjPluginClass))
+
+struct _SjPlugin {
+	GObject parent;
+};
+
+struct _SjPluginClass  {
+	GObjectClass parent_class;
+
+	void 		(*activate)		(SjPlugin *plugin,
+						 SjWindow *window);
+
+	void 		(*deactivate)		(SjPlugin *plugin,
+						 SjWindow *window);
+
+	void 		(*update_ui)		(SjPlugin *plugin,
+						 SjWindow *window);
+
+	GtkWidget 	*(*create_configure_dialog)
+						(SjPlugin *plugin);
+
+	/* Plugins should not override this, it's handled automatically 
+ 	 * by the SjPluginClass */
+	gboolean 	(*is_configurable)
+						(SjPlugin *plugin);
+
+	/* Padding for future expansion */
+	void		(*_sj_reserved1)	(void);
+	void		(*_sj_reserved2)	(void);
+	void		(*_sj_reserved3)	(void);
+	void		(*_sj_reserved4)	(void);
+};
+
+GType 		 sj_plugin_get_type 		(void) G_GNUC_CONST;
+
+void 		 sj_plugin_activate		(SjPlugin *plugin,
+						 SjWindow *window);
+
+void 		 sj_plugin_deactivate	        (SjPlugin *plugin,
+						 SjWindow *window);
+
+void 		 sj_plugin_update_ui		(SjPlugin *plugin,
+						 SjWindow *window);
+
+gboolean	 sj_plugin_is_configurable	(SjPlugin *plugin);
+
+GtkWidget	*sj_plugin_create_configure_dialog
+						(SjPlugin *plugin);
+
+/*
+ * Utility macro used to register plugins
+ *
+ * use: SJ_PLUGIN_REGISTER_TYPE_WITH_CODE(PluginName, plugin_name, CODE)
+ */
+#define SJ_PLUGIN_REGISTER_TYPE_WITH_CODE(PluginName, plugin_name, CODE)	\
+										\
+static GType plugin_name##_type = 0;						\
+										\
+GType										\
+plugin_name##_get_type (void)							\
+{										\
+	return plugin_name##_type;						\
+}										\
+										\
+static void     plugin_name##_init              (PluginName        *self);	\
+static void     plugin_name##_class_init        (PluginName##Class *klass);	\
+static gpointer plugin_name##_parent_class = NULL;				\
+static void     plugin_name##_class_intern_init (gpointer klass)		\
+{										\
+	plugin_name##_parent_class = g_type_class_peek_parent (klass);		\
+	plugin_name##_class_init ((PluginName##Class *) klass);			\
+}										\
+										\
+G_MODULE_EXPORT GType								\
+register_sj_plugin (GTypeModule *module)					\
+{										\
+	static const GTypeInfo our_info =					\
+	{									\
+		sizeof (PluginName##Class),					\
+		NULL, /* base_init */						\
+		NULL, /* base_finalize */					\
+		(GClassInitFunc) plugin_name##_class_intern_init,		\
+		NULL,								\
+		NULL, /* class_data */						\
+		sizeof (PluginName),						\
+		0, /* n_preallocs */						\
+		(GInstanceInitFunc) plugin_name##_init				\
+	};									\
+										\
+	sj_debug (DEBUG_PLUGINS, "Registering " #PluginName);			\
+										\
+	/* Initialise the i18n stuff */						\
+	bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);			\
+	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");			\
+										\
+	plugin_name##_type = g_type_module_register_type (module,		\
+					    SJ_TYPE_PLUGIN,			\
+					    #PluginName,			\
+					    &our_info,				\
+					    0);					\
+										\
+	CODE									\
+										\
+	return plugin_name##_type;						\
+}
+
+/*
+ * Utility macro used to register plugins
+ *
+ * use: SJ_PLUGIN_REGISTER_TYPE(PluginName, plugin_name)
+ */
+#define SJ_PLUGIN_REGISTER_TYPE(PluginName, plugin_name)			\
+	SJ_PLUGIN_REGISTER_TYPE_WITH_CODE(PluginName, plugin_name, ;)
+
+/*
+ * Utility macro used to register gobject types in plugins with additional code
+ *
+ * use: SJ_PLUGIN_DEFINE_TYPE_WITH_CODE(ObjectName, object_name, PARENT_TYPE, CODE)
+ */
+#define SJ_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 *module)					\
+{											\
+	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					\
+	};										\
+											\
+	sj_debug_message (DEBUG_PLUGINS, "Registering " #ObjectName);			\
+											\
+	g_define_type_id = g_type_module_register_type (module,				\
+					   	        PARENT_TYPE,			\
+					                #ObjectName,			\
+					                &our_info,			\
+					                0);				\
+											\
+	CODE										\
+											\
+	return g_define_type_id;							\
+}
+
+/*
+ * Utility macro used to register gobject types in plugins
+ *
+ * use: SJ_PLUGIN_DEFINE_TYPE(ObjectName, object_name, PARENT_TYPE)
+ */
+#define SJ_PLUGIN_DEFINE_TYPE(ObjectName, object_name, PARENT_TYPE)			\
+	SJ_PLUGIN_DEFINE_TYPE_WITH_CODE(ObjectName, object_name, PARENT_TYPE, ;)
+
+G_END_DECLS
+
+#endif  /* __SJ_PLUGIN_H__ */
Index: src/sj-plugin-manager.c
===================================================================
--- src/sj-plugin-manager.c	(revision 0)
+++ src/sj-plugin-manager.c	(revision 0)
@@ -0,0 +1,891 @@
+/*
+ * Sound Juicer - sj-plugins-manager.c
+ *
+ * Based on eog code (derived from gedit)
+ * Copyright (C) 2002 - Paolo Maggi and James Willcox
+ * Copyright (C) 2003-2006 Paolo Maggi
+ * Copyright (C) 2007 - The Free Software Foundation
+ *
+ * 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 "sound-juicer.h"
+
+#include <string.h>
+
+#include "sj-plugin-manager.h"
+#include "sj-plugins-engine.h"
+#include "sj-plugin.h"
+
+#include <glib/gi18n.h>
+#include <glade/glade-xml.h>
+#include <libgnome/gnome-url.h>
+
+enum {
+	ACTIVE_COLUMN,
+	AVAILABLE_COLUMN,
+	INFO_COLUMN,
+	N_COLUMNS
+};
+
+#define SJ_PLUGIN_MANAGER_GET_PRIVATE(object) \
+	(G_TYPE_INSTANCE_GET_PRIVATE ((object), SJ_TYPE_PLUGIN_MANAGER, SjPluginManagerPrivate))
+
+G_DEFINE_TYPE (SjPluginManager, sj_plugin_manager, GTK_TYPE_VBOX)
+
+#define PLUGIN_MANAGER_NAME_TITLE   _("Plugin")
+#define PLUGIN_MANAGER_ACTIVE_TITLE _("Enabled")
+
+struct _SjPluginManagerPrivate {
+	GtkWidget	*tree;
+
+	GtkWidget	*about_button;
+	GtkWidget	*configure_button;
+
+	const GList	*plugins;
+
+	GtkWidget 	*about;
+	
+	GtkWidget	*popup_menu;
+};
+
+static SjPluginInfo *plugin_manager_get_selected_plugin (SjPluginManager *pm); 
+static void plugin_manager_toggle_active (GtkTreeIter *iter, GtkTreeModel *model); 
+static void sj_plugin_manager_finalize (GObject *object);
+
+static void 
+sj_plugin_manager_class_init (SjPluginManagerClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = sj_plugin_manager_finalize;
+
+	g_type_class_add_private (object_class, sizeof (SjPluginManagerPrivate));
+}
+
+static void
+about_button_cb (GtkWidget       *button,
+		 SjPluginManager *pm)
+{
+	SjPluginInfo *info;
+
+	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,
+		"name", sj_plugins_engine_get_plugin_name (info),
+		"copyright", sj_plugins_engine_get_plugin_copyright (info),
+		"authors", sj_plugins_engine_get_plugin_authors (info),
+		"comments", sj_plugins_engine_get_plugin_description (info),
+		"website", sj_plugins_engine_get_plugin_website (info),
+		"logo-icon-name", sj_plugins_engine_get_plugin_icon_name (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,
+		     SjPluginManager *pm)
+{
+	SjPluginInfo *info;
+	GtkWindow *toplevel;
+
+	info = plugin_manager_get_selected_plugin (pm);
+
+	g_return_if_fail (info != NULL);
+
+	sj_debug (DEBUG_PLUGINS, "Configuring: %s\n", 
+		  sj_plugins_engine_get_plugin_name (info));
+
+	toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET(pm)));
+
+	sj_plugins_engine_configure_plugin (info, toplevel);
+
+	sj_debug (DEBUG_PLUGINS, "Done");
+}
+
+static void
+plugin_manager_view_info_cell_cb (GtkTreeViewColumn *tree_column,
+				  GtkCellRenderer   *cell,
+				  GtkTreeModel      *tree_model,
+				  GtkTreeIter       *iter,
+				  gpointer           data)
+{
+	SjPluginInfo *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",
+					sj_plugins_engine_get_plugin_name (info),
+					sj_plugins_engine_get_plugin_description (info));
+
+	g_object_set (G_OBJECT (cell),
+		      "markup", text,
+		      "sensitive", sj_plugins_engine_plugin_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)
+{
+	SjPluginInfo *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", sj_plugins_engine_get_plugin_icon_name (info),
+		      "sensitive", sj_plugins_engine_plugin_is_available (info),
+		      NULL);
+}
+
+
+static void
+active_toggled_cb (GtkCellRendererToggle *cell,
+		   gchar                 *path_str,
+		   SjPluginManager       *pm)
+{
+	GtkTreeIter iter;
+	GtkTreePath *path;
+	GtkTreeModel *model;
+
+	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 (&iter, model);
+
+	gtk_tree_path_free (path);
+}
+
+static void
+cursor_changed_cb (GtkTreeView *view,
+		   gpointer     data)
+{
+	SjPluginManager *pm = data;
+	SjPluginInfo *info;
+
+	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) && 
+				   sj_plugins_engine_plugin_is_configurable (info));
+}
+
+static void
+row_activated_cb (GtkTreeView       *tree_view,
+		  GtkTreePath       *path,
+		  GtkTreeViewColumn *column,
+		  gpointer           data)
+{
+	SjPluginManager *pm = data;
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+
+	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 (&iter, model);
+}
+
+static void
+plugin_manager_populate_lists (SjPluginManager *pm)
+{
+	const GList *plugins;
+	GtkListStore *model;
+	GtkTreeIter iter;
+
+	plugins = pm->priv->plugins;
+
+	model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (pm->priv->tree)));
+
+	while (plugins) {
+		SjPluginInfo *info;
+		info = (SjPluginInfo *)plugins->data;
+
+		gtk_list_store_append (model, &iter);
+		gtk_list_store_set (model, &iter,
+				    ACTIVE_COLUMN, sj_plugins_engine_plugin_is_active (info),
+				    AVAILABLE_COLUMN, sj_plugins_engine_plugin_is_available (info),
+				    INFO_COLUMN, info,
+				    -1);
+
+		plugins = plugins->next;
+	}
+
+	if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter)) {
+		GtkTreeSelection *selection;
+		SjPluginInfo *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),
+					  sj_plugins_engine_plugin_is_configurable (info));
+	}
+}
+
+static gboolean
+plugin_manager_set_active (GtkTreeIter  *iter,
+			   GtkTreeModel *model,
+			   gboolean      active)
+{
+	SjPluginInfo *info;
+	gboolean res = TRUE;
+
+	gtk_tree_model_get (model, iter, INFO_COLUMN, &info, -1);
+
+	g_return_val_if_fail (info != NULL, FALSE);
+
+	if (active) {
+		/* Activate the plugin */
+		if (!sj_plugins_engine_activate_plugin (info)) {
+			sj_debug (DEBUG_PLUGINS, "Could not activate %s.\n", 
+				  sj_plugins_engine_get_plugin_name (info));
+  
+			res = FALSE;
+		}
+	} else {
+		/* Deactivate the plugin */
+		if (!sj_plugins_engine_deactivate_plugin (info)) {
+			sj_debug (DEBUG_PLUGINS, "Could not deactivate %s.\n", 
+				  sj_plugins_engine_get_plugin_name (info));
+
+			res = FALSE;
+		}
+	}
+  
+	/* Set new value */
+	gtk_list_store_set (GTK_LIST_STORE (model), 
+			    iter, 
+			    ACTIVE_COLUMN, sj_plugins_engine_plugin_is_active (info),
+			    AVAILABLE_COLUMN, sj_plugins_engine_plugin_is_available (info),
+			    -1);
+
+	return res;
+}
+
+static void
+plugin_manager_toggle_active (GtkTreeIter  *iter,
+			      GtkTreeModel *model)
+{
+	gboolean active;
+
+	gtk_tree_model_get (model, iter, ACTIVE_COLUMN, &active, -1);
+
+	active ^= 1;
+
+	plugin_manager_set_active (iter, model, active);
+}
+
+static SjPluginInfo *
+plugin_manager_get_selected_plugin (SjPluginManager *pm)
+{
+	SjPluginInfo *info = NULL;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	GtkTreeSelection *selection;
+
+	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 (SjPluginManager *pm,
+			       gboolean         active)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+
+	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 (&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)
+{
+	SjPluginInfo *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 (sj_plugins_engine_get_plugin_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,
+		       SjPluginManager *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 (&iter, model);
+}
+
+static void
+enable_all_menu_cb (GtkMenu         *menu,
+		    SjPluginManager *pm)
+{
+	plugin_manager_set_active_all (pm, TRUE);
+}
+
+static void
+disable_all_menu_cb (GtkMenu         *menu,
+		     SjPluginManager *pm)
+{
+	plugin_manager_set_active_all (pm, FALSE);
+}
+
+static GtkWidget *
+create_tree_popup_menu (SjPluginManager *pm)
+{
+	GtkWidget *menu;
+	GtkWidget *item;
+	GtkWidget *image;
+	SjPluginInfo *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,
+				  sj_plugins_engine_plugin_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,
+				  sj_plugins_engine_plugin_is_available (info));	
+	gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
+					sj_plugins_engine_plugin_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 (SjPluginManager *pm,
+			GtkMenu         *menu)
+{
+	pm->priv->popup_menu = NULL;
+}
+
+static void
+menu_position_under_widget (GtkMenu  *menu,
+			    gint     *x,
+			    gint     *y,
+			    gboolean *push_in,
+			    gpointer  user_data)
+{
+	GtkWidget *w = GTK_WIDGET (user_data);
+	GtkRequisition requisition;
+
+	gdk_window_get_origin (w->window, x, y);
+	gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
+
+	if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL) {
+		*x += w->allocation.x + w->allocation.width - requisition.width;
+	} else {
+		*x += w->allocation.x;
+	}
+
+	*y += w->allocation.y + w->allocation.height;
+
+	*push_in = TRUE;
+}
+
+static void
+menu_position_under_tree_view (GtkMenu  *menu,
+			       gint     *x,
+			       gint     *y,
+			       gboolean *push_in,
+			       gpointer  user_data)
+{
+	GtkTreeView *tree = GTK_TREE_VIEW (user_data);
+	GtkTreeModel *model;
+	GtkTreeSelection *selection;
+	GtkTreeIter iter;
+
+	model = gtk_tree_view_get_model (tree);
+
+	g_return_if_fail (model != NULL);
+
+	selection = gtk_tree_view_get_selection (tree);
+
+	g_return_if_fail (selection != NULL);
+
+	if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+		GtkTreePath *path;
+		GdkRectangle rect;
+
+		gdk_window_get_origin (GTK_WIDGET (tree)->window, x, y);
+			
+		path = gtk_tree_model_get_path (model, &iter);
+
+		gtk_tree_view_get_cell_area (tree, 
+					     path,
+					     gtk_tree_view_get_column (tree, 0), /* FIXME 0 for RTL ? */
+					     &rect);
+		gtk_tree_path_free (path);
+		
+		*x += rect.x;
+		*y += rect.y + rect.height;
+		
+		if (gtk_widget_get_direction (GTK_WIDGET (tree)) == GTK_TEXT_DIR_RTL) {
+			GtkRequisition requisition;
+
+			gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
+
+			*x += rect.width - requisition.width;
+		}
+	} else {
+		/* No selection -> regular "under widget" positioning */
+		menu_position_under_widget (menu,
+					    x, y, push_in,
+					    tree);
+	}
+}
+static void
+show_tree_popup_menu (GtkTreeView     *tree,
+		      SjPluginManager *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,
+				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,
+		       SjPluginManager *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,
+	       SjPluginManager *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)
+{
+	SjPluginInfo *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 (sj_plugins_engine_get_plugin_name (info1),
+			       sj_plugins_engine_get_plugin_name (info2));
+}
+
+static void
+plugin_manager_construct_tree (SjPluginManager *pm)
+{
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *cell;
+	GtkListStore *model;
+
+	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 
+sj_plugin_manager_init (SjPluginManager *pm)
+{
+	GtkWidget *label;
+	GtkWidget *alignment;
+	GtkWidget *viewport;
+	GtkWidget *hbuttonbox;
+	gchar *markup;
+
+	pm->priv = SJ_PLUGIN_MANAGER_GET_PRIVATE (pm);
+
+	gtk_box_set_spacing (GTK_BOX (pm), 6);
+
+	label = gtk_label_new (NULL);
+	markup = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>",
+					  _("Active plugins"));
+	gtk_label_set_markup (GTK_LABEL (label), markup);
+
+	g_free (markup);
+
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+
+	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+	
+	gtk_box_pack_start (GTK_BOX (pm), label, FALSE, TRUE, 0);
+	
+	alignment = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
+	gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 12, 0);
+	gtk_box_pack_start (GTK_BOX (pm), alignment, TRUE, TRUE, 0);
+	
+	viewport = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (viewport),
+					GTK_POLICY_AUTOMATIC,
+					GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (viewport), 
+					     GTK_SHADOW_IN);
+
+	gtk_container_add (GTK_CONTAINER (alignment), viewport);
+
+	pm->priv->tree = gtk_tree_view_new ();
+	gtk_container_add (GTK_CONTAINER (viewport), pm->priv->tree);
+
+	hbuttonbox = gtk_hbutton_box_new ();
+
+	gtk_box_pack_start (GTK_BOX (pm), hbuttonbox, FALSE, FALSE, 0);
+
+	gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_END);
+	gtk_box_set_spacing (GTK_BOX (hbuttonbox), 8);
+
+	pm->priv->about_button = gtk_button_new_with_mnemonic (_("_About Plugin"));
+	gtk_button_set_image (GTK_BUTTON (pm->priv->about_button),
+			      gtk_image_new_from_stock (GTK_STOCK_ABOUT,
+							GTK_ICON_SIZE_BUTTON));
+
+	gtk_container_add (GTK_CONTAINER (hbuttonbox), pm->priv->about_button);
+
+	pm->priv->configure_button = gtk_button_new_with_mnemonic (_("C_onfigure Plugin"));
+	gtk_button_set_image (GTK_BUTTON (pm->priv->configure_button),
+			      gtk_image_new_from_stock (GTK_STOCK_PREFERENCES,
+							GTK_ICON_SIZE_BUTTON));
+
+	gtk_container_add (GTK_CONTAINER (hbuttonbox), pm->priv->configure_button);
+
+	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 list of available plugins (or installed) */
+	pm->priv->plugins = sj_plugins_engine_get_plugins_list ();
+
+	if (pm->priv->plugins != 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
+sj_plugin_manager_finalize (GObject *object)
+{
+	SjPluginManager *pm = SJ_PLUGIN_MANAGER (object);
+
+	if (pm->priv->popup_menu)
+		gtk_widget_destroy (pm->priv->popup_menu);
+
+	G_OBJECT_CLASS (sj_plugin_manager_parent_class)->finalize (object);
+}
+
+GtkWidget *
+sj_plugin_manager_new (void)
+{
+	return g_object_new (SJ_TYPE_PLUGIN_MANAGER, NULL);
+}
Index: src/sj-plugin-manager.h
===================================================================
--- src/sj-plugin-manager.h	(revision 0)
+++ src/sj-plugin-manager.h	(revision 0)
@@ -0,0 +1,58 @@
+/*
+ * Sound Juicer - sj-plugins-manager.h
+ *
+ * Based on eog code (derived from gedit)
+ * Copyright (C) 2002-2005 Paolo Maggi
+ * Copyright (C) 2007 - The Free Software Foundation
+ *
+ * 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 __SJ_PLUGIN_MANAGER_H__
+#define __SJ_PLUGIN_MANAGER_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _SjPluginManager SjPluginManager;
+typedef struct _SjPluginManagerClass SjPluginManagerClass;
+typedef struct _SjPluginManagerPrivate SjPluginManagerPrivate;
+
+#define SJ_TYPE_PLUGIN_MANAGER            (sj_plugin_manager_get_type())
+#define SJ_PLUGIN_MANAGER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), SJ_TYPE_PLUGIN_MANAGER, SjPluginManager))
+#define SJ_PLUGIN_MANAGER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  SJ_TYPE_PLUGIN_MANAGER, SjPluginManagerClass))
+#define SJ_IS_PLUGIN_MANAGER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), SJ_TYPE_PLUGIN_MANAGER))
+#define SJ_IS_PLUGIN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),  SJ_TYPE_PLUGIN_MANAGER))
+#define SJ_PLUGIN_MANAGER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  SJ_TYPE_PLUGIN_MANAGER, SjPluginManagerClass))
+
+struct _SjPluginManager {
+	GtkVBox vbox;
+
+	SjPluginManagerPrivate *priv;
+};
+
+struct _SjPluginManagerClass {
+	GtkVBoxClass parent_class;
+};
+
+GType		 sj_plugin_manager_get_type	(void) G_GNUC_CONST;
+
+GtkWidget	*sj_plugin_manager_new		(void);
+
+G_END_DECLS
+
+#endif  /* __SJ_PLUGIN_MANAGER_H__  */
Index: src/Makefile.am
===================================================================
--- src/Makefile.am	(revision 1798)
+++ src/Makefile.am	(working copy)
@@ -13,6 +13,14 @@
 	sj-about.c \
 	sj-extracting.h \
 	sj-extracting.c \
+	sj-module.h \
+	sj-module.c \
+	sj-plugin.h \
+	sj-plugin.c \
+	sj-plugin-manager.h \
+	sj-plugin-manager.c \
+	sj-plugins-engine.h \
+	sj-plugins-engine.c \
 	gconf-bridge.h \
 	gconf-bridge.c \
 	bacon-volume.c \
@@ -21,13 +29,14 @@
 
 sound_juicer_CPPFLAGS = \
 	-I$(top_srcdir)/libjuicer \
-	-DGNOMELOCALEDIR=\""$(datadir)/locale"\"  \
+	-DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
 	-DDATADIR=\""$(datadir)"\" \
 	-DPREFIX=\""$(prefix)"\" \
 	-DLIBDIR=\""$(libdir)"\" \
 	-DSYSCONFDIR=\""$(sysconfdir)"\" \
 	-DPIXMAPDIR=\""$(datadir)/pixmaps"\" \
 	-DPKGDATADIR=\""$(datadir)/sound-juicer"\" \
+	-DPLUGINDIR=\""$(libdir)/sound-juicer/plugins"\" \
 	$(DISABLE_DEPRECATED) \
 	$(AM_CPPFLAGS)
 
Index: src/sj-prefs.c
===================================================================
--- src/sj-prefs.c	(revision 1798)
+++ src/sj-prefs.c	(working copy)
@@ -35,6 +35,7 @@
 #include "gconf-bridge.h"
 #include "sj-extracting.h"
 #include "sj-prefs.h"
+#include "sj-plugin-manager.h"
 
 extern GladeXML *glade;
 extern GtkWidget *main_window;
@@ -42,6 +43,7 @@
 static GtkWidget *audio_profile;
 static GtkWidget *cd_option, *path_option, *file_option, *basepath_fcb, *check_strip, *check_eject;
 static GtkWidget *path_example_label;
+static GtkWidget *plugin_manager_place_holder;
 
 #define DEFAULT_AUDIO_PROFILE_NAME "cdlossy"
 
@@ -362,14 +364,17 @@
 void on_edit_preferences_cb (GtkMenuItem *item, gpointer user_data)
 {
   static GtkWidget *prefs_dialog = NULL;
+  static GtkWidget *prefs_notebook = NULL;
 
   if (prefs_dialog) {
+    gtk_notebook_set_current_page (GTK_NOTEBOOK (prefs_notebook), 0);
     gtk_window_present (GTK_WINDOW (prefs_dialog));
   } else {
     const char *labels[] = { "cd_label", "path_label", "folder_label", "file_label", "profile_label" };
     guint i;
     GtkSizeGroup *group;
     GConfBridge *bridge = gconf_bridge_get ();
+    GtkWidget *page_content;
 
     prefs_dialog = glade_xml_get_widget (glade, "prefs_dialog");
     g_assert (prefs_dialog != NULL);
@@ -398,12 +403,25 @@
     check_strip = glade_xml_get_widget (glade, "check_strip");
     check_eject = glade_xml_get_widget (glade, "check_eject");
     path_example_label = glade_xml_get_widget (glade, "path_example_label");
+    plugin_manager_place_holder = glade_xml_get_widget (glade, "plugin_manager_place_holder");
+    prefs_notebook = glade_xml_get_widget (glade, "prefs_notebook");
 
     populate_pattern_combo (GTK_COMBO_BOX (path_option), path_patterns);
     g_signal_connect (path_option, "changed", G_CALLBACK (prefs_path_option_changed), NULL);
     populate_pattern_combo (GTK_COMBO_BOX (file_option), file_patterns);
     g_signal_connect (file_option, "changed", G_CALLBACK (prefs_file_option_changed), NULL);
 
+    page_content = sj_plugin_manager_new ();
+    g_return_if_fail (page_content != NULL);
+
+    gtk_box_pack_start (GTK_BOX (plugin_manager_place_holder),
+			page_content,
+			TRUE,
+			TRUE,
+			0);
+
+    gtk_widget_show_all (page_content);
+
     /* Connect to GConf to update the UI */
     gconf_bridge_bind_property (bridge, GCONF_EJECT, G_OBJECT (check_eject), "active");
     gconf_bridge_bind_property (bridge, GCONF_STRIP, G_OBJECT (check_strip), "active");
Index: data/sound-juicer.glade
===================================================================
--- data/sound-juicer.glade	(revision 1798)
+++ data/sound-juicer.glade	(working copy)
@@ -953,665 +953,744 @@
       </child>
 
       <child>
-	<widget class="GtkVBox" id="vbox11">
-	  <property name="border_width">5</property>
+	<widget class="GtkNotebook" id="prefs_notebook">
 	  <property name="visible">True</property>
-	  <property name="homogeneous">False</property>
-	  <property name="spacing">18</property>
+	  <property name="can_focus">True</property>
+	  <property name="show_tabs">True</property>
+	  <property name="show_border">True</property>
+	  <property name="tab_pos">GTK_POS_TOP</property>
+	  <property name="scrollable">False</property>
+	  <property name="enable_popup">False</property>
 
 	  <child>
-	    <widget class="GtkVBox" id="frame_device">
-	      <property name="visible">True</property>
-	      <property name="homogeneous">False</property>
-	      <property name="spacing">6</property>
+    	<widget class="GtkVBox" id="vbox11">
+    	  <property name="border_width">12</property>
+    	  <property name="visible">True</property>
+    	  <property name="homogeneous">False</property>
+    	  <property name="spacing">18</property>
 
-	      <child>
-		<widget class="GtkLabel" id="label32">
-		  <property name="visible">True</property>
-		  <property name="label" translatable="yes">&lt;b&gt;Device&lt;/b&gt;</property>
-		  <property name="use_underline">False</property>
-		  <property name="use_markup">True</property>
-		  <property name="justify">GTK_JUSTIFY_LEFT</property>
-		  <property name="wrap">False</property>
-		  <property name="selectable">False</property>
-		  <property name="xalign">0</property>
-		  <property name="yalign">0.5</property>
-		  <property name="xpad">0</property>
-		  <property name="ypad">0</property>
-		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-		  <property name="width_chars">-1</property>
-		  <property name="single_line_mode">False</property>
-		  <property name="angle">0</property>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">False</property>
-		  <property name="fill">False</property>
-		</packing>
-	      </child>
+    	  <child>
+    	    <widget class="GtkVBox" id="frame_device">
+    	      <property name="visible">True</property>
+    	      <property name="homogeneous">False</property>
+    	      <property name="spacing">6</property>
 
-	      <child>
-		<widget class="GtkAlignment" id="alignment5">
-		  <property name="visible">True</property>
-		  <property name="xalign">0.5</property>
-		  <property name="yalign">0.5</property>
-		  <property name="xscale">1</property>
-		  <property name="yscale">1</property>
-		  <property name="top_padding">0</property>
-		  <property name="bottom_padding">0</property>
-		  <property name="left_padding">12</property>
-		  <property name="right_padding">0</property>
+    	      <child>
+    		<widget class="GtkLabel" id="label32">
+    		  <property name="visible">True</property>
+    		  <property name="label" translatable="yes">&lt;b&gt;Device&lt;/b&gt;</property>
+    		  <property name="use_underline">False</property>
+    		  <property name="use_markup">True</property>
+    		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+    		  <property name="wrap">False</property>
+    		  <property name="selectable">False</property>
+    		  <property name="xalign">0</property>
+    		  <property name="yalign">0.5</property>
+    		  <property name="xpad">0</property>
+    		  <property name="ypad">0</property>
+    		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+    		  <property name="width_chars">-1</property>
+    		  <property name="single_line_mode">False</property>
+    		  <property name="angle">0</property>
+    		</widget>
+    		<packing>
+    		  <property name="padding">0</property>
+    		  <property name="expand">False</property>
+    		  <property name="fill">False</property>
+    		</packing>
+    	      </child>
 
-		  <child>
-		    <widget class="GtkTable" id="table7">
-		      <property name="visible">True</property>
-		      <property name="n_rows">2</property>
-		      <property name="n_columns">2</property>
-		      <property name="homogeneous">False</property>
-		      <property name="row_spacing">6</property>
-		      <property name="column_spacing">12</property>
+    	      <child>
+    		<widget class="GtkAlignment" id="alignment5">
+    		  <property name="visible">True</property>
+    		  <property name="xalign">0.5</property>
+    		  <property name="yalign">0.5</property>
+    		  <property name="xscale">1</property>
+    		  <property name="yscale">1</property>
+    		  <property name="top_padding">0</property>
+    		  <property name="bottom_padding">0</property>
+    		  <property name="left_padding">12</property>
+    		  <property name="right_padding">0</property>
 
-		      <child>
-			<widget class="GtkLabel" id="cd_label">
-			  <property name="visible">True</property>
-			  <property name="label" translatable="yes">CD _drive:</property>
-			  <property name="use_underline">True</property>
-			  <property name="use_markup">False</property>
-			  <property name="justify">GTK_JUSTIFY_LEFT</property>
-			  <property name="wrap">False</property>
-			  <property name="selectable">False</property>
-			  <property name="xalign">0</property>
-			  <property name="yalign">0.5</property>
-			  <property name="xpad">0</property>
-			  <property name="ypad">0</property>
-			  <property name="mnemonic_widget">cd_option</property>
-			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-			  <property name="width_chars">-1</property>
-			  <property name="single_line_mode">False</property>
-			  <property name="angle">0</property>
-			</widget>
-			<packing>
-			  <property name="left_attach">0</property>
-			  <property name="right_attach">1</property>
-			  <property name="top_attach">0</property>
-			  <property name="bottom_attach">1</property>
-			  <property name="x_options">fill</property>
-			  <property name="y_options"></property>
-			</packing>
-		      </child>
+    		  <child>
+    		    <widget class="GtkTable" id="table7">
+    		      <property name="visible">True</property>
+    		      <property name="n_rows">2</property>
+    		      <property name="n_columns">2</property>
+    		      <property name="homogeneous">False</property>
+    		      <property name="row_spacing">6</property>
+    		      <property name="column_spacing">12</property>
 
-		      <child>
-			<widget class="Custom" id="cd_option">
-			  <property name="visible">True</property>
-			  <property name="can_focus">True</property>
-			  <property name="creation_function">nautilus_burn_drive_selection_new</property>
-			  <property name="int1">0</property>
-			  <property name="int2">0</property>
-			  <property name="last_modification_time">Sat, 05 Feb 2005 15:36:25 GMT</property>
-			</widget>
-			<packing>
-			  <property name="left_attach">1</property>
-			  <property name="right_attach">2</property>
-			  <property name="top_attach">0</property>
-			  <property name="bottom_attach">1</property>
-			  <property name="y_options">fill</property>
-			</packing>
-		      </child>
+    		      <child>
+    			<widget class="GtkLabel" id="cd_label">
+    			  <property name="visible">True</property>
+    			  <property name="label" translatable="yes">CD _drive:</property>
+    			  <property name="use_underline">True</property>
+    			  <property name="use_markup">False</property>
+    			  <property name="justify">GTK_JUSTIFY_LEFT</property>
+    			  <property name="wrap">False</property>
+    			  <property name="selectable">False</property>
+    			  <property name="xalign">0</property>
+    			  <property name="yalign">0.5</property>
+    			  <property name="xpad">0</property>
+    			  <property name="ypad">0</property>
+    			  <property name="mnemonic_widget">cd_option</property>
+    			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+    			  <property name="width_chars">-1</property>
+    			  <property name="single_line_mode">False</property>
+    			  <property name="angle">0</property>
+    			</widget>
+    			<packing>
+    			  <property name="left_attach">0</property>
+    			  <property name="right_attach">1</property>
+    			  <property name="top_attach">0</property>
+    			  <property name="bottom_attach">1</property>
+    			  <property name="x_options">fill</property>
+    			  <property name="y_options"></property>
+    			</packing>
+    		      </child>
 
-		      <child>
-			<widget class="GtkCheckButton" id="check_eject">
-			  <property name="visible">True</property>
-			  <property name="can_focus">True</property>
-			  <property name="label" translatable="yes">_Eject when finished</property>
-			  <property name="use_underline">True</property>
-			  <property name="relief">GTK_RELIEF_NORMAL</property>
-			  <property name="focus_on_click">True</property>
-			  <property name="active">False</property>
-			  <property name="inconsistent">False</property>
-			  <property name="draw_indicator">True</property>
-			</widget>
-			<packing>
-			  <property name="left_attach">1</property>
-			  <property name="right_attach">2</property>
-			  <property name="top_attach">1</property>
-			  <property name="bottom_attach">2</property>
-			  <property name="x_options">fill</property>
-			  <property name="y_options"></property>
-			</packing>
-		      </child>
-		    </widget>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">True</property>
-		  <property name="fill">True</property>
-		</packing>
-	      </child>
-	    </widget>
-	    <packing>
-	      <property name="padding">0</property>
-	      <property name="expand">False</property>
-	      <property name="fill">True</property>
-	    </packing>
-	  </child>
+    		      <child>
+    			<widget class="Custom" id="cd_option">
+    			  <property name="visible">True</property>
+    			  <property name="can_focus">True</property>
+    			  <property name="creation_function">nautilus_burn_drive_selection_new</property>
+    			  <property name="int1">0</property>
+    			  <property name="int2">0</property>
+    			  <property name="last_modification_time">Sat, 05 Feb 2005 15:36:25 GMT</property>
+    			</widget>
+    			<packing>
+    			  <property name="left_attach">1</property>
+    			  <property name="right_attach">2</property>
+    			  <property name="top_attach">0</property>
+    			  <property name="bottom_attach">1</property>
+    			  <property name="y_options">fill</property>
+    			</packing>
+    		      </child>
 
-	  <child>
-	    <widget class="GtkVBox" id="frame_folder">
-	      <property name="visible">True</property>
-	      <property name="homogeneous">False</property>
-	      <property name="spacing">6</property>
+    		      <child>
+    			<widget class="GtkCheckButton" id="check_eject">
+    			  <property name="visible">True</property>
+    			  <property name="can_focus">True</property>
+    			  <property name="label" translatable="yes">_Eject when finished</property>
+    			  <property name="use_underline">True</property>
+    			  <property name="relief">GTK_RELIEF_NORMAL</property>
+    			  <property name="focus_on_click">True</property>
+    			  <property name="active">False</property>
+    			  <property name="inconsistent">False</property>
+    			  <property name="draw_indicator">True</property>
+    			</widget>
+    			<packing>
+    			  <property name="left_attach">1</property>
+    			  <property name="right_attach">2</property>
+    			  <property name="top_attach">1</property>
+    			  <property name="bottom_attach">2</property>
+    			  <property name="x_options">fill</property>
+    			  <property name="y_options"></property>
+    			</packing>
+    		      </child>
+    		    </widget>
+    		  </child>
+    		</widget>
+    		<packing>
+    		  <property name="padding">0</property>
+    		  <property name="expand">True</property>
+    		  <property name="fill">True</property>
+    		</packing>
+    	      </child>
+    	    </widget>
+    	    <packing>
+    	      <property name="padding">0</property>
+    	      <property name="expand">False</property>
+    	      <property name="fill">True</property>
+    	    </packing>
+    	  </child>
 
-	      <child>
-		<widget class="GtkLabel" id="label33">
-		  <property name="visible">True</property>
-		  <property name="label" translatable="yes">&lt;b&gt;Music Folder&lt;/b&gt;</property>
-		  <property name="use_underline">False</property>
-		  <property name="use_markup">True</property>
-		  <property name="justify">GTK_JUSTIFY_LEFT</property>
-		  <property name="wrap">False</property>
-		  <property name="selectable">False</property>
-		  <property name="xalign">0</property>
-		  <property name="yalign">0.5</property>
-		  <property name="xpad">0</property>
-		  <property name="ypad">0</property>
-		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-		  <property name="width_chars">-1</property>
-		  <property name="single_line_mode">False</property>
-		  <property name="angle">0</property>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">False</property>
-		  <property name="fill">False</property>
-		</packing>
-	      </child>
+    	  <child>
+    	    <widget class="GtkVBox" id="frame_folder">
+    	      <property name="visible">True</property>
+    	      <property name="homogeneous">False</property>
+    	      <property name="spacing">6</property>
 
-	      <child>
-		<widget class="GtkAlignment" id="alignment10">
-		  <property name="visible">True</property>
-		  <property name="xalign">0.5</property>
-		  <property name="yalign">0.5</property>
-		  <property name="xscale">1</property>
-		  <property name="yscale">1</property>
-		  <property name="top_padding">0</property>
-		  <property name="bottom_padding">0</property>
-		  <property name="left_padding">12</property>
-		  <property name="right_padding">0</property>
+    	      <child>
+    		<widget class="GtkLabel" id="label33">
+    		  <property name="visible">True</property>
+    		  <property name="label" translatable="yes">&lt;b&gt;Music Folder&lt;/b&gt;</property>
+    		  <property name="use_underline">False</property>
+    		  <property name="use_markup">True</property>
+    		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+    		  <property name="wrap">False</property>
+    		  <property name="selectable">False</property>
+    		  <property name="xalign">0</property>
+    		  <property name="yalign">0.5</property>
+    		  <property name="xpad">0</property>
+    		  <property name="ypad">0</property>
+    		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+    		  <property name="width_chars">-1</property>
+    		  <property name="single_line_mode">False</property>
+    		  <property name="angle">0</property>
+    		</widget>
+    		<packing>
+    		  <property name="padding">0</property>
+    		  <property name="expand">False</property>
+    		  <property name="fill">False</property>
+    		</packing>
+    	      </child>
 
-		  <child>
-		    <widget class="GtkHBox" id="hbox9">
-		      <property name="visible">True</property>
-		      <property name="homogeneous">False</property>
-		      <property name="spacing">12</property>
+    	      <child>
+    		<widget class="GtkAlignment" id="alignment10">
+    		  <property name="visible">True</property>
+    		  <property name="xalign">0.5</property>
+    		  <property name="yalign">0.5</property>
+    		  <property name="xscale">1</property>
+    		  <property name="yscale">1</property>
+    		  <property name="top_padding">0</property>
+    		  <property name="bottom_padding">0</property>
+    		  <property name="left_padding">12</property>
+    		  <property name="right_padding">0</property>
 
-		      <child>
-			<widget class="GtkLabel" id="path_label">
-			  <property name="visible">True</property>
-			  <property name="label" translatable="yes">_Folder:</property>
-			  <property name="use_underline">True</property>
-			  <property name="use_markup">False</property>
-			  <property name="justify">GTK_JUSTIFY_LEFT</property>
-			  <property name="wrap">True</property>
-			  <property name="selectable">False</property>
-			  <property name="xalign">0</property>
-			  <property name="yalign">0.5</property>
-			  <property name="xpad">0</property>
-			  <property name="ypad">0</property>
-			  <property name="mnemonic_widget">path_chooser</property>
-			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-			  <property name="width_chars">-1</property>
-			  <property name="single_line_mode">False</property>
-			  <property name="angle">0</property>
-			</widget>
-			<packing>
-			  <property name="padding">0</property>
-			  <property name="expand">False</property>
-			  <property name="fill">True</property>
-			</packing>
-		      </child>
+    		  <child>
+    		    <widget class="GtkHBox" id="hbox9">
+    		      <property name="visible">True</property>
+    		      <property name="homogeneous">False</property>
+    		      <property name="spacing">12</property>
 
-		      <child>
-			<widget class="GtkFileChooserButton" id="path_chooser">
-			  <property name="visible">True</property>
-			  <property name="focus_on_click">True</property>
-			  <property name="title" translatable="yes">Select A Folder</property>
-			  <property name="action">GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER</property>
-			  <property name="local_only">False</property>
-			  <property name="show_hidden">False</property>
-			  <property name="do_overwrite_confirmation">False</property>
-			  <property name="width_chars">-1</property>
-			  <signal name="current_folder_changed" handler="prefs_base_folder_changed" last_modification_time="Mon, 07 Feb 2005 17:45:23 GMT"/>
-			</widget>
-			<packing>
-			  <property name="padding">0</property>
-			  <property name="expand">True</property>
-			  <property name="fill">True</property>
-			</packing>
-		      </child>
-		    </widget>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">True</property>
-		  <property name="fill">True</property>
-		</packing>
-	      </child>
-	    </widget>
-	    <packing>
-	      <property name="padding">0</property>
-	      <property name="expand">False</property>
-	      <property name="fill">True</property>
-	    </packing>
-	  </child>
+    		      <child>
+    			<widget class="GtkLabel" id="path_label">
+    			  <property name="visible">True</property>
+    			  <property name="label" translatable="yes">_Folder:</property>
+    			  <property name="use_underline">True</property>
+    			  <property name="use_markup">False</property>
+    			  <property name="justify">GTK_JUSTIFY_LEFT</property>
+    			  <property name="wrap">True</property>
+    			  <property name="selectable">False</property>
+    			  <property name="xalign">0</property>
+    			  <property name="yalign">0.5</property>
+    			  <property name="xpad">0</property>
+    			  <property name="ypad">0</property>
+    			  <property name="mnemonic_widget">path_chooser</property>
+    			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+    			  <property name="width_chars">-1</property>
+    			  <property name="single_line_mode">False</property>
+    			  <property name="angle">0</property>
+    			</widget>
+    			<packing>
+    			  <property name="padding">0</property>
+    			  <property name="expand">False</property>
+    			  <property name="fill">True</property>
+    			</packing>
+    		      </child>
 
-	  <child>
-	    <widget class="GtkVBox" id="frame_names">
-	      <property name="visible">True</property>
-	      <property name="homogeneous">False</property>
-	      <property name="spacing">6</property>
+    		      <child>
+    			<widget class="GtkFileChooserButton" id="path_chooser">
+    			  <property name="visible">True</property>
+    			  <property name="can_focus">True</property>
+    			  <property name="title" translatable="yes">Select A Folder</property>
+    			  <property name="action">GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER</property>
+    			  <property name="local_only">False</property>
+    			  <property name="show_hidden">False</property>
+    			  <property name="do_overwrite_confirmation">False</property>
+    			  <property name="width_chars">-1</property>
+    			  <signal name="current_folder_changed" handler="prefs_base_folder_changed" last_modification_time="Mon, 07 Feb 2005 17:45:23 GMT"/>
+    			</widget>
+    			<packing>
+    			  <property name="padding">0</property>
+    			  <property name="expand">True</property>
+    			  <property name="fill">True</property>
+    			</packing>
+    		      </child>
+    		    </widget>
+    		  </child>
+    		</widget>
+    		<packing>
+    		  <property name="padding">0</property>
+    		  <property name="expand">True</property>
+    		  <property name="fill">True</property>
+    		</packing>
+    	      </child>
+    	    </widget>
+    	    <packing>
+    	      <property name="padding">0</property>
+    	      <property name="expand">False</property>
+    	      <property name="fill">True</property>
+    	    </packing>
+    	  </child>
 
-	      <child>
-		<widget class="GtkLabel" id="label34">
-		  <property name="visible">True</property>
-		  <property name="label" translatable="yes">&lt;b&gt;Track Names&lt;/b&gt;</property>
-		  <property name="use_underline">False</property>
-		  <property name="use_markup">True</property>
-		  <property name="justify">GTK_JUSTIFY_LEFT</property>
-		  <property name="wrap">False</property>
-		  <property name="selectable">False</property>
-		  <property name="xalign">0</property>
-		  <property name="yalign">0.5</property>
-		  <property name="xpad">0</property>
-		  <property name="ypad">0</property>
-		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-		  <property name="width_chars">-1</property>
-		  <property name="single_line_mode">False</property>
-		  <property name="angle">0</property>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">False</property>
-		  <property name="fill">False</property>
-		</packing>
-	      </child>
+    	  <child>
+    	    <widget class="GtkVBox" id="frame_names">
+    	      <property name="visible">True</property>
+    	      <property name="homogeneous">False</property>
+    	      <property name="spacing">6</property>
 
-	      <child>
-		<widget class="GtkAlignment" id="alignment11">
-		  <property name="visible">True</property>
-		  <property name="xalign">0.5</property>
-		  <property name="yalign">0.5</property>
-		  <property name="xscale">1</property>
-		  <property name="yscale">1</property>
-		  <property name="top_padding">0</property>
-		  <property name="bottom_padding">0</property>
-		  <property name="left_padding">12</property>
-		  <property name="right_padding">0</property>
+    	      <child>
+    		<widget class="GtkLabel" id="label34">
+    		  <property name="visible">True</property>
+    		  <property name="label" translatable="yes">&lt;b&gt;Track Names&lt;/b&gt;</property>
+    		  <property name="use_underline">False</property>
+    		  <property name="use_markup">True</property>
+    		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+    		  <property name="wrap">False</property>
+    		  <property name="selectable">False</property>
+    		  <property name="xalign">0</property>
+    		  <property name="yalign">0.5</property>
+    		  <property name="xpad">0</property>
+    		  <property name="ypad">0</property>
+    		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+    		  <property name="width_chars">-1</property>
+    		  <property name="single_line_mode">False</property>
+    		  <property name="angle">0</property>
+    		</widget>
+    		<packing>
+    		  <property name="padding">0</property>
+    		  <property name="expand">False</property>
+    		  <property name="fill">False</property>
+    		</packing>
+    	      </child>
 
-		  <child>
-		    <widget class="GtkTable" id="table6">
-		      <property name="visible">True</property>
-		      <property name="n_rows">4</property>
-		      <property name="n_columns">2</property>
-		      <property name="homogeneous">False</property>
-		      <property name="row_spacing">6</property>
-		      <property name="column_spacing">12</property>
+    	      <child>
+    		<widget class="GtkAlignment" id="alignment11">
+    		  <property name="visible">True</property>
+    		  <property name="xalign">0.5</property>
+    		  <property name="yalign">0.5</property>
+    		  <property name="xscale">1</property>
+    		  <property name="yscale">1</property>
+    		  <property name="top_padding">0</property>
+    		  <property name="bottom_padding">0</property>
+    		  <property name="left_padding">12</property>
+    		  <property name="right_padding">0</property>
 
-		      <child>
-			<widget class="GtkLabel" id="folder_label">
-			  <property name="visible">True</property>
-			  <property name="label" translatable="yes">Folder hie_rarchy:</property>
-			  <property name="use_underline">True</property>
-			  <property name="use_markup">False</property>
-			  <property name="justify">GTK_JUSTIFY_LEFT</property>
-			  <property name="wrap">False</property>
-			  <property name="selectable">False</property>
-			  <property name="xalign">0</property>
-			  <property name="yalign">0.5</property>
-			  <property name="xpad">0</property>
-			  <property name="ypad">0</property>
-			  <property name="mnemonic_widget">path_option</property>
-			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-			  <property name="width_chars">-1</property>
-			  <property name="single_line_mode">False</property>
-			  <property name="angle">0</property>
-			</widget>
-			<packing>
-			  <property name="left_attach">0</property>
-			  <property name="right_attach">1</property>
-			  <property name="top_attach">0</property>
-			  <property name="bottom_attach">1</property>
-			  <property name="x_options">fill</property>
-			  <property name="y_options"></property>
-			</packing>
-		      </child>
+    		  <child>
+    		    <widget class="GtkTable" id="table6">
+    		      <property name="visible">True</property>
+    		      <property name="n_rows">4</property>
+    		      <property name="n_columns">2</property>
+    		      <property name="homogeneous">False</property>
+    		      <property name="row_spacing">6</property>
+    		      <property name="column_spacing">12</property>
 
-		      <child>
-			<widget class="GtkLabel" id="file_label">
-			  <property name="visible">True</property>
-			  <property name="label" translatable="yes">File _name:</property>
-			  <property name="use_underline">True</property>
-			  <property name="use_markup">False</property>
-			  <property name="justify">GTK_JUSTIFY_LEFT</property>
-			  <property name="wrap">False</property>
-			  <property name="selectable">False</property>
-			  <property name="xalign">0</property>
-			  <property name="yalign">0.5</property>
-			  <property name="xpad">0</property>
-			  <property name="ypad">0</property>
-			  <property name="mnemonic_widget">file_option</property>
-			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-			  <property name="width_chars">-1</property>
-			  <property name="single_line_mode">False</property>
-			  <property name="angle">0</property>
-			</widget>
-			<packing>
-			  <property name="left_attach">0</property>
-			  <property name="right_attach">1</property>
-			  <property name="top_attach">1</property>
-			  <property name="bottom_attach">2</property>
-			  <property name="x_options">fill</property>
-			  <property name="y_options"></property>
-			</packing>
-		      </child>
+    		      <child>
+    			<widget class="GtkLabel" id="folder_label">
+    			  <property name="visible">True</property>
+    			  <property name="label" translatable="yes">Folder hie_rarchy:</property>
+    			  <property name="use_underline">True</property>
+    			  <property name="use_markup">False</property>
+    			  <property name="justify">GTK_JUSTIFY_LEFT</property>
+    			  <property name="wrap">False</property>
+    			  <property name="selectable">False</property>
+    			  <property name="xalign">0</property>
+    			  <property name="yalign">0.5</property>
+    			  <property name="xpad">0</property>
+    			  <property name="ypad">0</property>
+    			  <property name="mnemonic_widget">path_option</property>
+    			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+    			  <property name="width_chars">-1</property>
+    			  <property name="single_line_mode">False</property>
+    			  <property name="angle">0</property>
+    			</widget>
+    			<packing>
+    			  <property name="left_attach">0</property>
+    			  <property name="right_attach">1</property>
+    			  <property name="top_attach">0</property>
+    			  <property name="bottom_attach">1</property>
+    			  <property name="x_options">fill</property>
+    			  <property name="y_options"></property>
+    			</packing>
+    		      </child>
 
-		      <child>
-			<widget class="GtkComboBox" id="path_option">
-			  <property name="visible">True</property>
-			  <property name="items" translatable="yes"></property>
-			  <property name="add_tearoffs">False</property>
-			  <property name="focus_on_click">True</property>
-			</widget>
-			<packing>
-			  <property name="left_attach">1</property>
-			  <property name="right_attach">2</property>
-			  <property name="top_attach">0</property>
-			  <property name="bottom_attach">1</property>
-			  <property name="y_options">fill</property>
-			</packing>
-		      </child>
+    		      <child>
+    			<widget class="GtkLabel" id="file_label">
+    			  <property name="visible">True</property>
+    			  <property name="label" translatable="yes">File _name:</property>
+    			  <property name="use_underline">True</property>
+    			  <property name="use_markup">False</property>
+    			  <property name="justify">GTK_JUSTIFY_LEFT</property>
+    			  <property name="wrap">False</property>
+    			  <property name="selectable">False</property>
+    			  <property name="xalign">0</property>
+    			  <property name="yalign">0.5</property>
+    			  <property name="xpad">0</property>
+    			  <property name="ypad">0</property>
+    			  <property name="mnemonic_widget">file_option</property>
+    			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+    			  <property name="width_chars">-1</property>
+    			  <property name="single_line_mode">False</property>
+    			  <property name="angle">0</property>
+    			</widget>
+    			<packing>
+    			  <property name="left_attach">0</property>
+    			  <property name="right_attach">1</property>
+    			  <property name="top_attach">1</property>
+    			  <property name="bottom_attach">2</property>
+    			  <property name="x_options">fill</property>
+    			  <property name="y_options"></property>
+    			</packing>
+    		      </child>
 
-		      <child>
-			<widget class="GtkComboBox" id="file_option">
-			  <property name="visible">True</property>
-			  <property name="items" translatable="yes"></property>
-			  <property name="add_tearoffs">False</property>
-			  <property name="focus_on_click">True</property>
-			</widget>
-			<packing>
-			  <property name="left_attach">1</property>
-			  <property name="right_attach">2</property>
-			  <property name="top_attach">1</property>
-			  <property name="bottom_attach">2</property>
-			  <property name="y_options">fill</property>
-			</packing>
-		      </child>
+    		      <child>
+    			<widget class="GtkComboBox" id="path_option">
+    			  <property name="visible">True</property>
+    			  <property name="items" translatable="yes"></property>
+    			  <property name="add_tearoffs">False</property>
+    			  <property name="focus_on_click">True</property>
+    			</widget>
+    			<packing>
+    			  <property name="left_attach">1</property>
+    			  <property name="right_attach">2</property>
+    			  <property name="top_attach">0</property>
+    			  <property name="bottom_attach">1</property>
+    			  <property name="y_options">fill</property>
+    			</packing>
+    		      </child>
 
-		      <child>
-			<widget class="GtkLabel" id="path_example_label">
-			  <property name="visible">True</property>
-			  <property name="label"></property>
-			  <property name="use_underline">False</property>
-			  <property name="use_markup">True</property>
-			  <property name="justify">GTK_JUSTIFY_LEFT</property>
-			  <property name="wrap">False</property>
-			  <property name="selectable">False</property>
-			  <property name="xalign">0</property>
-			  <property name="yalign">0.5</property>
-			  <property name="xpad">0</property>
-			  <property name="ypad">0</property>
-			  <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
-			  <property name="width_chars">-1</property>
-			  <property name="single_line_mode">True</property>
-			  <property name="angle">0</property>
-			</widget>
-			<packing>
-			  <property name="left_attach">1</property>
-			  <property name="right_attach">2</property>
-			  <property name="top_attach">3</property>
-			  <property name="bottom_attach">4</property>
-			  <property name="x_options">fill</property>
-			  <property name="y_options"></property>
-			</packing>
-		      </child>
+    		      <child>
+    			<widget class="GtkComboBox" id="file_option">
+    			  <property name="visible">True</property>
+    			  <property name="items" translatable="yes"></property>
+    			  <property name="add_tearoffs">False</property>
+    			  <property name="focus_on_click">True</property>
+    			</widget>
+    			<packing>
+    			  <property name="left_attach">1</property>
+    			  <property name="right_attach">2</property>
+    			  <property name="top_attach">1</property>
+    			  <property name="bottom_attach">2</property>
+    			  <property name="y_options">fill</property>
+    			</packing>
+    		      </child>
 
-		      <child>
-			<widget class="GtkCheckButton" id="check_strip">
-			  <property name="visible">True</property>
-			  <property name="can_focus">True</property>
-			  <property name="label" translatable="yes">_Strip special characters</property>
-			  <property name="use_underline">True</property>
-			  <property name="relief">GTK_RELIEF_NORMAL</property>
-			  <property name="focus_on_click">True</property>
-			  <property name="active">False</property>
-			  <property name="inconsistent">False</property>
-			  <property name="draw_indicator">True</property>
-			</widget>
-			<packing>
-			  <property name="left_attach">1</property>
-			  <property name="right_attach">2</property>
-			  <property name="top_attach">2</property>
-			  <property name="bottom_attach">3</property>
-			  <property name="x_options">fill</property>
-			  <property name="y_options"></property>
-			</packing>
-		      </child>
-		    </widget>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">True</property>
-		  <property name="fill">True</property>
-		</packing>
-	      </child>
-	    </widget>
-	    <packing>
-	      <property name="padding">0</property>
-	      <property name="expand">False</property>
-	      <property name="fill">True</property>
-	    </packing>
-	  </child>
+    		      <child>
+    			<widget class="GtkLabel" id="path_example_label">
+    			  <property name="visible">True</property>
+    			  <property name="label"></property>
+    			  <property name="use_underline">False</property>
+    			  <property name="use_markup">True</property>
+    			  <property name="justify">GTK_JUSTIFY_LEFT</property>
+    			  <property name="wrap">False</property>
+    			  <property name="selectable">False</property>
+    			  <property name="xalign">0</property>
+    			  <property name="yalign">0.5</property>
+    			  <property name="xpad">0</property>
+    			  <property name="ypad">0</property>
+    			  <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
+    			  <property name="width_chars">-1</property>
+    			  <property name="single_line_mode">True</property>
+    			  <property name="angle">0</property>
+    			</widget>
+    			<packing>
+    			  <property name="left_attach">1</property>
+    			  <property name="right_attach">2</property>
+    			  <property name="top_attach">3</property>
+    			  <property name="bottom_attach">4</property>
+    			  <property name="x_options">fill</property>
+    			  <property name="y_options"></property>
+    			</packing>
+    		      </child>
 
-	  <child>
-	    <widget class="GtkVBox" id="frame_format">
-	      <property name="visible">True</property>
-	      <property name="homogeneous">False</property>
-	      <property name="spacing">6</property>
+    		      <child>
+    			<widget class="GtkCheckButton" id="check_strip">
+    			  <property name="visible">True</property>
+    			  <property name="can_focus">True</property>
+    			  <property name="label" translatable="yes">_Strip special characters</property>
+    			  <property name="use_underline">True</property>
+    			  <property name="relief">GTK_RELIEF_NORMAL</property>
+    			  <property name="focus_on_click">True</property>
+    			  <property name="active">False</property>
+    			  <property name="inconsistent">False</property>
+    			  <property name="draw_indicator">True</property>
+    			</widget>
+    			<packing>
+    			  <property name="left_attach">1</property>
+    			  <property name="right_attach">2</property>
+    			  <property name="top_attach">2</property>
+    			  <property name="bottom_attach">3</property>
+    			  <property name="x_options">fill</property>
+    			  <property name="y_options"></property>
+    			</packing>
+    		      </child>
+    		    </widget>
+    		  </child>
+    		</widget>
+    		<packing>
+    		  <property name="padding">0</property>
+    		  <property name="expand">True</property>
+    		  <property name="fill">True</property>
+    		</packing>
+    	      </child>
+    	    </widget>
+    	    <packing>
+    	      <property name="padding">0</property>
+    	      <property name="expand">False</property>
+    	      <property name="fill">True</property>
+    	    </packing>
+    	  </child>
 
-	      <child>
-		<widget class="GtkLabel" id="label35">
-		  <property name="visible">True</property>
-		  <property name="label" translatable="yes">&lt;b&gt;Format&lt;/b&gt;</property>
-		  <property name="use_underline">False</property>
-		  <property name="use_markup">True</property>
-		  <property name="justify">GTK_JUSTIFY_LEFT</property>
-		  <property name="wrap">False</property>
-		  <property name="selectable">False</property>
-		  <property name="xalign">0</property>
-		  <property name="yalign">0.5</property>
-		  <property name="xpad">0</property>
-		  <property name="ypad">0</property>
-		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-		  <property name="width_chars">-1</property>
-		  <property name="single_line_mode">False</property>
-		  <property name="angle">0</property>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">False</property>
-		  <property name="fill">False</property>
-		</packing>
-	      </child>
+    	  <child>
+    	    <widget class="GtkVBox" id="frame_format">
+    	      <property name="visible">True</property>
+    	      <property name="homogeneous">False</property>
+    	      <property name="spacing">6</property>
 
-	      <child>
-		<widget class="GtkAlignment" id="alignment8">
-		  <property name="visible">True</property>
-		  <property name="xalign">0.5</property>
-		  <property name="yalign">0.5</property>
-		  <property name="xscale">1</property>
-		  <property name="yscale">1</property>
-		  <property name="top_padding">0</property>
-		  <property name="bottom_padding">0</property>
-		  <property name="left_padding">12</property>
-		  <property name="right_padding">0</property>
+    	      <child>
+    		<widget class="GtkLabel" id="label35">
+    		  <property name="visible">True</property>
+    		  <property name="label" translatable="yes">&lt;b&gt;Format&lt;/b&gt;</property>
+    		  <property name="use_underline">False</property>
+    		  <property name="use_markup">True</property>
+    		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+    		  <property name="wrap">False</property>
+    		  <property name="selectable">False</property>
+    		  <property name="xalign">0</property>
+    		  <property name="yalign">0.5</property>
+    		  <property name="xpad">0</property>
+    		  <property name="ypad">0</property>
+    		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+    		  <property name="width_chars">-1</property>
+    		  <property name="single_line_mode">False</property>
+    		  <property name="angle">0</property>
+    		</widget>
+    		<packing>
+    		  <property name="padding">0</property>
+    		  <property name="expand">False</property>
+    		  <property name="fill">False</property>
+    		</packing>
+    	      </child>
 
-		  <child>
-		    <widget class="GtkHBox" id="hbox8">
-		      <property name="visible">True</property>
-		      <property name="homogeneous">False</property>
-		      <property name="spacing">12</property>
+    	      <child>
+    		<widget class="GtkAlignment" id="alignment8">
+    		  <property name="visible">True</property>
+    		  <property name="xalign">0.5</property>
+    		  <property name="yalign">0.5</property>
+    		  <property name="xscale">1</property>
+    		  <property name="yscale">1</property>
+    		  <property name="top_padding">0</property>
+    		  <property name="bottom_padding">0</property>
+    		  <property name="left_padding">12</property>
+    		  <property name="right_padding">0</property>
 
-		      <child>
-			<widget class="GtkLabel" id="profile_label">
-			  <property name="visible">True</property>
-			  <property name="label" translatable="yes">O_utput Format:</property>
-			  <property name="use_underline">True</property>
-			  <property name="use_markup">False</property>
-			  <property name="justify">GTK_JUSTIFY_LEFT</property>
-			  <property name="wrap">False</property>
-			  <property name="selectable">False</property>
-			  <property name="xalign">0</property>
-			  <property name="yalign">0.5</property>
-			  <property name="xpad">0</property>
-			  <property name="ypad">0</property>
-			  <property name="mnemonic_widget">audio_profile</property>
-			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-			  <property name="width_chars">-1</property>
-			  <property name="single_line_mode">False</property>
-			  <property name="angle">0</property>
-			</widget>
-			<packing>
-			  <property name="padding">0</property>
-			  <property name="expand">False</property>
-			  <property name="fill">False</property>
-			</packing>
-		      </child>
+    		  <child>
+    		    <widget class="GtkHBox" id="hbox8">
+    		      <property name="visible">True</property>
+    		      <property name="homogeneous">False</property>
+    		      <property name="spacing">12</property>
 
-		      <child>
-			<widget class="GtkHBox" id="hbox14">
-			  <property name="visible">True</property>
-			  <property name="homogeneous">False</property>
-			  <property name="spacing">6</property>
+    		      <child>
+    			<widget class="GtkLabel" id="profile_label">
+    			  <property name="visible">True</property>
+    			  <property name="label" translatable="yes">O_utput Format:</property>
+    			  <property name="use_underline">True</property>
+    			  <property name="use_markup">False</property>
+    			  <property name="justify">GTK_JUSTIFY_LEFT</property>
+    			  <property name="wrap">False</property>
+    			  <property name="selectable">False</property>
+    			  <property name="xalign">0</property>
+    			  <property name="yalign">0.5</property>
+    			  <property name="xpad">0</property>
+    			  <property name="ypad">0</property>
+    			  <property name="mnemonic_widget">audio_profile</property>
+    			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+    			  <property name="width_chars">-1</property>
+    			  <property name="single_line_mode">False</property>
+    			  <property name="angle">0</property>
+    			</widget>
+    			<packing>
+    			  <property name="padding">0</property>
+    			  <property name="expand">False</property>
+    			  <property name="fill">False</property>
+    			</packing>
+    		      </child>
 
-			  <child>
-			    <widget class="Custom" id="audio_profile">
-			      <property name="visible">True</property>
-			      <property name="can_focus">True</property>
-			      <property name="creation_function">gm_audio_profile_choose_new</property>
-			      <property name="int1">0</property>
-			      <property name="int2">0</property>
-			      <property name="last_modification_time">Sat, 24 Jul 2004 19:58:00 GMT</property>
-			      <signal name="changed" handler="prefs_profile_changed" last_modification_time="Sun, 25 Jul 2004 02:23:35 GMT"/>
-			    </widget>
-			    <packing>
-			      <property name="padding">0</property>
-			      <property name="expand">True</property>
-			      <property name="fill">True</property>
-			    </packing>
-			  </child>
+    		      <child>
+    			<widget class="GtkHBox" id="hbox14">
+    			  <property name="visible">True</property>
+    			  <property name="homogeneous">False</property>
+    			  <property name="spacing">6</property>
 
-			  <child>
-			    <widget class="GtkButton" id="prefs_edit_profile">
-			      <property name="can_focus">True</property>
-			      <property name="relief">GTK_RELIEF_NORMAL</property>
-			      <property name="focus_on_click">True</property>
-			      <signal name="clicked" handler="prefs_edit_profile_clicked" last_modification_time="Thu, 19 May 2005 08:55:55 GMT"/>
+    			  <child>
+    			    <widget class="Custom" id="audio_profile">
+    			      <property name="visible">True</property>
+    			      <property name="can_focus">True</property>
+    			      <property name="creation_function">gm_audio_profile_choose_new</property>
+    			      <property name="int1">0</property>
+    			      <property name="int2">0</property>
+    			      <property name="last_modification_time">Sat, 24 Jul 2004 19:58:00 GMT</property>
+    			      <signal name="changed" handler="prefs_profile_changed" last_modification_time="Sun, 25 Jul 2004 02:23:35 GMT"/>
+    			    </widget>
+    			    <packing>
+    			      <property name="padding">0</property>
+    			      <property name="expand">True</property>
+    			      <property name="fill">True</property>
+    			    </packing>
+    			  </child>
 
-			      <child>
-				<widget class="GtkAlignment" id="alignment9">
-				  <property name="visible">True</property>
-				  <property name="xalign">0.5</property>
-				  <property name="yalign">0.5</property>
-				  <property name="xscale">0</property>
-				  <property name="yscale">0</property>
-				  <property name="top_padding">0</property>
-				  <property name="bottom_padding">0</property>
-				  <property name="left_padding">0</property>
-				  <property name="right_padding">0</property>
+    			  <child>
+    			    <widget class="GtkButton" id="prefs_edit_profile">
+    			      <property name="can_focus">True</property>
+    			      <property name="relief">GTK_RELIEF_NORMAL</property>
+    			      <property name="focus_on_click">True</property>
+    			      <signal name="clicked" handler="prefs_edit_profile_clicked" last_modification_time="Thu, 19 May 2005 08:55:55 GMT"/>
 
-				  <child>
-				    <widget class="GtkHBox" id="hbox11">
-				      <property name="visible">True</property>
-				      <property name="homogeneous">False</property>
-				      <property name="spacing">2</property>
+    			      <child>
+    				<widget class="GtkAlignment" id="alignment9">
+    				  <property name="visible">True</property>
+    				  <property name="xalign">0.5</property>
+    				  <property name="yalign">0.5</property>
+    				  <property name="xscale">0</property>
+    				  <property name="yscale">0</property>
+    				  <property name="top_padding">0</property>
+    				  <property name="bottom_padding">0</property>
+    				  <property name="left_padding">0</property>
+    				  <property name="right_padding">0</property>
 
-				      <child>
-					<widget class="GtkImage" id="image71">
-					  <property name="visible">True</property>
-					  <property name="stock">gtk-edit</property>
-					  <property name="icon_size">4</property>
-					  <property name="xalign">0.5</property>
-					  <property name="yalign">0.5</property>
-					  <property name="xpad">0</property>
-					  <property name="ypad">0</property>
-					</widget>
-					<packing>
-					  <property name="padding">0</property>
-					  <property name="expand">False</property>
-					  <property name="fill">False</property>
-					</packing>
-				      </child>
+    				  <child>
+    				    <widget class="GtkHBox" id="hbox11">
+    				      <property name="visible">True</property>
+    				      <property name="homogeneous">False</property>
+    				      <property name="spacing">2</property>
 
-				      <child>
-					<widget class="GtkLabel" id="label38">
-					  <property name="visible">True</property>
-					  <property name="label" translatable="yes">Edit _Profiles...</property>
-					  <property name="use_underline">True</property>
-					  <property name="use_markup">False</property>
-					  <property name="justify">GTK_JUSTIFY_LEFT</property>
-					  <property name="wrap">False</property>
-					  <property name="selectable">False</property>
-					  <property name="xalign">0.5</property>
-					  <property name="yalign">0.5</property>
-					  <property name="xpad">0</property>
-					  <property name="ypad">0</property>
-					  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-					  <property name="width_chars">-1</property>
-					  <property name="single_line_mode">False</property>
-					  <property name="angle">0</property>
-					</widget>
-					<packing>
-					  <property name="padding">0</property>
-					  <property name="expand">False</property>
-					  <property name="fill">False</property>
-					</packing>
-				      </child>
-				    </widget>
-				  </child>
-				</widget>
-			      </child>
-			    </widget>
-			    <packing>
-			      <property name="padding">0</property>
-			      <property name="expand">False</property>
-			      <property name="fill">False</property>
-			    </packing>
-			  </child>
-			</widget>
-			<packing>
-			  <property name="padding">0</property>
-			  <property name="expand">True</property>
-			  <property name="fill">True</property>
-			</packing>
-		      </child>
-		    </widget>
-		  </child>
-		</widget>
-		<packing>
-		  <property name="padding">0</property>
-		  <property name="expand">True</property>
-		  <property name="fill">True</property>
-		</packing>
+    				      <child>
+    					<widget class="GtkImage" id="image71">
+    					  <property name="visible">True</property>
+    					  <property name="stock">gtk-edit</property>
+    					  <property name="icon_size">4</property>
+    					  <property name="xalign">0.5</property>
+    					  <property name="yalign">0.5</property>
+    					  <property name="xpad">0</property>
+    					  <property name="ypad">0</property>
+    					</widget>
+    					<packing>
+    					  <property name="padding">0</property>
+    					  <property name="expand">False</property>
+    					  <property name="fill">False</property>
+    					</packing>
+    				      </child>
+
+    				      <child>
+    					<widget class="GtkLabel" id="label38">
+    					  <property name="visible">True</property>
+    					  <property name="label" translatable="yes">Edit _Profiles...</property>
+    					  <property name="use_underline">True</property>
+    					  <property name="use_markup">False</property>
+    					  <property name="justify">GTK_JUSTIFY_LEFT</property>
+    					  <property name="wrap">False</property>
+    					  <property name="selectable">False</property>
+    					  <property name="xalign">0.5</property>
+    					  <property name="yalign">0.5</property>
+    					  <property name="xpad">0</property>
+    					  <property name="ypad">0</property>
+    					  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+    					  <property name="width_chars">-1</property>
+    					  <property name="single_line_mode">False</property>
+    					  <property name="angle">0</property>
+    					</widget>
+    					<packing>
+    					  <property name="padding">0</property>
+    					  <property name="expand">False</property>
+    					  <property name="fill">False</property>
+    					</packing>
+    				      </child>
+    				    </widget>
+    				  </child>
+    				</widget>
+    			      </child>
+    			    </widget>
+    			    <packing>
+    			      <property name="padding">0</property>
+    			      <property name="expand">False</property>
+    			      <property name="fill">False</property>
+    			    </packing>
+    			  </child>
+    			</widget>
+    			<packing>
+    			  <property name="padding">0</property>
+    			  <property name="expand">True</property>
+    			  <property name="fill">True</property>
+    			</packing>
+    		      </child>
+    		    </widget>
+    		  </child>
+    		</widget>
+    		<packing>
+    		  <property name="padding">0</property>
+    		  <property name="expand">True</property>
+    		  <property name="fill">True</property>
+    		</packing>
+    	      </child>
+    	    </widget>
+    	    <packing>
+    	      <property name="padding">0</property>
+    	      <property name="expand">False</property>
+    	      <property name="fill">True</property>
+    	    </packing>
+    	  </child>
+    	</widget>
+	    <packing>
+	      <property name="tab_expand">False</property>
+	      <property name="tab_fill">True</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkLabel" id="label38">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">Audio Extraction</property>
+	      <property name="use_underline">False</property>
+	      <property name="use_markup">False</property>
+	      <property name="justify">GTK_JUSTIFY_LEFT</property>
+	      <property name="wrap">False</property>
+	      <property name="selectable">False</property>
+	      <property name="xalign">0.5</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xpad">0</property>
+	      <property name="ypad">0</property>
+	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+	      <property name="width_chars">-1</property>
+	      <property name="single_line_mode">False</property>
+	      <property name="angle">0</property>
+	    </widget>
+	    <packing>
+	      <property name="type">tab</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkVBox" id="plugin_manager_place_holder">
+	      <property name="border_width">12</property>
+	      <property name="visible">True</property>
+	      <property name="homogeneous">False</property>
+	      <property name="spacing">0</property>
+
+	      <child>
+		<placeholder/>
 	      </child>
 	    </widget>
 	    <packing>
-	      <property name="padding">0</property>
-	      <property name="expand">False</property>
-	      <property name="fill">True</property>
+	      <property name="tab_expand">False</property>
+	      <property name="tab_fill">True</property>
 	    </packing>
 	  </child>
+
+	  <child>
+	    <widget class="GtkLabel" id="label39">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">Plugins</property>
+	      <property name="use_underline">False</property>
+	      <property name="use_markup">False</property>
+	      <property name="justify">GTK_JUSTIFY_LEFT</property>
+	      <property name="wrap">False</property>
+	      <property name="selectable">False</property>
+	      <property name="xalign">0.5</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xpad">0</property>
+	      <property name="ypad">0</property>
+	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+	      <property name="width_chars">-1</property>
+	      <property name="single_line_mode">False</property>
+	      <property name="angle">0</property>
+	    </widget>
+	    <packing>
+	      <property name="type">tab</property>
+	    </packing>
+	  </child>
 	</widget>
 	<packing>
 	  <property name="padding">0</property>
Index: data/sound-juicer.schemas.in
===================================================================
--- data/sound-juicer.schemas.in	(revision 1798)
+++ data/sound-juicer.schemas.in	(working copy)
@@ -4,6 +4,20 @@
   <schemalist>
 
     <schema>
+      <key>/schemas/apps/sound-juicer/plugins/active-plugins</key>
+      <applyto>/apps/sound-juicer/plugins/active-plugins</applyto>
+      <type>list</type>
+      <owner>sound-juicer</owner>
+      <list_type>string</list_type>
+      <default>[]</default>
+      <locale name="C">
+	<short>Active plugins</short>
+	<long>List of active plugins. It contains the "Location" of the active plugins. See the .sj-plugin file for obtaining
+        the "Location" of a given plugin.</long>
+      </locale>
+    </schema>
+
+    <schema>
       <key>/schemas/apps/sound-juicer/device</key>
       <applyto>/apps/sound-juicer/device</applyto>
       <type>string</type>
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 1798)
+++ Makefile.am	(working copy)
@@ -1,4 +1,4 @@
-SUBDIRS = po data libjuicer src tests help
+SUBDIRS = po data libjuicer src plugins tests help
 
 ACLOCAL_AMFLAGS = -I m4
 
