Index: gladeui/glade-format-gtkbuilder.c
===================================================================
--- gladeui/glade-format-gtkbuilder.c	(revision 0)
+++ gladeui/glade-format-gtkbuilder.c	(revision 0)
@@ -0,0 +1,420 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ *
+ * Copyright (C) 1998-2002  James Henstridge <james@daa.com.au>
+ * Copyright (C) 2007 Johan Dahlin <johan@gnome.org>
+ *
+ * glade-format-gtkbuilder.c: functions for saving gtkbuilder files
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA  02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <libxml/parser.h>
+
+#include "glade-parser.h"
+
+#include "glade-format-gtkbuilder.h"
+
+static gchar *
+modifier_string_from_bits (GdkModifierType modifiers)
+{
+    GString *string = g_string_new ("");
+
+    if (modifiers & GDK_SHIFT_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_SHIFT_MASK");
+    }
+
+    if (modifiers & GDK_LOCK_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_LOCK_MASK");
+    }
+
+    if (modifiers & GDK_CONTROL_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_CONTROL_MASK");
+    }
+
+    if (modifiers & GDK_MOD1_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_MOD1_MASK");
+    }
+
+    if (modifiers & GDK_MOD2_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_MOD2_MASK");
+    }
+
+    if (modifiers & GDK_MOD3_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_MOD3_MASK");
+    }
+
+    if (modifiers & GDK_MOD4_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_MOD4_MASK");
+    }
+
+    if (modifiers & GDK_MOD5_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_MOD5_MASK");
+    }
+
+    if (modifiers & GDK_BUTTON1_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_BUTTON1_MASK");
+    }
+
+    if (modifiers & GDK_BUTTON2_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_BUTTON2_MASK");
+    }
+
+    if (modifiers & GDK_BUTTON3_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_BUTTON3_MASK");
+    }
+
+    if (modifiers & GDK_BUTTON4_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_BUTTON4_MASK");
+    }
+
+    if (modifiers & GDK_BUTTON5_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_BUTTON5_MASK");
+    }
+
+    if (modifiers & GDK_RELEASE_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_RELEASE_MASK");
+    }
+
+    if (string->len > 0)
+	return g_string_free (string, FALSE);
+
+    g_string_free (string, TRUE);
+    return NULL;
+}
+
+static void
+write_dialog_response(xmlNode *parent, gchar *widget_name, gchar *response)
+{
+  xmlNode *node;
+  xmlNode *dialog = NULL;
+  xmlNode *action_widgets = NULL;
+  xmlNode *action_widget;
+  
+  for (node = parent; node; node = node->parent)
+    {
+      if (!node || !node->name)
+	continue;
+      
+      if (strcmp ((char*)node->name, "object") != 0)
+	continue;
+
+      if (!strcmp ((char*)xmlGetProp (node, BAD_CAST("class")), "GtkDialog"))
+	{
+	  dialog = node;
+	  break;
+	}
+    }
+  
+  if (!dialog)
+    return;
+
+  for (node = dialog->children; node; node = node->next)
+    {
+      if (!strcmp ((char*)node->name, "action-widgets"))
+	{
+	  action_widgets = node;
+	  break;
+	}
+    }
+
+  if (!action_widgets)
+    {
+      action_widgets = xmlNewNode(NULL, BAD_CAST("action-widgets"));
+
+      xmlNodeAddContent(dialog, BAD_CAST("    "));
+      xmlAddChild(dialog, action_widgets);
+
+      xmlNodeAddContent(action_widgets, BAD_CAST("\n"));
+      xmlNodeAddContent(action_widgets, BAD_CAST("    "));
+      xmlNodeAddContent(dialog, BAD_CAST("\n"));
+    }
+
+  xmlNodeAddContent(action_widgets, BAD_CAST("  "));
+  
+  action_widget = xmlNewNode(NULL, BAD_CAST("action-widget"));
+  xmlSetProp(action_widget, BAD_CAST("response"), BAD_CAST(response));
+  xmlNodeSetContent(action_widget, BAD_CAST(widget_name));
+  xmlAddChild(action_widgets, action_widget);
+
+  xmlNodeAddContent(action_widgets, BAD_CAST("\n"));
+  xmlNodeAddContent(action_widgets, BAD_CAST("    "));
+}
+
+static void
+dump_widget(xmlNode *parent, GladeWidgetInfo *info, gint indent)
+{
+    xmlNode *widget;
+    gint i, j;
+
+    if (info == NULL) {
+	widget = xmlNewNode(NULL, BAD_CAST("placeholder"));
+	xmlAddChild(parent, widget);
+	return;
+    }
+
+    widget = xmlNewNode(NULL, BAD_CAST("object"));
+
+    xmlSetProp(widget, BAD_CAST("class"), BAD_CAST(info->classname));
+    xmlSetProp(widget, BAD_CAST("id"), BAD_CAST(info->name));
+    xmlAddChild(parent, widget);
+    xmlNodeAddContent(widget, BAD_CAST("\n"));
+
+    for (i = 0; i < info->n_properties; i++) { 
+	xmlNode *node;
+
+	if (!strcmp (info->classname, "GtkButton") &&
+	    !strcmp (info->properties[i].name, "response_id"))
+	  {
+	    write_dialog_response(parent, info->name, info->properties[i].value);
+	    continue;
+	  }
+	  
+	for (j = 0; j < indent + 1; j++)
+	    xmlNodeAddContent(widget, BAD_CAST("  "));
+	node = xmlNewNode(NULL, BAD_CAST("property"));
+	xmlSetProp(node, BAD_CAST("name"), BAD_CAST(info->properties[i].name));
+	if (info->properties[i].translatable)
+	    xmlSetProp(node, BAD_CAST("translatable"), BAD_CAST("yes"));
+	if (info->properties[i].has_context)
+	    xmlSetProp(node, BAD_CAST("context"), BAD_CAST("yes"));
+	if (info->properties[i].comment)
+	    xmlSetProp(node, BAD_CAST("comments"), 
+		       BAD_CAST(info->properties[i].comment));
+	xmlNodeSetContent(node, BAD_CAST(info->properties[i].value));
+	xmlAddChild(widget, node);
+	xmlNodeAddContent(widget, BAD_CAST("\n"));
+    }
+
+    for (i = 0; i < info->n_signals; i++) {
+	xmlNode *node;
+
+	for (j = 0; j < indent + 1; j++)
+	    xmlNodeAddContent(widget, BAD_CAST("  "));
+
+	node = xmlNewNode(NULL, BAD_CAST("signal"));
+	xmlSetProp(node, BAD_CAST("name"), BAD_CAST(info->signals[i].name));
+	xmlSetProp(node, BAD_CAST("handler"), BAD_CAST(info->signals[i].handler));
+	if (info->signals[i].after)
+	    xmlSetProp(node, BAD_CAST("after"), BAD_CAST("yes"));
+	if (info->signals[i].lookup)
+	    xmlSetProp(node, BAD_CAST("lookup"), BAD_CAST("yes"));
+	if (info->signals[i].object)
+	    xmlSetProp(node, BAD_CAST("object"), BAD_CAST(info->signals[i].object));
+	xmlAddChild(widget, node);
+	xmlNodeAddContent(widget, BAD_CAST("\n"));
+    }
+
+    for (i = 0; i < info->n_accels; i++) {
+	xmlNode *node;
+	gchar   *modifiers;
+
+	modifiers = modifier_string_from_bits (info->accels[i].modifiers);
+
+	for (j = 0; j < indent + 1; j++)
+	    xmlNodeAddContent(widget, BAD_CAST("  "));
+
+	node = xmlNewNode(NULL, BAD_CAST("accelerator"));
+	xmlSetProp(node, BAD_CAST("key"), BAD_CAST(gdk_keyval_name(info->accels[i].key)));
+	xmlSetProp(node, BAD_CAST("modifiers"), BAD_CAST(modifiers));
+	xmlSetProp(node, BAD_CAST("signal"), BAD_CAST(info->accels[i].signal));
+	xmlAddChild(widget, node);
+	xmlNodeAddContent(widget, BAD_CAST("\n"));
+
+	if (modifiers)
+	    g_free (modifiers);
+    }
+
+    for (i = 0; i < info->n_children; i++) {
+	xmlNode *child, *packing;
+	GladeChildInfo *childinfo = &info->children[i];
+	gint k;
+
+	for (j = 0; j < indent + 1; j++)
+	    xmlNodeAddContent(widget, BAD_CAST("  "));
+
+	child = xmlNewNode(NULL, BAD_CAST("child"));
+	if (childinfo->internal_child)
+	    xmlSetProp(child, BAD_CAST("internal-child"), BAD_CAST(childinfo->internal_child));
+	xmlAddChild(widget, child);
+	xmlNodeAddContent(widget, BAD_CAST("\n"));
+	xmlNodeAddContent(child, BAD_CAST("\n"));
+
+	for (j = 0; j < indent + 2; j++)
+	    xmlNodeAddContent(child, BAD_CAST("  "));
+	dump_widget(child, childinfo->child, indent + 2);
+	xmlNodeAddContent(child, BAD_CAST("\n"));
+
+	if (childinfo->n_properties) {
+	    for (j = 0; j < indent + 2; j++)
+		xmlNodeAddContent(child, BAD_CAST("  "));
+	    packing = xmlNewNode(NULL, BAD_CAST("packing"));
+	    xmlAddChild(child, packing);
+	    xmlNodeAddContent(packing, BAD_CAST("\n"));
+
+	    for (k = 0; k < childinfo->n_properties; k++) { 
+		xmlNode *node;
+
+		for (j = 0; j < indent + 3; j++)
+		    xmlNodeAddContent(packing, BAD_CAST("  "));
+		node = xmlNewNode(NULL, BAD_CAST("property"));
+		xmlSetProp(node, BAD_CAST("name"), BAD_CAST(childinfo->properties[k].name));
+		if (childinfo->properties[k].translatable)
+		    xmlSetProp(node, BAD_CAST("translatable"), BAD_CAST("yes"));
+		if (childinfo->properties[k].has_context)
+		    xmlSetProp(node, BAD_CAST("context"), BAD_CAST("yes"));
+		if (childinfo->properties[k].comment)
+		    xmlSetProp(node, BAD_CAST("comments"), 
+			       BAD_CAST(childinfo->properties[k].comment));
+		xmlNodeSetContent(node, BAD_CAST(childinfo->properties[k].value));
+		xmlAddChild(packing, node);
+		xmlNodeAddContent(packing, BAD_CAST("\n"));
+	    }
+	}
+
+	if (childinfo->n_properties) {
+	    for (j = 0; j < indent + 2; j++)
+		xmlNodeAddContent(packing, BAD_CAST("  "));
+	    xmlNodeAddContent(child, BAD_CAST("\n"));
+	}
+
+	for (j = 0; j < indent + 1; j++)
+	    xmlNodeAddContent(child, BAD_CAST("  "));
+    }
+
+    for (j = 0; j < indent; j++)
+	xmlNodeAddContent(widget, BAD_CAST("  "));
+}
+
+static xmlDoc *
+glade_interface_make_doc (GladeInterface *interface)
+{
+    xmlDoc *doc;
+    xmlNode *root, *comment;
+    gint i;
+
+    doc = xmlNewDoc(BAD_CAST("1.0"));
+    doc->standalone = FALSE;
+
+    if (interface->comment)
+    {
+	comment = xmlNewComment(BAD_CAST (interface->comment));
+	xmlDocSetRootElement(doc, comment);
+    }
+	
+    root = xmlNewNode(NULL, BAD_CAST("interface"));
+    xmlDocSetRootElement(doc, root);
+
+    xmlNodeAddContent(root, BAD_CAST("\n"));
+
+    for (i = 0; i < interface->n_toplevels; i++) {
+	xmlNodeAddContent(root, BAD_CAST("  "));
+	dump_widget(root, interface->toplevels[i], 1);
+	xmlNodeAddContent(root, BAD_CAST("\n"));
+    }
+    return doc;
+}
+
+static void
+glade_interface_buffer (GladeInterface  *interface,
+			gpointer        *buffer,
+			gint            *size)
+{
+    xmlDoc *doc;
+    g_return_if_fail (interface != NULL);
+    g_return_if_fail (buffer    != NULL);
+    g_return_if_fail (size      != NULL);
+
+    doc = glade_interface_make_doc (interface);
+    xmlDocDumpFormatMemoryEnc(doc, (xmlChar **)buffer,
+			      size, "UTF-8",  TRUE);
+    xmlFreeDoc(doc);
+}
+
+/**
+ * glade_interface_dump_gtkbuilder
+ * @interface: the GladeInterface
+ * @filename: the filename to write the interface data to.
+ * @error: a #GError for error handleing.
+ *
+ * This function dumps the contents of a GladeInterface into a file as
+ * XML.  It is used by glade to write glade files.
+ *
+ * Returns whether the write was successfull or not.
+ */
+gboolean
+glade_interface_dump_gtkbuilder (GladeInterface *interface,
+			       const gchar *filename,
+			       GError **error)
+{
+	GIOChannel *fd;
+	gpointer buffer;
+	gint     size, retval = G_IO_STATUS_ERROR;
+
+	glade_interface_buffer (interface, &buffer, &size);
+	
+	if (buffer == NULL)
+	{
+		g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOMEM,
+			     _("Could not allocate memory for interface"));
+		return FALSE;
+	}
+	
+	if ((fd = g_io_channel_new_file (filename, "w", error)))
+	{
+		retval = g_io_channel_write_chars (fd, buffer, size, NULL, error);
+		g_io_channel_shutdown(fd, TRUE, NULL);
+		g_io_channel_unref (fd);
+	}
+	
+	xmlFree (buffer);
+	
+	return (retval == G_IO_STATUS_NORMAL) ? TRUE : FALSE;
+}
+
Index: gladeui/glade-format-gtkbuilder.h
===================================================================
--- gladeui/glade-format-gtkbuilder.h	(revision 0)
+++ gladeui/glade-format-gtkbuilder.h	(revision 0)
@@ -0,0 +1,36 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * Copyright (C) 2007  Johan Dahlin <johan@gnome.org>
+ *
+ * glade-format-gtkbuilder.h: functions for saving gtkbuilder files
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA  02111-1307, USA.
+ */
+
+#ifndef __GLADE_FORMAT_GTKBUILDER_H__
+#define __GLADE_FORMAT_GTKBUILDER_H__
+
+#include <glib.h>
+#include "glade-parser.h"
+
+G_BEGIN_DECLS
+
+gboolean glade_interface_dump_gtkbuilder (GladeInterface *interface,
+					  const gchar *filename,
+					  GError **error);
+
+G_END_DECLS
+
+#endif
Index: gladeui/glade-format-libglade.c
===================================================================
--- gladeui/glade-format-libglade.c	(revision 0)
+++ gladeui/glade-format-libglade.c	(revision 0)
@@ -0,0 +1,426 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ *
+ * glade-format-libglade.c: functions for saveing libglade files
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA  02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+#include <libxml/parser.h>
+
+#include "glade-parser.h"
+
+#include "glade-format-libglade.h"
+
+static gchar *
+modifier_string_from_bits (GdkModifierType modifiers)
+{
+    GString *string = g_string_new ("");
+
+    if (modifiers & GDK_SHIFT_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_SHIFT_MASK");
+    }
+
+    if (modifiers & GDK_LOCK_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_LOCK_MASK");
+    }
+
+    if (modifiers & GDK_CONTROL_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_CONTROL_MASK");
+    }
+
+    if (modifiers & GDK_MOD1_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_MOD1_MASK");
+    }
+
+    if (modifiers & GDK_MOD2_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_MOD2_MASK");
+    }
+
+    if (modifiers & GDK_MOD3_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_MOD3_MASK");
+    }
+
+    if (modifiers & GDK_MOD4_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_MOD4_MASK");
+    }
+
+    if (modifiers & GDK_MOD5_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_MOD5_MASK");
+    }
+
+    if (modifiers & GDK_BUTTON1_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_BUTTON1_MASK");
+    }
+
+    if (modifiers & GDK_BUTTON2_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_BUTTON2_MASK");
+    }
+
+    if (modifiers & GDK_BUTTON3_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_BUTTON3_MASK");
+    }
+
+    if (modifiers & GDK_BUTTON4_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_BUTTON4_MASK");
+    }
+
+    if (modifiers & GDK_BUTTON5_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_BUTTON5_MASK");
+    }
+
+    if (modifiers & GDK_RELEASE_MASK) {
+	if (string->len > 0)
+	    g_string_append (string, " | ");
+	g_string_append (string, "GDK_RELEASE_MASK");
+    }
+
+    if (string->len > 0)
+	return g_string_free (string, FALSE);
+
+    g_string_free (string, TRUE);
+    return NULL;
+}
+
+static void
+dump_widget(xmlNode *parent, GladeWidgetInfo *info, gint indent)
+{
+    xmlNode *widget;
+    gint i, j;
+
+    if (info == NULL) {
+	widget = xmlNewNode(NULL, BAD_CAST("placeholder"));
+	xmlAddChild(parent, widget);
+	return;
+    }
+
+    widget = xmlNewNode(NULL, BAD_CAST("widget"));
+
+    xmlSetProp(widget, BAD_CAST("class"), BAD_CAST(info->classname));
+    xmlSetProp(widget, BAD_CAST("id"), BAD_CAST(info->name));
+    xmlAddChild(parent, widget);
+    xmlNodeAddContent(widget, BAD_CAST("\n"));
+
+    for (i = 0; i < info->n_properties; i++) { 
+	xmlNode *node;
+
+	for (j = 0; j < indent + 1; j++)
+	    xmlNodeAddContent(widget, BAD_CAST("  "));
+	node = xmlNewNode(NULL, BAD_CAST("property"));
+	xmlSetProp(node, BAD_CAST("name"), BAD_CAST(info->properties[i].name));
+	if (info->properties[i].translatable)
+	    xmlSetProp(node, BAD_CAST("translatable"), BAD_CAST("yes"));
+	if (info->properties[i].has_context)
+	    xmlSetProp(node, BAD_CAST("context"), BAD_CAST("yes"));
+	if (info->properties[i].comment)
+	    xmlSetProp(node, BAD_CAST("comments"), 
+		       BAD_CAST(info->properties[i].comment));
+	xmlNodeSetContent(node, BAD_CAST(info->properties[i].value));
+	xmlAddChild(widget, node);
+	xmlNodeAddContent(widget, BAD_CAST("\n"));
+    }
+
+    if (info->n_atk_props   != 0 ||
+	info->n_atk_actions != 0 ||
+	info->n_relations   != 0) {
+	xmlNode *atk;
+
+	for (j = 0; j < indent + 1; j++)
+	    xmlNodeAddContent(widget, BAD_CAST("  "));
+	atk = xmlNewNode(NULL, BAD_CAST("accessibility"));
+	xmlAddChild(widget, atk);
+	xmlNodeAddContent(widget, BAD_CAST("\n"));
+	xmlNodeAddContent(atk, BAD_CAST("\n"));
+
+	for (i = 0; i < info->n_atk_props; i++) {
+	    xmlNode *node;
+
+	    for (j = 0; j < indent + 2; j++)
+		xmlNodeAddContent(atk, BAD_CAST("  "));
+	    node = xmlNewNode(NULL, BAD_CAST("atkproperty"));
+	    xmlSetProp(node, BAD_CAST("name"), BAD_CAST(info->atk_props[i].name));
+	    if (info->atk_props[i].translatable)
+		xmlSetProp(node, BAD_CAST("translatable"), BAD_CAST("yes"));
+	    if (info->atk_props[i].has_context)
+		xmlSetProp(node, BAD_CAST("context"), BAD_CAST("yes"));
+	    if (info->atk_props[i].comment)
+		xmlSetProp(node, BAD_CAST("comments"), 
+			   BAD_CAST(info->atk_props[i].comment));
+	    xmlNodeSetContent(node, BAD_CAST(info->atk_props[i].value));
+	    xmlAddChild(atk, node);
+	    xmlNodeAddContent(atk, BAD_CAST("\n"));
+	}
+
+	for (i = 0; i < info->n_atk_actions; i++) {
+	    xmlNode *node;
+
+	    for (j = 0; j < indent + 2; j++)
+		xmlNodeAddContent(atk, BAD_CAST("  "));
+	    node = xmlNewNode(NULL, BAD_CAST("atkaction"));
+	    xmlSetProp(node, BAD_CAST("action_name"), 
+		       BAD_CAST(info->atk_actions[i].action_name));
+	    xmlSetProp(node, BAD_CAST("description"), 
+		       BAD_CAST(info->atk_actions[i].description));
+	    xmlAddChild(atk, node);
+	    xmlNodeAddContent(atk, BAD_CAST("\n"));
+	}
+
+	for (i = 0; i < info->n_relations; i++) {
+	    xmlNode *node;
+
+	    for (j = 0; j < indent + 2; j++)
+		xmlNodeAddContent(atk, BAD_CAST("  "));
+	    node = xmlNewNode(NULL, BAD_CAST("atkrelation"));
+	    xmlSetProp(node, BAD_CAST("target"), 
+		       BAD_CAST(info->relations[i].target));
+	    xmlSetProp(node, BAD_CAST("type"), 
+		       BAD_CAST(info->relations[i].type));
+	    xmlAddChild(atk, node);
+	    xmlNodeAddContent(atk, BAD_CAST("\n"));
+	}
+
+	for (j = 0; j < indent + 1; j++)
+	    xmlNodeAddContent(atk, BAD_CAST("  "));
+    }
+
+    for (i = 0; i < info->n_signals; i++) {
+	xmlNode *node;
+
+	for (j = 0; j < indent + 1; j++)
+	    xmlNodeAddContent(widget, BAD_CAST("  "));
+
+	node = xmlNewNode(NULL, BAD_CAST("signal"));
+	xmlSetProp(node, BAD_CAST("name"), BAD_CAST(info->signals[i].name));
+	xmlSetProp(node, BAD_CAST("handler"), BAD_CAST(info->signals[i].handler));
+	if (info->signals[i].after)
+	    xmlSetProp(node, BAD_CAST("after"), BAD_CAST("yes"));
+	if (info->signals[i].lookup)
+	    xmlSetProp(node, BAD_CAST("lookup"), BAD_CAST("yes"));
+	if (info->signals[i].object)
+	    xmlSetProp(node, BAD_CAST("object"), BAD_CAST(info->signals[i].object));
+	xmlAddChild(widget, node);
+	xmlNodeAddContent(widget, BAD_CAST("\n"));
+    }
+
+    for (i = 0; i < info->n_accels; i++) {
+	xmlNode *node;
+	gchar   *modifiers;
+
+	modifiers = modifier_string_from_bits (info->accels[i].modifiers);
+
+	for (j = 0; j < indent + 1; j++)
+	    xmlNodeAddContent(widget, BAD_CAST("  "));
+
+	node = xmlNewNode(NULL, BAD_CAST("accelerator"));
+	xmlSetProp(node, BAD_CAST("key"), BAD_CAST(gdk_keyval_name(info->accels[i].key)));
+	xmlSetProp(node, BAD_CAST("modifiers"), BAD_CAST(modifiers));
+	xmlSetProp(node, BAD_CAST("signal"), BAD_CAST(info->accels[i].signal));
+	xmlAddChild(widget, node);
+	xmlNodeAddContent(widget, BAD_CAST("\n"));
+
+	if (modifiers)
+	    g_free (modifiers);
+    }
+
+    for (i = 0; i < info->n_children; i++) {
+	xmlNode *child, *packing;
+	GladeChildInfo *childinfo = &info->children[i];
+	gint k;
+
+	for (j = 0; j < indent + 1; j++)
+	    xmlNodeAddContent(widget, BAD_CAST("  "));
+
+	child = xmlNewNode(NULL, BAD_CAST("child"));
+	if (childinfo->internal_child)
+	    xmlSetProp(child, BAD_CAST("internal-child"), BAD_CAST(childinfo->internal_child));
+	xmlAddChild(widget, child);
+	xmlNodeAddContent(widget, BAD_CAST("\n"));
+	xmlNodeAddContent(child, BAD_CAST("\n"));
+
+	for (j = 0; j < indent + 2; j++)
+	    xmlNodeAddContent(child, BAD_CAST("  "));
+	dump_widget(child, childinfo->child, indent + 2);
+	xmlNodeAddContent(child, BAD_CAST("\n"));
+
+	if (childinfo->n_properties) {
+	    for (j = 0; j < indent + 2; j++)
+		xmlNodeAddContent(child, BAD_CAST("  "));
+	    packing = xmlNewNode(NULL, BAD_CAST("packing"));
+	    xmlAddChild(child, packing);
+	    xmlNodeAddContent(packing, BAD_CAST("\n"));
+
+	    for (k = 0; k < childinfo->n_properties; k++) { 
+		xmlNode *node;
+
+		for (j = 0; j < indent + 3; j++)
+		    xmlNodeAddContent(packing, BAD_CAST("  "));
+		node = xmlNewNode(NULL, BAD_CAST("property"));
+		xmlSetProp(node, BAD_CAST("name"), BAD_CAST(childinfo->properties[k].name));
+		if (childinfo->properties[k].translatable)
+		    xmlSetProp(node, BAD_CAST("translatable"), BAD_CAST("yes"));
+		if (childinfo->properties[k].has_context)
+		    xmlSetProp(node, BAD_CAST("context"), BAD_CAST("yes"));
+		if (childinfo->properties[k].comment)
+		    xmlSetProp(node, BAD_CAST("comments"), 
+			       BAD_CAST(childinfo->properties[k].comment));
+		xmlNodeSetContent(node, BAD_CAST(childinfo->properties[k].value));
+		xmlAddChild(packing, node);
+		xmlNodeAddContent(packing, BAD_CAST("\n"));
+	    }
+	}
+
+	if (childinfo->n_properties) {
+	    for (j = 0; j < indent + 2; j++)
+		xmlNodeAddContent(packing, BAD_CAST("  "));
+	    xmlNodeAddContent(child, BAD_CAST("\n"));
+	}
+
+	for (j = 0; j < indent + 1; j++)
+	    xmlNodeAddContent(child, BAD_CAST("  "));
+    }
+
+    for (j = 0; j < indent; j++)
+	xmlNodeAddContent(widget, BAD_CAST("  "));
+}
+
+static xmlDoc *
+glade_interface_make_doc (GladeInterface *interface)
+{
+    xmlDoc *doc;
+    xmlNode *root, *comment;
+    gint i;
+
+    doc = xmlNewDoc(BAD_CAST("1.0"));
+    doc->standalone = FALSE;
+    xmlCreateIntSubset(doc, BAD_CAST("glade-interface"),
+		       NULL, BAD_CAST("glade-2.0.dtd"));
+
+    if (interface->comment)
+    {
+	comment = xmlNewComment(BAD_CAST (interface->comment));
+	xmlDocSetRootElement(doc, comment);
+    }
+	
+    root = xmlNewNode(NULL, BAD_CAST("glade-interface"));
+    xmlDocSetRootElement(doc, root);
+
+    xmlNodeAddContent(root, BAD_CAST("\n"));
+
+    for (i = 0; i < interface->n_requires; i++) {
+	xmlNode *node = xmlNewNode(NULL, BAD_CAST("requires"));
+
+	xmlSetProp(node, BAD_CAST("lib"), BAD_CAST(interface->requires[i]));
+
+	xmlNodeAddContent(root, BAD_CAST("  "));
+	xmlAddChild(root, node);
+	xmlNodeAddContent(root, BAD_CAST("\n"));
+    }
+
+    for (i = 0; i < interface->n_toplevels; i++) {
+	xmlNodeAddContent(root, BAD_CAST("  "));
+	dump_widget(root, interface->toplevels[i], 1);
+	xmlNodeAddContent(root, BAD_CAST("\n"));
+    }
+    return doc;
+}
+
+static void
+glade_interface_buffer (GladeInterface  *interface,
+			gpointer        *buffer,
+			gint            *size)
+{
+    xmlDoc *doc;
+    g_return_if_fail (interface != NULL);
+    g_return_if_fail (buffer    != NULL);
+    g_return_if_fail (size      != NULL);
+
+    doc = glade_interface_make_doc (interface);
+    xmlDocDumpFormatMemoryEnc(doc, (xmlChar **)buffer,
+			      size, "UTF-8",  TRUE);
+    xmlFreeDoc(doc);
+}
+
+/**
+ * glade_interface_dump_libglade
+ * @interface: the GladeInterface
+ * @filename: the filename to write the interface data to.
+ * @error: a #GError for error handleing.
+ *
+ * This function dumps the contents of a GladeInterface into a file as
+ * XML.  It is used by glade to write glade files.
+ *
+ * Returns whether the write was successfull or not.
+ */
+gboolean
+glade_interface_dump_libglade (GladeInterface *interface,
+			       const gchar *filename,
+			       GError **error)
+{
+	GIOChannel *fd;
+	gpointer buffer;
+	gint     size, retval = G_IO_STATUS_ERROR;
+
+	glade_interface_buffer (interface, &buffer, &size);
+	
+	if (buffer == NULL)
+	{
+		g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOMEM,
+			     _("Could not allocate memory for interface"));
+		return FALSE;
+	}
+	
+	if ((fd = g_io_channel_new_file (filename, "w", error)))
+	{
+		retval = g_io_channel_write_chars (fd, buffer, size, NULL, error);
+		g_io_channel_shutdown(fd, TRUE, NULL);
+		g_io_channel_unref (fd);
+	}
+	
+	xmlFree (buffer);
+	
+	return (retval == G_IO_STATUS_NORMAL) ? TRUE : FALSE;
+}
+
Index: gladeui/glade-format-libglade.h
===================================================================
--- gladeui/glade-format-libglade.h	(revision 0)
+++ gladeui/glade-format-libglade.h	(revision 0)
@@ -0,0 +1,36 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * Copyright (C) 2007  Johan Dahlin <johan@gnome.org>
+ *
+ * glade-format-libglade.h: headers for saving libglade files
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the 
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA  02111-1307, USA.
+ */
+
+#ifndef __GLADE_FORMAT_LIBGLADE_H__
+#define __GLADE_FORMAT_LIBGLADE_H__
+
+#include <glib.h>
+#include "glade-parser.h"
+
+G_BEGIN_DECLS
+
+gboolean glade_interface_dump_libglade (GladeInterface *interface,
+					const gchar *filename,
+					GError **error);
+
+G_END_DECLS
+
+#endif
Index: gladeui/glade-parser.c
===================================================================
--- gladeui/glade-parser.c	(revision 1639)
+++ gladeui/glade-parser.c	(working copy)
@@ -1276,401 +1276,6 @@
     return state.interface;
 }
 
