Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/glade3/ChangeLog,v
retrieving revision 1.701
diff -u -u -p -r1.701 ChangeLog
--- ChangeLog	9 Nov 2006 17:00:50 -0000	1.701
+++ ChangeLog	16 Nov 2006 19:29:33 -0000
@@ -1,3 +1,46 @@
+2006-11-16  Juan Pablo Ugarte <juanpablougarte@gmail.com>
+
+	* configure.in: Added python/pygtk checks.
+
+	* src/Makefile.am: added glade-binding.[ch] and BUILD_PYTHON rules
+
+	* src/glade-app.[ch]:
+	  o added glade_scripts_dir and glade_bindings_dir globals
+	  o added new function glade_app_get_project_by_name()
+	  o loading / unloading bindings.
+
+	* src/glade-catalog.c: support for loading catalogs supported by
+	  bindings, added language member to GladeCatalog.
+
+	* src/glade-paths.sh.in: added GLADE_BINDINGSDIR and GLADE_SCRIPTSDIR.
+
+	* src/glade-popup.c: added support for GWAAction
+	  (shows context actions as menu items)
+
+	* src/glade-project-window.c: added window which a console for each
+	  GladeBinding that provide a console.
+
+	* glade-python-support.[defs override]: files used by pygtk-codegen-2.0
+	  to create glade-python-support.c (GladeWidgetAdaptor wrappers)
+
+	* glade-python.c GladeBinding plugin for python language.
+
+	* src/glade-widget-adaptor.[ch]:
+	  o added "action-activated" signal
+	  o added GWAAction support.
+	  o added glade_create_reason_get_type() so the enum can be exposed in
+	    bindings as a GEnum.
+	  o gwa_derive_adaptor_for_type() now checks if the adaptor is already
+	    registered, because catalogs plugins could register adaptors when
+	    are loaded. (This is how python's catalog works)
+	  o setup binding scripts as actions.
+	  o added glade_widget_adaptor_emit_action_activated()
+	    (used in glade-popup.c)
+	
+	* src/glade.h: added GLADE_TAG_LANGUAGE, GLADE_TAG_ACTION_GROUP,
+	  GLADE_TAG_ACTION, GLADE_TAG_STOCK, glade_scripts_dir and
+	  glade_bindings_dir.
+
 2006-11-09  Juan Pablo Ugarte <juanpablougarte@gmail.com>
 
 	* src/glade-catalog.[ch]:
Index: configure.in
===================================================================
RCS file: /cvs/gnome/glade3/configure.in,v
retrieving revision 1.76
diff -u -u -p -r1.76 configure.in
--- configure.in	27 Oct 2006 15:20:36 -0000	1.76
+++ configure.in	16 Nov 2006 19:29:36 -0000
@@ -73,6 +73,35 @@ fi
 
 AM_CONDITIONAL(BUILD_GNOME, test x"$have_gnome" = "xyes")
 
+dnl ===============================================================
+dnl Check for Python
+dnl ================================================================
+AC_ARG_ENABLE(python,
+[  --disable-python         disable python scripting module],
+     check_python=$enableval, check_python=yes)
+
+if test x"$check_python" = x"yes"; then
+    AC_PATH_PROGS([PYTHON], [python])
+    PKG_CHECK_MODULES(PYGTK, pygtk-2.0 >= 2.8.0, [have_pygtk=yes],[have_pygtk=no])
+    AC_PATH_PROGS([PYGTK_CODEGEN], [pygtk-codegen-2.0])
+    if test -f $PYTHON -a -f $PYGTK_CODEGEN -a "$have_pygtk" = "yes"; then
+             PYTHON_CFLAGS="`$PYTHON -c "from distutils import sysconfig; getvar = sysconfig.get_config_var; flags = ['-I' + sysconfig.get_python_inc(), '-I' + sysconfig.get_python_inc(plat_specific=True)]; print ' '.join(flags)"` $PYGTK_CFLAGS"
+             PYTHON_LIBS="`$PYTHON -c "from distutils import sysconfig; pyver = sysconfig.get_config_var('VERSION'); getvar = sysconfig.get_config_var; libs = getvar('LIBS').split() + getvar('SYSLIBS').split(); libs.append('-lpython'+pyver); libs.insert(0, '-L' + getvar('LIBPL')); print ' '.join(libs)"` $PYGTK_LIBS"
+	     PYGTK_DEFS=`$PKG_CONFIG --variable=defsdir pygtk-2.0`
+             AC_SUBST(PYTHON_CFLAGS)
+             AC_SUBST(PYTHON_LIBS)
+	     AC_SUBST(PYGTK_CODEGEN)
+	     AC_SUBST(PYGTK_DEFS)
+             have_python=yes
+    else
+        have_python=no
+    fi
+else
+     have_python=no
+fi
+
+AM_CONDITIONAL(BUILD_PYTHON, test x"$have_python" = "xyes")
+
 dnl ================================================================
 dnl Check for windows
 dnl ================================================================
@@ -92,7 +121,7 @@ glade_datadir='${datadir}/${PACKAGE}'
 glade_libdir='${libdir}/${PACKAGE}'
 glade_catalogsdir='${glade_datadir}/catalogs'
 glade_pixmapsdir='${glade_datadir}/pixmaps'
-glade_scriptsdir='${glade_datadir}/script-do'
+glade_scriptsdir='${glade_datadir}/scripts'
 glade_modulesdir='${glade_libdir}/modules'
 glade_pluginsdir='${glade_libdir}/plugins'
 glade_bindingsdir='${glade_libdir}/bindings'
@@ -132,5 +161,5 @@ Configuration:
 	Source code location:	${srcdir}
 	Compiler:		${CC} 
 	GnomeUI Catalog:	${have_gnome}
-
+	Python Binding:		${have_python}
 "
Index: src/Makefile.am
===================================================================
RCS file: /cvs/gnome/glade3/src/Makefile.am,v
retrieving revision 1.61
diff -u -u -p -r1.61 Makefile.am
--- src/Makefile.am	26 Oct 2006 00:45:20 -0000	1.61
+++ src/Makefile.am	16 Nov 2006 19:29:36 -0000
@@ -88,6 +88,7 @@ libgladeui_1_la_SOURCES = \
 	glade-app.c \
 	glade-keysyms.c \
 	glade-fixed.c \
+	glade-binding.c \
 	glade-base-editor.c
 
 libgladeui_1_la_CFLAGS =    \
@@ -138,6 +139,7 @@ libgladeuiinclude_HEADERS = \
 	glade-app.h \
 	glade-builtins.h \
 	glade-fixed.h \
+	glade-binding.h \
 	glade-base-editor.h \
 	fixed_bg.xpm \
 	atk.xpm
@@ -145,6 +147,21 @@ libgladeuiinclude_HEADERS = \
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libgladeui-1.0.pc glade-3.pc
 
+if BUILD_PYTHON
+gladepython_LTLIBRARIES = libgladepython.la
+gladepythondir = $(glade_bindingsdir)
+libgladepython_la_SOURCES = glade-python.c glade-python-support.c
+libgladepython_la_CFLAGS = -g -Wall $(PYTHON_CFLAGS) $(GTK_CFLAGS)
+libgladepython_la_LDFLAGS = -module -avoid-version $(PYTHON_LIBS)
+libgladepython_la_LIBADD = libgladeui-1.la $(PYTHON_LIBS)
+
+%.c: %.defs %.override
+		${PYGTK_CODEGEN} --register $(PYGTK_DEFS)/gdk-types.defs \
+ --register $(PYGTK_DEFS)/gtk-types.defs \
+ -p ${subst -,_,$*} -o $*.override $< > $@
+
+endif
+
 if BUILD_GNOME
 gladegnome_LTLIBRARIES = libgladegnome.la
 gladegnomedir = $(glade_modulesdir)
@@ -160,6 +177,10 @@ if WITH_WIN32
 
 if BUILD_GNOME
   libgladegnome_la_LDFLAGS += -no-undefined
+endif
+
+if BUILD_PYTHON
+  libgladepython_la_LDFLAGS += -no-undefined
 endif
 
 endif
Index: src/glade-app.c
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-app.c,v
retrieving revision 1.48
diff -u -u -p -r1.48 glade-app.c
--- src/glade-app.c	9 Nov 2006 17:00:49 -0000	1.48
+++ src/glade-app.c	16 Nov 2006 19:29:36 -0000
@@ -36,6 +36,7 @@
 #include "glade-catalog.h"
 #include "glade-paths.h"
 #include "glade-fixed.h"
+#include "glade-binding.h"
 
 #include <gdk/gdkkeysyms.h>
 #include <gtk/gtkstock.h>
@@ -81,8 +82,10 @@ enum
 static guint glade_app_signals[LAST_SIGNAL] = { 0 };
 
 gchar *glade_pixmaps_dir = GLADE_PIXMAPSDIR;
+gchar *glade_scripts_dir = GLADE_SCRIPTSDIR;
 gchar *glade_catalogs_dir = GLADE_CATALOGSDIR;
 gchar *glade_modules_dir = GLADE_MODULESDIR;
+gchar *glade_bindings_dir = GLADE_BINDINGSDIR;
 gchar *glade_plugins_dir = GLADE_PLUGINSDIR;
 gchar *glade_locale_dir = GLADE_LOCALEDIR;
 gchar *glade_icon_dir = GLADE_ICONDIR;
@@ -151,11 +154,16 @@ glade_app_finalize (GObject *app)
 
 #ifdef G_OS_WIN32 
 	g_free (glade_pixmaps_dir);
+	g_free (glade_scripts_dir);
 	g_free (glade_catalogs_dir);
 	g_free (glade_modules_dir);
+	g_free (glade_bindings_dir);	
 	g_free (glade_locale_dir);
 	g_free (glade_icon_dir);
 #endif
+	
+	glade_binding_unload_all ();
+	
 	glade_catalog_modules_close ();
 
 	g_free (GLADE_APP (app)->priv);
@@ -308,14 +316,19 @@ glade_app_init (GladeApp *app)
 	
 		prefix = g_win32_get_package_installation_directory (NULL, NULL);
 		glade_pixmaps_dir = g_build_filename (prefix, "share", PACKAGE, "pixmaps", NULL);
+		glade_scripts_dir = g_build_filename (prefix, "share", PACKAGE, GLADE_BINDING_SCRIPT_DIR, NULL);
 		glade_catalogs_dir = g_build_filename (prefix, "share", PACKAGE, "catalogs", NULL);
 		glade_modules_dir = g_build_filename (prefix, "lib", PACKAGE, "modules", NULL);
+		glade_bindings_dir = g_build_filename (prefix, "lib", PACKAGE, "bindings", NULL);
 		glade_locale_dir = g_build_filename (prefix, "share", "locale", NULL);
 		glade_icon_dir = g_build_filename (prefix, "share", "pixmaps", NULL);
 		g_free (prefix);
 #endif
 	
 		glade_cursor_init ();
+		
+		glade_binding_load_all ();
+		
 		initialized = TRUE;
 	}
 	app->priv = g_new0 (GladeAppPriv, 1);
@@ -761,6 +774,35 @@ glade_app_get_project_by_path (const gch
 	}
 
 	g_free (canonical_path);
+
+	return NULL;
+}
+
+/**
+ * glade_app_get_project_by_name:
+ * @project_name: The name of an open project
+ *
+ * Finds an open project by name.
+ *
+ * Returns: A #GladeProject, or NULL if no such open project was found
+ */
+GladeProject *
+glade_app_get_project_by_name (const gchar *project_name)
+{
+	GladeApp *app;
+	GList *l;
+
+	if (project_name == NULL) return NULL;
+
+	app = glade_app_get ();
+
+	for (l = app->priv->projects; l; l = g_list_next (l))
+	{
+		GladeProject *project = l->data;
+
+		if (strcmp (project_name, project->name) == 0)
+			return project;
+	}
 
 	return NULL;
 }
Index: src/glade-app.h
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-app.h,v
retrieving revision 1.20
diff -u -u -p -r1.20 glade-app.h
--- src/glade-app.h	12 Aug 2006 01:34:01 -0000	1.20
+++ src/glade-app.h	16 Nov 2006 19:29:37 -0000
@@ -99,6 +99,8 @@ LIBGLADEUI_API 
 gboolean           glade_app_is_project_loaded (const gchar *project_path);
 LIBGLADEUI_API 
 GladeProject*      glade_app_get_project_by_path (const gchar *project_path);
+LIBGLADEUI_API
+GladeProject      *glade_app_get_project_by_name (const gchar *project_name);
 LIBGLADEUI_API 
 void               glade_app_show_properties (gboolean raise);
 LIBGLADEUI_API 
