2 * Copyright (C) 2003, 2004 Marco Pesenti Gritti
3 * Copyright (C) 2003, 2004, 2005 Christian Persch
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "egg-editable-toolbar.h"
25 #include "egg-toolbars-model.h"
26 #include "egg-toolbar-editor.h"
28 #include <gtk/gtkvseparator.h>
29 #include <gtk/gtkiconfactory.h>
30 #include <gtk/gtkwindow.h>
31 #include <gtk/gtkmain.h>
32 #include <gtk/gtkdnd.h>
33 #include <gtk/gtkhbox.h>
34 #include <gtk/gtkimage.h>
35 #include <gtk/gtkimagemenuitem.h>
36 #include <gtk/gtkmenu.h>
37 #include <gtk/gtkstock.h>
38 #include <gtk/gtktoolbar.h>
39 #include <gtk/gtktoolitem.h>
40 #include <gtk/gtkseparatortoolitem.h>
41 #include <glib/gi18n.h>
44 static void egg_editable_toolbar_class_init (EggEditableToolbarClass *klass);
45 static void egg_editable_toolbar_init (EggEditableToolbar *t);
46 static void egg_editable_toolbar_finalize (GObject *object);
48 #define MIN_TOOLBAR_HEIGHT 20
50 static const GtkTargetEntry dest_drag_types[] = {
51 {EGG_TOOLBAR_ITEM_TYPE, GTK_TARGET_SAME_APP, 0},
67 static guint egg_editable_toolbar_signals[LAST_SIGNAL] = { 0 };
69 static GObjectClass *parent_class = NULL;
71 #define EGG_EDITABLE_TOOLBAR_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EGG_TYPE_EDITABLE_TOOLBAR, EggEditableToolbarPrivate))
73 struct _EggEditableToolbarPrivate
75 GtkUIManager *manager;
76 EggToolbarsModel *model;
78 GtkWidget *selected_toolbar;
79 GtkWidget *fixed_toolbar;
82 GtkToolbar *target_toolbar;
83 GtkWidget *dragged_item;
87 egg_editable_toolbar_get_type (void)
89 static GType type = 0;
91 if (G_UNLIKELY (type == 0))
93 static const GTypeInfo our_info = {
94 sizeof (EggEditableToolbarClass),
96 NULL, /* base_finalize */
97 (GClassInitFunc) egg_editable_toolbar_class_init,
99 NULL, /* class_data */
100 sizeof (EggEditableToolbar),
102 (GInstanceInitFunc) egg_editable_toolbar_init
105 type = g_type_register_static (GTK_TYPE_VBOX,
106 "EggEditableToolbar",
114 get_toolbar_position (EggEditableToolbar *etoolbar, GtkWidget *toolbar)
119 l = gtk_container_get_children (GTK_CONTAINER (etoolbar));
120 result = g_list_index (l, toolbar->parent);
127 get_n_toolbars (EggEditableToolbar *etoolbar)
132 l = gtk_container_get_children (GTK_CONTAINER (etoolbar));
133 result = g_list_length (l);
140 get_dock_nth (EggEditableToolbar *etoolbar,
146 l = gtk_container_get_children (GTK_CONTAINER (etoolbar));
147 result = g_list_nth_data (l, position);
154 get_toolbar_nth (EggEditableToolbar *etoolbar,
161 dock = get_dock_nth (etoolbar, position);
163 l = gtk_container_get_children (GTK_CONTAINER (dock));
164 result = GTK_WIDGET (l->data);
171 find_action (EggEditableToolbar *t,
175 GtkAction *action = NULL;
177 l = gtk_ui_manager_get_action_groups (t->priv->manager);
179 g_return_val_if_fail (name != NULL, NULL);
181 for (; l != NULL; l = l->next)
185 tmp = gtk_action_group_get_action (GTK_ACTION_GROUP (l->data), name);
194 drag_data_delete_cb (GtkWidget *widget,
195 GdkDragContext *context,
196 EggEditableToolbar *etoolbar)
198 int pos, toolbar_pos;
200 g_return_if_fail (EGG_IS_EDITABLE_TOOLBAR (etoolbar));
202 pos = gtk_toolbar_get_item_index (GTK_TOOLBAR (widget->parent),
203 GTK_TOOL_ITEM (widget));
204 toolbar_pos = get_toolbar_position (etoolbar, widget->parent);
206 egg_toolbars_model_remove_item (etoolbar->priv->model,
211 drag_begin_cb (GtkWidget *widget,
212 GdkDragContext *context,
213 EggEditableToolbar *etoolbar)
215 gtk_widget_hide (widget);
219 drag_end_cb (GtkWidget *widget,
220 GdkDragContext *context,
221 EggEditableToolbar *etoolbar)
223 gtk_widget_show (widget);
227 drag_data_get_cb (GtkWidget *widget,
228 GdkDragContext *context,
229 GtkSelectionData *selection_data,
232 EggEditableToolbar *etoolbar)
234 const char *id, *type;
237 g_return_if_fail (EGG_IS_EDITABLE_TOOLBAR (etoolbar));
239 type = g_object_get_data (G_OBJECT (widget), "type");
240 id = g_object_get_data (G_OBJECT (widget), "id");
241 if (strcmp (id, "separator") == 0)
243 target = g_strdup (id);
247 target = egg_toolbars_model_get_item_data (etoolbar->priv->model,
251 gtk_selection_data_set (selection_data,
252 selection_data->target, 8,
253 (const guchar *)target, strlen (target));
259 set_drag_cursor (GtkWidget *widget)
266 pixbuf = gdk_pixbuf_new_from_file (CURSOR_DIR "/hand-open.png", NULL);
267 cursor = gdk_cursor_new_from_pixbuf (gdk_display_get_default (),
269 gdk_window_set_cursor (widget->window, cursor);
270 gdk_cursor_unref (cursor);
271 g_object_unref (pixbuf);
276 unset_drag_cursor (GtkWidget *widget)
280 gdk_window_set_cursor (widget->window, NULL);
285 set_item_drag_source (EggToolbarsModel *model,
288 gboolean is_separator,
291 GtkTargetEntry target_entry;
294 target_entry.target = (char *)type;
295 target_entry.flags = GTK_TARGET_SAME_APP;
296 target_entry.info = 0;
298 gtk_drag_source_set (item, GDK_BUTTON1_MASK,
309 icon = _egg_editable_toolbar_new_separator_image ();
310 pixbuf = gtk_image_get_pixbuf (GTK_IMAGE (icon));
311 gtk_drag_source_set_icon_pixbuf (item, pixbuf);
315 const char *stock_id;
316 GValue value = { 0, };
319 id = gtk_action_get_name (action);
321 g_value_init (&value, G_TYPE_STRING);
322 g_object_get_property (G_OBJECT (action), "stock_id", &value);
323 stock_id = g_value_get_string (&value);
325 if (stock_id != NULL)
327 pixbuf = gtk_widget_render_icon (item, stock_id,
328 GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
332 pixbuf = gtk_widget_render_icon (item, GTK_STOCK_DND,
333 GTK_ICON_SIZE_LARGE_TOOLBAR, NULL);
336 gtk_drag_source_set_icon_pixbuf (item, pixbuf);
337 g_object_unref (pixbuf);
339 g_value_unset (&value);
342 g_object_set_data_full (G_OBJECT (item), "id",
343 g_strdup (id), g_free);
344 g_object_set_data_full (G_OBJECT (item), "type",
345 g_strdup (type), g_free);
349 create_item_from_action (EggEditableToolbar *t,
350 const char *action_name,
352 gboolean is_separator,
353 GtkAction **ret_action)
360 item = GTK_WIDGET (gtk_separator_tool_item_new ());
365 g_return_val_if_fail (action_name != NULL, NULL);
367 g_signal_emit (G_OBJECT (t), egg_editable_toolbar_signals[ACTION_REQUEST],
370 action = find_action (t, action_name);
373 item = gtk_action_create_tool_item (action);
381 gtk_widget_show (item);
383 g_signal_connect (item, "drag_begin",
384 G_CALLBACK (drag_begin_cb), t);
385 g_signal_connect (item, "drag_end",
386 G_CALLBACK (drag_end_cb), t);
387 g_signal_connect (item, "drag_data_get",
388 G_CALLBACK (drag_data_get_cb), t);
389 g_signal_connect (item, "drag_data_delete",
390 G_CALLBACK (drag_data_delete_cb), t);
392 if (t->priv->edit_mode)
394 set_drag_cursor (item);
395 gtk_widget_set_sensitive (item, TRUE);
396 set_item_drag_source (t->priv->model, item, action,
398 gtk_tool_item_set_use_drag_window (GTK_TOOL_ITEM (item), TRUE);
403 *ret_action = action;
410 create_item (EggEditableToolbar *t,
411 EggToolbarsModel *model,
412 int toolbar_position,
414 GtkAction **ret_action)
416 const char *action_name, *type;
417 gboolean is_separator;
419 egg_toolbars_model_item_nth (model, toolbar_position, position,
420 &is_separator, &action_name, &type);
421 return create_item_from_action (t, action_name, type,
422 is_separator, ret_action);
426 data_is_separator (const char *data)
428 return strcmp (data, "separator") == 0;
432 drag_data_received_cb (GtkWidget *widget,
433 GdkDragContext *context,
436 GtkSelectionData *selection_data,
439 EggEditableToolbar *etoolbar)
446 target = gtk_drag_dest_find_target (widget, context, NULL);
447 type = egg_toolbars_model_get_item_type (etoolbar->priv->model, target);
448 id = egg_toolbars_model_get_item_id (etoolbar->priv->model, type,
449 (const char*)selection_data->data);
451 /* This function can be called for two reasons
453 * (1) drag_motion() needs an item to pass to
454 * gtk_toolbar_set_drop_highlight_item(). We can
455 * recognize this case by etoolbar->priv->pending being TRUE
456 * We should just create an item and return.
458 * (2) The drag has finished, and drag_drop() wants us to
459 * actually add a new item to the toolbar.
464 etoolbar->priv->pending = FALSE;
469 if (etoolbar->priv->pending)
471 etoolbar->priv->pending = FALSE;
472 etoolbar->priv->dragged_item =
473 create_item_from_action (etoolbar, id, type,
474 data_is_separator (id), NULL);
475 g_object_ref (etoolbar->priv->dragged_item);
476 gtk_object_sink (GTK_OBJECT (etoolbar->priv->dragged_item));
480 int pos, toolbar_pos;
482 pos = gtk_toolbar_get_drop_index (GTK_TOOLBAR (widget), x, y);
483 toolbar_pos = get_toolbar_position (etoolbar, widget);
485 if (data_is_separator ((const char*)selection_data->data))
487 egg_toolbars_model_add_separator (etoolbar->priv->model,
492 egg_toolbars_model_add_item (etoolbar->priv->model,
493 toolbar_pos, pos, id, type);
496 gtk_drag_finish (context, TRUE, context->action == GDK_ACTION_MOVE,
505 remove_toolbar_cb (GtkWidget *menuitem,
506 EggEditableToolbar *etoolbar)
510 pos = get_toolbar_position (etoolbar, etoolbar->priv->selected_toolbar);
511 egg_toolbars_model_remove_toolbar (etoolbar->priv->model, pos);
515 popup_toolbar_context_menu_cb (GtkWidget *toolbar,
519 EggEditableToolbar *t)
525 if (t->priv->edit_mode)
527 EggTbModelFlags flags;
530 t->priv->selected_toolbar = toolbar;
532 menu = gtk_menu_new ();
534 item = gtk_image_menu_item_new_with_mnemonic (_("_Remove Toolbar"));
535 gtk_widget_show (item);
536 image = gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU);
537 gtk_widget_show (image);
538 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
539 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
540 g_signal_connect (item, "activate",
541 G_CALLBACK (remove_toolbar_cb),
544 position = get_toolbar_position (t, toolbar);
545 flags = egg_toolbars_model_get_flags (t->priv->model, position);
546 if (flags & EGG_TB_MODEL_NOT_REMOVABLE)
548 gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE);
551 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 2,
552 gtk_get_current_event_time ());
557 free_dragged_item (EggEditableToolbar *etoolbar)
559 if (etoolbar->priv->dragged_item)
561 gtk_widget_destroy (etoolbar->priv->dragged_item);
562 g_object_unref (etoolbar->priv->dragged_item);
563 etoolbar->priv->dragged_item = NULL;
568 toolbar_drag_drop_cb (GtkWidget *widget,
569 GdkDragContext *context,
573 EggEditableToolbar *etoolbar)
577 target = gtk_drag_dest_find_target (widget, context, NULL);
578 if (target != GDK_NONE)
580 gtk_drag_get_data (widget, context,
586 free_dragged_item (etoolbar);
592 toolbar_drag_motion_cb (GtkWidget *widget,
593 GdkDragContext *context,
597 EggEditableToolbar *etoolbar)
601 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
605 source = gtk_drag_get_source_widget (context);
608 EggTbModelFlags flags;
612 pos = get_toolbar_position (etoolbar, widget);
613 flags = egg_toolbars_model_get_flags (etoolbar->priv->model, pos);
615 is_item = etoolbar->priv->edit_mode &&
616 (gtk_widget_get_ancestor (source, EGG_TYPE_EDITABLE_TOOLBAR) ||
617 gtk_widget_get_ancestor (source, EGG_TYPE_TOOLBAR_EDITOR));
619 if ((flags & EGG_TB_MODEL_ACCEPT_ITEMS_ONLY) && !is_item)
621 gdk_drag_status (context, 0, time);
625 if (gtk_widget_is_ancestor (source, widget))
627 context->suggested_action = GDK_ACTION_MOVE;
631 target = gtk_drag_dest_find_target (widget, context, NULL);
632 if (target == GDK_NONE)
634 gdk_drag_status (context, 0, time);
638 if (etoolbar->priv->target_toolbar != toolbar)
640 if (etoolbar->priv->target_toolbar)
641 gtk_toolbar_set_drop_highlight_item
642 (etoolbar->priv->target_toolbar, NULL, 0);
644 free_dragged_item (etoolbar);
645 etoolbar->priv->pending = TRUE;
647 etoolbar->priv->target_toolbar = toolbar;
649 gtk_drag_get_data (widget, context, target, time);
652 if (etoolbar->priv->dragged_item != NULL &&
653 etoolbar->priv->edit_mode)
655 item = GTK_TOOL_ITEM (etoolbar->priv->dragged_item);
657 index = gtk_toolbar_get_drop_index (toolbar, x, y);
658 gtk_toolbar_set_drop_highlight_item (toolbar, item, index);
661 gdk_drag_status (context, context->suggested_action, time);
667 toolbar_drag_leave_cb (GtkToolbar *toolbar,
668 GdkDragContext *context,
670 EggEditableToolbar *etoolbar)
672 /* This is a workaround for bug 125557. Sometimes
673 * we seemingly enter another toolbar *before* leaving
676 * In that case etoolbar->priv->target_toolbar will
677 * have been set to something else and the highlighting
678 * will already have been turned off
681 if (etoolbar->priv->target_toolbar == toolbar)
683 gtk_toolbar_set_drop_highlight_item (toolbar, NULL, 0);
685 etoolbar->priv->target_toolbar = NULL;
686 free_dragged_item (etoolbar);
691 create_dock (EggEditableToolbar *t)
693 GtkWidget *toolbar, *hbox;
695 hbox = gtk_hbox_new (0, FALSE);
696 gtk_widget_show (hbox);
698 toolbar = gtk_toolbar_new ();
699 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), TRUE);
700 gtk_widget_show (toolbar);
701 gtk_box_pack_start (GTK_BOX (hbox), toolbar, TRUE, TRUE, 0);
703 gtk_drag_dest_set (toolbar, 0,
704 dest_drag_types, G_N_ELEMENTS (dest_drag_types),
705 GDK_ACTION_MOVE | GDK_ACTION_COPY);
707 g_signal_connect (toolbar, "drag_drop",
708 G_CALLBACK (toolbar_drag_drop_cb), t);
709 g_signal_connect (toolbar, "drag_motion",
710 G_CALLBACK (toolbar_drag_motion_cb), t);
711 g_signal_connect (toolbar, "drag_leave",
712 G_CALLBACK (toolbar_drag_leave_cb), t);
714 g_signal_connect (toolbar, "drag_data_received",
715 G_CALLBACK (drag_data_received_cb), t);
716 g_signal_connect (toolbar, "popup_context_menu",
717 G_CALLBACK (popup_toolbar_context_menu_cb), t);
723 set_fixed_style (EggEditableToolbar *t, GtkToolbarStyle style)
725 g_return_if_fail (GTK_IS_TOOLBAR (t->priv->fixed_toolbar));
726 gtk_toolbar_set_style (GTK_TOOLBAR (t->priv->fixed_toolbar),
727 style == GTK_TOOLBAR_ICONS ? GTK_TOOLBAR_BOTH_HORIZ : style);
731 unset_fixed_style (EggEditableToolbar *t)
733 g_return_if_fail (GTK_IS_TOOLBAR (t->priv->fixed_toolbar));
734 gtk_toolbar_unset_style (GTK_TOOLBAR (t->priv->fixed_toolbar));
738 toolbar_changed_cb (EggToolbarsModel *model,
740 EggEditableToolbar *t)
743 EggTbModelFlags flags;
744 GtkToolbarStyle style;
746 flags = egg_toolbars_model_get_flags (model, position);
747 toolbar = get_toolbar_nth (t, position);
749 if (flags & EGG_TB_MODEL_ICONS)
751 style = GTK_TOOLBAR_ICONS;
753 else if (flags & EGG_TB_MODEL_TEXT)
755 style = GTK_TOOLBAR_TEXT;
757 else if (flags & EGG_TB_MODEL_BOTH)
759 style = GTK_TOOLBAR_BOTH;
761 else if (flags & EGG_TB_MODEL_BOTH_HORIZ)
763 style = GTK_TOOLBAR_BOTH_HORIZ;
767 gtk_toolbar_unset_style (GTK_TOOLBAR (toolbar));
768 if (position == 0 && t->priv->fixed_toolbar)
770 unset_fixed_style (t);
775 gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), style);
776 if (position == 0 && t->priv->fixed_toolbar)
778 set_fixed_style (t, style);
783 unparent_fixed (EggEditableToolbar *t)
785 GtkWidget *toolbar, *dock;
786 g_return_if_fail (GTK_IS_TOOLBAR (t->priv->fixed_toolbar));
788 toolbar = t->priv->fixed_toolbar;
789 dock = get_dock_nth (t, 0);
791 if (dock && toolbar->parent != NULL)
793 gtk_container_remove (GTK_CONTAINER (dock), toolbar);
798 update_fixed (EggEditableToolbar *t)
800 GtkWidget *toolbar, *dock;
801 if (!t->priv->fixed_toolbar) return;
803 toolbar = t->priv->fixed_toolbar;
804 dock = get_dock_nth (t, 0);
806 if (dock && toolbar && toolbar->parent == NULL)
808 gtk_box_pack_end (GTK_BOX (dock), toolbar, FALSE, TRUE, 0);
810 gtk_widget_show (toolbar);
812 gtk_widget_set_size_request (dock, -1, -1);
813 gtk_widget_queue_resize_no_redraw (dock);
818 toolbar_added_cb (EggToolbarsModel *model,
820 EggEditableToolbar *t)
824 dock = create_dock (t);
826 gtk_widget_set_size_request (dock, -1, MIN_TOOLBAR_HEIGHT);
828 gtk_box_pack_start (GTK_BOX (t), dock, TRUE, TRUE, 0);
830 gtk_box_reorder_child (GTK_BOX (t), dock, position);
832 gtk_widget_show_all (dock);
838 toolbar_removed_cb (EggToolbarsModel *model,
840 EggEditableToolbar *t)
844 if (position == 0 && t->priv->fixed_toolbar != NULL)
849 toolbar = get_dock_nth (t, position);
850 gtk_widget_destroy (toolbar);
856 item_added_cb (EggToolbarsModel *model,
857 int toolbar_position,
859 EggEditableToolbar *t)
866 toolbar = get_toolbar_nth (t, toolbar_position);
867 item = create_item (t, model, toolbar_position, position, &action);
868 gtk_toolbar_insert (GTK_TOOLBAR (toolbar),
869 GTK_TOOL_ITEM (item), position);
871 dock = get_dock_nth (t, toolbar_position);
872 gtk_widget_set_size_request (dock, -1, -1);
873 gtk_widget_queue_resize_no_redraw (dock);
875 /* FIXME Hack to make tooltip work from gtk */
878 g_object_notify (G_OBJECT (action), "tooltip");
883 item_removed_cb (EggToolbarsModel *model,
884 int toolbar_position,
886 EggEditableToolbar *t)
891 toolbar = get_toolbar_nth (t, toolbar_position);
892 item = GTK_WIDGET (gtk_toolbar_get_nth_item
893 (GTK_TOOLBAR (toolbar), position));
894 g_return_if_fail (item != NULL);
895 gtk_container_remove (GTK_CONTAINER (toolbar), item);
897 if (egg_toolbars_model_n_items (model, toolbar_position) == 0)
899 egg_toolbars_model_remove_toolbar (model, toolbar_position);
904 egg_editable_toolbar_construct (EggEditableToolbar *t)
906 int i, l, n_items, n_toolbars;
907 EggToolbarsModel *model = t->priv->model;
909 g_return_if_fail (model != NULL);
910 g_return_if_fail (t->priv->manager != NULL);
912 n_toolbars = egg_toolbars_model_n_toolbars (model);
914 for (i = 0; i < n_toolbars; i++)
916 GtkWidget *toolbar, *dock;
918 dock = create_dock (t);
919 gtk_box_pack_start (GTK_BOX (t), dock, TRUE, TRUE, 0);
920 toolbar = get_toolbar_nth (t, i);
922 n_items = egg_toolbars_model_n_items (model, i);
923 for (l = 0; l < n_items; l++)
928 item = create_item (t, model, i, l, &action);
931 gtk_toolbar_insert (GTK_TOOLBAR (toolbar),
932 GTK_TOOL_ITEM (item), l);
933 /* FIXME Hack to make tooltip work from gtk */
936 g_object_notify (G_OBJECT (action), "tooltip");
941 egg_toolbars_model_remove_item (model, i, l);
949 gtk_widget_set_size_request (dock, -1, MIN_TOOLBAR_HEIGHT);
956 for (i = 0; i < n_toolbars; i ++)
958 toolbar_changed_cb (model, i, t);
963 egg_editable_toolbar_disconnect_model (EggEditableToolbar *toolbar)
965 EggToolbarsModel *model = toolbar->priv->model;
967 g_signal_handlers_disconnect_by_func
968 (model, G_CALLBACK (item_added_cb), toolbar);
969 g_signal_handlers_disconnect_by_func
970 (model, G_CALLBACK (item_removed_cb), toolbar);
971 g_signal_handlers_disconnect_by_func
972 (model, G_CALLBACK (toolbar_added_cb), toolbar);
973 g_signal_handlers_disconnect_by_func
974 (model, G_CALLBACK (toolbar_removed_cb), toolbar);
975 g_signal_handlers_disconnect_by_func
976 (model, G_CALLBACK (toolbar_changed_cb), toolbar);
980 egg_editable_toolbar_deconstruct (EggEditableToolbar *toolbar)
982 EggToolbarsModel *model = toolbar->priv->model;
985 g_return_if_fail (model != NULL);
987 if (toolbar->priv->fixed_toolbar)
989 unset_fixed_style (toolbar);
990 unparent_fixed (toolbar);
993 children = gtk_container_get_children (GTK_CONTAINER (toolbar));
994 g_list_foreach (children, (GFunc) gtk_widget_destroy, NULL);
995 g_list_free (children);
999 egg_editable_toolbar_set_model (EggEditableToolbar *toolbar,
1000 EggToolbarsModel *model)
1002 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (model));
1003 g_return_if_fail (EGG_IS_EDITABLE_TOOLBAR (toolbar));
1004 g_return_if_fail (toolbar->priv->manager);
1006 if (toolbar->priv->model == model) return;
1008 if (toolbar->priv->model)
1010 egg_editable_toolbar_disconnect_model (toolbar);
1011 egg_editable_toolbar_deconstruct (toolbar);
1013 g_object_unref (toolbar->priv->model);
1016 toolbar->priv->model = g_object_ref (model);
1018 egg_editable_toolbar_construct (toolbar);
1020 g_signal_connect (model, "item_added",
1021 G_CALLBACK (item_added_cb), toolbar);
1022 g_signal_connect (model, "item_removed",
1023 G_CALLBACK (item_removed_cb), toolbar);
1024 g_signal_connect (model, "toolbar_added",
1025 G_CALLBACK (toolbar_added_cb), toolbar);
1026 g_signal_connect (model, "toolbar_removed",
1027 G_CALLBACK (toolbar_removed_cb), toolbar);
1028 g_signal_connect (model, "toolbar_changed",
1029 G_CALLBACK (toolbar_changed_cb), toolbar);
1033 egg_editable_toolbar_set_ui_manager (EggEditableToolbar *t,
1034 GtkUIManager *manager)
1036 g_return_if_fail (GTK_IS_UI_MANAGER (manager));
1038 t->priv->manager = g_object_ref (manager);
1042 egg_editable_toolbar_set_property (GObject *object,
1044 const GValue *value,
1047 EggEditableToolbar *t = EGG_EDITABLE_TOOLBAR (object);
1051 case PROP_UI_MANAGER:
1052 egg_editable_toolbar_set_ui_manager (t, g_value_get_object (value));
1054 case PROP_TOOLBARS_MODEL:
1055 egg_editable_toolbar_set_model (t, g_value_get_object (value));
1058 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1064 egg_editable_toolbar_get_property (GObject *object,
1069 EggEditableToolbar *t = EGG_EDITABLE_TOOLBAR (object);
1073 case PROP_UI_MANAGER:
1074 g_value_set_object (value, t->priv->manager);
1076 case PROP_TOOLBARS_MODEL:
1077 g_value_set_object (value, t->priv->model);
1080 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1086 egg_editable_toolbar_class_init (EggEditableToolbarClass *klass)
1088 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1090 parent_class = g_type_class_peek_parent (klass);
1092 object_class->finalize = egg_editable_toolbar_finalize;
1093 object_class->set_property = egg_editable_toolbar_set_property;
1094 object_class->get_property = egg_editable_toolbar_get_property;
1096 egg_editable_toolbar_signals[ACTION_REQUEST] =
1097 g_signal_new ("action_request",
1098 G_OBJECT_CLASS_TYPE (object_class),
1100 G_STRUCT_OFFSET (EggEditableToolbarClass, action_request),
1101 NULL, NULL, g_cclosure_marshal_VOID__STRING,
1102 G_TYPE_NONE, 1, G_TYPE_STRING);
1104 g_object_class_install_property (object_class,
1106 g_param_spec_object ("ui-manager",
1109 GTK_TYPE_UI_MANAGER,
1110 G_PARAM_READWRITE));
1111 g_object_class_install_property (object_class,
1112 PROP_TOOLBARS_MODEL,
1113 g_param_spec_object ("model",
1116 EGG_TYPE_TOOLBARS_MODEL,
1117 G_PARAM_READWRITE));
1119 g_type_class_add_private (object_class, sizeof (EggEditableToolbarPrivate));
1123 egg_editable_toolbar_init (EggEditableToolbar *t)
1125 t->priv = EGG_EDITABLE_TOOLBAR_GET_PRIVATE (t);
1129 egg_editable_toolbar_finalize (GObject *object)
1131 EggEditableToolbar *t = EGG_EDITABLE_TOOLBAR (object);
1133 if (t->priv->fixed_toolbar)
1135 g_object_unref (t->priv->fixed_toolbar);
1138 if (t->priv->manager)
1140 g_object_unref (t->priv->manager);
1145 egg_editable_toolbar_disconnect_model (t);
1146 g_object_unref (t->priv->model);
1149 G_OBJECT_CLASS (parent_class)->finalize (object);
1153 egg_editable_toolbar_new (GtkUIManager *manager)
1155 return GTK_WIDGET (g_object_new (EGG_TYPE_EDITABLE_TOOLBAR,
1156 "ui-manager", manager,
1161 egg_editable_toolbar_new_with_model (GtkUIManager *manager,
1162 EggToolbarsModel *model)
1164 return GTK_WIDGET (g_object_new (EGG_TYPE_EDITABLE_TOOLBAR,
1165 "ui-manager", manager,
1171 egg_editable_toolbar_get_edit_mode (EggEditableToolbar *etoolbar)
1173 return etoolbar->priv->edit_mode;
1177 egg_editable_toolbar_set_edit_mode (EggEditableToolbar *etoolbar,
1180 int i, l, n_toolbars, n_items;
1182 etoolbar->priv->edit_mode = mode;
1184 n_toolbars = get_n_toolbars (etoolbar);
1185 for (i = 0; i < n_toolbars; i++)
1189 toolbar = get_toolbar_nth (etoolbar, i);
1190 n_items = gtk_toolbar_get_n_items (GTK_TOOLBAR (toolbar));
1191 for (l = 0; l < n_items; l++)
1194 const char *action_name, *type;
1195 gboolean is_separator;
1196 GtkAction *action = NULL;
1198 egg_toolbars_model_item_nth (etoolbar->priv->model, i, l,
1199 &is_separator, &action_name, &type);
1200 action = find_action (etoolbar, action_name);
1202 item = gtk_toolbar_get_nth_item (GTK_TOOLBAR (toolbar), l);
1203 gtk_tool_item_set_use_drag_window (item, mode);
1207 set_drag_cursor (GTK_WIDGET (item));
1208 gtk_widget_set_sensitive (GTK_WIDGET (item), TRUE);
1209 set_item_drag_source (etoolbar->priv->model, GTK_WIDGET (item),
1210 action, is_separator, type);
1214 unset_drag_cursor (GTK_WIDGET (item));
1215 gtk_drag_source_unset (GTK_WIDGET (item));
1219 g_object_notify (G_OBJECT (action), "sensitive");
1227 egg_editable_toolbar_show (EggEditableToolbar *etoolbar,
1231 EggToolbarsModel *model = etoolbar->priv->model;
1233 g_return_if_fail (model != NULL);
1235 n_toolbars = egg_toolbars_model_n_toolbars (model);
1236 for (i = 0; i < n_toolbars; i++)
1238 const char *toolbar_name;
1240 toolbar_name = egg_toolbars_model_toolbar_nth (model, i);
1241 if (strcmp (toolbar_name, name) == 0)
1243 gtk_widget_show (get_dock_nth (etoolbar, i));
1249 egg_editable_toolbar_hide (EggEditableToolbar *etoolbar,
1253 EggToolbarsModel *model = etoolbar->priv->model;
1255 g_return_if_fail (model != NULL);
1257 n_toolbars = egg_toolbars_model_n_toolbars (model);
1258 for (i = 0; i < n_toolbars; i++)
1260 const char *toolbar_name;
1262 toolbar_name = egg_toolbars_model_toolbar_nth (model, i);
1263 if (strcmp (toolbar_name, name) == 0)
1265 gtk_widget_hide (get_dock_nth (etoolbar, i));
1271 egg_editable_toolbar_set_fixed (EggEditableToolbar *toolbar,
1272 GtkToolbar *fixed_toolbar)
1274 g_return_if_fail (EGG_IS_EDITABLE_TOOLBAR (toolbar));
1275 g_return_if_fail (!fixed_toolbar || GTK_IS_TOOLBAR (fixed_toolbar));
1277 if (toolbar->priv->fixed_toolbar)
1279 unparent_fixed (toolbar);
1280 g_object_unref (toolbar->priv->fixed_toolbar);
1281 toolbar->priv->fixed_toolbar = NULL;
1286 toolbar->priv->fixed_toolbar = GTK_WIDGET (fixed_toolbar);
1287 gtk_toolbar_set_show_arrow (fixed_toolbar, FALSE);
1288 g_object_ref (fixed_toolbar);
1289 gtk_object_sink (GTK_OBJECT (fixed_toolbar));
1292 update_fixed (toolbar);
1296 egg_editable_toolbar_set_drag_dest (EggEditableToolbar *etoolbar,
1297 const GtkTargetEntry *targets,
1299 const char *toolbar_name)
1302 EggToolbarsModel *model = etoolbar->priv->model;
1304 g_return_if_fail (model != NULL);
1306 n_toolbars = egg_toolbars_model_n_toolbars (model);
1307 for (i = 0; i < n_toolbars; i++)
1311 name = egg_toolbars_model_toolbar_nth (model, i);
1312 if (strcmp (toolbar_name, name) == 0)
1314 GtkWidget *widget = get_toolbar_nth (etoolbar, i);
1316 gtk_drag_dest_unset (widget);
1317 gtk_drag_dest_set (widget, 0,
1319 GDK_ACTION_MOVE | GDK_ACTION_COPY);
1324 #define DEFAULT_ICON_HEIGHT 20
1325 #define DEFAULT_ICON_WIDTH 0
1328 fake_expose_widget (GtkWidget *widget,
1331 GdkWindow *tmp_window;
1332 GdkEventExpose event;
1334 event.type = GDK_EXPOSE;
1335 event.window = pixmap;
1336 event.send_event = FALSE;
1337 event.area = widget->allocation;
1338 event.region = NULL;
1341 tmp_window = widget->window;
1342 widget->window = pixmap;
1343 gtk_widget_send_expose (widget, (GdkEvent *) &event);
1344 widget->window = tmp_window;
1347 /* We should probably experiment some more with this.
1348 * Right now the rendered icon is pretty good for most
1349 * themes. However, the icon is slightly large for themes
1350 * with large toolbar icons.
1353 new_pixbuf_from_widget (GtkWidget *widget)
1357 GtkRequisition requisition;
1358 GtkAllocation allocation;
1364 icon_width = DEFAULT_ICON_WIDTH;
1366 if (!gtk_icon_size_lookup_for_settings (gtk_settings_get_default (),
1367 GTK_ICON_SIZE_LARGE_TOOLBAR,
1371 icon_height = DEFAULT_ICON_HEIGHT;
1374 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1376 gtk_container_add (GTK_CONTAINER (window), widget);
1377 gtk_widget_realize (window);
1378 gtk_widget_show (widget);
1379 gtk_widget_realize (widget);
1380 gtk_widget_map (widget);
1382 /* Gtk will never set the width or height of a window to 0. So setting the width to
1383 * 0 and than getting it will provide us with the minimum width needed to render
1384 * the icon correctly, without any additional window background noise.
1385 * This is needed mostly for pixmap based themes.
1387 gtk_window_set_default_size (GTK_WINDOW (window), icon_width, icon_height);
1388 gtk_window_get_size (GTK_WINDOW (window),&icon_width, &icon_height);
1390 gtk_widget_size_request (window, &requisition);
1393 allocation.width = icon_width;
1394 allocation.height = icon_height;
1395 gtk_widget_size_allocate (window, &allocation);
1396 gtk_widget_size_request (window, &requisition);
1398 /* Create a pixmap */
1399 visual = gtk_widget_get_visual (window);
1400 pixmap = gdk_pixmap_new (NULL, icon_width, icon_height, visual->depth);
1401 gdk_drawable_set_colormap (GDK_DRAWABLE (pixmap), gtk_widget_get_colormap (window));
1403 /* Draw the window */
1404 gtk_widget_ensure_style (window);
1405 g_assert (window->style);
1406 g_assert (window->style->font_desc);
1408 fake_expose_widget (window, pixmap);
1409 fake_expose_widget (widget, pixmap);
1411 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, icon_width, icon_height);
1412 gdk_pixbuf_get_from_drawable (pixbuf, pixmap, NULL, 0, 0, 0, 0, icon_width, icon_height);
1414 gtk_widget_destroy (window);
1420 new_separator_pixbuf ()
1422 GtkWidget *separator;
1425 separator = gtk_vseparator_new ();
1426 pixbuf = new_pixbuf_from_widget (separator);
1431 update_separator_image (GtkImage *image)
1433 GdkPixbuf *pixbuf = new_separator_pixbuf ();
1434 gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
1435 g_object_unref (pixbuf);
1439 style_set_cb (GtkWidget *widget,
1440 GtkStyle *previous_style,
1444 update_separator_image (image);
1449 _egg_editable_toolbar_new_separator_image (void)
1451 GtkWidget *image = gtk_image_new ();
1452 update_separator_image (GTK_IMAGE (image));
1453 g_signal_connect (G_OBJECT (image), "style_set",
1454 G_CALLBACK (style_set_cb), GTK_IMAGE (image));
1460 egg_editable_toolbar_get_model (EggEditableToolbar *etoolbar)
1462 return etoolbar->priv->model;