-static gchar *
-modifier_string_from_bits (GdkModifierType modifiers)
-{
-    GString *string = g_string_new ("");
-
-    if (modifiers & GDK_SHIFT_MASK) {
-	if (string->len > 0)
-	    g_string_append (string, " | ");
-	g_string_append (string, "GDK_SHIFT_MASK");
-    }
-
-    if (modifiers & GDK_LOCK_MASK) {
-	if (string->len > 0)
-	    g_string_append (string, " | ");
-	g_string_append (string, "GDK_LOCK_MASK");
-    }
-
-    if (modifiers & GDK_CONTROL_MASK) {
-	if (string->len > 0)
-	    g_string_append (string, " | ");
-	g_string_append (string, "GDK_CONTROL_MASK");
-    }
-
-    if (modifiers & GDK_MOD1_MASK) {
-	if (string->len > 0)
-	    g_string_append (string, " | ");
-	g_string_append (string, "GDK_MOD1_MASK");
-    }
-
-    if (modifiers & GDK_MOD2_MASK) {
-	if (string->len > 0)
-	    g_string_append (string, " | ");
-	g_string_append (string, "GDK_MOD2_MASK");
-    }
-
-    if (modifiers & GDK_MOD3_MASK) {
-	if (string->len > 0)
-	    g_string_append (string, " | ");
-	g_string_append (string, "GDK_MOD3_MASK");
-    }
-
-    if (modifiers & GDK_MOD4_MASK) {
-	if (string->len > 0)
-	    g_string_append (string, " | ");
-	g_string_append (string, "GDK_MOD4_MASK");
-    }
-
-    if (modifiers & GDK_MOD5_MASK) {
-	if (string->len > 0)
-	    g_string_append (string, " | ");
-	g_string_append (string, "GDK_MOD5_MASK");
-    }
-
-    if (modifiers & GDK_BUTTON1_MASK) {
-	if (string->len > 0)
-	    g_string_append (string, " | ");
-	g_string_append (string, "GDK_BUTTON1_MASK");
-    }
-
-    if (modifiers & GDK_BUTTON2_MASK) {
-	if (string->len > 0)
-	    g_string_append (string, " | ");
-	g_string_append (string, "GDK_BUTTON2_MASK");
-    }
-
-    if (modifiers & GDK_BUTTON3_MASK) {
-	if (string->len > 0)
-	    g_string_append (string, " | ");
-	g_string_append (string, "GDK_BUTTON3_MASK");
-    }
-
-    if (modifiers & GDK_BUTTON4_MASK) {
-	if (string->len > 0)
-	    g_string_append (string, " | ");
-	g_string_append (string, "GDK_BUTTON4_MASK");
-    }
-
-    if (modifiers & GDK_BUTTON5_MASK) {
-	if (string->len > 0)
-	    g_string_append (string, " | ");
-	g_string_append (string, "GDK_BUTTON5_MASK");
-    }
-
-    if (modifiers & GDK_RELEASE_MASK) {
-	if (string->len > 0)
-	    g_string_append (string, " | ");
-	g_string_append (string, "GDK_RELEASE_MASK");
-    }
-
-    if (string->len > 0)
-	return g_string_free (string, FALSE);
-
-    g_string_free (string, TRUE);
-    return NULL;
-}
-
-static void
-dump_widget(xmlNode *parent, GladeWidgetInfo *info, gint indent)
-{
-    xmlNode *widget;
-    gint i, j;
-
-    if (info == NULL) {
-	widget = xmlNewNode(NULL, BAD_CAST("placeholder"));
-	xmlAddChild(parent, widget);
-	return;
-    }
-
-    widget = xmlNewNode(NULL, BAD_CAST("widget"));
-
-    xmlSetProp(widget, BAD_CAST("class"), BAD_CAST(info->classname));
-    xmlSetProp(widget, BAD_CAST("id"), BAD_CAST(info->name));
-    xmlAddChild(parent, widget);
-    xmlNodeAddContent(widget, BAD_CAST("\n"));
-
-    for (i = 0; i < info->n_properties; i++) { 
-	xmlNode *node;
-
-	for (j = 0; j < indent + 1; j++)
-	    xmlNodeAddContent(widget, BAD_CAST("  "));
-	node = xmlNewNode(NULL, BAD_CAST("property"));
-	xmlSetProp(node, BAD_CAST("name"), BAD_CAST(info->properties[i].name));
-	if (info->properties[i].translatable)
-	    xmlSetProp(node, BAD_CAST("translatable"), BAD_CAST("yes"));
-	if (info->properties[i].has_context)
-	    xmlSetProp(node, BAD_CAST("context"), BAD_CAST("yes"));
-	if (info->properties[i].comment)
-	    xmlSetProp(node, BAD_CAST("comments"), 
-		       BAD_CAST(info->properties[i].comment));
-	xmlNodeSetContent(node, BAD_CAST(info->properties[i].value));
-	xmlAddChild(widget, node);
-	xmlNodeAddContent(widget, BAD_CAST("\n"));
-    }
-
-    if (info->n_atk_props   != 0 ||
-	info->n_atk_actions != 0 ||
-	info->n_relations   != 0) {
-	xmlNode *atk;
-
-	for (j = 0; j < indent + 1; j++)
-	    xmlNodeAddContent(widget, BAD_CAST("  "));
-	atk = xmlNewNode(NULL, BAD_CAST("accessibility"));
-	xmlAddChild(widget, atk);
-	xmlNodeAddContent(widget, BAD_CAST("\n"));
-	xmlNodeAddContent(atk, BAD_CAST("\n"));
-
-	for (i = 0; i < info->n_atk_props; i++) {
-	    xmlNode *node;
-
-	    for (j = 0; j < indent + 2; j++)
-		xmlNodeAddContent(atk, BAD_CAST("  "));
-	    node = xmlNewNode(NULL, BAD_CAST("atkproperty"));
-	    xmlSetProp(node, BAD_CAST("name"), BAD_CAST(info->atk_props[i].name));
-	    if (info->atk_props[i].translatable)
-		xmlSetProp(node, BAD_CAST("translatable"), BAD_CAST("yes"));
-	    if (info->atk_props[i].has_context)
-		xmlSetProp(node, BAD_CAST("context"), BAD_CAST("yes"));
-	    if (info->atk_props[i].comment)
-		xmlSetProp(node, BAD_CAST("comments"), 
-			   BAD_CAST(info->atk_props[i].comment));
-	    xmlNodeSetContent(node, BAD_CAST(info->atk_props[i].value));
-	    xmlAddChild(atk, node);
-	    xmlNodeAddContent(atk, BAD_CAST("\n"));
-	}
-
-	for (i = 0; i < info->n_atk_actions; i++) {
-	    xmlNode *node;
-
-	    for (j = 0; j < indent + 2; j++)
-		xmlNodeAddContent(atk, BAD_CAST("  "));
-	    node = xmlNewNode(NULL, BAD_CAST("atkaction"));
-	    xmlSetProp(node, BAD_CAST("action_name"), 
-		       BAD_CAST(info->atk_actions[i].action_name));
-	    xmlSetProp(node, BAD_CAST("description"), 
-		       BAD_CAST(info->atk_actions[i].description));
-	    xmlAddChild(atk, node);
-	    xmlNodeAddContent(atk, BAD_CAST("\n"));
-	}
-
-	for (i = 0; i < info->n_relations; i++) {
-	    xmlNode *node;
-
-	    for (j = 0; j < indent + 2; j++)
-		xmlNodeAddContent(atk, BAD_CAST("  "));
-	    node = xmlNewNode(NULL, BAD_CAST("atkrelation"));
-	    xmlSetProp(node, BAD_CAST("target"), 
-		       BAD_CAST(info->relations[i].target));
-	    xmlSetProp(node, BAD_CAST("type"), 
-		       BAD_CAST(info->relations[i].type));
-	    xmlAddChild(atk, node);
-	    xmlNodeAddContent(atk, BAD_CAST("\n"));
-	}
-
-	for (j = 0; j < indent + 1; j++)
-	    xmlNodeAddContent(atk, BAD_CAST("  "));
-    }
-
-    for (i = 0; i < info->n_signals; i++) {
-	xmlNode *node;
-
-	for (j = 0; j < indent + 1; j++)
-	    xmlNodeAddContent(widget, BAD_CAST("  "));
-
-	node = xmlNewNode(NULL, BAD_CAST("signal"));
-	xmlSetProp(node, BAD_CAST("name"), BAD_CAST(info->signals[i].name));
-	xmlSetProp(node, BAD_CAST("handler"), BAD_CAST(info->signals[i].handler));
-	if (info->signals[i].after)
-	    xmlSetProp(node, BAD_CAST("after"), BAD_CAST("yes"));
-	if (info->signals[i].lookup)
-	    xmlSetProp(node, BAD_CAST("lookup"), BAD_CAST("yes"));
-	if (info->signals[i].object)
-	    xmlSetProp(node, BAD_CAST("object"), BAD_CAST(info->signals[i].object));
-	xmlAddChild(widget, node);
-	xmlNodeAddContent(widget, BAD_CAST("\n"));
-    }
-
-    for (i = 0; i < info->n_accels; i++) {
-	xmlNode *node;
-	gchar   *modifiers;
-
-	modifiers = modifier_string_from_bits (info->accels[i].modifiers);
-
-	for (j = 0; j < indent + 1; j++)
-	    xmlNodeAddContent(widget, BAD_CAST("  "));
-
-	node = xmlNewNode(NULL, BAD_CAST("accelerator"));
-	xmlSetProp(node, BAD_CAST("key"), BAD_CAST(gdk_keyval_name(info->accels[i].key)));
-	xmlSetProp(node, BAD_CAST("modifiers"), BAD_CAST(modifiers));
-	xmlSetProp(node, BAD_CAST("signal"), BAD_CAST(info->accels[i].signal));
-	xmlAddChild(widget, node);
-	xmlNodeAddContent(widget, BAD_CAST("\n"));
-
-	if (modifiers)
-	    g_free (modifiers);
-    }
-
-    for (i = 0; i < info->n_children; i++) {
-	xmlNode *child, *packing;
-	GladeChildInfo *childinfo = &info->children[i];
-	gint k;
-
-	for (j = 0; j < indent + 1; j++)
-	    xmlNodeAddContent(widget, BAD_CAST("  "));
-
-	child = xmlNewNode(NULL, BAD_CAST("child"));
-	if (childinfo->internal_child)
-	    xmlSetProp(child, BAD_CAST("internal-child"), BAD_CAST(childinfo->internal_child));
-	xmlAddChild(widget, child);
-	xmlNodeAddContent(widget, BAD_CAST("\n"));
-	xmlNodeAddContent(child, BAD_CAST("\n"));
-
-	for (j = 0; j < indent + 2; j++)
-	    xmlNodeAddContent(child, BAD_CAST("  "));
-	dump_widget(child, childinfo->child, indent + 2);
-	xmlNodeAddContent(child, BAD_CAST("\n"));
-
-	if (childinfo->n_properties) {
-	    for (j = 0; j < indent + 2; j++)
-		xmlNodeAddContent(child, BAD_CAST("  "));
-	    packing = xmlNewNode(NULL, BAD_CAST("packing"));
-	    xmlAddChild(child, packing);
-	    xmlNodeAddContent(packing, BAD_CAST("\n"));
-
-	    for (k = 0; k < childinfo->n_properties; k++) { 
-		xmlNode *node;
-
-		for (j = 0; j < indent + 3; j++)
-		    xmlNodeAddContent(packing, BAD_CAST("  "));
-		node = xmlNewNode(NULL, BAD_CAST("property"));
-		xmlSetProp(node, BAD_CAST("name"), BAD_CAST(childinfo->properties[k].name));
-		if (childinfo->properties[k].translatable)
-		    xmlSetProp(node, BAD_CAST("translatable"), BAD_CAST("yes"));
-		if (childinfo->properties[k].has_context)
-		    xmlSetProp(node, BAD_CAST("context"), BAD_CAST("yes"));
-		if (childinfo->properties[k].comment)
-		    xmlSetProp(node, BAD_CAST("comments"), 
-			       BAD_CAST(childinfo->properties[k].comment));
-		xmlNodeSetContent(node, BAD_CAST(childinfo->properties[k].value));
-		xmlAddChild(packing, node);
-		xmlNodeAddContent(packing, BAD_CAST("\n"));
-	    }
-	}
-
-	if (childinfo->n_properties) {
-	    for (j = 0; j < indent + 2; j++)
-		xmlNodeAddContent(packing, BAD_CAST("  "));
-	    xmlNodeAddContent(child, BAD_CAST("\n"));
-	}
-
-	for (j = 0; j < indent + 1; j++)
-	    xmlNodeAddContent(child, BAD_CAST("  "));
-    }
-
-    for (j = 0; j < indent; j++)
-	xmlNodeAddContent(widget, BAD_CAST("  "));
-}
-
-static xmlDoc *
-glade_interface_make_doc (GladeInterface *interface)
-{
-    xmlDoc *doc;
-    xmlNode *root, *comment;
-    gint i;
-
-    doc = xmlNewDoc(BAD_CAST("1.0"));
-    doc->standalone = FALSE;
-    xmlCreateIntSubset(doc, BAD_CAST("glade-interface"),
-		       NULL, BAD_CAST("glade-2.0.dtd"));
-
-    if (interface->comment)
-    {
-	comment = xmlNewComment(BAD_CAST (interface->comment));
-	xmlDocSetRootElement(doc, comment);
-    }
-	
-    root = xmlNewNode(NULL, BAD_CAST("glade-interface"));
-    xmlDocSetRootElement(doc, root);
-
-    xmlNodeAddContent(root, BAD_CAST("\n"));
-
-    for (i = 0; i < interface->n_requires; i++) {
-	xmlNode *node = xmlNewNode(NULL, BAD_CAST("requires"));
-
-	xmlSetProp(node, BAD_CAST("lib"), BAD_CAST(interface->requires[i]));
-
-	xmlNodeAddContent(root, BAD_CAST("  "));
-	xmlAddChild(root, node);
-	xmlNodeAddContent(root, BAD_CAST("\n"));
-    }
-
-    for (i = 0; i < interface->n_toplevels; i++) {
-	xmlNodeAddContent(root, BAD_CAST("  "));
-	dump_widget(root, interface->toplevels[i], 1);
-	xmlNodeAddContent(root, BAD_CAST("\n"));
-    }
-    return doc;
-}
-
-static void
-glade_interface_buffer (GladeInterface  *interface,
-			gpointer        *buffer,
-			gint            *size)
-{
-    xmlDoc *doc;
-    g_return_if_fail (interface != NULL);
-    g_return_if_fail (buffer    != NULL);
-    g_return_if_fail (size      != NULL);
-
-    doc = glade_interface_make_doc (interface);
-    xmlDocDumpFormatMemoryEnc(doc, (xmlChar **)buffer,
-			      size, "UTF-8",  TRUE);
-    xmlFreeDoc(doc);
-}
-
-/**
- * glade_parser_interface_dump
- * @interface: the GladeInterface
- * @filename: the filename to write the interface data to.
- * @error: a #GError for error handleing.
- *
- * This function dumps the contents of a GladeInterface into a file as
- * XML.  It is used by glade to write glade files.
- *
- * Returns whether the write was successfull or not.
- */
-gboolean
-glade_parser_interface_dump (GladeInterface *interface,
-			     const gchar *filename,
-			     GError **error)
-{
-	GIOChannel *fd;
-	gpointer buffer;
-	gint     size, retval = G_IO_STATUS_ERROR;
-
-	glade_interface_buffer (interface, &buffer, &size);
-	
-	if (buffer == NULL)
-	{
-		g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOMEM,
-			     _("Could not allocate memory for interface"));
-		return FALSE;
-	}
-	
-	if ((fd = g_io_channel_new_file (filename, "w", error)))
-	{
-		retval = g_io_channel_write_chars (fd, buffer, size, NULL, error);
-		g_io_channel_shutdown(fd, TRUE, NULL);
-		g_io_channel_unref (fd);
-	}
-	
-	xmlFree (buffer);
-	
-	return (retval == G_IO_STATUS_NORMAL) ? TRUE : FALSE;
-}
-
 G_CONST_RETURN gchar *
 glade_parser_pvalue_from_winfo (GladeWidgetInfo *winfo,
 				const gchar     *pname)
