[eog] Revert "Remove all other references to the toolbar"



commit c8a25656244e794fc85a8d7058d54b8b1def966b
Author: Felix Riemann <friemann gnome org>
Date:   Wed Dec 17 21:39:58 2014 +0100

    Revert "Remove all other references to the toolbar"
    
    This reverts commit 6df4284cda1954e4192d387a676df1fc50730647.

 Makefile.am                                        |    2 +-
 configure.ac                                       |    9 +
 cut-n-paste/Makefile.am                            |    3 +
 cut-n-paste/toolbar-editor/Makefile.am             |  105 ++
 cut-n-paste/toolbar-editor/egg-editable-toolbar.c  | 1936 ++++++++++++++++++++
 cut-n-paste/toolbar-editor/egg-editable-toolbar.h  |   95 +
 cut-n-paste/toolbar-editor/egg-toolbar-editor.c    |  677 +++++++
 cut-n-paste/toolbar-editor/egg-toolbar-editor.h    |   63 +
 cut-n-paste/toolbar-editor/egg-toolbars-model.c    |  987 ++++++++++
 cut-n-paste/toolbar-editor/egg-toolbars-model.h    |  190 ++
 cut-n-paste/toolbar-editor/eggmarshalers.list      |    1 +
 .../update-toolbareditor-from-libegg.sh            |   33 +
 data/Makefile.am                                   |    5 +
 data/eog-app-menu.xml                              |    4 +
 data/eog-toolbar.xml                               |   37 +
 data/eog-ui.xml                                    |    2 +
 data/eog.convert                                   |    1 +
 data/org.gnome.eog.gschema.xml.in                  |    6 +-
 doc/reference/Makefile.am                          |    2 +
 doc/reference/eog-sections.txt                     |    4 +
 tests/actions.feature                              |    9 +
 21 files changed, 4169 insertions(+), 2 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 5e2d014..9094eaf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,7 @@ if ENABLE_JPEG
 jpeg_DIRS = jpegutils
 endif
 
-SUBDIRS = $(jpeg_DIRS) src plugins po help data doc
+SUBDIRS = $(jpeg_DIRS) cut-n-paste src plugins po help data doc
 
 ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
 
diff --git a/configure.ac b/configure.ac
index c01e30e..3ca9d02 100644
--- a/configure.ac
+++ b/configure.ac
@@ -263,6 +263,13 @@ AC_SUBST(LIBJPEG)
 AM_CONDITIONAL(ENABLE_JPEG, test x$have_jpeg = xyes)
 AM_CONDITIONAL(HAVE_LIBJPEG_80, test "x$have_libjpeg_80" = xyes)
 
+# ************************************
+# libXML2 (required for toolbareditor)
+# ************************************
+
+LIBXML2_REQUIRED=2.0
+PKG_CHECK_MODULES(LIBXML2, [libxml-2.0 >= $LIBXML2_REQUIRED])
+
 # ***************
 # RSVG (optional for scaling svg image)
 # ***************
