[monkey-bubble: 667/753] Committing sane HEAD versions of these for Anders to hack on. Removed the



commit e05ba59f22ab10de05035c83fb092f70aa40011b
Author: George Lebl <jirka 5z com>
Date:   Sun Aug 26 09:30:00 2001 +0000

    Committing sane HEAD versions of these for Anders to hack on. Removed the
    
    Sun Aug 26 09:18:55 2001  George Lebl <jirka 5z com>
    
    	* gnome-app-helper.[ch], gnome-app-util.[ch], gnome-app.[ch],
    	  gnome-appbar.[ch]:  Committing sane HEAD versions of these for
    	  Anders to hack on.  Removed the helpsys stuff since we'll likely
    	  not use that.  Not added these to the build since they probably
    	  won't.  They need a bit of loving before that.

 libgnomeui/ChangeLog          |    8 +
 libgnomeui/gnome-app-helper.c | 2679 +++++++++++++++++++++++++++++++++++++++++
 libgnomeui/gnome-app-helper.h |  742 ++++++++++++
 libgnomeui/gnome-app-util.c   |  985 +++++++++++++++
 libgnomeui/gnome-app-util.h   |  147 +++
 libgnomeui/gnome-app.c        |  821 +++++++++++++
 libgnomeui/gnome-app.h        |  173 +++
 libgnomeui/gnome-appbar.c     |  759 ++++++++++++
 libgnomeui/gnome-appbar.h     |  138 +++
 9 files changed, 6452 insertions(+), 0 deletions(-)
---
diff --git a/libgnomeui/ChangeLog b/libgnomeui/ChangeLog
index 84b8c88..42d955f 100644
--- a/libgnomeui/ChangeLog
+++ b/libgnomeui/ChangeLog
@@ -1,3 +1,11 @@
+Sun Aug 26 09:18:55 2001  George Lebl <jirka 5z com>
+
+	* gnome-app-helper.[ch], gnome-app-util.[ch], gnome-app.[ch],
+	  gnome-appbar.[ch]:  Committing sane HEAD versions of these for
+	  Anders to hack on.  Removed the helpsys stuff since we'll likely
+	  not use that.  Not added these to the build since they probably
+	  won't.  They need a bit of loving before that.
+
 Sat Aug 25 20:18:13 2001  George Lebl <jirka 5z com>
 
 	* gnome-druid-page-standard.c:  Fix bad prototype