Index: gladeui/glade-parser.h
===================================================================
--- gladeui/glade-parser.h	(revision 1639)
+++ gladeui/glade-parser.h	(working copy)
@@ -140,10 +140,6 @@
 
 void            glade_parser_interface_destroy   (GladeInterface  *interface);
 
-gboolean        glade_parser_interface_dump (GladeInterface  *interface, 
-					     const gchar     *filename,
-					     GError         **error);
-
 G_CONST_RETURN gchar *glade_parser_pvalue_from_winfo (GladeWidgetInfo *winfo,
 						      const gchar     *pname);
 
Index: gladeui/glade-project.c
===================================================================
--- gladeui/glade-project.c	(revision 1639)
+++ gladeui/glade-project.c	(working copy)
@@ -43,6 +43,8 @@
 #include "glade-app.h"
 #include "glade-marshallers.h"
 #include "glade-catalog.h"
+#include "glade-format-gtkbuilder.h"
+#include "glade-format-libglade.h"
 
 #include "glade-project.h"
 
@@ -122,6 +124,8 @@
 			        */
 			 
 	time_t  mtime;         /* last UTC modification time of file, or 0 if it could not be read */
+
+	GladeFileFormatType file_format;
 };
 
 
@@ -496,7 +500,8 @@
 						 g_direct_equal, 
 						 NULL, g_free);
 