@@ -327,6 +334,8 @@ AC_CONFIG_FILES([
 Makefile
 src/Makefile
 jpegutils/Makefile
+cut-n-paste/Makefile
+cut-n-paste/toolbar-editor/Makefile
 help/Makefile
 po/Makefile.in
 data/Makefile
diff --git a/cut-n-paste/Makefile.am b/cut-n-paste/Makefile.am
new file mode 100644
index 0000000..e105f1d
--- /dev/null
+++ b/cut-n-paste/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = toolbar-editor
+
+-include $(top_srcdir)/git.mk
diff --git a/cut-n-paste/toolbar-editor/Makefile.am b/cut-n-paste/toolbar-editor/Makefile.am
new file mode 100644
index 0000000..28e907f
--- /dev/null
+++ b/cut-n-paste/toolbar-editor/Makefile.am
@@ -0,0 +1,105 @@
+EGGSOURCES = \
+       egg-editable-toolbar.c \
+       egg-toolbars-model.c \
+       egg-toolbar-editor.c
+
+EGGHEADERS = \
+       egg-editable-toolbar.h \
+       egg-toolbars-model.h \
+       egg-toolbar-editor.h
+
+noinst_HEADERS = \
+       $(EGGHEADERS) \
+       eggmarshalers.h
+
+noinst_LTLIBRARIES = libtoolbareditor.la
+
+libtoolbareditor_la_SOURCES =  \
+       $(BUILT_SOURCES)        \
+       $(EGGSOURCES)           \
+       $(EGGHEADERS)
+
+libtoolbareditor_la_LIBADD = $(LIBXML2_LIBS)
+
+libtoolbareditor_la_CFLAGS = \
+       $(EOG_CFLAGS)                           \
+       $(WARN_CFLAGS)                          \
+       $(LIBXML2_CFLAGS)                       \
+       -DCURSOR_DIR=\"$(pkgdatadir)\"
+
+BUILT_SOURCES = \
+       eggmarshalers.c \
+       eggmarshalers.h \
+       eggtypebuiltins.c \
+       eggtypebuiltins.h
+
+stamp_files = \
+       stamp-eggmarshalers.c \
+       stamp-eggmarshalers.h \
+       stamp-eggtypebuiltins.c \
+       stamp-eggtypebuiltins.h
+
+eggmarshalers.h: stamp-eggmarshalers.h
+       @true
+stamp-eggmarshalers.h: eggmarshalers.list
+       $(AM_V_GEN)$(GLIB_GENMARSHAL) --internal --prefix=_egg_marshal $(srcdir)/eggmarshalers.list --header 
eggmarshalers.h \
+       && echo timestamp > $(@F)
+
+eggmarshalers.c: stamp-eggmarshalers.c
+       @true
+stamp-eggmarshalers.c: eggmarshalers.list
+       $(AM_V_GEN)$(GLIB_GENMARSHAL) --prefix=_egg_marshal $(srcdir)/eggmarshalers.list --header --body > 
eggmarshalers.c \
+       && echo timestamp > $(@F)
+
+eggtypebuiltins.c: stamp-eggtypebuiltins.c
+       @true
+stamp-eggtypebuiltins.c: $(EGGHEADERS)
+       $(AM_V_GEN)( cd $(srcdir) && $(GLIB_MKENUMS) \
+               --fhead "#include \"eggtypebuiltins.h\"\n\n" \
+               --fprod "\n/* enumerations from \"@filename \" */" \
+               --fprod "\n#include \"@filename \"" \
+               --vhead "static const G Type@Value _ enum_name@_values[] = {" \
+               --vprod "  { @VALUENAME@, \"@VALUENAME \", \"@valuenick \" }," \
+               --vtail "  { 0, NULL, NULL }\n};\n\n" \
+               --vtail "G_GNUC_INTERNAL GType\n enum_name@_get_type (void)\n{\n" \
+               --vtail "  static GType type = 0;\n\n" \
+               --vtail "  if (G_UNLIKELY (type == 0))\n" \
+               --vtail "    type = g_ type@_register_static (\"@EnumName \", _ enum_name@_values);\n\n" \
+               --vtail "  return type;\n}\n\n" \
+               $(^F) ) > xgen-$(@F) \
+       && ( cmp -s xgen-$(@F) $(@F:stamp-%=%) || cp xgen-$(@F) $(@F:stamp-%=%) ) \
+       && rm -f xgen-$(@F) \
+       && echo timestamp > $(@F)
+
+eggtypebuiltins.h: stamp-eggtypebuiltins.h
+       @true
+stamp-eggtypebuiltins.h: $(EGGHEADERS)
+       $(AM_V_GEN)( cd $(srcdir) && $(GLIB_MKENUMS) \
+               --fhead "#ifndef __EGGTYPEBUILTINS_H__\n" \
+               --fhead "#define __EGGTYPEBUILTINS_H__ 1\n\n" \
+               --fhead "#include <glib-object.h>\n\n" \
+               --fhead "G_BEGIN_DECLS\n\n" \
+               --ftail "G_END_DECLS\n\n" \
+               --ftail "#endif /* __EGGTYPEBUILTINS_H__ */\n" \
+               --fprod "\n/* --- @filename@ --- */" \
+               --eprod "#define EGG_TYPE_ ENUMSHORT@ @enum_name _get_type()\n" \
+               --eprod "G_GNUC_INTERNAL GType @enum_name _get_type (void);\n" \
+               $(^F) ) > xgen-$(@F) \
+       && ( cmp -s xgen-$(@F) $(@F:stamp-%=%) || cp xgen-$(@F) $(@F:stamp-%=%) ) \
+       && rm -f xgen-$(@F) \
+       && echo timestamp > $(@F)
+
+EXTRA_DIST = \
+       eggmarshalers.list
+
+EGGFILES=$(EGGSOURCES) $(EGGHEADERS)
+EGGDIR=$(srcdir)/../../../libegg/libegg
+
+regenerate-built-sources:
+       EGGFILES="$(EGGFILES) eggmarshalers.list" EGGDIR="$(EGGDIR)" 
$(top_srcdir)/cut-n-paste/update-from-egg.sh
+
+CLEANFILES = $(stamp_files) $(BUILT_SOURCES)
+DISTCLEANFILES = $(stamp_files) $(BUILT_SOURCES)
+MAINTAINERCLEANFILES = $(stamp_files) $(BUILT_SOURCES)
+
+-include $(top_srcdir)/git.mk
diff --git a/cut-n-paste/toolbar-editor/egg-editable-toolbar.c 
b/cut-n-paste/toolbar-editor/egg-editable-toolbar.c
new file mode 100644
index 0000000..3613578
--- /dev/null
+++ b/cut-n-paste/toolbar-editor/egg-editable-toolbar.c
@@ -0,0 +1,1936 @@
+/*
+ *  Copyright (C) 2003, 2004  Marco Pesenti Gritti
+ *  Copyright (C) 2003, 2004, 2005  Christian Persch
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *  $Id: egg-editable-toolbar.c 937 2009-04-07 11:16:53Z friemann $
+ */
+
+#include "config.h"
+
+#include "egg-editable-toolbar.h"
+#include "egg-toolbars-model.h"
+#include "egg-toolbar-editor.h"
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <string.h>
+
+static GdkPixbuf * new_separator_pixbuf         (void);
+
+#define MIN_TOOLBAR_HEIGHT 20
+#define EGG_ITEM_NAME      "egg-item-name"
+#define STOCK_DRAG_MODE    "stock_drag-mode"
+
+static const GtkTargetEntry dest_drag_types[] = {
+  {EGG_TOOLBAR_ITEM_TYPE, GTK_TARGET_SAME_APP, 0},
+};
+
+enum
+{
+  PROP_0,
+  PROP_TOOLBARS_MODEL,
+  PROP_UI_MANAGER,
+  PROP_POPUP_PATH,
+  PROP_SELECTED,
+  PROP_EDIT_MODE
+};
+
+enum
+{
+  ACTION_REQUEST,
+  LAST_SIGNAL
+};
+
+static guint egg_editable_toolbar_signals[LAST_SIGNAL] = { 0 };
+
+#define EGG_EDITABLE_TOOLBAR_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), 
EGG_TYPE_EDITABLE_TOOLBAR, EggEditableToolbarPrivate))
+
+struct _EggEditableToolbarPrivate
+{
+  GtkUIManager *manager;
+  EggToolbarsModel *model;
+  guint edit_mode;
+  gboolean save_hidden;
+  GtkWidget *fixed_toolbar;
+
+  GtkWidget *selected;
+  GtkActionGroup *actions;
+
+  guint visibility_id;
+  GList *visibility_paths;
+  GPtrArray *visibility_actions;
+
+  char *popup_path;
+
+  guint        dnd_pending;
+  GtkToolbar  *dnd_toolbar;
+  GtkToolItem *dnd_toolitem;
+
+  gboolean set_primary_class;
+  gchar *primary_name;
+};
+
+G_DEFINE_TYPE (EggEditableToolbar, egg_editable_toolbar, GTK_TYPE_BOX);
+
+static int
+get_dock_position (EggEditableToolbar *etoolbar,
+                   GtkWidget *dock)
+{
+  GList *l;
+  int result;
+
+  l = gtk_container_get_children (GTK_CONTAINER (etoolbar));
+  result = g_list_index (l, dock);
+  g_list_free (l);
+
+  return result;
+}
+
+static int
+get_toolbar_position (EggEditableToolbar *etoolbar, GtkWidget *toolbar)
+{
+  return get_dock_position (etoolbar, gtk_widget_get_parent (toolbar));
+}
+
+static int
+get_n_toolbars (EggEditableToolbar *etoolbar)
+{
+  GList *l;
+  int result;
+
+  l = gtk_container_get_children (GTK_CONTAINER (etoolbar));
+  result = g_list_length (l);
+  g_list_free (l);
+
+  return result;
+}
+
+static GtkWidget *
+get_dock_nth (EggEditableToolbar *etoolbar,
+             int                 position)
+{
+  GList *l;
+  GtkWidget *result;
+
+  l = gtk_container_get_children (GTK_CONTAINER (etoolbar));
+  result = g_list_nth_data (l, position);
+  g_list_free (l);
+
+  return result;
+}
+
+static GtkWidget *
+get_toolbar_nth (EggEditableToolbar *etoolbar,
+                int                 position)
+{
+  GList *l;
+  GtkWidget *dock;
+  GtkWidget *result;
+
+  dock = get_dock_nth (etoolbar, position);
+  g_return_val_if_fail (dock != NULL, NULL);
+
+  l = gtk_container_get_children (GTK_CONTAINER (dock));
+  result = GTK_WIDGET (l->data);
+  g_list_free (l);
+
+  return result;
+}
+
+static GtkAction *
+find_action (EggEditableToolbar *etoolbar,
+            const char         *name)
+{
+  GList *l;
+  GtkAction *action = NULL;
+
+  l = gtk_ui_manager_get_action_groups (etoolbar->priv->manager);
+
+  g_return_val_if_fail (name != NULL, NULL);
+
+  for (; l != NULL; l = l->next)
+    {
+      GtkAction *tmp;
+
+      tmp = gtk_action_group_get_action (GTK_ACTION_GROUP (l->data), name);
+      if (tmp)
+       action = tmp;
+    }
+
+  return action;
+}
+
+static void
+drag_data_delete_cb (GtkWidget          *widget,
+                    GdkDragContext     *context,
+                    EggEditableToolbar *etoolbar)
+{
+  int pos, toolbar_pos;
+  GtkWidget *parent;
+
+  widget = gtk_widget_get_ancestor (widget, GTK_TYPE_TOOL_ITEM);
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (EGG_IS_EDITABLE_TOOLBAR (etoolbar));
+
+  parent = gtk_widget_get_parent (widget);
+  pos = gtk_toolbar_get_item_index (GTK_TOOLBAR (parent),
+                                   GTK_TOOL_ITEM (widget));
+  toolbar_pos = get_toolbar_position (etoolbar, parent);
+
+  egg_toolbars_model_remove_item (etoolbar->priv->model,
+                                 toolbar_pos, pos);
+}
+
+static void
+drag_begin_cb (GtkWidget          *widget,
+              GdkDragContext     *context,
+              EggEditableToolbar *etoolbar)
+{
+  GtkAction *action;
+  gint flags;
+
+  gtk_widget_hide (widget);
+
+#if GTK_CHECK_VERSION (2, 16, 0)
+  action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (widget));
+#else
+  action = gtk_widget_get_action (widget);
+#endif
+
+  if (action == NULL) return;
+
+  flags = egg_toolbars_model_get_name_flags (etoolbar->priv->model,
+                                            gtk_action_get_name (action));
+  if (!(flags & EGG_TB_MODEL_NAME_INFINITE))
+    {
+      flags &= ~EGG_TB_MODEL_NAME_USED;
+      egg_toolbars_model_set_name_flags (etoolbar->priv->model,
+                                        gtk_action_get_name (action),
+                                        flags);
+    }
+}
+
+static void
+drag_end_cb (GtkWidget          *widget,
+            GdkDragContext     *context,
+            EggEditableToolbar *etoolbar)
+{
+  GtkAction *action;
+  gint flags;
+
+  if (gtk_widget_get_parent (widget) != NULL)
+    {
+      gtk_widget_show (widget);
+
+#if GTK_CHECK_VERSION (2, 16, 0)
+      action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (widget));
+#else
+      action = gtk_widget_get_action (widget);
+#endif
+
+      if (action == NULL) return;
+
+      flags = egg_toolbars_model_get_name_flags (etoolbar->priv->model,
+                                                gtk_action_get_name (action));
+      if (!(flags & EGG_TB_MODEL_NAME_INFINITE))
+        {
+         flags |= EGG_TB_MODEL_NAME_USED;
+         egg_toolbars_model_set_name_flags (etoolbar->priv->model,
+                                            gtk_action_get_name (action),
+                                            flags);
+       }
+    }
+}
+
+static void
+drag_data_get_cb (GtkWidget          *widget,
+                 GdkDragContext     *context,
+                 GtkSelectionData   *selection_data,
+                 guint               info,
+                 guint32             time,
+                 EggEditableToolbar *etoolbar)
+{
+  EggToolbarsModel *model;
+  const char *name;
+  char *data;
+  GdkAtom target;
+
+  g_return_if_fail (EGG_IS_EDITABLE_TOOLBAR (etoolbar));
+  model = egg_editable_toolbar_get_model (etoolbar);
+
+  name = g_object_get_data (G_OBJECT (widget), EGG_ITEM_NAME);
+  if (name == NULL)
+    {
+      name = g_object_get_data (G_OBJECT (gtk_widget_get_parent (widget)), EGG_ITEM_NAME);
+      g_return_if_fail (name != NULL);
+    }
+
+  target = gtk_selection_data_get_target (selection_data);
+  data = egg_toolbars_model_get_data (model, target, name);
+  if (data != NULL)
+    {
+      gtk_selection_data_set (selection_data, target, 8, (unsigned char *)data, strlen (data));
+      g_free (data);
+    }
+}
+
+static void
+move_item_cb (GtkAction          *action,
+              EggEditableToolbar *etoolbar)
+{
+  GtkWidget *toolitem = gtk_widget_get_ancestor (egg_editable_toolbar_get_selected (etoolbar), 
GTK_TYPE_TOOL_ITEM);
+  GtkTargetList *list = gtk_target_list_new (dest_drag_types, G_N_ELEMENTS (dest_drag_types));
+
+  GdkEvent *realevent = gtk_get_current_event();
+  GdkEvent *event = gdk_event_new (GDK_MOTION_NOTIFY);
+  event->motion.window = g_object_ref (realevent->any.window);
+  event->motion.send_event = FALSE;
+  event->motion.axes = NULL;
+  event->motion.time = gdk_event_get_time (realevent);
+  gdk_event_set_device (event, gdk_event_get_device (realevent));
+  gdk_event_get_state (realevent, &event->motion.state);
+  gdk_event_get_coords (realevent, &event->motion.x, &event->motion.y);
+  gdk_event_get_root_coords (realevent, &event->motion.x_root, &event->motion.y_root);
+
+  gtk_drag_begin (toolitem, list, GDK_ACTION_MOVE, 1, event);
+  gdk_event_free (event);
+  gtk_target_list_unref (list);
+}
+
+static void
+remove_item_cb (GtkAction          *action,
+                EggEditableToolbar *etoolbar)
+{
+  GtkWidget *toolitem = gtk_widget_get_ancestor (egg_editable_toolbar_get_selected (etoolbar), 
GTK_TYPE_TOOL_ITEM);
+  GtkWidget *parent = gtk_widget_get_parent (toolitem);
+  int pos, toolbar_pos;
+
+  toolbar_pos = get_toolbar_position (etoolbar, parent);
+  pos = gtk_toolbar_get_item_index (GTK_TOOLBAR (parent),
+                                   GTK_TOOL_ITEM (toolitem));
+
+  egg_toolbars_model_remove_item (etoolbar->priv->model,
+                                 toolbar_pos, pos);
+
+  if (egg_toolbars_model_n_items (etoolbar->priv->model, toolbar_pos) == 0)
+    {
+      egg_toolbars_model_remove_toolbar (etoolbar->priv->model, toolbar_pos);
+    }
+}
+
+static void
+remove_toolbar_cb (GtkAction          *action,
+                  EggEditableToolbar *etoolbar)
+{
+  GtkWidget *selected = egg_editable_toolbar_get_selected (etoolbar);
+  GtkWidget *toolbar = gtk_widget_get_ancestor (selected, GTK_TYPE_TOOLBAR);
+  int toolbar_pos;
+
+  toolbar_pos = get_toolbar_position (etoolbar, toolbar);
+  egg_toolbars_model_remove_toolbar (etoolbar->priv->model, toolbar_pos);
+}
+
+static void
+popup_context_deactivate (GtkMenuShell *menu,
+                         EggEditableToolbar *etoolbar)
+{
+  egg_editable_toolbar_set_selected (etoolbar, NULL);
+  g_object_notify (G_OBJECT (etoolbar), "selected");
+}
+
+static void
+popup_context_menu_cb (GtkWidget          *toolbar,
+                       gint               x,
+                       gint               y,
+                       gint                button_number,
+                       EggEditableToolbar *etoolbar)
+{
+  if (etoolbar->priv->popup_path != NULL)
+    {
+      GtkMenu *menu;
+
+      egg_editable_toolbar_set_selected (etoolbar, toolbar);
+      g_object_notify (G_OBJECT (etoolbar), "selected");
+
+      menu = GTK_MENU (gtk_ui_manager_get_widget (etoolbar->priv->manager,
+                                                 etoolbar->priv->popup_path));
+      g_return_if_fail (menu != NULL);
+      gtk_menu_popup (menu, NULL, NULL, NULL, NULL, button_number, gtk_get_current_event_time ());
+      g_signal_connect_object (menu, "selection-done",
+                              G_CALLBACK (popup_context_deactivate),
+                              etoolbar, 0);
+    }
+}
+
+static gboolean
+edit_mode_button_press_event_cb (GtkWidget          *widget,
+                                 GdkEventButton     *event,
+                                 EggEditableToolbar *etoolbar)
+{
+  if (event->button == 1)
+    {
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+button_press_event_cb (GtkWidget *widget,
+                       GdkEventButton *event,
+                       EggEditableToolbar *etoolbar)
+{
+  if (event->button == 3 && etoolbar->priv->popup_path != NULL)
+    {
+      GtkMenu *menu;
+
+      egg_editable_toolbar_set_selected (etoolbar, widget);
+      g_object_notify (G_OBJECT (etoolbar), "selected");
+
+      menu = GTK_MENU (gtk_ui_manager_get_widget (etoolbar->priv->manager,
+                                                 etoolbar->priv->popup_path));
+      g_return_val_if_fail (menu != NULL, FALSE);
+      gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event->button, event->time);
+      g_signal_connect_object (menu, "selection-done",
+                              G_CALLBACK (popup_context_deactivate),
+                              etoolbar, 0);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+configure_item_sensitivity (GtkToolItem *item, EggEditableToolbar *etoolbar)
+{
+  GtkAction *action;
+  char *name;
+
+  name = g_object_get_data (G_OBJECT (item), EGG_ITEM_NAME);
+  action = name ? find_action (etoolbar, name) : NULL;
+
+  if (action)
+    {
+      g_object_notify (G_OBJECT (action), "sensitive");
+    }
+
+  gtk_tool_item_set_use_drag_window (item,
+                                    (etoolbar->priv->edit_mode > 0) ||
+                                    GTK_IS_SEPARATOR_TOOL_ITEM (item));
+
+}
+
+static void
+configure_item_window_drag (GtkToolItem        *item,
+                            EggEditableToolbar *etoolbar)
+{
+  if (etoolbar->priv->edit_mode > 0)
+    {
+      g_signal_connect (item, "button-press-event",
+                        G_CALLBACK (edit_mode_button_press_event_cb), NULL);
+    }
+  else
+    {
+      g_signal_handlers_disconnect_by_func (item,
+                                            G_CALLBACK (edit_mode_button_press_event_cb),
+                                            NULL);
+    }
+}
+
+static void
+configure_item_cursor (GtkToolItem *item,
+                      EggEditableToolbar *etoolbar)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+  GtkWidget *widget = GTK_WIDGET (item);
+  GdkWindow *window = gtk_widget_get_window (widget);
+
+  if (window != NULL)
+    {
+      if (priv->edit_mode > 0)
+        {
+          GdkCursor *cursor;
+         GdkScreen *screen;
+          GdkPixbuf *pixbuf = NULL;
+
+         screen = gtk_widget_get_screen (GTK_WIDGET (etoolbar));
+
+          cursor = gdk_cursor_new_for_display (gdk_screen_get_display (screen),
+                                              GDK_HAND2);
+          gdk_window_set_cursor (window, cursor);
+#if GTK_CHECK_VERSION (3,0,0)
+          g_object_unref (cursor);
+#else
+          gdk_cursor_unref (cursor);
+#endif
+
+          gtk_drag_source_set (widget, GDK_BUTTON1_MASK, dest_drag_types,
+                               G_N_ELEMENTS (dest_drag_types), GDK_ACTION_MOVE);
+          if (GTK_IS_SEPARATOR_TOOL_ITEM (item))
+            {
+              pixbuf = new_separator_pixbuf ();
+            }
+          else
+            {
+              char *icon_name=NULL;
+              char *stock_id=NULL;
+              GtkAction *action;
+              char *name;
+
+              name = g_object_get_data (G_OBJECT (widget), EGG_ITEM_NAME);
+              action = name ? find_action (etoolbar, name) : NULL;
+
+              if (action)
+                {
+                   g_object_get (action,
+                                 "icon-name", &icon_name,
+                                 "stock-id", &stock_id,
+                                 NULL);
+                }
+              if (icon_name)
+                {
+                  GdkScreen *screen;
+                  GtkIconTheme *icon_theme;
+                  GtkSettings *settings;
+                  gint width, height;
+
+                  screen = gtk_widget_get_screen (widget);
+                  icon_theme = gtk_icon_theme_get_for_screen (screen);
+                  settings = gtk_settings_get_for_screen (screen);
+
+                  if (!gtk_icon_size_lookup_for_settings (settings,
+                                                          GTK_ICON_SIZE_LARGE_TOOLBAR,
+                                                          &width, &height))
+                    {
+                      width = height = 24;
+                    }
+
+                  pixbuf = gtk_icon_theme_load_icon (icon_theme, icon_name,
+                                                     MIN (width, height), 0, NULL);
+                }
+              else if (stock_id)
+                {
+                  pixbuf = gtk_widget_render_icon_pixbuf (widget, stock_id,
+                                                          GTK_ICON_SIZE_LARGE_TOOLBAR);
+                }
+              g_free (icon_name);
+              g_free (stock_id);
+            }
+
+          if (G_UNLIKELY (!pixbuf))
+            {
+              return;
+            }
+          gtk_drag_source_set_icon_pixbuf (widget, pixbuf);
+          g_object_unref (pixbuf);
+
+        }
+      else
+        {
+          gdk_window_set_cursor (window, NULL);
+        }
+    }
+}
+
+
+static void
+configure_item_tooltip (GtkToolItem *item)
+{
+  GtkAction *action;
+
+#if GTK_CHECK_VERSION (2, 16, 0)
+  action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (item));
+#else
+  action = gtk_widget_get_action (GTK_WIDGET (item));
+#endif
+
+  if (action != NULL)
+    {
+      g_object_notify (G_OBJECT (action), "tooltip");
+    }
+}
+
+
+static void
+connect_widget_signals (GtkWidget *proxy, EggEditableToolbar *etoolbar)
+{
+  if (GTK_IS_CONTAINER (proxy))
+    {
+       gtk_container_forall (GTK_CONTAINER (proxy),
+                            (GtkCallback) connect_widget_signals,
+                            (gpointer) etoolbar);
+    }
+
+  if (GTK_IS_TOOL_ITEM (proxy))
+    {
+      g_signal_connect_object (proxy, "drag_begin",
+                              G_CALLBACK (drag_begin_cb),
+                              etoolbar, 0);
+      g_signal_connect_object (proxy, "drag_end",
+                              G_CALLBACK (drag_end_cb),
+                              etoolbar, 0);
+      g_signal_connect_object (proxy, "drag_data_get",
+                              G_CALLBACK (drag_data_get_cb),
+                              etoolbar, 0);
+      g_signal_connect_object (proxy, "drag_data_delete",
+                              G_CALLBACK (drag_data_delete_cb),
+                              etoolbar, 0);
+    }
+
+  if (GTK_IS_BUTTON (proxy) || GTK_IS_TOOL_ITEM (proxy))
+    {
+      g_signal_connect_object (proxy, "button-press-event",
+                              G_CALLBACK (button_press_event_cb),
+                              etoolbar, 0);
+    }
+}
+
+static void
+action_sensitive_cb (GtkAction   *action,
+                     GParamSpec  *pspec,
+                     GtkToolItem *item)
+{
+  EggEditableToolbar *etoolbar;
+  GtkWidget *ancestor = gtk_widget_get_ancestor (GTK_WIDGET (item), EGG_TYPE_EDITABLE_TOOLBAR);
+
+  if (!ancestor)
+    return;
+
+  etoolbar = EGG_EDITABLE_TOOLBAR (ancestor);
+  if (etoolbar->priv->edit_mode > 0)
+    {
+      gtk_widget_set_sensitive (GTK_WIDGET (item), TRUE);
+    }
+}
+
+static GtkToolItem *
+create_item_from_action (EggEditableToolbar *etoolbar,
+                        const char *name)
+{
+  GtkToolItem *item;
+
+  g_return_val_if_fail (name != NULL, NULL);
+
+  if (strcmp (name, "_separator") == 0)
+    {
+      item = gtk_separator_tool_item_new ();
+      gtk_widget_show (GTK_WIDGET (item));
+    }
+  else
+    {
+      GtkAction *action = find_action (etoolbar, name);
+      if (action == NULL) return NULL;
+
+      item = GTK_TOOL_ITEM (gtk_action_create_tool_item (action));
+
+      /* Normally done on-demand by the GtkUIManager, but no
+       * such demand may have been made yet, so do it ourselves.
+       */
+      gtk_action_set_accel_group
+        (action, gtk_ui_manager_get_accel_group(etoolbar->priv->manager));
+
+      g_signal_connect_object (action, "notify::sensitive",
+                               G_CALLBACK (action_sensitive_cb), item, 0);
+    }
+
+  g_object_set_data_full (G_OBJECT (item), EGG_ITEM_NAME,
+                          g_strdup (name), g_free);
+
+  return item;
+}
+
+static GtkToolItem *
+create_item_from_position (EggEditableToolbar *etoolbar,
+                           int                 toolbar_position,
+                           int                 position)
+{
+  GtkToolItem *item;
+  const char *name;
+
+  name = egg_toolbars_model_item_nth (etoolbar->priv->model, toolbar_position, position);
+  item = create_item_from_action (etoolbar, name);
+
+  return item;
+}
+
+static void
+toolbar_drag_data_received_cb (GtkToolbar         *toolbar,
+                               GdkDragContext     *context,
+                               gint                x,
+                               gint                y,
+                               GtkSelectionData   *selection_data,
+                               guint               info,
+                               guint               time,
+                               EggEditableToolbar *etoolbar)
+{
+  /* This function can be called for two reasons
+   *
+   *  (1) drag_motion() needs an item to pass to
+   *      gtk_toolbar_set_drop_highlight_item(). We can
+   *      recognize this case by etoolbar->priv->pending being TRUE
+   *      We should just create an item and return.
+   *
+   *  (2) The drag has finished, and drag_drop() wants us to
+   *      actually add a new item to the toolbar.
+   */
+
+  GdkAtom type = gtk_selection_data_get_data_type (selection_data);
+  const char *data = (char *)gtk_selection_data_get_data (selection_data);
+
+  int ipos = -1;
+  char *name = NULL;
+  gboolean used = FALSE;
+
+  /* Find out where the drop is occuring, and the name of what is being dropped. */
+  if (gtk_selection_data_get_length (selection_data) >= 0)
+    {
+      ipos = gtk_toolbar_get_drop_index (toolbar, x, y);
+      name = egg_toolbars_model_get_name (etoolbar->priv->model, type, data, FALSE);
+      if (name != NULL)
+       {
+         used = ((egg_toolbars_model_get_name_flags (etoolbar->priv->model, name) & EGG_TB_MODEL_NAME_USED) 
!= 0);
+        }
+    }
+
+  /* If we just want a highlight item, then . */
+  if (etoolbar->priv->dnd_pending > 0)
+    {
+      etoolbar->priv->dnd_pending--;
+
+      if (name != NULL && etoolbar->priv->dnd_toolbar == toolbar && !used)
+        {
+          etoolbar->priv->dnd_toolitem = create_item_from_action (etoolbar, name);
+          gtk_toolbar_set_drop_highlight_item (etoolbar->priv->dnd_toolbar,
+                                               etoolbar->priv->dnd_toolitem, ipos);
+        }
+    }
+  else
+    {
+      gtk_toolbar_set_drop_highlight_item (toolbar, NULL, 0);
+      etoolbar->priv->dnd_toolbar = NULL;
+      etoolbar->priv->dnd_toolitem = NULL;
+
+      /* If we don't have a name to use yet, try to create one. */
+      if (name == NULL && gtk_selection_data_get_length (selection_data) >= 0)
+        {
+          name = egg_toolbars_model_get_name (etoolbar->priv->model, type, data, TRUE);
+        }
+
+      if (name != NULL && !used)
+        {
+          gint tpos = get_toolbar_position (etoolbar, GTK_WIDGET (toolbar));
+          egg_toolbars_model_add_item (etoolbar->priv->model, tpos, ipos, name);
+          gtk_drag_finish (context, TRUE, gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE, 
time);
+        }
+      else
+        {
+          gtk_drag_finish (context, FALSE, gdk_drag_context_get_selected_action (context) == 
GDK_ACTION_MOVE, time);
+        }
+    }
+
+  g_free (name);
+}
+
+static gboolean
+toolbar_drag_drop_cb (GtkToolbar         *toolbar,
+                     GdkDragContext     *context,
+                     gint                x,
+                     gint                y,
+                     guint               time,
+                     EggEditableToolbar *etoolbar)
+{
+  GdkAtom target;
+
+  target = gtk_drag_dest_find_target (GTK_WIDGET (toolbar), context, NULL);
+  if (target != GDK_NONE)
+    {
+      gtk_drag_get_data (GTK_WIDGET (toolbar), context, target, time);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+toolbar_drag_motion_cb (GtkToolbar         *toolbar,
+                       GdkDragContext     *context,
+                       gint                x,
+                       gint                y,
+                       guint               time,
+                       EggEditableToolbar *etoolbar)
+{
+  GdkAtom target = gtk_drag_dest_find_target (GTK_WIDGET (toolbar), context, NULL);
+  if (target == GDK_NONE)
+    {
+      gdk_drag_status (context, 0, time);
+      return FALSE;
+    }
+
+  /* Make ourselves the current dnd toolbar, and request a highlight item. */
+  if (etoolbar->priv->dnd_toolbar != toolbar)
+    {
+      etoolbar->priv->dnd_toolbar = toolbar;
+      etoolbar->priv->dnd_toolitem = NULL;
+      etoolbar->priv->dnd_pending++;
+      gtk_drag_get_data (GTK_WIDGET (toolbar), context, target, time);
+    }
+
+  /* If a highlight item is available, use it. */
+  else if (etoolbar->priv->dnd_toolitem)
+    {
+      gint ipos = gtk_toolbar_get_drop_index (etoolbar->priv->dnd_toolbar, x, y);
+      gtk_toolbar_set_drop_highlight_item (etoolbar->priv->dnd_toolbar,
+                                           etoolbar->priv->dnd_toolitem, ipos);
+    }
+
+  gdk_drag_status (context, gdk_drag_context_get_suggested_action (context), time);
+
+  return TRUE;
+}
+
+static void
+toolbar_drag_leave_cb (GtkToolbar         *toolbar,
+                      GdkDragContext     *context,
+                      guint               time,
+                      EggEditableToolbar *etoolbar)
+{
+  gtk_toolbar_set_drop_highlight_item (toolbar, NULL, 0);
+
+  /* If we were the current dnd toolbar target, remove the item. */
+  if (etoolbar->priv->dnd_toolbar == toolbar)
+    {
+      etoolbar->priv->dnd_toolbar = NULL;
+      etoolbar->priv->dnd_toolitem = NULL;
+    }
+}
+
+static void
+configure_drag_dest (EggEditableToolbar *etoolbar,
+                     GtkToolbar         *toolbar)
+{
+  EggToolbarsItemType *type;
+  GtkTargetList *targets;
+  GList *list;
+
+  /* Make every toolbar able to receive drag-drops. */
+  gtk_drag_dest_set (GTK_WIDGET (toolbar), 0,
+                    dest_drag_types, G_N_ELEMENTS (dest_drag_types),
+                    GDK_ACTION_MOVE | GDK_ACTION_COPY);
+
+  /* Add any specialist drag-drop abilities. */
+  targets = gtk_drag_dest_get_target_list (GTK_WIDGET (toolbar));
+  list = egg_toolbars_model_get_types (etoolbar->priv->model);
+  while (list)
+  {
+    type = list->data;
+    if (type->new_name != NULL || type->get_name != NULL)
+      gtk_target_list_add (targets, type->type, 0, 0);
+    list = list->next;
+  }
+}
+
+static void
+toggled_visibility_cb (GtkToggleAction *action,
+                      EggEditableToolbar *etoolbar)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+  GtkWidget *dock;
+  EggTbModelFlags flags;
+  gboolean visible;
+  gint i;
+
+  visible = gtk_toggle_action_get_active (action);
+  for (i = 0; i < priv->visibility_actions->len; i++)
+    if (g_ptr_array_index (priv->visibility_actions, i) == action)
+      break;
+
+  g_return_if_fail (i < priv->visibility_actions->len);
+
+  dock = get_dock_nth (etoolbar, i);
+  if (visible)
+    {
+      gtk_widget_show (dock);
+    }
+  else
+    {
+      gtk_widget_hide (dock);
+    }
+
+  if (priv->save_hidden)
+    {
+      flags = egg_toolbars_model_get_flags (priv->model, i);
+
+      if (visible)
+        {
+         flags &= ~(EGG_TB_MODEL_HIDDEN);
+       }
+      else
+       {
+         flags |=  (EGG_TB_MODEL_HIDDEN);
+       }
+
+      egg_toolbars_model_set_flags (priv->model, i, flags);
+    }
+}
+
+static void
+toolbar_visibility_refresh (EggEditableToolbar *etoolbar)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+  gint n_toolbars, n_items, i, j, k;
+  GtkToggleAction *action;
+  GList *list;
+  GString *string;
+  gboolean showing;
+  char action_name[40];
+  char *action_label;
+  char *tmp;
+  gboolean primary_class_set;
+  GtkStyleContext *context;
+  const gchar *toolbar_name;
+  gboolean visible;
+
+  if (priv == NULL || priv->model == NULL || priv->manager == NULL ||
+      priv->visibility_paths == NULL || priv->actions == NULL)
+    {
+      return;
+    }
+
+  if (priv->visibility_actions == NULL)
+    {
+      priv->visibility_actions = g_ptr_array_new ();
+    }
+
+  if (priv->visibility_id != 0)
+    {
+      gtk_ui_manager_remove_ui (priv->manager, priv->visibility_id);
+    }
+
+  priv->visibility_id = gtk_ui_manager_new_merge_id (priv->manager);
+
+#if GTK_CHECK_VERSION(2,20,0)
+  showing = gtk_widget_get_visible (GTK_WIDGET (etoolbar));
+#else
+  showing = GTK_WIDGET_VISIBLE (etoolbar);
+#endif
+
+  primary_class_set = !priv->set_primary_class;
+
+  n_toolbars = egg_toolbars_model_n_toolbars (priv->model);
+  for (i = 0; i < n_toolbars; i++)
+    {
+      toolbar_name = egg_toolbars_model_toolbar_nth (priv->model, i);
+      string = g_string_sized_new (0);
+      n_items = egg_toolbars_model_n_items (priv->model, i);
+      for (k = 0, j = 0; j < n_items; j++)
+        {
+          GValue value = { 0, };
+          GtkAction *action;
+          const char *name;
+
+          name = egg_toolbars_model_item_nth (priv->model, i, j);
+          if (name == NULL) continue;
+          action = find_action (etoolbar, name);
+          if (action == NULL) continue;
+
+          g_value_init (&value, G_TYPE_STRING);
+          g_object_get_property (G_OBJECT (action), "label", &value);
+          name = g_value_get_string (&value);
+          if (name == NULL)
+           {
+               g_value_unset (&value);
+               continue;
+           }
+         k += g_utf8_strlen (name, -1) + 2;
+         if (j > 0)
+           {
+             g_string_append (string, ", ");
+             if (j > 1 && k > 25)
+               {
+                 g_value_unset (&value);
+                 break;
+               }
+           }
+         g_string_append (string, name);
+         g_value_unset (&value);
+       }
+      if (j < n_items)
+        {
+         g_string_append (string, " ...");
+        }
+
+      tmp = g_string_free (string, FALSE);
+      for (j = 0, k = 0; tmp[j]; j++)
+      {
+       if (tmp[j] == '_') continue;
+       tmp[k] = tmp[j];
+       k++;
+      }
+      tmp[k] = 0;
+      /* Translaters: This string is for a toggle to display a toolbar.
+       * The name of the toolbar is automatically computed from the widgets
+       * on the toolbar, and is placed at the %s. Note the _ before the %s
+       * which is used to add mnemonics. We know that this is likely to
+       * produce duplicates, but don't worry about it. If your language
+       * normally has a mnemonic at the start, please use the _. If not,
+       * please remove. */
+      action_label = g_strdup_printf (_("Show ā€œ_%sā€"), tmp);
+      g_free (tmp);
+
+      sprintf(action_name, "ToolbarToggle%d", i);
+
+      if (i >= priv->visibility_actions->len)
+        {
+         action = gtk_toggle_action_new (action_name, action_label, NULL, NULL);
+         g_ptr_array_add (priv->visibility_actions, action);
+         g_signal_connect_object (action, "toggled",
+                                  G_CALLBACK (toggled_visibility_cb),
+                                  etoolbar, 0);
+         gtk_action_group_add_action (priv->actions, GTK_ACTION (action));
+       }
+      else
+        {
+         action = g_ptr_array_index (priv->visibility_actions, i);
+         g_object_set (action, "label", action_label, NULL);
+        }
+
+      gtk_action_set_visible (GTK_ACTION (action), (egg_toolbars_model_get_flags (priv->model, i)
+                                                   & EGG_TB_MODEL_NOT_REMOVABLE) == 0);
+      gtk_action_set_sensitive (GTK_ACTION (action), showing);
+
+#if GTK_CHECK_VERSION(2,20,0)
+      visible = gtk_widget_get_visible (get_dock_nth (etoolbar, i));
+#else
+      visible = GTK_WIDGET_VISIBLE (get_dock_nth (etoolbar, i));
+#endif
+
+      gtk_toggle_action_set_active (action, visible);
+      context = gtk_widget_get_style_context (get_toolbar_nth (etoolbar, i));
+
+      /* apply the primary toolbar class to the first toolbar we see,
+       * or to that specified by the primary name, if any.
+       */
+      if (!primary_class_set && visible &&
+          ((g_strcmp0 (priv->primary_name, toolbar_name) == 0) ||
+           (priv->primary_name == NULL)))
+        {
+          primary_class_set = TRUE;
+          gtk_style_context_add_class (context, GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
+        }
+      else
+        {
+          gtk_style_context_remove_class (context, GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
+        }
+
+      gtk_widget_reset_style (get_toolbar_nth (etoolbar, i));
+
+      for (list = priv->visibility_paths; list != NULL; list = g_list_next (list))
+        {
+         gtk_ui_manager_add_ui (priv->manager, priv->visibility_id,
+                                (const char *)list->data, action_name, action_name,
+                                GTK_UI_MANAGER_MENUITEM, FALSE);
+       }
+
+      g_free (action_label);
+    }
+
+  gtk_ui_manager_ensure_update (priv->manager);
+
+  while (i < priv->visibility_actions->len)
+    {
+      action = g_ptr_array_index (priv->visibility_actions, i);
+      g_ptr_array_remove_index_fast (priv->visibility_actions, i);
+      gtk_action_group_remove_action (priv->actions, GTK_ACTION (action));
+      i++;
+    }
+}
+
+static GtkWidget *
+create_dock (EggEditableToolbar *etoolbar)
+{
+  GtkWidget *toolbar, *hbox;
+
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+
+  toolbar = gtk_toolbar_new ();
+  gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), TRUE);
+  gtk_widget_show (toolbar);
+  gtk_box_pack_start (GTK_BOX (hbox), toolbar, TRUE, TRUE, 0);
+
+  g_signal_connect (toolbar, "drag_drop",
+                   G_CALLBACK (toolbar_drag_drop_cb), etoolbar);
+  g_signal_connect (toolbar, "drag_motion",
+                   G_CALLBACK (toolbar_drag_motion_cb), etoolbar);
+  g_signal_connect (toolbar, "drag_leave",
+                   G_CALLBACK (toolbar_drag_leave_cb), etoolbar);
+
+  g_signal_connect (toolbar, "drag_data_received",
+                   G_CALLBACK (toolbar_drag_data_received_cb), etoolbar);
+  g_signal_connect (toolbar, "popup_context_menu",
+                   G_CALLBACK (popup_context_menu_cb), etoolbar);
+
+  configure_drag_dest (etoolbar, GTK_TOOLBAR (toolbar));
+
+  return hbox;
+}
+
+static void
+set_fixed_style (EggEditableToolbar *t, GtkToolbarStyle style)
+{
+  g_return_if_fail (GTK_IS_TOOLBAR (t->priv->fixed_toolbar));
+  gtk_toolbar_set_style (GTK_TOOLBAR (t->priv->fixed_toolbar),
+                        style == GTK_TOOLBAR_ICONS ? GTK_TOOLBAR_BOTH_HORIZ : style);
+}
+
+static void
+unset_fixed_style (EggEditableToolbar *t)
+{
+  g_return_if_fail (GTK_IS_TOOLBAR (t->priv->fixed_toolbar));
+  gtk_toolbar_unset_style (GTK_TOOLBAR (t->priv->fixed_toolbar));
+}
+
+static void
+toolbar_changed_cb (EggToolbarsModel   *model,
+                   int                 position,
+                   EggEditableToolbar *etoolbar)
+{
+  GtkWidget *toolbar;
+  EggTbModelFlags flags;
+  GtkToolbarStyle style;
+
+  flags = egg_toolbars_model_get_flags (model, position);
+  toolbar = get_toolbar_nth (etoolbar, position);
+
+  if (flags & EGG_TB_MODEL_ICONS)
+  {
+    style = GTK_TOOLBAR_ICONS;
+  }
+  else if (flags & EGG_TB_MODEL_TEXT)
+  {
+    style = GTK_TOOLBAR_TEXT;
+  }
+  else if (flags & EGG_TB_MODEL_BOTH)
+  {
+    style = GTK_TOOLBAR_BOTH;
+  }
+  else if (flags & EGG_TB_MODEL_BOTH_HORIZ)
+  {
+    style = GTK_TOOLBAR_BOTH_HORIZ;
+  }
+  else
+  {
+    gtk_toolbar_unset_style (GTK_TOOLBAR (toolbar));
+    if (position == 0 && etoolbar->priv->fixed_toolbar)
+      {
+        unset_fixed_style (etoolbar);
+      }
+    return;
+  }
+
+  gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), style);
+  if (position == 0 && etoolbar->priv->fixed_toolbar)
+    {
+      set_fixed_style (etoolbar, style);
+    }
+
+  toolbar_visibility_refresh (etoolbar);
+}
+
+static void
+unparent_fixed (EggEditableToolbar *etoolbar)
+{
+  GtkWidget *toolbar, *dock;
+  g_return_if_fail (GTK_IS_TOOLBAR (etoolbar->priv->fixed_toolbar));
+
+  toolbar = etoolbar->priv->fixed_toolbar;
+  dock = get_dock_nth (etoolbar, 0);
+
+  if (dock && gtk_widget_get_parent (toolbar) != NULL)
+    {
+      gtk_container_remove (GTK_CONTAINER (dock), toolbar);
+    }
+}
+
+static void
+update_fixed (EggEditableToolbar *etoolbar)
+{
+  GtkWidget *toolbar, *dock;
+  if (!etoolbar->priv->fixed_toolbar) return;
+
+  toolbar = etoolbar->priv->fixed_toolbar;
+  dock = get_dock_nth (etoolbar, 0);
+
+  if (dock && toolbar && gtk_widget_get_parent (toolbar) == NULL)
+    {
+      gtk_box_pack_end (GTK_BOX (dock), toolbar, FALSE, TRUE, 0);
+
+      gtk_widget_show (toolbar);
+
+      gtk_widget_set_size_request (dock, -1, -1);
+      gtk_widget_queue_resize_no_redraw (dock);
+    }
+}
+
+static void
+toolbar_added_cb (EggToolbarsModel   *model,
+                 int                 position,
+                 EggEditableToolbar *etoolbar)
+{
+  GtkWidget *dock;
+
+  dock = create_dock (etoolbar);
+  if ((egg_toolbars_model_get_flags (model, position) & EGG_TB_MODEL_HIDDEN) == 0)
+    gtk_widget_show (dock);
+
+  gtk_widget_set_size_request (dock, -1, MIN_TOOLBAR_HEIGHT);
+
+  gtk_box_pack_start (GTK_BOX (etoolbar), dock, TRUE, TRUE, 0);
+
+  gtk_box_reorder_child (GTK_BOX (etoolbar), dock, position);
+
+  gtk_widget_show_all (dock);
+
+  update_fixed (etoolbar);
+
+  toolbar_visibility_refresh (etoolbar);
+}
+
+static void
+toolbar_removed_cb (EggToolbarsModel   *model,
+                   int                 position,
+                   EggEditableToolbar *etoolbar)
+{
+  GtkWidget *dock;
+
+  if (position == 0 && etoolbar->priv->fixed_toolbar != NULL)
+    {
+      unparent_fixed (etoolbar);
+    }
+
+  dock = get_dock_nth (etoolbar, position);
+  gtk_widget_destroy (dock);
+
+  update_fixed (etoolbar);
+
+  toolbar_visibility_refresh (etoolbar);
+}
+
+static void
+item_added_cb (EggToolbarsModel   *model,
+              int                 tpos,
+              int                 ipos,
+              EggEditableToolbar *etoolbar)
+{
+  GtkWidget *dock;
+  GtkWidget *toolbar;
+  GtkToolItem *item;
+
+  toolbar = get_toolbar_nth (etoolbar, tpos);
+  item = create_item_from_position (etoolbar, tpos, ipos);
+  if (item == NULL) return;
+
+  gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, ipos);
+
+  connect_widget_signals (GTK_WIDGET (item), etoolbar);
+  configure_item_tooltip (item);
+  configure_item_cursor (item, etoolbar);
+  configure_item_window_drag (item, etoolbar);
+  configure_item_sensitivity (item, etoolbar);
+
+  dock = get_dock_nth (etoolbar, tpos);
+  gtk_widget_set_size_request (dock, -1, -1);
+  gtk_widget_queue_resize_no_redraw (dock);
+
+  toolbar_visibility_refresh (etoolbar);
+}
+
+static void
+item_removed_cb (EggToolbarsModel   *model,
+                int                 toolbar_position,
+                int                 position,
+                EggEditableToolbar *etoolbar)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+
+  GtkWidget *toolbar;
+  GtkWidget *item;
+
+  toolbar = get_toolbar_nth (etoolbar, toolbar_position);
+  item = GTK_WIDGET (gtk_toolbar_get_nth_item
+       (GTK_TOOLBAR (toolbar), position));
+  g_return_if_fail (item != NULL);
+
+  if (item == priv->selected)
+    {
+      /* FIXME */
+    }
+
+  gtk_container_remove (GTK_CONTAINER (toolbar), item);
+
+  toolbar_visibility_refresh (etoolbar);
+}
+
+static void
+egg_editable_toolbar_build (EggEditableToolbar *etoolbar)
+{
+  int i, l, n_items, n_toolbars;
+  EggToolbarsModel *model = etoolbar->priv->model;
+
+  g_return_if_fail (model != NULL);
+  g_return_if_fail (etoolbar->priv->manager != NULL);
+
+  n_toolbars = egg_toolbars_model_n_toolbars (model);
+
+  for (i = 0; i < n_toolbars; i++)
+    {
+      GtkWidget *toolbar, *dock;
+
+      dock = create_dock (etoolbar);
+      if ((egg_toolbars_model_get_flags (model, i) & EGG_TB_MODEL_HIDDEN) == 0)
+        gtk_widget_show (dock);
+      gtk_box_pack_start (GTK_BOX (etoolbar), dock, TRUE, TRUE, 0);
+      toolbar = get_toolbar_nth (etoolbar, i);
+
+      n_items = egg_toolbars_model_n_items (model, i);
+      for (l = 0; l < n_items; l++)
+        {
+          GtkToolItem *item;
+
+          item = create_item_from_position (etoolbar, i, l);
+          if (item)
+            {
+             gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, l);
+
+              connect_widget_signals (GTK_WIDGET (item), etoolbar);
+             configure_item_tooltip (item);
+              configure_item_sensitivity (item, etoolbar);
+            }
+          else
+            {
+              egg_toolbars_model_remove_item (model, i, l);
+              l--;
+              n_items--;
+            }
+        }
+
+      if (n_items == 0)
+        {
+            gtk_widget_set_size_request (dock, -1, MIN_TOOLBAR_HEIGHT);
+        }
+    }
+
+  update_fixed (etoolbar);
+
+  /* apply styles */
+  for (i = 0; i < n_toolbars; i ++)
+    {
+      toolbar_changed_cb (model, i, etoolbar);
+    }
+}
+
+static void
+egg_editable_toolbar_disconnect_model (EggEditableToolbar *toolbar)
+{
+  EggToolbarsModel *model = toolbar->priv->model;
+
+  g_signal_handlers_disconnect_by_func
+    (model, G_CALLBACK (item_added_cb), toolbar);
+  g_signal_handlers_disconnect_by_func
+    (model, G_CALLBACK (item_removed_cb), toolbar);
+  g_signal_handlers_disconnect_by_func
+    (model, G_CALLBACK (toolbar_added_cb), toolbar);
+  g_signal_handlers_disconnect_by_func
+    (model, G_CALLBACK (toolbar_removed_cb), toolbar);
+  g_signal_handlers_disconnect_by_func
+    (model, G_CALLBACK (toolbar_changed_cb), toolbar);
+}
+
+static void
+egg_editable_toolbar_deconstruct (EggEditableToolbar *toolbar)
+{
+  EggToolbarsModel *model = toolbar->priv->model;
+  GList *children;
+
+  g_return_if_fail (model != NULL);
+
+  if (toolbar->priv->fixed_toolbar)
+    {
+       unset_fixed_style (toolbar);
+       unparent_fixed (toolbar);
+    }
+
+  children = gtk_container_get_children (GTK_CONTAINER (toolbar));
+  g_list_foreach (children, (GFunc) gtk_widget_destroy, NULL);
+  g_list_free (children);
+}
+
+void
+egg_editable_toolbar_set_model (EggEditableToolbar *etoolbar,
+                               EggToolbarsModel   *model)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+
+  if (priv->model == model) return;
+
+  if (priv->model)
+    {
+      egg_editable_toolbar_disconnect_model (etoolbar);
+      egg_editable_toolbar_deconstruct (etoolbar);
+
+      g_object_unref (priv->model);
+    }
+
+  priv->model = g_object_ref (model);
+
+  egg_editable_toolbar_build (etoolbar);
+
+  toolbar_visibility_refresh (etoolbar);
+
+  g_signal_connect (model, "item_added",
+                   G_CALLBACK (item_added_cb), etoolbar);
+  g_signal_connect (model, "item_removed",
+                   G_CALLBACK (item_removed_cb), etoolbar);
+  g_signal_connect (model, "toolbar_added",
+                   G_CALLBACK (toolbar_added_cb), etoolbar);
+  g_signal_connect (model, "toolbar_removed",
+                   G_CALLBACK (toolbar_removed_cb), etoolbar);
+  g_signal_connect (model, "toolbar_changed",
+                   G_CALLBACK (toolbar_changed_cb), etoolbar);
+}
+
+static void
+egg_editable_toolbar_init (EggEditableToolbar *etoolbar)
+{
+  EggEditableToolbarPrivate *priv;
+
+  priv = etoolbar->priv = EGG_EDITABLE_TOOLBAR_GET_PRIVATE (etoolbar);
+
+  gtk_orientable_set_orientation (GTK_ORIENTABLE (etoolbar),
+                                  GTK_ORIENTATION_VERTICAL);
+  priv->save_hidden = TRUE;
+
+  g_signal_connect (etoolbar, "notify::visible",
+                   G_CALLBACK (toolbar_visibility_refresh), NULL);
+}
+
+static void
+egg_editable_toolbar_dispose (GObject *object)
+{
+  EggEditableToolbar *etoolbar = EGG_EDITABLE_TOOLBAR (object);
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+  GList *children;
+
+  if (priv->fixed_toolbar != NULL)
+    {
+      g_object_unref (priv->fixed_toolbar);
+      priv->fixed_toolbar = NULL;
+    }
+
+  if (priv->visibility_paths)
+    {
+      children = priv->visibility_paths;
+      g_list_foreach (children, (GFunc) g_free, NULL);
+      g_list_free (children);
+      priv->visibility_paths = NULL;
+    }
+
+  g_free (priv->popup_path);
+  priv->popup_path = NULL;
+
+  g_free (priv->primary_name);
+  priv->primary_name = NULL;
+
+  if (priv->manager != NULL)
+    {
+      if (priv->visibility_id)
+        {
+         gtk_ui_manager_remove_ui (priv->manager, priv->visibility_id);
+         priv->visibility_id = 0;
+       }
+
+      g_object_unref (priv->manager);
+      priv->manager = NULL;
+    }
+
+  if (priv->model)
+    {
+      egg_editable_toolbar_disconnect_model (etoolbar);
+      g_object_unref (priv->model);
+      priv->model = NULL;
+    }
+
+  G_OBJECT_CLASS (egg_editable_toolbar_parent_class)->dispose (object);
+}
+
+static void
+egg_editable_toolbar_set_ui_manager (EggEditableToolbar *etoolbar,
+                                    GtkUIManager       *manager)
+{
+  static const GtkActionEntry actions[] = {
+    { "MoveToolItem", STOCK_DRAG_MODE, N_("_Move on Toolbar"), NULL,
+      N_("Move the selected item on the toolbar"), G_CALLBACK (move_item_cb) },
+    { "RemoveToolItem", GTK_STOCK_REMOVE, N_("_Remove from Toolbar"), NULL,
+      N_("Remove the selected item from the toolbar"), G_CALLBACK (remove_item_cb) },
+    { "RemoveToolbar", GTK_STOCK_DELETE, N_("_Delete Toolbar"), NULL,
+      N_("Remove the selected toolbar"), G_CALLBACK (remove_toolbar_cb) },
+  };
+
+  etoolbar->priv->manager = g_object_ref (manager);
+
+  etoolbar->priv->actions = gtk_action_group_new ("ToolbarActions");
+  gtk_action_group_set_translation_domain (etoolbar->priv->actions, GETTEXT_PACKAGE);
+  gtk_action_group_add_actions (etoolbar->priv->actions, actions,
+                               G_N_ELEMENTS (actions), etoolbar);
+  gtk_ui_manager_insert_action_group (manager, etoolbar->priv->actions, -1);
+  g_object_unref (etoolbar->priv->actions);
+
+  toolbar_visibility_refresh (etoolbar);
+}
+
+/**
+ * egg_editable_toolbar_get_selected:
+ * @etoolbar:
+ *
+ * Returns: (transfer none):
+ **/
+GtkWidget * egg_editable_toolbar_get_selected (EggEditableToolbar   *etoolbar)
+{
+  return etoolbar->priv->selected;
+}
+
+void
+egg_editable_toolbar_set_selected (EggEditableToolbar *etoolbar,
+                                  GtkWidget          *widget)
+{
+  GtkWidget *toolbar, *toolitem;
+  gboolean editable;
+
+  etoolbar->priv->selected = widget;
+
+  toolbar = (widget != NULL) ? gtk_widget_get_ancestor (widget, GTK_TYPE_TOOLBAR) : NULL;
+  toolitem = (widget != NULL) ? gtk_widget_get_ancestor (widget, GTK_TYPE_TOOL_ITEM) : NULL;
+
+  if(toolbar != NULL)
+    {
+      gint tpos = get_toolbar_position (etoolbar, toolbar);
+      editable = ((egg_toolbars_model_get_flags (etoolbar->priv->model, tpos) & EGG_TB_MODEL_NOT_EDITABLE) 
== 0);
+    }
+  else
+    {
+      editable = FALSE;
+    }
+
+  gtk_action_set_visible (find_action (etoolbar, "RemoveToolbar"), (toolbar != NULL) && 
(etoolbar->priv->edit_mode > 0));
+  gtk_action_set_visible (find_action (etoolbar, "RemoveToolItem"), (toolitem != NULL) && editable);
+  gtk_action_set_visible (find_action (etoolbar, "MoveToolItem"), (toolitem != NULL) && editable);
+}
+
+static void
+set_edit_mode (EggEditableToolbar *etoolbar,
+              gboolean mode)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+  int i, l, n_items;
+
+  i = priv->edit_mode;
+  if (mode)
+    {
+      priv->edit_mode++;
+    }
+  else
+    {
+      g_return_if_fail (priv->edit_mode > 0);
+      priv->edit_mode--;
+    }
+  i *= priv->edit_mode;
+
+  if (i == 0)
+    {
+      for (i = get_n_toolbars (etoolbar)-1; i >= 0; i--)
+        {
+          GtkWidget *toolbar;
+
+          toolbar = get_toolbar_nth (etoolbar, i);
+          n_items = gtk_toolbar_get_n_items (GTK_TOOLBAR (toolbar));
+
+          if (n_items == 0 && priv->edit_mode == 0)
+            {
+              egg_toolbars_model_remove_toolbar (priv->model, i);
+            }
+          else
+            {
+              for (l = 0; l < n_items; l++)
+                {
+                  GtkToolItem *item;
+
+                  item = gtk_toolbar_get_nth_item (GTK_TOOLBAR (toolbar), l);
+
+                  configure_item_cursor (item, etoolbar);
+                  configure_item_window_drag (item, etoolbar);
+                  configure_item_sensitivity (item, etoolbar);
+                }
+            }
+        }
+    }
+}
+
+static void
+egg_editable_toolbar_set_property (GObject      *object,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+  EggEditableToolbar *etoolbar = EGG_EDITABLE_TOOLBAR (object);
+
+  switch (prop_id)
+    {
+    case PROP_UI_MANAGER:
+      egg_editable_toolbar_set_ui_manager (etoolbar, g_value_get_object (value));
+      break;
+    case PROP_TOOLBARS_MODEL:
+      egg_editable_toolbar_set_model (etoolbar, g_value_get_object (value));
+      break;
+    case PROP_SELECTED:
+      egg_editable_toolbar_set_selected (etoolbar, g_value_get_object (value));
+      break;
+    case PROP_POPUP_PATH:
+      etoolbar->priv->popup_path = g_strdup (g_value_get_string (value));
+      break;
+    case PROP_EDIT_MODE:
+      set_edit_mode (etoolbar, g_value_get_boolean (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+egg_editable_toolbar_get_property (GObject    *object,
+                                  guint       prop_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+  EggEditableToolbar *etoolbar = EGG_EDITABLE_TOOLBAR (object);
+
+  switch (prop_id)
+    {
+    case PROP_UI_MANAGER:
+      g_value_set_object (value, etoolbar->priv->manager);
+      break;
+    case PROP_TOOLBARS_MODEL:
+      g_value_set_object (value, etoolbar->priv->model);
+      break;
+    case PROP_SELECTED:
+      g_value_set_object (value, etoolbar->priv->selected);
+      break;
+    case PROP_EDIT_MODE:
+      g_value_set_boolean (value, etoolbar->priv->edit_mode>0);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+egg_editable_toolbar_class_init (EggEditableToolbarClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = egg_editable_toolbar_dispose;
+  object_class->set_property = egg_editable_toolbar_set_property;
+  object_class->get_property = egg_editable_toolbar_get_property;
+
+  egg_editable_toolbar_signals[ACTION_REQUEST] =
+    g_signal_new ("action_request",
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (EggEditableToolbarClass, action_request),
+                 NULL, NULL, g_cclosure_marshal_VOID__STRING,
+                 G_TYPE_NONE, 1, G_TYPE_STRING);
+
+  g_object_class_install_property (object_class,
+                                  PROP_UI_MANAGER,
+                                  g_param_spec_object ("ui-manager",
+                                                       "UI-Mmanager",
+                                                       "UI Manager",
+                                                       GTK_TYPE_UI_MANAGER,
+                                                       G_PARAM_READWRITE | G_PARAM_STATIC_NAME | 
G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+  g_object_class_install_property (object_class,
+                                  PROP_TOOLBARS_MODEL,
+                                  g_param_spec_object ("model",
+                                                       "Model",
+                                                       "Toolbars Model",
+                                                       EGG_TYPE_TOOLBARS_MODEL,
+                                                       G_PARAM_READWRITE | G_PARAM_STATIC_NAME | 
G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+  g_object_class_install_property (object_class,
+                                  PROP_SELECTED,
+                                  g_param_spec_object ("selected",
+                                                       "Selected",
+                                                       "Selected toolitem",
+                                                       GTK_TYPE_TOOL_ITEM,
+                                                       G_PARAM_READABLE | G_PARAM_STATIC_NAME | 
G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+  g_object_class_install_property (object_class,
+                                  PROP_POPUP_PATH,
+                                  g_param_spec_string ("popup-path",
+                                                       "popup-path",
+                                                       "popup-path",
+                                                       NULL,
+                                                       G_PARAM_READWRITE | G_PARAM_STATIC_NAME | 
G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+  g_object_class_install_property (object_class,
+                                  PROP_EDIT_MODE,
+                                  g_param_spec_boolean ("edit-mode",
+                                                        "Edit-Mode",
+                                                        "Edit Mode",
+                                                        FALSE,
+                                                        G_PARAM_READWRITE | G_PARAM_STATIC_NAME | 
G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+  g_type_class_add_private (object_class, sizeof (EggEditableToolbarPrivate));
+}
+
+GtkWidget *
+egg_editable_toolbar_new (GtkUIManager *manager,
+                          const char *popup_path)
+{
+    return GTK_WIDGET (g_object_new (EGG_TYPE_EDITABLE_TOOLBAR,
+                                     "ui-manager", manager,
+                                     "popup-path", popup_path,
+                                     NULL));
+}
+
+GtkWidget *
+egg_editable_toolbar_new_with_model (GtkUIManager *manager,
+                                    EggToolbarsModel *model,
+                                     const char *popup_path)
+{
+  return GTK_WIDGET (g_object_new (EGG_TYPE_EDITABLE_TOOLBAR,
+                                   "ui-manager", manager,
+                                   "model", model,
+                                   "popup-path", popup_path,
+                                  NULL));
+}
+
+gboolean
+egg_editable_toolbar_get_edit_mode (EggEditableToolbar *etoolbar)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+
+  return priv->edit_mode > 0;
+}
+
+void
+egg_editable_toolbar_set_edit_mode (EggEditableToolbar *etoolbar,
+                                   gboolean mode)
+{
+  set_edit_mode (etoolbar, mode);
+  g_object_notify (G_OBJECT (etoolbar), "edit-mode");
+}
+
+void
+egg_editable_toolbar_add_visibility (EggEditableToolbar *etoolbar,
+                                    const char *path)
+{
+  etoolbar->priv->visibility_paths = g_list_prepend
+         (etoolbar->priv->visibility_paths, g_strdup (path));
+}
+
+void
+egg_editable_toolbar_show (EggEditableToolbar *etoolbar,
+                          const char *name)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+  EggToolbarsModel *model = priv->model;
+  int i, n_toolbars;
+
+  n_toolbars = egg_toolbars_model_n_toolbars (model);
+  for (i = 0; i < n_toolbars; i++)
+    {
+      const char *toolbar_name;
+
+      toolbar_name = egg_toolbars_model_toolbar_nth (model, i);
+      if (strcmp (toolbar_name, name) == 0)
+        {
+          gtk_widget_show (get_dock_nth (etoolbar, i));
+        }
+    }
+}
+
+void
+egg_editable_toolbar_hide (EggEditableToolbar *etoolbar,
+                          const char *name)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+  EggToolbarsModel *model = priv->model;
+  int i, n_toolbars;
+
+  n_toolbars = egg_toolbars_model_n_toolbars (model);
+  for (i = 0; i < n_toolbars; i++)
+    {
+      const char *toolbar_name;
+
+      toolbar_name = egg_toolbars_model_toolbar_nth (model, i);
+      if (strcmp (toolbar_name, name) == 0)
+      {
+        gtk_widget_hide (get_dock_nth (etoolbar, i));
+      }
+    }
+}
+
+void
+egg_editable_toolbar_set_fixed (EggEditableToolbar *etoolbar,
+                               GtkToolbar *toolbar)
+{
+  EggEditableToolbarPrivate *priv = etoolbar->priv;
+
+  g_return_if_fail (!toolbar || GTK_IS_TOOLBAR (toolbar));
+
+  if (priv->fixed_toolbar)
+    {
+      unparent_fixed (etoolbar);
+      g_object_unref (priv->fixed_toolbar);
+      priv->fixed_toolbar = NULL;
+    }
+
+  if (toolbar)
+    {
+      priv->fixed_toolbar = GTK_WIDGET (toolbar);
+      gtk_toolbar_set_show_arrow (toolbar, FALSE);
+      g_object_ref_sink (toolbar);
+    }
+
+  update_fixed (etoolbar);
+}
+
+#define DEFAULT_ICON_HEIGHT 20
+
+/* We should probably experiment some more with this.
+ * Right now the rendered icon is pretty good for most
+ * themes. However, the icon is slightly large for themes
+ * with large toolbar icons.
+ */
+static GdkPixbuf *
+new_pixbuf_from_widget (GtkWidget *widget)
+{
+  GtkWidget *window;
+  GdkPixbuf *pixbuf;
+  gint icon_height;
+  GdkScreen *screen;
+
+  screen = gtk_widget_get_screen (widget);
+
+  if (!gtk_icon_size_lookup_for_settings (gtk_settings_get_for_screen (screen),
+                                         GTK_ICON_SIZE_LARGE_TOOLBAR,
+                                         NULL,
+                                         &icon_height))
+    {
+      icon_height = DEFAULT_ICON_HEIGHT;
+    }
+
+  window = gtk_offscreen_window_new ();
+  /* Set the width to -1 as we want the separator to be as thin as possible. */
+  gtk_widget_set_size_request (widget, -1, icon_height);
+
+  gtk_container_add (GTK_CONTAINER (window), widget);
+  gtk_widget_show_all (window);
+
+  /* Process the waiting events to have the widget actually drawn */
+  gdk_window_process_updates (gtk_widget_get_window (window), TRUE);
+  pixbuf = gtk_offscreen_window_get_pixbuf (GTK_OFFSCREEN_WINDOW (window));
+  gtk_widget_destroy (window);
+
+  return pixbuf;
+}
+
+static GdkPixbuf *
+new_separator_pixbuf (void)
+{
+  GtkWidget *separator;
+  GdkPixbuf *pixbuf;
+
+  separator = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
+  pixbuf = new_pixbuf_from_widget (separator);
+  return pixbuf;
+}
+
+static void
+update_separator_image (GtkImage *image)
+{
+  GdkPixbuf *pixbuf = new_separator_pixbuf ();
+  gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
+  g_object_unref (pixbuf);
+}
+
+static gboolean
+style_set_cb (GtkWidget *widget,
+              GtkStyle *previous_style,
+              GtkImage *image)
+{
+
+  update_separator_image (image);
+  return FALSE;
+}
+
+GtkWidget *
+_egg_editable_toolbar_new_separator_image (void)
+{
+  GtkWidget *image = gtk_image_new ();
+  update_separator_image (GTK_IMAGE (image));
+  g_signal_connect (G_OBJECT (image), "style_set",
+                   G_CALLBACK (style_set_cb), GTK_IMAGE (image));
+
+  return image;
+}
+
+/**
+ * egg_editable_toolbar_get_model:
+ * @etoolbar:
+ *
+ * Returns: (transfer none):
+ **/
+EggToolbarsModel *
+egg_editable_toolbar_get_model (EggEditableToolbar *etoolbar)
+{
+  return etoolbar->priv->model;
+}
+
+/**
+ * egg_editable_toolbar_get_manager:
+ *
+ * Return value: (transfer none):
+ */
+GtkUIManager *
+egg_editable_toolbar_get_manager (EggEditableToolbar *etoolbar)
+{
+  return etoolbar->priv->manager;
+}
+
+void
+egg_editable_toolbar_set_primary_class (EggEditableToolbar *etoolbar,
+                                        gboolean set,
+                                        const gchar *name)
+{
+  etoolbar->priv->set_primary_class = set;
+
+  g_free (etoolbar->priv->primary_name);
+  etoolbar->priv->primary_name = g_strdup (name);
+
+  toolbar_visibility_refresh (etoolbar);
+}
diff --git a/cut-n-paste/toolbar-editor/egg-editable-toolbar.h 
b/cut-n-paste/toolbar-editor/egg-editable-toolbar.h
new file mode 100644
index 0000000..85df6de
--- /dev/null
+++ b/cut-n-paste/toolbar-editor/egg-editable-toolbar.h
@@ -0,0 +1,95 @@
+/*
+ *  Copyright (C) 2003, 2004  Marco Pesenti Gritti
+ *  Copyright (C) 2003, 2004, 2005  Christian Persch
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *  $Id: egg-editable-toolbar.h 891 2008-08-08 21:14:52Z friemann $
+ */
+
+#ifndef EGG_EDITABLE_TOOLBAR_H
+#define EGG_EDITABLE_TOOLBAR_H
+
+#include "egg-toolbars-model.h"
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_EDITABLE_TOOLBAR             (egg_editable_toolbar_get_type ())
+#define EGG_EDITABLE_TOOLBAR(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_EDITABLE_TOOLBAR, 
EggEditableToolbar))
+#define EGG_EDITABLE_TOOLBAR_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_EDITABLE_TOOLBAR, 
EggEditableToolbarClass))
+#define EGG_IS_EDITABLE_TOOLBAR(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_EDITABLE_TOOLBAR))
+#define EGG_IS_EDITABLE_TOOLBAR_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_EDITABLE_TOOLBAR))
+#define EGG_EDITABLE_TOOLBAR_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_EDITABLE_TOOLBAR, 
EggEditableToolbarClass))
+
+typedef struct _EggEditableToolbar        EggEditableToolbar;
+typedef struct _EggEditableToolbarPrivate EggEditableToolbarPrivate;
+typedef struct _EggEditableToolbarClass   EggEditableToolbarClass;
+
+struct _EggEditableToolbar
+{
+  GtkBox parent_object;
+
+  /*< private >*/
+  EggEditableToolbarPrivate *priv;
+};
+
+struct _EggEditableToolbarClass
+{
+  GtkBoxClass parent_class;
+
+  void (* action_request) (EggEditableToolbar *etoolbar,
+                          const char *action_name);
+};
+
+GType               egg_editable_toolbar_get_type        (void);
+GtkWidget         *egg_editable_toolbar_new             (GtkUIManager         *manager,
+                                                         const char           *visibility_path);
+GtkWidget         *egg_editable_toolbar_new_with_model  (GtkUIManager         *manager,
+                                                         EggToolbarsModel     *model,
+                                                         const char           *visibility_path);
+void               egg_editable_toolbar_set_model       (EggEditableToolbar   *etoolbar,
+                                                         EggToolbarsModel     *model);
+EggToolbarsModel   *egg_editable_toolbar_get_model       (EggEditableToolbar   *etoolbar);
+GtkUIManager       *egg_editable_toolbar_get_manager     (EggEditableToolbar   *etoolbar);
+void               egg_editable_toolbar_set_edit_mode   (EggEditableToolbar   *etoolbar,
+                                                         gboolean              mode);
+gboolean           egg_editable_toolbar_get_edit_mode   (EggEditableToolbar   *etoolbar);
+void               egg_editable_toolbar_show            (EggEditableToolbar   *etoolbar,
+                                                         const char           *name);
+void               egg_editable_toolbar_hide            (EggEditableToolbar   *etoolbar,
+                                                         const char           *name);
+void               egg_editable_toolbar_set_fixed       (EggEditableToolbar   *etoolbar,
+                                                         GtkToolbar           *fixed_toolbar);
+
+GtkWidget *         egg_editable_toolbar_get_selected    (EggEditableToolbar   *etoolbar);
+void                egg_editable_toolbar_set_selected    (EggEditableToolbar   *etoolbar,
+                                                         GtkWidget            *widget);
+
+void              egg_editable_toolbar_add_visibility    (EggEditableToolbar   *etoolbar,
+                                                         const char           *path);
+
+void              egg_editable_toolbar_set_primary_class (EggEditableToolbar *etoolbar,
+                                                          gboolean            set,
+                                                          const gchar        *path);
+
+/* Private Functions */
+
+GtkWidget         *_egg_editable_toolbar_new_separator_image (void);
+
+G_END_DECLS
+
+#endif
diff --git a/cut-n-paste/toolbar-editor/egg-toolbar-editor.c b/cut-n-paste/toolbar-editor/egg-toolbar-editor.c
new file mode 100644
index 0000000..7c681cb
--- /dev/null
+++ b/cut-n-paste/toolbar-editor/egg-toolbar-editor.c
@@ -0,0 +1,677 @@
+/*
+ *  Copyright (C) 2003 Marco Pesenti Gritti
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *  $Id: egg-toolbar-editor.c 929 2009-02-19 14:49:56Z friemann $
+ */
+
+#include "config.h"
+
+#include "egg-toolbar-editor.h"
+#include "egg-editable-toolbar.h"
+
+#include <string.h>
+#include <libxml/tree.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+static const GtkTargetEntry dest_drag_types[] = {
+  {EGG_TOOLBAR_ITEM_TYPE, GTK_TARGET_SAME_APP, 0},
+};
+
+static const GtkTargetEntry source_drag_types[] = {
+  {EGG_TOOLBAR_ITEM_TYPE, GTK_TARGET_SAME_APP, 0},
+};
+
+
+static void egg_toolbar_editor_finalize         (GObject *object);
+static void update_editor_sheet                 (EggToolbarEditor *editor);
+
+enum
+{
+  PROP_0,
+  PROP_UI_MANAGER,
+  PROP_TOOLBARS_MODEL
+};
+
+enum
+{
+  SIGNAL_HANDLER_ITEM_ADDED,
+  SIGNAL_HANDLER_ITEM_REMOVED,
+  SIGNAL_HANDLER_TOOLBAR_REMOVED,
+  SIGNAL_HANDLER_LIST_SIZE  /* Array size */
+};
+
+#define EGG_TOOLBAR_EDITOR_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), 
EGG_TYPE_TOOLBAR_EDITOR, EggToolbarEditorPrivate))
+
+struct EggToolbarEditorPrivate
+{
+  GtkUIManager *manager;
+  EggToolbarsModel *model;
+
+  GtkWidget *grid;
+  GtkWidget *scrolled_window;
+  GList     *actions_list;
+  GList     *factory_list;
+
+  /* These handlers need to be sanely disconnected when switching models */
+  gulong     sig_handlers[SIGNAL_HANDLER_LIST_SIZE];
+};
+
+G_DEFINE_TYPE (EggToolbarEditor, egg_toolbar_editor, GTK_TYPE_BOX);
+
+static gint
+compare_items (gconstpointer a,
+               gconstpointer b)
+{
+  const GtkWidget *item1 = a;
+  const GtkWidget *item2 = b;
+
+  char *key1 = g_object_get_data (G_OBJECT (item1),
+                                  "egg-collate-key");
+  char *key2 = g_object_get_data (G_OBJECT (item2),
+                                  "egg-collate-key");
+
+  return strcmp (key1, key2);
+}
+
+static GtkAction *
+find_action (EggToolbarEditor *t,
+            const char       *name)
+{
+  GList *l;
+  GtkAction *action = NULL;
+
+  l = gtk_ui_manager_get_action_groups (t->priv->manager);
+
+  g_return_val_if_fail (EGG_IS_TOOLBAR_EDITOR (t), NULL);
+  g_return_val_if_fail (name != NULL, NULL);
+
+  for (; l != NULL; l = l->next)
+    {
+      GtkAction *tmp;
+
+      tmp = gtk_action_group_get_action (GTK_ACTION_GROUP (l->data), name);
+      if (tmp)
+       action = tmp;
+    }
+
+  return action;
+}
+
+static void
+egg_toolbar_editor_set_ui_manager (EggToolbarEditor *t,
+                                  GtkUIManager     *manager)
+{
+  g_return_if_fail (GTK_IS_UI_MANAGER (manager));
+
+  t->priv->manager = g_object_ref (manager);
+}
+
+static void
+item_added_or_removed_cb (EggToolbarsModel   *model,
+                          int                 tpos,
+                          int                 ipos,
+                          EggToolbarEditor   *editor)
+{
+  update_editor_sheet (editor);
+}
+
+static void
+toolbar_removed_cb (EggToolbarsModel   *model,
+                   int                 position,
+                   EggToolbarEditor   *editor)
+{
+  update_editor_sheet (editor);
+}
+
+static void
+egg_toolbar_editor_disconnect_model (EggToolbarEditor *t)
+{
+  EggToolbarEditorPrivate *priv = t->priv;
+  EggToolbarsModel *model = priv->model;
+  gulong handler;
+  int i;
+
+  for (i = 0; i < SIGNAL_HANDLER_LIST_SIZE; i++)
+    {
+      handler = priv->sig_handlers[i];
+
+      if (handler != 0)
+        {
+         if (g_signal_handler_is_connected (model, handler))
+           {
+             g_signal_handler_disconnect (model, handler);
+           }
+
+         priv->sig_handlers[i] = 0;
+        }
+    }
+}
+
+void
+egg_toolbar_editor_set_model (EggToolbarEditor *t,
+                             EggToolbarsModel *model)
+{
+  EggToolbarEditorPrivate *priv;
+
+  g_return_if_fail (EGG_IS_TOOLBAR_EDITOR (t));
+  g_return_if_fail (model != NULL);
+
+  priv = t->priv;
+
+  if (priv->model)
+    {
+      if (G_UNLIKELY (priv->model == model)) return;
+
+      egg_toolbar_editor_disconnect_model (t);
+      g_object_unref (priv->model);
+    }
+
+  priv->model = g_object_ref (model);
+
+  update_editor_sheet (t);
+
+  priv->sig_handlers[SIGNAL_HANDLER_ITEM_ADDED] =
+    g_signal_connect_object (model, "item_added",
+                            G_CALLBACK (item_added_or_removed_cb), t, 0);
+  priv->sig_handlers[SIGNAL_HANDLER_ITEM_REMOVED] =
+    g_signal_connect_object (model, "item_removed",
+                            G_CALLBACK (item_added_or_removed_cb), t, 0);
+  priv->sig_handlers[SIGNAL_HANDLER_TOOLBAR_REMOVED] =
+    g_signal_connect_object (model, "toolbar_removed",
+                            G_CALLBACK (toolbar_removed_cb), t, 0);
+}
+
+static void
+egg_toolbar_editor_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  EggToolbarEditor *t = EGG_TOOLBAR_EDITOR (object);
+
+  switch (prop_id)
+    {
+    case PROP_UI_MANAGER:
+      egg_toolbar_editor_set_ui_manager (t, g_value_get_object (value));
+      break;
+    case PROP_TOOLBARS_MODEL:
+      egg_toolbar_editor_set_model (t, g_value_get_object (value));
+      break;
+    }
+}
+
+static void
+egg_toolbar_editor_get_property (GObject    *object,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+  EggToolbarEditor *t = EGG_TOOLBAR_EDITOR (object);
+
+  switch (prop_id)
+    {
+    case PROP_UI_MANAGER:
+      g_value_set_object (value, t->priv->manager);
+      break;
+    case PROP_TOOLBARS_MODEL:
+      g_value_set_object (value, t->priv->model);
+      break;
+    }
+}
+
+static void
+egg_toolbar_editor_class_init (EggToolbarEditorClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = egg_toolbar_editor_finalize;
+  object_class->set_property = egg_toolbar_editor_set_property;
+  object_class->get_property = egg_toolbar_editor_get_property;
+
+  g_object_class_install_property (object_class,
+                                  PROP_UI_MANAGER,
+                                  g_param_spec_object ("ui-manager",
+                                                       "UI-Manager",
+                                                       "UI Manager",
+                                                       GTK_TYPE_UI_MANAGER,
+                                                       G_PARAM_READWRITE | G_PARAM_STATIC_NAME | 
G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
+                                                       G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+                                 PROP_TOOLBARS_MODEL,
+                                 g_param_spec_object ("model",
+                                                      "Model",
+                                                      "Toolbars Model",
+                                                      EGG_TYPE_TOOLBARS_MODEL,
+                                                      G_PARAM_READWRITE | G_PARAM_STATIC_NAME | 
G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
+                                                      G_PARAM_CONSTRUCT));
+
+  g_type_class_add_private (object_class, sizeof (EggToolbarEditorPrivate));
+}
+
+static void
+egg_toolbar_editor_finalize (GObject *object)
+{
+  EggToolbarEditor *editor = EGG_TOOLBAR_EDITOR (object);
+
+  if (editor->priv->manager)
+    {
+      g_object_unref (editor->priv->manager);
+    }
+
+  if (editor->priv->model)
+    {
+      egg_toolbar_editor_disconnect_model (editor);
+      g_object_unref (editor->priv->model);
+    }
+
+  g_list_free (editor->priv->actions_list);
+  g_list_free (editor->priv->factory_list);
+
+  G_OBJECT_CLASS (egg_toolbar_editor_parent_class)->finalize (object);
+}
+
+GtkWidget *
+egg_toolbar_editor_new (GtkUIManager *manager,
+                       EggToolbarsModel *model)
+{
+  return GTK_WIDGET (g_object_new (EGG_TYPE_TOOLBAR_EDITOR,
+                                  "ui-manager", manager,
+                                  "model", model,
+                                  NULL));
+}
+
+static void
+drag_begin_cb (GtkWidget          *widget,
+              GdkDragContext     *context)
+{
+  gtk_widget_hide (widget);
+}
+
+static void
+drag_end_cb (GtkWidget          *widget,
+            GdkDragContext     *context)
+{
+  gtk_widget_show (widget);
+}
+
+static void
+drag_data_get_cb (GtkWidget          *widget,
+                 GdkDragContext     *context,
+                 GtkSelectionData   *selection_data,
+                 guint               info,
+                 guint32             time,
+                 EggToolbarEditor   *editor)
+{
+  const char *target;
+
+  target = g_object_get_data (G_OBJECT (widget), "egg-item-name");
+  g_return_if_fail (target != NULL);
+
+  gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8,
+                         (const guchar *) target, strlen (target));
+}
+
+static gchar *
+elide_underscores (const gchar *original)
+{
+  gchar *q, *result;
+  const gchar *p;
+  gboolean last_underscore;
+
+  q = result = g_malloc (strlen (original) + 1);
+  last_underscore = FALSE;
+
+  for (p = original; *p; p++)
+    {
+      if (!last_underscore && *p == '_')
+       last_underscore = TRUE;
+      else
+       {
+         last_underscore = FALSE;
+         *q++ = *p;
+       }
+    }
+
+  *q = '\0';
+
+  return result;
+}
+
+static void
+set_drag_cursor (GtkWidget *widget)
+{
+  GdkCursor *cursor;
+  GdkScreen *screen;
+
+  screen = gtk_widget_get_screen (widget);
+
+  cursor = gdk_cursor_new_for_display (gdk_screen_get_display (screen),
+                                      GDK_HAND2);
+  gdk_window_set_cursor (gtk_widget_get_window (widget), cursor);
+#if GTK_CHECK_VERSION (3,0,0)
+  g_object_unref (cursor);
+#else
+  gdk_cursor_unref (cursor);
+#endif
+}
+
+static void
+event_box_realize_cb (GtkWidget *widget, GtkImage *icon)
+{
+  GtkImageType type;
+
+  set_drag_cursor (widget);
+
+  type = gtk_image_get_storage_type (icon);
+  if (type == GTK_IMAGE_STOCK)
+    {
+      gchar *stock_id;
+      GdkPixbuf *pixbuf;
+
+      gtk_image_get_stock (icon, &stock_id, NULL);
+      pixbuf = gtk_widget_render_icon_pixbuf (widget, stock_id,
+                                              GTK_ICON_SIZE_LARGE_TOOLBAR);
+      gtk_drag_source_set_icon_pixbuf (widget, pixbuf);
+      g_object_unref (pixbuf);
+    }
+  else if (type == GTK_IMAGE_ICON_NAME)
+    {
+      const gchar *icon_name;
+      GdkScreen *screen;
+      GtkIconTheme *icon_theme;
+      GtkSettings *settings;
+      gint width, height;
+      GdkPixbuf *pixbuf;
+
+      gtk_image_get_icon_name (icon, &icon_name, NULL);
+      screen = gtk_widget_get_screen (widget);
+      icon_theme = gtk_icon_theme_get_for_screen (screen);
+      settings = gtk_settings_get_for_screen (screen);
+
+      if (!gtk_icon_size_lookup_for_settings (settings,
+                                              GTK_ICON_SIZE_LARGE_TOOLBAR,
+                                             &width, &height))
+        {
+         width = height = 24;
+       }
+
+      pixbuf = gtk_icon_theme_load_icon (icon_theme, icon_name,
+                                         MIN (width, height), 0, NULL);
+      if (G_UNLIKELY (!pixbuf))
+        return;
+
+      gtk_drag_source_set_icon_pixbuf (widget, pixbuf);
+      g_object_unref (pixbuf);
+
+    }
+  else if (type == GTK_IMAGE_PIXBUF)
+    {
+      GdkPixbuf *pixbuf = gtk_image_get_pixbuf (icon);
+      gtk_drag_source_set_icon_pixbuf (widget, pixbuf);
+    }
+}
+
+static GtkWidget *
+editor_create_item (EggToolbarEditor *editor,
+                   GtkImage         *icon,
+                   const char       *label_text,
+                   GdkDragAction     action)
+{
+  GtkWidget *event_box;
+  GtkWidget *vbox;
+  GtkWidget *label;
+  gchar *label_no_mnemonic = NULL;
+
+  event_box = gtk_event_box_new ();
+  gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE);
+  gtk_widget_show (event_box);
+  gtk_drag_source_set (event_box,
+                      GDK_BUTTON1_MASK,
+                      source_drag_types, G_N_ELEMENTS (source_drag_types), action);
+  g_signal_connect (event_box, "drag_data_get",
+                   G_CALLBACK (drag_data_get_cb), editor);
+  g_signal_connect_after (event_box, "realize",
+                         G_CALLBACK (event_box_realize_cb), icon);
+
+  if (action == GDK_ACTION_MOVE)
+    {
+      g_signal_connect (event_box, "drag_begin",
+                       G_CALLBACK (drag_begin_cb), NULL);
+      g_signal_connect (event_box, "drag_end",
+                       G_CALLBACK (drag_end_cb), NULL);
+    }
+
+  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+  gtk_widget_show (vbox);
+  gtk_container_add (GTK_CONTAINER (event_box), vbox);
+
+  gtk_widget_show (GTK_WIDGET (icon));
+  gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (icon), FALSE, TRUE, 0);
+  label_no_mnemonic = elide_underscores (label_text);
+  label = gtk_label_new (label_no_mnemonic);
+  g_free (label_no_mnemonic);
+  gtk_widget_show (label);
+  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
+
+  return event_box;
+}
+
+static GtkWidget *
+editor_create_item_from_name (EggToolbarEditor *editor,
+                              const char *      name,
+                              GdkDragAction     drag_action)
+{
+  GtkWidget *item;
+  const char *item_name;
+  char *short_label;
+  const char *collate_key;
+
+  if (strcmp (name, "_separator") == 0)
+    {
+      GtkWidget *icon;
+
+      icon = _egg_editable_toolbar_new_separator_image ();
+      short_label = _("Separator");
+      item_name = g_strdup (name);
+      collate_key = g_utf8_collate_key (short_label, -1);
+      item = editor_create_item (editor, GTK_IMAGE (icon),
+                                 short_label, drag_action);
+    }
+  else
+    {
+      GtkAction *action;
+      GtkWidget *icon;
+      char *stock_id, *icon_name = NULL;
+
+      action = find_action (editor, name);
+      g_return_val_if_fail (action != NULL, NULL);
+
+      g_object_get (action,
+                    "icon-name", &icon_name,
+                    "stock-id", &stock_id,
+                   "short-label", &short_label,
+                   NULL);
+
+      /* This is a workaround to catch named icons. */
+      if (icon_name)
+        icon = gtk_image_new_from_icon_name (icon_name,
+                                            GTK_ICON_SIZE_LARGE_TOOLBAR);
+      else
+        icon = gtk_image_new_from_stock (stock_id ? stock_id : GTK_STOCK_DND,
+                                         GTK_ICON_SIZE_LARGE_TOOLBAR);
+
+      item_name = g_strdup (name);
+      collate_key = g_utf8_collate_key (short_label, -1);
+      item = editor_create_item (editor, GTK_IMAGE (icon),
+                                 short_label, drag_action);
+
+      g_free (short_label);
+      g_free (stock_id);
+      g_free (icon_name);
+    }
+
+  g_object_set_data_full (G_OBJECT (item), "egg-collate-key",
+                          (gpointer) collate_key, g_free);
+  g_object_set_data_full (G_OBJECT (item), "egg-item-name",
+                          (gpointer) item_name, g_free);
+
+  return item;
+}
+
+static gint
+append_grid (GtkGrid *grid, GList *items, gint y, gint width)
+{
+  if (items != NULL)
+    {
+      gint x = 0;
+      GtkWidget *alignment;
+      GtkWidget *item;
+
+      if (y > 0)
+        {
+          item = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+          alignment = gtk_alignment_new (0.5, 0.5, 1.0, 0.0);
+          g_object_set (G_OBJECT (alignment), "expand", TRUE, NULL);
+          gtk_container_add (GTK_CONTAINER (alignment), item);
+          gtk_widget_show (alignment);
+          gtk_widget_show (item);
+
+          gtk_grid_attach (grid, alignment, 0, y, width, 1);
+          y++;
+        }
+
+      for (; items != NULL; items = items->next)
+        {
+          item = items->data;
+          alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
+          g_object_set (G_OBJECT (alignment), "expand", TRUE, NULL);
+          gtk_container_add (GTK_CONTAINER (alignment), item);
+          gtk_widget_show (alignment);
+          gtk_widget_show (item);
+
+          if (x >= width)
+            {
+              x = 0;
+              y++;
+            }
+          gtk_grid_attach (grid, alignment, x, y, 1, 1);
+          x++;
+        }
+
+      y++;
+    }
+  return y;
+}
+
+static void
+update_editor_sheet (EggToolbarEditor *editor)
+{
+  gint y;
+  GPtrArray *items;
+  GList *to_move = NULL, *to_copy = NULL;
+  GtkWidget *grid;
+  GtkWidget *viewport;
+
+  g_return_if_fail (EGG_IS_TOOLBAR_EDITOR (editor));
+
+  /* Create new grid. */
+  grid = gtk_grid_new ();
+  editor->priv->grid = grid;
+  gtk_container_set_border_width (GTK_CONTAINER (grid), 12);
+  gtk_grid_set_row_spacing (GTK_GRID (grid), 24);
+  gtk_widget_show (grid);
+  gtk_drag_dest_set (grid, GTK_DEST_DEFAULT_ALL,
+                    dest_drag_types, G_N_ELEMENTS (dest_drag_types),
+                     GDK_ACTION_MOVE | GDK_ACTION_COPY);
+
+  /* Build two lists of items (one for copying, one for moving). */
+  items = egg_toolbars_model_get_name_avail (editor->priv->model);
+  while (items->len > 0)
+    {
+      GtkWidget *item;
+      const char *name;
+      gint flags;
+
+      name = g_ptr_array_index (items, 0);
+      g_ptr_array_remove_index_fast (items, 0);
+
+      flags = egg_toolbars_model_get_name_flags (editor->priv->model, name);
+      if ((flags & EGG_TB_MODEL_NAME_INFINITE) == 0)
+        {
+          item = editor_create_item_from_name (editor, name, GDK_ACTION_MOVE);
+          if (item != NULL)
+            to_move = g_list_insert_sorted (to_move, item, compare_items);
+        }
+      else
+        {
+          item = editor_create_item_from_name (editor, name, GDK_ACTION_COPY);
+          if (item != NULL)
+            to_copy = g_list_insert_sorted (to_copy, item, compare_items);
+        }
+    }
+
+  /* Add them to the sheet. */
+  y = 0;
+  y = append_grid (GTK_GRID (grid), to_move, y, 4);
+  y = append_grid (GTK_GRID (grid), to_copy, y, 4);
+
+  g_list_free (to_move);
+  g_list_free (to_copy);
+  g_ptr_array_free (items, TRUE);
+
+  /* Delete old grid. */
+  viewport = gtk_bin_get_child (GTK_BIN (editor->priv->scrolled_window));
+  if (viewport)
+    {
+      gtk_container_remove (GTK_CONTAINER (viewport),
+                            gtk_bin_get_child (GTK_BIN (viewport)));
+    }
+
+  /* Add grid to window. */
+  gtk_scrolled_window_add_with_viewport
+    (GTK_SCROLLED_WINDOW (editor->priv->scrolled_window), grid);
+
+}
+
+static void
+setup_editor (EggToolbarEditor *editor)
+{
+  GtkWidget *scrolled_window;
+
+  gtk_container_set_border_width (GTK_CONTAINER (editor), 12);
+  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+  editor->priv->scrolled_window = scrolled_window;
+  gtk_widget_show (scrolled_window);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+  gtk_box_pack_start (GTK_BOX (editor), scrolled_window, TRUE, TRUE, 0);
+}
+
+static void
+egg_toolbar_editor_init (EggToolbarEditor *t)
+{
+  t->priv = EGG_TOOLBAR_EDITOR_GET_PRIVATE (t);
+
+  gtk_orientable_set_orientation (GTK_ORIENTABLE (t),
+                                  GTK_ORIENTATION_VERTICAL);
+  t->priv->manager = NULL;
+  t->priv->actions_list = NULL;
+
+  setup_editor (t);
+}
+
diff --git a/cut-n-paste/toolbar-editor/egg-toolbar-editor.h b/cut-n-paste/toolbar-editor/egg-toolbar-editor.h
new file mode 100644
index 0000000..93ac052
--- /dev/null
+++ b/cut-n-paste/toolbar-editor/egg-toolbar-editor.h
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (C) 2003 Marco Pesenti Gritti
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef EGG_TOOLBAR_EDITOR_H
+#define EGG_TOOLBAR_EDITOR_H
+
+#include <gtk/gtk.h>
+
+#include "egg-toolbars-model.h"
+
+G_BEGIN_DECLS
+
+typedef struct EggToolbarEditorClass EggToolbarEditorClass;
+
+#define EGG_TYPE_TOOLBAR_EDITOR             (egg_toolbar_editor_get_type ())
+#define EGG_TOOLBAR_EDITOR(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TOOLBAR_EDITOR, 
EggToolbarEditor))
+#define EGG_TOOLBAR_EDITOR_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_TOOLBAR_EDITOR, 
EggToolbarEditorClass))
+#define EGG_IS_TOOLBAR_EDITOR(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TOOLBAR_EDITOR))
+#define EGG_IS_TOOLBAR_EDITOR_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TOOLBAR_EDITOR))
+#define EGG_TOOLBAR_EDITOR_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TOOLBAR_EDITOR, 
EggToolbarEditorClass))
+
+
+typedef struct EggToolbarEditor EggToolbarEditor;
+typedef struct EggToolbarEditorPrivate EggToolbarEditorPrivate;
+
+struct EggToolbarEditor
+{
+  GtkBox parent_object;
+
+  /*< private >*/
+  EggToolbarEditorPrivate *priv;
+};
+
+struct EggToolbarEditorClass
+{
+  GtkBoxClass parent_class;
+};
+
+
+GType             egg_toolbar_editor_get_type     (void);
+GtkWidget        *egg_toolbar_editor_new          (GtkUIManager *manager,
+                                                  EggToolbarsModel *model);
+void             egg_toolbar_editor_set_model    (EggToolbarEditor *t,
+                                                  EggToolbarsModel *model);
+
+G_END_DECLS
+
+#endif
diff --git a/cut-n-paste/toolbar-editor/egg-toolbars-model.c b/cut-n-paste/toolbar-editor/egg-toolbars-model.c
new file mode 100644
index 0000000..f64e79b
--- /dev/null
+++ b/cut-n-paste/toolbar-editor/egg-toolbars-model.c
@@ -0,0 +1,987 @@
+/*
+ *  Copyright (C) 2002-2004 Marco Pesenti Gritti
+ *  Copyright (C) 2004 Christian Persch
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *  $Id: egg-toolbars-model.c 929 2009-02-19 14:49:56Z friemann $
+ */
+
+#include "config.h"
+
+#include "egg-toolbars-model.h"
+#include "eggtypebuiltins.h"
+#include "eggmarshalers.h"
+
+#include <unistd.h>
+#include <string.h>
+#include <libxml/tree.h>
+#include <gdk/gdk.h>
+
+static void egg_toolbars_model_finalize   (GObject               *object);
+
+enum
+{
+  ITEM_ADDED,
+  ITEM_REMOVED,
+  TOOLBAR_ADDED,
+  TOOLBAR_CHANGED,
+  TOOLBAR_REMOVED,
+  LAST_SIGNAL
+};
+
+typedef struct
+{
+  char *name;
+  EggTbModelFlags flags;
+} EggToolbarsToolbar;
+
+typedef struct
+{
+  char *name;
+} EggToolbarsItem;
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+#define EGG_TOOLBARS_MODEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), 
EGG_TYPE_TOOLBARS_MODEL, EggToolbarsModelPrivate))
+
+struct EggToolbarsModelPrivate
+{
+  GNode *toolbars;
+  GList *types;
+  GHashTable *flags;
+};
+
+G_DEFINE_TYPE (EggToolbarsModel, egg_toolbars_model, G_TYPE_OBJECT)
+
+static xmlDocPtr
+egg_toolbars_model_to_xml (EggToolbarsModel *model)
+{
+  GNode *l1, *l2, *tl;
+  GList *l3;
+  xmlDocPtr doc;
+
+  g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (model), NULL);
+
+  tl = model->priv->toolbars;
+
+  xmlIndentTreeOutput = TRUE;
+  doc = xmlNewDoc ((const xmlChar*) "1.0");
+  doc->children = xmlNewDocNode (doc, NULL, (const xmlChar*) "toolbars", NULL);
+
+  for (l1 = tl->children; l1 != NULL; l1 = l1->next)
+    {
+      xmlNodePtr tnode;
+      EggToolbarsToolbar *toolbar = l1->data;
+
+      tnode = xmlNewChild (doc->children, NULL, (const xmlChar*) "toolbar", NULL);
+      xmlSetProp (tnode, (const xmlChar*) "name", (const xmlChar*) toolbar->name);
+      xmlSetProp (tnode, (const xmlChar*) "hidden",
+                 (toolbar->flags&EGG_TB_MODEL_HIDDEN) ? (const xmlChar*) "true" : (const xmlChar*) "false");
+      xmlSetProp (tnode, (const xmlChar*) "editable",
+                 (toolbar->flags&EGG_TB_MODEL_NOT_EDITABLE) ? (const xmlChar*) "false" : (const xmlChar*) 
"true");
+
+      for (l2 = l1->children; l2 != NULL; l2 = l2->next)
+       {
+         xmlNodePtr node;
+         EggToolbarsItem *item = l2->data;
+
+          if (strcmp (item->name, "_separator") == 0)
+            {
+              node = xmlNewChild (tnode, NULL, (const xmlChar*) "separator", NULL);
+              continue;
+            }
+
+          node = xmlNewChild (tnode, NULL, (const xmlChar*) "toolitem", NULL);
+          xmlSetProp (node, (const xmlChar*) "name", (const xmlChar*) item->name);
+
+          /* Add 'data' nodes for each data type which can be written out for this
+           * item. Only write types which can be used to restore the data. */
+          for (l3 = model->priv->types; l3 != NULL; l3 = l3->next)
+            {
+              EggToolbarsItemType *type = l3->data;
+              if (type->get_name != NULL && type->get_data != NULL)
+                {
+                  xmlNodePtr dnode;
+                  char *tmp;
+
+                  tmp = type->get_data (type, item->name);
+                  if (tmp != NULL)
+                    {
+                      dnode = xmlNewTextChild (node, NULL, (const xmlChar*) "data", (const xmlChar*) tmp);
+                      g_free (tmp);
+
+                      tmp = gdk_atom_name (type->type);
+                      xmlSetProp (dnode, (const xmlChar*) "type", (const xmlChar*) tmp);
+                      g_free (tmp);
+                    }
+                }
+           }
+       }
+    }
+
+  return doc;
+}
+
+static gboolean
+safe_save_xml (const char *xml_file, xmlDocPtr doc)
+{
+       char *tmp_file;
+       char *old_file;
+       gboolean old_exist;
+       gboolean retval = TRUE;
+
+       tmp_file = g_strconcat (xml_file, ".tmp", NULL);
+       old_file = g_strconcat (xml_file, ".old", NULL);
+
+       if (xmlSaveFormatFile (tmp_file, doc, 1) <= 0)
+       {
+               g_warning ("Failed to write XML data to %s", tmp_file);
+               goto failed;
+       }
+
+       old_exist = g_file_test (xml_file, G_FILE_TEST_EXISTS);
+
+       if (old_exist)
+       {
+               if (rename (xml_file, old_file) < 0)
+               {
+                       g_warning ("Failed to rename %s to %s", xml_file, old_file);
+                       retval = FALSE;
+                       goto failed;
+               }
+       }
+
+       if (rename (tmp_file, xml_file) < 0)
+       {
+               g_warning ("Failed to rename %s to %s", tmp_file, xml_file);
+
+               if (rename (old_file, xml_file) < 0)
+               {
+                       g_warning ("Failed to restore %s from %s", xml_file, tmp_file);
+               }
+               retval = FALSE;
+               goto failed;
+       }
+
+       if (old_exist)
+       {
+               if (unlink (old_file) < 0)
+               {
+                       g_warning ("Failed to delete old file %s", old_file);
+               }
+       }
+
+       failed:
+       g_free (old_file);
+       g_free (tmp_file);
+
+       return retval;
+}
+
+void
+egg_toolbars_model_save_toolbars (EggToolbarsModel *model,
+                                 const char *xml_file,
+                                 const char *version)
+{
+  xmlDocPtr doc;
+  xmlNodePtr root;
+
+  g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model));
+
+  doc = egg_toolbars_model_to_xml (model);
+  root = xmlDocGetRootElement (doc);
+  xmlSetProp (root, (const xmlChar*) "version", (const xmlChar*) version);
+  safe_save_xml (xml_file, doc);
+  xmlFreeDoc (doc);
+}
+
+static gboolean
+is_unique (EggToolbarsModel *model,
+          EggToolbarsItem *idata)
+{
+  EggToolbarsItem *idata2;
+  GNode *toolbar, *item;
+
+
+  for(toolbar = g_node_first_child (model->priv->toolbars);
+      toolbar != NULL; toolbar = g_node_next_sibling (toolbar))
+    {
+      for(item = g_node_first_child (toolbar);
+         item != NULL; item = g_node_next_sibling (item))
+        {
+         idata2 = item->data;
+
+         if (idata != idata2 && strcmp (idata->name, idata2->name) == 0)
+           {
+             return FALSE;
+           }
+       }
+    }
+
+  return TRUE;
+}
+
+static GNode *
+toolbar_node_new (const char *name)
+{
+  EggToolbarsToolbar *toolbar;
+
+  toolbar = g_new (EggToolbarsToolbar, 1);
+  toolbar->name = g_strdup (name);
+  toolbar->flags = 0;
+
+  return g_node_new (toolbar);
+}
+
+static GNode *
+item_node_new (const char *name, EggToolbarsModel *model)
+{
+  EggToolbarsItem *item;
+  int flags;
+
+  g_return_val_if_fail (name != NULL, NULL);
+
+  item = g_new (EggToolbarsItem, 1);
+  item->name = g_strdup (name);
+
+  flags = GPOINTER_TO_INT (g_hash_table_lookup (model->priv->flags, item->name));
+  if ((flags & EGG_TB_MODEL_NAME_INFINITE) == 0)
+    g_hash_table_insert (model->priv->flags,
+                        g_strdup (item->name),
+                        GINT_TO_POINTER (flags | EGG_TB_MODEL_NAME_USED));
+
+  return g_node_new (item);
+}
+
+static void
+item_node_free (GNode *item_node, EggToolbarsModel *model)
+{
+  EggToolbarsItem *item = item_node->data;
+  int flags;
+
+  flags = GPOINTER_TO_INT (g_hash_table_lookup (model->priv->flags, item->name));
+  if ((flags & EGG_TB_MODEL_NAME_INFINITE) == 0 && is_unique (model, item))
+    g_hash_table_insert (model->priv->flags,
+                        g_strdup (item->name),
+                        GINT_TO_POINTER (flags & ~EGG_TB_MODEL_NAME_USED));
+
+  g_free (item->name);
+  g_free (item);
+
+  g_node_destroy (item_node);
+}
+
+static void
+toolbar_node_free (GNode *toolbar_node, EggToolbarsModel *model)
+{
+  EggToolbarsToolbar *toolbar = toolbar_node->data;
+
+  g_node_children_foreach (toolbar_node, G_TRAVERSE_ALL,
+                          (GNodeForeachFunc) item_node_free, model);
+
+  g_free (toolbar->name);
+  g_free (toolbar);
+
+  g_node_destroy (toolbar_node);
+}
+
+EggTbModelFlags
+egg_toolbars_model_get_flags (EggToolbarsModel *model,
+                             int               toolbar_position)
+{
+  GNode *toolbar_node;
+  EggToolbarsToolbar *toolbar;
+
+  toolbar_node = g_node_nth_child (model->priv->toolbars, toolbar_position);
+  g_return_val_if_fail (toolbar_node != NULL, 0);
+
+  toolbar = toolbar_node->data;
+
+  return toolbar->flags;
+}
+
+void
+egg_toolbars_model_set_flags (EggToolbarsModel *model,
+                             int               toolbar_position,
+                             EggTbModelFlags   flags)
+{
+  GNode *toolbar_node;
+  EggToolbarsToolbar *toolbar;
+
+  toolbar_node = g_node_nth_child (model->priv->toolbars, toolbar_position);
+  g_return_if_fail (toolbar_node != NULL);
+
+  toolbar = toolbar_node->data;
+
+  toolbar->flags = flags;
+
+  g_signal_emit (G_OBJECT (model), signals[TOOLBAR_CHANGED],
+                0, toolbar_position);
+}
+
+
+char *
+egg_toolbars_model_get_data (EggToolbarsModel *model,
+                             GdkAtom           type,
+                             const char       *name)
+{
+  EggToolbarsItemType *t;
+  char *data = NULL;
+  GList *l;
+
+  if (type == GDK_NONE || type == gdk_atom_intern (EGG_TOOLBAR_ITEM_TYPE, FALSE))
+    {
+      g_return_val_if_fail (name != NULL, NULL);
+      g_return_val_if_fail (*name != 0,   NULL);
+      return strdup (name);
+    }
+
+  for (l = model->priv->types; l != NULL; l = l->next)
+    {
+      t = l->data;
+      if (t->type == type && t->get_data != NULL)
+        {
+          data = t->get_data (t, name);
+         if (data != NULL) break;
+        }
+    }
+
+  return data;
+}
+
+char *
+egg_toolbars_model_get_name (EggToolbarsModel *model,
+                             GdkAtom           type,
+                             const char       *data,
+                             gboolean          create)
+{
+  EggToolbarsItemType *t;
+  char *name = NULL;
+  GList *l;
+
+  if (type == GDK_NONE || type == gdk_atom_intern (EGG_TOOLBAR_ITEM_TYPE, FALSE))
+    {
+      g_return_val_if_fail (data, NULL);
+      g_return_val_if_fail (*data, NULL);
+      return strdup (data);
+    }
+
+  if (create)
+    {
+      for (l = model->priv->types; name == NULL && l != NULL; l = l->next)
+        {
+          t = l->data;
+          if (t->type == type && t->new_name != NULL)
+            name = t->new_name (t, data);
+        }
+
+      return name;
+    }
+  else
+    {
+      for (l = model->priv->types; name == NULL && l != NULL; l = l->next)
+        {
+          t = l->data;
+          if (t->type == type && t->get_name != NULL)
+            name = t->get_name (t, data);
+        }
+
+      return name;
+    }
+}
+
+static gboolean
+impl_add_item (EggToolbarsModel    *model,
+              int                  toolbar_position,
+              int                  position,
+              const char          *name)
+{
+  GNode *parent_node;
+  GNode *child_node;
+  int real_position;
+
+  g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (model), FALSE);
+  g_return_val_if_fail (name != NULL, FALSE);
+
+  parent_node = g_node_nth_child (model->priv->toolbars, toolbar_position);
+  child_node = item_node_new (name, model);
+  g_node_insert (parent_node, position, child_node);
+
+  real_position = g_node_child_position (parent_node, child_node);
+
+  g_signal_emit (G_OBJECT (model), signals[ITEM_ADDED], 0,
+                toolbar_position, real_position);
+
+  return TRUE;
+}
+
+gboolean
+egg_toolbars_model_add_item (EggToolbarsModel *model,
+                            int               toolbar_position,
+                            int               position,
+                            const char       *name)
+{
+  EggToolbarsModelClass *klass = EGG_TOOLBARS_MODEL_GET_CLASS (model);
+  return klass->add_item (model, toolbar_position, position, name);
+}
+
+int
+egg_toolbars_model_add_toolbar (EggToolbarsModel *model,
+                               int               position,
+                               const char       *name)
+{
+  GNode *node;
+  int real_position;
+
+  g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (model), -1);
+
+  node = toolbar_node_new (name);
+  g_node_insert (model->priv->toolbars, position, node);
+
+  real_position = g_node_child_position (model->priv->toolbars, node);
+
+  g_signal_emit (G_OBJECT (model), signals[TOOLBAR_ADDED],
+                0, real_position);
+
+  return g_node_child_position (model->priv->toolbars, node);
+}
+
+static char *
+parse_data_list (EggToolbarsModel *model,
+                xmlNodePtr        child,
+                 gboolean          create)
+{
+  char *name = NULL;
+  while (child && name == NULL)
+    {
+      if (xmlStrEqual (child->name, (const xmlChar*) "data"))
+        {
+          xmlChar *type = xmlGetProp (child, (const xmlChar*) "type");
+          xmlChar *data = xmlNodeGetContent (child);
+
+          if (type != NULL)
+            {
+              GdkAtom atom = gdk_atom_intern ((const char*) type, TRUE);
+              name = egg_toolbars_model_get_name (model, atom, (const char*) data, create);
+            }
+
+          xmlFree (type);
+          xmlFree (data);
+        }
+
+      child = child->next;
+    }
+
+  return name;
+}
+
+static void
+parse_item_list (EggToolbarsModel *model,
+                xmlNodePtr        child,
+                int               position)
+{
+  while (child)
+    {
+      if (xmlStrEqual (child->name, (const xmlChar*) "toolitem"))
+       {
+          char *name;
+
+          /* Try to get the name using the data elements first,
+             as they are more 'portable' or 'persistent'. */
+          name = parse_data_list (model, child->children, FALSE);
+          if (name == NULL)
+            {
+              name = parse_data_list (model, child->children, TRUE);
+            }
+
+          /* If that fails, try to use the name. */
+          if (name == NULL)
+            {
+              xmlChar *type = xmlGetProp (child, (const xmlChar*) "type");
+              xmlChar *data = xmlGetProp (child, (const xmlChar*) "name");
+              GdkAtom  atom = type ? gdk_atom_intern ((const char*) type, TRUE) : GDK_NONE;
+
+              /* If an old format, try to use it. */
+              name = egg_toolbars_model_get_name (model, atom, (const char*) data, FALSE);
+              if (name == NULL)
+                {
+                  name = egg_toolbars_model_get_name (model, atom, (const char*) data, TRUE);
+                }
+
+              xmlFree (type);
+              xmlFree (data);
+            }
+
+          if (name != NULL)
+            {
+              egg_toolbars_model_add_item (model, position, -1, name);
+              g_free (name);
+            }
+       }
+      else if (xmlStrEqual (child->name, (const xmlChar*) "separator"))
+       {
+          egg_toolbars_model_add_item (model, position, -1, "_separator");
+       }
+
+      child = child->next;
+    }
+}
+
+static void
+parse_toolbars (EggToolbarsModel *model,
+               xmlNodePtr        child)
+{
+  while (child)
+    {
+      if (xmlStrEqual (child->name, (const xmlChar*) "toolbar"))
+       {
+         xmlChar *string;
+         int position;
+          EggTbModelFlags flags;
+
+         string = xmlGetProp (child, (const xmlChar*) "name");
+         position = egg_toolbars_model_add_toolbar (model, -1, (const char*) string);
+          flags = egg_toolbars_model_get_flags (model, position);
+         xmlFree (string);
+
+         string = xmlGetProp (child, (const xmlChar*) "editable");
+          if (string && xmlStrEqual (string, (const xmlChar*) "false"))
+            flags |= EGG_TB_MODEL_NOT_EDITABLE;
+         xmlFree (string);
+
+         string = xmlGetProp (child, (const xmlChar*) "hidden");
+          if (string && xmlStrEqual (string, (const xmlChar*) "true"))
+            flags |= EGG_TB_MODEL_HIDDEN;
+         xmlFree (string);
+
+         string = xmlGetProp (child, (const xmlChar*) "style");
+         if (string && xmlStrEqual (string, (const xmlChar*) "icons-only"))
+            flags |= EGG_TB_MODEL_ICONS;
+         xmlFree (string);
+
+          egg_toolbars_model_set_flags (model, position, flags);
+
+         parse_item_list (model, child->children, position);
+       }
+
+      child = child->next;
+    }
+}
+
+gboolean
+egg_toolbars_model_load_toolbars (EggToolbarsModel *model,
+                                 const char *xml_file)
+{
+  xmlDocPtr doc;
+  xmlNodePtr root;
+
+  g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (model), FALSE);
+
+  if (!xml_file || !g_file_test (xml_file, G_FILE_TEST_EXISTS)) return FALSE;
+
+  doc = xmlParseFile (xml_file);
+  if (doc == NULL)
+  {
+    g_warning ("Failed to load XML data from %s", xml_file);
+    return FALSE;
+  }
+  root = xmlDocGetRootElement (doc);
+
+  parse_toolbars (model, root->children);
+
+  xmlFreeDoc (doc);
+
+  return TRUE;
+}
+
+static void
+parse_available_list (EggToolbarsModel *model,
+                     xmlNodePtr        child)
+{
+  gint flags;
+
+  while (child)
+    {
+      if (xmlStrEqual (child->name, (const xmlChar*) "toolitem"))
+       {
+         xmlChar *name;
+
+         name = xmlGetProp (child, (const xmlChar*) "name");
+         flags = egg_toolbars_model_get_name_flags
+           (model, (const char*)name);
+         egg_toolbars_model_set_name_flags
+           (model, (const char*)name, flags | EGG_TB_MODEL_NAME_KNOWN);
+         xmlFree (name);
+       }
+      child = child->next;
+    }
+}
+
+static void
+parse_names (EggToolbarsModel *model,
+            xmlNodePtr        child)
+{
+  while (child)
+    {
+      if (xmlStrEqual (child->name, (const xmlChar*) "available"))
+       {
+         parse_available_list (model, child->children);
+       }
+
+      child = child->next;
+    }
+}
+
+gboolean
+egg_toolbars_model_load_names (EggToolbarsModel *model,
+                              const char *xml_file)
+{
+  xmlDocPtr doc;
+  xmlNodePtr root;
+
+  g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (model), FALSE);
+
+  if (!xml_file || !g_file_test (xml_file, G_FILE_TEST_EXISTS)) return FALSE;
+
+  doc = xmlParseFile (xml_file);
+  if (doc == NULL)
+  {
+    g_warning ("Failed to load XML data from %s", xml_file);
+    return FALSE;
+  }
+  root = xmlDocGetRootElement (doc);
+
+  parse_names (model, root->children);
+
+  xmlFreeDoc (doc);
+
+  return TRUE;
+}
+
+static void
+egg_toolbars_model_class_init (EggToolbarsModelClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  volatile GType flags_type G_GNUC_UNUSED; /* work around gcc's optimiser */
+
+  /* make sure the flags type is known */
+  flags_type = EGG_TYPE_TB_MODEL_FLAGS;
+
+  object_class->finalize = egg_toolbars_model_finalize;
+
+  klass->add_item = impl_add_item;
+
+  signals[ITEM_ADDED] =
+    g_signal_new ("item_added",
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (EggToolbarsModelClass, item_added),
+                 NULL, NULL, _egg_marshal_VOID__INT_INT,
+                 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
+  signals[TOOLBAR_ADDED] =
+    g_signal_new ("toolbar_added",
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_added),
+                 NULL, NULL, g_cclosure_marshal_VOID__INT,
+                 G_TYPE_NONE, 1, G_TYPE_INT);
+  signals[ITEM_REMOVED] =
+    g_signal_new ("item_removed",
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (EggToolbarsModelClass, item_removed),
+                 NULL, NULL, _egg_marshal_VOID__INT_INT,
+                 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
+  signals[TOOLBAR_REMOVED] =
+    g_signal_new ("toolbar_removed",
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_removed),
+                 NULL, NULL, g_cclosure_marshal_VOID__INT,
+                 G_TYPE_NONE, 1, G_TYPE_INT);
+  signals[TOOLBAR_CHANGED] =
+    g_signal_new ("toolbar_changed",
+                 G_OBJECT_CLASS_TYPE (object_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_changed),
+                 NULL, NULL, g_cclosure_marshal_VOID__INT,
+                 G_TYPE_NONE, 1, G_TYPE_INT);
+
+  g_type_class_add_private (object_class, sizeof (EggToolbarsModelPrivate));
+}
+
+static void
+egg_toolbars_model_init (EggToolbarsModel *model)
+{
+  model->priv =EGG_TOOLBARS_MODEL_GET_PRIVATE (model);
+
+  model->priv->toolbars = g_node_new (NULL);
+  model->priv->flags = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+  egg_toolbars_model_set_name_flags (model, "_separator",
+                                    EGG_TB_MODEL_NAME_KNOWN |
+                                    EGG_TB_MODEL_NAME_INFINITE);
+}
+
+static void
+egg_toolbars_model_finalize (GObject *object)
+{
+  EggToolbarsModel *model = EGG_TOOLBARS_MODEL (object);
+
+  g_node_children_foreach (model->priv->toolbars, G_TRAVERSE_ALL,
+                          (GNodeForeachFunc) toolbar_node_free, model);
+  g_node_destroy (model->priv->toolbars);
+  g_hash_table_destroy (model->priv->flags);
+
+  G_OBJECT_CLASS (egg_toolbars_model_parent_class)->finalize (object);
+}
+
+EggToolbarsModel *
+egg_toolbars_model_new (void)
+{
+  return EGG_TOOLBARS_MODEL (g_object_new (EGG_TYPE_TOOLBARS_MODEL, NULL));
+}
+
+void
+egg_toolbars_model_remove_toolbar (EggToolbarsModel   *model,
+                                  int                 position)
+{
+  GNode *node;
+  EggTbModelFlags flags;
+
+  g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model));
+
+  flags = egg_toolbars_model_get_flags (model, position);
+
+  if (!(flags & EGG_TB_MODEL_NOT_REMOVABLE))
+    {
+      node = g_node_nth_child (model->priv->toolbars, position);
+      g_return_if_fail (node != NULL);
+
+      toolbar_node_free (node, model);
+
+      g_signal_emit (G_OBJECT (model), signals[TOOLBAR_REMOVED],
+                    0, position);
+    }
+}
+
+void
+egg_toolbars_model_remove_item (EggToolbarsModel *model,
+                               int               toolbar_position,
+                               int               position)
+{
+  GNode *node, *toolbar;
+
+  g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model));
+
+  toolbar = g_node_nth_child (model->priv->toolbars, toolbar_position);
+  g_return_if_fail (toolbar != NULL);
+
+  node = g_node_nth_child (toolbar, position);
+  g_return_if_fail (node != NULL);
+
+  item_node_free (node, model);
+
+  g_signal_emit (G_OBJECT (model), signals[ITEM_REMOVED], 0,
+                toolbar_position, position);
+}
+
+void
+egg_toolbars_model_move_item (EggToolbarsModel *model,
+                             int               toolbar_position,
+                             int               position,
+                             int               new_toolbar_position,
+                             int               new_position)
+{
+  GNode *node, *toolbar, *new_toolbar;
+
+  g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model));
+
+  toolbar = g_node_nth_child (model->priv->toolbars, toolbar_position);
+  g_return_if_fail (toolbar != NULL);
+
+  new_toolbar = g_node_nth_child (model->priv->toolbars, new_toolbar_position);
+  g_return_if_fail (new_toolbar != NULL);
+
+  node = g_node_nth_child (toolbar, position);
+  g_return_if_fail (node != NULL);
+
+  g_node_unlink (node);
+
+  g_signal_emit (G_OBJECT (model), signals[ITEM_REMOVED], 0,
+                toolbar_position, position);
+
+  g_node_insert (new_toolbar, new_position, node);
+
+  g_signal_emit (G_OBJECT (model), signals[ITEM_ADDED], 0,
+                new_toolbar_position, new_position);
+}
+
+void
+egg_toolbars_model_delete_item (EggToolbarsModel *model,
+                               const char       *name)
+{
+  EggToolbarsItem *idata;
+  EggToolbarsToolbar *tdata;
+  GNode *toolbar, *item, *next;
+  int tpos, ipos;
+
+  g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model));
+
+  toolbar = g_node_first_child (model->priv->toolbars);
+  tpos = 0;
+
+  while (toolbar != NULL)
+    {
+      item = g_node_first_child (toolbar);
+      ipos = 0;
+
+      /* Don't delete toolbars that were already empty */
+      if (item == NULL)
+        {
+         toolbar = g_node_next_sibling (toolbar);
+         continue;
+        }
+
+      while (item != NULL)
+        {
+         next = g_node_next_sibling (item);
+         idata = item->data;
+         if (strcmp (idata->name, name) == 0)
+           {
+             item_node_free (item, model);
+             g_signal_emit (G_OBJECT (model),
+                            signals[ITEM_REMOVED],
+                            0, tpos, ipos);
+           }
+         else
+           {
+             ipos++;
+           }
+
+         item = next;
+        }
+
+      next = g_node_next_sibling (toolbar);
+      tdata = toolbar->data;
+      if (!(tdata->flags & EGG_TB_MODEL_NOT_REMOVABLE) &&
+         g_node_first_child (toolbar) == NULL)
+        {
+         toolbar_node_free (toolbar, model);
+
+         g_signal_emit (G_OBJECT (model),
+                        signals[TOOLBAR_REMOVED],
+                        0, tpos);
+        }
+      else
+        {
+         tpos++;
+        }
+
+      toolbar = next;
+    }
+}
+
+int
+egg_toolbars_model_n_items (EggToolbarsModel *model,
+                           int               toolbar_position)
+{
+  GNode *toolbar;
+
+  toolbar = g_node_nth_child (model->priv->toolbars, toolbar_position);
+  g_return_val_if_fail (toolbar != NULL, -1);
+
+  return g_node_n_children (toolbar);
+}
+
+const char *
+egg_toolbars_model_item_nth (EggToolbarsModel *model,
+                            int               toolbar_position,
+                            int               position)
+{
+  GNode *toolbar;
+  GNode *item;
+  EggToolbarsItem *idata;
+
+  toolbar = g_node_nth_child (model->priv->toolbars, toolbar_position);
+  g_return_val_if_fail (toolbar != NULL, NULL);
+
+  item = g_node_nth_child (toolbar, position);
+  g_return_val_if_fail (item != NULL, NULL);
+
+  idata = item->data;
+  return idata->name;
+}
+
+int
+egg_toolbars_model_n_toolbars (EggToolbarsModel *model)
+{
+  return g_node_n_children (model->priv->toolbars);
+}
+
+const char *
+egg_toolbars_model_toolbar_nth (EggToolbarsModel *model,
+                               int               position)
+{
+  GNode *toolbar;
+  EggToolbarsToolbar *tdata;
+
+  toolbar = g_node_nth_child (model->priv->toolbars, position);
+  g_return_val_if_fail (toolbar != NULL, NULL);
+
+  tdata = toolbar->data;
+
+  return tdata->name;
+}
+
+GList *
+egg_toolbars_model_get_types (EggToolbarsModel *model)
+{
+  return model->priv->types;
+}
+
+void
+egg_toolbars_model_set_types (EggToolbarsModel *model, GList *types)
+{
+  model->priv->types = types;
+}
+
+static void
+fill_avail_array (gpointer key, gpointer value, GPtrArray *array)
+{
+  int flags = GPOINTER_TO_INT (value);
+  if ((flags & EGG_TB_MODEL_NAME_KNOWN) && !(flags & EGG_TB_MODEL_NAME_USED))
+      g_ptr_array_add (array, key);
+}
+
+GPtrArray *
+egg_toolbars_model_get_name_avail (EggToolbarsModel *model)
+{
+  GPtrArray *array = g_ptr_array_new ();
+  g_hash_table_foreach (model->priv->flags, (GHFunc) fill_avail_array, array);
+  return array;
+}
+
+gint
+egg_toolbars_model_get_name_flags (EggToolbarsModel *model, const char *name)
+{
+  return GPOINTER_TO_INT (g_hash_table_lookup (model->priv->flags, name));
+}
+
+void
+egg_toolbars_model_set_name_flags (EggToolbarsModel *model, const char *name, gint flags)
+{
+  g_hash_table_insert (model->priv->flags, g_strdup (name), GINT_TO_POINTER (flags));
+}
diff --git a/cut-n-paste/toolbar-editor/egg-toolbars-model.h b/cut-n-paste/toolbar-editor/egg-toolbars-model.h
new file mode 100644
index 0000000..a791249
--- /dev/null
+++ b/cut-n-paste/toolbar-editor/egg-toolbars-model.h
@@ -0,0 +1,190 @@
+/*
+ *  Copyright (C) 2003-2004 Marco Pesenti Gritti
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *  $Id: egg-toolbars-model.h 929 2009-02-19 14:49:56Z friemann $
+ */
+
+#ifndef EGG_TOOLBARS_MODEL_H
+#define EGG_TOOLBARS_MODEL_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_TOOLBARS_MODEL             (egg_toolbars_model_get_type ())
+#define EGG_TOOLBARS_MODEL(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TOOLBARS_MODEL, 
EggToolbarsModel))
+#define EGG_TOOLBARS_MODEL_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_TOOLBARS_MODEL, 
EggToolbarsModelClass))
+#define EGG_IS_TOOLBARS_MODEL(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TOOLBARS_MODEL))
+#define EGG_IS_TOOLBARS_MODEL_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TOOLBARS_MODEL))
+#define EGG_TOOLBARS_MODEL_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TOOLBARS_MODEL, 
EggToolbarsModelClass))
+
+typedef struct EggToolbarsModel                EggToolbarsModel;
+typedef struct EggToolbarsModelPrivate EggToolbarsModelPrivate;
+typedef struct EggToolbarsModelClass   EggToolbarsModelClass;
+
+#define EGG_TOOLBAR_ITEM_TYPE "application/x-toolbar-item"
+
+typedef enum
+{
+  EGG_TB_MODEL_NOT_REMOVABLE    = 1 << 0,
+  EGG_TB_MODEL_NOT_EDITABLE     = 1 << 1,
+  EGG_TB_MODEL_BOTH             = 1 << 2,
+  EGG_TB_MODEL_BOTH_HORIZ       = 1 << 3,
+  EGG_TB_MODEL_ICONS            = 1 << 4,
+  EGG_TB_MODEL_TEXT             = 1 << 5,
+  EGG_TB_MODEL_STYLES_MASK      = 0x3C,
+  EGG_TB_MODEL_ACCEPT_ITEMS_ONLY = 1 << 6,
+  EGG_TB_MODEL_HIDDEN            = 1 << 7
+} EggTbModelFlags;
+
+typedef enum
+{
+  EGG_TB_MODEL_NAME_USED         = 1 << 0,
+  EGG_TB_MODEL_NAME_INFINITE     = 1 << 1,
+  EGG_TB_MODEL_NAME_KNOWN        = 1 << 2
+} EggTbModelNameFlags;
+
+struct EggToolbarsModel
+{
+  GObject parent_object;
+
+  /*< private >*/
+  EggToolbarsModelPrivate *priv;
+};
+
+struct EggToolbarsModelClass
+{
+  GObjectClass parent_class;
+
+  /* Signals */
+  void (* item_added)      (EggToolbarsModel *model,
+                           int toolbar_position,
+                           int position);
+  void (* item_removed)    (EggToolbarsModel *model,
+                           int toolbar_position,
+                           int position);
+  void (* toolbar_added)   (EggToolbarsModel *model,
+                           int position);
+  void (* toolbar_changed) (EggToolbarsModel *model,
+                           int position);
+  void (* toolbar_removed) (EggToolbarsModel *model,
+                           int position);
+
+  /* Virtual Table */
+  gboolean (* add_item)    (EggToolbarsModel *t,
+                           int               toolbar_position,
+                           int               position,
+                           const char       *name);
+};
+
+typedef struct EggToolbarsItemType EggToolbarsItemType;
+
+struct EggToolbarsItemType
+{
+  GdkAtom type;
+
+  gboolean (* has_data) (EggToolbarsItemType *type,
+                         const char          *name);
+  char *   (* get_data) (EggToolbarsItemType *type,
+                         const char          *name);
+
+  char *   (* new_name) (EggToolbarsItemType *type,
+                         const char          *data);
+  char *   (* get_name) (EggToolbarsItemType *type,
+                         const char          *data);
+};
+
+GType            egg_tb_model_flags_get_type       (void);
+GType            egg_toolbars_model_get_type       (void);
+EggToolbarsModel *egg_toolbars_model_new           (void);
+gboolean          egg_toolbars_model_load_names     (EggToolbarsModel *model,
+                                                    const char *xml_file);
+gboolean          egg_toolbars_model_load_toolbars  (EggToolbarsModel *model,
+                                                    const char *xml_file);
+void              egg_toolbars_model_save_toolbars  (EggToolbarsModel *model,
+                                                    const char *xml_file,
+                                                    const char *version);
+
+/* Functions for manipulating the types of portable data this toolbar understands. */
+GList *           egg_toolbars_model_get_types      (EggToolbarsModel *model);
+void              egg_toolbars_model_set_types      (EggToolbarsModel *model,
+                                                     GList            *types);
+
+/* Functions for converting between name and portable data. */
+char *            egg_toolbars_model_get_name       (EggToolbarsModel *model,
+                                                     GdkAtom           type,
+                                                     const char       *data,
+                                                     gboolean          create);
+char *            egg_toolbars_model_get_data       (EggToolbarsModel *model,
+                                                     GdkAtom           type,
+                                                     const char       *name);
+
+/* Functions for retrieving what items are available for adding to the toolbars. */
+GPtrArray *       egg_toolbars_model_get_name_avail (EggToolbarsModel *model);
+gint              egg_toolbars_model_get_name_flags (EggToolbarsModel *model,
+                                                    const char *name);
+void              egg_toolbars_model_set_name_flags (EggToolbarsModel *model,
+                                                    const char *name,
+                                                    gint flags);
+
+/* Functions for manipulating flags on individual toolbars. */
+EggTbModelFlags   egg_toolbars_model_get_flags      (EggToolbarsModel *model,
+                                                    int               toolbar_position);
+void              egg_toolbars_model_set_flags      (EggToolbarsModel *model,
+                                                    int               toolbar_position,
+                                                    EggTbModelFlags   flags);
+
+/* Functions for adding and removing toolbars. */
+int               egg_toolbars_model_add_toolbar    (EggToolbarsModel *model,
+                                                    int               position,
+                                                    const char       *name);
+void             egg_toolbars_model_remove_toolbar (EggToolbarsModel *model,
+                                                    int               position);
+
+/* Functions for adding, removing and moving items. */
+gboolean         egg_toolbars_model_add_item       (EggToolbarsModel *model,
+                                                    int               toolbar_position,
+                                                    int               position,
+                                                    const char       *name);
+void             egg_toolbars_model_remove_item    (EggToolbarsModel *model,
+                                                    int               toolbar_position,
+                                                    int               position);
+void             egg_toolbars_model_move_item      (EggToolbarsModel *model,
+                                                    int               toolbar_position,
+                                                    int               position,
+                                                    int               new_toolbar_position,
+                                                    int               new_position);
+void             egg_toolbars_model_delete_item    (EggToolbarsModel *model,
+                                                    const char       *name);
+
+/* Functions for accessing the names of items. */
+int              egg_toolbars_model_n_items        (EggToolbarsModel *model,
+                                                    int               toolbar_position);
+const char *      egg_toolbars_model_item_nth      (EggToolbarsModel *model,
+                                                    int               toolbar_position,
+                                                    int               position);
+
+/* Functions for accessing the names of toolbars. */
+int              egg_toolbars_model_n_toolbars     (EggToolbarsModel *model);
+const char      *egg_toolbars_model_toolbar_nth    (EggToolbarsModel *model,
+                                                    int               position);
+
+G_END_DECLS
+
+#endif
diff --git a/cut-n-paste/toolbar-editor/eggmarshalers.list b/cut-n-paste/toolbar-editor/eggmarshalers.list
new file mode 100644
index 0000000..1f953dd
--- /dev/null
+++ b/cut-n-paste/toolbar-editor/eggmarshalers.list
@@ -0,0 +1 @@
+VOID:INT,INT
diff --git a/cut-n-paste/toolbar-editor/update-toolbareditor-from-libegg.sh 
b/cut-n-paste/toolbar-editor/update-toolbareditor-from-libegg.sh
new file mode 100755
index 0000000..33d60c5
--- /dev/null
+++ b/cut-n-paste/toolbar-editor/update-toolbareditor-from-libegg.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# update-toolbareditor-from-libegg.sh
+#
+# Get latest toolbar editor from libegg
+# Developers using the toolbar editor in their projects can use this script to
+# fetch the latest toolbar editor from libegg. Just run this script
+#
+
+SCRIPT_NAME=update-toolbareditor-from-libegg.sh
+SVN_URI=http://svn.gnome.org/svn/libegg/trunk/libegg/toolbareditor
+FILES="egg-editable-toolbar.c \
+       egg-toolbars-model.c \
+       egg-toolbar-editor.c \
+       egg-editable-toolbar.h \
+       egg-toolbars-model.h \
+       egg-toolbar-editor.h \
+       eggmarshalers.list"
+
+
+if [ -z $1 ]; then
+  echo "Obtaining latest version of "$SCRIPT_NAME
+  svn export $SVN_URI/$SCRIPT_NAME
+  ./$SCRIPT_NAME --update-sources
+fi
+if  [ "$1"  = "--update-sources" ]; then
+
+  echo "Obtaining latest version of the sources"
+  for FILE in $FILES
+  do
+    svn export $SVN_URI/$FILE
+  done
+fi
+
diff --git a/data/Makefile.am b/data/Makefile.am
index 06599aa..5390299 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -23,10 +23,15 @@ gsettings_SCHEMAS = org.gnome.eog.gschema.xml
 gsettingsconvertdir = $(datadir)/GConf/gsettings
 gsettingsconvert_DATA = eog.convert
 