Index: src/glade-binding.c
===================================================================
RCS file: src/glade-binding.c
diff -N src/glade-binding.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/glade-binding.c	16 Nov 2006 19:29:37 -0000
@@ -0,0 +1,352 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006 Juan Pablo Ugarte.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Authors:
+ *   Juan Pablo Ugarte <juanpablougarte@gmail.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glade.h"
+#include "glade-binding.h"
+#include "glade-paths.h"
+#include <string.h>
+
+/*
+GladeBindings are glade's modules to add support for others languages.
+
+The principal objective is to be able to support widgets written in other
+language than C.
+
+The bindings modules provides this functionality to the core trought a couple
+of obligatory functions.
+
+GladeBindingInitFunc glade_binding_init() to initialize the binding and
+GladeBindingLibraryLoadFunc glade_binding_library_load() to load a library
+written in language supported by the binding.
+
+You can add Scripting capability to the core by providing 
+GladeBindingRunScriptFunc glade_binding_run_script() and/or
+GladeBindingConsoleNewFunc glade_binding_console_new()
+
+The core will search for script in two different directories,
+datadir/package/scripts/ and g_get_user_config_dir()/package/scripts/
+
+The hierarchy in those directories should be binding_name/gtype_name/ *
+For example if you want to add a python script to GtkContainers you can do it by
+installing the script file in 
+g_get_user_config_dir()/glade3/scripts/python/GtkContainer/Delete_Children.py
+This will add a context menu item for any GtkContainer called "Delete Children"
+that will trigger GtkContainer's widget adaptor "action-activated::Delete_Children" signal.
+*/
+
+static GHashTable *bindings = NULL;
+
+static GList*
+glade_binding_script_add (GList *list, GladeBinding *binding, gchar *path)
+{
+	GladeBindingScript *script = g_new0 (GladeBindingScript, 1);
+	gchar *tmp;
+	
+	script->binding = binding;
+	script->path = path;
+	script->name = g_path_get_basename (path);
+	if ((tmp = strrchr (script->name, '.'))) *tmp = '\0';
+	return g_list_prepend (list, script);
+}
+
+static GList *
+glade_binding_get_script_list (GladeBinding *binding, gchar *directory)
+{
+	const gchar *filename;
+	GList *list = NULL;
+	GDir *dir;
+
+	if ((dir = g_dir_open (directory, 0, NULL)) == NULL) 
+		return NULL;
+
+	while ((filename = g_dir_read_name (dir)))
+	{
+		gchar *path = g_build_filename (directory, filename, NULL);
+		
+		if (g_file_test (path, G_FILE_TEST_IS_REGULAR))
+			list = glade_binding_script_add (list, binding, path);
+		else
+			g_free (path);
+	}
+	
+	return list;
+}
+
+static void
+glade_binding_script_free (gpointer data, gpointer user_data)
+{
+	GladeBindingScript *script = data;
+	if (script->path) g_free (script->path);
+	if (script->name) g_free (script->name);
+	g_free (script);
+}
+
+static void 
+glade_binding_classes_destroy (gpointer value)
+{
+	g_list_foreach (value, glade_binding_script_free, NULL);
+	g_list_free (value);
+}
+
+static void
+glade_binding_scriptdo_load (GladeBinding *binding, gchar *rootdir)
+{
+	const gchar *filename;
+	GDir *dir;
+	
+	if ((dir = g_dir_open (rootdir, 0, NULL)) == NULL) 
+		return;
+
+	while ((filename = g_dir_read_name (dir)))
+	{
+		gchar *path = g_build_filename (rootdir, filename, NULL);
+		GType type;
+
+		if (g_file_test (path, G_FILE_TEST_IS_DIR) &&
+		    (type = glade_util_get_type_from_name (filename)))
+		{
+			GList *list, *old_list;
+
+			list = glade_binding_get_script_list (binding, path);
+			old_list = g_datalist_id_get_data (&binding->context_scripts,
+							   type);
+
+			g_datalist_id_remove_no_notify (&binding->context_scripts, type);
+			list = g_list_concat (old_list, list);
+
+			g_datalist_id_set_data_full (&binding->context_scripts, type, list,
+						     glade_binding_classes_destroy);
+		}
+		else if (g_file_test (path, G_FILE_TEST_IS_REGULAR))
+			binding->scripts = glade_binding_script_add (binding->scripts, binding, path);
+		else
+			g_free (path);
+	}
+}
+
+/**
+ * glade_binding_load_all:
+ *
+ * Loads and initialize every binding plugin.
+ *
+ */
+void
+glade_binding_load_all ()
+{
+	const gchar *filename;
+	GError *error = NULL;
+	GDir *dir;
+
+	/* Read all files in bindings dir */
+	if ((dir = g_dir_open (glade_bindings_dir, 0, &error)) == NULL) 
+	{
+		g_warning ("Failed to open bindings directory: %s", error->message);
+		return;
+	}
+	
+	if (bindings == NULL)
+		bindings = g_hash_table_new (g_str_hash, g_str_equal);
+	
+	while ((filename = g_dir_read_name (dir)))
+	{
+		GladeBindingInitFunc init;
+		GladeBinding *binding;
+		GModule *module;
+		gchar *path;
+		
+		if (g_str_has_suffix (filename, G_MODULE_SUFFIX) == FALSE)
+			continue;
+		
+		path = g_build_filename (glade_bindings_dir, filename, NULL);
+		module = g_module_open (path, G_MODULE_BIND_LAZY);
+		g_free (path);
+		
+		if (module == NULL) continue;
+	
+		binding = g_new0 (GladeBinding, 1);
+		binding->module = module;
+		
+		if (g_module_symbol (module, "glade_binding_init",
+				     (gpointer)&init) && 
+		    g_module_symbol (module, "glade_binding_library_load",
+				     (gpointer)&binding->library_load) &&
+		    (binding->name = init ()))
+		{
+			g_module_symbol (module, "glade_binding_finalize",
+					 (gpointer)&binding->finalize);
+			g_module_symbol (module, "glade_binding_run_script",
+					 (gpointer)&binding->run_script);
+			g_module_symbol (module, "glade_binding_console_new",
+					 (gpointer)&binding->console_new);
+
+			g_hash_table_insert (bindings, binding->name, binding);
+			
+			if (binding->run_script)
+			{
+				gchar *rootdir;
+				g_datalist_init (&binding->context_scripts);
+				
+				rootdir = g_build_filename (glade_scripts_dir,
+							    binding->name, NULL);
+				glade_binding_scriptdo_load (binding, rootdir);
+				g_free (rootdir);
+		
+				rootdir = g_build_filename (g_get_user_config_dir (),
+							    PACKAGE_NAME, GLADE_BINDING_SCRIPT_DIR,
+							    binding->name, NULL);
+				glade_binding_scriptdo_load (binding, rootdir);
+				g_free (rootdir);
+			}
+		}
+		else
+		{
+			g_module_close (module);
+			g_free (binding);
+		}
+	}
+}
+
+static void 
+glade_binding_remove (gpointer key, gpointer value, gpointer user_data)
+{
+	GladeBinding *binding = value;
+	
+	if (binding->finalize) binding->finalize();
+	g_free (binding->name);	
+	g_module_close (binding->module);
+	
+	if (binding->scripts)
+		glade_binding_classes_destroy (binding->scripts);
+	
+	if (binding->context_scripts)
+		g_datalist_clear (&binding->context_scripts);
+	
+	g_free (binding);
+}
+
+/**
+ * glade_binding_unload_all:
+ *
+ * Finalize and unload every binding plugin.
+ *
+ */
+void
+glade_binding_unload_all ()
+{
+	if (bindings == NULL) return;
+		
+	g_hash_table_foreach (bindings, glade_binding_remove, NULL);
+	g_hash_table_destroy (bindings);
+	bindings = NULL;
+}
+
+/**
+ * glade_binding_get:
+ *
+ * @name: the binding name (ie: python)
+ *
+ * Returns the loaded binding.
+ *
+ */
+GladeBinding *
+glade_binding_get (const gchar *name)
+{
+	g_return_val_if_fail (name != NULL, NULL);
+	return g_hash_table_lookup (bindings, name);	
+}
+
+static void
+glade_binding_get_all_foreach (gpointer key, gpointer value, gpointer user_data)
+{
+	GList **l = user_data;
+	*l = g_list_append (*l, value);
+}
+
+/**
+ * glade_binding_get_all:
+ *
+ * Return a newly alocated list of every laoded binding.
+ *
+ */
+GList *
+glade_binding_get_all ()
+{
+	GList *l = NULL;
+	
+	g_hash_table_foreach (bindings, glade_binding_get_all_foreach, &l);
+	
+	return l;
+}
+
+/**
+ * glade_binding_library_load:
+ *
+ * @binding: a GladeBinding.
+ * @library: the library name.
+ *
+ * Loads the library name.
+ *
+ */
+void
+glade_binding_library_load (GladeBinding *binding, gchar *library)
+{
+	g_return_if_fail (binding != NULL && library != NULL);
+	binding->library_load (library);
+}
+
+/**
+ * glade_binding_console_new:
+ *
+ * @binding: a GladeBinding.
+ *
+ * Create a new console.
+ *
+ */
+GtkWidget *
+glade_binding_console_new (GladeBinding *binding)
+{
+	g_return_val_if_fail (binding != NULL, NULL);
+	return binding->console_new ();
+}
+
+/**
+ * glade_binding_run_script:
+ *
+ * @binding: a GladeBinding.
+ * @path: the library init function name.
+ *
+ * Run a script file.
+ *
+ */
+gint
+glade_binding_run_script (GladeBinding *binding, gchar *path)
+{
+	g_return_val_if_fail (binding != NULL && path != NULL, -1);
+	if (binding->run_script)
+		return binding->run_script (path);
+	else
+		return -1;
+}
Index: src/glade-binding.h
===================================================================
RCS file: src/glade-binding.h
diff -N src/glade-binding.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/glade-binding.h	16 Nov 2006 19:29:37 -0000
@@ -0,0 +1,134 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006 Juan Pablo Ugarte.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Authors:
+ *   Juan Pablo Ugarte <juanpablougarte@gmail.com>
+ */
+ 
+#ifndef __GLADE_BINDING_H__
+#define __GLADE_BINDING_H__
+
+G_BEGIN_DECLS
+
+#define GLADE_BINDING_SCRIPT_DIR "scripts"
+
+/**
+ * GladeBindingInitFunc:
+ *
+ * This function is called after loading the binding plugin.
+ *
+ * With interpreted language this would initialize the language's interpreter.
+ *
+ * Returns: a newly allocated string with the name of the binding of NULL if
+ * initialization failed.
+ *
+ */
+typedef gchar     *(*GladeBindingInitFunc)        (void);
+
+/**
+ * GladeBindingFinalizeFunc:
+ *
+ * This function is called after unloading the binding plugin.
+ *
+ */
+typedef void       (*GladeBindingFinalizeFunc)    (void);
+
+/**
+ * GladeBindingLibraryLoadFunc:
+ *
+ * @str: the library name to load.
+ *
+ * This function is used to load a library written in the language that is 
+ * supported by the binding.
+ *
+ * For example if I had a custom widget library writen in python, this function
+ * will provide the core a way to load "glademywidgets" python module.
+ *
+ * <glade-catalog name="mywidgets" library="glademywidgets" language="python">
+ *
+ */
+typedef void       (*GladeBindingLibraryLoadFunc) (gchar *str);
+
+/**
+ * GladeBindingRunScriptFunc:
+ *
+ * @path: the script path.
+ *
+ * Run the script @path.
+ * Define this function for the binding to support running scripts.
+ *
+ */
+typedef gint       (*GladeBindingRunScriptFunc)   (gchar *path);
+
+/**
+ * GladeBindingConsoleNewFunc:
+ *
+ * Create a new console widget for this binding.
+ * In glade3 this widget will be packed in the console window.
+ *
+ * Returns: A new GtkWidget.
+ *
+ */
+typedef GtkWidget *(*GladeBindingConsoleNewFunc)  (void);
+
+typedef struct _GladeBinding GladeBinding ;
+struct _GladeBinding {
+	GModule  *module; /* The binding module */
+	gchar    *name;   /* the name of the module (ie: python) */
+	
+	GList *scripts;   /* A list of GladeBindingScript */
+	
+	GData *context_scripts; /* A list of GladeBindingScript separated by GType */
+	
+	/* Module symbols */
+	GladeBindingFinalizeFunc    finalize;
+	GladeBindingLibraryLoadFunc library_load;
+	GladeBindingRunScriptFunc   run_script;
+	GladeBindingConsoleNewFunc  console_new;
+};
+
+typedef struct _GladeBindingScript GladeBindingScript ;
+struct _GladeBindingScript {
+	GladeBinding *binding;
+	gchar *name, *path;
+};
+
+LIBGLADEUI_API
+void          glade_binding_load_all (void);
+
+LIBGLADEUI_API
+void          glade_binding_unload_all (void);
+
+LIBGLADEUI_API
+GladeBinding *glade_binding_get (const gchar *name);
+
+LIBGLADEUI_API
+GList        *glade_binding_get_all ();
+
+LIBGLADEUI_API
+void          glade_binding_library_load (GladeBinding *binding, gchar *library);
+
+LIBGLADEUI_API
+gint          glade_binding_run_script (GladeBinding *script, gchar *path);
+
+LIBGLADEUI_API
+GtkWidget    *glade_binding_console_new (GladeBinding *binding);
+
+G_END_DECLS
+
+#endif
Index: src/glade-catalog.c
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-catalog.c,v
retrieving revision 1.39
diff -u -u -p -r1.39 glade-catalog.c
--- src/glade-catalog.c	9 Nov 2006 17:00:49 -0000	1.39
+++ src/glade-catalog.c	16 Nov 2006 19:29:41 -0000
@@ -36,11 +36,13 @@
 #include "glade.h"
 #include "glade-catalog.h"
 #include "glade-widget-adaptor.h"