-	priv->unsaved_number = glade_id_allocator_allocate (get_unsaved_number_allocator ());	
+	priv->unsaved_number = glade_id_allocator_allocate (get_unsaved_number_allocator ());
+	priv->file_format = GLADE_FILE_FORMAT_LIBGLADE;
 }
 
 static void
@@ -1748,12 +1753,14 @@
  * Returns: %TRUE on success, %FALSE on failure
  */
 gboolean
-glade_project_save (GladeProject *project, const gchar *path, GError **error)
+glade_project_save (GladeProject *project, const gchar *path,
+		    GError **error)
 {
 	GladeInterface *interface;
 	gboolean        ret;
 	gchar          *canonical_path;
-
+	GladeFileFormatType file_format;
+	
 	g_return_val_if_fail (GLADE_IS_PROJECT (project), FALSE);
 	g_return_val_if_fail (path != NULL, FALSE);
 
@@ -1764,7 +1771,15 @@
 		return FALSE;
 	}
 
-	ret = glade_parser_interface_dump (interface, path, error);
+	file_format = glade_project_get_file_format (project);
+	
+	if (file_format == GLADE_FILE_FORMAT_LIBGLADE)
+		ret = glade_interface_dump_libglade (interface, path, error);
+	else if (file_format == GLADE_FILE_FORMAT_GTKBUILDER)
+		ret = glade_interface_dump_gtkbuilder (interface, path, error);
+	else
+		g_assert_not_reached ();
+
 	glade_parser_interface_destroy (interface);
 
 	canonical_path = glade_util_canonical_path (path);