+uidir = $(pkgdatadir)
+ui_DATA = \
+       eog-toolbar.xml
+
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = eog.pc
 
 EXTRA_DIST =                   \
+       $(ui_DATA)              \
        eog.css                 \
        eog-app-menu.xml        \
        eog-image-properties-dialog.ui  \
diff --git a/data/eog-app-menu.xml b/data/eog-app-menu.xml
index cb72804..2edd74e 100644
--- a/data/eog-app-menu.xml
+++ b/data/eog-app-menu.xml
@@ -5,6 +5,10 @@
         <attribute name="label" translatable="yes">_View</attribute>
         <link name="submenu">
           <item>
+            <attribute name="action">app.toolbar</attribute>
+            <attribute name="label" translatable="yes">_Toolbar</attribute>
+          </item>
+          <item>
             <attribute name="action">app.view-statusbar</attribute>
             <attribute name="label" translatable="yes">_Statusbar</attribute>
           </item>
diff --git a/data/eog-toolbar.xml b/data/eog-toolbar.xml
new file mode 100644
index 0000000..cb51eaa
--- /dev/null
+++ b/data/eog-toolbar.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<toolbars version="1.0">
+<available>
+    <toolitem name="ImageOpen"/>
+    <toolitem name="ImageSave"/>
+    <toolitem name="ImageOpenContainingFolder"/>
+    <toolitem name="ImagePrint"/>
+    <toolitem name="ImageProperties"/>
+    <toolitem name="ViewImageGallery"/>
+    <toolitem name="ViewFullscreen"/>
+    <toolitem name="ViewSlideshow"/>
+    <toolitem name="ViewZoomIn"/>
+    <toolitem name="ViewZoomOut"/>
+    <toolitem name="ViewZoomNormal"/>
+    <toolitem name="ViewZoomFit"/>
+    <toolitem name="EditRotate270"/>
+    <toolitem name="EditRotate90"/>
+    <toolitem name="GoFirst"/>
+    <toolitem name="GoLast"/>
+    <toolitem name="GoPrevious"/>
+    <toolitem name="GoNext"/>
+    <toolitem name="EditMoveToTrash"/>
+    <toolitem name="EditDelete"/>
+</available>
+<toolbar name="Toolbar">
+    <toolitem name="GoPrevious"/>
+    <toolitem name="GoNext"/>
+    <separator/>
+    <toolitem name="ViewZoomIn"/>
+    <toolitem name="ViewZoomOut"/>
+    <toolitem name="ViewZoomNormal"/>
+    <toolitem name="ViewZoomFit"/>
+    <separator/>
+    <toolitem name="EditRotate270"/>
+    <toolitem name="EditRotate90"/>
+ </toolbar>
+</toolbars>
diff --git a/data/eog-ui.xml b/data/eog-ui.xml
index c20cb9e..e741785 100644
--- a/data/eog-ui.xml
+++ b/data/eog-ui.xml
@@ -34,9 +34,11 @@
       <menuitem action="EditMoveToTrash"/>
       <menuitem action="EditDelete"/>
       <separator/>