+#include "glade-binding.h"
 
 typedef void   (*GladeCatalogInitFunc) (void);
 
 struct _GladeCatalog
 {
+	gchar *language;	 /* Library language, NULL means language is C */
 	gchar *library;          /* Library name for backend support  */
 
 	gchar *name;             /* Symbolic catalog name             */
@@ -148,6 +150,8 @@ catalog_open (const gchar *filename)
 		return NULL;
 	}
 	
+	catalog->language =
+		glade_xml_get_property_string (root, GLADE_TAG_LANGUAGE);
 	catalog->library =
 		glade_xml_get_property_string (root, GLADE_TAG_LIBRARY);
 	catalog->dep_catalog =
@@ -159,7 +163,7 @@ catalog_open (const gchar *filename)
 	catalog->init_function_name =
 		glade_xml_get_value_string (root, GLADE_TAG_INIT_FUNCTION);
 	
-	if (catalog->init_function_name)
+	if (catalog->init_function_name && catalog->language == NULL)
 		catalog_get_function (catalog, catalog->init_function_name,
 				      (gpointer) &catalog->init_function);
 
@@ -266,16 +270,26 @@ catalog_load_library (GladeCatalog *cata
 		
 	if (catalog->library == NULL) return NULL;
 
-	if ((module = g_hash_table_lookup (modules, catalog->library)))
-		return module;	
-		
-	if ((module = glade_util_load_library (catalog->library)))
-		g_hash_table_insert (modules, g_strdup (catalog->library), module);
+	if (catalog->language)
+	{
+		GladeBinding *binding = glade_binding_get (catalog->language);
+		if (binding)
+			glade_binding_library_load (binding, catalog->library);
+		return NULL;
+	}
 	else
-		g_warning ("Failed to load external library '%s'",
-			   catalog->library);
+	{
+		if ((module = g_hash_table_lookup (modules, catalog->library)))
+			return module;	
+		
+		if ((module = glade_util_load_library (catalog->library)))
+			g_hash_table_insert (modules, g_strdup (catalog->library), module);
+		else
+			g_warning ("Failed to load external library '%s'",
+				   catalog->library);
 		
-	return module;
+		return module;
+	}
 }
 
 static gboolean
Index: src/glade-marshallers.list
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-marshallers.list,v
retrieving revision 1.8
diff -u -u -p -r1.8 glade-marshallers.list
--- src/glade-marshallers.list	13 Jul 2006 21:38:19 -0000	1.8
+++ src/glade-marshallers.list	16 Nov 2006 19:29:41 -0000
@@ -5,10 +5,12 @@ VOID:OBJECT,BOOLEAN
 VOID:STRING,STRING,STRING
 OBJECT:POINTER
 OBJECT:OBJECT,UINT
+BOOLEAN:STRING
 BOOLEAN:OBJECT
 BOOLEAN:BOXED
 BOOLEAN:OBJECT,POINTER
 BOOLEAN:OBJECT,BOOLEAN
 BOOLEAN:OBJECT,UINT
 BOOLEAN:OBJECT,OBJECT
+BOOLEAN:OBJECT,STRING
 STRING:OBJECT
Index: src/glade-paths.sh.in
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-paths.sh.in,v
retrieving revision 1.2
diff -u -u -p -r1.2 glade-paths.sh.in
--- src/glade-paths.sh.in	30 Apr 2006 06:27:36 -0000	1.2
+++ src/glade-paths.sh.in	16 Nov 2006 19:29:41 -0000
@@ -15,7 +15,9 @@ glade_libdir="@glade_libdir@"
 glade_catalogsdir="@glade_catalogsdir@"
 glade_modulesdir="@glade_modulesdir@"
 glade_pluginsdir="@glade_pluginsdir@"
+glade_bindingsdir="@glade_bindingsdir@"
 glade_pixmapsdir="@glade_pixmapsdir@"
+glade_scriptsdir="@glade_scriptsdir@"
 glade_icondir="@glade_icondir@"
 glade_localedir="@glade_localedir@"
 
@@ -31,7 +33,9 @@ cat <<EOF
 #define GLADE_CATALOGSDIR "$glade_catalogsdir"
 #define GLADE_MODULESDIR "$glade_modulesdir"
 #define GLADE_PLUGINSDIR "$glade_pluginsdir"
+#define GLADE_BINDINGSDIR "$glade_bindingsdir"
 #define GLADE_PIXMAPSDIR "$glade_pixmapsdir"
+#define GLADE_SCRIPTSDIR "$glade_scriptsdir"
 #define GLADE_ICONDIR "$glade_icondir"
 #define GLADE_LOCALEDIR "$glade_localedir"
 
Index: src/glade-popup.c
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-popup.c,v
retrieving revision 1.37
diff -u -u -p -r1.37 glade-popup.c
--- src/glade-popup.c	29 Oct 2006 17:17:58 -0000	1.37
+++ src/glade-popup.c	16 Nov 2006 19:29:41 -0000
@@ -35,6 +35,7 @@
 #include "glade-command.h"
 #include "glade-project.h"
 #include "glade-app.h"
+#include "glade-binding.h"
 
 /********************************************************
                       WIDGET POPUP
@@ -141,10 +142,6 @@ glade_popup_clipboard_delete_cb (GtkMenu
 /********************************************************
                     POPUP BUILDING
  *******************************************************/
-
-/*
- * If stock_id != NULL, label is ignored
- */
 static GtkWidget *
 glade_popup_append_item (GtkWidget *popup_menu,
 			 const gchar *stock_id,
@@ -155,7 +152,13 @@ glade_popup_append_item (GtkWidget *popu
 {
 	GtkWidget *menu_item;
 
-	if (stock_id != NULL)
+	if (stock_id && label)
+	{
+		menu_item = gtk_image_menu_item_new_with_mnemonic (label);
+		gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
+			gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU));
+	}
+	else if (stock_id)
 		menu_item = gtk_image_menu_item_new_from_stock (stock_id, NULL);
 	else
 		menu_item = gtk_menu_item_new_with_mnemonic (label);
@@ -198,6 +201,46 @@ glade_popup_populate_childs (GtkWidget* 
 	}
 }
 
+static void
+glade_popup_menuitem_activated (GtkMenuItem *item, GladeWidget *widget)
+{
+	gchar *detail;
+	
+	if ((detail = g_object_get_data (G_OBJECT (item), "menuitem_detail")))
+		glade_widget_adaptor_action_activate (widget, detail);
+}
+
+static void
+glade_popup_add_actions (GtkWidget *menu, GladeWidget *widget, GList *actions)
+{
+	GList *list;
+	GtkWidget *item;
+	
+	for (list = actions; list; list = g_list_next (list))
+	{
+		GWAAction *action = list->data;
+		GtkWidget *submenu = NULL;
+		
+		if (action->actions)
+		{
+			submenu = gtk_menu_new ();
+			glade_popup_add_actions (submenu, widget, action->actions);
+		}
+		
+		if (action->is_a_group && submenu == NULL) continue;
+		
+		item = glade_popup_append_item (menu, 
+				action->stock,
+				action->label, TRUE,
+				(action->is_a_group) ? NULL : glade_popup_menuitem_activated,
+				(action->is_a_group) ? NULL : widget);
+		if (action->is_a_group == FALSE)
+			g_object_set_data (G_OBJECT (item), "menuitem_detail", action->id);
+		
+		if (submenu)
+			gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
+	}
+}
 
 static GtkWidget *
 glade_popup_create_menu (GladeWidget *widget, gboolean add_childs)