@@ -2320,3 +2335,18 @@
 	return project->priv->modified;
 }
 
+void
+glade_project_set_file_format (GladeProject *project, GladeFileFormatType file_format)
+{
+	g_return_if_fail (GLADE_IS_PROJECT (project));
+
+	project->priv->file_format = file_format; 
+}
+
+GladeFileFormatType
+glade_project_get_file_format (GladeProject *project)
+{
+	g_return_val_if_fail (GLADE_IS_PROJECT (project), -1);
+
+	return project->priv->file_format;
+}
Index: gladeui/glade-project.h
===================================================================
--- gladeui/glade-project.h	(revision 1639)
+++ gladeui/glade-project.h	(working copy)
@@ -4,6 +4,7 @@
 
 #include <gladeui/glade-widget.h>
 #include <gladeui/glade-command.h>
+#include <gladeui/glade-utils.h>
 
 G_BEGIN_DECLS
 
@@ -68,7 +69,7 @@
 gboolean       glade_project_save                (GladeProject *project, 
 						  const gchar   *path, 
 						  GError       **error);
-						 
+
 const gchar   *glade_project_get_path            (GladeProject *project);						 
 
 gchar         *glade_project_get_name            (GladeProject *project);
@@ -160,6 +161,10 @@
 
 gboolean       glade_project_get_modified         (GladeProject *project);
 