+      <menuitem action="EditToolbar"/>
       <menuitem action="EditPreferences"/>
     </menu>
     <menu action="View">
+      <menuitem name="ToolbarToggle" action="ViewToolbar"/>
       <menuitem name="StatusbarToggle" action="ViewStatusbar"/>
       <menuitem name="ImageGalleryToggle" action="ViewImageGallery"/>
       <menuitem name="SidebarToggle" action="ViewSidebar"/>
diff --git a/data/eog.convert b/data/eog.convert
index c0f2f7b..675ede9 100644
--- a/data/eog.convert
+++ b/data/eog.convert
@@ -16,6 +16,7 @@ propsdialog-netbook-mode=/apps/eog/ui/propsdialog_netbook_mode
 scroll-buttons=/apps/eog/ui/scroll_buttons
 sidebar=/apps/eog/ui/sidebar
 statusbar=/apps/eog/ui/statusbar
+toolbar=/apps/eog/ui/toolbar
 
 [org.gnome.eog.view]
 autorotate=/apps/eog/view/autorotate
diff --git a/data/org.gnome.eog.gschema.xml.in b/data/org.gnome.eog.gschema.xml.in
index b779f49..f7b96bd 100644
--- a/data/org.gnome.eog.gschema.xml.in
+++ b/data/org.gnome.eog.gschema.xml.in
@@ -70,6 +70,10 @@
     </key>
   </schema>
   <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.eog.ui" path="/org/gnome/eog/ui/">
