[eog] Revert "Remove all other references to the toolbar"
- From: Felix Riemann <friemann src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [eog] Revert "Remove all other references to the toolbar"
- Date: Wed, 17 Dec 2014 20:42:45 +0000 (UTC)
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]