+void           glade_project_set_file_format      (GladeProject *project, GladeFileFormatType file_format);
+
+GladeFileFormatType glade_project_get_file_format (GladeProject *project);
+
 G_END_DECLS
 
 #endif /* __GLADE_PROJECT_H__ */
Index: gladeui/glade-utils.c
===================================================================
--- gladeui/glade-utils.c	(revision 1639)
+++ gladeui/glade-utils.c	(working copy)
@@ -527,6 +527,8 @@
 {
 	GtkWidget *file_dialog;
 	GtkFileFilter *file_filter;
+	GtkWidget *frame, *vbox;
+	GtkWidget *radio1, *radio2;
 
 	g_return_val_if_fail ((action == GLADE_FILE_DIALOG_ACTION_OPEN ||
 			       action == GLADE_FILE_DIALOG_ACTION_SAVE), NULL);
@@ -551,12 +553,65 @@
 
 	gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (file_dialog), file_filter);
 
+	file_filter = gtk_file_filter_new ();
+	gtk_file_filter_add_pattern (file_filter, "*.ui");
+	gtk_file_filter_set_name (file_filter, _("GtkBuilder Files"));
+	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (file_dialog), file_filter);
+
 	gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (file_dialog), TRUE);
 	gtk_dialog_set_default_response (GTK_DIALOG (file_dialog), GTK_RESPONSE_OK);
 