diff --git a/libgnomeui/gnome-app-helper.c b/libgnomeui/gnome-app-helper.c
new file mode 100644
index 0000000..ea9794a
--- /dev/null
+++ b/libgnomeui/gnome-app-helper.c
@@ -0,0 +1,2679 @@
+/* Copyright (C) 1998 Red Hat Software, Miguel de Icaza, Federico Mena, 
+ * Chris Toshok.
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome 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.
+ *
+ * The Gnome 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 the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+ */
+/*
+ * Originally by Elliot Lee, with hacking by Chris Toshok for *_data, Marc 
+ * Ewing added menu support, toggle and radio support, and I don't know what 
+ * you other people did :) menu insertion/removal functions by Jaka Mocnik.
+ * Small fixes and documentation by Justin Maurer.
+ *
+ * Major cleanups and rearrangements by Federico Mena and Justin Maurer.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+#include <libgnome/libgnome.h>
+
+#include <libgnome/gnome-util.h>
+#include <libgnome/gnome-config.h>
+#include "gnome-helpsys.h"
+#include "gnome-gconf.h"
+
+/* Note that this file must include gnome-i18n, and not gnome-i18nP, so that 
+ * _() is the same as the one seen by the application.  This is moderately 
+ * bogus; we should just call gettext() directly here.
+ */
+
+#include <libgnome/gnome-i18n.h>
+#include "gnome-app.h"
+#include "gnome-app-helper.h"
+#include "gnome-uidefs.h"
+#include "gnome-stock.h"
+#include "gnome-pixmap.h"
+#include <libgnome/gnome-preferences.h>
+#include "gnome-stock.h"
+
+extern const gchar *gnome_user_accels_dir;
+
+/* keys used for get/set_data */
+const char *gnome_app_helper_gconf_client = "gnome-app-helper-gconf-client";
+const char *gnome_app_helper_menu_hint = "gnome-app-helper:menu-hint";
+const char *gnome_app_helper_pixmap_type = "gnome-app-helper-pixmap-type";
+const char *gnome_app_helper_pixmap_info = "gnome-app-helper-pixmap-info";
+const char *apphelper_statusbar_hint = "apphelper_statusbar_hint";
+const char *apphelper_appbar_hint = "apphelper_appbar_hint";
+const char *GtkMenu_uline_accel_group = "GtkMenu-uline-accel-group";
+
+/* prototypes */
+static gint g_strncmp_ignore_char( const gchar *first, const gchar *second,
+				   gint length, gchar ignored );
+
+
+#ifdef NEVER_DEFINED
+static const char strings [] = {
+	N_("_File"),
+	N_("_File/"),
+	N_("_Edit"),
+	N_("_Edit/"),
+	N_("_View"),
+	N_("_View/"),
+	N_("_Settings"),
+	N_("_Settings/"),
+        N_("_New"),
+	N_("_New/"),
+	N_("Fi_les"),
+	N_("Fi_les/"),
+	N_("_Windows"),
+	N_("_Game"), 
+	N_("_Help"), 
+	N_("_Windows/")
+};
+
+#endif
+
+static GnomeUIInfo menu_defaults[] = {
+        /* New */
+        { GNOME_APP_UI_ITEM, NULL, NULL,
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_NEW,
+          GNOME_KEY_NAME_NEW, GNOME_KEY_MOD_NEW, NULL },
+        /* Open */
+        { GNOME_APP_UI_ITEM, N_("_Open..."), N_("Open a file"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_OPEN,
+          GNOME_KEY_NAME_OPEN, GNOME_KEY_MOD_OPEN, NULL },
+	/* Save */
+        { GNOME_APP_UI_ITEM, N_("_Save"), N_("Save the current file"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_SAVE,
+          GNOME_KEY_NAME_SAVE, GNOME_KEY_MOD_SAVE, NULL },
+	/* Save As */
+        { GNOME_APP_UI_ITEM, N_("Save _As..."),
+          N_("Save the current file with a different name"),
+          NULL, NULL, NULL,
+	  GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_SAVE_AS,
+          GNOME_KEY_NAME_SAVE_AS, GNOME_KEY_MOD_SAVE_AS, NULL },
+	/* Revert */
+        { GNOME_APP_UI_ITEM, N_("_Revert"),
+          N_("Revert to a saved version of the file"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_REVERT,
+          0,  (GdkModifierType) 0, NULL },
+	/* Print */
+        { GNOME_APP_UI_ITEM, N_("_Print"), N_("Print the current file"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_PRINT,
+          GNOME_KEY_NAME_PRINT,  GNOME_KEY_MOD_PRINT, NULL },
+	/* Print Setup */
+        { GNOME_APP_UI_ITEM, N_("Print S_etup..."),
+          N_("Setup the page settings for your current printer"),
+          NULL, NULL,
+	  NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_PRINT,
+          GNOME_KEY_NAME_PRINT_SETUP,  GNOME_KEY_MOD_PRINT_SETUP, NULL },
+	/* Close */
+        { GNOME_APP_UI_ITEM, N_("_Close"), N_("Close the current file"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_CLOSE,
+          GNOME_KEY_NAME_CLOSE, GNOME_KEY_MOD_CLOSE, NULL },
+	/* Exit */
+        { GNOME_APP_UI_ITEM, N_("E_xit"), N_("Exit the program"),
+          NULL, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
+	  GNOME_STOCK_MENU_EXIT, GNOME_KEY_NAME_EXIT, GNOME_KEY_MOD_EXIT,
+	    NULL },
+	/*
+	 * The "Edit" menu
+	 */
+	/* Cut */
+        { GNOME_APP_UI_ITEM, N_("C_ut"), N_("Cut the selection"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_CUT,
+          GNOME_KEY_NAME_CUT, GNOME_KEY_MOD_CUT, NULL },
+	/* 10 */
+	/* Copy */
+        { GNOME_APP_UI_ITEM, N_("_Copy"), N_("Copy the selection"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_COPY,
+          GNOME_KEY_NAME_COPY, GNOME_KEY_MOD_COPY, NULL },
+	/* Paste */
+        { GNOME_APP_UI_ITEM, N_("_Paste"), N_("Paste the clipboard"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_PASTE,
+          GNOME_KEY_NAME_PASTE, GNOME_KEY_MOD_PASTE, NULL },
+	/* Clear */
+        { GNOME_APP_UI_ITEM, N_("C_lear"), N_("Clear the selection"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_NONE, NULL,
+          GNOME_KEY_NAME_CLEAR, GNOME_KEY_MOD_CLEAR, NULL },
+	/* Undo */
+        { GNOME_APP_UI_ITEM, N_("_Undo"), N_("Undo the last action"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_UNDO,
+          GNOME_KEY_NAME_UNDO, GNOME_KEY_MOD_UNDO, NULL },
+	/* Redo */
+        { GNOME_APP_UI_ITEM, N_("_Redo"), N_("Redo the undone action"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_REDO,
+          GNOME_KEY_NAME_REDO, GNOME_KEY_MOD_REDO, NULL },
+	/* Find */
+        { GNOME_APP_UI_ITEM, N_("_Find..."),  N_("Search for a string"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_SEARCH,
+          GNOME_KEY_NAME_FIND, GNOME_KEY_MOD_FIND, NULL },
+	/* Find Again */
+        { GNOME_APP_UI_ITEM, N_("Find _Again"),
+          N_("Search again for the same string"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_SEARCH,
+          GNOME_KEY_NAME_FIND_AGAIN, GNOME_KEY_MOD_FIND_AGAIN, NULL },
+	/* Replace */
+        { GNOME_APP_UI_ITEM, N_("_Replace..."), N_("Replace a string"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_SRCHRPL,
+          GNOME_KEY_NAME_REPLACE, GNOME_KEY_MOD_REPLACE, NULL },
+	/* Properties */
+        { GNOME_APP_UI_ITEM, N_("_Properties..."),
+          N_("Modify the file's properties"),
+          NULL, NULL, NULL,
+	  GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_PROP,
+          0,  (GdkModifierType) 0, NULL },
+	/*
+	 * The Settings menu
+	 */
+	/* Settings */
+        { GNOME_APP_UI_ITEM, N_("_Preferences..."),
+          N_("Configure the application"),
+          NULL, NULL,
+	  NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_PREF,
+          0,  (GdkModifierType) 0, NULL },
+	/* 20 */
+	/*
+	 * And the "Help" menu
+	 */
+	/* About */
+        { GNOME_APP_UI_ITEM, N_("_About"),
+          N_("About this application"), NULL, NULL,
+	  NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT,
+          0,  (GdkModifierType) 0, NULL },
+	{ GNOME_APP_UI_ITEM, N_("_Select All"),
+          N_("Select everything"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_NONE, NULL,
+          GNOME_KEY_NAME_SELECT_ALL, GNOME_KEY_MOD_SELECT_ALL, NULL },
+
+	/*
+	 * Window menu
+	 */
+        { GNOME_APP_UI_ITEM, N_("Create New _Window"),
+          N_("Create a new window"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_NONE, NULL,
+          GNOME_KEY_NAME_NEW_WINDOW, GNOME_KEY_MOD_NEW_WINDOW, NULL },
+        { GNOME_APP_UI_ITEM, N_("_Close This Window"),
+          N_("Close the current window"),
+          NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_NONE, NULL,
+          GNOME_KEY_NAME_CLOSE_WINDOW, GNOME_KEY_MOD_CLOSE_WINDOW, NULL },
+
+	/*
+	 * The "Game" menu
+	 */
+        { GNOME_APP_UI_ITEM, N_("_New game"),
+          N_("Start a new game"),
+	  NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_NONE, NULL,
+          GNOME_KEY_NAME_NEW_GAME,  GNOME_KEY_MOD_NEW_GAME, NULL },
+        { GNOME_APP_UI_ITEM, N_("_Pause game"),
+          N_("Pause the game"), 
+	  NULL, NULL, NULL,
+	  GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_TIMER_STOP,
+          GNOME_KEY_NAME_PAUSE_GAME,  GNOME_KEY_MOD_PAUSE_GAME, NULL },
+        { GNOME_APP_UI_ITEM, N_("_Restart game"),
+          N_("Restart the game"),
+	  NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_NONE, NULL,
+          0,  0, NULL },
+        { GNOME_APP_UI_ITEM, N_("_Undo move"),
+          N_("Undo the last move"),
+	  NULL, NULL, NULL,
+	  GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_UNDO,
+          GNOME_KEY_NAME_UNDO_MOVE,  GNOME_KEY_MOD_UNDO_MOVE, NULL },
+        { GNOME_APP_UI_ITEM, N_("_Redo move"),
+          N_("Redo the undone move"),
+	  NULL, NULL, NULL,
+	  GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_REDO,
+          GNOME_KEY_NAME_REDO_MOVE,  GNOME_KEY_MOD_REDO_MOVE, NULL },
+        { GNOME_APP_UI_ITEM, N_("_Hint"),
+          N_("Get a hint for your next move"),
+	  NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_NONE, NULL,
+          0,  0, NULL },
+	/* 30 */
+        { GNOME_APP_UI_ITEM, N_("_Scores..."),
+          N_("View the scores"),
+	  NULL, NULL, NULL,
+	  GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_SCORES,
+          0,  (GdkModifierType) 0, NULL },
+        { GNOME_APP_UI_ITEM, N_("_End game"),
+          N_("End the current game"),
+	  NULL, NULL, NULL,
+          GNOME_APP_PIXMAP_NONE, NULL,
+          0,  (GdkModifierType) 0, NULL }
+};
+
+static gchar *menu_names[] =
+{
+  /* 0 */
+  "new",
+  "open",
+  "save",
+  "save-as",
+  "revert",
+  "print",
+  "print-setup",
+  "close",
+  "exit",
+  "cut",
+  /* 10 */
+  "copy",
+  "paste",
+  "clear",
+  "undo",
+  "redo",
+  "find",
+  "find-again",
+  "replace",
+  "properties",
+  "preferences",
+  /* 20 */
+  "about",
+  "select-all",
+  "new-window",
+  "close-window",
+  "new-game",
+  "pause-game",
+  "restart-game",
+  "undo-move",
+  "redo-move",
+  "hint",
+  /* 30 */
+  "scores",
+  "end-game"
+};
+
+
+/* Creates a pixmap appropriate for items.  */
+
+static GtkWidget *
+create_pixmap (GnomeUIPixmapType pixmap_type, gconstpointer pixmap_info)
+{
+	GtkWidget *pixmap;
+	char *name;
+
+	pixmap = NULL;
+
+	switch (pixmap_type) {
+#ifdef FIXME
+	case GNOME_APP_PIXMAP_STOCK:
+		pixmap = gnome_stock_new_with_icon (pixmap_info);
+		break;
+#endif
+
+	case GNOME_APP_PIXMAP_DATA:
+		if (pixmap_info)
+			pixmap = gnome_pixmap_new_from_xpm_d ((const char**)pixmap_info);
+
+		break;
+
+	case GNOME_APP_PIXMAP_NONE:
+		break;
+
+	case GNOME_APP_PIXMAP_FILENAME:
+		name = gnome_program_locate_file (gnome_program_get (),
+						  GNOME_FILE_DOMAIN_PIXMAP,
+						  pixmap_info, TRUE, NULL);
+		
+		if (!name)
+			g_warning ("Could not find GNOME pixmap file %s", 
+					(char *) pixmap_info);
+		else {
+			pixmap = gnome_pixmap_new_from_file (name);
+			g_free (name);
+		}
+
+		break;
+
+	default:
+		g_assert_not_reached ();
+		g_warning("Invalid pixmap_type %d", (int) pixmap_type); 
+	}
+
+	return pixmap;
+}
+
+static void
+showing_pixmaps_changed_notify(GConfClient            *client,
+                               guint                   cnxn_id,
+			       GConfEntry             *entry,
+                               gpointer                user_data)
+{
+        gboolean new_setting = TRUE;
+        GtkWidget *w = user_data;
+        GtkImageMenuItem *mi = GTK_IMAGE_MENU_ITEM(w);
+	GConfValue *value;
+
+	value = gconf_entry_get_value (entry);
+
+        if (value && value->type == GCONF_VALUE_BOOL) {
+                new_setting = gconf_value_get_bool(value);
+        }
+
+        if (new_setting && (mi->image == NULL)) {
+                GtkWidget *pixmap;
+                GnomeUIPixmapType pixmap_type;
+                gconstpointer pixmap_info;
+
+                pixmap_type = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(mi),
+                                                                  gnome_app_helper_pixmap_type));
+                pixmap_info = gtk_object_get_data(GTK_OBJECT(mi),
+                                                  gnome_app_helper_pixmap_info);
+
+                pixmap = create_pixmap(pixmap_type, pixmap_info);
+
+                gtk_widget_show(pixmap);
+                
+		g_object_set(G_OBJECT(mi), "image", pixmap, NULL);
+        } else if (!new_setting && (mi->image != NULL)) {
+		g_object_set(G_OBJECT(mi), "image", NULL, NULL);
+        }
+}
+
+/* Note that this function is also used for toolbars, don't assume
+   obj is a menu item */
+static void
+remove_notify_cb(GtkObject *obj, gpointer data)
+{
+        guint notify_id;
+        GConfClient *conf;
+        
+        notify_id = GPOINTER_TO_INT(data);
+
+        conf = gtk_object_get_data(obj, gnome_app_helper_gconf_client);
+
+        gconf_client_notify_remove(conf, notify_id);
+}
+
+static void
+setup_image_menu_item(GtkWidget *mi, GnomeUIPixmapType pixmap_type,
+		      gconstpointer pixmap_info)
+{
+        guint notify_id;
+        GConfClient *conf;
+        
+        g_return_if_fail(GTK_IS_IMAGE_MENU_ITEM(mi));
+
+        gtk_object_set_data(GTK_OBJECT(mi), gnome_app_helper_pixmap_type,
+                            GINT_TO_POINTER(pixmap_type));
+
+        gtk_object_set_data(GTK_OBJECT(mi), gnome_app_helper_pixmap_info,
+                            (gpointer)pixmap_info);
+
+        
+        conf = gconf_client_get_default();
+
+        g_object_ref (G_OBJECT (conf));
+        gtk_object_set_data_full(GTK_OBJECT(mi), gnome_app_helper_gconf_client,
+                                 conf, (GtkDestroyNotify)g_object_unref);
+
+        if (gconf_client_get_bool(conf,
+                                  "/desktop/gnome/menus/show-icons",
+                                  NULL)) {
+                GtkWidget *pixmap;
+
+                pixmap = create_pixmap(pixmap_type, pixmap_info);
+
+                gtk_widget_show(pixmap);
+                
+		g_object_set(G_OBJECT(mi), "image", pixmap, NULL);
+        }
+
+        notify_id = gconf_client_notify_add(conf,
+                                            "/desktop/gnome/menus/show-icons",
+                                            showing_pixmaps_changed_notify,
+                                            mi, NULL, NULL);
+
+        gtk_signal_connect(GTK_OBJECT(mi), "destroy",
+                           GTK_SIGNAL_FUNC(remove_notify_cb),
+			   GINT_TO_POINTER(notify_id));
+}
+
+/* Creates  a menu item label. It will also return the underlined 
+ * letter's keyval if keyval is not NULL. */
+static GtkWidget *
+create_label (const char *label_text, guint *keyval)
+{
+	guint kv;
+	GtkWidget *label;
+
+	label = gtk_accel_label_new (label_text);
+
+	kv = gtk_label_parse_uline (GTK_LABEL (label), label_text);
+	if (keyval)
+		*keyval = kv;
+
+	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+	gtk_widget_show (label);
+
+	return label;
+}
+
+/* Creates the accelerator for the specified uiinfo item's hotkey */
+static void
+setup_accelerator (GtkAccelGroup *accel_group, GnomeUIInfo *uiinfo, 
+		char *signal_name, int accel_flags)
+{
+	if (uiinfo->accelerator_key != 0)
+		gtk_widget_add_accelerator (uiinfo->widget, signal_name, 
+					    accel_group, uiinfo->accelerator_key, 
+					    uiinfo->ac_mods, accel_flags);
+}
+
+#ifndef	GTK_CHECK_VERSION
+GtkAccelGroup*
+gtk_menu_ensure_uline_accel_group (GtkMenu *menu)
+{
+  GtkAccelGroup *accel_group;
+
+  g_return_val_if_fail (GTK_IS_MENU (menu), NULL);
+
+  accel_group = gtk_object_get_data (GTK_OBJECT (menu),
+				     GtkMenu_uline_accel_group);
+  if (!accel_group)
+    {
+      accel_group = gtk_accel_group_new ();
+      gtk_accel_group_attach (accel_group, GTK_OBJECT (menu));
+      gtk_object_set_data_full (GTK_OBJECT (menu),
+				GtkMenu_uline_accel_group,
+				accel_group,
+				(GtkDestroyNotify) gtk_accel_group_unref);
+    }
+
+  return accel_group;
+}
+void
+gtk_item_factory_add_foreign (GtkWidget      *accel_widget,
+			      const gchar    *full_path,
+			      GtkAccelGroup  *accel_group,
+			      guint           keyval,
+			      GdkModifierType modifiers)
+{
+  if (accel_group)
+    gtk_widget_add_accelerator (accel_widget,
+				"activate",
+				accel_group,
+				keyval,
+				modifiers,
+				GTK_ACCEL_VISIBLE);
+}
+#endif
+
+/* Creates the accelerators for the underlined letter in a menu item's label. 
+ * The keyval is what gtk_label_parse_uline() returned.  If accel_group is not 
+ * NULL, then the keyval will be put with MOD1 as modifier in it (i.e. for 
+ * Alt-F in the _File menu).
+ */
+static void
+setup_uline_accel (GtkMenuShell  *menu_shell,
+		   GtkAccelGroup *accel_group,
+		   GtkWidget     *menu_item,
+		   guint          keyval)
+{
+#if 0 /* FIXME FIXME FIXME */
+	if (keyval != GDK_VoidSymbol) {
+		if (GTK_IS_MENU (menu_shell))
+			gtk_widget_add_accelerator (menu_item,
+						    "activate_item",
+						    gtk_menu_ensure_uline_accel_group (GTK_MENU (menu_shell)),
+						    keyval, 0,
+						    0);
+		if (GTK_IS_MENU_BAR (menu_shell) && accel_group)
+			gtk_widget_add_accelerator (menu_item,
+						    "activate_item", 
+						    accel_group,
+						    keyval, GDK_MOD1_MASK,
+						    0);
+	}
+#endif
+}
+
+/* Callback to display hint in the statusbar when a menu item is 
+ * activated. For GtkStatusbar.
+ */
+
+static void
+put_hint_in_statusbar(GtkWidget* menuitem, gpointer data)
+{
+	gchar* hint = gtk_object_get_data(GTK_OBJECT(menuitem),
+					  apphelper_statusbar_hint);
+	GtkWidget* bar = data;
+	guint id;
+	
+	g_return_if_fail (hint != NULL);
+	g_return_if_fail (bar != NULL);
+	g_return_if_fail (GTK_IS_STATUSBAR(bar));
+	
+	id = gtk_statusbar_get_context_id(GTK_STATUSBAR(bar),
+					  gnome_app_helper_menu_hint);
+	
+	gtk_statusbar_push(GTK_STATUSBAR(bar),id,hint);
+}
+
+/* Callback to remove hint when the menu item is deactivated.
+ * For GtkStatusbar.
+ */
+static void
+remove_hint_from_statusbar(GtkWidget* menuitem, gpointer data)
+{
+	GtkWidget* bar = data;
+	guint id;
+	
+	g_return_if_fail (bar != NULL);
+	g_return_if_fail (GTK_IS_STATUSBAR(bar));
+	
+	id = gtk_statusbar_get_context_id(GTK_STATUSBAR(bar),
+					  gnome_app_helper_menu_hint);
+	
+	gtk_statusbar_pop(GTK_STATUSBAR(bar), id);
+}
+
+/* Install a hint for a menu item
+ */
+static void
+install_menuitem_hint_to_statusbar(GnomeUIInfo* uiinfo, GtkStatusbar* bar)
+{
+  g_return_if_fail (uiinfo != NULL);
+  g_return_if_fail (uiinfo->widget != NULL);
+  g_return_if_fail (GTK_IS_MENU_ITEM(uiinfo->widget));
+
+  /* This is mildly fragile; if someone destroys the appbar
+     but not the menu, chaos will ensue. */
+
+  if (uiinfo->hint)
+    {
+      gtk_object_set_data (GTK_OBJECT(uiinfo->widget),
+                           apphelper_statusbar_hint,
+                           (gpointer)L_(uiinfo->hint));
+
+      gtk_signal_connect (GTK_OBJECT (uiinfo->widget),
+                          "select",
+                          GTK_SIGNAL_FUNC(put_hint_in_statusbar),
+                          bar);
+      
+      gtk_signal_connect (GTK_OBJECT (uiinfo->widget),
+                          "deselect",
+                          GTK_SIGNAL_FUNC(remove_hint_from_statusbar),
+                          bar);
+    }
+}        
+
+/**
+ * gnome_app_install_statusbar_menu_hints
+ * @bar: Pointer to Gtk+ status bar object
+ * @uiinfo: Gnome UI info for the menu to be changed
+ *
+ * Description:
+ * Install menu hints for the given status bar.
+ */
+
+void 
+gnome_app_install_statusbar_menu_hints (GtkStatusbar* bar,
+                                        GnomeUIInfo* uiinfo)
+{
+	g_return_if_fail (bar != NULL);
+	g_return_if_fail (uiinfo != NULL);
+	g_return_if_fail (GTK_IS_STATUSBAR (bar));
+	
+	
+	while (uiinfo->type != GNOME_APP_UI_ENDOFINFO)
+	{
+		switch (uiinfo->type) {
+		case GNOME_APP_UI_INCLUDE:
+			gnome_app_install_statusbar_menu_hints(bar, uiinfo->moreinfo);
+			break;
+
+		case GNOME_APP_UI_SUBTREE:
+		case GNOME_APP_UI_SUBTREE_STOCK:
+			gnome_app_install_statusbar_menu_hints(bar, uiinfo->moreinfo);
+			
+		case GNOME_APP_UI_ITEM:
+		case GNOME_APP_UI_TOGGLEITEM:
+		case GNOME_APP_UI_SEPARATOR:
+			install_menuitem_hint_to_statusbar(uiinfo, bar);
+			break;
+		case GNOME_APP_UI_RADIOITEMS:
+			gnome_app_install_statusbar_menu_hints(bar, uiinfo->moreinfo);
+			break;
+		default:
+			;
+			break;
+		}
+		
+		++uiinfo;
+	}
+}
+
+
+/* Callback to display hint in the statusbar when a menu item is 
+ * activated. For GnomeAppBar.
+ */
+
+static void
+put_hint_in_appbar(GtkWidget* menuitem, gpointer data)
+{
+  gchar* hint = gtk_object_get_data (GTK_OBJECT(menuitem),
+                                     "apphelper_appbar_hint");
+  GtkWidget* bar = data;
+
+  g_return_if_fail (hint != NULL);
+  g_return_if_fail (bar != NULL);
+  g_return_if_fail (GNOME_IS_APPBAR(bar));
+
+  gnome_appbar_set_status (GNOME_APPBAR(bar), hint);
+}
+
+/* Callback to remove hint when the menu item is deactivated.
+ * For GnomeAppBar.
+ */
+static void
+remove_hint_from_appbar(GtkWidget* menuitem, gpointer data)
+{
+  GtkWidget* bar = data;
+
+  g_return_if_fail (bar != NULL);
+  g_return_if_fail (GNOME_IS_APPBAR(bar));
+
+  gnome_appbar_refresh (GNOME_APPBAR(bar));
+}
+
+/* Install a hint for a menu item
+ */
+static void
+install_menuitem_hint_to_appbar(GnomeUIInfo* uiinfo, GnomeAppBar* bar)
+{
+  g_return_if_fail (uiinfo != NULL);
+  g_return_if_fail (uiinfo->widget != NULL);
+  g_return_if_fail (GTK_IS_MENU_ITEM(uiinfo->widget));
+
+  /* This is mildly fragile; if someone destroys the appbar
+     but not the menu, chaos will ensue. */
+
+  if (uiinfo->hint)
+    {
+      gtk_object_set_data (GTK_OBJECT(uiinfo->widget),
+                           apphelper_appbar_hint,
+                           (gpointer)L_(uiinfo->hint));
+
+      gtk_signal_connect (GTK_OBJECT (uiinfo->widget),
+                          "select",
+                          GTK_SIGNAL_FUNC(put_hint_in_appbar),
+                          bar);
+      
+      gtk_signal_connect (GTK_OBJECT (uiinfo->widget),
+                          "deselect",
+                          GTK_SIGNAL_FUNC(remove_hint_from_appbar),
+                          bar);
+    }
+}
+
+
+/**
+ * gnome_app_ui_configure_configurable
+ * @uiinfo: Pointer to GNOME UI menu/toolbar info
+ * 
+ * Description:
+ * Configure all user-configurable elements in the given UI info 
+ * structure.  This includes loading and setting previously-set options from
+ * GNOME config files.
+ */
+
+void
+gnome_app_ui_configure_configurable (GnomeUIInfo* uiinfo)
+{
+  if (uiinfo->type == GNOME_APP_UI_ITEM_CONFIGURABLE)
+  {
+        GnomeUIInfoConfigurableTypes type = (GnomeUIInfoConfigurableTypes) uiinfo->accelerator_key;
+	
+	gboolean accelerator_key_def;
+	gchar *accelerator_key_string;
+	gint accelerator_key;
+	
+	gboolean ac_mods_def;
+	gchar *ac_mods_string;
+	gint ac_mods;
+	
+	if ( type != GNOME_APP_CONFIGURABLE_ITEM_NEW ) {
+#if 0
+	        gboolean label_def;
+		gchar *label_string;
+		gchar *label;
+	        gboolean hint_def;
+		gchar *hint_string;
+		gchar *hint;
+		
+		label_string = g_strdup_sprintf( "/Gnome/Menus/Menu-%s-label", menu_names[(int) type] );
+		label = gnome_config_get_string_with_default( label_string, &label_def);
+		if ( label_def )
+		  uiinfo->label = label;
+		else
+		  {
+#endif
+		    uiinfo->label = menu_defaults[(int) type].label;
+#if 0
+		    g_free( label );
+		  }
+		g_free( label_string );
+
+		hint_string = g_strdup_sprintf( "/Gnome/Menus/Menu-%s-hint", menu_names[(int) type] );
+		hint = gnome_config_get_string_with_default( hint_string, &hint_def);
+		if ( hint_def )
+		  uiinfo->hint = hint;
+		else
+		  {
+#endif
+		    uiinfo->hint = menu_defaults[(int) type].hint;
+#if 0
+		    g_free( hint );
+		  }
+		g_free( hint_string );
+#endif
+	}
+	uiinfo->pixmap_type = menu_defaults[(int) type].pixmap_type;
+	uiinfo->pixmap_info = menu_defaults[(int) type].pixmap_info;
+
+	accelerator_key_string = g_strdup_printf( "/Gnome/Menus/Menu-%s-accelerator-key", menu_names[(int) type] );
+	accelerator_key = gnome_config_get_int_with_default( accelerator_key_string, &accelerator_key_def);
+	if ( accelerator_key_def )
+	  uiinfo->accelerator_key = menu_defaults[(int) type].accelerator_key;
+	else
+	  uiinfo->accelerator_key = accelerator_key;
+	g_free( accelerator_key_string );
+	
+	ac_mods_string = g_strdup_printf( "/Gnome/Menus/Menu-%s-ac-mods", menu_names[(int) type] );
+	ac_mods = gnome_config_get_int_with_default( ac_mods_string, &ac_mods_def);
+	if ( ac_mods_def )
+	  uiinfo->ac_mods = menu_defaults[(int) type].ac_mods;
+	else
+	  uiinfo->ac_mods = (GdkModifierType) ac_mods;
+	g_free( ac_mods_string );
+
+	
+	uiinfo->type = GNOME_APP_UI_ITEM;
+  }
+}
+
+
+/**
+ * gnome_app_install_appbar_menu_hints
+ * @appbar: Pointer to GNOME app bar object.
+ * @uiinfo: GNOME UI info for menu
+ *
+ * Description:
+ * Install menu hints for the given GNOME app bar object.
+ */
+
+void
+gnome_app_install_appbar_menu_hints (GnomeAppBar* appbar,
+                                     GnomeUIInfo* uiinfo)
+{
+	g_return_if_fail (appbar != NULL);
+	g_return_if_fail (uiinfo != NULL);
+	g_return_if_fail (GNOME_IS_APPBAR (appbar));
+	
+	
+	while (uiinfo->type != GNOME_APP_UI_ENDOFINFO)
+	{
+		
+		/* Translate configurable menu items to normal menu items. */
+		
+		if ( uiinfo->type == GNOME_APP_UI_ITEM_CONFIGURABLE ) {
+			gnome_app_ui_configure_configurable( uiinfo );
+		}
+		switch (uiinfo->type) {
+		case GNOME_APP_UI_INCLUDE:
+			gnome_app_install_appbar_menu_hints(appbar, uiinfo->moreinfo);
+			break;
+
+		case GNOME_APP_UI_SUBTREE:
+		case GNOME_APP_UI_SUBTREE_STOCK:
+			gnome_app_install_appbar_menu_hints(appbar, uiinfo->moreinfo);
+			
+		case GNOME_APP_UI_ITEM:
+		case GNOME_APP_UI_TOGGLEITEM:
+		case GNOME_APP_UI_SEPARATOR:
+			install_menuitem_hint_to_appbar(uiinfo, appbar);
+			break;
+		case GNOME_APP_UI_RADIOITEMS:
+			gnome_app_install_appbar_menu_hints(appbar, uiinfo->moreinfo);
+			break;
+		default:
+			; 
+			break;
+		}
+		
+		++uiinfo;
+	}
+}
+
+
+/**
+ * gnome_app_install_menu_hints
+ * @app: Pointer to GNOME app object
+ * @uiinfo: GNOME UI menu for which hints will be set
+ *
+ * Description:
+ * Set menu hints for the GNOME app object's attached status bar.
+ */
+
+void
+gnome_app_install_menu_hints (GnomeApp *app,
+                              GnomeUIInfo *uiinfo) {
+  g_return_if_fail (app != NULL);
+  g_return_if_fail (uiinfo != NULL);
+  g_return_if_fail (app->statusbar != NULL);
+  g_return_if_fail (GNOME_IS_APP (app));
+
+  if(GNOME_IS_APPBAR(app->statusbar))
+    gnome_app_install_appbar_menu_hints(GNOME_APPBAR(app->statusbar), uiinfo);
+  else if(GTK_IS_STATUSBAR(app->statusbar))
+    gnome_app_install_statusbar_menu_hints(GTK_STATUSBAR(app->statusbar), uiinfo);
+}
+
+static gint
+gnome_save_accels (gpointer data)
+{
+	gchar *file_name;
+
+	file_name = g_concat_dir_and_file (gnome_user_accels_dir, gnome_program_get_name(gnome_program_get()));
+	gtk_item_factory_dump_rc (file_name, NULL, TRUE);
+	g_free (file_name);
+
+	return TRUE;
+}
+
+void
+gnome_accelerators_sync (void)
+{
+  gnome_save_accels (NULL);
+}
+
+/* Creates a menu item appropriate for the SEPARATOR, ITEM, TOGGLEITEM, or 
+ * SUBTREE types.  If the item is inside a radio group, then a pointer to the 
+ * group's list must be specified as well (*radio_group must be NULL for the 
+ * first item!).  This function does *not* create the submenu of a subtree 
+ * menu item.
+ */
+static void
+create_menu_item (GtkMenuShell       *menu_shell,
+		  GnomeUIInfo        *uiinfo,
+		  int                 is_radio,
+		  GSList            **radio_group,
+		  GnomeUIBuilderData *uibdata,
+		  GtkAccelGroup      *accel_group,
+		  gboolean	      uline_accels,
+		  gint		      pos)
+{
+	GtkWidget *label;
+	guint keyval;
+	int type;
+	
+	/* Translate configurable menu items to normal menu items. */
+
+	if (uiinfo->type == GNOME_APP_UI_ITEM_CONFIGURABLE)
+	        gnome_app_ui_configure_configurable( uiinfo );
+
+	/* Create the menu item */
+
+	switch (uiinfo->type) {
+	case GNOME_APP_UI_SEPARATOR:
+	        uiinfo->widget = gtk_menu_item_new ();
+		break;
+	case GNOME_APP_UI_ITEM:
+	case GNOME_APP_UI_SUBTREE:
+	case GNOME_APP_UI_SUBTREE_STOCK:
+		if (is_radio) {
+			uiinfo->widget = gtk_radio_menu_item_new (*radio_group);
+			*radio_group = gtk_radio_menu_item_group
+				(GTK_RADIO_MENU_ITEM (uiinfo->widget));
+		} else {
+
+		        /* Create the pixmap */
+
+		        /* FIXME: this should later allow for on-the-fly configuration of 
+			 * whether pixmaps are displayed or not ???
+			 */
+
+		        if ((uiinfo->pixmap_type != GNOME_APP_PIXMAP_NONE) &&
+			    gnome_preferences_get_menus_have_icons()) {
+			        uiinfo->widget = gtk_image_menu_item_new (NULL,
+									  uiinfo->label ? uiinfo->label : "");
+
+                                setup_image_menu_item(uiinfo->widget,
+						      uiinfo->pixmap_type, 
+						      uiinfo->pixmap_info);
+			} else
+			        uiinfo->widget = gtk_menu_item_new ();
+		}
+		break;
+
+	case GNOME_APP_UI_TOGGLEITEM:
+		uiinfo->widget = gtk_check_menu_item_new ();
+		break;
+
+	default:
+		g_warning ("Invalid GnomeUIInfo type %d passed to "
+				"create_menu_item()", (int) uiinfo->type);
+		return;
+	}
+
+	if (!accel_group)
+		gtk_widget_lock_accelerators (uiinfo->widget);
+
+	gtk_widget_show (uiinfo->widget);
+	gtk_menu_shell_insert (menu_shell, uiinfo->widget, pos);
+
+	/* If it is a separator, set it as insensitive so that it cannot be 
+	 * selected, and return -- there is nothing left to do.
+	 */
+
+	if (uiinfo->type == GNOME_APP_UI_SEPARATOR) {
+		gtk_widget_set_sensitive (uiinfo->widget, FALSE);
+		return;
+	}
+
+	/* Create the contents of the menu item */
+
+	/* Don't use gettext on the empty string since gettext will map
+	 * the empty string to the header at the beginning of the .pot file. */
+
+	label = create_label ( uiinfo->label [0] == '\0'?
+			       "":(uiinfo->type == GNOME_APP_UI_SUBTREE_STOCK ?
+				   D_(uiinfo->label):L_(uiinfo->label)),
+			       &keyval);
+
+	gtk_container_add (GTK_CONTAINER (uiinfo->widget), label);
+
+	gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), 
+					  uiinfo->widget);
+	
+	/* setup underline accelerators
+	 */
+	if (uline_accels)
+		setup_uline_accel (menu_shell,
+				   accel_group,
+				   uiinfo->widget,
+				   keyval);
+
+	/* install global accelerator
+	 */
+	{
+		static guint save_accels_id = 0;
+		GString *gstring;
+		GtkWidget *widget;
+		
+		/* build up the menu item path */
+		gstring = g_string_new ("");
+		widget = uiinfo->widget;
+		while (widget) {
+			if (GTK_IS_MENU_ITEM (widget)) {
+				GtkWidget *child = GTK_BIN (widget)->child;
+				
+				if (GTK_IS_LABEL (child)) {
+					g_string_prepend (gstring, GTK_LABEL (child)->label);
+					g_string_prepend_c (gstring, '/');
+				}
+				widget = widget->parent;
+			} else if (GTK_IS_MENU (widget)) {
+				widget = gtk_menu_get_attach_widget (GTK_MENU (widget));
+				if (widget == NULL) {
+					g_string_prepend (gstring, "/-Orphan");
+					widget = NULL;
+				}
+			} else
+				widget = widget->parent;
+		}
+		g_string_prepend_c (gstring, '>');
+		g_string_prepend (gstring, gnome_program_get_name(gnome_program_get()));
+		g_string_prepend_c (gstring, '<');
+
+		/* g_print ("######## menu item path: %s\n", gstring->str); */
+		
+		/* the item factory cares about installing the correct accelerator */
+		
+		gtk_item_factory_add_foreign (uiinfo->widget,
+					      gstring->str,
+					      accel_group,
+					      uiinfo->accelerator_key,
+					      uiinfo->ac_mods);
+		g_string_free (gstring, TRUE);
+
+		if (!save_accels_id)
+			save_accels_id = gtk_quit_add (1, gnome_save_accels, NULL);
+	}
+	
+	/* Set toggle information, if appropriate */
+	
+	if ((uiinfo->type == GNOME_APP_UI_TOGGLEITEM) || is_radio) {
+		gtk_check_menu_item_set_show_toggle
+			(GTK_CHECK_MENU_ITEM(uiinfo->widget), TRUE);
+		gtk_check_menu_item_set_active
+			(GTK_CHECK_MENU_ITEM (uiinfo->widget), FALSE);
+	}
+	
+	/* Connect to the signal and set user data */
+	
+	type = uiinfo->type;
+	if (type == GNOME_APP_UI_SUBTREE_STOCK)
+		type = GNOME_APP_UI_SUBTREE;
+	
+	if (type != GNOME_APP_UI_SUBTREE) {
+	        gtk_object_set_data (GTK_OBJECT (uiinfo->widget),
+				     GNOMEUIINFO_KEY_UIDATA,
+				     uiinfo->user_data);
+
+		gtk_object_set_data (GTK_OBJECT (uiinfo->widget),
+				     GNOMEUIINFO_KEY_UIBDATA,
+				     uibdata->data);
+
+		(* uibdata->connect_func) (uiinfo, "activate", uibdata);
+	}
+}
+
+/* Creates a group of radio menu items.  Returns the updated position parameter. */
+static int
+create_radio_menu_items (GtkMenuShell *menu_shell, GnomeUIInfo *uiinfo, 
+		GnomeUIBuilderData *uibdata, GtkAccelGroup *accel_group, 
+		gint pos)
+{
+	GSList *group;
+
+	group = NULL;
+
+	for (; uiinfo->type != GNOME_APP_UI_ENDOFINFO; uiinfo++)
+		switch (uiinfo->type) {
+		case GNOME_APP_UI_BUILDER_DATA:
+			uibdata = uiinfo->moreinfo;
+			break;
+
+		case GNOME_APP_UI_ITEM:
+			create_menu_item (menu_shell, uiinfo, TRUE,
+					  &group, uibdata, 
+					  accel_group, FALSE, pos);
+			pos++;
+			break;
+
+		default:
+			g_warning ("GnomeUIInfo element type %d is not valid "
+					"inside a menu radio item group",
+				   (int) uiinfo->type);
+		}
+
+	return pos;
+}
+
+/* Creates the menu entries for help topics.  Returns the updated position 
+ * value. */
+static int
+create_help_entries (GtkMenuShell *menu_shell, GnomeUIInfo *uiinfo, gint pos)
+{
+	GSList *topics, *cur;
+
+	uiinfo->widget = NULL; /* No relevant widget, as we may have created 
+				  several of them */
+
+	if (!uiinfo->moreinfo) {
+		g_warning ("GnomeUIInfo->moreinfo cannot be NULL for "
+				"GNOME_APP_UI_HELP");
+		return pos;
+	}
+
+	/* #warning FIXME: this needs to use helpsys!!!! */
+	topics = NULL;
+	/* topics = gnome_help_app_topics ((const char *)uiinfo->moreinfo);*/
+
+	for (cur = topics; cur && cur->next; cur = cur->next->next)
+	  {
+	    GtkWidget *item;
+	    GtkWidget *label;
+	    guint keyval;
+
+	    item = gtk_menu_item_new ();
+	    label = create_label (cur->data, &keyval);
+	    g_free(cur->data);
+
+	    gtk_container_add (GTK_CONTAINER (item), label);
+	    setup_uline_accel (menu_shell, NULL, item, keyval);
+	    gtk_widget_lock_accelerators (item);
+
+	    /* #warning FIXME: this needs to use helpsys!!!! */
+	    /*
+	    gtk_signal_connect_full (GTK_OBJECT (item), "activate",
+				     (GtkSignalFunc) gnome_help_view_display_callback, NULL,
+				     cur->next->data, g_free,
+				     FALSE, FALSE);
+				     */
+
+	    gtk_menu_shell_insert (menu_shell, item, pos);
+	    pos++;
+
+	    gtk_widget_show (item);
+
+	  }
+	g_slist_free(topics);
+
+	return pos;
+}
+
+/* Performs signal connection as appropriate for interpreters or native bindings */
+static void
+do_ui_signal_connect (GnomeUIInfo *uiinfo, const char *signal_name, 
+		GnomeUIBuilderData *uibdata)
+{
+	if (uibdata->is_interp)
+		gtk_signal_connect_full (GTK_OBJECT (uiinfo->widget), 
+				signal_name, NULL, uibdata->relay_func, 
+				uibdata->data ? 
+				uibdata->data : uiinfo->user_data,
+				uibdata->destroy_func, FALSE, FALSE);
+	
+	else if (uiinfo->moreinfo)
+		gtk_signal_connect (GTK_OBJECT (uiinfo->widget), 
+				signal_name, uiinfo->moreinfo, uibdata->data ? 
+				uibdata->data : uiinfo->user_data);
+}
+
+
+/**
+ * gnome_app_fill_menu
+ * @menu_shell:
+ * @uiinfo:
+ * @accel_group:
+ * @uline_accels:
+ * @pos:
+ *
+ * Description:
+ * Fills the specified menu shell with items created from the specified
+ * info, inserting them from the item no. pos on.
+ * The accel group will be used as the accel group for all newly created
+ * sub menus and serves as the global accel group for all menu item
+ * hotkeys. If it is passed as NULL, global hotkeys will be disabled.
+ * The uline_accels argument determines whether underline accelerators
+ * will be featured from the menu item labels.
+ **/
+
+void
+gnome_app_fill_menu (GtkMenuShell  *menu_shell,
+		     GnomeUIInfo   *uiinfo, 
+		     GtkAccelGroup *accel_group,
+		     gboolean       uline_accels,
+		     gint           pos)
+{
+	GnomeUIBuilderData uibdata;
+
+	g_return_if_fail (menu_shell != NULL);
+	g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
+	g_return_if_fail (uiinfo != NULL);
+	g_return_if_fail (pos >= 0);
+	
+	uibdata.connect_func =  do_ui_signal_connect;
+	uibdata.data = NULL;
+	uibdata.is_interp = FALSE;
+	uibdata.relay_func = NULL;
+	uibdata.destroy_func = NULL;
+
+	gnome_app_fill_menu_custom (menu_shell, uiinfo, &uibdata,
+				    accel_group, uline_accels,
+				    pos);
+	return;
+}
+
+
+/**
+ * gnome_app_fill_menu_with_data
+ * @menu_shell:
+ * @uiinfo:
+ * @accel_group:
+ * @uline_accels:
+ * @pos:
+ * @user_data:
+ *
+ * Description:
+ **/
+
+void
+gnome_app_fill_menu_with_data (GtkMenuShell  *menu_shell,
+			       GnomeUIInfo   *uiinfo, 
+			       GtkAccelGroup *accel_group,
+			       gboolean       uline_accels,
+			       gint	      pos,
+			       gpointer       user_data)
+{
+	GnomeUIBuilderData uibdata;
+
+	g_return_if_fail (menu_shell != NULL);
+	g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
+	g_return_if_fail (uiinfo != NULL);
+
+	uibdata.connect_func = do_ui_signal_connect;
+	uibdata.data = user_data;
+	uibdata.is_interp = FALSE;
+	uibdata.relay_func = NULL;
+	uibdata.destroy_func = NULL;
+
+	gnome_app_fill_menu_custom (menu_shell, uiinfo, &uibdata,
+				    accel_group, uline_accels,
+				    pos);
+}
+
+
+/**
+ * gnome_app_fill_menu_custom
+ * @menu_shell:
+ * @uiinfo:
+ * @uibdata:
+ * @accel_group:
+ * @uline_accels:
+ * @pos:
+ *
+ * Description:
+ * Fills the specified menu shell with items created from the specified
+ * info, inserting them from item no. pos on and using the specified
+ * builder data -- this is intended for language bindings.
+ * The accel group will be used as the accel group for all newly created
+ * sub menus and serves as the global accel group for all menu item
+ * hotkeys. If it is passed as NULL, global hotkeys will be disabled.
+ * The uline_accels argument determines whether underline accelerators
+ * will be featured from the menu item labels.
+ **/
+
+void
+gnome_app_fill_menu_custom (GtkMenuShell       *menu_shell,
+			    GnomeUIInfo        *uiinfo, 
+			    GnomeUIBuilderData *uibdata,
+			    GtkAccelGroup      *accel_group, 
+			    gboolean            uline_accels,
+			    gint                pos)
+{
+	GnomeUIBuilderData *orig_uibdata;
+
+	g_return_if_fail (menu_shell != NULL);
+	g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
+	g_return_if_fail (uiinfo != NULL);
+	g_return_if_fail (uibdata != NULL);
+	g_return_if_fail (pos >= 0);
+
+	/* Store a pointer to the original uibdata so that we can use it for 
+	 * the subtrees */
+
+	orig_uibdata = uibdata;
+
+	for (; uiinfo->type != GNOME_APP_UI_ENDOFINFO; uiinfo++)
+		switch (uiinfo->type) {
+		case GNOME_APP_UI_BUILDER_DATA:
+			/* Set the builder data for subsequent entries in the 
+			 * current uiinfo array */
+			uibdata = uiinfo->moreinfo;
+			break;
+
+		case GNOME_APP_UI_HELP:
+			/* Create entries for the help topics */
+			pos = create_help_entries (menu_shell, uiinfo, pos);
+			break;
+
+		case GNOME_APP_UI_RADIOITEMS:
+			/* Create the radio item group */
+			pos = create_radio_menu_items (menu_shell, 
+					uiinfo->moreinfo, uibdata, accel_group, 
+					pos);
+			break;
+
+		case GNOME_APP_UI_SEPARATOR:
+		case GNOME_APP_UI_ITEM:
+		case GNOME_APP_UI_ITEM_CONFIGURABLE:
+		case GNOME_APP_UI_TOGGLEITEM:
+		case GNOME_APP_UI_SUBTREE:
+		case GNOME_APP_UI_SUBTREE_STOCK:
+			if (uiinfo->type == GNOME_APP_UI_SUBTREE_STOCK)
+				create_menu_item (menu_shell, uiinfo, FALSE,
+						  NULL, uibdata, 
+						  accel_group, uline_accels,
+						  pos);
+			else
+				create_menu_item (menu_shell, uiinfo, FALSE,
+						  NULL, uibdata, 
+						  accel_group, uline_accels,
+						  pos);
+			
+			if (uiinfo->type == GNOME_APP_UI_SUBTREE ||
+			    uiinfo->type == GNOME_APP_UI_SUBTREE_STOCK) {
+				/* Create the subtree for this item */
+
+				GtkWidget *menu;
+				GtkWidget *tearoff;
+
+				menu = gtk_menu_new ();
+				gtk_menu_item_set_submenu
+					(GTK_MENU_ITEM(uiinfo->widget), menu);
+				gtk_menu_set_accel_group (GTK_MENU (menu), accel_group);
+				gnome_app_fill_menu_custom
+					(GTK_MENU_SHELL (menu), 
+					 uiinfo->moreinfo, orig_uibdata, 
+					 accel_group, uline_accels, 0);
+				if (gnome_preferences_get_menus_have_tearoff ()) {
+					tearoff = gtk_tearoff_menu_item_new ();
+					gtk_widget_show (tearoff);
+					gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), tearoff);
+				}
+			}
+			pos++;
+			break;
+
+		case GNOME_APP_UI_INCLUDE:
+		        gnome_app_fill_menu_custom
+			  (menu_shell, 
+			   uiinfo->moreinfo, orig_uibdata,
+			   accel_group, uline_accels, pos);
+			break;
+
+		default:
+			g_warning ("Invalid GnomeUIInfo element type %d\n", 
+					(int) uiinfo->type);
+		}
+
+	/* Make the end item contain a pointer to the parent menu shell */
+
+	uiinfo->widget = GTK_WIDGET (menu_shell);
+
+#ifdef FIXME
+	/* Configure menu to gnome preferences, if possible.
+	 * (sync to gnome-app.c:gnome_app_set_menus) */
+	if (!gnome_preferences_get_menubar_relief () && GTK_IS_MENU_BAR (menu_shell))
+		gtk_menu_bar_set_shadow_type (GTK_MENU_BAR (menu_shell), GTK_SHADOW_NONE);
+#endif
+}
+
+
+/**
+ * gnome_app_create_menus
+ * @app: Pointer to GNOME app object.
+ * @uiinfo:
+ *
+ * Description:
+ * Constructs a menu bar and attaches it to the specified application
+ * window.
+ **/
+
+void
+gnome_app_create_menus (GnomeApp *app, GnomeUIInfo *uiinfo)
+{
+	GnomeUIBuilderData uibdata;
+
+	g_return_if_fail (app != NULL);
+	g_return_if_fail (GNOME_IS_APP (app));
+	g_return_if_fail (uiinfo != NULL);
+
+	uibdata.connect_func = do_ui_signal_connect;
+	uibdata.data = NULL;
+	uibdata.is_interp = FALSE;
+	uibdata.relay_func = NULL;
+	uibdata.destroy_func = NULL;
+
+	gnome_app_create_menus_custom (app, uiinfo, &uibdata);
+}
+
+
+/**
+ * gnome_app_create_menus_interp
+ * @app: Pointer to GNOME app object.
+ * @uiinfo:
+ * @relay_func:
+ * @data:
+ * @destroy_func:
+ *
+ * Description:
+ **/
+
+void
+gnome_app_create_menus_interp (GnomeApp *app, GnomeUIInfo *uiinfo, 
+		GtkCallbackMarshal relay_func, gpointer data, 
+		GtkDestroyNotify destroy_func)
+{
+	GnomeUIBuilderData uibdata;
+
+	g_return_if_fail (app != NULL);
+	g_return_if_fail (GNOME_IS_APP (app));
+	g_return_if_fail (uiinfo != NULL);
+
+	uibdata.connect_func = do_ui_signal_connect;
+	uibdata.data = data;
+	uibdata.is_interp = TRUE;
+	uibdata.relay_func = relay_func;
+	uibdata.destroy_func = destroy_func;
+
+	gnome_app_create_menus_custom (app, uiinfo, &uibdata);
+}
+
+
+/**
+ * gnome_app_create_menus_with_data
+ * @app: Pointer to GNOME app object.
+ * @uiinfo:
+ * @user_data:
+ *
+ * Description:
+ **/
+
+void
+gnome_app_create_menus_with_data (GnomeApp *app, GnomeUIInfo *uiinfo,
+				  gpointer user_data)
+{
+	GnomeUIBuilderData uibdata;
+
+	g_return_if_fail (app != NULL);
+	g_return_if_fail (GNOME_IS_APP (app));
+	g_return_if_fail (uiinfo != NULL);
+
+	uibdata.connect_func = do_ui_signal_connect;
+	uibdata.data = user_data;
+	uibdata.is_interp = FALSE;
+	uibdata.relay_func = NULL;
+	uibdata.destroy_func = NULL;
+
+	gnome_app_create_menus_custom (app, uiinfo, &uibdata);
+}
+
+static void
+gnome_app_set_tearoff_menu_titles(GnomeApp *app, GnomeUIInfo *uiinfo,
+				  char *above)
+{
+	int i;
+	char *ctmp = NULL, *ctmp2;
+
+	g_return_if_fail(above);
+	
+	for(i = 0; uiinfo[i].type != GNOME_APP_UI_ENDOFINFO; i++) {
+		int type;
+		
+		type = uiinfo[i].type;
+
+		if(type == GNOME_APP_UI_INCLUDE)
+		  {
+		    gnome_app_set_tearoff_menu_titles (app, uiinfo[i].moreinfo, above);
+		    continue;
+		  }
+
+		if (type == GNOME_APP_UI_SUBTREE_STOCK)
+			type = GNOME_APP_UI_SUBTREE;
+				
+		if(type != GNOME_APP_UI_SUBTREE
+		   || !uiinfo[i].widget)
+			continue;
+
+		if(!ctmp)
+			ctmp = g_alloca(strlen(above) + sizeof(" : ") + strlen(uiinfo[i].label)
+					+ 75 /* eek! Hope noone uses huge menu item names! */);
+		strcpy(ctmp, above);
+		strcat(ctmp, " : ");
+		strcat(ctmp, uiinfo[i].label);
+		
+		ctmp2 = ctmp;
+		while((ctmp2 = strchr(ctmp2, '_')))
+			g_memmove(ctmp2, ctmp2+1, strlen(ctmp2+1)+1);
+
+		gtk_menu_set_title(GTK_MENU(GTK_MENU_ITEM(uiinfo[i].widget)->submenu), ctmp);
+
+		gnome_app_set_tearoff_menu_titles(app, uiinfo[i].moreinfo, ctmp);
+	}
+}
+
+
+/**
+ * gnome_app_create_menus_custom
+ * @app: Pointer to GNOME app object.
+ * @uiinfo:
+ * @uibdata:
+ *
+ * Description:
+ **/
+
+void
+gnome_app_create_menus_custom (GnomeApp *app, GnomeUIInfo *uiinfo, 
+			       GnomeUIBuilderData *uibdata)
+{
+	GtkWidget *menubar;
+
+	g_return_if_fail (app != NULL);
+	g_return_if_fail (GNOME_IS_APP (app));
+	g_return_if_fail (uiinfo != NULL);
+	g_return_if_fail (uibdata != NULL);
+
+	menubar = gtk_menu_bar_new ();
+	gnome_app_set_menus (app, GTK_MENU_BAR (menubar));
+	gnome_app_fill_menu_custom (GTK_MENU_SHELL (menubar), uiinfo, uibdata, 
+				    app->accel_group, TRUE, 0);
+
+	if (gnome_preferences_get_menus_have_tearoff ()) {
+		gchar *app_name;
+
+		app_name = GTK_WINDOW (app)->title;
+		if (!app_name)
+			app_name = GNOME_APP (app)->name;
+		gnome_app_set_tearoff_menu_titles (app, uiinfo, app_name);
+	}
+}
+
+/* Creates a toolbar item appropriate for the SEPARATOR, ITEM, or TOGGLEITEM 
+ * types.  If the item is inside a radio group, then a pointer to the group's 
+ * trailing widget must be specified as well (*radio_group must be NULL for 
+ * the first item!).
+ */
+static void
+create_toolbar_item (GtkToolbar *toolbar, GnomeUIInfo *uiinfo, int is_radio, 
+		GtkWidget **radio_group, GnomeUIBuilderData *uibdata, 
+		GtkAccelGroup *accel_group)
+{
+	GtkWidget *pixmap;
+	GtkToolbarChildType type;
+
+	switch (uiinfo->type) {
+	case GNOME_APP_UI_SEPARATOR:
+		gtk_toolbar_append_space (toolbar);
+		uiinfo->widget = NULL; /* no meaningful widget for a space */
+		break;
+
+	case GNOME_APP_UI_ITEM:
+	case GNOME_APP_UI_TOGGLEITEM:
+		/* Create the icon */
+
+		pixmap = create_pixmap (uiinfo->pixmap_type, uiinfo->pixmap_info);
+
+		/* Create the toolbar item */
+
+		if (is_radio)
+			type = GTK_TOOLBAR_CHILD_RADIOBUTTON;
+		else if (uiinfo->type == GNOME_APP_UI_ITEM)
+			type = GTK_TOOLBAR_CHILD_BUTTON;
+		else
+			type = GTK_TOOLBAR_CHILD_TOGGLEBUTTON;
+
+		uiinfo->widget =
+			gtk_toolbar_append_element (toolbar,
+						    type,
+						    is_radio ? 
+						    *radio_group : NULL,
+						    L_(uiinfo->label),
+						    L_(uiinfo->hint),
+						    NULL,
+						    pixmap,
+						    NULL,
+						    NULL);
+
+		if (is_radio)
+			*radio_group = uiinfo->widget;
+
+		break;
+
+	default:
+		g_warning ("Invalid GnomeUIInfo type %d passed to "
+			   "create_toolbar_item()", (int) uiinfo->type);
+		return;
+	}
+
+	if (uiinfo->type == GNOME_APP_UI_SEPARATOR)
+		return; /* nothing more to do */
+
+	/* Set the accelerator and connect to the signal */
+
+	if (is_radio || (uiinfo->type == GNOME_APP_UI_TOGGLEITEM)) {
+		setup_accelerator (accel_group, uiinfo, "toggled", 0);
+		(* uibdata->connect_func) (uiinfo, "toggled", uibdata);
+	} else {
+		setup_accelerator (accel_group, uiinfo, "clicked", 0);
+		(* uibdata->connect_func) (uiinfo, "clicked", uibdata);
+	}
+}
+
+static void
+create_radio_toolbar_items (GtkToolbar *toolbar, GnomeUIInfo *uiinfo, 
+		GnomeUIBuilderData *uibdata, GtkAccelGroup *accel_group)
+{
+	GtkWidget *group;
+	gpointer orig_uibdata = uibdata;
+
+	group = NULL;
+
+	for (; uiinfo->type != GNOME_APP_UI_ENDOFINFO; uiinfo++)
+		switch (uiinfo->type) {
+		case GNOME_APP_UI_BUILDER_DATA:
+			uibdata = uiinfo->moreinfo;
+			break;
+
+		case GNOME_APP_UI_ITEM:
+			create_toolbar_item (toolbar, uiinfo, TRUE, &group, 
+					uibdata, accel_group);
+			break;
+
+		case GNOME_APP_UI_INCLUDE:
+		        create_radio_toolbar_items (toolbar, uiinfo->moreinfo, orig_uibdata, accel_group);
+		        break;
+
+		default:
+			g_warning ("GnomeUIInfo element type %d is not valid "
+				   "inside a toolbar radio item group",
+				   (int) uiinfo->type);
+		}
+}
+
+
+/**
+ * gnome_app_fill_toolbar
+ * @toolbar:
+ * @uiinfo:
+ * @accel_group:
+ *
+ * Description:
+ **/
+
+void
+gnome_app_fill_toolbar (GtkToolbar *toolbar, GnomeUIInfo *uiinfo, 
+		GtkAccelGroup *accel_group)
+{
+	GnomeUIBuilderData uibdata;
+
+	g_return_if_fail (toolbar != NULL);
+	g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
+	g_return_if_fail (uiinfo != NULL);
+
+	uibdata.connect_func = do_ui_signal_connect;
+	uibdata.data = NULL;
+	uibdata.is_interp = FALSE;
+	uibdata.relay_func = NULL;
+	uibdata.destroy_func = NULL;
+
+	gnome_app_fill_toolbar_custom (toolbar, uiinfo, &uibdata, accel_group);
+}
+
+
+/**
+ * gnome_app_fill_toolbar_with_data
+ * @toolbar:
+ * @uiinfo:
+ * @accel_group:
+ * @user_data:
+ *
+ * Description:
+ **/
+
+void
+gnome_app_fill_toolbar_with_data (GtkToolbar *toolbar, GnomeUIInfo *uiinfo, 
+				  GtkAccelGroup *accel_group, gpointer user_data)
+{
+	GnomeUIBuilderData uibdata;
+
+	g_return_if_fail (toolbar != NULL);
+	g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
+	g_return_if_fail (uiinfo != NULL);
+
+	uibdata.connect_func = do_ui_signal_connect;
+	uibdata.data = user_data;
+	uibdata.is_interp = FALSE;
+	uibdata.relay_func = NULL;
+	uibdata.destroy_func = NULL;
+
+	gnome_app_fill_toolbar_custom (toolbar, uiinfo, &uibdata, accel_group);
+}
+
+
+/**
+ * gnome_app_fill_toolbar_custom
+ * @toolbar:
+ * @uiinfo:
+ * @uibdata:
+ * @accel_group:
+ *
+ * Description:
+ **/
+
+void
+gnome_app_fill_toolbar_custom (GtkToolbar *toolbar, GnomeUIInfo *uiinfo, 
+		GnomeUIBuilderData *uibdata, GtkAccelGroup *accel_group)
+{
+	g_return_if_fail (toolbar != NULL);
+	g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
+	g_return_if_fail (uiinfo != NULL);
+	g_return_if_fail (uibdata != NULL);
+
+	for (; uiinfo->type != GNOME_APP_UI_ENDOFINFO; uiinfo++)
+		switch (uiinfo->type) {
+		case GNOME_APP_UI_INCLUDE:
+		        gnome_app_fill_toolbar_custom (toolbar, uiinfo->moreinfo, uibdata, accel_group);
+		        break;
+
+		case GNOME_APP_UI_BUILDER_DATA:
+			/* Set the builder data for subsequent entries in the 
+			 * current uiinfo array */
+			uibdata = uiinfo->moreinfo;
+			break;
+
+		case GNOME_APP_UI_RADIOITEMS:
+			/* Create the radio item group */
+			create_radio_toolbar_items (toolbar, uiinfo->moreinfo, 
+					uibdata, accel_group);
+			break;
+
+		case GNOME_APP_UI_SEPARATOR:
+		case GNOME_APP_UI_ITEM:
+		case GNOME_APP_UI_TOGGLEITEM:
+			create_toolbar_item (toolbar, uiinfo, FALSE, NULL, 
+					uibdata, accel_group);
+			break;
+
+		default:
+			g_warning ("Invalid GnomeUIInfo element type %d\n", 
+					(int) uiinfo->type);
+		}
+
+	/* Make the end item contain a pointer to the parent toolbar */
+
+	uiinfo->widget = GTK_WIDGET (toolbar);
+
+        gnome_app_setup_toolbar(toolbar, NULL);
+}
+
+/**
+ * gnome_app_create_toolbar
+ * @app: Pointer to GNOME app object.
+ * @uiinfo:
+ *
+ * Description:
+ * Constructs a toolbar and attaches it to the specified application
+ * window.
+ **/
+
+void
+gnome_app_create_toolbar (GnomeApp *app, GnomeUIInfo *uiinfo)
+{
+	GnomeUIBuilderData uibdata;
+
+	g_return_if_fail (app != NULL);
+	g_return_if_fail (GNOME_IS_APP (app));
+	g_return_if_fail (uiinfo != NULL);
+
+	uibdata.connect_func = do_ui_signal_connect;
+	uibdata.data = NULL;
+	uibdata.is_interp = FALSE;
+	uibdata.relay_func = NULL;
+	uibdata.destroy_func = NULL;
+
+	gnome_app_create_toolbar_custom (app, uiinfo, &uibdata);
+}
+
+/**
+ * gnome_app_create_toolbar_interp
+ * @app: Pointer to GNOME app object.
+ * @uiinfo:
+ * @relay_func:
+ * @data:
+ * @destroy_func:
+ *
+ * Description:
+ * Constructs a toolbar and attaches it to the specified application
+ * window -- this version is intended for language bindings.
+ **/
+
+void
+gnome_app_create_toolbar_interp (GnomeApp *app, GnomeUIInfo *uiinfo,
+				 GtkCallbackMarshal relay_func, gpointer data,
+				 GtkDestroyNotify destroy_func)
+{
+	GnomeUIBuilderData uibdata;
+
+	g_return_if_fail (app != NULL);
+	g_return_if_fail (GNOME_IS_APP (app));
+	g_return_if_fail (uiinfo != NULL);
+
+	uibdata.connect_func = do_ui_signal_connect;
+	uibdata.data = data;
+	uibdata.is_interp = TRUE;
+	uibdata.relay_func = relay_func;
+	uibdata.destroy_func = destroy_func;
+
+	gnome_app_create_toolbar_custom (app, uiinfo, &uibdata);
+}
+
+/**
+ * gnome_app_create_toolbar_with_data
+ * @app: Pointer to GNOME app object.
+ * @uiinfo:
+ * @user_data:
+ *
+ * Description:
+ * Constructs a toolbar, sets all the user data pointers to
+ * @user_data, and attaches it to @app.
+ **/
+
+void
+gnome_app_create_toolbar_with_data (GnomeApp *app, GnomeUIInfo *uiinfo, 
+		gpointer user_data)
+{
+	GnomeUIBuilderData uibdata;
+
+	g_return_if_fail (app != NULL);
+	g_return_if_fail (GNOME_IS_APP (app));
+	g_return_if_fail (uiinfo != NULL);
+
+	uibdata.connect_func = do_ui_signal_connect;
+	uibdata.data = user_data;
+	uibdata.is_interp = FALSE;
+	uibdata.relay_func = NULL;
+	uibdata.destroy_func = NULL;
+
+	gnome_app_create_toolbar_custom (app, uiinfo, &uibdata);
+}
+
+/**
+ * gnome_app_create_toolbar_custom
+ * @app: Pointer to GNOME app object.
+ * @uiinfo:
+ * @uibdata:
+ *
+ * Description:
+ * Constructs a toolbar and attaches it to the @app window,
+ * using @uibdata builder data -- intended for language bindings.
+ **/
+
+void
+gnome_app_create_toolbar_custom (GnomeApp *app, GnomeUIInfo *uiinfo, GnomeUIBuilderData *uibdata)
+{
+	GtkWidget *toolbar;
+
+	g_return_if_fail (app != NULL);
+	g_return_if_fail (GNOME_IS_APP (app));
+	g_return_if_fail (uiinfo != NULL);
+	g_return_if_fail (uibdata != NULL);
+
+	toolbar = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_BOTH);
+	gnome_app_fill_toolbar_custom(GTK_TOOLBAR (toolbar), uiinfo, uibdata, 
+			app->accel_group);
+	gnome_app_set_toolbar (app, GTK_TOOLBAR (toolbar));
+}
+
+/**
+ * g_strncmp_ignore_char
+ * @first: The first string to compare
+ * @second: The second string to compare
+ * @length: The length of the first string to consider (the length of
+ *          which string you're considering matters because this
+ *          includes copies of the ignored character) 
+ * @ignored: The character to ignore
+ *
+ * Description:
+ * Does a strcmp, only considering the first length characters of
+ * first, and ignoring the ignored character in both strings.
+ * Returns -1 if first comes before second in lexicographical order,
+ * Returns 0 if they're equivalent, and
+ * Returns 1 if the second comes before the first in lexicographical order.
+ **/
+
+static gint
+g_strncmp_ignore_char( const gchar *first, const gchar *second, gint length, gchar ignored )
+{
+        gint i, j;
+	for ( i = 0, j = 0; i < length; i++, j++ )
+	{
+                while ( first[i] == ignored && i < length ) i++;
+		while ( second[j] == ignored ) j++;
+		if ( i == length )
+		        return 0;
+		if ( first[i] < second[j] )
+		        return -1; 
+		if ( first[i] > second[j] )
+		        return 1;
+	}
+	return 0;
+}
+
+/* menu insertion/removal functions
+ * <jaka mocnik kiss uni-lj si>
+ *
+ * the path argument should be in the form "File/.../.../Something". "" will 
+ * insert the item as the first one in the menubar "File/" will insert it as 
+ * the first one in the File menu "File/Settings" will insert it after the 
+ * Setting item in the File menu use of "File/<Separator>" should be obvious. 
+ * However this stops after the first separator. I hope this explains use of 
+ * the insert/remove functions well enough.
+ */
+
+/**
+ * gnome_app_find_menu_pos
+ * @parent: Root menu shell widget containing menu items to be searched
+ * @path: Specifies the target menu item by menu path
+ * @pos: (output) returned item position
+ *
+ * Description:
+ * finds menu item described by path starting
+ * in the GtkMenuShell top and returns its parent GtkMenuShell and the
+ * position after this item in pos:  gtk_menu_shell_insert(p, w, pos)
+ * would then insert widget w in GtkMenuShell p right after the menu item
+ * described by path.
+ **/
+
+GtkWidget *
+gnome_app_find_menu_pos (GtkWidget *parent, const gchar *path, gint *pos)
+{
+	GtkBin *item;
+	gchar *label = NULL;
+	GList *children;
+	gchar *name_end;
+	gchar *part;
+	const gchar *transl;
+	gint p;
+	int  path_len;
+	int  stripped_path_len;
+	
+	g_return_val_if_fail (parent != NULL, NULL);
+	g_return_val_if_fail (path != NULL, NULL);
+	g_return_val_if_fail (pos != NULL, NULL);
+
+	children = GTK_MENU_SHELL (parent)->children;
+	
+	name_end = strchr(path, '/');
+	if(name_end == NULL)
+		path_len = strlen(path);
+	else
+		path_len = name_end - path;
+
+	if (path_len == 0) {
+
+	        if (children && GTK_IS_TEAROFF_MENU_ITEM(children->data))
+		        /* consider the position after the tear off item as the topmost one. */
+			*pos = 1;
+		else
+			*pos = 0;
+		return parent;
+	}
+
+	/* this ugly thing should fix the localization problems */
+	part = g_malloc(path_len + 1);
+	if(!part)
+	        return NULL;
+	strncpy(part, path, path_len);
+	part[path_len] = '\0';
+	transl = L_(part);
+	path_len = strlen(transl);
+
+	stripped_path_len = path_len;
+	for ( p = 0; p < path_len; p++ )
+	        if( transl[p] == '_' )
+		        stripped_path_len--;
+		
+	p = 0;
+
+	while (children){
+		item = GTK_BIN (children->data);
+		children = children->next;
+		label = NULL;
+		p++;
+		
+		if (GTK_IS_TEAROFF_MENU_ITEM(item))
+			label = NULL;
+		else if (!item->child)          /* this is a separator, right? */
+			label = "<Separator>";
+		else if (GTK_IS_LABEL (item->child))  /* a simple item with a label */
+			label = GTK_LABEL (item->child)->label;
+		else
+			label = NULL; /* something that we just can't handle */
+		if (label && (stripped_path_len == strlen (label)) &&
+		    (g_strncmp_ignore_char (transl, label, path_len, '_') == 0)){
+			if (name_end == NULL) {
+				*pos = p;
+				g_free(part);
+				return parent;
+			}
+			else if (GTK_MENU_ITEM (item)->submenu) {
+			        g_free(part);
+				return gnome_app_find_menu_pos
+					(GTK_MENU_ITEM (item)->submenu, 
+					 (gchar *)(name_end + 1), pos);
+			}
+			else {
+			        g_free(part);
+				return NULL;
+			}
+		}
+	}
+	
+	g_free(part);
+	return NULL;
+}
+
+
+/**
+ * gnome_app_remove_menus
+ * @app: Pointer to GNOME app object.
+ * @path:
+ * @items:
+ *
+ * Description: removes num items from the existing app's menu structure
+ * beginning with item described by path
+ **/
+
+void
+gnome_app_remove_menus(GnomeApp *app, const gchar *path, gint items)
+{
+	GtkWidget *parent, *child;
+	GList *children;
+	gint pos;
+	
+	g_return_if_fail (app != NULL);
+	g_return_if_fail (GNOME_IS_APP(app));
+	
+	/* find the first item (which is actually at position pos-1) to 
+	 * remove */
+	parent = gnome_app_find_menu_pos(app->menubar, path, &pos);
+	
+	/* in case of path ".../" remove the first item */
+  if(path[strlen(path) - 1] == '/')
+    pos++;
+	
+	if( parent == NULL ) {
+		g_warning("gnome_app_remove_menus: couldn't find first item to"
+			  " remove!");
+		return;
+	}
+	
+	/* remove items */
+	children = g_list_nth(GTK_MENU_SHELL(parent)->children, pos - 1);
+	while(children && items > 0) {
+		child = GTK_WIDGET(children->data);
+		children = children->next;
+    /* if this item contains a gtkaccellabel, we have to set its
+       accel_widget to NULL so that the item gets unrefed. */
+    if(GTK_IS_ACCEL_LABEL(GTK_BIN(child)->child))
+      gtk_accel_label_set_accel_widget(GTK_ACCEL_LABEL(GTK_BIN(child)->child), NULL);
+
+		gtk_container_remove(GTK_CONTAINER(parent), child);
+		items--;
+	}
+	
+	gtk_widget_queue_resize(parent);
+}
+
+
+/**
+ * gnome_app_remove_menu_range
+ * @app: Pointer to GNOME app object.
+ * @path:
+ * @start:
+ * @items:
+ *
+ * Description:
+ * Same as the gnome_app_remove_menus, except it removes the specified number
+ * of @items from the existing app's menu structure begining with item described
+ * by path, plus the number specified by @start - very useful for adding and
+ * removing Recent document items in the File menu.
+ **/
+
+void
+gnome_app_remove_menu_range (GnomeApp *app, const gchar *path, gint start, gint items)
+{
+	GtkWidget *parent, *child;
+	GList *children;
+	gint pos;
+	
+	g_return_if_fail (app != NULL);
+	g_return_if_fail (GNOME_IS_APP (app));
+
+	/* find the first item (which is actually at position pos-1) to remove */
+	parent = gnome_app_find_menu_pos (app->menubar, path, &pos);
+
+	/* in case of path ".../" remove the first item */
+	if (path [strlen (path) - 1] == '/')
+		pos++;
+
+	pos += start;
+  
+	if (parent == NULL){
+		g_warning("gnome_app_remove_menus: couldn't find first item to remove!");
+		return;
+	}
+
+	/* remove items */
+	children = g_list_nth (GTK_MENU_SHELL (parent)->children, pos - 1);
+	while (children && items > 0) {
+		child = GTK_WIDGET (children->data);
+		children = children->next;
+		/*
+		 * if this item contains a gtkaccellabel, we have to set its
+		 * accel_widget to NULL so that the item gets unrefed.
+		 */
+		if (GTK_IS_ACCEL_LABEL (GTK_BIN (child)->child))
+			gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (GTK_BIN (child)->child), NULL);
+		gtk_container_remove (GTK_CONTAINER (parent), child);
+		items--;
+	}
+
+	gtk_widget_queue_resize(parent);
+}
+
+/**
+ * gnome_app_insert_menus_custom
+ * @app: Pointer to GNOME app object.
+ * @path:
+ * @uiinfo:
+ * @uibdata:
+ *
+ * Description: inserts menus described by @uiinfo in existing app's menu
+ * structure right after the item described by @path.
+ **/
+
+void
+gnome_app_insert_menus_custom (GnomeApp *app, const gchar *path, 
+		GnomeUIInfo *uiinfo, GnomeUIBuilderData *uibdata)
+{
+	GtkWidget *parent;
+	gint pos;
+	
+	g_return_if_fail (app != NULL);
+	g_return_if_fail (GNOME_IS_APP(app));
+	g_return_if_fail (app->menubar != NULL);
+	
+	/* find the parent menushell and position for insertion of menus */
+	parent = gnome_app_find_menu_pos(app->menubar, path, &pos);
+	if(parent == NULL) {
+		g_warning("gnome_app_insert_menus_custom: couldn't find "
+			  "insertion point for menus!");
+		return;
+	}
+	
+	/* create menus and insert them */
+	gnome_app_fill_menu_custom (GTK_MENU_SHELL (parent), uiinfo, uibdata, 
+			app->accel_group, TRUE, pos);
+}
+
+
+/**
+ * gnome_app_insert_menus
+ * @app: Pointer to GNOME app object.
+ * @path:
+ * @menuinfo:
+ *
+ * Description:
+ **/
+
+void
+gnome_app_insert_menus (GnomeApp *app,
+			const gchar *path,
+			GnomeUIInfo *menuinfo)
+{
+	GnomeUIBuilderData uidata =
+	{
+		do_ui_signal_connect,
+		NULL, FALSE, NULL, NULL
+	};
+	
+	gnome_app_insert_menus_custom (app, path, menuinfo, &uidata);
+}
+
+
+/**
+ * gnome_app_insert_menus_with_data
+ * @app: Pointer to GNOME app object.
+ * @path:
+ * @menuinfo:
+ * @data:
+ *
+ * Description:
+ **/
+
+void
+gnome_app_insert_menus_with_data (GnomeApp *app, const gchar *path, 
+		GnomeUIInfo *menuinfo, gpointer data)
+{
+	GnomeUIBuilderData uidata =
+	{
+		do_ui_signal_connect,
+		NULL, FALSE, NULL, NULL
+	};
+	
+	uidata.data = data;
+	
+	gnome_app_insert_menus_custom (app, path, menuinfo, &uidata);
+}
+
+
+/**
+ * gnome_app_insert_menus_interp
+ * @app: Pointer to GNOME app object.
+ * @path:
+ * @menuinfo:
+ * @relay_func:
+ * @data:
+ * @destroy_func:
+ *
+ * Description:
+ **/
+
+void
+gnome_app_insert_menus_interp (GnomeApp *app, const gchar *path, 
+		GnomeUIInfo *menuinfo, GtkCallbackMarshal relay_func, 
+		gpointer data, GtkDestroyNotify destroy_func)
+{
+	GnomeUIBuilderData uidata =
+	{
+		do_ui_signal_connect,
+		NULL, FALSE, NULL, NULL
+	};
+	
+	uidata.data = data;
+	uidata.is_interp = TRUE;
+	uidata.relay_func = relay_func;
+	uidata.destroy_func = destroy_func;
+	
+	gnome_app_insert_menus_custom(app, path, menuinfo, &uidata);
+}
+
+#ifdef ENABLE_NLS
+const gchar *
+gnome_app_helper_gettext (const gchar *str)
+{
+	char *s;
+
+        s = gettext (str);
+	if ( s == str )
+	        s = dgettext (PACKAGE, str);
+
+	return s;
+}
+#endif
+
+static void
+set_bevels(GnomeDockItem *dock_item, gboolean bevels)
+{
+        if (bevels) {
+                gtk_container_set_border_width (GTK_CONTAINER (dock_item), 1);
+                gnome_dock_item_set_shadow_type (GNOME_DOCK_ITEM (dock_item),
+                                                 GTK_SHADOW_OUT);
+        } else {
+                gtk_container_set_border_width (GTK_CONTAINER (dock_item), 0);
+                gnome_dock_item_set_shadow_type (GNOME_DOCK_ITEM (dock_item),
+                                                 GTK_SHADOW_NONE);
+        }
+}
+
+static void
+dockitem_bevels_changed_notify(GConfClient            *client,
+                               guint                   cnxn_id,
+			       GConfEntry             *entry,
+                               gpointer                user_data)
+{
+        gboolean bevels = TRUE;
+        GtkWidget *w = user_data;
+        GnomeDockItem *dock_item = GNOME_DOCK_ITEM(w);
+	GConfValue *value = gconf_entry_get_value (entry);
+
+        if (value &&
+            value->type == GCONF_VALUE_BOOL) {
+                bevels = gconf_value_get_bool(value);
+        }
+
+        set_bevels(dock_item, bevels);
+}
+
+static void
+set_separators(GtkToolbar *toolbar, gboolean separators)
+{
+#ifdef FIXME
+        if (separators) {
+                gtk_toolbar_set_space_style (toolbar, GTK_TOOLBAR_SPACE_LINE);
+                gtk_toolbar_set_space_size (toolbar, GNOME_PAD_SMALL * 2);
+        } else {
+                gtk_toolbar_set_space_style (toolbar, GTK_TOOLBAR_SPACE_EMPTY);
+                gtk_toolbar_set_space_size (toolbar, GNOME_PAD_SMALL);
+        }
+#endif
+}
+
+static void
+toolbar_separators_changed_notify(GConfClient            *client,
+                                  guint                   cnxn_id,
+				  GConfEntry             *entry,
+                                  gpointer                user_data)
+{
+        gboolean separators = TRUE;
+        GtkWidget *w = user_data;
+        GtkToolbar *toolbar = GTK_TOOLBAR(w);
+	GConfValue *value = gconf_entry_get_value (entry);
+
+        if (value &&
+            value->type == GCONF_VALUE_BOOL) {
+                separators = gconf_value_get_bool(value);
+        }
+
+        set_separators(toolbar, separators);
+}
+
+static GConfEnumStringPair toolbar_reliefs[] = {
+        { GTK_RELIEF_NORMAL, "normal" },
+        { GTK_RELIEF_NONE, "none" },
+        { GTK_RELIEF_HALF, "half" }
+};
+
+static void
+toolbar_relief_changed_notify(GConfClient            *client,
+                              guint                   cnxn_id,
+			      GConfEntry             *entry,
+                              gpointer                user_data)
+{
+#ifdef FIXME
+        GtkReliefStyle style = GTK_RELIEF_NONE;
+        GtkWidget *w = user_data;
+        GtkToolbar *toolbar = GTK_TOOLBAR(w);
+	GConfValue *value = gconf_entry_get_value (entry);
+
+        if (value &&
+            value->type == GCONF_VALUE_STRING &&
+            gconf_value_get_string(value) != NULL) {
+                gconf_string_to_enum(toolbar_reliefs,
+                                     gconf_value_get_string(value),
+                                     (gint*)&style);
+        }
+
+        gtk_toolbar_set_button_relief(toolbar, style);
+#endif
+}
+
+static GConfEnumStringPair toolbar_styles[] = {
+        { GTK_TOOLBAR_TEXT, "text" },
+        { GTK_TOOLBAR_ICONS, "icons" },
+        { GTK_TOOLBAR_BOTH, "both" }
+};
+
+static void
+per_app_toolbar_style_changed_notify(GConfClient            *client,
+                                     guint                   cnxn_id,
+				     GConfEntry             *entry,
+                                     gpointer                user_data)
+{
+        GtkToolbarStyle style = GTK_TOOLBAR_BOTH;
+        GtkWidget *w = user_data;
+        GtkToolbar *toolbar = GTK_TOOLBAR(w);
+        gboolean got_it = FALSE;
+	GConfValue *value = gconf_entry_get_value (entry);
+
+        if (value &&
+            value->type == GCONF_VALUE_STRING &&
+            gconf_value_get_string(value) != NULL) {
+
+                if (gconf_string_to_enum(toolbar_styles,
+                                         gconf_value_get_string(value),
+                                         (gint*)&style)) {
+                        got_it = TRUE;
+                }
+        }
+
+        /* Fall back to global setting */
+        if (!got_it) {
+                gchar *str;
+
+                str = gconf_client_get_string(client,
+                                              "/desktop/gnome/toolbars/style",
+                                              NULL);
+
+                if (str) {
+                        gconf_string_to_enum(toolbar_styles,
+                                             str,
+                                             (gint*)&style);
+                        
+                        g_free(str);
+                }
+        }
+        
+        gtk_toolbar_set_style(toolbar, style);
+}
+
+/* FIXME FIXME FIXME */
+#define gnome_gconf_get_gnome_libs_settings_relative(p) NULL
+
+static void
+toolbar_style_changed_notify(GConfClient            *client,
+                             guint                   cnxn_id,
+			     GConfEntry             *entry,
+                             gpointer                user_data)
+{
+        GtkToolbarStyle style = GTK_TOOLBAR_BOTH;
+        GtkWidget *w = user_data;
+        GtkToolbar *toolbar = GTK_TOOLBAR(w);
+        gchar *per_app_key;
+        gchar *str;
+        gboolean got_it = FALSE;
+	GConfValue *value;
+
+        /* Check for app-specific override */
+        per_app_key = gnome_gconf_get_gnome_libs_settings_relative("toolbar-style");
+        str = gconf_client_get_string(client, per_app_key, NULL);
+        g_free(per_app_key);
+
+        if (str) {
+                if (gconf_string_to_enum(toolbar_styles,
+                                         str,
+                                         (gint*)&style)) {
+                        got_it = TRUE;
+                }
+                g_free(str);
+        }
+
+	value = gconf_entry_get_value (entry);
+
+        /* If no per-app setting use this new global setting */
+        if (!got_it &&
+            value &&
+            value->type == GCONF_VALUE_STRING &&
+            gconf_value_get_string(value) != NULL) {
+                gconf_string_to_enum(toolbar_styles,
+                                     gconf_value_get_string(value),
+                                     (gint*)&style);
+        }
+
+        gtk_toolbar_set_style(toolbar, style);
+}
+
+/**
+ * gnome_app_setup_toolbar
+ * @toolbar: Pointer to #GtkToolbar widget
+ * @dock_item: Pointer to a #GnomeDockItem the toolbar is inside, or NULL for none
+ *
+ * Description:
+ * Sets up a toolbar to use GNOME user preferences
+ **/
+
+void
+gnome_app_setup_toolbar (GtkToolbar *toolbar,
+                         GnomeDockItem *dock_item)
+{
+        GConfClient *conf;
+
+        conf = gconf_client_get_default();
+
+        g_object_ref (G_OBJECT (conf));
+        gtk_object_set_data_full(GTK_OBJECT(toolbar), gnome_app_helper_gconf_client,
+                                 conf, (GtkDestroyNotify)g_object_unref);
+        
+        /* Attach GConf settings */
+
+        if (dock_item != NULL) { /* Dock item bevel */
+                gboolean bevels = TRUE;
+                guint notify_id;
+
+		g_object_ref (G_OBJECT (conf));
+		gtk_object_set_data_full(GTK_OBJECT(dock_item), gnome_app_helper_gconf_client,
+					 conf, (GtkDestroyNotify)g_object_unref);
+                
+                bevels = gconf_client_get_bool(conf,
+                                               "/desktop/gnome/toolbars/bevels",
+                                               NULL);
+                
+                notify_id = gconf_client_notify_add(conf,
+                                                    "/desktop/gnome/toolbars/bevels",
+                                                    dockitem_bevels_changed_notify,
+                                                    dock_item, NULL, NULL);
+                
+                gtk_signal_connect(GTK_OBJECT(dock_item), "destroy",
+                                   GTK_SIGNAL_FUNC(remove_notify_cb),
+				   GINT_TO_POINTER(notify_id));
+
+                set_bevels(dock_item, bevels);
+        }
+        
+        { /* Toolbar line separators */
+                gboolean separators = TRUE;
+                guint notify_id;
+                
+                separators = gconf_client_get_bool(conf,
+                                                   "/desktop/gnome/toolbars/separators",
+                                                   NULL);
+                
+                notify_id = gconf_client_notify_add(conf,
+                                                    "/desktop/gnome/toolbars/separators",
+                                                    toolbar_separators_changed_notify,
+                                                    toolbar, NULL, NULL);
+
+                gtk_signal_connect(GTK_OBJECT(toolbar), "destroy",
+                                   GTK_SIGNAL_FUNC(remove_notify_cb),
+				   GINT_TO_POINTER(notify_id));
+
+                set_separators(toolbar, separators);
+        }
+        
+        { /* Toolbar button relief */
+                GtkReliefStyle relief_style = GTK_RELIEF_NONE;
+                guint notify_id;
+                gchar *str;
+                
+                str = gconf_client_get_string(conf,
+                                              "/desktop/gnome/toolbars/relief",
+                                              NULL);
+
+                if (str != NULL) {
+                        gconf_string_to_enum(toolbar_reliefs,
+                                             str,
+                                             (gint*)&relief_style);
+                        g_free(str);
+                }
+                
+                notify_id = gconf_client_notify_add(conf,
+                                                    "/desktop/gnome/toolbars/relief",
+                                                    toolbar_relief_changed_notify,
+                                                    toolbar, NULL, NULL);
+
+                gtk_signal_connect(GTK_OBJECT(toolbar), "destroy",
+                                   GTK_SIGNAL_FUNC(remove_notify_cb),
+				   GINT_TO_POINTER(notify_id));
+
+#ifdef FIXME
+                gtk_toolbar_set_button_relief (toolbar, relief_style);
+#endif
+        }
+        
+        { /* Toolbar Style */
+                /* This one is a lot more complex because
+                   we have a per-app setting that overrides
+                   the default global setting */
+                
+                GtkToolbarStyle toolbar_style = GTK_TOOLBAR_BOTH;
+                guint notify_id;
+                gchar *str;
+                gchar *per_app_key;
+                gboolean got_it = FALSE;
+
+                /* Try per-app key */
+                per_app_key = gnome_gconf_get_gnome_libs_settings_relative("toolbar-style");
+
+                str = gconf_client_get_string(conf,
+                                              per_app_key,
+                                              NULL);
+                
+                if (str &&
+                    gconf_string_to_enum(toolbar_styles,
+                                         str,
+                                         (gint*)&toolbar_style)) {
+                        got_it = TRUE;
+                }
+
+                g_free(str);
+
+                /* Try global default */
+                if (!got_it) {
+                        str = gconf_client_get_string(conf,
+                                                      "/desktop/gnome/toolbars/style",
+                                                      NULL);
+
+                        if (str != NULL) {
+                                gconf_string_to_enum(toolbar_styles,
+                                                     str,
+                                                     (gint*)&toolbar_style);
+                                g_free(str);
+                        }
+                }
+                
+                notify_id = gconf_client_notify_add(conf,
+                                                    "/desktop/gnome/toolbars/style",
+                                                    toolbar_style_changed_notify,
+                                                    toolbar, NULL, NULL);
+
+                gtk_signal_connect(GTK_OBJECT(toolbar), "destroy",
+                                   GTK_SIGNAL_FUNC(remove_notify_cb),
+				   GINT_TO_POINTER(notify_id));
+
+                notify_id = gconf_client_notify_add(conf,
+                                                    per_app_key,
+                                                    per_app_toolbar_style_changed_notify,
+                                                    toolbar, NULL, NULL);
+
+                gtk_signal_connect(GTK_OBJECT(toolbar), "destroy",
+                                   GTK_SIGNAL_FUNC(remove_notify_cb),
+				   GINT_TO_POINTER(notify_id));
+                
+                g_free(per_app_key);
+                
+                gtk_toolbar_set_style (toolbar, toolbar_style);
+        }
+}
+
diff --git a/libgnomeui/gnome-app-helper.h b/libgnomeui/gnome-app-helper.h
new file mode 100644
index 0000000..227ad9a
--- /dev/null
+++ b/libgnomeui/gnome-app-helper.h
@@ -0,0 +1,742 @@
+/*
+ * Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
+ * Copyright (C) 1998, 1999 Miguel de Icaza, Federico Mena, Chris Toshok.
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome 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.
+ *
+ * The Gnome 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 the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+ */
+/*
+ * Originally by Elliot Lee, with hacking by Chris Toshok for *_data,
+ * Marc Ewing added menu support, toggle and radio support, and I
+ * don't know what you other people did :) menu insertion/removal
+ * functions by Jaka Mocnik.  Standard menu items by George Lebl and
+ * Nat Friedman.
+ *
+ * Some subtree hackage (and possibly various justification hacks) by Justin 
+ * Maurer.
+ *
+ * Major cleanups and rearrangements by Federico Mena and Justin Maurer.  */
+
+#ifndef GNOME_APP_HELPER_H
+#define GNOME_APP_HELPER_H
+
+#include <gtk/gtkstatusbar.h>
+
+#include <libgnomeui/gnome-appbar.h>
+#include <libgnomeui/gnome-app.h>
+
+G_BEGIN_DECLS
+
+/* This module lets you easily create menus and toolbars for your 
+ * applications. You basically define a hierarchy of arrays of GnomeUIInfo 
+ * structures, and you later call the provided functions to create menu bars 
+ * or tool bars.
+ */
+
+/* These values identify the item type that a particular GnomeUIInfo structure 
+ * specifies */
+typedef enum {
+	GNOME_APP_UI_ENDOFINFO,		/* No more items, use it at the end of 
+					   an array */
+	GNOME_APP_UI_ITEM,		/* Normal item, or radio item if it is 
+					   inside a radioitems group */
+	GNOME_APP_UI_TOGGLEITEM,	/* Toggle (check box) item */
+	GNOME_APP_UI_RADIOITEMS,	/* Radio item group */
+	GNOME_APP_UI_SUBTREE,		/* Item that defines a 
+					   subtree/submenu */
+	GNOME_APP_UI_SEPARATOR,		/* Separator line (menus) or blank 
+					   space (toolbars) */
+	GNOME_APP_UI_HELP,		/* Create a list of help topics, 
+					   used in the Help menu */
+	GNOME_APP_UI_BUILDER_DATA,	/* Specifies the builder data for the 
+					   following entries, see code for 
+					   further info */
+	GNOME_APP_UI_ITEM_CONFIGURABLE, /* A configurable menu item. */
+	/* one should be careful when using 
+	 * gnome_app_create_*_[custom|interp|with_data]() functions with 
+	 * GnomeUIInfo arrays containing GNOME_APP_UI_BUILDER_DATA items since 
+	 * their GnomeUIBuilderData structures completely override the ones 
+	 * generated or supplied by the above functions. */
+	GNOME_APP_UI_SUBTREE_STOCK,	/* Item that defines a 
+					   subtree/submenu, same as GNOME_APP_UI_SUBTREE,
+					   but the texts should be looked up in the
+					   gnome-libs catalog
+					*/
+	GNOME_APP_UI_INCLUDE            /* almost like SUBTREE, but inserts items into the current menu/whatever. instead of
+					   making a submenu */
+} GnomeUIInfoType;
+
+/* If you insert a value into this enum it'll break configurations all
+   over the place.  Only append.  You should also append a matching
+   item in the default types near the top of gnome-app-helper.c */
+typedef enum {
+        /* 0 */
+        GNOME_APP_CONFIGURABLE_ITEM_NEW,
+        GNOME_APP_CONFIGURABLE_ITEM_OPEN,
+        GNOME_APP_CONFIGURABLE_ITEM_SAVE,
+        GNOME_APP_CONFIGURABLE_ITEM_SAVE_AS,
+        GNOME_APP_CONFIGURABLE_ITEM_REVERT,
+        GNOME_APP_CONFIGURABLE_ITEM_PRINT,
+        GNOME_APP_CONFIGURABLE_ITEM_PRINT_SETUP,
+        GNOME_APP_CONFIGURABLE_ITEM_CLOSE,
+        GNOME_APP_CONFIGURABLE_ITEM_EXIT,
+        GNOME_APP_CONFIGURABLE_ITEM_CUT,
+	/* 10 */
+        GNOME_APP_CONFIGURABLE_ITEM_COPY,
+        GNOME_APP_CONFIGURABLE_ITEM_PASTE,
+        GNOME_APP_CONFIGURABLE_ITEM_CLEAR,
+        GNOME_APP_CONFIGURABLE_ITEM_UNDO,
+        GNOME_APP_CONFIGURABLE_ITEM_REDO,
+        GNOME_APP_CONFIGURABLE_ITEM_FIND,
+        GNOME_APP_CONFIGURABLE_ITEM_FIND_AGAIN,
+        GNOME_APP_CONFIGURABLE_ITEM_REPLACE,
+        GNOME_APP_CONFIGURABLE_ITEM_PROPERTIES,
+        GNOME_APP_CONFIGURABLE_ITEM_PREFERENCES,
+	/* 20 */
+        GNOME_APP_CONFIGURABLE_ITEM_ABOUT,
+	GNOME_APP_CONFIGURABLE_ITEM_SELECT_ALL,
+	GNOME_APP_CONFIGURABLE_ITEM_NEW_WINDOW,
+	GNOME_APP_CONFIGURABLE_ITEM_CLOSE_WINDOW,
+	GNOME_APP_CONFIGURABLE_ITEM_NEW_GAME,
+	GNOME_APP_CONFIGURABLE_ITEM_PAUSE_GAME,
+	GNOME_APP_CONFIGURABLE_ITEM_RESTART_GAME,
+	GNOME_APP_CONFIGURABLE_ITEM_UNDO_MOVE,
+	GNOME_APP_CONFIGURABLE_ITEM_REDO_MOVE,
+	GNOME_APP_CONFIGURABLE_ITEM_HINT,
+	/* 30 */
+	GNOME_APP_CONFIGURABLE_ITEM_SCORES,
+	GNOME_APP_CONFIGURABLE_ITEM_END_GAME
+} GnomeUIInfoConfigurableTypes;
+
+
+/* These values identify the type of pixmap used in an item */
+typedef enum {
+	GNOME_APP_PIXMAP_NONE,		/* No pixmap specified */
+	GNOME_APP_PIXMAP_STOCK,		/* Use a stock pixmap (GnomeStock) */
+	GNOME_APP_PIXMAP_DATA,		/* Use a pixmap from inline xpm data */
+	GNOME_APP_PIXMAP_FILENAME	/* Use a pixmap from the specified 
+					   filename */
+} GnomeUIPixmapType;
+
+/* This is the structure that defines an item in a menu bar or toolbar.  The 
+ * idea is to create an array of such structures with the information needed 
+ * to create menus or toolbars.  The most convenient way to create such a 
+ * structure is to use the GNOMEUIINFO_* macros provided below. */
+typedef struct {
+	GnomeUIInfoType type;		/* Type of item */
+	gchar *label;			/* String to use in the label */
+	gchar *hint;			/* For toolbar items, the tooltip. For 
+					   menu items, the status bar message */
+	gpointer moreinfo;		/* For an item, toggleitem, or 
+					   radioitem, this is a pointer to the 
+					   function to call when the item is 
+					   activated. For a subtree, a pointer 
+					   to another array of GnomeUIInfo 
+					   structures. For a radioitem lead 
+					   entry, a pointer to an array of 
+					   GnomeUIInfo structures for the radio 
+					   item group. For a help item, 
+					   specifies the help node to load 
+					   (i.e. the application's identifier) 
+					   or NULL for the main program's name.
+					   For builder data, points to the 
+					   GnomeUIBuilderData structure for 
+					   the following items */
+	gpointer user_data;		/* Data pointer to pass to callbacks */
+	gpointer unused_data;		/* Reserved for future expansion, 
+					   should be NULL */
+	GnomeUIPixmapType pixmap_type;	/* Type of pixmap for the item */
+	gconstpointer pixmap_info;      /* Pointer to the pixmap information:
+					 *
+					 * For GNOME_APP_PIXMAP_STOCK, a 
+					 * pointer to the stock icon name.
+					 *
+					 * For GNOME_APP_PIXMAP_DATA, a 
+					 * pointer to the inline xpm data.
+					 *
+					 * For GNOME_APP_PIXMAP_FILENAME, a 
+					 * pointer to the filename string.
+					 */
+	guint accelerator_key;		/* Accelerator key, or 0 for none */
+	GdkModifierType ac_mods;	/* Mask of modifier keys for the 
+					   accelerator */
+
+	GtkWidget *widget;		/* Filled in by gnome_app_create*, you 
+					   can use this to tweak the widgets 
+					   once they have been created */
+} GnomeUIInfo;
+
+/* Callback data */
+
+#define GNOMEUIINFO_KEY_UIDATA		"uidata"
+#define GNOMEUIINFO_KEY_UIBDATA		"uibdata"
+
+/* Handy GnomeUIInfo macros */
+
+/* Used to terminate an array of GnomeUIInfo structures */
+#define GNOMEUIINFO_END			{ GNOME_APP_UI_ENDOFINFO, NULL, NULL, NULL, NULL, NULL,		\
+					  (GnomeUIPixmapType) 0, NULL, 0, (GdkModifierType) 0, NULL }
+
+/* Insert a separator line (on a menu) or a blank space (on a toolbar) */
+#define GNOMEUIINFO_SEPARATOR		{ GNOME_APP_UI_SEPARATOR, NULL, NULL, NULL, NULL, NULL,		\
+					  (GnomeUIPixmapType) 0, NULL, 0, (GdkModifierType) 0, NULL }
+
+/* Insert an item with an inline xpm icon */
+#define GNOMEUIINFO_ITEM(label, tooltip, callback, xpm_data) \
+	{ GNOME_APP_UI_ITEM, label, tooltip, (gpointer)callback, NULL, NULL, \
+		GNOME_APP_PIXMAP_DATA, xpm_data, 0, (GdkModifierType) 0, NULL}
+
+/* Insert an item with a stock icon */
+#define GNOMEUIINFO_ITEM_STOCK(label, tooltip, callback, stock_id) \
+	{ GNOME_APP_UI_ITEM, label, tooltip, (gpointer)callback, NULL, NULL, \
+		GNOME_APP_PIXMAP_STOCK, stock_id, 0, (GdkModifierType) 0, NULL }
+
+/* Insert an item with no icon */
+#define GNOMEUIINFO_ITEM_NONE(label, tooltip, callback) \
+	{ GNOME_APP_UI_ITEM, label, tooltip, (gpointer)callback, NULL, NULL, \
+		GNOME_APP_PIXMAP_NONE, NULL, 0, (GdkModifierType) 0, NULL }
+
+/* Insert an item with an inline xpm icon and a user data pointer */
+#define GNOMEUIINFO_ITEM_DATA(label, tooltip, callback, user_data, xpm_data) \
+	{ GNOME_APP_UI_ITEM, label, tooltip, (gpointer)callback, user_data, NULL, \
+		GNOME_APP_PIXMAP_DATA, xpm_data, 0, (GdkModifierType) 0, NULL }
+
+/* Insert a toggle item (check box) with an inline xpm icon */
+#define GNOMEUIINFO_TOGGLEITEM(label, tooltip, callback, xpm_data) \
+	{ GNOME_APP_UI_TOGGLEITEM, label, tooltip, (gpointer)callback, NULL, NULL, \
+		GNOME_APP_PIXMAP_DATA, xpm_data, 0, (GdkModifierType) 0, NULL }
+
+/* Insert a toggle item (check box) with an inline xpm icon and a user data pointer */
+#define GNOMEUIINFO_TOGGLEITEM_DATA(label, tooltip, callback, user_data, xpm_data)		\
+					{ GNOME_APP_UI_TOGGLEITEM, label, tooltip, (gpointer)callback,	\
+					  user_data, NULL, GNOME_APP_PIXMAP_DATA, xpm_data,	\
+					  0, (GdkModifierType) 0, NULL }
+
+/* Insert all the help topics based on the application's id */
+#define GNOMEUIINFO_HELP(app_name) \
+	{ GNOME_APP_UI_HELP, NULL, NULL, app_name, NULL, NULL, \
+		(GnomeUIPixmapType) 0, NULL, 0,	(GdkModifierType) 0, NULL }
+
+/* Insert a subtree (submenu) */
+#define GNOMEUIINFO_SUBTREE(label, tree) \
+	{ GNOME_APP_UI_SUBTREE, label, NULL, tree, NULL, NULL, \
+		(GnomeUIPixmapType) 0, NULL, 0,	(GdkModifierType) 0, NULL }
+
+/* Insert a subtree with a hint */
+#define GNOMEUIINFO_SUBTREE_HINT(label, hint, tree) \
+	{ GNOME_APP_UI_SUBTREE, label, hint, tree, NULL, NULL, \
+		(GnomeUIPixmapType) 0, NULL, 0,	(GdkModifierType) 0, NULL }
+
+/* Insert a subtree (submenu) with a stock icon */
+#define GNOMEUIINFO_SUBTREE_STOCK(label, tree, stock_id) \
+	{ GNOME_APP_UI_SUBTREE, label, NULL, tree, NULL, NULL, \
+		GNOME_APP_PIXMAP_STOCK, stock_id, 0, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_INCLUDE(tree) \
+	{ GNOME_APP_UI_INCLUDE, NULL, NULL, tree, NULL, NULL, \
+		(GnomeUIPixmapType) 0, NULL, 0,	(GdkModifierType) 0, NULL }
+
+/* Insert a list of radio items */
+#define GNOMEUIINFO_RADIOLIST(list) \
+	{ GNOME_APP_UI_RADIOITEMS, NULL, NULL, list, NULL, NULL, \
+		(GnomeUIPixmapType) 0, NULL, 0,	(GdkModifierType) 0, NULL }
+
+/* Insert a radio item with an inline xpm icon */
+#define GNOMEUIINFO_RADIOITEM(label, tooltip, callback, xpm_data) \
+	{ GNOME_APP_UI_ITEM, label, tooltip, (gpointer)callback, NULL, NULL, \
+		GNOME_APP_PIXMAP_DATA, xpm_data, 0, (GdkModifierType) 0, NULL }
+
+/* Insert a radio item with an inline xpm icon and a user data pointer */
+#define GNOMEUIINFO_RADIOITEM_DATA(label, tooltip, callback, user_data, xpm_data)		\
+					{ GNOME_APP_UI_ITEM, label, tooltip, (gpointer)callback,	\
+					  user_data, NULL, GNOME_APP_PIXMAP_DATA, xpm_data,	\
+					  0, (GdkModifierType) 0, NULL }
+					  
+/*
+ * Stock menu item macros for some common menu items.  Please see
+ * gnome-libs/devel-docs/suggestions.txt about GNOME menu standards.
+ */
+
+/*
+ * The 'File' menu
+ */
+
+/*
+ * Note: New item requires to to specify what is new, so you need
+ * to specify the document type, so you need to supply the label
+ * as well (it should start with "_New ")
+ */
+#define GNOMEUIINFO_MENU_NEW_ITEM(label, tip, cb, data)                     \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, label, tip,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_NEW, (GdkModifierType) 0, NULL }
+
+/* If you have more then one New type, use this tree */
+#define GNOMEUIINFO_MENU_NEW_SUBTREE(tree)                                  \
+        { GNOME_APP_UI_SUBTREE_STOCK, N_("_New"), NULL, tree, NULL, NULL,   \
+          GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_NEW,                     \
+          GNOME_KEY_NAME_NEW, GNOME_KEY_MOD_NEW, NULL }
+
+#define GNOMEUIINFO_MENU_OPEN_ITEM(cb, data)                                \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_OPEN, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_SAVE_ITEM(cb, data)                                \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_SAVE, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_SAVE_AS_ITEM(cb, data)                             \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_SAVE_AS, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_REVERT_ITEM(cb, data)                              \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_REVERT, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_PRINT_ITEM(cb, data)                               \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_PRINT, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_PRINT_SETUP_ITEM(cb, data)                         \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_PRINT_SETUP, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_CLOSE_ITEM(cb, data)                               \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_CLOSE, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_EXIT_ITEM(cb, data)                                \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_EXIT, (GdkModifierType) 0, NULL }
+/*
+ * The "Edit" menu
+ */
+
+#define GNOMEUIINFO_MENU_CUT_ITEM(cb, data)                                 \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_CUT, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_COPY_ITEM(cb, data)                                \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_COPY, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_PASTE_ITEM(cb, data)                               \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_PASTE, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_SELECT_ALL_ITEM(cb, data)                          \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_SELECT_ALL, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_CLEAR_ITEM(cb, data)                               \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_CLEAR, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_UNDO_ITEM(cb, data)                                \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_UNDO, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_REDO_ITEM(cb, data)                                \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_REDO, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_FIND_ITEM(cb, data)                                \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_FIND, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_FIND_AGAIN_ITEM(cb, data)                          \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_FIND_AGAIN, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_REPLACE_ITEM(cb, data)                             \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_REPLACE, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_PROPERTIES_ITEM(cb, data)                          \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_PROPERTIES, (GdkModifierType) 0, NULL }
+
+/*
+ * The Settings menu
+ */
+#define GNOMEUIINFO_MENU_PREFERENCES_ITEM(cb, data)                         \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_PREFERENCES, (GdkModifierType) 0, NULL }
+
+/*
+ * The Windows menu
+ */
+#define GNOMEUIINFO_MENU_NEW_WINDOW_ITEM(cb, data)                          \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_NEW_WINDOW, (GdkModifierType) 0, NULL }
+
+#define GNOMEUIINFO_MENU_CLOSE_WINDOW_ITEM(cb, data)                        \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_CLOSE_WINDOW, (GdkModifierType) 0, NULL }
+
+/*
+ * And the "Help" menu
+ */
+#define GNOMEUIINFO_MENU_ABOUT_ITEM(cb, data)                               \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_ABOUT, (GdkModifierType) 0, NULL }
+
+/* 
+ * The "Game" menu
+ */
+
+#define GNOMEUIINFO_MENU_NEW_GAME_ITEM(cb, data)                            \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_NEW_GAME, (GdkModifierType) 0, NULL }
+	  
+#define GNOMEUIINFO_MENU_PAUSE_GAME_ITEM(cb, data)                          \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_PAUSE_GAME, (GdkModifierType) 0, NULL }
+	  
+#define GNOMEUIINFO_MENU_RESTART_GAME_ITEM(cb, data)                        \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_RESTART_GAME, (GdkModifierType) 0, NULL }
+	  
+#define GNOMEUIINFO_MENU_UNDO_MOVE_ITEM(cb, data)                           \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_UNDO_MOVE, (GdkModifierType) 0, NULL }
+	  
+#define GNOMEUIINFO_MENU_REDO_MOVE_ITEM(cb, data)                           \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_REDO_MOVE, (GdkModifierType) 0, NULL }
+	  
+#define GNOMEUIINFO_MENU_HINT_ITEM(cb, data)                                \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_HINT, (GdkModifierType) 0, NULL }
+	  
+#define GNOMEUIINFO_MENU_SCORES_ITEM(cb, data)                              \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_SCORES, (GdkModifierType) 0, NULL }
+	  
+#define GNOMEUIINFO_MENU_END_GAME_ITEM(cb, data)                            \
+        { GNOME_APP_UI_ITEM_CONFIGURABLE, NULL, NULL,                       \
+          (gpointer)cb, (gpointer)(data), NULL,                             \
+          GNOME_APP_PIXMAP_NONE, NULL,                                      \
+          GNOME_APP_CONFIGURABLE_ITEM_END_GAME, (GdkModifierType) 0, NULL }
+
+const gchar * gnome_app_helper_gettext (const gchar *string);
+
+#ifdef ENABLE_NLS
+#define D_(x) dgettext (PACKAGE, x)
+#define L_(x) gnome_app_helper_gettext(x)
+#else
+#define D_(x) x
+#define L_(x) x
+#endif
+
+/* Some standard menus */
+#define GNOMEUIINFO_MENU_FILE_TREE(tree) \
+	{ GNOME_APP_UI_SUBTREE_STOCK, N_("_File"), NULL, tree, NULL, NULL, \
+		(GnomeUIPixmapType) 0, NULL, 0,	(GdkModifierType) 0, NULL }
+#define GNOMEUIINFO_MENU_EDIT_TREE(tree) \
+	{ GNOME_APP_UI_SUBTREE_STOCK, N_("_Edit"), NULL, tree, NULL, NULL, \
+		(GnomeUIPixmapType) 0, NULL, 0,	(GdkModifierType) 0, NULL }
+#define GNOMEUIINFO_MENU_VIEW_TREE(tree) \
+	{ GNOME_APP_UI_SUBTREE_STOCK, N_("_View"), NULL, tree, NULL, NULL, \
+		(GnomeUIPixmapType) 0, NULL, 0,	(GdkModifierType) 0, NULL }
+#define GNOMEUIINFO_MENU_SETTINGS_TREE(tree) \
+	{ GNOME_APP_UI_SUBTREE_STOCK, N_("_Settings"), NULL, tree, NULL, NULL, \
+		(GnomeUIPixmapType) 0, NULL, 0,	(GdkModifierType) 0, NULL }
+#define GNOMEUIINFO_MENU_FILES_TREE(tree) \
+	{ GNOME_APP_UI_SUBTREE_STOCK, N_("Fi_les"), NULL, tree, NULL, NULL, \
+		(GnomeUIPixmapType) 0, NULL, 0,	(GdkModifierType) 0, NULL }
+#define GNOMEUIINFO_MENU_WINDOWS_TREE(tree) \
+	{ GNOME_APP_UI_SUBTREE_STOCK, N_("_Windows"), NULL, tree, NULL, NULL, \
+		(GnomeUIPixmapType) 0, NULL, 0,	(GdkModifierType) 0, NULL }
+#define GNOMEUIINFO_MENU_HELP_TREE(tree) \
+	{ GNOME_APP_UI_SUBTREE_STOCK, N_("_Help"), NULL, tree, NULL, NULL, \
+		(GnomeUIPixmapType) 0, NULL, 0,	(GdkModifierType) 0, NULL }
+#define GNOMEUIINFO_MENU_GAME_TREE(tree) \
+	{ GNOME_APP_UI_SUBTREE_STOCK, N_("_Game"), NULL, tree, NULL, NULL, \
+		(GnomeUIPixmapType) 0, NULL, 0,	(GdkModifierType) 0, NULL }
+		
+/*these are strings to be used for paths when working with the menus stuff*/
+#define GNOME_MENU_FILE_STRING D_("_File")
+#define GNOME_MENU_FILE_PATH D_("_File/")
+#define GNOME_MENU_EDIT_STRING D_("_Edit")
+#define GNOME_MENU_EDIT_PATH D_("_Edit/")
+#define GNOME_MENU_VIEW_STRING D_("_View")
+#define GNOME_MENU_VIEW_PATH D_("_View/")
+#define GNOME_MENU_SETTINGS_STRING D_("_Settings")
+#define GNOME_MENU_SETTINGS_PATH D_("_Settings/")
+#define GNOME_MENU_NEW_STRING D_("_New")
+#define GNOME_MENU_NEW_PATH D_("_New/")
+#define GNOME_MENU_FILES_STRING D_("Fi_les")
+#define GNOME_MENU_FILES_PATH D_("Fi_les/")
+#define GNOME_MENU_WINDOWS_STRING D_("_Windows")
+#define GNOME_MENU_WINDOWS_PATH D_("_Windows/")
+
+
+/* Types useful to language bindings */
+    
+typedef struct _GnomeUIBuilderData GnomeUIBuilderData;
+
+typedef void (* GnomeUISignalConnectFunc) (GnomeUIInfo        *uiinfo,
+					   const char         *signal_name,
+					   GnomeUIBuilderData *uibdata);
+
+struct _GnomeUIBuilderData {
+	GnomeUISignalConnectFunc connect_func;	/* Function that connects to the item's signals */
+	gpointer data;				/* User data pointer */
+	gboolean is_interp;			/* Should use gtk_signal_connect_interp or normal gtk_signal_connect? */
+	GtkCallbackMarshal relay_func;		/* Marshaller function for language bindings */
+	GtkDestroyNotify destroy_func;		/* Destroy notification function for language bindings */
+};
+
+/* Flush the accelerator definitions into the application specific
+ * configuration file ~/.gnome/accels/<app-id>.
+ */
+void gnome_accelerators_sync (void);
+     
+
+/* Fills the specified menu shell with items created from the specified
+ * info, inserting them from the item no. pos on.
+ * The accel group will be used as the accel group for all newly created
+ * sub menus and serves as the global accel group for all menu item
+ * hotkeys. If it is passed as NULL, global hotkeys will be disabled.
+ * The uline_accels argument determines whether underline accelerators
+ * will be featured from the menu item labels.
+ */
+void gnome_app_fill_menu (GtkMenuShell	*menu_shell,
+			  GnomeUIInfo	*uiinfo,
+			  GtkAccelGroup	*accel_group,
+			  gboolean	 uline_accels,
+			  gint		 pos);
+
+/* Same as gnome_app_fill_menu, but sets all the user data pointers to
+ * the specified value.
+ */
+void gnome_app_fill_menu_with_data (GtkMenuShell	*menu_shell,
+				    GnomeUIInfo		*uiinfo,
+				    GtkAccelGroup	*accel_group,
+				    gboolean		 uline_accels,
+				    gint		 pos,
+				    gpointer		 user_data);
+
+/* Fills the specified menu shell with items created from the specified
+ * info, inserting them from item no. pos on and using the specified
+ * builder data -- this is intended for language bindings.
+ * The accel group will be used as the accel group for all newly created
+ * sub menus and serves as the global accel group for all menu item
+ * hotkeys. If it is passed as NULL, global hotkeys will be disabled.
+ * The uline_accels argument determines whether underline accelerators
+ * will be featured from the menu item labels.
+ */
+void gnome_app_fill_menu_custom (GtkMenuShell	    *menu_shell,
+				 GnomeUIInfo	    *uiinfo,
+				 GnomeUIBuilderData *uibdata,
+				 GtkAccelGroup	    *accel_group,
+				 gboolean	     uline_accels,
+				 gint		     pos);
+
+/* Converts GNOME_APP_UI_ITEM_CONFIGURABLE menu GnomeUIInfos to the
+   corresponding standard GNOME_APP_UI_ITEMs.  gnome_app_create_menus
+   calls this for you, but if you need to alter something afterwards,
+   you can call this function first.  The main reason for this being a
+   public interface is so that it can be called from
+   gnome_popup_menu_new which clears a copy of the passed
+   GnomeUIInofs. */
+void gnome_app_ui_configure_configurable (GnomeUIInfo* uiinfo);
+
+
+/* Constructs a menu bar and attaches it to the specified application window */
+void gnome_app_create_menus (GnomeApp *app, GnomeUIInfo *uiinfo);
+
+/* Constructs a menu bar and attaches it to the specified application window -- this version is
+ * intended for language bindings.
+ */
+void gnome_app_create_menus_interp (GnomeApp *app, GnomeUIInfo *uiinfo,
+				    GtkCallbackMarshal relay_func, gpointer data,
+				    GtkDestroyNotify destroy_func);
+
+/* Constructs a menu bar, sets all the user data pointers to the specified value, and attaches it to
+ * the specified application window.
+ */
+void gnome_app_create_menus_with_data (GnomeApp *app, GnomeUIInfo *uiinfo, gpointer user_data);
+
+/* Constructs a menu bar and attaches it to the specified application window, using the
+ * specified builder data -- intended for language bindings.
+ */
+void gnome_app_create_menus_custom (GnomeApp *app, GnomeUIInfo *uiinfo, GnomeUIBuilderData *uibdata);
+
+/* Fills the specified toolbar with buttons created from the specified info.  If accel_group is not
+ * NULL, then the items' accelerator keys are put into it.
+ */
+void gnome_app_fill_toolbar (GtkToolbar *toolbar, GnomeUIInfo *uiinfo, GtkAccelGroup *accel_group);
+
+/* Same as gnome_app_fill_toolbar, but sets all the user data pointers
+ * to the specified value.
+ */
+void gnome_app_fill_toolbar_with_data (GtkToolbar *toolbar, GnomeUIInfo *uiinfo,
+				       GtkAccelGroup *accel_group, gpointer user_data);
+
+/* Fills the specified toolbar with buttons created from the specified info, using the specified
+ * builder data -- this is intended for language bindings.  If accel_group is not NULL, then the
+ * items' accelerator keys are put into it.
+ */
+void gnome_app_fill_toolbar_custom (GtkToolbar *toolbar, GnomeUIInfo *uiinfo, GnomeUIBuilderData *uibdata,
+				    GtkAccelGroup *accel_group);
+
+/* Constructs a toolbar and attaches it to the specified application window */
+void gnome_app_create_toolbar (GnomeApp *app, GnomeUIInfo *uiinfo);
+
+/* Constructs a toolbar and attaches it to the specified application window -- this version is
+ * intended for language bindings.
+ */
+void gnome_app_create_toolbar_interp (GnomeApp *app, GnomeUIInfo *uiinfo,
+				      GtkCallbackMarshal relay_func, gpointer data,
+				      GtkDestroyNotify destroy_func);
+
+/* Constructs a toolbar, sets all the user data pointers to the specified value, and attaches it to
+ * the specified application window.
+ */
+void gnome_app_create_toolbar_with_data (GnomeApp *app, GnomeUIInfo *uiinfo, gpointer user_data);
+
+/* Constructs a toolbar and attaches it to the specified application window, using the specified
+ * builder data -- intended for language bindings.
+ */
+void gnome_app_create_toolbar_custom (GnomeApp *app, GnomeUIInfo *uiinfo, GnomeUIBuilderData *uibdata);
+
+/* finds menu item described by path (see below for details) starting in the GtkMenuShell top
+ * and returns its parent GtkMenuShell and the position after this item in pos:
+ * gtk_menu_shell_insert(p, w, pos) would then insert widget w in GtkMenuShell p right after
+ * the menu item described by path.
+ * the path argument should be in the form "File/.../.../Something".
+ * "" will insert the item as the first one in the menubar
+ * "File/" will insert it as the first one in the File menu
+ * "File/Settings" will insert it after the Setting item in the File menu
+ * use of  "File/<Separator>" should be obvious. however this stops after the first separator.
+ */
+GtkWidget *gnome_app_find_menu_pos (GtkWidget *parent, const gchar *path, gint *pos);
+
+/* removes num items from the existing app's menu structure begining with item described
+ * by path
+ */
+void gnome_app_remove_menus (GnomeApp *app, const gchar *path, gint items);
+
+/* Same as the above, except it removes the specified number of items 
+ * from the existing app's menu structure begining with item described by path,
+ * plus the number specified by start - very useful for adding and removing Recent
+ * document items in the File menu.
+ */
+void gnome_app_remove_menu_range (GnomeApp *app, const gchar *path, gint start, gint items);
+
+/* inserts menus described by uiinfo in existing app's menu structure right after the item described by path.
+ */
+void gnome_app_insert_menus_custom (GnomeApp *app, const gchar *path, GnomeUIInfo *menuinfo, GnomeUIBuilderData *uibdata);
+
+/* FIXME: what does it do? */
+void gnome_app_insert_menus (GnomeApp *app, const gchar *path, GnomeUIInfo *menuinfo);
+
+/* FIXME: what does it do? */
+void gnome_app_insert_menus_with_data (GnomeApp *app, const gchar *path, GnomeUIInfo *menuinfo, gpointer data);
+
+/* FIXME: what does it do? */
+void gnome_app_insert_menus_interp (GnomeApp *app, const gchar *path, GnomeUIInfo *menuinfo,
+				    GtkCallbackMarshal relay_func, gpointer data,
+				    GtkDestroyNotify destroy_func);
+
+
+/* Activate the menu item hints, displaying in the given appbar.
+   This can't be automatic since we can't reliably find the 
+   appbar. */
+void gnome_app_install_appbar_menu_hints    (GnomeAppBar* appbar,
+                                             GnomeUIInfo* uiinfo);
+
+void gnome_app_install_statusbar_menu_hints (GtkStatusbar* bar,
+                                             GnomeUIInfo* uiinfo);
+
+/* really? why can't it be automatic? */
+void gnome_app_install_menu_hints           (GnomeApp *app,
+                                             GnomeUIInfo *uinfo);
+
+void gnome_app_setup_toolbar                (GtkToolbar *toolbar,
+                                             GnomeDockItem *dock_item);
+
+G_END_DECLS
+
+#endif
diff --git a/libgnomeui/gnome-app-util.c b/libgnomeui/gnome-app-util.c
new file mode 100644
index 0000000..08f2c0e
--- /dev/null
+++ b/libgnomeui/gnome-app-util.c
@@ -0,0 +1,985 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome 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.
+ *
+ * The Gnome 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 the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+ */
+#include <config.h>
+
+#include "gnome-app-util.h"
+
+#include <libgnome/gnome-i18n.h>
+#include <libgnome/gnome-util.h>
+
+#include "gnome-stock.h"
+#include "gnome-dialog-util.h"
+#include "gnome-dialog.h"
+#include "gnome-uidefs.h"
+#include "gnome-preferences.h"
+#include "gnome-appbar.h"
+
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+static gboolean 
+gnome_app_has_appbar_progress(GnomeApp * app)
+{
+  return ( (app->statusbar != NULL) &&
+	   (GNOME_APPBAR_HAS_PROGRESS(app->statusbar)) );
+}
+
+static gboolean 
+gnome_app_has_appbar_status(GnomeApp * app)
+{
+  return ( (app->statusbar != NULL) &&
+	   (GNOME_APPBAR_HAS_STATUS(app->statusbar)) );
+}
+
+static gboolean
+gnome_app_interactive_statusbar(GnomeApp * app)
+{
+ return ( gnome_app_has_appbar_status (app) && 
+	  gnome_preferences_get_statusbar_dialog() &&
+	  gnome_preferences_get_statusbar_interactive() );
+}
+
+static void gnome_app_activate_statusbar(GnomeApp *app)
+{
+  gtk_window_set_focus(GTK_WINDOW(app),
+		       gnome_appbar_get_status(GNOME_APPBAR(app->statusbar)));
+  gtk_window_activate_focus(GTK_WINDOW(app));
+  gdk_window_raise(GTK_WIDGET(app)->window);
+}
+
+/* ================================================================== */
+
+/* =================================================================== */
+/* Simple messages */
+
+static void
+ack_cb(GnomeAppBar * bar, gpointer data)
+{
+  gnome_appbar_clear_prompt(bar);
+}
+
+static void
+ack_clear_prompt_cb(GnomeAppBar * bar, gpointer data)
+{
+#ifdef GNOME_ENABLE_DEBUG
+  g_print("Clearing prompt (ack)\n");
+#endif
+
+  gtk_signal_disconnect_by_func(GTK_OBJECT(bar), 
+				GTK_SIGNAL_FUNC(ack_cb),
+				data);
+  gtk_signal_disconnect_by_func(GTK_OBJECT(bar), 
+				GTK_SIGNAL_FUNC(ack_clear_prompt_cb),
+				data);
+}
+
+static void gnome_app_message_bar (GnomeApp * app, const gchar * message)
+{
+  gchar * prompt = g_strconcat(message, _(" (press return)"), NULL);
+  gnome_appbar_set_prompt(GNOME_APPBAR(app->statusbar), prompt, FALSE);
+  gnome_app_activate_statusbar(app);
+  g_free(prompt);
+  gtk_signal_connect(GTK_OBJECT(app->statusbar), "user_response",
+		     GTK_SIGNAL_FUNC(ack_cb), NULL);
+  gtk_signal_connect(GTK_OBJECT(app->statusbar), "clear_prompt",
+		     GTK_SIGNAL_FUNC(ack_clear_prompt_cb), NULL);
+}
+
+
+/**
+ * gnome_app_message
+ * @app: Pointer to GNOME app object
+ * @message: Text of message to be displayed
+ *
+ * Description: A simple message, in an OK dialog or the status bar.
+ * Requires confirmation from the user before it goes away.
+ *
+ * Returns:
+ * Pointer to dialog widget, or %NULL if error or message in
+ * status bar.
+ **/
+
+GtkWidget *
+gnome_app_message (GnomeApp * app, const gchar * message)
+{
+  g_return_val_if_fail(app != NULL, NULL);
+  g_return_val_if_fail(GNOME_IS_APP(app), NULL);
+
+  if ( gnome_preferences_get_statusbar_dialog() &&
+       gnome_app_interactive_statusbar(app) ) {
+    gnome_app_message_bar ( app, message );
+    return NULL;
+  }
+  else {
+    return gnome_ok_dialog_parented(message,GTK_WINDOW(app));
+  }
+}
+
+static void 
+gnome_app_error_bar(GnomeApp * app, const gchar * error)
+{
+  gchar * s = g_strconcat(_("ERROR: "), error, NULL);
+  gdk_beep();
+  gnome_app_message_bar(app, s);
+  g_free(s);
+}
+
+
+/**
+ * gnome_app_error
+ * @app: Pointer to GNOME app object
+ * @error: Text of error message to be displayed
+ *
+ * Description:
+ * An important fatal error; if it appears in the statusbar, 
+ * it might gdk_beep() and require acknowledgement.
+ *
+ * Returns:
+ * Pointer to dialog widget, or %NULL if error or message in
+ * status bar.
+ **/
+
+GtkWidget * 
+gnome_app_error (GnomeApp * app, const gchar * error)
+{
+  g_return_val_if_fail(app != NULL, NULL);
+  g_return_val_if_fail(GNOME_IS_APP(app), NULL);
+  g_return_val_if_fail(error != NULL, NULL);
+
+  if ( gnome_app_interactive_statusbar(app) ) {
+    gnome_app_error_bar(app, error);
+    return NULL;
+  }
+  else return gnome_error_dialog_parented (error,GTK_WINDOW(app));
+}
+
+static void gnome_app_warning_bar (GnomeApp * app, const gchar * warning)
+{
+  gchar * s = g_strconcat(_("Warning: "), warning, NULL);
+  gdk_beep();
+  gnome_app_flash(app, s);
+  g_free(s);
+}
+
+
+/**
+ * gnome_app_warning
+ * @app: Pointer to GNOME app object
+ * @warning: Text of warning message to be displayed
+ *
+ * Description:
+ * A not-so-important error, but still marked better than a flash
+ *
+ * Returns:
+ * Pointer to dialog widget, or %NULL if error or message in
+ * status bar.
+ **/
+
+GtkWidget * 
+gnome_app_warning (GnomeApp * app, const gchar * warning)
+{
+  g_return_val_if_fail(app != NULL, NULL);
+  g_return_val_if_fail(GNOME_IS_APP(app), NULL);
+  g_return_val_if_fail(warning != NULL, NULL);
+
+  if ( gnome_app_has_appbar_status(app) && 
+       gnome_preferences_get_statusbar_dialog() ) {
+    gnome_app_warning_bar(app, warning);
+    return NULL;
+  }
+  else {
+    return gnome_warning_dialog_parented(warning,GTK_WINDOW(app));
+  }
+}
+
+/* =================================================== */
+/* Flash */
+
+struct _MessageInfo {
+  GnomeApp * app;
+  guint timeoutid;
+  guint handlerid;
+};
+
+typedef struct _MessageInfo MessageInfo;
+
+static gint
+remove_message_timeout (MessageInfo * mi) 
+{
+  GDK_THREADS_ENTER ();	
+	
+  gnome_appbar_refresh(GNOME_APPBAR(mi->app->statusbar));
+  gtk_signal_disconnect(GTK_OBJECT(mi->app), mi->handlerid);
+  g_free ( mi );
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE; /* removes the timeout */
+}
+
+/* Called if the app is destroyed before the timeout occurs. */
+static void
+remove_timeout_cb ( GtkWidget * app, MessageInfo * mi ) 
+{
+  gtk_timeout_remove(mi->timeoutid);
+  g_free(mi);
+}
+
+static const guint32 flash_length = 3000; /* 3 seconds, I hope */
+
+
+/**
+ * gnome_app_flash
+ * @app: Pointer to GNOME app object
+ * @flash: Text of message to be flashed
+ *
+ * Description:
+ * Flash the message in the statusbar for a few moments; if no
+ * statusbar, do nothing (?). For trivial little status messages,
+ * e.g. "Auto saving..."
+ **/
+
+void 
+gnome_app_flash (GnomeApp * app, const gchar * flash)
+{
+  /* This is a no-op for dialogs, since these messages aren't 
+     important enough to pester users. */
+  g_return_if_fail(app != NULL);
+  g_return_if_fail(GNOME_IS_APP(app));
+  g_return_if_fail(flash != NULL);
+
+  /* OK to call app_flash without a statusbar */
+  if ( gnome_app_has_appbar_status(app) ) {
+    MessageInfo * mi;
+
+    g_return_if_fail(GNOME_IS_APPBAR(app->statusbar));
+    
+    gnome_appbar_set_status(GNOME_APPBAR(app->statusbar), flash);
+
+    mi = g_new(MessageInfo, 1);
+
+    mi->timeoutid = 
+      gtk_timeout_add ( flash_length,
+			(GtkFunction) remove_message_timeout,
+			mi );
+    
+    mi->handlerid = 
+      gtk_signal_connect ( GTK_OBJECT(app),
+			   "destroy",
+			   GTK_SIGNAL_FUNC(remove_timeout_cb),
+			   mi );
+
+    mi->app       = app;
+  }   
+}
+
+/* ========================================================== */
+
+typedef struct {
+  GnomeReplyCallback callback;
+  gpointer data;
+} ReplyInfo;
+
+static void
+bar_reply_cb(GnomeAppBar * ab, ReplyInfo * ri)
+{
+  gchar * response;
+
+  response = gnome_appbar_get_response(ab);
+  g_return_if_fail(response != NULL);
+
+#ifdef GNOME_ENABLE_DEBUG
+  g_print("Got reply: \"%s\"\n", response);
+#endif
+
+  if ( (g_strcasecmp(_("y"), response) == 0) || 
+       (g_strcasecmp(_("yes"), response) == 0) ) {
+    (* (ri->callback)) (GNOME_YES, ri->data);
+  }
+  else if ( (g_strcasecmp(_("n"), response) == 0) || 
+	    (g_strcasecmp(_("no"), response) == 0) ) {
+    (* (ri->callback)) (GNOME_NO, ri->data);
+  }
+  else {
+    g_free(response);
+    gdk_beep(); /* Kind of lame; better to give a helpful message */
+    return;
+  }
+  g_free(response);
+  gnome_appbar_clear_prompt(ab);
+  return;
+}
+
+/* FIXME this can all be done as a special case of request_string
+   where we check the string for yes/no afterward. */
+
+static void
+reply_clear_prompt_cb(GnomeAppBar * ab, ReplyInfo * ri)
+{
+#ifdef GNOME_ENABLE_DEBUG
+  g_print("Clear prompt callback (reply)\n");
+#endif
+  gtk_signal_disconnect_by_func(GTK_OBJECT(ab), 
+				GTK_SIGNAL_FUNC(bar_reply_cb),
+				ri);
+  gtk_signal_disconnect_by_func(GTK_OBJECT(ab), 
+				GTK_SIGNAL_FUNC(reply_clear_prompt_cb),
+				ri);
+  g_free(ri);
+}
+
+static void 
+gnome_app_reply_bar(GnomeApp * app, const gchar * question,
+		    GnomeReplyCallback callback, gpointer data,
+		    gboolean yes_or_ok, gboolean modal)
+{
+  gchar * prompt;
+  ReplyInfo * ri;
+
+  prompt = g_strconcat(question, yes_or_ok ? _(" (yes or no)") : 
+			  _("  - OK? (yes or no)"), NULL);
+  gnome_appbar_set_prompt(GNOME_APPBAR(app->statusbar), prompt, modal);
+  gnome_app_activate_statusbar(app);
+  g_free(prompt);
+  
+  ri = g_new(ReplyInfo, 1);
+  ri->callback = callback;
+  ri->data     = data;
+
+  gtk_signal_connect(GTK_OBJECT(app->statusbar), "user_response",
+		     GTK_SIGNAL_FUNC(bar_reply_cb), ri);
+  gtk_signal_connect(GTK_OBJECT(app->statusbar), "clear_prompt",
+		     GTK_SIGNAL_FUNC(reply_clear_prompt_cb), ri);
+}
+
+
+/**
+ * gnome_app_question
+ * @app: Pointer to GNOME app object
+ * @question: Text of question to be displayed
+ * @callback:
+ * @data:
+ *
+ * Description:
+ * Ask a yes or no question, and call the callback when it's answered.
+ *
+ * Returns:
+ * Pointer to dialog widget, or %NULL if error or message in
+ * status bar.
+ **/
+
+GtkWidget * 
+gnome_app_question (GnomeApp * app, const gchar * question,
+		    GnomeReplyCallback callback, gpointer data)
+{
+  g_return_val_if_fail(app != NULL, NULL);
+  g_return_val_if_fail(GNOME_IS_APP(app), NULL);
+  g_return_val_if_fail(question != NULL, NULL);
+  g_return_val_if_fail(callback != NULL, NULL);
+
+  if ( gnome_app_interactive_statusbar(app) ) {
+    gnome_app_reply_bar(app, question, callback, data, TRUE, FALSE);
+    return NULL;
+  }
+  else {
+    return gnome_question_dialog_parented(question, callback, data,
+					  GTK_WINDOW(app));
+  }
+}
+
+
+/**
+ * gnome_app_question_modal
+ * @app: Pointer to GNOME app object
+ * @question: Text of question to be displayed
+ * @callback:
+ * @data:
+ *
+ * Description:
+ * Ask a yes or no question, and call the callback when it's answered.
+ *
+ * Returns:
+ * Pointer to dialog widget, or %NULL if error or message in
+ * status bar.
+ **/
+
+GtkWidget * 
+gnome_app_question_modal (GnomeApp * app, const gchar * question,
+			  GnomeReplyCallback callback, gpointer data)
+{
+  g_return_val_if_fail(app != NULL, NULL);
+  g_return_val_if_fail(GNOME_IS_APP(app), NULL);
+  g_return_val_if_fail(question != NULL, NULL);
+  g_return_val_if_fail(callback != NULL, NULL);
+
+  if ( gnome_app_interactive_statusbar(app) ) {
+    gnome_app_reply_bar(app, question, callback, data, TRUE, TRUE);
+    return NULL;
+  }
+  else {
+    return gnome_question_dialog_modal_parented(question, callback, data,
+						GTK_WINDOW(app));
+  }
+}
+
+
+/**
+ * gnome_app_ok_cancel
+ * @app: Pointer to GNOME app object
+ * @message: Text of message to be displayed
+ * @callback:
+ * @data:
+ *
+ * Description:
+ *
+ * Returns:
+ * Pointer to dialog widget, or %NULL if error or message in
+ * status bar.
+ **/
+
+GtkWidget * 
+gnome_app_ok_cancel (GnomeApp * app, const gchar * message,
+		     GnomeReplyCallback callback, gpointer data)
+{
+  g_return_val_if_fail(app != NULL, NULL);
+  g_return_val_if_fail(GNOME_IS_APP(app), NULL);
+  g_return_val_if_fail(message != NULL, NULL);
+  g_return_val_if_fail(callback != NULL, NULL);
+
+  if ( gnome_app_interactive_statusbar(app) ) {
+    gnome_app_reply_bar(app, message, callback, data, FALSE, FALSE);
+    return NULL;
+  }
+  else {
+    return gnome_ok_cancel_dialog_parented(message, callback, data,
+					   GTK_WINDOW(app));
+  }
+}
+
+
+/**
+ * gnome_app_ok_cancel_modal
+ * @app: Pointer to GNOME app object
+ * @message: Text of message to be displayed
+ * @callback:
+ * @data:
+ *
+ * Description:
+ *
+ * Returns:
+ * Pointer to dialog widget, or %NULL if error or message in
+ * status bar.
+ **/
+
+GtkWidget * 
+gnome_app_ok_cancel_modal (GnomeApp * app, const gchar * message,
+			   GnomeReplyCallback callback, gpointer data)
+{
+  g_return_val_if_fail(app != NULL, NULL);
+  g_return_val_if_fail(GNOME_IS_APP(app), NULL);
+  g_return_val_if_fail(message != NULL, NULL);
+  g_return_val_if_fail(callback != NULL, NULL);
+
+  if ( gnome_app_interactive_statusbar(app) ) {
+    gnome_app_reply_bar(app, message, callback, data, FALSE, TRUE);
+    return NULL;
+  }
+  else {
+    return gnome_ok_cancel_dialog_modal_parented(message, callback, data,
+						 GTK_WINDOW(app));
+  }
+}
+
+typedef struct {
+  GnomeStringCallback callback;
+  gpointer data;
+} RequestInfo;
+
+
+static void 
+bar_request_cb(GnomeAppBar * ab, RequestInfo * ri)
+{
+  gchar * response;
+
+  response = gnome_appbar_get_response(ab);
+  g_return_if_fail(response != NULL);
+
+#ifdef GNOME_ENABLE_DEBUG
+  g_print("Got string: \"%s\"\n", response);
+#endif
+
+  /* response isn't freed because the callback expects an 
+     allocated string. */
+  (* (ri->callback)) (response, ri->data);
+
+  gnome_appbar_clear_prompt(ab);
+  return;
+}
+
+static void
+request_clear_prompt_cb(GnomeAppBar * ab, RequestInfo * ri)
+{
+#ifdef GNOME_ENABLE_DEBUG
+  g_print("Clearing prompt (request)\n");
+#endif
+
+
+  gtk_signal_disconnect_by_func(GTK_OBJECT(ab), 
+				GTK_SIGNAL_FUNC(bar_request_cb),
+				ri);
+  gtk_signal_disconnect_by_func(GTK_OBJECT(ab), 
+				GTK_SIGNAL_FUNC(request_clear_prompt_cb),
+				ri);
+  g_free(ri);
+}
+
+static void 
+gnome_app_request_bar  (GnomeApp * app, const gchar * prompt,
+			GnomeStringCallback callback, 
+			gpointer data, gboolean password)
+{
+  if (password == TRUE) {
+    g_warning("Password support not implemented for appbar");
+  }
+  else {
+    RequestInfo * ri;
+    
+    gnome_appbar_set_prompt(GNOME_APPBAR(app->statusbar), prompt, FALSE);
+    
+    ri = g_new(RequestInfo, 1);
+    ri->callback = callback;
+    ri->data     = data;
+    
+    gtk_signal_connect(GTK_OBJECT(app->statusbar), "user_response",
+		       GTK_SIGNAL_FUNC(bar_request_cb), ri);   
+    gtk_signal_connect(GTK_OBJECT(app->statusbar), "clear_prompt",
+		       GTK_SIGNAL_FUNC(request_clear_prompt_cb), ri);     
+  }
+}
+
+
+/**
+ * gnome_app_request_string
+ * @app: Pointer to GNOME app object
+ * @prompt: Text of prompt to be displayed
+ * @callback:
+ * @data:
+ *
+ * Description:
+ *
+ * Returns:
+ * Pointer to dialog widget, or %NULL if error or message in
+ * status bar.
+ **/
+
+GtkWidget * 
+gnome_app_request_string (GnomeApp * app, const gchar * prompt,
+			  GnomeStringCallback callback, gpointer data)
+{ 
+  g_return_val_if_fail(app != NULL, NULL);
+  g_return_val_if_fail(GNOME_IS_APP(app), NULL);
+  g_return_val_if_fail(prompt != NULL, NULL);
+  g_return_val_if_fail(callback != NULL, NULL);
+
+  if ( gnome_app_interactive_statusbar(app) ) {
+    gnome_app_request_bar(app, prompt, callback, data, FALSE);
+    return NULL;
+  }
+  else {
+    return gnome_request_dialog(FALSE, prompt, NULL, 0,
+				callback, data, GTK_WINDOW(app));   
+  }
+}
+
+
+
+/**
+ * gnome_app_request_password
+ * @app: Pointer to GNOME app object
+ * @prompt: Text of prompt to be displayed
+ * @callback:
+ * @data:
+ *
+ * Description:
+ *
+ * Returns:
+ * Pointer to dialog widget, or %NULL if error or message in
+ * status bar.
+ **/
+
+GtkWidget * 
+gnome_app_request_password (GnomeApp * app, const gchar * prompt,
+			    GnomeStringCallback callback, gpointer data)
+{
+  g_return_val_if_fail(app != NULL, NULL);
+  g_return_val_if_fail(GNOME_IS_APP(app), NULL);
+  g_return_val_if_fail(prompt != NULL, NULL);
+  g_return_val_if_fail(callback != NULL, NULL);
+
+  /* FIXME implement for AppBar */
+
+  return gnome_request_dialog(TRUE, prompt, NULL, 0,
+			      callback, data, GTK_WINDOW(app));   
+}
+
+/* ================================================== */
+
+typedef struct {
+  GtkWidget * bar; /* Progress bar, for dialog; NULL for AppBar */
+  GtkWidget * widget; /* dialog or AppBar */
+  GnomeApp * app;
+  GnomeAppProgressFunc percentage_cb;
+  GnomeAppProgressCancelFunc cancel_cb;
+  gpointer data;
+  guint timeout_tag, handler_id;
+} ProgressKeyReal;
+
+/* Invalid value, I hope. FIXME */
+#define INVALID_TIMEOUT 0
+
+/* Works for statusbar and dialog both. */
+static gint progress_timeout_cb (ProgressKeyReal * key)
+{
+  gdouble percent;
+
+  GDK_THREADS_ENTER ();
+	
+  percent = (* key->percentage_cb)(key->data);
+  gnome_app_set_progress (key, percent);
+
+  GDK_THREADS_LEAVE ();
+  
+  return TRUE;
+}
+
+
+/* dialog only */
+static void progress_clicked_cb (GnomeDialog * d, gint button,
+				 ProgressKeyReal * key)
+{
+  if (key->cancel_cb) {
+    (* key->cancel_cb)(key->data);
+  }
+  key->widget = NULL; /* The click closed the dialog */
+  gnome_app_progress_done(key);
+}
+
+static void 
+progress_dialog (const gchar * description, ProgressKeyReal * key)
+{
+  GtkWidget * d, * pb, * label;
+
+  d = gnome_dialog_new ( _("Progress"), 
+			 GNOME_STOCK_BUTTON_CANCEL,
+			 NULL );
+  gnome_dialog_set_close (GNOME_DIALOG(d), TRUE);
+  gnome_dialog_set_parent(GNOME_DIALOG(d), GTK_WINDOW(key->app));
+  gtk_signal_connect (GTK_OBJECT(d), "clicked", 
+		      GTK_SIGNAL_FUNC(progress_clicked_cb),
+		      key);
+			       
+  label = gtk_label_new (description);
+
+  pb = gtk_progress_bar_new();
+
+  gtk_box_pack_start ( GTK_BOX(GNOME_DIALOG(d)->vbox), 
+		       label, TRUE, TRUE, GNOME_PAD );
+  gtk_box_pack_start ( GTK_BOX(GNOME_DIALOG(d)->vbox),
+		       pb, TRUE, TRUE, GNOME_PAD );
+
+  key->bar = pb;
+  key->widget = d;
+
+  gtk_widget_show_all (d);
+}
+
+static void 
+progress_bar (const gchar * description, ProgressKeyReal * key)
+{
+  key->bar = NULL;
+  key->widget = key->app->statusbar;
+  gnome_appbar_set_status(GNOME_APPBAR(key->widget), description);
+}
+
+static void
+stop_progress_cb(GnomeApp * app, GnomeAppProgressKey key)
+{
+  gnome_app_progress_done(key);
+}
+
+/* FIXME share code between manual and timeout */
+
+/**
+ * gnome_app_progress_timeout
+ * @app:
+ * @description:
+ * @interval:
+ * @percentage_cb:
+ * @cancel_cb:
+ * @data:
+ *
+ * Description:
+ *
+ * Returns:
+ **/
+
+GnomeAppProgressKey 
+gnome_app_progress_timeout (GnomeApp * app, 
+			    const gchar * description,
+			    guint32 interval, 
+			    GnomeAppProgressFunc percentage_cb,
+			    GnomeAppProgressCancelFunc cancel_cb,
+			    gpointer data)
+{
+  ProgressKeyReal * key;
+
+  g_return_val_if_fail (app != NULL, NULL);
+  g_return_val_if_fail (GNOME_IS_APP(app), NULL);
+  g_return_val_if_fail (description != NULL, NULL);
+  g_return_val_if_fail (percentage_cb != NULL, NULL);
+
+  key = g_new (ProgressKeyReal, 1);
+
+  key->app = app;
+  key->percentage_cb = percentage_cb;
+  key->cancel_cb = cancel_cb;
+  key->data = data;
+
+  if ( gnome_app_has_appbar_progress(app) &&
+       gnome_preferences_get_statusbar_dialog() ) {
+    progress_bar    (description, key);
+  }
+  else {
+    progress_dialog (description, key);
+  }
+
+  key->timeout_tag = gtk_timeout_add ( interval, 
+				       (GtkFunction) progress_timeout_cb,
+				       key );
+
+  /* Make sure progress stops if the app is destroyed. */
+  key->handler_id = gtk_signal_connect(GTK_OBJECT(app), "destroy",
+				       GTK_SIGNAL_FUNC(stop_progress_cb),
+	 			       key);
+
+  return key;
+}
+
+
+/**
+ * gnome_app_progress_manual
+ * @app:
+ * @description:
+ * @cancel_cb:
+ * @data:
+ *
+ * Description:
+ *
+ * Returns:
+ **/
+
+GnomeAppProgressKey 
+gnome_app_progress_manual (GnomeApp * app, 
+			   const gchar * description,
+			   GnomeAppProgressCancelFunc cancel_cb,
+			   gpointer data)
+{
+  ProgressKeyReal * key;
+
+  g_return_val_if_fail (app != NULL, NULL);
+  g_return_val_if_fail (GNOME_IS_APP(app), NULL);
+  g_return_val_if_fail (description != NULL, NULL);
+
+  key = g_new (ProgressKeyReal, 1);
+
+  key->app = app;
+  key->cancel_cb = cancel_cb;
+  key->data = data;
+  key->timeout_tag = INVALID_TIMEOUT;  
+
+  if ( gnome_app_has_appbar_progress(app) &&
+       gnome_preferences_get_statusbar_dialog() ) {
+    progress_bar    (description, key);
+  }
+  else {
+    progress_dialog (description, key);
+  }
+
+  /* Make sure progress stops if the app is destroyed. */
+  key->handler_id = gtk_signal_connect(GTK_OBJECT(app), "destroy",
+				       GTK_SIGNAL_FUNC(stop_progress_cb),
+				       key);
+
+  return key;
+}
+
+/**
+ * gnome_app_set_progress
+ * @key:
+ * @percent:
+ *
+ * Description:
+ **/
+
+void gnome_app_set_progress (GnomeAppProgressKey key, gdouble percent)
+{
+  ProgressKeyReal * real_key = (GnomeAppProgressKey) key;
+
+  g_return_if_fail ( key != NULL );  
+
+  if (real_key->bar) {
+    gtk_progress_bar_update ( GTK_PROGRESS_BAR(real_key->bar), percent );
+  }
+  else {
+    gnome_appbar_set_progress_percentage ( GNOME_APPBAR(real_key->widget), percent );
+  }
+}
+
+static void progress_timeout_remove(ProgressKeyReal * key)
+{
+  if (key->timeout_tag != INVALID_TIMEOUT) {
+    gtk_timeout_remove(key->timeout_tag);
+    key->timeout_tag = INVALID_TIMEOUT;
+  }
+}
+
+/**
+ * gnome_app_progress_done
+ * @key:
+ *
+ * Description:
+ **/
+
+void gnome_app_progress_done (GnomeAppProgressKey key)
+{
+  ProgressKeyReal * real_key = (GnomeAppProgressKey) key;
+
+  g_return_if_fail ( key != NULL );
+
+  progress_timeout_remove((ProgressKeyReal *)key);
+
+  gtk_signal_disconnect(GTK_OBJECT(real_key->app), real_key->handler_id);
+
+  if (real_key->bar) { /* It's a dialog */
+    if (real_key->widget) gnome_dialog_close(GNOME_DIALOG(real_key->widget));
+  }
+  else {
+    /* Reset the bar */
+    gnome_appbar_set_progress_percentage ( GNOME_APPBAR(real_key->widget), 0.0 );
+  }
+  g_free(key);
+}
+
+typedef struct {
+  GdkPixmap *icon_pixmap;
+  GdkBitmap *icon_mask;
+  GdkWindow *icon_window;
+} IconInfo;
+
+static void
+gnome_window_realized(GtkWindow *window, IconInfo *pbi)
+{
+  gdk_window_set_icon(GTK_WIDGET(window)->window, pbi->icon_window, pbi->icon_pixmap, pbi->icon_mask);
+}
+
+static void
+gnome_window_destroyed(GtkWindow *window, IconInfo *pbi)
+{
+  gdk_pixmap_unref(pbi->icon_pixmap);
+  gdk_bitmap_unref(pbi->icon_mask);
+  gdk_window_unref(pbi->icon_window);
+  g_free(pbi);
+}
+
+void
+gnome_window_set_icon(GtkWindow *window, GdkPixbuf *pixbuf, gboolean overwrite)
+{
+  gboolean skip_connect = FALSE;
+  IconInfo *pbi;
+
+  pbi = gtk_object_get_data(GTK_OBJECT(window), "WM_HINTS.icon_info");
+  if(pbi && !overwrite)
+    return;
+  if(pbi)
+    {
+      skip_connect = TRUE;
+      gdk_pixmap_unref(pbi->icon_pixmap);
+      gdk_pixmap_unref(pbi->icon_mask);
+      gdk_window_unref(pbi->icon_window);
+    }
+  else
+    pbi = g_new(IconInfo, 1);
+
+  {
+    GdkWindowAttr wa;
+    wa.visual = gdk_rgb_get_visual();
+    wa.colormap = gdk_rgb_get_cmap();
+    pbi->icon_window = gdk_window_new(GDK_ROOT_PARENT(), &wa, GDK_WA_VISUAL|GDK_WA_COLORMAP);
+  }
+  gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pbi->icon_pixmap, &pbi->icon_mask, 128);
+
+  if(!skip_connect)
+    {
+      gtk_object_set_data(GTK_OBJECT(window), "WM_HINTS.icon_info", pbi);
+      gtk_signal_connect_after(GTK_OBJECT(window), "realize", GTK_SIGNAL_FUNC(gnome_window_realized), pbi);
+      gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(gnome_window_destroyed), pbi);
+    }
+
+  if(GTK_WIDGET_REALIZED(window))
+    gnome_window_realized(window, pbi);
+}
+
+void
+gnome_window_set_icon_from_file(GtkWindow *window, const char *filename, gboolean overwrite)
+{
+  GdkPixbuf *pb;
+  GError *error;
+
+  error = NULL;
+  pb = gdk_pixbuf_new_from_file(filename, &error);
+  if (error != NULL) {
+      g_warning (error->message);
+      g_error_free (error);
+  }
+  if(!pb)
+    {
+      error = NULL;
+      filename = gnome_program_locate_file (gnome_program_get (),
+					    GNOME_FILE_DOMAIN_PIXMAP,
+					    filename, TRUE, NULL);
+		
+      pb = gdk_pixbuf_new_from_file(filename, &error);
+      if (error != NULL) {
+	g_warning (error->message);
+	g_error_free (error);
+      }
+      g_free((gpointer)filename);
+    }
+  if(!pb)
+    return;
+
+  gnome_window_set_icon(window, pb, overwrite);
+  gdk_pixbuf_unref(pb);
+}
diff --git a/libgnomeui/gnome-app-util.h b/libgnomeui/gnome-app-util.h
new file mode 100644
index 0000000..fddabe2
--- /dev/null
+++ b/libgnomeui/gnome-app-util.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome 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.
+ *
+ * The Gnome 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 the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+#ifndef GNOME_APP_UTIL_H
+#define GNOME_APP_UTIL_H
+/****
+  Convenience UI functions for use with GnomeApp 
+  ****/
+
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include "gnome-app.h"
+#include "gnome-types.h"
+
+G_BEGIN_DECLS
+
+/* =============================================
+  Simple messages and questions to the user; use dialogs for now, but
+   ultimately can use either dialogs or statusbar. Supposed to be a
+   "semantic markup" kind of thing. */
+/* If the function returns GtkWidget *, it will return any dialog
+   created, or NULL if none */
+
+/* A simple message, in an OK dialog or the status bar. Requires
+   confirmation from the user before it goes away. */
+GtkWidget * 
+gnome_app_message (GnomeApp * app, const gchar * message);
+
+/* Flash the message in the statusbar for a few moments; if no
+   statusbar, do nothing (?). For trivial little status messages,
+   e.g. "Auto saving..." */
+void 
+gnome_app_flash (GnomeApp * app, const gchar * flash);
+
+/* An important fatal error; if it appears in the statusbar, 
+   it might gdk_beep() and require acknowledgement. */
+GtkWidget * 
+gnome_app_error (GnomeApp * app, const gchar * error);
+
+/* A not-so-important error, but still marked better than a flash */
+GtkWidget * 
+gnome_app_warning (GnomeApp * app, const gchar * warning);
+
+/* =============================================================== */
+
+/* For these, the user can cancel without ever calling the callback,
+   e.g. by clicking the dialog's "close" button. So don't count on the
+   callback ever being called. */
+
+/* Ask a yes or no question, and call the callback when it's answered. */
+GtkWidget * 
+gnome_app_question (GnomeApp * app, const gchar * question,
+		    GnomeReplyCallback callback, gpointer data);
+
+GtkWidget * 
+gnome_app_question_modal (GnomeApp * app, const gchar * question,
+			  GnomeReplyCallback callback, gpointer data);
+
+/* OK-Cancel question. */
+GtkWidget *
+gnome_app_ok_cancel (GnomeApp * app, const gchar * message,
+		     GnomeReplyCallback callback, gpointer data);
+
+GtkWidget * 
+gnome_app_ok_cancel_modal (GnomeApp * app, const gchar * message,
+			   GnomeReplyCallback callback, gpointer data);
+
+/* Get a string. */
+GtkWidget * 
+gnome_app_request_string (GnomeApp * app, const gchar * prompt,
+			  GnomeStringCallback callback, gpointer data);
+
+/* Request a string, but don't echo to the screen. */
+GtkWidget * 
+gnome_app_request_password (GnomeApp * app, const gchar * prompt,
+			    GnomeStringCallback callback, gpointer data);
+
+
+/* ========================================================== */
+
+/* Returns the fraction of the task done at a given time. */
+typedef gdouble (* GnomeAppProgressFunc) (gpointer data);
+
+/* What to call if the operation is canceled. */
+typedef void (* GnomeAppProgressCancelFunc) (gpointer data);
+
+/* A key used to refer to the callback. DO NOT FREE.
+   It's freed by _done or when the progress is canceled. */
+typedef gpointer GnomeAppProgressKey;
+
+/* These will be a progress bar dialog or the progress bar in the AppBar. */
+
+/* Call percentage_cb every interval to set the progress indicator.
+   Both callbacks get the data arg. */
+GnomeAppProgressKey 
+gnome_app_progress_timeout (GnomeApp * app, 
+			    const gchar * description,
+			    guint32 interval, 
+			    GnomeAppProgressFunc percentage_cb,
+			    GnomeAppProgressCancelFunc cancel_cb,
+			    gpointer data);
+
+/* Just create a callback key; it then has to be updated 
+   with _update() */
+GnomeAppProgressKey 
+gnome_app_progress_manual (GnomeApp * app, 
+			   const gchar * description,
+			   GnomeAppProgressCancelFunc cancel_cb,
+			   gpointer data);
+
+/* Only makes sense with manual. */
+void 
+gnome_app_set_progress (GnomeAppProgressKey key, gdouble percent);
+
+/* Call this when the progress meter should go away. Automatically 
+   called if progress is cancelled. */
+void 
+gnome_app_progress_done (GnomeAppProgressKey key);
+
+void gnome_window_set_icon(GtkWindow *window, GdkPixbuf *pixbuf, gboolean overwrite);
+void gnome_window_set_icon_from_file(GtkWindow *window, const char *filename, gboolean overwrite);
+
+G_END_DECLS
+
+#endif
diff --git a/libgnomeui/gnome-app.c b/libgnomeui/gnome-app.c
new file mode 100644
index 0000000..ea259be
--- /dev/null
+++ b/libgnomeui/gnome-app.c
@@ -0,0 +1,821 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Red Hat Software, The Free
+ * Software Foundation, Miguel de Icaza, Federico Menu, Chris Toshok.
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome 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.
+ *
+ * The Gnome 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 the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.  */
+/*
+  @NOTATION@
+ */
+
+/*
+ * Originally by Elliot Lee,
+ *
+ * improvements and rearrangement by Miguel,
+ * and I don't know what you other people did :)
+ *
+ * Even more changes by Federico Mena.
+ *
+ * Toolbar separators and configurable relief by Andrew Veliath.
+ *
+ * Modified by Ettore Perazzoli to support GnomeDock.
+ *
+ */
+
+#include "config.h"
+#include "gnome-macros.h"
+
+#include <string.h>
+#include <gtk/gtk.h>
+#include <libgnome/gnome-program.h>
+
+#include <libgnome/gnome-i18n.h>
+#include <libgnome/gnome-util.h>
+#include <libgnome/gnome-config.h>
+#include <libgnome/gnome-preferences.h>
+#include "gnome-app-helper.h"
+#include "gnome-uidefs.h"
+#include "gnome-dock.h"
+#include "gnome-init.h"
+#include "gnome-window.h"
+
+#include "gnome-app.h"
+
+#define LAYOUT_CONFIG_PATH      "Placement/Dock"
+
+struct _GnomeAppPrivate
+{
+	int dummy;
+	/* Nothing right now, needs to get filled with the private things */
+	/* XXX: When stuff is added, uncomment the allocation in the
+	 * gnome_app_init function! */
+};
+
+
+static void gnome_app_class_init  (GnomeAppClass *class);
+static void gnome_app_init        (GnomeApp      *app);
+static void gnome_app_destroy     (GtkObject     *object);
+static void gnome_app_finalize    (GObject       *object);
+static void gnome_app_show        (GtkWidget     *widget);
+static void gnome_app_get_property   (GObject       *object,
+				   guint          param_id,
+				   GValue        *value,
+				   GParamSpec    *pspec);
+static void gnome_app_set_property   (GObject       *object,
+				   guint          param_id,
+				   const GValue  *value,
+				   GParamSpec    *pspec);
+
+static gchar *read_layout_config  (GnomeApp      *app);
+static void   write_layout_config (GnomeApp      *app,
+				   GnomeDockLayout *layout);
+static void   layout_changed      (GtkWidget     *widget,
+				   gpointer       data);
+
+/* define _get_type and parent_class */
+GNOME_CLASS_BOILERPLATE (GnomeApp, gnome_app,
+			 GtkWindow, gtk_window)
+
+static gchar *
+read_layout_config (GnomeApp *app)
+{
+	gchar *s;
+
+	gnome_config_push_prefix (app->prefix);
+	s = gnome_config_get_string (LAYOUT_CONFIG_PATH);
+	gnome_config_pop_prefix ();
+
+	return s;
+}
+
+static void
+write_layout_config (GnomeApp *app, GnomeDockLayout *layout)
+{
+	gchar *s;
+
+	s = gnome_dock_layout_create_string (layout);
+	gnome_config_push_prefix (app->prefix);
+	gnome_config_set_string (LAYOUT_CONFIG_PATH, s);
+	gnome_config_pop_prefix ();
+	gnome_config_sync ();
+
+	g_free (s);
+}
+
+enum {
+	PROP_0,
+	PROP_APP_ID
+};
+
+static void
+gnome_app_class_init (GnomeAppClass *class)
+{
+	GtkObjectClass *object_class;
+	GObjectClass *gobject_class;
+	GtkWidgetClass *widget_class;
+
+	gobject_class = (GObjectClass *) class;
+	object_class = (GtkObjectClass *) class;
+	widget_class = (GtkWidgetClass *) class;
+
+	gobject_class->finalize = gnome_app_finalize;
+	gobject_class->set_property = gnome_app_set_property;
+	gobject_class->get_property = gnome_app_get_property;
+
+	object_class->destroy = gnome_app_destroy;
+
+	widget_class->show = gnome_app_show;
+
+	g_object_class_install_property (gobject_class,
+				      PROP_APP_ID,
+				      g_param_spec_string ("app_id",
+							   _("App ID"),
+							   _("The application ID string"),
+							   NULL,
+							   (G_PARAM_READABLE |
+							    G_PARAM_WRITABLE)));
+}
+
+static void
+gnome_app_set_property (GObject       *object,
+			guint          param_id,
+			const GValue  *value,
+			GParamSpec    *pspec)
+{
+	GnomeApp *app = GNOME_APP (object);
+
+	switch (param_id) {
+	case PROP_APP_ID:
+		g_free (app->name);
+		app->name = g_value_dup_string (value);
+		g_free (app->prefix);
+		app->prefix = g_strconcat("/", app->name, "/", NULL);
+		break;
+	}
+}
+
+static void
+gnome_app_get_property (GObject       *object,
+			guint          param_id,
+			GValue        *value,
+			GParamSpec    *pspec)
+{
+	GnomeApp *app = GNOME_APP (object);
+
+	switch (param_id) {
+	case PROP_APP_ID:
+		g_value_set_string (value, app->name);
+		break;
+	}
+}
+
+static void
+gnome_app_init (GnomeApp *app)
+{
+	const char *str = NULL;
+	GValue value = { 0, };
+
+	app->_priv = NULL;
+	/* XXX: when there is some private stuff enable this
+	app->_priv = g_new0(GnomeAppPrivate, 1);
+	*/
+
+	app->name = NULL;
+	app->prefix = NULL;
+
+	app->accel_group = gtk_accel_group_new ();
+	gtk_window_add_accel_group (GTK_WINDOW (app), app->accel_group);
+	
+	app->vbox = gtk_vbox_new (FALSE, 0);
+	gtk_container_add (GTK_CONTAINER (app), app->vbox);
+
+	app->dock = gnome_dock_new ();
+	gtk_box_pack_start (GTK_BOX (app->vbox), app->dock,
+			    TRUE, TRUE, 0);
+
+	gtk_signal_connect (GTK_OBJECT (app->dock),
+			    "layout_changed",
+			    GTK_SIGNAL_FUNC (layout_changed),
+			    (gpointer) app);
+
+	app->layout = gnome_dock_layout_new ();
+
+	app->enable_layout_config = TRUE;
+	g_value_init (&value, G_TYPE_STRING);
+	g_object_get_property (G_OBJECT (gnome_program_get ()),
+			       LIBGNOMEUI_PARAM_DEFAULT_ICON, &value);
+	str = g_value_get_string (&value);
+	if (str != NULL)
+		gnome_window_set_icon_from_file (GTK_WINDOW (app), str, FALSE);
+	g_value_unset (&value);
+}
+
+static void
+gnome_app_show (GtkWidget *widget)
+{
+	GnomeApp *app;
+
+	app = GNOME_APP (widget);
+
+	if (app->layout != NULL) {
+		if (app->enable_layout_config) {
+			gchar *s;
+
+			/* Override the layout with the user's saved
+			   configuration.  */
+			s = read_layout_config (app);
+			gnome_dock_layout_parse_string (app->layout, s);
+			g_free (s);
+		}
+
+		gnome_dock_add_from_layout (GNOME_DOCK (app->dock),
+					    app->layout);
+
+		if (app->enable_layout_config)
+			write_layout_config (app, app->layout);
+
+		gtk_object_unref (GTK_OBJECT (app->layout));
+		app->layout = NULL;
+	}
+			
+	gtk_widget_show (app->vbox);
+	gtk_widget_show (app->dock);
+
+	GNOME_CALL_PARENT_HANDLER (GTK_WIDGET_CLASS, show, (widget));
+}
+
+static void
+layout_changed (GtkWidget *w, gpointer data)
+{
+	GnomeApp *app;
+
+	g_return_if_fail (GNOME_IS_APP (data));
+	g_return_if_fail (GNOME_IS_DOCK (w));
+
+	app = GNOME_APP (data);
+
+	if (app->enable_layout_config) {
+		GnomeDockLayout *layout;
+
+		layout = gnome_dock_get_layout (GNOME_DOCK (app->dock));
+		write_layout_config (app, layout);
+		gtk_object_unref (GTK_OBJECT (layout));
+	}
+}
+
+/**
+ * gnome_app_new
+ * @appname: Name of program, using in file names and paths.
+ * @title: Window title for application.
+ *
+ * Description:
+ * Create a new (empty) application window.  You must specify the
+ * application's name (used internally as an identifier).
+ * @title can be left as NULL, in which case the window's title will
+ * not be set.
+ *
+ * Returns: Pointer to new GNOME app object.
+ **/
+
+GtkWidget *
+gnome_app_new (const gchar *appname, const gchar *title)
+{
+	GtkObject *app;
+
+	g_return_val_if_fail (appname != NULL, NULL);
+
+	if (title != NULL) {
+		app = g_object_new (gnome_app_get_type (),
+				    "app_id", appname,
+				    NULL);
+		gtk_object_set (GTK_OBJECT (app),
+				"title", title,
+				NULL);
+	} else {
+		app = g_object_new (gnome_app_get_type (),
+				    "app_id", appname,
+				    NULL);
+	}
+	return GTK_WIDGET (app);
+}
+
+/**
+ * gnome_app_construct
+ * @app: Pointer to newly-created GNOME app object.
+ * @appname: Name of program, using in file names and paths.
+ * @title: Window title for application.
+ *
+ * Description:
+ * Constructor for language bindings; you don't normally need this.
+ **/
+
+void 
+gnome_app_construct (GnomeApp *app, const gchar *appname, const gchar *title)
+{
+	g_return_if_fail (appname != NULL);
+
+	if (title != NULL) {
+		g_object_set (G_OBJECT (app),
+			      "app_id", appname,
+			      NULL);
+		gtk_object_set (GTK_OBJECT (app),
+				"title", title,
+				NULL);
+	} else {
+		g_object_set (G_OBJECT (app),
+			      "app_id", appname,
+			      NULL);
+	}
+}
+
+static void
+gnome_app_destroy (GtkObject *object)
+{
+	GnomeApp *app;
+
+	/* remember, destroy can be run multiple times! */
+	
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (GNOME_IS_APP (object));
+
+	app = GNOME_APP (object);
+
+	g_free (app->name);
+	app->name = NULL;
+	g_free (app->prefix);
+	app->prefix = NULL;
+
+	if (app->accel_group != NULL) {
+		gtk_accel_group_unref (app->accel_group);
+		app->accel_group = NULL;
+	}
+
+	if (app->layout != NULL) {
+		gtk_object_unref (GTK_OBJECT (app->layout));
+		app->layout = NULL;
+	}
+
+	GNOME_CALL_PARENT_HANDLER (GTK_OBJECT_CLASS, destroy, (object));
+}
+
+static void
+gnome_app_finalize (GObject *object)
+{
+	GnomeApp *app;
+	
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (GNOME_IS_APP (object));
+
+	app = GNOME_APP (object);
+
+	/* Free private data */
+	g_free (app->_priv);
+	app->_priv = NULL;
+
+	GNOME_CALL_PARENT_HANDLER (G_OBJECT_CLASS, finalize, (object));
+}
+
+/* Callback for an app's contents' parent_set signal.  We set the app->contents
+ * to NULL and detach the signal.
+ */
+static void
+contents_parent_set (GtkWidget *widget, GtkWidget *previous_parent, gpointer data)
+{
+	GnomeApp *app;
+
+	app = GNOME_APP (data);
+
+	g_assert (previous_parent == app->dock);
+
+	gtk_signal_disconnect_by_func (GTK_OBJECT (widget),
+				       GTK_SIGNAL_FUNC (contents_parent_set),
+				       data);
+
+	app->contents = NULL;
+}
+
+/**
+ * gnome_app_set_contents
+ * @app: Pointer to GNOME app object.
+ * @contents: Widget to be application content area.
+ *
+ * Description:
+ * Sets the content area of the GNOME app's main window.
+ **/
+void
+gnome_app_set_contents (GnomeApp *app, GtkWidget *contents)
+{
+	GtkWidget *new_contents;
+
+	g_return_if_fail (app != NULL);
+	g_return_if_fail (GNOME_IS_APP(app));
+	g_return_if_fail (app->dock != NULL);
+	g_return_if_fail (contents != NULL);
+	g_return_if_fail (GTK_IS_WIDGET (contents));
+
+	gnome_dock_set_client_area (GNOME_DOCK (app->dock), contents);
+
+	/* Re-fetch it in case it did not change */
+	new_contents = gnome_dock_get_client_area (GNOME_DOCK (app->dock));
+
+	if (new_contents == contents && new_contents != app->contents) {
+		gtk_widget_show (new_contents);
+		gtk_signal_connect (GTK_OBJECT (new_contents), "parent_set",
+				    GTK_SIGNAL_FUNC (contents_parent_set),
+				    app);
+
+		app->contents = new_contents;
+	}
+}
+
+/**
+ * gnome_app_set_menus
+ * @app: Pointer to GNOME app object.
+ * @menubar: Menu bar widget for main app window.
+ *
+ * Description:
+ * Sets the menu bar of the application window.
+ **/
+
+void
+gnome_app_set_menus (GnomeApp *app, GtkMenuBar *menubar)
+{
+	GtkWidget *dock_item;
+	GtkAccelGroup *ag;
+	GnomeDockItemBehavior behavior;
+
+	g_return_if_fail(app != NULL);
+	g_return_if_fail(GNOME_IS_APP(app));
+	g_return_if_fail(app->menubar == NULL);
+	g_return_if_fail(menubar != NULL);
+	g_return_if_fail(GTK_IS_MENU_BAR(menubar));
+
+	behavior = (GNOME_DOCK_ITEM_BEH_EXCLUSIVE
+		    | GNOME_DOCK_ITEM_BEH_NEVER_VERTICAL);
+	
+	if (!gnome_preferences_get_menubar_detachable())
+		behavior |= GNOME_DOCK_ITEM_BEH_LOCKED;
+
+	dock_item = gnome_dock_item_new (GNOME_APP_MENUBAR_NAME,
+					 behavior);
+	gtk_container_add (GTK_CONTAINER (dock_item), GTK_WIDGET (menubar));
+
+	app->menubar = GTK_WIDGET (menubar);
+
+	/* To have menubar relief agree with the toolbar (and have the relief
+	 * outside of smaller handles), substitute the dock item's relief for
+	 * the menubar's relief, but don't change the size of the menubar in
+	 * the process. */
+#ifdef FIXME
+	gtk_menu_bar_set_shadow_type (GTK_MENU_BAR (app->menubar),
+				      GTK_SHADOW_NONE);
+#endif
+	if (gnome_preferences_get_menubar_relief ()) {
+		guint border_width;
+		
+		gtk_container_set_border_width (GTK_CONTAINER (dock_item), 2);
+		border_width = GTK_CONTAINER (app->menubar)->border_width;
+		if (border_width >= 2)
+			border_width -= 2;
+		gtk_container_set_border_width (GTK_CONTAINER (app->menubar),
+						border_width);
+	} else
+		gnome_dock_item_set_shadow_type (GNOME_DOCK_ITEM (dock_item),
+						 GTK_SHADOW_NONE);
+
+	if (app->layout != NULL)
+		gnome_dock_layout_add_item (app->layout,
+					    GNOME_DOCK_ITEM (dock_item),
+					    GNOME_DOCK_TOP,
+					    0, 0, 0);
+	else
+		gnome_dock_add_item(GNOME_DOCK(app->dock),
+				    GNOME_DOCK_ITEM (dock_item),
+				    GNOME_DOCK_TOP,
+				    0, 0, 0, TRUE);
+
+	gtk_widget_show (GTK_WIDGET (menubar));
+	gtk_widget_show (GTK_WIDGET (dock_item));
+
+	ag = gtk_object_get_data(GTK_OBJECT(app), "GtkAccelGroup");
+	if (ag && !g_slist_find(gtk_accel_groups_from_object (GTK_OBJECT (app)), ag))
+	        gtk_window_add_accel_group(GTK_WINDOW(app), ag);
+}
+
+
+/**
+ * gnome_app_set_statusbar
+ * @app: Pointer to GNOME app object
+ * @statusbar: Statusbar widget for main app window
+ *
+ * Description:
+ * Sets the status bar of the application window.
+ **/
+
+void
+gnome_app_set_statusbar (GnomeApp *app,
+		         GtkWidget *statusbar)
+{
+	GtkWidget *hbox;
+
+	g_return_if_fail(app != NULL);
+	g_return_if_fail(GNOME_IS_APP(app));
+	g_return_if_fail(statusbar != NULL);
+	g_return_if_fail(app->statusbar == NULL);
+
+	app->statusbar = GTK_WIDGET(statusbar);
+	gtk_widget_show(app->statusbar);
+
+	hbox = gtk_hbox_new(FALSE, 0);
+	gtk_container_set_border_width(GTK_CONTAINER(hbox), 0);
+	gtk_box_pack_start(GTK_BOX(hbox), statusbar, TRUE, TRUE, 0);
+	gtk_widget_show(hbox);
+
+	gtk_box_pack_start (GTK_BOX (app->vbox), hbox, FALSE, FALSE, 0);
+}
+
+/**
+ * gnome_app_set_statusbar_custom
+ * @app: Pointer to GNOME app object
+ * @container: container widget containing the statusbar
+ * @statusbar: Statusbar widget for main app window
+ *
+ * Description:
+ * Sets the status bar of the application window, but use @container
+ * as its container.
+ *
+ **/
+
+void
+gnome_app_set_statusbar_custom (GnomeApp *app,
+				GtkWidget *container,
+				GtkWidget *statusbar)
+{
+	g_return_if_fail(app != NULL);
+	g_return_if_fail(GNOME_IS_APP(app));
+	g_return_if_fail(container != NULL);
+	g_return_if_fail(GTK_IS_CONTAINER(container));
+	g_return_if_fail(statusbar != NULL);
+	g_return_if_fail(app->statusbar == NULL);
+
+	app->statusbar = GTK_WIDGET(statusbar);
+
+	gtk_box_pack_start (GTK_BOX (app->vbox), container, FALSE, FALSE, 0);
+}
+
+/**
+ * gnome_app_add_toolbar:
+ * @app: A &GnomeApp widget
+ * @toolbar: Toolbar to be added to @app's dock
+ * @name: Name for the dock item that will contain @toolbar
+ * @behavior: Behavior for the new dock item
+ * @placement: Placement for the new dock item
+ * @band_num: Number of the band where the dock item should be placed
+ * @band_position: Position of the new dock item in band @band_num
+ * @offset: Offset from the previous dock item in the band; if there is
+ * no previous item, offset from the beginning of the band.
+ *
+ * Create a new &GnomeDockItem widget containing @toolbar, and add it
+ * to @app's dock with the specified layout information.  Notice that,
+ * if automatic layout configuration is enabled, the layout is
+ * overridden by the saved configuration, if any.
+ **/
+void
+gnome_app_add_toolbar (GnomeApp *app,
+		       GtkToolbar *toolbar,
+		       const gchar *name,
+		       GnomeDockItemBehavior behavior,
+		       GnomeDockPlacement placement,
+		       gint band_num,
+		       gint band_position,
+		       gint offset)
+{
+
+	GtkWidget *dock_item;
+	GtkAccelGroup *ag;
+
+	g_return_if_fail(app != NULL);
+	g_return_if_fail(GNOME_IS_APP(app));
+	g_return_if_fail(toolbar != NULL);
+
+	dock_item = gnome_dock_item_new (name, behavior);
+
+	gtk_container_set_border_width (GTK_CONTAINER (toolbar), 1);
+	gtk_container_add (GTK_CONTAINER (dock_item), GTK_WIDGET (toolbar));
+
+	if(app->layout)
+		gnome_dock_layout_add_item (app->layout,
+					    GNOME_DOCK_ITEM (dock_item),
+					    placement,
+					    band_num,
+					    band_position,
+					    offset);
+	else
+		gnome_dock_add_item (GNOME_DOCK(app->dock),
+				     GNOME_DOCK_ITEM (dock_item),
+				     placement,
+				     band_num,
+				     band_position,
+				     offset,
+				     TRUE);
+
+
+	gnome_app_setup_toolbar(toolbar, GNOME_DOCK_ITEM(dock_item));
+	
+	gtk_widget_show (GTK_WIDGET (toolbar));
+	gtk_widget_show (GTK_WIDGET (dock_item));
+
+	ag = gtk_object_get_data(GTK_OBJECT(app), "GtkAccelGroup");
+	if (ag && !g_slist_find(gtk_accel_groups_from_object (GTK_OBJECT (app)), ag))
+	        gtk_window_add_accel_group(GTK_WINDOW(app), ag);
+}
+
+/**
+ * gnome_app_set_toolbar
+ * @app: Pointer to GNOME app object.
+ * @toolbar: Toolbar widget for main app window.
+ *
+ * Description:
+ * Sets the main toolbar of the application window.
+ **/
+
+void
+gnome_app_set_toolbar (GnomeApp *app,
+		       GtkToolbar *toolbar)
+{
+	GnomeDockItemBehavior behavior;
+
+	/* Making dock items containing toolbars use
+	   `GNOME_DOCK_ITEM_BEH_EXCLUSIVE' is not really a
+	   requirement.  We only do this for backwards compatibility.  */
+	behavior = GNOME_DOCK_ITEM_BEH_EXCLUSIVE;
+	
+	if (!gnome_preferences_get_toolbar_detachable())
+		behavior |= GNOME_DOCK_ITEM_BEH_LOCKED;
+	
+	gnome_app_add_toolbar (app, toolbar,
+			       GNOME_APP_TOOLBAR_NAME,
+			       behavior,
+			       GNOME_DOCK_TOP,
+			       1, 0, 0);
+}
+
+
+/**
+ * gnome_app_add_dock_item:
+ * @app: A &GnomeApp widget
+ * @item: Dock item to be added to @app's dock.
+ * @placement: Placement for the dock item
+ * @band_num: Number of the band where the dock item should be placed
+ * @band_position: Position of the dock item in band @band_num
+ * @offset: Offset from the previous dock item in the band; if there is
+ * no previous item, offset from the beginning of the band.
+ * 
+ * Add @item according to the specified layout information.  Notice
+ * that, if automatic layout configuration is enabled, the layout is
+ * overridden by the saved configuration, if any.
+ **/
+void
+gnome_app_add_dock_item (GnomeApp *app,
+			 GnomeDockItem *item,
+			 GnomeDockPlacement placement,
+			 gint band_num,
+			 gint band_position,
+			 gint offset)
+{
+	if (app->layout)
+		gnome_dock_layout_add_item (app->layout,
+					    GNOME_DOCK_ITEM (item),
+					    placement,
+					    band_num,
+					    band_position,
+					    offset);
+	else
+		gnome_dock_add_item (GNOME_DOCK(app->dock),
+				     GNOME_DOCK_ITEM( item),
+				     placement,
+				     band_num,
+				     band_position,
+				     offset,
+				     FALSE);
+
+	gtk_signal_emit_by_name (GTK_OBJECT (app->dock),
+				 "layout_changed",
+				 (gpointer) app);
+}
+
+/**
+ * gnome_app_add_docked:
+ * @app: A &GnomeApp widget
+ * @widget: Widget to be added to the &GnomeApp
+ * @name: Name for the new dock item
+ * @behavior: Behavior for the new dock item
+ * @placement: Placement for the new dock item
+ * @band_num: Number of the band where the dock item should be placed
+ * @band_position: Position of the new dock item in band @band_num
+ * @offset: Offset from the previous dock item in the band; if there is
+ * no previous item, offset from the beginning of the band.
+ *
+ * Returns: The dock item used to contain the widget.
+ * 
+ * Add @widget as a dock item according to the specified layout
+ * information.  Notice that, if automatic layout configuration is
+ * enabled, the layout is overridden by the saved configuration, if
+ * any.
+ **/
+GtkWidget *
+gnome_app_add_docked (GnomeApp *app,
+		      GtkWidget *widget,
+		      const gchar *name,
+		      GnomeDockItemBehavior behavior,
+		      GnomeDockPlacement placement,
+		      gint band_num,
+		      gint band_position,
+		      gint offset)
+{
+	GtkWidget *item;
+
+	item = gnome_dock_item_new (name, behavior);
+	gtk_container_add (GTK_CONTAINER (item), widget);
+	gnome_app_add_dock_item (app, GNOME_DOCK_ITEM (item),
+				 placement, band_num, band_position, offset);
+
+	return item;
+}
+
+/**
+ * gnome_app_enable_layout_config:
+ * @app: A &GnomeApp widget
+ * @enable: Boolean specifying whether automatic configuration saving
+ * is enabled
+ * 
+ * Specify whether @app should automatically save the dock's
+ * layout configuration via gnome-config whenever it changes or not.
+ **/
+void
+gnome_app_enable_layout_config (GnomeApp *app, gboolean enable)
+{
+	app->enable_layout_config = enable;
+}
+
+/**
+ * gnome_app_get_dock_item_by_name:
+ * @app: A &GnomeApp widget
+ * @name: Name of the dock item to retrieve
+ * 
+ * Retrieve the dock item whose name matches @name.
+ * 
+ * Return value: The retrieved dock item.
+ **/
+GnomeDockItem *
+gnome_app_get_dock_item_by_name (GnomeApp *app,
+				 const gchar *name)
+{
+	GnomeDockItem *item;
+
+	item = gnome_dock_get_item_by_name (GNOME_DOCK (app->dock), name,
+					    NULL, NULL, NULL, NULL);
+
+	if (item == NULL && app->layout != NULL) {
+		GnomeDockLayoutItem *i;
+
+		i = gnome_dock_layout_get_item_by_name (app->layout,
+							name);
+		if (i == NULL)
+			return NULL;
+
+		return i->item;
+	} else {
+		return item;
+	}
+}
+
+/**
+ * gnome_app_get_dock:
+ * @app: A &GnomeApp widget
+ * 
+ * Retrieves the &GnomeDock widget contained in the &GnomeApp.
+ * 
+ * Returns: The &GnomeDock widget.
+ **/
+GnomeDock *
+gnome_app_get_dock (GnomeApp *app)
+{
+	return GNOME_DOCK (app->dock);
+}
diff --git a/libgnomeui/gnome-app.h b/libgnomeui/gnome-app.h
new file mode 100644
index 0000000..2e56638
--- /dev/null
+++ b/libgnomeui/gnome-app.h
@@ -0,0 +1,173 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Red Hat Software, The Free
+ * Software Foundation, Miguel de Icaza, Federico Menu, Chris Toshok.
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome 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.
+ *
+ * The Gnome 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 the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.  */
+/*
+  @NOTATION@
+ */
+
+/*
+ *
+ * Originally by Elliot Lee,
+ *
+ * improvements and rearrangement by Miguel,
+ * and I don't know what you other people did :)
+ *
+ * Even more changes by Federico Mena.
+ */
+
+#ifndef GNOME_APP_H
+#define GNOME_APP_H
+
+#include <gtk/gtkmenubar.h>
+#include <gtk/gtktoolbar.h>
+#include <gtk/gtkwindow.h>
+
+
+#include "gnome-dock.h"
+
+G_BEGIN_DECLS
+
+#define GNOME_APP_MENUBAR_NAME "Menubar"
+#define GNOME_APP_TOOLBAR_NAME "Toolbar"
+
+
+#define GNOME_TYPE_APP            (gnome_app_get_type ())
+#define GNOME_APP(obj)            (GTK_CHECK_CAST ((obj), GNOME_TYPE_APP, GnomeApp))
+#define GNOME_APP_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_APP, GnomeAppClass))
+#define GNOME_IS_APP(obj)         (GTK_CHECK_TYPE ((obj), GNOME_TYPE_APP))
+#define GNOME_IS_APP_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_APP))
+#define GNOME_APP_GET_CLASS(obj)  (GTK_CHECK_GET_CLASS ((obj), GNOME_TYPE_APP, GnomeAppClass))
+
+
+typedef struct _GnomeApp        GnomeApp;
+typedef struct _GnomeAppPrivate GnomeAppPrivate;
+typedef struct _GnomeAppClass   GnomeAppClass;
+
+struct _GnomeApp {
+	GtkWindow parent_object;
+
+	/* Application name. */
+	gchar *name;
+
+	/* Prefix for gnome-config (used to save the layout).  */
+	gchar *prefix;
+
+        /* The dock.  */
+        GtkWidget *dock;
+
+	/* The status bar.  */
+        GtkWidget *statusbar;
+
+	/* The vbox widget that ties them.  */
+	GtkWidget *vbox;
+
+	/* The menubar.  This is a pointer to a widget contained into
+           the dock.  */
+	GtkWidget *menubar;
+
+	/* The contents.  This is a pointer to dock->client_area.  */
+	GtkWidget *contents;
+
+	/* Dock layout.  */
+	GnomeDockLayout *layout;
+
+	/* Main accelerator group for this window (hotkeys live here).  */
+	GtkAccelGroup *accel_group;
+
+	/* If TRUE, the application uses gnome-config to retrieve and
+           save the docking configuration automagically.  */
+	gboolean enable_layout_config : 1;
+
+	/*< private >*/
+	GnomeAppPrivate *_priv;
+};
+
+struct _GnomeAppClass {
+	GtkWindowClass parent_class;
+};
+
+
+/* Standard Gtk function */
+GtkType gnome_app_get_type (void) G_GNUC_CONST;
+
+/* Create a new (empty) application window.  You must specify the application's name (used
+ * internally as an identifier).  The window title can be left as NULL, in which case the window's
+ * title will not be set.
+ */
+GtkWidget *gnome_app_new (const gchar *appname, const gchar *title);
+
+/* Constructor for language bindings; you don't normally need this. */
+void gnome_app_construct (GnomeApp *app, const gchar *appname, const gchar *title);
+
+/* Sets the menu bar of the application window */
+void gnome_app_set_menus (GnomeApp *app, GtkMenuBar *menubar);
+
+/* Sets the main toolbar of the application window */
+void gnome_app_set_toolbar (GnomeApp *app, GtkToolbar *toolbar);
+
+/* Sets the status bar of the application window */
+void gnome_app_set_statusbar (GnomeApp *app, GtkWidget *statusbar);
+
+/* Sets the status bar of the application window, but uses the given
+ * container widget rather than creating a new one. */
+void gnome_app_set_statusbar_custom (GnomeApp *app,
+				     GtkWidget *container,
+				     GtkWidget *statusbar);
+
+/* Sets the content area of the application window */
+void gnome_app_set_contents (GnomeApp *app, GtkWidget *contents);
+
+void gnome_app_add_toolbar (GnomeApp *app,
+			    GtkToolbar *toolbar,
+			    const gchar *name,
+			    GnomeDockItemBehavior behavior,
+			    GnomeDockPlacement placement,
+			    gint band_num,
+			    gint band_position,
+			    gint offset);
+
+GtkWidget *gnome_app_add_docked (GnomeApp *app,
+				 GtkWidget *widget,
+				 const gchar *name,
+				 GnomeDockItemBehavior behavior,
+				 GnomeDockPlacement placement,
+				 gint band_num,
+				 gint band_position,
+				 gint offset);
+
+void gnome_app_add_dock_item (GnomeApp *app,
+			      GnomeDockItem *item,
+			      GnomeDockPlacement placement,
+			      gint band_num,
+			      gint band_position,
+			      gint offset);
+
+void gnome_app_enable_layout_config (GnomeApp *app, gboolean enable);
+
+GnomeDock *gnome_app_get_dock (GnomeApp *app);
+
+GnomeDockItem *gnome_app_get_dock_item_by_name (GnomeApp *app,
+						const gchar *name);
+
+G_END_DECLS
+
+#endif /* GNOME_APP_H */
diff --git a/libgnomeui/gnome-appbar.c b/libgnomeui/gnome-appbar.c
new file mode 100644
index 0000000..07d1503
--- /dev/null
+++ b/libgnomeui/gnome-appbar.c
@@ -0,0 +1,759 @@
+/* gnome-appbar.h: statusbar/progress/minibuffer widget for Gnome apps
+ * 
+ * This version by Havoc Pennington
+ * Based on MozStatusbar widget, by Chris Toshok
+ * In turn based on GtkStatusbar widget, from Gtk+,
+ * Copyright (C) 1995-1998 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * GtkStatusbar Copyright (C) 1998 Shawn T. Amundson
+ * All rights reserved.
+ *
+ * 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, Cambridge, MA 02139, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+#include "config.h"
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <string.h> /* for strlen */
+
+#include "gnome-appbar.h"
+
+#include <libgnome/gnome-util.h>
+#include <libgnome/gnome-i18n.h>
+#include <libgnome/gnome-preferences.h>
+
+#include "gnome-uidefs.h"
+
+#ifndef GNOME_ENABLE_DEBUG
+#define GNOME_ENABLE_DEBUG /* to be sure */
+#endif
+
+struct _GnomeAppBarPrivate
+{
+  /* Private; there's no guarantee on the type of these in the
+     future. Statusbar could be a label, entry, GtkStatusbar, or
+     something else; progress could be a label or progress bar; it's
+     all up in the air for now. */
+  GtkWidget * progress;
+  GtkWidget * status;
+  gchar * prompt; /* The text of a prompt, if any. */
+
+  /* Keep it simple; no contexts. 
+     if (status_stack) display_top_of_stack;
+     else if (default_status) display_default;
+     else display_nothing;      */
+  /* Also private by the way */
+  GSList * status_stack;
+  gchar  * default_status;
+
+  gint16 editable_start; /* The first editable position in the interactive
+			  buffer. */
+  gboolean interactive : 1; /* This means status is an entry rather than a
+			       label, for the moment. */
+};
+
+
+static void gnome_appbar_class_init               (GnomeAppBarClass *class);
+static void gnome_appbar_init                     (GnomeAppBar      *ab);
+static void gnome_appbar_destroy                  (GtkObject        *object);
+static void gnome_appbar_finalize                 (GObject          *object);
+     
+static GtkContainerClass *parent_class;
+
+enum {
+  USER_RESPONSE,
+  CLEAR_PROMPT,
+  LAST_SIGNAL
+};
+
+static gint appbar_signals[LAST_SIGNAL] = { 0 };
+
+guint      
+gnome_appbar_get_type ()
+{
+  static guint ab_type = 0;
+
+  if (!ab_type)
+    {
+      GtkTypeInfo ab_info =
+      {
+        "GnomeAppBar",
+        sizeof (GnomeAppBar),
+        sizeof (GnomeAppBarClass),
+        (GtkClassInitFunc) gnome_appbar_class_init,
+        (GtkObjectInitFunc) gnome_appbar_init,
+        NULL,
+        NULL,
+	NULL
+      };
+
+      ab_type = gtk_type_unique (gtk_hbox_get_type (), &ab_info);
+    }
+
+  return ab_type;
+}
+
+static void
+gnome_appbar_class_init (GnomeAppBarClass *class)
+{
+  GtkObjectClass *object_class;
+  GObjectClass *gobject_class;
+  GtkWidgetClass *widget_class;
+  GtkContainerClass *container_class;
+
+  object_class = (GtkObjectClass *) class;
+  gobject_class = (GObjectClass *) class;
+  widget_class = (GtkWidgetClass *) class;
+  container_class = (GtkContainerClass *) class;
+
+  appbar_signals[USER_RESPONSE] =
+    gtk_signal_new ("user_response",
+		    GTK_RUN_LAST,
+		    GTK_CLASS_TYPE (object_class),
+		    GTK_SIGNAL_OFFSET (GnomeAppBarClass, user_response),
+		    gtk_signal_default_marshaller,
+		    GTK_TYPE_NONE, 0);
+
+  appbar_signals[CLEAR_PROMPT] =
+    gtk_signal_new ("clear_prompt",
+		    GTK_RUN_LAST,
+		    GTK_CLASS_TYPE (object_class),
+		    GTK_SIGNAL_OFFSET (GnomeAppBarClass, clear_prompt),
+		    gtk_signal_default_marshaller,
+		    GTK_TYPE_NONE, 0);
+
+  parent_class = gtk_type_class (gtk_hbox_get_type ());
+  
+  class->user_response = NULL;
+  class->clear_prompt  = NULL; /* maybe should have a handler
+				  and the clear_prompt function
+				  just emits. */
+  object_class->destroy = gnome_appbar_destroy;
+  gobject_class->finalize = gnome_appbar_finalize;
+}
+
+static GSList * 
+stringstack_push(GSList * stringstack, const gchar * s)
+{
+  return g_slist_prepend(stringstack, g_strdup(s));
+}
+
+static GSList *
+stringstack_pop(GSList * stringstack)
+{
+  /* Could be optimized */
+  if (stringstack) {
+    g_free(stringstack->data);
+    return g_slist_remove(stringstack, stringstack->data);
+  }
+  else return NULL;
+}
+
+static const gchar *
+stringstack_top(GSList * stringstack)
+{
+  if (stringstack) return stringstack->data;
+  else return NULL;
+}
+
+static void
+stringstack_free(GSList * stringstack)
+{
+  GSList * tmp = stringstack;
+  while (tmp) {
+    g_free(tmp->data);
+    tmp = g_slist_next(tmp);
+  }
+  g_slist_free(stringstack);
+}
+
+static void
+entry_delete_text_cb(GtkWidget * entry, gint start, 
+		     gint stop, GnomeAppBar * ab)
+{
+  g_return_if_fail(GNOME_IS_APPBAR(ab));
+  g_return_if_fail(GTK_IS_ENTRY(entry));
+  g_return_if_fail(ab->_priv->interactive);
+
+  if (ab->_priv->prompt == NULL) return; /* not prompting, so don't 
+				     interfere. */
+#ifdef GNOME_ENABLE_DEBUG
+    g_print("Start is %d, stop is %d, start of editable is %d\n", 
+	    start, stop, ab->_priv->editable_start);
+#endif
+  
+  if (start < ab->_priv->editable_start) {
+    /* Block the signal, since it's trying to delete text
+       that shouldn't be deleted. */
+    gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "delete_text");
+    gdk_beep();
+  }
+}
+static void 
+entry_insert_text_cb  (GtkEditable    *entry,
+		       const gchar    *text,
+		       gint            length,
+		       gint           *position,
+		       GnomeAppBar * ab)
+{
+  gint pos; 
+
+  if (ab->_priv->prompt == NULL) return; /* not prompting, so don't 
+				     interfere. */
+
+  pos = gtk_editable_get_position(entry);
+
+#ifdef GNOME_ENABLE_DEBUG
+    g_print("Position is %d, start of editable is %d\n", 
+	    pos, ab->_priv->editable_start);
+#endif
+
+  if (pos < ab->_priv->editable_start) {
+
+    /*    gtk_editable_set_position(entry, ab->_priv->editable_start); */
+    gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "insert_text");
+    /*    gtk_signal_emit_by_name(GTK_OBJECT(entry), "insert_text",
+			    text, length, position); */
+  }
+}
+
+static gint
+entry_key_press_cb(GtkWidget * entry, GdkEventKey * e, GnomeAppBar * ab)
+{
+  /* This should be some kind of configurable binding
+      or accelerator, probably. */
+  if ( (e->keyval == GDK_g) && 
+       (e->state & GDK_CONTROL_MASK) ) {
+    /* Cancel */
+    gnome_appbar_clear_prompt(ab);
+    return TRUE; /* Override other handlers */
+  }
+  else return FALSE; /* let entry handle it. */
+}
+
+static void
+entry_activate_cb(GtkWidget * entry, GnomeAppBar * ab)
+{
+  gtk_signal_emit(GTK_OBJECT(ab), appbar_signals[USER_RESPONSE]);
+}
+
+static void
+gnome_appbar_init (GnomeAppBar *ab)
+{
+  ab->_priv                 = g_new0(GnomeAppBarPrivate, 1);
+  ab->_priv->default_status = NULL;
+  ab->_priv->status_stack   = NULL;
+  ab->_priv->editable_start = 0;
+  ab->_priv->prompt         = NULL;
+}
+
+
+/**
+ * gnome_appbar_new
+ * @has_progress: %TRUE if appbar needs progress bar widget, %FALSE if not
+ * @has_status: %TRUE if appbar needs status bar widget, %FALSE if not
+ * @interactivity: Level of user activity required
+ *
+ * Description:
+ * Create a new GNOME application status bar.  If @has_progress is
+ * %TRUE, a small progress bar widget will be created, and placed on the
+ * left side of the appbar.  If @has_status is %TRUE, a status bar,
+ * possibly an editable one, is created.
+ *
+ * @interactivity determines whether the appbar is an interactive
+ * "minibuffer" or just a status bar.  If it is set to
+ * %GNOME_PREFERENCES_NEVER, it is never interactive.  If it is set to
+ * %GNOME_PREFERENCES_USER we respect user preferences from
+ * ui-properties. If it's %GNOME_PREFERENCES_ALWAYS we are interactive
+ * whether the user likes it or not. Basically, if your app supports
+ * both interactive and not (for example, if you use the
+ * gnome-app-util interfaces), you should use
+ * %GNOME_PREFERENCES_USER. Otherwise, use the setting you
+ * support. Please note that "interactive" mode is not functional now;
+ * GtkEntry is inadequate and so a custom widget will be written
+ * eventually.
+ *
+ *
+ * Returns:  Pointer to new GNOME appbar widget.
+ **/
+
+GtkWidget* 
+gnome_appbar_new (gboolean has_progress,
+		  gboolean has_status,
+		  GnomePreferencesType interactivity)
+{
+  GnomeAppBar * ab = gtk_type_new (gnome_appbar_get_type ());
+
+  gnome_appbar_construct(ab, has_progress, has_status, interactivity);
+
+  return GTK_WIDGET(ab);
+}
+
+
+/**
+ * gnome_appbar_construct
+ * @ab: Pointer to GNOME appbar object.
+ * @has_progress: %TRUE if appbar needs progress bar widget.
+ * @has_status: %TRUE if appbar needs status bar widget.
+ * @interactivity: See gnome_appbar_new() explanation.
+ *
+ * Description:
+ * For use to bindings in languages other than C. Don't use.
+ **/
+
+void
+gnome_appbar_construct(GnomeAppBar * ab,
+		       gboolean has_progress,
+		       gboolean has_status,
+		       GnomePreferencesType interactivity)
+{
+  GtkBox *box;
+
+  /* These checks are kind of gross because an unfinished object will
+     be returned from _new instead of NULL */
+
+  /* Can't be interactive if there's no status bar */
+  g_return_if_fail( ((has_status == FALSE) && 
+		     (interactivity == GNOME_PREFERENCES_NEVER)) ||
+		    (has_status == TRUE)); 
+
+  box = GTK_BOX (ab);
+
+  box->spacing = GNOME_PAD_SMALL;
+  box->homogeneous = FALSE;
+
+  if (has_progress)
+    ab->_priv->progress = gtk_progress_bar_new();
+  else
+    ab->_priv->progress = NULL;
+
+  /*
+   * If the progress meter goes on the right then we place it after we
+   * create the status line.
+   */
+  if (has_progress && !gnome_preferences_get_statusbar_meter_on_right ())
+    gtk_box_pack_start (box, ab->_priv->progress, FALSE, FALSE, 0);
+
+  if ( has_status ) {
+    if ( (interactivity == GNOME_PREFERENCES_ALWAYS) ||
+	 ( (interactivity == GNOME_PREFERENCES_USER) &&
+	   gnome_preferences_get_statusbar_interactive()) ) {
+      ab->_priv->interactive = TRUE;
+   
+      ab->_priv->status = gtk_entry_new();
+
+      gtk_signal_connect (GTK_OBJECT(ab->_priv->status), "delete_text",
+			  GTK_SIGNAL_FUNC(entry_delete_text_cb),
+			  ab);
+      gtk_signal_connect (GTK_OBJECT(ab->_priv->status), "insert_text",
+			  GTK_SIGNAL_FUNC(entry_insert_text_cb),
+			  ab);
+      gtk_signal_connect_after(GTK_OBJECT(ab->_priv->status), "key_press_event",
+			       GTK_SIGNAL_FUNC(entry_key_press_cb),
+			       ab);
+      gtk_signal_connect(GTK_OBJECT(ab->_priv->status), "activate",
+			 GTK_SIGNAL_FUNC(entry_activate_cb),
+			 ab);
+
+      /* no prompt now */
+      gtk_entry_set_editable(GTK_ENTRY(ab->_priv->status), FALSE);
+
+      gtk_box_pack_start (box, ab->_priv->status, TRUE, TRUE, 0);
+    }
+    else {
+      GtkWidget * frame;
+      
+      ab->_priv->interactive = FALSE;
+
+      frame = gtk_frame_new (NULL);
+      gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_IN);
+      
+      ab->_priv->status = gtk_label_new ("");
+      gtk_misc_set_alignment (GTK_MISC (ab->_priv->status), 0.0, 0.0);
+      gtk_widget_set_usize (ab->_priv->status, 1, -1);
+      
+      gtk_box_pack_start (box, frame, TRUE, TRUE, 0);
+      gtk_container_add (GTK_CONTAINER(frame), ab->_priv->status);
+      
+      gtk_widget_show (frame);
+    }
+  }
+  else {
+    ab->_priv->status = NULL;
+    ab->_priv->interactive = FALSE;
+  }
+
+  if (has_progress && gnome_preferences_get_statusbar_meter_on_right ())
+    gtk_box_pack_start (box, ab->_priv->progress, FALSE, FALSE, 0);
+
+  if (ab->_priv->status) gtk_widget_show (ab->_priv->status);
+  if (ab->_priv->progress) gtk_widget_show(ab->_priv->progress);
+}
+
+
+/**
+ * gnome_appbar_set_prompt
+ * @appbar: Pointer to GNOME appbar object.
+ * @prompt: Text of the prompt message.
+ * @modal: If %TRUE, grabs input.
+ *
+ * Description:
+ * Put a prompt in the appbar and wait for a response. When the
+ * user responds or cancels, a user_response signal is emitted.
+ **/
+
+void
+gnome_appbar_set_prompt (GnomeAppBar * appbar, 
+			 const gchar * prompt,
+			 gboolean modal)
+{
+  g_return_if_fail(appbar != NULL);
+  g_return_if_fail(prompt != NULL);
+  g_return_if_fail(appbar->_priv->interactive);
+
+  /* Remove anything old. */
+  if (appbar->_priv->prompt) {
+    gnome_appbar_clear_prompt(appbar);
+  }
+
+  appbar->_priv->prompt = g_strconcat(prompt, "  ", NULL);
+
+  if (modal) gtk_grab_add(appbar->_priv->status);
+
+  gnome_appbar_refresh(appbar);
+}
+
+
+/**
+ * gnome_appbar_clear_prompt
+ * @appbar: Pointer to GNOME appbar object
+ *
+ * Description:
+ * Remove any prompt.
+ **/
+
+void       
+gnome_appbar_clear_prompt    (GnomeAppBar * appbar)
+{
+  g_return_if_fail(appbar != NULL);
+  g_return_if_fail(appbar->_priv->interactive);
+
+  /* This isn't really right; most of Gtk would only emit here,
+     and then have a clear_prompt_real as default handler. */
+  
+  g_free(appbar->_priv->prompt);
+  appbar->_priv->prompt = NULL;
+
+  gnome_appbar_refresh(appbar);
+
+  gtk_signal_emit(GTK_OBJECT(appbar), 
+		  appbar_signals[CLEAR_PROMPT]);  
+}
+
+
+/**
+ * gnome_appbar_get_response
+ * @appbar: Pointer to GNOME appbar object
+ *
+ * Description:
+ * Get the response to the prompt, if any. Result must be g_free'd.
+ *
+ * Returns:
+ * Text from appbar entry widget, as entered by user.
+ **/
+
+gchar *    
+gnome_appbar_get_response    (GnomeAppBar * appbar)
+{
+  g_return_val_if_fail(appbar != NULL, NULL);
+  g_return_val_if_fail(appbar->_priv->interactive, NULL);
+  g_return_val_if_fail(appbar->_priv->prompt != NULL, NULL);
+  
+  /* This returns an allocated string. */
+  return gtk_editable_get_chars(GTK_EDITABLE(appbar->_priv->status),
+				appbar->_priv->editable_start, 
+				GTK_ENTRY(appbar->_priv->status)->text_length);
+} 
+
+
+/**
+ * gnome_appbar_refresh
+ * @appbar: Pointer to GNOME appbar object
+ *
+ * Description:
+ * Reflect the current state of stack/default. Useful to force a
+ * set_status to disappear.
+ **/
+
+void 
+gnome_appbar_refresh           (GnomeAppBar * appbar)
+{
+  g_return_if_fail(appbar != NULL);
+  g_return_if_fail(GNOME_IS_APPBAR(appbar));
+  
+  if (appbar->_priv->prompt) {
+    g_return_if_fail(appbar->_priv->interactive); /* Just a consistency check */
+    gtk_entry_set_editable(GTK_ENTRY(appbar->_priv->status), TRUE);
+    /* Allow insert_text to work, so we can set the prompt. */
+    appbar->_priv->editable_start = 0;
+    gtk_entry_set_text(GTK_ENTRY(appbar->_priv->status), appbar->_priv->prompt);
+    /* This has to be after setting the text. */
+    appbar->_priv->editable_start = strlen(appbar->_priv->prompt);   
+    gtk_entry_set_position(GTK_ENTRY(appbar->_priv->status), 
+			   appbar->_priv->editable_start);
+    gtk_widget_grab_focus(appbar->_priv->status);
+  }
+  else {
+    if (appbar->_priv->interactive) {
+      appbar->_priv->editable_start = 0;
+      gtk_entry_set_editable(GTK_ENTRY(appbar->_priv->status), FALSE);
+      gtk_grab_remove(appbar->_priv->status); /* In case */
+    }
+
+    if (appbar->_priv->status_stack)
+      gnome_appbar_set_status(appbar, stringstack_top(appbar->_priv->status_stack));
+    else if (appbar->_priv->default_status)
+      gnome_appbar_set_status(appbar, appbar->_priv->default_status);
+    else 
+      gnome_appbar_set_status(appbar, "");
+  }
+}
+
+
+/**
+ * gnome_appbar_set_status
+ * @appbar: Pointer to GNOME appbar object.
+ * @status: Text to which status label will be set.
+ *
+ * Description:
+ * Sets the status label without changing widget state; next set or push
+ * will destroy this permanently. 
+ **/
+
+void       
+gnome_appbar_set_status       (GnomeAppBar * appbar,
+			       const gchar * status)
+{
+  g_return_if_fail(appbar != NULL);
+  g_return_if_fail(status != NULL);
+  g_return_if_fail(GNOME_IS_APPBAR(appbar));
+
+  if (appbar->_priv->interactive) 
+    gtk_entry_set_text(GTK_ENTRY(appbar->_priv->status), status);
+  else
+    gtk_label_set_text(GTK_LABEL(appbar->_priv->status), status);
+}
+
+
+/**
+ * gnome_appbar_set_default
+ * @appbar: Pointer to GNOME appbar object
+ * @default_status: Text for status label
+ *
+ * Description:
+ * What to show when showing nothing else; defaults to nothing.
+ **/
+
+void	   
+gnome_appbar_set_default      (GnomeAppBar * appbar,
+			       const gchar * default_status)
+{
+  g_return_if_fail(appbar != NULL);
+  g_return_if_fail(default_status != NULL);
+  g_return_if_fail(GNOME_IS_APPBAR(appbar));
+  
+  /* g_free handles NULL */
+  g_free(appbar->_priv->default_status);
+  appbar->_priv->default_status = g_strdup(default_status);
+  gnome_appbar_refresh(appbar);
+}
+
+
+/**
+ * gnome_appbar_push
+ * @appbar: Pointer to GNOME appbar object
+ * @status: Text of status message.
+ *
+ * Description:
+ * Push a new status message onto the status bar stack, and
+ * display it.
+ **/
+
+void       
+gnome_appbar_push             (GnomeAppBar * appbar,
+			       const gchar * status)
+{
+  g_return_if_fail(appbar != NULL);
+  g_return_if_fail(status != NULL);
+  g_return_if_fail(GNOME_IS_APPBAR(appbar));
+
+  appbar->_priv->status_stack = stringstack_push(appbar->_priv->status_stack, status);
+  gnome_appbar_refresh(appbar);
+}
+
+
+/**
+ * gnome_appbar_pop
+ * @appbar: Pointer to GNOME appbar object
+ *
+ * Description:
+ * Remove current status message, and display previous status
+ * message, if any.  It is OK to call this with an empty stack.
+ **/
+
+void       
+gnome_appbar_pop              (GnomeAppBar * appbar)
+{
+  g_return_if_fail(appbar != NULL);
+  g_return_if_fail(GNOME_IS_APPBAR(appbar));
+  
+  appbar->_priv->status_stack = stringstack_pop(appbar->_priv->status_stack);
+  gnome_appbar_refresh(appbar);
+}
+
+
+/**
+ * gnome_appbar_clear_stack
+ * @appbar: Pointer to GNOME appbar object
+ *
+ * Description:
+ * Remove all status messages from appbar, and display default status
+ * message (if present).
+ **/
+
+void       
+gnome_appbar_clear_stack      (GnomeAppBar * appbar)
+{
+  g_return_if_fail(appbar != NULL);
+  g_return_if_fail(GNOME_IS_APPBAR(appbar));
+
+  stringstack_free(appbar->_priv->status_stack);
+  appbar->_priv->status_stack = NULL;
+  gnome_appbar_refresh(appbar);
+}
+
+
+/**
+ * gnome_appbar_set_progress_precentage
+ * @appbar: Pointer to GNOME appbar object
+ * @percentage: Percentage to which progress bar should be set.
+ *
+ * Description:
+ * Sets progress bar to the given percentage.
+ **/
+
+void
+gnome_appbar_set_progress_percentage(GnomeAppBar *appbar,
+				     gfloat percentage)
+{
+  g_return_if_fail (appbar != NULL);
+  g_return_if_fail (appbar->_priv->progress != NULL);
+  g_return_if_fail (GNOME_IS_APPBAR(appbar));
+
+  gtk_progress_bar_update(GTK_PROGRESS_BAR(appbar->_priv->progress), percentage);
+}
+
+
+/**
+ * gnome_appbar_get_progress
+ * @appbar: Pointer to GNOME appbar object
+ *
+ * Description:
+ * Returns &GtkProgress widget pointer, so that the progress bar may be
+ * manipulated further.
+ *
+ * Returns:
+ * Pointer to appbar's progress bar object. May be NULL if the appbar
+ * has no progress object.
+ **/
+
+GtkProgress* 
+gnome_appbar_get_progress    (GnomeAppBar * appbar)
+{
+  g_return_val_if_fail(appbar != NULL, NULL);
+  g_return_val_if_fail(GNOME_IS_APPBAR(appbar), NULL);
+  g_return_val_if_fail(appbar->_priv->progress != NULL, NULL);
+
+  return GTK_PROGRESS(appbar->_priv->progress);
+}
+
+/**
+ * gnome_appbar_get_status
+ * @appbar: Pointer to GNOME appbar object
+ *
+ * Description:
+ * Returns the statusbar widget.
+ *
+ * Returns:
+ * A pointer to the statusbar widget.
+ **/
+GtkWidget *
+gnome_appbar_get_status    (GnomeAppBar * appbar)
+{
+  g_return_val_if_fail(appbar != NULL, NULL);
+  g_return_val_if_fail(GNOME_IS_APPBAR(appbar), NULL);
+
+  return (appbar->_priv->status);
+}
+
+static void
+gnome_appbar_destroy (GtkObject *object)
+{
+  GnomeAppBar *ab;
+  GnomeAppBarClass *class;
+
+  /* remember, destroy can be run multiple times! */
+
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GNOME_IS_APPBAR (object));
+
+  ab = GNOME_APPBAR (object);
+  class = GNOME_APPBAR_GET_CLASS (ab);
+
+  if(ab->_priv->status_stack) {
+	  stringstack_free(ab->_priv->status_stack);
+	  ab->_priv->status_stack = NULL;
+  }
+
+  /* g_free checks if these are NULL */
+  g_free(ab->_priv->default_status);
+  ab->_priv->default_status = NULL;;
+  g_free(ab->_priv->prompt);
+  ab->_priv->prompt = NULL;
+
+  if(GTK_OBJECT_CLASS (parent_class)->destroy)
+	  GTK_OBJECT_CLASS (parent_class)->destroy (object);
+}
+
+static void
+gnome_appbar_finalize (GObject *object)
+{
+  GnomeAppBar *ab;
+
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GNOME_IS_APPBAR (object));
+
+  ab = GNOME_APPBAR (object);
+
+  g_free(ab->_priv);
+  ab->_priv = NULL;
+
+  if(G_OBJECT_CLASS (parent_class)->finalize)
+	  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
diff --git a/libgnomeui/gnome-appbar.h b/libgnomeui/gnome-appbar.h
new file mode 100644
index 0000000..8334c7d
--- /dev/null
+++ b/libgnomeui/gnome-appbar.h
@@ -0,0 +1,138 @@
+/* gnome-appbar.h: statusbar/progress/minibuffer widget for Gnome apps
+ * 
+ * This version by Havoc Pennington
+ * Based on MozStatusbar widget, by Chris Toshok
+ * In turn based on GtkStatusbar widget, from Gtk+,
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * GtkStatusbar Copyright (C) 1998 Shawn T. Amundson
+ * All rights reserved.
+ *
+ * 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, Cambridge, MA 02139, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+#ifndef __GNOME_APPBAR_H__
+#define __GNOME_APPBAR_H__
+
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkprogress.h>
+
+
+#include "gnome-types.h"
+
+G_BEGIN_DECLS
+
+#define GNOME_TYPE_APPBAR            (gnome_appbar_get_type ())
+#define GNOME_APPBAR(obj)            (GTK_CHECK_CAST ((obj), GNOME_TYPE_APPBAR, GnomeAppBar))
+#define GNOME_APPBAR_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_APPBAR, GnomeAppBarClass))
+#define GNOME_IS_APPBAR(obj)         (GTK_CHECK_TYPE ((obj), GNOME_TYPE_APPBAR))
+#define GNOME_IS_APPBAR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_APPBAR))
+#define GNOME_APPBAR_GET_CLASS(obj)  (GTK_CHECK_GET_CLASS ((obj), GNOME_TYPE_APPBAR, GnomeAppBarClass))
+
+/* Used in gnome-app-util to determine the capabilities of the appbar */
+#define GNOME_APPBAR_HAS_STATUS(appbar) (gnome_appbar_get_status(GNOME_APPBAR(appbar)) != NULL)
+#define GNOME_APPBAR_HAS_PROGRESS(appbar) (gnome_appbar_get_progress(GNOME_APPBAR(appbar)) != NULL)
+
+typedef struct _GnomeAppBar        GnomeAppBar;
+typedef struct _GnomeAppBarPrivate GnomeAppBarPrivate;
+typedef struct _GnomeAppBarClass   GnomeAppBarClass;
+typedef struct _GnomeAppBarMsg     GnomeAppBarMsg;
+
+struct _GnomeAppBar
+{
+  GtkHBox parent_widget;
+
+  /*< private >*/
+  GnomeAppBarPrivate *_priv;
+};
+
+struct _GnomeAppBarClass
+{
+  GtkHBoxClass parent_class;
+
+  /* Emitted when the user hits enter after a prompt. */
+  void (* user_response) (GnomeAppBar * ab);
+  /* Emitted when the prompt is cleared. */
+  void (* clear_prompt)  (GnomeAppBar * ab);
+};
+
+#define GNOME_APPBAR_INTERACTIVE(ab) ((ab) ? (ab)->interactive : FALSE)
+
+guint      gnome_appbar_get_type     	(void) G_GNUC_CONST;
+
+GtkWidget* gnome_appbar_new          	(gboolean has_progress, 
+					 gboolean has_status,
+					 GnomePreferencesType interactivity);
+
+/* Sets the status label without changing widget state; next set or push
+   will destroy this permanently. */
+void       gnome_appbar_set_status       (GnomeAppBar * appbar,
+					  const gchar * status);
+
+/* get the statusbar */
+GtkWidget* gnome_appbar_get_status       (GnomeAppBar * appbar);
+
+/* What to show when showing nothing else; defaults to nothing */
+void	   gnome_appbar_set_default      (GnomeAppBar * appbar,
+					  const gchar * default_status);
+
+void       gnome_appbar_push             (GnomeAppBar * appbar,
+					  const gchar * status);
+/* OK to call on empty stack */
+void       gnome_appbar_pop              (GnomeAppBar * appbar);
+
+/* Nuke the stack. */
+void       gnome_appbar_clear_stack      (GnomeAppBar * appbar);
+
+/* Sugar function to set the percentage of the progressbar. */
+void	     gnome_appbar_set_progress_percentage	  (GnomeAppBar *appbar,
+							   gfloat percentage);
+/* use GtkProgress functions on returned value */
+GtkProgress* gnome_appbar_get_progress    (GnomeAppBar * appbar);
+
+/* Reflect the current state of stack/default. Useful to force a set_status
+   to disappear. */
+void       gnome_appbar_refresh         (GnomeAppBar * appbar);
+
+/* Put a prompt in the appbar and wait for a response. When the 
+   user responds or cancels, a user_response signal is emitted. */
+void       gnome_appbar_set_prompt          (GnomeAppBar * appbar,
+					     const gchar * prompt,
+					     gboolean modal);
+/* Remove any prompt */
+void       gnome_appbar_clear_prompt    (GnomeAppBar * appbar);
+
+/* Get the response to the prompt, if any. Result must be g_free'd. */
+gchar *    gnome_appbar_get_response    (GnomeAppBar * appbar);
+
+
+/* For use to bindings in languages other than C. Don't use. */
+void       gnome_appbar_construct(GnomeAppBar * ab,
+				  gboolean has_progress,
+				  gboolean has_status,
+				  GnomePreferencesType interactivity);
+
+G_END_DECLS
+
+#endif /* __GNOME_APPBAR_H__ */
+
+
+
+
+
+
+



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