@@ -220,6 +263,8 @@ glade_popup_create_menu (GladeWidget *wi
 
 	glade_popup_append_item (popup_menu, GTK_STOCK_DELETE, NULL, TRUE,
 				 glade_popup_delete_cb, widget);
+
+	glade_popup_add_actions (popup_menu, widget, widget->adaptor->actions);
 
 	if (add_childs &&
 	    !g_type_is_a (widget->adaptor->type, GTK_TYPE_WINDOW)) {
Index: src/glade-project-window.c
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-project-window.c,v
retrieving revision 1.169
diff -u -u -p -r1.169 glade-project-window.c
--- src/glade-project-window.c	29 Oct 2006 17:17:58 -0000	1.169
+++ src/glade-project-window.c	16 Nov 2006 19:29:44 -0000
@@ -33,6 +33,7 @@
 #include "glade.h"
 #include "glade-design-view.h"
 #include "glade-project-window.h"
+#include "glade-binding.h"
 
 #define GLADE_ACTION_GROUP_STATIC "GladeStatic"
 #define GLADE_ACTION_GROUP_PROJECT "GladeProject"
@@ -69,7 +70,9 @@ struct _GladeProjectWindowPrivate
 	
 	GtkRecentManager *recent_manager;
 	GtkWidget *recent_menu;
-	
+
+	GtkWidget *console;
+
 	gchar *default_path; /* the default path for open/save operations */
 };
 
@@ -989,51 +992,63 @@ gpw_redo_cb (GtkAction *action, GladePro
 	glade_app_command_redo ();
 }
 
-static void
-gpw_doc_search_cb (GladeEditor        *editor,
-		   const gchar        *book,
-		   const gchar        *page,
-		   const gchar        *search,
-		   GladeProjectWindow *gpw)
-{
-	glade_util_search_devhelp (book, page, search);
-}
-
 static gboolean
-gpw_hide_clipboard_view_on_delete (GtkWidget *clipboard_view, gpointer not_used,
-				   GtkUIManager *ui)
+gpw_hide_window_on_delete (GtkWidget *window, gpointer not_used, GtkUIManager *ui)
 {
-	glade_util_hide_window (GTK_WINDOW (clipboard_view));
+	glade_util_hide_window (GTK_WINDOW (window));
 	return TRUE;
 }
 
-static void 
-gpw_create_clipboard_view (GladeProjectWindow *gpw)
-{
-	GtkWidget *view;
-	
-	view = glade_app_get_clipboard_view ();
-
-	g_signal_connect (G_OBJECT (view), "delete_event",
-			  G_CALLBACK (gpw_hide_clipboard_view_on_delete),
-			  gpw->priv->ui);
-}
-
 static void
-gpw_show_clipboard_view (GladeProjectWindow *gpw)
+gpw_construct_console (GladeProjectWindow *gpw)
 {
-	static gboolean created = FALSE;
+	GtkWidget *window, *console, *notebook;
+	GList *list, *l;
 	
 	g_return_if_fail (gpw != NULL);
 
-	if (!created)
+	window = gpw->priv->console = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+	gtk_window_set_title (GTK_WINDOW (window), _("Glade's Script-do Console"));
+	gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
+	gtk_widget_set_size_request (window, 640, 480);
+	
+	notebook = gtk_notebook_new ();
+	gtk_container_add (GTK_CONTAINER (window), notebook);
+	gtk_widget_show (notebook);
+	
+	for (list = l = glade_binding_get_all(); l && l->data; l = g_list_next (l))
 	{
-		gpw_create_clipboard_view (gpw);
-		created = TRUE;
+		GladeBinding *binding = l->data;
+		
+		if ((console = glade_binding_console_new (binding)))
+		{
+			gtk_notebook_append_page (GTK_NOTEBOOK (notebook), console,
+						  gtk_label_new (binding->name));
+			gtk_widget_show (console);
+		}
 	}
-	
-	gtk_widget_show_all (GTK_WIDGET (glade_app_get_clipboard_view ()));
-        gtk_window_present (GTK_WINDOW (glade_app_get_clipboard_view ()));
+
+	if (list == NULL)
+		gtk_widget_set_sensitive (gtk_ui_manager_get_widget 
+					  (gpw->priv->ui, "/MenuBar/ViewMenu/Console"),
+					  FALSE);
+
+	g_list_free (list);
+	
+	/* Delete event, don't destroy it */
+	g_signal_connect (window, "delete_event",
+			  G_CALLBACK (gpw_hide_window_on_delete), gpw->priv->ui);
+}
+
+static void
+gpw_doc_search_cb (GladeEditor        *editor,
+		   const gchar        *book,
+		   const gchar        *page,
+		   const gchar        *search,
+		   GladeProjectWindow *gpw)
+{
+	glade_util_search_devhelp (book, page, search);
 }
 
 static void
@@ -1093,6 +1108,16 @@ gpw_notebook_switch_page_cb (GtkNotebook
 }
 
 static void
+gpw_show_console_cb (GtkAction *action, GladeProjectWindow *gpw)
+{
+	g_return_if_fail (gpw != NULL);
+
+	gtk_widget_show (gpw->priv->console);
+
+	gtk_window_present (GTK_WINDOW (gpw->priv->console));
+}
+
+static void
 gpw_notebook_tab_added_cb (GtkNotebook *notebook,
 			   GladeDesignView *view,
 			   guint page_num,
@@ -1211,7 +1236,20 @@ gpw_palette_toggle_small_icons_cb (GtkAc
 static void
 gpw_show_clipboard_cb (GtkAction *action, GladeProjectWindow *gpw)
 {
-	gpw_show_clipboard_view (gpw);
+	static GtkWidget *view = NULL;
+	
+	g_return_if_fail (gpw != NULL);
+
+	if (view == NULL)
+	{
+		view = glade_app_get_clipboard_view ();
+
+		g_signal_connect (view, "delete_event",
+				  G_CALLBACK (gpw_hide_window_on_delete),
+				  gpw->priv->ui);
+	}
+	
+        gtk_window_present (GTK_WINDOW (view));
 }
 
 static void
@@ -1336,6 +1374,7 @@ static const gchar *ui_info =
 "    </menu>\n"
 "    <menu action='ViewMenu'>\n"
 "      <menuitem action='Clipboard'/>\n"
+"      <menuitem action='Console'/>\n"
 "      <separator/>\n"
 "      <menu action='PaletteAppearance'>\n"
 "        <menuitem action='IconsAndLabels'/>\n"
@@ -1439,7 +1478,11 @@ static GtkActionEntry project_entries[] 
 	{ "Clipboard", NULL, N_("_Clipboard"), NULL,
 	  N_("Show the clipboard"),
 	  G_CALLBACK (gpw_show_clipboard_cb) },
-
+	  
+	{ "Console", NULL, N_("C_onsole"), NULL,
+	  N_("Show Script console"),
+	  G_CALLBACK (gpw_show_console_cb) },
+	  
 	/* ProjectsMenu */
 	{ "PreviousProject", NULL, N_("_Previous Project"), "<control>Page_Up",
 	  N_("Activate previous project"), G_CALLBACK (glade_project_window_previous_project_cb) },
@@ -1765,6 +1808,9 @@ glade_project_window_create (GladeProjec
 
 	gtk_widget_set_sensitive (editor_item, FALSE);
 	gtk_widget_set_sensitive (docs_item, FALSE);
+	
+	/* Console */
+	gpw_construct_console (gpw);
 	
 	/* recent files */	
 	gpw->priv->recent_manager = gtk_recent_manager_get_for_screen (gtk_widget_get_screen (gpw->priv->window));
Index: src/glade-python-support.defs
===================================================================
RCS file: src/glade-python-support.defs
diff -N src/glade-python-support.defs
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/glade-python-support.defs	16 Nov 2006 19:29:44 -0000
@@ -0,0 +1,101 @@
+(define-object GladeWidgetAdaptor
+  (parent "GObject")
+  (c-name "GladeWidgetAdaptor")
+  (gtype-id "GLADE_TYPE_WIDGET_ADAPTOR")
+)
+
+(define-enum GladeCreateReason
+  (in-module "Glade")
+  (c-name "GladeCreateReason")
+  (gtype-id "GLADE_CREATE_REASON")
+  (values
+    '("create-user"    "GLADE_CREATE_USER")
+    '("create-copy"    "GLADE_CREATE_COPY")
+    '("create-load"    "GLADE_CREATE_LOAD")
+    '("create-rebuild" "GLADE_CREATE_REBUILD")
+  )
+)
+
+(define-virtual child_set_property
+  (of-object "GladeWidgetAdaptor")
+  (return-type "none")
+  (parameters
+    '("GObject*" "container")
+    '("GObject*" "child")
+    '("const-gchar*" "property_name")
+    '("const-GValue*" "value")
+  )
+)
+
+(define-virtual child_get_property
+  (of-object "GladeWidgetAdaptor")
+  (return-type "none")
+  (parameters
+    '("GObject*" "container")
+    '("GObject*" "child")
+    '("const-gchar*" "property_name")
+    '("GValue*" "value")
+  )
+)
+
+(define-virtual get_children
+  (of-object "GladeWidgetAdaptor")
+  (return-type "GList*")
+  (parameters
+    '("GObject*" "container")
+  )
+)
+
+(define-virtual add
+  (of-object "GladeWidgetAdaptor")
+  (return-type "none")
+  (parameters
+    '("GObject*" "parent")
+    '("GObject*" "child")
+  )
+)
+
+(define-virtual remove
+  (of-object "GladeWidgetAdaptor")
+  (return-type "none")
+  (parameters
+    '("GObject*" "parent")
+    '("GObject*" "child")
+  )
+)
+
+(define-virtual replace_child
+  (of-object "GladeWidgetAdaptor")
+  (return-type "none")
+  (parameters
+    '("GObject*" "container")
+    '("GObject*" "old")
+    '("GObject*" "new")
+  )
+)
+
+(define-virtual post_create
+  (of-object "GladeWidgetAdaptor")
+  (return-type "none")
+  (parameters
+    '("GObject*" "object")
+    '("GladeCreateReason" "reason")
+  )
+)
+
+(define-virtual get_internal_child
+  (of-object "GladeWidgetAdaptor")
+  (return-type "GObject*")
+  (parameters
+    '("GObject*" "parent")
+    '("const-gchar*" "name")
+  )
+)
+
+(define-virtual launch_editor
+  (of-object "GladeWidgetAdaptor")
+  (return-type "none")
+  (parameters
+    '("GObject*" "object")
+  )
+)
Index: src/glade-python-support.override
===================================================================
RCS file: src/glade-python-support.override
diff -N src/glade-python-support.override
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/glade-python-support.override	16 Nov 2006 19:29:45 -0000
@@ -0,0 +1,405 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006 Juan Pablo Ugarte.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Authors:
+ *   Juan Pablo Ugarte <juanpablougarte@gmail.com>
+ */
+%%
+headers
+#include <Python.h>               
+#include <pygobject.h>
+#include "glade.h"
+
+static gboolean
+glade_python_support_init_value (GObject *container, const gchar *property_name, GValue *value)
+{
+	GParamSpec *pspec = gtk_container_class_find_child_property 
+				(G_OBJECT_GET_CLASS (container), property_name);
+
+	if (pspec == NULL)
+	{
+        	gchar *error =	g_strdup_printf ("container does not support property `%s'", property_name);
+		PyErr_SetString (PyExc_TypeError, error);
+		return FALSE;
+	}
+	
+	g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+	return TRUE;
+}
+
+static GList *
+glade_python_support_glist_from_list (PyObject *list)
+{
+	gint i, size = PyList_Size (list);
+	GList *retval = NULL;
+	
+	for (i = 0; i < size; i++)
+	{
+		PyObject *val = PyList_GetItem (list, i);
+		retval = g_list_prepend (retval, pygobject_get(val));
+	}
+	return retval;
+}
+
+static PyObject *
+glade_python_support_list_from_glist (GList *list)
+{
+	PyObject *retval = PyList_New (0);;
+	
+	for (; list; list = g_list_next (list))
+	{
+		GObject *obj = list->data;
+		PyList_Append (retval, Py_BuildValue ("O", pygobject_new (obj)));
+	}
+	
+	return retval;
+}
+
+/*
+  NOTE: the next functions where created by codegen and adapted to support 
+  GValue* and GList* types.
+*/
+
+%%
+import gobject.GObject as PyGObject_Type
+%%
+override GladeWidgetAdaptor__do_child_set_property kwargs
+static PyObject *
+_wrap_GladeWidgetAdaptor__do_child_set_property(PyObject *cls, PyObject *args, PyObject *kwargs)
+{
+    gpointer klass;
+    static char *kwlist[] = { "self", "container", "child", "property_name", "value", NULL };
+    PyGObject *self, *container, *child;
+    PyObject *val;
+    char *property_name;
+    GValue value = {0,};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!O!sO:GladeWidgetAdaptor.child_set_property", kwlist, &PyGladeWidgetAdaptor_Type, &self, &PyGObject_Type, &container, &PyGObject_Type, &child, &property_name, &val))
+        return NULL;
+    klass = g_type_class_ref(pyg_type_from_object(cls));
+    
+    glade_python_support_init_value (container->obj, property_name, &value);
+    pyg_value_from_pyobject (&value, val);    
+    
+    if (GLADE_WIDGET_ADAPTOR_CLASS(klass)->child_set_property)
+        GLADE_WIDGET_ADAPTOR_CLASS(klass)->child_set_property(GLADE_WIDGET_ADAPTOR(self->obj), G_OBJECT(container->obj), G_OBJECT(child->obj), property_name, &value);
+    else {
+        PyErr_SetString(PyExc_NotImplementedError, "virtual method GladeWidgetAdaptor.child_set_property not implemented");
+        g_type_class_unref(klass);
+        return NULL;
+    }
+    g_type_class_unref(klass);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+%%
+override GladeWidgetAdaptor__proxy_do_child_set_property
+static void
+_wrap_GladeWidgetAdaptor__proxy_do_child_set_property(GladeWidgetAdaptor *self, GObject*container, GObject*child, const gchar*property_name, const GValue *value)
+{
+    PyGILState_STATE __py_state;
+    PyObject *py_self;
+    PyObject *py_container = NULL;
+    PyObject *py_child = NULL;
+    PyObject *py_property_name;
+    PyObject *py_value;
+    PyObject *py_retval;
+    PyObject *py_args;
+    PyObject *py_method;
+    
+    __py_state = pyg_gil_state_ensure();
+    py_self = pygobject_new((GObject *) self);
+    if (!py_self) {
+        if (PyErr_Occurred())
+            PyErr_Print();
+        pyg_gil_state_release(__py_state);
+        return;
+    }
+    if (container)
+        py_container = pygobject_new((GObject *) container);
+    else {
+        Py_INCREF(Py_None);
+        py_container = Py_None;
+    }
+    if (child)
+        py_child = pygobject_new((GObject *) child);
+    else {
+        Py_INCREF(Py_None);
+        py_child = Py_None;
+    }
+    py_property_name = PyString_FromString(property_name);
+    if (!py_property_name) {
+        if (PyErr_Occurred())
+            PyErr_Print();
+        Py_DECREF(py_child);
+        Py_DECREF(py_container);
+        Py_DECREF(py_self);
+        pyg_gil_state_release(__py_state);
+        return;
+    }
+    py_value = pyg_value_as_pyobject (value, TRUE);
+    if (!py_value) {
+        if (PyErr_Occurred())
+            PyErr_Print();
+        Py_DECREF(py_property_name);
+        Py_DECREF(py_child);
+        Py_DECREF(py_container);
+        Py_DECREF(py_self);
+        pyg_gil_state_release(__py_state);
+        return;
+    }
+    
+    py_args = PyTuple_New(4);
+    PyTuple_SET_ITEM(py_args, 0, py_container);
+    PyTuple_SET_ITEM(py_args, 1, py_child);
+    PyTuple_SET_ITEM(py_args, 2, py_property_name);
+    PyTuple_SET_ITEM(py_args, 3, py_value);
+    
+    py_method = PyObject_GetAttrString(py_self, "do_child_set_property");
+    if (!py_method) {
+        if (PyErr_Occurred())
+            PyErr_Print();
+        Py_DECREF(py_args);
+        Py_DECREF(py_self);
+        pyg_gil_state_release(__py_state);
+        return;
+    }
+    py_retval = PyObject_CallObject(py_method, py_args);
+    if (!py_retval) {
+        if (PyErr_Occurred())
+            PyErr_Print();
+        Py_DECREF(py_method);
+        Py_DECREF(py_args);
+        Py_DECREF(py_self);
+        pyg_gil_state_release(__py_state);
+        return;
+    }
+    if (py_retval != Py_None) {
+        if (PyErr_Occurred())
+            PyErr_Print();
+        PyErr_SetString(PyExc_TypeError, "retval should be None");
+        Py_DECREF(py_retval);
+        Py_DECREF(py_method);
+        Py_DECREF(py_args);
+        Py_DECREF(py_self);
+        pyg_gil_state_release(__py_state);
+        return;
+    }
+    
+    Py_DECREF(py_retval);
+    Py_DECREF(py_method);
+    Py_DECREF(py_args);
+    Py_DECREF(py_self);
+    pyg_gil_state_release(__py_state);
+}
+%%
+override GladeWidgetAdaptor__do_child_get_property kwargs
+static PyObject *
+_wrap_GladeWidgetAdaptor__do_child_get_property(PyObject *cls, PyObject *args, PyObject *kwargs)
+{
+    gpointer klass;
+    static char *kwlist[] = { "self", "container", "child", "property_name", NULL };
+    PyGObject *self, *container, *child;
+    char *property_name;
+    PyObject *ret;
+    GValue value = { 0, } ;
+    
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!O!s:GladeWidgetAdaptor.child_get_property", kwlist, &PyGladeWidgetAdaptor_Type, &self, &PyGObject_Type, &container, &PyGObject_Type, &child, &property_name))
+        return NULL;
+    klass = g_type_class_ref(pyg_type_from_object(cls));
+    if (GLADE_WIDGET_ADAPTOR_CLASS(klass)->child_get_property)
+    {
+	glade_python_support_init_value (container->obj, property_name, &value);
+        GLADE_WIDGET_ADAPTOR_CLASS(klass)->child_get_property(GLADE_WIDGET_ADAPTOR(self->obj), G_OBJECT(container->obj), G_OBJECT(child->obj), property_name, &value);
+	ret = pyg_value_as_pyobject (&value, TRUE);
+	g_value_unset (&value);
+    }
+    else {
+        PyErr_SetString(PyExc_NotImplementedError, "virtual method GladeWidgetAdaptor.child_get_property not implemented");
+        g_type_class_unref(klass);
+        return NULL;
+    }
+    g_type_class_unref(klass);
+    return ret;
+}
+%%
+override GladeWidgetAdaptor__proxy_do_child_get_property
+static void
+_wrap_GladeWidgetAdaptor__proxy_do_child_get_property(GladeWidgetAdaptor *self, GObject*container, GObject*child, const gchar*property_name, GValue *value)
+{
+    PyGILState_STATE __py_state;
+    PyObject *py_self;
+    PyObject *py_container = NULL;
+    PyObject *py_child = NULL;
+    PyObject *py_property_name;
+    PyObject *py_retval;
+    PyObject *py_args;
+    PyObject *py_method;
+    
+    __py_state = pyg_gil_state_ensure();
+    py_self = pygobject_new((GObject *) self);
+    if (!py_self) {
+        if (PyErr_Occurred())
+            PyErr_Print();
+        pyg_gil_state_release(__py_state);
+        return;
+    }
+    if (container)
+        py_container = pygobject_new((GObject *) container);
+    else {
+        Py_INCREF(Py_None);
+        py_container = Py_None;
+    }
+    if (child)
+        py_child = pygobject_new((GObject *) child);
+    else {
+        Py_INCREF(Py_None);
+        py_child = Py_None;
+    }
+    py_property_name = PyString_FromString(property_name);
+    if (!py_property_name) {
+        if (PyErr_Occurred())
+            PyErr_Print();
+        Py_DECREF(py_child);
+        Py_DECREF(py_container);
+        Py_DECREF(py_self);
+        pyg_gil_state_release(__py_state);
+        return;
+    }
+    
+    py_args = PyTuple_New(3);
+    PyTuple_SET_ITEM(py_args, 0, py_container);
+    PyTuple_SET_ITEM(py_args, 1, py_child);
+    PyTuple_SET_ITEM(py_args, 2, py_property_name);
+    
+    py_method = PyObject_GetAttrString(py_self, "do_child_get_property");
+    if (!py_method) {
+        if (PyErr_Occurred())
+            PyErr_Print();
+        Py_DECREF(py_args);
+        Py_DECREF(py_self);
+        pyg_gil_state_release(__py_state);
+        return;
+    }
+    py_retval = PyObject_CallObject(py_method, py_args);
+    if (!py_retval) {
+        if (PyErr_Occurred())
+            PyErr_Print();
+        Py_DECREF(py_method);
+        Py_DECREF(py_args);
+        Py_DECREF(py_self);
+        pyg_gil_state_release(__py_state);
+        return;
+    }
+    
+    pyg_value_from_pyobject (value, py_retval);
+   
+    Py_DECREF(py_retval);
+    Py_DECREF(py_method);
+    Py_DECREF(py_args);
+    Py_DECREF(py_self);
+    pyg_gil_state_release(__py_state);
+}
+%%
+override GladeWidgetAdaptor__do_get_children kwargs
+static PyObject *
+_wrap_GladeWidgetAdaptor__do_get_children(PyObject *cls, PyObject *args, PyObject *kwargs)
+{
+    gpointer klass;
+    static char *kwlist[] = { "self", "container", NULL };
+    PyGObject *self, *container;
+    PyObject *list;
+    GList *ret;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:GladeWidgetAdaptor.get_children", kwlist, &PyGladeWidgetAdaptor_Type, &self, &PyGObject_Type, &container))
+        return NULL;
+    klass = g_type_class_ref(pyg_type_from_object(cls));
+    if (GLADE_WIDGET_ADAPTOR_CLASS(klass)->get_children)
+        ret = GLADE_WIDGET_ADAPTOR_CLASS(klass)->get_children(GLADE_WIDGET_ADAPTOR(self->obj), G_OBJECT(container->obj));
+    else {
+        PyErr_SetString(PyExc_NotImplementedError, "virtual method GladeWidgetAdaptor.get_children not implemented");
+        g_type_class_unref(klass);
+        return NULL;
+    }
+    g_type_class_unref(klass);
+
+    list = glade_python_support_list_from_glist (ret);
+    g_list_free (ret);
+    return list;
+}
+%%
+override GladeWidgetAdaptor__proxy_do_get_children
+static GList*
+_wrap_GladeWidgetAdaptor__proxy_do_get_children(GladeWidgetAdaptor *self, GObject*container)
+{
+    PyGILState_STATE __py_state;
+    PyObject *py_self;
+    PyObject *py_container = NULL;
+    GList* retval;
+    PyObject *py_retval;
+    PyObject *py_args;
+    PyObject *py_method;
+    
+    __py_state = pyg_gil_state_ensure();
+    py_self = pygobject_new((GObject *) self);
+    if (!py_self) {
+        if (PyErr_Occurred())
+            PyErr_Print();
+        pyg_gil_state_release(__py_state);
+        return NULL;
+    }
+    if (container)
+        py_container = pygobject_new((GObject *) container);
+    else {
+        Py_INCREF(Py_None);
+        py_container = Py_None;
+    }
+    
+    py_args = PyTuple_New(1);
+    PyTuple_SET_ITEM(py_args, 0, py_container);
+    
+    py_method = PyObject_GetAttrString(py_self, "do_get_children");
+    if (!py_method) {
+        if (PyErr_Occurred())
+            PyErr_Print();
+        Py_DECREF(py_args);
+        Py_DECREF(py_self);
+        pyg_gil_state_release(__py_state);
+        return NULL;
+    }
+    py_retval = PyObject_CallObject(py_method, py_args);
+    if (!py_retval) {
+        if (PyErr_Occurred())
+            PyErr_Print();
+        Py_DECREF(py_method);
+        Py_DECREF(py_args);
+        Py_DECREF(py_self);
+        pyg_gil_state_release(__py_state);
+        return NULL;
+    }
+	
+    retval = glade_python_support_glist_from_list (py_retval);
+    
+    Py_DECREF(py_retval);
+    Py_DECREF(py_method);
+    Py_DECREF(py_args);
+    Py_DECREF(py_self);
+    pyg_gil_state_release(__py_state);
+    
+    return retval;
+}
Index: src/glade-python.c
===================================================================
RCS file: src/glade-python.c
diff -N src/glade-python.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/glade-python.c	16 Nov 2006 19:29:45 -0000
@@ -0,0 +1,567 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006 Juan Pablo Ugarte.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Authors:
+ *   Juan Pablo Ugarte <juanpablougarte@gmail.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <Python.h>
+#include <pygobject.h>
+#include <glade.h>
+
+static GtkTextBuffer *PythonBuffer = NULL;
+static GtkTextMark   *PythonBufferEnd;
+
+static 	PyObject *glade, *glade_dict, *GladeError, *GladeStdout, *GladeStderr;
+
+static PyObject *
+glade_python_undo (PyObject *self, PyObject *args)
+{
+	glade_app_command_undo ();
+	
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+glade_python_redo (PyObject *self, PyObject *args)
+{
+	glade_app_command_redo ();
+	
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+glade_python_project_new (PyObject *self, PyObject *args)
+{	
+	glade_app_add_project (glade_project_new (TRUE));
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+glade_python_project_open (PyObject *self, PyObject *args)
+{
+	gchar *path;
+	
+	Py_INCREF(Py_None);
+	
+	if (PyArg_ParseTuple(args, "s", &path))
+	{
+		GladeProject *project;
+		
+		if ((project = glade_app_get_project_by_path (path)))
+			glade_app_set_project (project);
+		else if ((project = glade_project_open (path)))
+			glade_app_add_project (project);
+		else
+			return Py_None;
+	}
+	
+	return Py_None;
+}
+
+static PyObject *
+glade_python_project_save (PyObject *self, PyObject *args)
+{
+	gchar *path;
+	
+	if (PyArg_ParseTuple(args, "s", &path))
+		glade_project_save (glade_app_get_project (), path, NULL);
+	
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+glade_python_project_close (PyObject *self, PyObject *args)
+{
+
+	gchar *name;
+	
+	if (PyArg_ParseTuple(args, "s", &name))
+	{
+		GladeProject *project = glade_app_get_project_by_name (name);
+		if (project) glade_app_remove_project (project);
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+glade_python_project_get (PyObject *self, PyObject *args)
+{
+	GladeProject *project = glade_app_get_project ();
+	return Py_BuildValue ("s", (project) ? project->name : "");
+}
+
+static PyObject *
+glade_python_project_list (PyObject *self, PyObject *args)
+{
+	GList *p, *projects = glade_app_get_projects ();
+	PyObject *list;
+	
+	list = PyList_New (0);
+	
+	for (p = projects; p && p->data; p = g_list_next (p))
+	{
+		GladeProject *project = p->data;
+		PyList_Append (list, Py_BuildValue ("s", project->name));
+	}
+	
+	return list;
+}
+
+static PyObject *
+glade_python_project_set (PyObject *self, PyObject *args)
+{
+	gchar *name;
+	
+	if (PyArg_ParseTuple(args, "s", &name))
+	{
+		GladeProject *project = glade_app_get_project_by_name (name);
+		if (project) glade_app_set_project (project);
+	}
+	
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+glade_python_widget_new (PyObject *self, PyObject *args)
+{
+	GladeProject *project = glade_app_get_project ();
+	GladeWidgetAdaptor *adaptor; 
+	GladeWidget *widget = NULL;
+	gchar *class_name, *parent;
+
+	if (project && PyArg_ParseTuple(args, "ss", &class_name, &parent) &&
+	    (adaptor = glade_widget_adaptor_get_by_name (class_name)))
+		widget = glade_command_create (adaptor,
+				glade_project_get_widget_by_name (project, parent),
+				NULL, project);
+	
+	return Py_BuildValue ("s", (widget) ? widget->name : "");
+}
+
+static PyObject *
+glade_python_widget_delete (PyObject *self, PyObject *args)
+{
+	GladeProject *project = glade_app_get_project ();
+	gchar *name;
+	
+	if (project && PyArg_ParseTuple(args, "s", &name))
+	{
+		GladeWidget *widget;
+		if ((widget = glade_project_get_widget_by_name (project, name)))
+		{
+			GList list;
+			list.data = widget;
+			list.next = list.prev = NULL;
+			glade_command_delete (&list);
+		}
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+glade_python_widget_set (PyObject *self, PyObject *args)
+{
+	GladeProject *project = glade_app_get_project ();
+	gchar *name, *id_property;
+	PyObject *val;
+	
+	if (project && PyArg_ParseTuple(args, "ssO", &name, &id_property, &val))
+	{
+		GladeWidget *widget;
+		GladeProperty *property;
+
+		if ((widget = glade_project_get_widget_by_name (project, name)) &&
+		    (property = glade_widget_get_property (widget, id_property)))
+		{
+			GValue value = {0,};
+			g_value_init (&value, G_VALUE_TYPE (property->value));
+			if (pyg_value_from_pyobject (&value, val) == 0)
+				glade_command_set_property_value (property, &value);
+		}
+	}
+	
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+glade_python_widget_get (PyObject *self, PyObject *args)
+{
+	GladeProject *project = glade_app_get_project ();
+	gchar *name, *id_property;
+	
+	if (project && PyArg_ParseTuple(args, "ss", &name, &id_property))
+	{
+		GladeWidget *widget;
+		GladeProperty *property;
+
+		if ((widget = glade_project_get_widget_by_name (project, name)) &&
+		    (property = glade_widget_get_property (widget, id_property)))
+			return pyg_value_as_pyobject (property->value, TRUE);
+	}
+	
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+glade_python_widget_list (PyObject *self, PyObject *args)
+{
+	GList *p;
+	GladeProject *project = glade_app_get_project ();
+	PyObject *list;
+	
+	list = PyList_New (0);
+	
+	for (p = project->objects; p && p->data; p = g_list_next (p))
+	{
+		GladeWidget *widget = glade_widget_get_from_gobject (p->data);
+		if (widget)
+			PyList_Append (list, Py_BuildValue ("s", glade_widget_get_name (widget)));
+	}
+	
+	return list;
+}
+
+extern PyTypeObject PyGladeWidgetAdaptor_Type;
+
+static GHashTable *registered_classes = NULL;
+
+static PyTypeObject *
+glade_python_register_class (GType type)
+{
+	GType parent = g_type_parent (type);
+	PyTypeObject *class, *parent_class;
+	
+	if (parent == 0 || type == GLADE_TYPE_WIDGET_ADAPTOR)
+		return &PyGladeWidgetAdaptor_Type;
+	
+	if (g_hash_table_lookup (registered_classes, GUINT_TO_POINTER (parent)) == NULL)
+		parent_class = glade_python_register_class (parent);
+	else
+		parent_class = pygobject_lookup_class (parent);
+	
+	class = pygobject_lookup_class (type);
+	
+	pygobject_register_class (glade_dict, g_type_name (type), type, class,
+				  Py_BuildValue("(O)", parent_class));
+	pyg_set_object_has_new_constructor (type);
+
+	g_hash_table_insert (registered_classes, GUINT_TO_POINTER (type), class);
+	
+	return class;
+}
+
+static PyObject *
+glade_python_get_adaptor_for_type (PyObject *self, PyObject *args)
+{
+	GladeWidgetAdaptor *adaptor;
+	PyObject *class;
+	gchar *name;
+
+	if (PyArg_ParseTuple(args, "s", &name) &&
+	    (adaptor = glade_widget_adaptor_get_by_name (name)))
+	{
+		GType type = G_TYPE_FROM_INSTANCE (adaptor);
+
+		if ((class = g_hash_table_lookup (registered_classes, GUINT_TO_POINTER (type))))
+			return (PyObject *) class;
+		else
+			return (PyObject *) glade_python_register_class (type);
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyMethodDef GladeMethods[] = {
+	{"undo",  glade_python_undo, METH_VARARGS, "Execute undo command."},
+	{"redo",  glade_python_redo, METH_VARARGS, "Execute redo command."},
+	{"project_new",  glade_python_project_new, METH_VARARGS, "Create a new project."},
+	{"project_open",  glade_python_project_open, METH_VARARGS, "Open an existing project."},
+	{"project_save",  glade_python_project_save, METH_VARARGS, "Save the current project."},
+	{"project_close",  glade_python_project_close, METH_VARARGS, "Close the current project."},
+	{"project_get",  glade_python_project_get, METH_VARARGS, "Get the current project."},
+	{"project_set",  glade_python_project_set, METH_VARARGS, "Set the current project."},
+	{"project_list",  glade_python_project_list, METH_VARARGS, "List all projects."},
+	{"widget_new",  glade_python_widget_new, METH_VARARGS, "Create a new GtkWidget."},
+	{"widget_delete",  glade_python_widget_delete, METH_VARARGS, "Delete a GtkWidget."},
+	{"widget_set",  glade_python_widget_set, METH_VARARGS, "Set a GtkWidget's property."},
+	{"widget_get",  glade_python_widget_get, METH_VARARGS, "Get a GtkWidget's property."},
+	{"widget_list",  glade_python_widget_list, METH_VARARGS, "List all widgets."},
+	{"get_adaptor_for_type",  glade_python_get_adaptor_for_type, METH_VARARGS, "Get the corresponding GladeWidgetAdaptor. Use this function to create your own derived Adaptor."},
+	{NULL, NULL, 0, NULL}
+};
+
+/* GladeStdout GladeStderr write method */
+static PyObject *
+glade_python_std_write (PyObject *self, PyObject *args, gboolean stdout)
+{
+	gchar *string;
+	
+	if (PythonBuffer && PyArg_ParseTuple(args, "s", &string))
+	{
+		GtkTextIter iter;
+		gtk_text_buffer_get_end_iter (PythonBuffer, &iter);
+		if (stdout)
+			gtk_text_buffer_insert (PythonBuffer, &iter, string, -1);
+		else
+			gtk_text_buffer_insert_with_tags_by_name (PythonBuffer, 
+				&iter, string, -1, "red_foreground", NULL);
+	}
+	
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+glade_python_stdout_write (PyObject *self, PyObject *args)
+{
+	return glade_python_std_write (self, args, TRUE);
+}
+static PyObject *
+glade_python_stderr_write (PyObject *self, PyObject *args)
+{
+	return glade_python_std_write (self, args, FALSE);
+}
+
+static PyMethodDef GladeStdoutMethods[] = {
+    {"write",  glade_python_stdout_write, METH_VARARGS, NULL},
+    {NULL, NULL, 0, NULL}
+};
+
+static PyMethodDef GladeStderrMethods[] = {
+    {"write",  glade_python_stderr_write, METH_VARARGS, NULL},
+    {NULL, NULL, 0, NULL}
+};
+
+void
+glade_python_init ()
+{
+	char *argv[2] = {"", NULL};
+	Py_Initialize ();
+	PySys_SetArgv (1, argv);
+	init_pygobject ();
+}
+
+/*  Defined in glade_python_support.c wich is generated by pygtk-codegen-2.0 */
+void glade_python_support_register_classes (PyObject *d);
+
+static gboolean
+glade_binding_init_idle (gpointer data)
+{
+	/*
+	  FIXME:
+	   This redirect the program's stdout and stderr, it would be better if 
+	   only the python's interpreter output is redirected. Also it has to be
+	   called from an idle function because some mutex issue.
+	*/
+	/* Redirect stdout & stderr to the TextBuffer */
+	PySys_SetObject("stdout", GladeStdout);
+	PySys_SetObject("stderr", GladeStderr);
+	return FALSE;
+}
+
+/* Bindings */
+gchar *
+glade_binding_init (void)
+{
+	GtkTextIter iter;
+	gchar *command;
+	
+	if (PythonBuffer == NULL)
+	{	
+		PythonBuffer = gtk_text_buffer_new (NULL);
+		gtk_text_buffer_create_tag (PythonBuffer, "blue_foreground",
+					    "foreground", "blue", NULL);
+		gtk_text_buffer_create_tag (PythonBuffer, "red_foreground",
+					    "foreground", "red", NULL);
+		gtk_text_buffer_get_end_iter (PythonBuffer, &iter);
+		PythonBufferEnd = gtk_text_buffer_create_mark (PythonBuffer, NULL, &iter, FALSE);
+	}
+	else return NULL;
+
+    	Py_SetProgramName (PACKAGE_NAME);
+	
+    	/* Initialize the Python interpreter if it is not */
+	if (Py_IsInitialized() == FALSE) glade_python_init ();
+	
+	/* Create glade object */
+	glade = Py_InitModule ("glade", GladeMethods);
+	GladeError = PyErr_NewException ("glade.error", NULL, NULL);
+	Py_INCREF (GladeError);
+	PyModule_AddObject (glade, "error", GladeError);
+
+	/* Create GladeStdout and GladeStderr objects */
+	GladeStdout = Py_InitModule ("stdout", GladeStdoutMethods);
+	GladeStderr = Py_InitModule ("stderr", GladeStderrMethods);
+
+	g_idle_add (glade_binding_init_idle, NULL);
+
+	/* Register GladeUI classes (GladeWidgetAdaptor) */
+	glade_dict = PyModule_GetDict (glade);
+	glade_python_support_register_classes (glade_dict);
+	
+	/* Create registered_classes hash table */
+	registered_classes = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+	/* Insert GladeWidgetAdaptor class in the hash table */
+	g_hash_table_insert (registered_classes,
+			     GUINT_TO_POINTER (GLADE_TYPE_WIDGET_ADAPTOR),
+			     &PyGladeWidgetAdaptor_Type);
+
+	/* Import glade module and set path */
+	command = g_strdup_printf ("import sys; import glade; sys.path+=['.', '%s'];\n",
+				    glade_modules_dir);
+	PyRun_SimpleString (command);
+	g_free (command);
+
+	gtk_text_buffer_get_end_iter (PythonBuffer, &iter);
+	gtk_text_buffer_insert_with_tags_by_name (PythonBuffer, &iter,
+					">>> import sys;\n>>> import glade;\n",
+					-1, "blue_foreground", NULL);
+	
+	return g_strdup ("python");
+}
+
+void
+glade_binding_finalize (void)
+{
+	if (PythonBuffer)
+	{
+		Py_Finalize ();
+		g_object_unref (PythonBuffer);
+	}
+}
+
+void 
+glade_binding_library_load (gchar *library)
+{
+	gchar *str = g_strdup_printf ("import %s", library);
+	PyRun_SimpleString (str);
+	g_free (str);
+}
+
+gint
+glade_binding_run_script (gchar *path)
+{
+	FILE *fp = fopen (path, "r");
+	gint retval;
+	
+	if (fp == NULL) return -1;
+	
+	retval = PyRun_SimpleFile (fp, path);
+	fclose (fp);
+	
+	return retval;
+}
+
+static void
+glade_python_console_entry_activate (GtkEntry *entry, GtkTextView *textview)
+{
+	const gchar *command = gtk_entry_get_text (entry);
+	GtkTextIter iter;
+	
+	gtk_text_buffer_get_end_iter (PythonBuffer, &iter);
+	gtk_text_buffer_insert_with_tags_by_name (PythonBuffer, &iter, ">>> ", -1,
+						  "blue_foreground", NULL);
+	gtk_text_buffer_get_end_iter (PythonBuffer, &iter);
+	gtk_text_buffer_insert_with_tags_by_name (PythonBuffer, &iter, command, -1,
+						  "blue_foreground", NULL);
+	gtk_text_buffer_get_end_iter (PythonBuffer, &iter);
+	gtk_text_buffer_insert (PythonBuffer, &iter, "\n", -1);
+	
+	if (PyRun_SimpleString (command) == 0) gtk_entry_set_text (entry, "");
+}
+
+static void
+glade_python_buffer_changed (GtkTextBuffer *buffer, GtkTextView *textview)
+{
+	gtk_text_view_scroll_to_mark (textview, PythonBufferEnd, 0.0, TRUE, 0.0, 1.0);
+}
+
+static void 
+glade_python_textview_destroy (GtkObject *object, gpointer data)
+{
+	g_signal_handler_disconnect (PythonBuffer, GPOINTER_TO_UINT (data));
+}
+
+GtkWidget *
+glade_binding_console_new (void)
+{
+	GtkWidget *vbox, *hbox, *textview, *label, *entry, *sw;
+	gulong handler_id;
+	
+	vbox = gtk_vbox_new (FALSE, 4);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox),
+					GLADE_GENERIC_BORDER_WIDTH);
+	
+	sw = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
+					     GTK_SHADOW_ETCHED_IN);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+					GTK_POLICY_AUTOMATIC,
+					GTK_POLICY_AUTOMATIC);
+	gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
+	
+	textview = gtk_text_view_new_with_buffer (PythonBuffer);
+	gtk_text_view_set_editable (GTK_TEXT_VIEW (textview), FALSE);
+	gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (textview), FALSE);
+	gtk_container_add (GTK_CONTAINER (sw), textview);
+	handler_id = g_signal_connect (PythonBuffer, "changed",
+				       G_CALLBACK (glade_python_buffer_changed),
+				       GTK_TEXT_VIEW (textview));
+	g_signal_connect (textview, "destroy",
+			  G_CALLBACK (glade_python_textview_destroy),
+			  GUINT_TO_POINTER (handler_id));
+
+	hbox = gtk_hbox_new (FALSE, 4);
+	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+	
+	label = gtk_label_new (">>>");
+	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+	
+	entry = gtk_entry_new ();
+	g_signal_connect (entry, "activate", 
+			  G_CALLBACK (glade_python_console_entry_activate),
+			  GTK_TEXT_VIEW (textview));
+	gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
+	
+	gtk_widget_show (textview);
+	gtk_widget_show (label);
+	gtk_widget_show (entry);
+	gtk_widget_show (hbox);
+	gtk_widget_show (sw);
+
+	return vbox;
+}
Index: src/glade-widget-adaptor.c
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-widget-adaptor.c,v
retrieving revision 1.3
diff -u -u -p -r1.3 glade-widget-adaptor.c
--- src/glade-widget-adaptor.c	9 Nov 2006 17:00:49 -0000	1.3
+++ src/glade-widget-adaptor.c	16 Nov 2006 19:29:48 -0000
@@ -40,6 +40,9 @@
 #include "glade-xml-utils.h"
 #include "glade-property-class.h"
 #include "glade-signal.h"
+#include "glade-marshallers.h"
+#include "glade-accumulators.h"
+#include "glade-binding.h"
 
 struct _GladeWidgetAdaptorPriv {
 
@@ -80,13 +83,19 @@ enum {
 	PROP_CURSOR
 };
 
+enum
+{
+	SIGNAL_ACTION_ACTIVATED,
+	LAST_SIGNAL
+};
+
 typedef struct _GladeChildPacking GladeChildPacking;
 
+static guint gwa_signals [LAST_SIGNAL] = {0,};
 
 static GObjectClass *parent_class = NULL;
 static GHashTable   *adaptor_hash = NULL;
 
-
 /*******************************************************************************
                               Helper functions
  *******************************************************************************/
@@ -554,6 +563,40 @@ gwa_inherit_child_packing (GladeWidgetAd
 	return child_packings;
 }
 
+static GList *
+gwa_action_copy (GList *src)
+{
+	GList *l, *list = NULL;
+	
+	for (l = src; l; l = g_list_next (l))
+	{
+		GWAAction *action = l->data, *copy = g_new0 (GWAAction, 1);
+	
+		copy->id = g_strdup (action->id);
+		copy->label = g_strdup (action->label);
+		copy->stock = g_strdup (action->stock);
+		copy->is_a_group = action->is_a_group;
+		
+		list = g_list_append (list, l->data);
+		
+		if (action->actions)
+			copy->actions = gwa_action_copy (action->actions);
+	}
+	
+	return list;
+}
+
+static void
+gwa_action_setup (GladeWidgetAdaptor *adaptor)
+{
+	GladeWidgetAdaptor *parent = gwa_get_parent_adaptor (adaptor);
+	
+	if (parent && parent->actions)
+		adaptor->actions = gwa_action_copy (parent->actions);
+	else
+		adaptor->actions = NULL;
+}
+
 static GObject *
 glade_widget_adaptor_constructor (GType                  type,
 				  guint                  n_construct_properties,
@@ -586,6 +629,8 @@ glade_widget_adaptor_constructor (GType 
 	/* Inherit packing defaults here */
 	adaptor->child_packings = gwa_inherit_child_packing (adaptor);
 
+	gwa_action_setup (adaptor);
+	
 	return ret_obj;
 }
 
@@ -606,6 +651,25 @@ gwa_child_packing_free (GladeChildPackin
         g_list_free (packing->packing_defaults);
 }
 
+static  void
+gwa_actions_free (GList *actions)
+{
+	GList *l;
+	
+	for (l = actions; l; l = g_list_next (l))
+	{
+		GWAAction *action = l->data;
+
+		if (action->actions) gwa_actions_free (action->actions);
+		
+		g_free (action->id);
+		g_free (action->label);
+		g_free (action->stock);
+		g_free (action);		
+	}
+	g_list_free (actions);
+}
+
 static void
 glade_widget_adaptor_finalize (GObject *object)
 {
@@ -646,6 +710,8 @@ glade_widget_adaptor_finalize (GObject *
 	if (adaptor->generic_name) g_free (adaptor->generic_name);
 	if (adaptor->title)        g_free (adaptor->title);
 
+	if (adaptor->actions)      gwa_actions_free (adaptor->actions);
+	
 	g_free (adaptor->priv);
 
 	G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -733,6 +799,23 @@ glade_widget_adaptor_init (GladeWidgetAd
 	adaptor->priv = g_new0 (GladeWidgetAdaptorPriv, 1);
 }
 
+static gboolean
+gwa_action_activated_impl (GladeWidgetAdaptor *adaptor,
+			   GladeWidget *widget,
+			   const gchar *action_id)
+{
+	static guint signal = 0;
+	gboolean retval;
+	
+	if (signal == 0)
+		signal = g_signal_lookup ("action-activated", GLADE_TYPE_WIDGET);
+	
+	g_signal_emit (widget, signal, g_quark_from_string (action_id),
+		       action_id, &retval);
+
+	return retval;
+}
+
 static void
 glade_widget_adaptor_class_init (GladeWidgetAdaptorClass *adaptor_class)
 {
@@ -759,6 +842,28 @@ glade_widget_adaptor_class_init (GladeWi
 	adaptor_class->child_set_property   = NULL;
 	adaptor_class->child_get_property   = NULL;
 
+	adaptor_class->action_activated     = gwa_action_activated_impl;
+
+	/**
+	 * GladeWidgetAdaptor::action-activated:
+	 * @adaptor: the GladeWidgetAdaptor which received the signal.
+	 * @widget: the action's GladeWidget or NULL.
+	 * @action_id: the action id (signal detail) or NULL.
+	 *
+	 * Use this to catch up actions.
+	 *
+	 * Returns TRUE to stop others handlers being invoked.
+	 *
+	 */
+	gwa_signals [SIGNAL_ACTION_ACTIVATED] =
+		g_signal_new ("action-activated",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+			      G_STRUCT_OFFSET (GladeWidgetAdaptorClass, action_activated),
+			      glade_boolean_handled_accumulator, NULL,
+			      glade_marshal_BOOLEAN__OBJECT_STRING,
+			      G_TYPE_BOOLEAN, 2, GLADE_TYPE_WIDGET, G_TYPE_STRING);	
+
 	/* Properties */
 	g_object_class_install_property 
 		(object_class, PROP_NAME,
@@ -868,6 +973,27 @@ glade_widget_adaptor_get_type (void)
 	return adaptor_type;
 }
 
+GType
+glade_create_reason_get_type (void)
+{
+	static GType etype = 0;
+
+	if (etype == 0)
+	{
+		static const GEnumValue values[] = {
+			{ GLADE_CREATE_USER,    "GLADE_CREATE_USER",    "create-user" },
+			{ GLADE_CREATE_COPY,    "GLADE_CREATE_COPY",    "create-copy" },
+			{ GLADE_CREATE_LOAD,    "GLADE_CREATE_LOAD",    "create-load" },
+			{ GLADE_CREATE_REBUILD, "GLADE_CREATE_REBUILD", "create-rebuild" },
+			{ 0, NULL, NULL }
+		};
+
+		etype = g_enum_register_static ("GladeCreateReason", values);
+
+	}
+
+	return etype;
+}
 
 /*******************************************************************************
                         Synthetic Object Derivation
@@ -907,7 +1033,7 @@ gwa_derive_adaptor_for_type (GType objec
 	/* Note that we must pass ownership of the type_name string
 	 * to the type system 
 	 */
-	type_name    = g_strdup_printf ("Glade%sAdaptor", g_type_name (object_type));
+	type_name = g_strdup_printf ("Glade%sAdaptor", g_type_name (object_type));
 	derived_type = 
 		g_type_register_static_simple (parent_type, type_name,
 					       sizeof (GladeWidgetAdaptorClass),
@@ -1131,6 +1257,110 @@ gwa_update_properties_from_node (GladeWi
 	}
 }
 
+static GList **
+gwa_action_lookup (GList **actions, const gchar *id, gboolean only_group)
+{
+	GList **group = actions, *l;
+	
+	for (l = *actions; l; l = g_list_next (l))
+	{
+		GWAAction *action = l->data;
+		
+		if (only_group && action->is_a_group == FALSE) continue;
+		
+		if (strcmp (action->id, id) == 0)
+			return (only_group) ? &action->actions : group;
+			
+		if (action->is_a_group && action->actions &&
+		    (group = gwa_action_lookup (&action->actions, id, only_group)))
+			return group;
+	}
+	
+	return NULL;
+}
+
+/*
+ * gwa_action_append:
+ *
+ * @adaptor: the GladeWidgetAdaptor.
+ * @group_id: the group id weater to append this action or NULL.
+ * @id: the id of the action.
+ * @label: the label of the action or NULL.
+ * @stock: the stock id of the action or NULL (ie: "gtk-delete").
+ * @is_a_group: if this is an action group.
+ *
+ * Append a new GWAAction to @adaptor.
+ *
+ * Returns weater or not the action wass appended
+ *
+ */
+static gboolean
+gwa_action_append (GladeWidgetAdaptor *adaptor,
+		   const gchar *group_id,
+		   const gchar *id,
+		   const gchar *label,
+		   const gchar *stock,
+		   gboolean is_a_group)
+{
+	GList **group;
+	GWAAction *action;
+
+	g_return_val_if_fail (id != NULL, FALSE);
+
+	if (group_id)
+	{
+		group = gwa_action_lookup (&adaptor->actions, group_id, TRUE);
+		if (group == NULL) return FALSE;
+	}
+	else group = &adaptor->actions;
+		
+	if (gwa_action_lookup (&adaptor->actions, id, FALSE)) return FALSE;
+			
+	action = g_new0 (GWAAction, 1);
+	action->id = g_strdup (id);
+	action->label = (label) ? g_strdup (label) : NULL;
+	action->stock = (stock) ? g_strdup (stock) : NULL;
+	action->is_a_group = is_a_group;	
+	
+	*group = g_list_prepend (*group, action);
+	
+	return TRUE;
+}
+
+static void
+gwa_update_actions (GladeWidgetAdaptor *adaptor,
+		    GladeXmlNode *node,
+		    gchar *group_id)
+{
+	GladeXmlNode *child;
+	gchar *id, *label, *stock;
+	gboolean group;
+	
+	for (child = glade_xml_node_get_children (node);
+	     child; child = glade_xml_node_next (child))
+	{
+		if ((group = glade_xml_node_verify_silent (child, GLADE_TAG_ACTION_GROUP)) == FALSE &&
+		    glade_xml_node_verify_silent (child, GLADE_TAG_ACTION) == FALSE)
+			continue;
+
+		id = glade_xml_get_property_string_required
+					(child,	GLADE_TAG_ID, adaptor->name);
+		if (id == NULL)
+			continue;
+
+		label = glade_xml_get_property_string (child, GLADE_TAG_NAME);
+		stock = glade_xml_get_property_string (child, GLADE_TAG_STOCK);
+
+		gwa_action_append (adaptor, group_id, id,
+				   (label == NULL && stock == NULL) ? id : label,
+				   stock, group);
+		if (group) gwa_update_actions (adaptor, child, id);
+			
+		g_free (id);
+		g_free (label);
+		g_free (stock);
+	}
+}
 
 static gboolean
 gwa_extend_with_node (GladeWidgetAdaptor *adaptor, 
@@ -1206,11 +1436,60 @@ gwa_extend_with_node (GladeWidgetAdaptor
 	if ((child = 
 	     glade_xml_search_child (node, GLADE_TAG_PACKING_DEFAULTS)) != NULL)
 		gwa_set_packing_defaults_from_node (adaptor, child);
+	
+	/* Search for actions */
+	gwa_update_actions (adaptor, node, NULL);
+	
+	return TRUE;
+}
 
+static gboolean
+gwa_script_item_activate_cb (GladeWidgetAdaptor *adaptor,
+			     GladeWidget *widget,
+			     const gchar *action_id,
+			     GladeBindingScript *script)
+{
+	glade_binding_run_script (script->binding, script->path);
 	return TRUE;
 }
 
+static void
+gwa_setup_binding_scripts (GladeWidgetAdaptor *adaptor)
+{
+	GList *l, *bindings;
 
+	if ((bindings = glade_binding_get_all ()) == NULL) return;
+	
+	gwa_action_append (adaptor, NULL, "scripts", "Scripts", NULL, TRUE);
+	
+	for (l = bindings; l; l = g_list_next (l))
+	{
+		GladeBinding *binding = l->data;
+		GList *list;
+	
+		for (list = g_datalist_id_get_data (&binding->context_scripts, adaptor->type);
+		     list; list = g_list_next (list))
+		{
+			GladeBindingScript *script = list->data;
+			gchar *detailed_signal, *name = g_strdup (script->name);
+			
+			detailed_signal = g_strdup_printf ("action-activated::%s", script->name);
+			glade_util_replace (name, '_', ' ');
+
+			gwa_action_append (adaptor, "scripts", script->name,
+					   name, NULL, FALSE);
+
+			g_signal_connect (adaptor, detailed_signal,
+					  G_CALLBACK (gwa_script_item_activate_cb),
+					  script);
+
+			g_free (name);
+			g_free (detailed_signal);
+		}
+	}
+	
+	g_list_free (bindings);
+}
 
 /**
  * glade_widget_adaptor_from_catalog:
@@ -1233,7 +1512,7 @@ glade_widget_adaptor_from_catalog (Glade
 				   const gchar      *book)
 {
 	GladeWidgetAdaptor *adaptor = NULL;
-	gchar              *name, *generic_name;
+	gchar              *name, *generic_name, *adaptor_name;
 	GType               object_type, adaptor_type, parent_type;
 
 	if (!glade_xml_node_verify (class_node, GLADE_TAG_GLADE_WIDGET_CLASS))
@@ -1258,10 +1537,24 @@ glade_widget_adaptor_from_catalog (Glade
 	{
 		g_warning ("Adaptor class for '%s' already defined", 
 			   g_type_name (object_type));
+		g_free (name);
 		return NULL;
 	}
-
-	adaptor_type = gwa_derive_adaptor_for_type (object_type);
+	
+	if ((adaptor_name = glade_xml_get_property_string (class_node, GLADE_TAG_ADAPTOR)))
+		adaptor_type = g_type_from_name (adaptor_name);
+	else
+		adaptor_type = gwa_derive_adaptor_for_type (object_type);
+	
+	if (adaptor_type == 0)
+	{
+		g_warning ("Failed to get %s's adaptor %s", name,
+			   (adaptor_name) ? adaptor_name : "");
+		g_free (adaptor_name);
+		g_free (name);
+		return NULL;
+	}
+	
 	generic_name = glade_xml_get_property_string (class_node, GLADE_TAG_GENERIC_NAME);
 	adaptor      = g_object_new (adaptor_type, 
 				     "type", object_type,
@@ -1317,6 +1610,8 @@ glade_widget_adaptor_from_catalog (Glade
 		gwa_properties_set_weight (&adaptor->packing_props, parent_type);
 	}
 
+	gwa_setup_binding_scripts (adaptor);
+	
 	glade_widget_adaptor_register (adaptor);
 
 	return adaptor;
@@ -1951,4 +2246,39 @@ glade_widget_adaptor_get_packing_default
 		}
 	}
 	return NULL;
+}
+
+/*
+ * glade_widget_adaptor_action_activate:
+ *
+ * @widget: the GladeWidget.
+ * @action_id: The action id (detail of GladeWidgetAdaptor's action-activated signal).
+ *
+ * Emit @widget's adaptor action-activated::@action_id signal.
+ * GladeWidget's action-activated proxy signal is also emited.
+ *
+ */
+void
+glade_widget_adaptor_action_activate (GladeWidget *widget, const gchar *action_id)
+{
+	GladeWidgetAdaptor *adaptor;
+	GQuark detail;
+	guint signal;
+	gboolean retval;
+	
+	g_return_if_fail (GLADE_IS_WIDGET (widget) && action_id);
+
+	signal = gwa_signals [SIGNAL_ACTION_ACTIVATED];	
+	detail = g_quark_from_string (action_id);
+	
+	for (adaptor = widget->adaptor;
+	     adaptor;
+	     adaptor = gwa_get_parent_adaptor (adaptor))
+	{
+		if (gwa_action_lookup (&adaptor->actions, action_id, FALSE))
+			g_signal_emit (adaptor, signal, detail, widget,
+				       action_id, &retval);
+		else
+			return;
+	}
 }
Index: src/glade-widget-adaptor.h
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-widget-adaptor.h,v
retrieving revision 1.2
diff -u -u -p -r1.2 glade-widget-adaptor.h
--- src/glade-widget-adaptor.h	9 Nov 2006 17:00:49 -0000	1.2
+++ src/glade-widget-adaptor.h	16 Nov 2006 19:29:48 -0000
@@ -89,6 +89,8 @@ typedef enum _GladeCreateReason
 	GLADE_CREATE_REASONS
 } GladeCreateReason;
 
+#define GLADE_CREATE_REASON (glade_create_reason_get_type())
+
 /**
  * GladeChildSetPropertyFunc:
  * @adaptor: A #GladeWidgetAdaptor
@@ -215,6 +217,14 @@ struct _GladeSignalClass
 
 };
 
+typedef struct _GWAAction GWAAction;
+struct _GWAAction
+{
+	gchar *id, *label, *stock;
+	gboolean is_a_group;
+	GList *actions;
+};
+
 /* Note that everything that must be processed at the creation of
  * every instance is managed on the instance structure, and everywhere
  * that we want to take advantage of inheritance is handled in the class
@@ -255,6 +265,7 @@ struct _GladeWidgetAdaptor
 
         GList       *child_packings; /* Default packing property values */
 
+	GList       *actions;        /* A list of GWAAction */
 
 	GladeWidgetAdaptorPriv *priv;
 
@@ -296,6 +307,8 @@ struct _GladeWidgetAdaptorClass
 						    * replace a placeholder with
 						    * a widget and viceversa.
 						    */
+	/* Signals */
+	gboolean                   (*action_activated) (GladeWidgetAdaptor *, GladeWidget *, const gchar *);
 };
 
 #define glade_widget_adaptor_create_widget(adaptor, query, ...) \
@@ -307,6 +320,8 @@ struct _GladeWidgetAdaptorClass
 LIBGLADEUI_API
 GType glade_widget_adaptor_get_type         (void) G_GNUC_CONST;
  
+LIBGLADEUI_API
+GType glade_create_reason_get_type          (void) G_GNUC_CONST;
 
 LIBGLADEUI_API
 GladeWidgetAdaptor  *glade_widget_adaptor_from_catalog     (GladeXmlNode         *class_node,
@@ -396,7 +411,9 @@ LIBGLADEUI_API G_CONST_RETURN
 gchar               *glade_widget_adaptor_get_packing_default(GladeWidgetAdaptor *child_adaptor,
 							      GladeWidgetAdaptor *parent_adaptor,
 							      const gchar        *propert_id);
-
+LIBGLADEUI_API
+void                 glade_widget_adaptor_action_activate    (GladeWidget *widget,
+					    		      const gchar *action_id);
 G_END_DECLS
 
 #endif /* __GLADE_WIDGET_ADAPTOR_H__ */
Index: src/glade-widget.c
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-widget.c,v
retrieving revision 1.207
diff -u -u -p -r1.207 glade-widget.c
--- src/glade-widget.c	26 Oct 2006 00:45:21 -0000	1.207
+++ src/glade-widget.c	16 Nov 2006 19:29:56 -0000
@@ -76,6 +76,7 @@ enum
 	BUTTON_RELEASE_EVENT,
 	MOTION_NOTIFY_EVENT,
 	ENTER_NOTIFY_EVENT,
+	ACTION_ACTIVATED,
 	LAST_SIGNAL
 };
 
@@ -266,7 +267,6 @@ glade_widget_change_signal_handler_impl 
 	}
 }
 
-
 /* A temp data struct that we use when looking for a widget inside a container
  * we need a struct, because the forall can only pass one pointer
  */
@@ -1051,12 +1051,12 @@ glade_widget_class_init (GladeWidgetClas
 	klass->add_signal_handler     = glade_widget_add_signal_handler_impl;
 	klass->remove_signal_handler  = glade_widget_remove_signal_handler_impl;
 	klass->change_signal_handler  = glade_widget_change_signal_handler_impl;
-
+	
 	klass->button_press_event     = glade_widget_button_press_event_impl;
 	klass->button_release_event   = NULL;
 	klass->motion_notify_event    = NULL;
 	klass->enter_notify_event     = NULL;
-	
+
 	g_object_class_install_property
 		(object_class, PROP_NAME,
 		 g_param_spec_string ("name", _("Name"),
@@ -1260,6 +1260,26 @@ glade_widget_class_init (GladeWidgetClas
 			      glade_marshal_BOOLEAN__BOXED,
 			      G_TYPE_BOOLEAN, 1,
 			      GDK_TYPE_EVENT);
+
+	/**
+	 * GladeWidget::action-activated:
+	 * @widget: the #GladeWidget which received the signal.
+	 * @action_id: the action id (signal detail) or NULL.
+	 *
+	 * Use this to catch up actions. This signal is proxied from 
+	 * GladeWidgetAdaptor's "action-emited" signal default handler.
+	 *
+	 * Returns TRUE to stop others handlers being invoked.
+	 *
+	 */
+	glade_widget_signals [ACTION_ACTIVATED] =
+		g_signal_new ("action-activated",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+			      G_STRUCT_OFFSET (GladeWidgetClass, action_activated),
+			      glade_boolean_handled_accumulator, NULL,
+			      glade_marshal_BOOLEAN__STRING,
+			      G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
 }
 
 GType
Index: src/glade-widget.h
===================================================================
RCS file: /cvs/gnome/glade3/src/glade-widget.h,v
retrieving revision 1.70
diff -u -u -p -r1.70 glade-widget.h
--- src/glade-widget.h	26 Oct 2006 00:45:22 -0000	1.70
+++ src/glade-widget.h	16 Nov 2006 19:29:56 -0000
@@ -102,15 +102,15 @@ struct _GladeWidgetClass
 	void         (*add_signal_handler)	(GladeWidget *, GladeSignal *);
 	void         (*remove_signal_handler)	(GladeWidget *, GladeSignal *);
 	void         (*change_signal_handler)	(GladeWidget *, GladeSignal *, GladeSignal *);
-
+	gboolean     (*action_activated)        (GladeWidget *, const gchar *);
+	
 	gint         (*button_press_event)      (GladeWidget *, GdkEvent *);
 	gint         (*button_release_event)    (GladeWidget *, GdkEvent *);
 	gint         (*motion_notify_event)     (GladeWidget *, GdkEvent *);
 	gint         (*enter_notify_event)      (GladeWidget *, GdkEvent *);
-
+	
 	void         (*setup_events)            (GladeWidget *, GtkWidget *);
 	gboolean     (*event)                   (GtkWidget *, GdkEvent *, GladeWidget *);
-
 };
 
 /*******************************************************************************
Index: src/glade.h
===================================================================
RCS file: /cvs/gnome/glade3/src/glade.h,v
retrieving revision 1.77
diff -u -u -p -r1.77 glade.h
--- src/glade.h	9 Nov 2006 17:00:49 -0000	1.77
+++ src/glade.h	16 Nov 2006 19:29:56 -0000
@@ -86,6 +86,8 @@ typedef enum   _GladeItemAppearance Glad
 #define GLADE_TAG_GLADE_WIDGET_GROUP              "glade-widget-group"
 #define GLADE_TAG_GLADE_WIDGET_CLASS_REF          "glade-widget-class-ref"
 
+#define GLADE_TAG_LANGUAGE                        "language"
+#define GLADE_TAG_ADAPTOR                         "adaptor"
 #define GLADE_TAG_LIBRARY                         "library"
 #define GLADE_TAG_DEPENDS                         "depends"
 #define GLADE_TAG_DOMAIN                          "domain"
@@ -144,6 +146,9 @@ typedef enum   _GladeItemAppearance Glad
 #define GLADE_TAG_FIXED                           "fixed"
 #define GLADE_TAG_TRANSFER_ON_PASTE               "transfer-on-paste"
 #define GLADE_TAG_WEIGHT                          "weight"
+#define GLADE_TAG_ACTION_GROUP                    "action-group"
+#define GLADE_TAG_ACTION                          "action"
+#define GLADE_TAG_STOCK                           "stock"
 
 #define GLADE_NUMERICAL_STEP_INCREMENT             1
 #define GLADE_FLOATING_STEP_INCREMENT              0.01F
@@ -154,9 +159,11 @@ typedef enum   _GladeItemAppearance Glad
 LIBGLADEUI_API gboolean glade_verbose;
 
 LIBGLADEUI_API gchar* glade_pixmaps_dir;
+LIBGLADEUI_API gchar* glade_scripts_dir;
 LIBGLADEUI_API gchar* glade_catalogs_dir;
 LIBGLADEUI_API gchar* glade_modules_dir;
 LIBGLADEUI_API gchar* glade_plugins_dir;
+LIBGLADEUI_API gchar* glade_bindings_dir;
 LIBGLADEUI_API gchar* glade_locale_dir;
 LIBGLADEUI_API gchar* glade_icon_dir;