+	if (action == GLADE_FILE_DIALOG_ACTION_SAVE)
+	{
+		frame = gtk_frame_new (_("File format:"));
+		gtk_widget_show (frame);
+		
+		vbox = gtk_vbox_new (FALSE, 0);
+		gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+		gtk_container_add (GTK_CONTAINER (frame), vbox);
+		gtk_widget_show (vbox);
+			
+		radio1 = gtk_radio_button_new_with_label (NULL, _("Libglade format"));
+		gtk_box_pack_start (GTK_BOX (vbox), radio1, FALSE, FALSE, 6);
+		gtk_widget_show (radio1);
+		
+		radio2 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (radio1),
+								      _("GtkBuilder format"));
+		gtk_box_pack_start (GTK_BOX (vbox), radio2, FALSE, FALSE, 6);
+		gtk_widget_show (radio2);
+		
+		gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (file_dialog), frame);
+
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio2), TRUE);
+		
+		g_object_set_data (G_OBJECT (file_dialog), "libglade-radio", radio1);
+		g_object_set_data (G_OBJECT (file_dialog), "gtkbuilder-radio", radio2);
+	}
+	
 	return file_dialog;
 }
 
+GladeFileFormatType
+glade_util_file_dialog_get_file_format (GtkFileChooser *file_chooser)
+{
+	gpointer libglade_radio, gtkbuilder_radio;
+	
+	libglade_radio = g_object_get_data (file_chooser, "libglade-radio");
+	g_return_val_if_fail (libglade_radio != NULL, -1);
+	g_return_val_if_fail (GTK_IS_RADIO_BUTTON (libglade_radio), -1);
+	gtkbuilder_radio = g_object_get_data (file_chooser, "gtkbuilder-radio");
+	g_return_val_if_fail (gtkbuilder_radio != NULL, -1);
+	g_return_val_if_fail (GTK_IS_RADIO_BUTTON (gtkbuilder_radio), -1);
+
+	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (libglade_radio)))
+		return GLADE_FILE_FORMAT_LIBGLADE;
+	else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gtkbuilder_radio)))
+		return GLADE_FILE_FORMAT_GTKBUILDER;
+	else
+		g_assert_not_reached ();
+	
+}
+
 /**
  * glade_util_replace:
  * @str: a string
Index: gladeui/glade-utils.h
===================================================================
--- gladeui/glade-utils.h	(revision 1639)
+++ gladeui/glade-utils.h	(working copy)
@@ -13,6 +13,13 @@
         GLADE_FILE_DIALOG_ACTION_SAVE
 } GladeUtilFileDialogType;
 
+
+typedef enum
+{
+	GLADE_FILE_FORMAT_LIBGLADE,
+	GLADE_FILE_FORMAT_GTKBUILDER
+} GladeFileFormatType;
+
 typedef enum 
 {
 	GLADE_UI_INFO,
@@ -127,6 +134,8 @@
 
 time_t            glade_util_get_file_mtime        (const gchar *filename, GError **error);
 
+GladeFileFormatType glade_util_file_dialog_get_file_format (GtkFileChooser *file_chooser);
+
 G_END_DECLS
 
 #endif /* __GLADE_UTILS_H__ */