+    <key name="toolbar" type="b">
+      <default>true</default>
+      <summary>Show/Hide the window toolbar.</summary>
+    </key>
     <key name="statusbar" type="b">
       <default>true</default>
       <summary>Show/Hide the window statusbar.</summary>
@@ -116,7 +120,7 @@
     <key name="external-editor" type="s">
       <default>''</default>
       <summary>External program to use for editing images</summary>
-      <description>The desktop file name (including the ".desktop") of the application to use for editing 
images (when the "Edit Image" button is clicked). Set to the empty string to disable this 
feature.</description>
+      <description>The desktop file name (including the ".desktop") of the application to use for editing 
images (when the "Edit Image" toolbar button is clicked). Set to the empty string to disable this 
feature.</description>
     </key>
   </schema>
   <schema id="org.gnome.eog.plugins" path="/org/gnome/eog/plugins/">
diff --git a/doc/reference/Makefile.am b/doc/reference/Makefile.am
index e97a65a..09bf37e 100644
--- a/doc/reference/Makefile.am
+++ b/doc/reference/Makefile.am
@@ -107,6 +107,7 @@ GTKDOC_CFLAGS= \
        -I$(top_srcdir)/src     \
        -I$(top_srcdir)/plugins \
        -I$(top_srcdir)/jpegutils                               \