Index: gladeui/Makefile.am
===================================================================
--- gladeui/Makefile.am	(revision 1639)
+++ gladeui/Makefile.am	(working copy)
@@ -64,7 +64,11 @@
 	glade-catalog.h \
 	glade-marshallers.h \
 	glade-accumulators.h \
-	glade-widget-action.c
+	glade-widget-action.c \
+	glade-format-libglade.c	\
+	glade-format-libglade.h \
+	glade-format-gtkbuilder.c \
+	glade-format-gtkbuilder.h
 
 libgladeui_1_la_CPPFLAGS =  \
 	$(common_defines)   \
Index: src/glade-window.c
===================================================================
--- src/glade-window.c	(revision 1639)
+++ src/glade-window.c	(working copy)
@@ -1272,6 +1272,9 @@
  	GtkWidget    *dialog;
 	gchar *path = NULL;
 	gchar *real_path, *ch, *project_name;
+	GladeFileFormatType file_format_type;
+	GtkFileFilter *file_filter;
+	const gchar *filter_name;
 	
 	project = glade_design_view_get_project (window->priv->active_view);
 	
@@ -1302,7 +1305,10 @@
 	
  	if (gtk_dialog_run (GTK_DIALOG(filechooser)) == GTK_RESPONSE_OK)
 		path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser));
-	
+
+	file_format_type = glade_util_file_dialog_get_file_format (GTK_FILE_CHOOSER (filechooser));
+	glade_project_set_file_format (project, file_format_type);
+	  
  	gtk_widget_destroy (filechooser);
  
  	if (!path)
@@ -1310,7 +1316,12 @@
 
 	ch = strrchr (path, '.');
 	if (!ch || strchr (ch, G_DIR_SEPARATOR))
-		real_path = g_strconcat (path, ".glade", NULL);
+		if (file_format_type == GLADE_FILE_FORMAT_LIBGLADE)
+			real_path = g_strconcat (path, ".glade", NULL);
+		else if (file_format_type == GLADE_FILE_FORMAT_GTKBUILDER)
+			real_path = g_strconcat (path, ".ui", NULL);
+	        else
+			g_assert_not_reached ();
 	else 
 		real_path = g_strdup (path);
 	