+       -I$(top_srcdir)/cut-n-paste/toolbar-editor              \
        $(EOG_CFLAGS)
 
 if ENABLE_JPEG
@@ -115,6 +116,7 @@ endif
 
 GTKDOC_LIBS=\
        $(top_builddir)/src/libeog.la   \
+       $(top_builddir)/cut-n-paste/toolbar-editor/libtoolbareditor.la \
        $(BINDING_LIBS)                 \
        $(LIBJPEG)                      \
        $(X_LIBS)                       \
diff --git a/doc/reference/eog-sections.txt b/doc/reference/eog-sections.txt
index 538c3f1..9ee94ad 100644
--- a/doc/reference/eog-sections.txt
+++ b/doc/reference/eog-sections.txt
@@ -381,6 +381,9 @@ eog_application_open_uri_list
 eog_application_open_file_list
 eog_application_open_uris
 eog_application_get_windows
+eog_application_get_toolbars_model
+eog_application_save_toolbars_model
+eog_application_reset_toolbars_model
 eog_application_screensaver_enable
 eog_application_screensaver_disable
 <SUBSECTION Standard>
@@ -656,6 +659,7 @@ EOG_CONF_VIEW_USE_BG_COLOR
 EOG_CONF_FULLSCREEN_LOOP
 EOG_CONF_FULLSCREEN_UPSCALE
 EOG_CONF_FULLSCREEN_SECONDS
+EOG_CONF_UI_TOOLBAR
 EOG_CONF_UI_STATUSBAR
 EOG_CONF_UI_SIDEBAR
 EOG_CONF_UI_SCROLL_BUTTONS
diff --git a/tests/actions.feature b/tests/actions.feature
index bb79c2a..33847cc 100644
--- a/tests/actions.feature
+++ b/tests/actions.feature
@@ -9,6 +9,15 @@ Feature: Smoke tests
     Then Website link to wiki is displayed
      And GPL 2.0 link is displayed
 
+  @undo @undo_via_toolbar
+  Scenario: Undo via toolbar
+    * Open "/tmp/gnome-logo.png" via menu
+    Then image size is 199x76
+    * Rotate the image clockwise
+    Then image size is 76x199
+    * Select "Edit -> Undo" menu
+    Then image size is 199x76
+
   @undo @undo_via_shortcut
   Scenario: Undo via shortcut
     * Open "/tmp/gnome-logo.png" via menu


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