1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 * GtkToolbar copyright (C) Federico Mena
5 * Copyright (C) 2002 Anders Carlsson <andersca@gnome.org>
6 * Copyright (C) 2002 James Henstridge <james@daa.com.au>
7 * Copyright (C) 2003, 2004 Soeren Sandmann <sandmann@daimi.au.dk>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
26 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
27 * file for a list of people on the GTK+ Team. See the ChangeLog
28 * files for a list of changes. These files are distributed with
29 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
38 #include "gtktoolbar.h"
41 #include "gtkbindings.h"
45 #include "gtkmainprivate.h"
46 #include "gtkmarshalers.h"
48 #include "gtkorientable.h"
49 #include "gtkradiobutton.h"
50 #include "gtkradiotoolbutton.h"
51 #include "gtkseparatormenuitem.h"
52 #include "gtkseparatortoolitem.h"
54 #include "gtktoolshell.h"
56 #include "gtkprivate.h"
58 #include "gtktypebuiltins.h"
63 * @Short_description: Create bars of buttons and other widgets
65 * @See_also: #GtkToolItem
67 * A toolbar is created with a call to gtk_toolbar_new().
69 * A toolbar can contain instances of a subclass of #GtkToolItem. To add
70 * a #GtkToolItem to the a toolbar, use gtk_toolbar_insert(). To remove
71 * an item from the toolbar use gtk_container_remove(). To add a button
72 * to the toolbar, add an instance of #GtkToolButton.
74 * Toolbar items can be visually grouped by adding instances of
75 * #GtkSeparatorToolItem to the toolbar. If the GtkToolbar child property
76 * "expand" is #TRUE and the property #GtkSeparatorToolItem:draw is set to
77 * #FALSE, the effect is to force all following items to the end of the toolbar.
79 * Creating a context menu for the toolbar can be done by connecting to
80 * the #GtkToolbar::popup-context-menu signal.
84 typedef struct _ToolbarContent ToolbarContent;
86 #define DEFAULT_IPADDING 0
88 #define DEFAULT_SPACE_SIZE 12
89 #define DEFAULT_SPACE_STYLE GTK_TOOLBAR_SPACE_LINE
90 #define SPACE_LINE_DIVISION 10.0
91 #define SPACE_LINE_START 2.0
92 #define SPACE_LINE_END 8.0
94 #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_LARGE_TOOLBAR
95 #define DEFAULT_TOOLBAR_STYLE GTK_TOOLBAR_BOTH
96 #define DEFAULT_ANIMATION_STATE TRUE
98 #define MAX_HOMOGENEOUS_N_CHARS 13 /* Items that are wider than this do not participate
99 * in the homogeneous game. In units of
100 * pango_font_get_estimated_char_width().
102 #define SLIDE_SPEED 600.0 /* How fast the items slide, in pixels per second */
103 #define ACCEL_THRESHOLD 0.18 /* After how much time in seconds will items start speeding up */
106 struct _GtkToolbarPrivate
109 GtkSettings *settings;
111 GtkIconSize icon_size;
112 GtkToolbarStyle style;
114 GtkToolItem *highlight_tool_item;
116 GtkWidget *arrow_button;
118 GdkWindow *event_window;
124 GtkWidgetPath *sibling_path;
126 gulong settings_connection;
129 gint button_maxw; /* maximum width of homogeneous children */
130 gint button_maxh; /* maximum height of homogeneous children */
131 gint max_homogeneous_pixels;
134 GtkOrientation orientation;
137 guint icon_size_set : 1;
138 guint is_sliding : 1;
139 guint need_rebuild : 1; /* whether the overflow menu should be regenerated */
141 guint show_arrow : 1;
156 /* Child properties */
160 CHILD_PROP_HOMOGENEOUS
180 static void gtk_toolbar_set_property (GObject *object,
184 static void gtk_toolbar_get_property (GObject *object,
188 static gint gtk_toolbar_draw (GtkWidget *widget,
190 static void gtk_toolbar_realize (GtkWidget *widget);
191 static void gtk_toolbar_unrealize (GtkWidget *widget);
192 static void gtk_toolbar_get_preferred_width (GtkWidget *widget,
195 static void gtk_toolbar_get_preferred_height (GtkWidget *widget,
199 static void gtk_toolbar_size_allocate (GtkWidget *widget,
200 GtkAllocation *allocation);
201 static void gtk_toolbar_style_updated (GtkWidget *widget);
202 static gboolean gtk_toolbar_focus (GtkWidget *widget,
203 GtkDirectionType dir);
204 static void gtk_toolbar_move_focus (GtkWidget *widget,
205 GtkDirectionType dir);
206 static void gtk_toolbar_screen_changed (GtkWidget *widget,
207 GdkScreen *previous_screen);
208 static void gtk_toolbar_map (GtkWidget *widget);
209 static void gtk_toolbar_unmap (GtkWidget *widget);
210 static void gtk_toolbar_set_child_property (GtkContainer *container,
215 static void gtk_toolbar_get_child_property (GtkContainer *container,
220 static void gtk_toolbar_finalize (GObject *object);
221 static void gtk_toolbar_show_all (GtkWidget *widget);
222 static void gtk_toolbar_add (GtkContainer *container,
224 static void gtk_toolbar_remove (GtkContainer *container,
226 static void gtk_toolbar_forall (GtkContainer *container,
227 gboolean include_internals,
228 GtkCallback callback,
229 gpointer callback_data);
230 static GType gtk_toolbar_child_type (GtkContainer *container);
231 static GtkWidgetPath * gtk_toolbar_get_path_for_child
232 (GtkContainer *container,
234 static void gtk_toolbar_invalidate_order (GtkToolbar *toolbar);
236 static void gtk_toolbar_orientation_changed (GtkToolbar *toolbar,
237 GtkOrientation orientation);
238 static void gtk_toolbar_real_style_changed (GtkToolbar *toolbar,
239 GtkToolbarStyle style);
240 static gboolean gtk_toolbar_focus_home_or_end (GtkToolbar *toolbar,
241 gboolean focus_home);
242 static gboolean gtk_toolbar_button_press (GtkWidget *toolbar,
243 GdkEventButton *event);
244 static gboolean gtk_toolbar_arrow_button_press (GtkWidget *button,
245 GdkEventButton *event,
246 GtkToolbar *toolbar);
247 static void gtk_toolbar_arrow_button_clicked (GtkWidget *button,
248 GtkToolbar *toolbar);
249 static void gtk_toolbar_update_button_relief (GtkToolbar *toolbar);
250 static gboolean gtk_toolbar_popup_menu (GtkWidget *toolbar);
251 static void gtk_toolbar_reconfigured (GtkToolbar *toolbar);
253 static GtkReliefStyle get_button_relief (GtkToolbar *toolbar);
254 static gint get_internal_padding (GtkToolbar *toolbar);
255 static gint get_max_child_expand (GtkToolbar *toolbar);
256 static GtkShadowType get_shadow_type (GtkToolbar *toolbar);
258 /* methods on ToolbarContent 'class' */
259 static ToolbarContent *toolbar_content_new_tool_item (GtkToolbar *toolbar,
261 gboolean is_placeholder,
263 static void toolbar_content_remove (ToolbarContent *content,
264 GtkToolbar *toolbar);
265 static void toolbar_content_free (ToolbarContent *content);
266 static void toolbar_content_draw (ToolbarContent *content,
267 GtkContainer *container,
269 static gboolean toolbar_content_visible (ToolbarContent *content,
270 GtkToolbar *toolbar);
271 static void toolbar_content_size_request (ToolbarContent *content,
273 GtkRequisition *requisition);
274 static gboolean toolbar_content_is_homogeneous (ToolbarContent *content,
275 GtkToolbar *toolbar);
276 static gboolean toolbar_content_is_placeholder (ToolbarContent *content);
277 static gboolean toolbar_content_disappearing (ToolbarContent *content);
278 static ItemState toolbar_content_get_state (ToolbarContent *content);
279 static gboolean toolbar_content_child_visible (ToolbarContent *content);
280 static void toolbar_content_get_goal_allocation (ToolbarContent *content,
281 GtkAllocation *allocation);
282 static void toolbar_content_get_allocation (ToolbarContent *content,
283 GtkAllocation *allocation);
284 static void toolbar_content_set_start_allocation (ToolbarContent *content,
285 GtkAllocation *new_start_allocation);
286 static void toolbar_content_get_start_allocation (ToolbarContent *content,
287 GtkAllocation *start_allocation);
288 static gboolean toolbar_content_get_expand (ToolbarContent *content);
289 static void toolbar_content_set_goal_allocation (ToolbarContent *content,
290 GtkAllocation *allocation);
291 static void toolbar_content_set_child_visible (ToolbarContent *content,
294 static void toolbar_content_size_allocate (ToolbarContent *content,
295 GtkAllocation *allocation);
296 static void toolbar_content_set_state (ToolbarContent *content,
297 ItemState new_state);
298 static GtkWidget * toolbar_content_get_widget (ToolbarContent *content);
299 static void toolbar_content_set_disappearing (ToolbarContent *content,
300 gboolean disappearing);
301 static void toolbar_content_set_size_request (ToolbarContent *content,
304 static void toolbar_content_toolbar_reconfigured (ToolbarContent *content,
305 GtkToolbar *toolbar);
306 static GtkWidget * toolbar_content_retrieve_menu_item (ToolbarContent *content);
307 static gboolean toolbar_content_has_proxy_menu_item (ToolbarContent *content);
308 static gboolean toolbar_content_is_separator (ToolbarContent *content);
309 static void toolbar_content_show_all (ToolbarContent *content);
310 static void toolbar_content_set_expand (ToolbarContent *content,
313 static void toolbar_tool_shell_iface_init (GtkToolShellIface *iface);
314 static GtkIconSize toolbar_get_icon_size (GtkToolShell *shell);
315 static GtkOrientation toolbar_get_orientation (GtkToolShell *shell);
316 static GtkToolbarStyle toolbar_get_style (GtkToolShell *shell);
317 static GtkReliefStyle toolbar_get_relief_style (GtkToolShell *shell);
318 static void toolbar_rebuild_menu (GtkToolShell *shell);
321 G_DEFINE_TYPE_WITH_CODE (GtkToolbar, gtk_toolbar, GTK_TYPE_CONTAINER,
322 G_IMPLEMENT_INTERFACE (GTK_TYPE_TOOL_SHELL,
323 toolbar_tool_shell_iface_init)
324 G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
327 static guint toolbar_signals[LAST_SIGNAL] = { 0 };
331 add_arrow_bindings (GtkBindingSet *binding_set,
333 GtkDirectionType dir)
335 guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
337 gtk_binding_entry_add_signal (binding_set, keysym, 0,
339 GTK_TYPE_DIRECTION_TYPE, dir);
340 gtk_binding_entry_add_signal (binding_set, keypad_keysym, 0,
342 GTK_TYPE_DIRECTION_TYPE, dir);
346 add_ctrl_tab_bindings (GtkBindingSet *binding_set,
347 GdkModifierType modifiers,
348 GtkDirectionType direction)
350 gtk_binding_entry_add_signal (binding_set,
351 GDK_KEY_Tab, GDK_CONTROL_MASK | modifiers,
353 GTK_TYPE_DIRECTION_TYPE, direction);
354 gtk_binding_entry_add_signal (binding_set,
355 GDK_KEY_KP_Tab, GDK_CONTROL_MASK | modifiers,
357 GTK_TYPE_DIRECTION_TYPE, direction);
361 gtk_toolbar_class_init (GtkToolbarClass *klass)
363 GObjectClass *gobject_class;
364 GtkWidgetClass *widget_class;
365 GtkContainerClass *container_class;
366 GtkBindingSet *binding_set;
368 gobject_class = (GObjectClass *)klass;
369 widget_class = (GtkWidgetClass *)klass;
370 container_class = (GtkContainerClass *)klass;
372 gobject_class->set_property = gtk_toolbar_set_property;
373 gobject_class->get_property = gtk_toolbar_get_property;
374 gobject_class->finalize = gtk_toolbar_finalize;
376 widget_class->button_press_event = gtk_toolbar_button_press;
377 widget_class->draw = gtk_toolbar_draw;
378 widget_class->get_preferred_width = gtk_toolbar_get_preferred_width;
379 widget_class->get_preferred_height = gtk_toolbar_get_preferred_height;
380 widget_class->size_allocate = gtk_toolbar_size_allocate;
381 widget_class->style_updated = gtk_toolbar_style_updated;
382 widget_class->focus = gtk_toolbar_focus;
384 gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_TOOL_BAR);
386 /* need to override the base class function via override_class_handler,
387 * because the signal slot is not available in GtkWidgetClass
389 g_signal_override_class_handler ("move-focus",
391 G_CALLBACK (gtk_toolbar_move_focus));
393 widget_class->screen_changed = gtk_toolbar_screen_changed;
394 widget_class->realize = gtk_toolbar_realize;
395 widget_class->unrealize = gtk_toolbar_unrealize;
396 widget_class->map = gtk_toolbar_map;
397 widget_class->unmap = gtk_toolbar_unmap;
398 widget_class->popup_menu = gtk_toolbar_popup_menu;
399 widget_class->show_all = gtk_toolbar_show_all;
401 container_class->add = gtk_toolbar_add;
402 container_class->remove = gtk_toolbar_remove;
403 container_class->forall = gtk_toolbar_forall;
404 container_class->child_type = gtk_toolbar_child_type;
405 container_class->get_child_property = gtk_toolbar_get_child_property;
406 container_class->set_child_property = gtk_toolbar_set_child_property;
407 container_class->get_path_for_child = gtk_toolbar_get_path_for_child;
409 klass->orientation_changed = gtk_toolbar_orientation_changed;
410 klass->style_changed = gtk_toolbar_real_style_changed;
413 * GtkToolbar::orientation-changed:
414 * @toolbar: the object which emitted the signal
415 * @orientation: the new #GtkOrientation of the toolbar
417 * Emitted when the orientation of the toolbar changes.
419 toolbar_signals[ORIENTATION_CHANGED] =
420 g_signal_new (I_("orientation-changed"),
421 G_OBJECT_CLASS_TYPE (klass),
423 G_STRUCT_OFFSET (GtkToolbarClass, orientation_changed),
425 g_cclosure_marshal_VOID__ENUM,
427 GTK_TYPE_ORIENTATION);
429 * GtkToolbar::style-changed:
430 * @toolbar: The #GtkToolbar which emitted the signal
431 * @style: the new #GtkToolbarStyle of the toolbar
433 * Emitted when the style of the toolbar changes.
435 toolbar_signals[STYLE_CHANGED] =
436 g_signal_new (I_("style-changed"),
437 G_OBJECT_CLASS_TYPE (klass),
439 G_STRUCT_OFFSET (GtkToolbarClass, style_changed),
441 g_cclosure_marshal_VOID__ENUM,
443 GTK_TYPE_TOOLBAR_STYLE);
445 * GtkToolbar::popup-context-menu:
446 * @toolbar: the #GtkToolbar which emitted the signal
447 * @x: the x coordinate of the point where the menu should appear
448 * @y: the y coordinate of the point where the menu should appear
449 * @button: the mouse button the user pressed, or -1
451 * Emitted when the user right-clicks the toolbar or uses the
452 * keybinding to display a popup menu.
454 * Application developers should handle this signal if they want
455 * to display a context menu on the toolbar. The context-menu should
456 * appear at the coordinates given by @x and @y. The mouse button
457 * number is given by the @button parameter. If the menu was popped
458 * up using the keybaord, @button is -1.
460 * Return value: return %TRUE if the signal was handled, %FALSE if not
462 toolbar_signals[POPUP_CONTEXT_MENU] =
463 g_signal_new (I_("popup-context-menu"),
464 G_OBJECT_CLASS_TYPE (klass),
466 G_STRUCT_OFFSET (GtkToolbarClass, popup_context_menu),
467 _gtk_boolean_handled_accumulator, NULL,
468 _gtk_marshal_BOOLEAN__INT_INT_INT,
470 G_TYPE_INT, G_TYPE_INT,
474 * GtkToolbar::focus-home-or-end:
475 * @toolbar: the #GtkToolbar which emitted the signal
476 * @focus_home: %TRUE if the first item should be focused
478 * A keybinding signal used internally by GTK+. This signal can't
479 * be used in application code
481 * Return value: %TRUE if the signal was handled, %FALSE if not
483 toolbar_signals[FOCUS_HOME_OR_END] =
484 g_signal_new_class_handler (I_("focus-home-or-end"),
485 G_OBJECT_CLASS_TYPE (klass),
486 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
487 G_CALLBACK (gtk_toolbar_focus_home_or_end),
489 _gtk_marshal_BOOLEAN__BOOLEAN,
494 g_object_class_override_property (gobject_class,
498 g_object_class_install_property (gobject_class,
500 g_param_spec_enum ("toolbar-style",
502 P_("How to draw the toolbar"),
503 GTK_TYPE_TOOLBAR_STYLE,
504 DEFAULT_TOOLBAR_STYLE,
505 GTK_PARAM_READWRITE));
506 g_object_class_install_property (gobject_class,
508 g_param_spec_boolean ("show-arrow",
510 P_("If an arrow should be shown if the toolbar doesn't fit"),
512 GTK_PARAM_READWRITE));
515 * GtkToolbar:icon-size:
517 * The size of the icons in a toolbar is normally determined by
518 * the toolbar-icon-size setting. When this property is set, it
519 * overrides the setting.
521 * This should only be used for special-purpose toolbars, normal
522 * application toolbars should respect the user preferences for the
527 g_object_class_install_property (gobject_class,
529 g_param_spec_int ("icon-size",
531 P_("Size of icons in this toolbar"),
534 GTK_PARAM_READWRITE));
537 * GtkToolbar:icon-size-set:
539 * Is %TRUE if the icon-size property has been set.
543 g_object_class_install_property (gobject_class,
545 g_param_spec_boolean ("icon-size-set",
547 P_("Whether the icon-size property has been set"),
549 GTK_PARAM_READWRITE));
551 /* child properties */
552 gtk_container_class_install_child_property (container_class,
554 g_param_spec_boolean ("expand",
556 P_("Whether the item should receive extra space when the toolbar grows"),
558 GTK_PARAM_READWRITE));
560 gtk_container_class_install_child_property (container_class,
561 CHILD_PROP_HOMOGENEOUS,
562 g_param_spec_boolean ("homogeneous",
564 P_("Whether the item should be the same size as other homogeneous items"),
566 GTK_PARAM_READWRITE));
568 /* style properties */
569 gtk_widget_class_install_style_property (widget_class,
570 g_param_spec_int ("space-size",
572 P_("Size of spacers"),
576 GTK_PARAM_READABLE));
578 gtk_widget_class_install_style_property (widget_class,
579 g_param_spec_int ("internal-padding",
580 P_("Internal padding"),
581 P_("Amount of border space between the toolbar shadow and the buttons"),
585 GTK_PARAM_READABLE));
587 gtk_widget_class_install_style_property (widget_class,
588 g_param_spec_int ("max-child-expand",
589 P_("Maximum child expand"),
590 P_("Maximum amount of space an expandable item will be given"),
594 GTK_PARAM_READABLE));
596 gtk_widget_class_install_style_property (widget_class,
597 g_param_spec_enum ("space-style",
599 P_("Whether spacers are vertical lines or just blank"),
600 GTK_TYPE_TOOLBAR_SPACE_STYLE,
602 GTK_PARAM_READABLE));
604 gtk_widget_class_install_style_property (widget_class,
605 g_param_spec_enum ("button-relief",
607 P_("Type of bevel around toolbar buttons"),
608 GTK_TYPE_RELIEF_STYLE,
610 GTK_PARAM_READABLE));
611 gtk_widget_class_install_style_property (widget_class,
612 g_param_spec_enum ("shadow-type",
614 P_("Style of bevel around the toolbar"),
615 GTK_TYPE_SHADOW_TYPE,
617 GTK_PARAM_READABLE));
619 binding_set = gtk_binding_set_by_class (klass);
621 add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
622 add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
623 add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
624 add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
626 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Home, 0,
627 "focus-home-or-end", 1,
628 G_TYPE_BOOLEAN, TRUE);
629 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Home, 0,
630 "focus-home-or-end", 1,
631 G_TYPE_BOOLEAN, TRUE);
632 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_End, 0,
633 "focus-home-or-end", 1,
634 G_TYPE_BOOLEAN, FALSE);
635 gtk_binding_entry_add_signal (binding_set, GDK_KEY_End, 0,
636 "focus-home-or-end", 1,
637 G_TYPE_BOOLEAN, FALSE);
639 add_ctrl_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
640 add_ctrl_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
642 g_type_class_add_private (gobject_class, sizeof (GtkToolbarPrivate));
646 toolbar_tool_shell_iface_init (GtkToolShellIface *iface)
648 iface->get_icon_size = toolbar_get_icon_size;
649 iface->get_orientation = toolbar_get_orientation;
650 iface->get_style = toolbar_get_style;
651 iface->get_relief_style = toolbar_get_relief_style;
652 iface->rebuild_menu = toolbar_rebuild_menu;
656 gtk_toolbar_init (GtkToolbar *toolbar)
658 GtkToolbarPrivate *priv;
659 GtkStyleContext *context;
661 toolbar->priv = G_TYPE_INSTANCE_GET_PRIVATE (toolbar,
664 priv = toolbar->priv;
666 gtk_widget_set_can_focus (GTK_WIDGET (toolbar), FALSE);
667 gtk_widget_set_has_window (GTK_WIDGET (toolbar), FALSE);
669 priv->orientation = GTK_ORIENTATION_HORIZONTAL;
670 priv->style = DEFAULT_TOOLBAR_STYLE;
671 priv->icon_size = DEFAULT_ICON_SIZE;
672 priv->animation = DEFAULT_ANIMATION_STATE;
674 priv->arrow_button = gtk_toggle_button_new ();
675 g_signal_connect (priv->arrow_button, "button-press-event",
676 G_CALLBACK (gtk_toolbar_arrow_button_press), toolbar);
677 g_signal_connect (priv->arrow_button, "clicked",
678 G_CALLBACK (gtk_toolbar_arrow_button_clicked), toolbar);
679 gtk_button_set_relief (GTK_BUTTON (priv->arrow_button),
680 get_button_relief (toolbar));
682 gtk_button_set_focus_on_click (GTK_BUTTON (priv->arrow_button), FALSE);
684 priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
685 gtk_widget_set_name (priv->arrow, "gtk-toolbar-arrow");
686 gtk_widget_show (priv->arrow);
687 gtk_container_add (GTK_CONTAINER (priv->arrow_button), priv->arrow);
689 gtk_widget_set_parent (priv->arrow_button, GTK_WIDGET (toolbar));
691 /* which child position a drop will occur at */
693 priv->show_arrow = TRUE;
694 priv->settings = NULL;
696 priv->max_homogeneous_pixels = -1;
698 priv->timer = g_timer_new ();
700 context = gtk_widget_get_style_context (GTK_WIDGET (toolbar));
701 gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOOLBAR);
705 gtk_toolbar_set_property (GObject *object,
710 GtkToolbar *toolbar = GTK_TOOLBAR (object);
711 GtkToolbarPrivate *priv = toolbar->priv;
715 case PROP_ORIENTATION:
716 g_signal_emit (toolbar, toolbar_signals[ORIENTATION_CHANGED], 0,
717 g_value_get_enum (value));
719 case PROP_TOOLBAR_STYLE:
720 gtk_toolbar_set_style (toolbar, g_value_get_enum (value));
722 case PROP_SHOW_ARROW:
723 gtk_toolbar_set_show_arrow (toolbar, g_value_get_boolean (value));
726 gtk_toolbar_set_icon_size (toolbar, g_value_get_int (value));
728 case PROP_ICON_SIZE_SET:
729 if (g_value_get_boolean (value))
730 priv->icon_size_set = TRUE;
732 gtk_toolbar_unset_icon_size (toolbar);
735 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
741 gtk_toolbar_get_property (GObject *object,
746 GtkToolbar *toolbar = GTK_TOOLBAR (object);
747 GtkToolbarPrivate *priv = toolbar->priv;
751 case PROP_ORIENTATION:
752 g_value_set_enum (value, priv->orientation);
754 case PROP_TOOLBAR_STYLE:
755 g_value_set_enum (value, priv->style);
757 case PROP_SHOW_ARROW:
758 g_value_set_boolean (value, priv->show_arrow);
761 g_value_set_int (value, gtk_toolbar_get_icon_size (toolbar));
763 case PROP_ICON_SIZE_SET:
764 g_value_set_boolean (value, priv->icon_size_set);
767 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
773 gtk_toolbar_map (GtkWidget *widget)
775 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
776 GtkToolbarPrivate *priv = toolbar->priv;
778 GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->map (widget);
780 if (priv->event_window)
781 gdk_window_show_unraised (priv->event_window);
785 gtk_toolbar_unmap (GtkWidget *widget)
787 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
788 GtkToolbarPrivate *priv = toolbar->priv;
790 if (priv->event_window)
791 gdk_window_hide (priv->event_window);
793 GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->unmap (widget);
797 gtk_toolbar_realize (GtkWidget *widget)
799 GtkAllocation allocation;
800 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
801 GtkToolbarPrivate *priv = toolbar->priv;
803 GdkWindowAttr attributes;
804 gint attributes_mask;
807 gtk_widget_set_realized (widget, TRUE);
809 gtk_widget_get_allocation (widget, &allocation);
810 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
812 attributes.wclass = GDK_INPUT_ONLY;
813 attributes.window_type = GDK_WINDOW_CHILD;
814 attributes.x = allocation.x + border_width;
815 attributes.y = allocation.y + border_width;
816 attributes.width = allocation.width - border_width * 2;
817 attributes.height = allocation.height - border_width * 2;
818 attributes.event_mask = gtk_widget_get_events (widget);
819 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
820 GDK_BUTTON_RELEASE_MASK |
821 GDK_ENTER_NOTIFY_MASK |
822 GDK_LEAVE_NOTIFY_MASK);
824 attributes_mask = GDK_WA_X | GDK_WA_Y;
826 window = gtk_widget_get_parent_window (widget);
827 gtk_widget_set_window (widget, window);
828 g_object_ref (window);
830 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
831 &attributes, attributes_mask);
832 gdk_window_set_user_data (priv->event_window, toolbar);
836 gtk_toolbar_unrealize (GtkWidget *widget)
838 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
839 GtkToolbarPrivate *priv = toolbar->priv;
841 if (priv->event_window)
843 gdk_window_set_user_data (priv->event_window, NULL);
844 gdk_window_destroy (priv->event_window);
845 priv->event_window = NULL;
848 GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->unrealize (widget);
852 gtk_toolbar_draw (GtkWidget *widget,
855 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
856 GtkToolbarPrivate *priv = toolbar->priv;
857 GtkStyleContext *context;
862 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
863 context = gtk_widget_get_style_context (widget);
864 state = gtk_widget_get_state_flags (widget);
866 gtk_style_context_save (context);
867 gtk_style_context_set_state (context, state);
869 gtk_render_background (context, cr, border_width, border_width,
870 gtk_widget_get_allocated_width (widget) - 2 * border_width,
871 gtk_widget_get_allocated_height (widget) - 2 * border_width);
872 gtk_render_frame (context, cr, border_width, border_width,
873 gtk_widget_get_allocated_width (widget) - 2 * border_width,
874 gtk_widget_get_allocated_height (widget) - 2 * border_width);
876 for (list = priv->content; list != NULL; list = list->next)
878 ToolbarContent *content = list->data;
880 toolbar_content_draw (content, GTK_CONTAINER (widget), cr);
883 gtk_container_propagate_draw (GTK_CONTAINER (widget),
887 gtk_style_context_restore (context);
893 gtk_toolbar_size_request (GtkWidget *widget,
894 GtkRequisition *requisition)
896 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
897 GtkToolbarPrivate *priv = toolbar->priv;
899 gint max_child_height;
900 gint max_child_width;
901 gint max_homogeneous_child_width;
902 gint max_homogeneous_child_height;
903 gint homogeneous_size;
905 gint pack_front_size;
908 GtkRequisition arrow_requisition;
910 max_homogeneous_child_width = 0;
911 max_homogeneous_child_height = 0;
913 max_child_height = 0;
914 for (list = priv->content; list != NULL; list = list->next)
916 GtkRequisition requisition;
917 ToolbarContent *content = list->data;
919 if (!toolbar_content_visible (content, toolbar))
922 toolbar_content_size_request (content, toolbar, &requisition);
924 max_child_width = MAX (max_child_width, requisition.width);
925 max_child_height = MAX (max_child_height, requisition.height);
927 if (toolbar_content_is_homogeneous (content, toolbar))
929 max_homogeneous_child_width = MAX (max_homogeneous_child_width, requisition.width);
930 max_homogeneous_child_height = MAX (max_homogeneous_child_height, requisition.height);
934 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
935 homogeneous_size = max_homogeneous_child_width;
937 homogeneous_size = max_homogeneous_child_height;
940 for (list = priv->content; list != NULL; list = list->next)
942 ToolbarContent *content = list->data;
945 if (!toolbar_content_visible (content, toolbar))
948 if (toolbar_content_is_homogeneous (content, toolbar))
950 size = homogeneous_size;
954 GtkRequisition requisition;
956 toolbar_content_size_request (content, toolbar, &requisition);
958 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
959 size = requisition.width;
961 size = requisition.height;
964 pack_front_size += size;
967 if (priv->show_arrow)
969 gtk_widget_get_preferred_size (priv->arrow_button,
970 &arrow_requisition, NULL);
972 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
973 long_req = arrow_requisition.width;
975 long_req = arrow_requisition.height;
977 /* There is no point requesting space for the arrow if that would take
978 * up more space than all the items combined
980 long_req = MIN (long_req, pack_front_size);
984 arrow_requisition.height = 0;
985 arrow_requisition.width = 0;
987 long_req = pack_front_size;
990 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
992 requisition->width = long_req;
993 requisition->height = MAX (max_child_height, arrow_requisition.height);
997 requisition->height = long_req;
998 requisition->width = MAX (max_child_width, arrow_requisition.width);
1002 ipadding = get_internal_padding (toolbar);
1004 border_width = gtk_container_get_border_width (GTK_CONTAINER (toolbar));
1005 requisition->width += 2 * (ipadding + border_width);
1006 requisition->height += 2 * (ipadding + border_width);
1008 if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1010 GtkStyleContext *context;
1011 GtkStateFlags state;
1014 context = gtk_widget_get_style_context (widget);
1015 state = gtk_widget_get_state_flags (widget);
1016 gtk_style_context_get_padding (context, state, &padding);
1018 requisition->width += padding.left + padding.right;
1019 requisition->height += padding.top + padding.bottom;
1022 priv->button_maxw = max_homogeneous_child_width;
1023 priv->button_maxh = max_homogeneous_child_height;
1027 gtk_toolbar_get_preferred_width (GtkWidget *widget,
1031 GtkRequisition requisition;
1033 gtk_toolbar_size_request (widget, &requisition);
1035 *minimum = *natural = requisition.width;
1039 gtk_toolbar_get_preferred_height (GtkWidget *widget,
1043 GtkRequisition requisition;
1045 gtk_toolbar_size_request (widget, &requisition);
1047 *minimum = *natural = requisition.height;
1051 position (GtkToolbar *toolbar,
1056 GtkToolbarPrivate *priv = toolbar->priv;
1059 if (!priv->animation)
1062 if (elapsed <= ACCEL_THRESHOLD)
1064 n_pixels = SLIDE_SPEED * elapsed;
1068 /* The formula is a second degree polynomial in
1069 * @elapsed that has the line SLIDE_SPEED * @elapsed
1070 * as tangent for @elapsed == ACCEL_THRESHOLD.
1071 * This makes @n_pixels a smooth function of elapsed time.
1073 n_pixels = (SLIDE_SPEED / ACCEL_THRESHOLD) * elapsed * elapsed -
1074 SLIDE_SPEED * elapsed + SLIDE_SPEED * ACCEL_THRESHOLD;
1078 return MIN (from + n_pixels, to);
1080 return MAX (from - n_pixels, to);
1084 compute_intermediate_allocation (GtkToolbar *toolbar,
1085 const GtkAllocation *start,
1086 const GtkAllocation *goal,
1087 GtkAllocation *intermediate)
1089 GtkToolbarPrivate *priv = toolbar->priv;
1090 gdouble elapsed = g_timer_elapsed (priv->timer, NULL);
1092 intermediate->x = position (toolbar, start->x, goal->x, elapsed);
1093 intermediate->y = position (toolbar, start->y, goal->y, elapsed);
1094 intermediate->width = position (toolbar, start->x + start->width,
1095 goal->x + goal->width,
1096 elapsed) - intermediate->x;
1097 intermediate->height = position (toolbar, start->y + start->height,
1098 goal->y + goal->height,
1099 elapsed) - intermediate->y;
1103 fixup_allocation_for_rtl (gint total_size,
1104 GtkAllocation *allocation)
1106 allocation->x += (total_size - (2 * allocation->x + allocation->width));
1110 fixup_allocation_for_vertical (GtkAllocation *allocation)
1114 tmp = allocation->x;
1115 allocation->x = allocation->y;
1116 allocation->y = tmp;
1118 tmp = allocation->width;
1119 allocation->width = allocation->height;
1120 allocation->height = tmp;
1124 get_item_size (GtkToolbar *toolbar,
1125 ToolbarContent *content)
1127 GtkToolbarPrivate *priv = toolbar->priv;
1128 GtkRequisition requisition;
1130 toolbar_content_size_request (content, toolbar, &requisition);
1132 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1134 if (toolbar_content_is_homogeneous (content, toolbar))
1135 return priv->button_maxw;
1137 return requisition.width;
1141 if (toolbar_content_is_homogeneous (content, toolbar))
1142 return priv->button_maxh;
1144 return requisition.height;
1149 slide_idle_handler (gpointer data)
1151 GtkToolbar *toolbar = GTK_TOOLBAR (data);
1152 GtkToolbarPrivate *priv = toolbar->priv;
1155 if (priv->need_sync)
1158 priv->need_sync = FALSE;
1161 for (list = priv->content; list != NULL; list = list->next)
1163 ToolbarContent *content = list->data;
1165 GtkAllocation goal_allocation;
1166 GtkAllocation allocation;
1169 state = toolbar_content_get_state (content);
1170 toolbar_content_get_goal_allocation (content, &goal_allocation);
1171 toolbar_content_get_allocation (content, &allocation);
1175 if (state == NOT_ALLOCATED)
1177 /* an unallocated item means that size allocate has to
1178 * called at least once more
1183 /* An invisible item with a goal allocation of
1184 * 0 is already at its goal.
1186 if ((state == NORMAL || state == OVERFLOWN) &&
1187 ((goal_allocation.width != 0 &&
1188 goal_allocation.height != 0) ||
1189 toolbar_content_child_visible (content)))
1191 if ((goal_allocation.x != allocation.x ||
1192 goal_allocation.y != allocation.y ||
1193 goal_allocation.width != allocation.width ||
1194 goal_allocation.height != allocation.height))
1196 /* An item is not in its right position yet. Note
1197 * that OVERFLOWN items do get an allocation in
1198 * gtk_toolbar_size_allocate(). This way you can see
1199 * them slide back in when you drag an item off the
1206 if (toolbar_content_is_placeholder (content) &&
1207 toolbar_content_disappearing (content) &&
1208 toolbar_content_child_visible (content))
1210 /* A disappearing placeholder is still visible.
1218 gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1224 gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1226 priv->is_sliding = FALSE;
1233 rect_within (GtkAllocation *a1,
1236 return (a1->x >= a2->x &&
1237 a1->x + a1->width <= a2->x + a2->width &&
1239 a1->y + a1->height <= a2->y + a2->height);
1243 gtk_toolbar_begin_sliding (GtkToolbar *toolbar)
1245 GtkAllocation allocation;
1246 GtkWidget *widget = GTK_WIDGET (toolbar);
1247 GtkToolbarPrivate *priv = toolbar->priv;
1248 GtkStyleContext *context;
1249 GtkStateFlags state;
1258 /* Start the sliding. This function copies the allocation of every
1259 * item into content->start_allocation. For items that haven't
1260 * been allocated yet, we calculate their position and save that
1261 * in start_allocatino along with zero width and zero height.
1263 * FIXME: It would be nice if we could share this code with
1264 * the equivalent in gtk_widget_size_allocate().
1266 priv->is_sliding = TRUE;
1269 priv->idle_id = gdk_threads_add_idle (slide_idle_handler, toolbar);
1271 gtk_widget_get_allocation (widget, &allocation);
1272 context = gtk_widget_get_style_context (widget);
1273 state = gtk_widget_get_state_flags (widget);
1274 gtk_style_context_get_padding (context, state, &padding);
1276 rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1277 vertical = (priv->orientation == GTK_ORIENTATION_VERTICAL);
1278 border_width = get_internal_padding (toolbar) + gtk_container_get_border_width (GTK_CONTAINER (toolbar));
1282 cur_x = allocation.width - border_width - padding.right;
1283 cur_y = allocation.height - border_width - padding.top;
1287 cur_x = border_width + padding.left;
1288 cur_y = border_width + padding.top;
1291 cur_x += allocation.x;
1292 cur_y += allocation.y;
1294 for (list = priv->content; list != NULL; list = list->next)
1296 ToolbarContent *content = list->data;
1297 GtkAllocation new_start_allocation;
1298 GtkAllocation item_allocation;
1301 state = toolbar_content_get_state (content);
1302 toolbar_content_get_allocation (content, &item_allocation);
1304 if ((state == NORMAL &&
1305 rect_within (&item_allocation, &allocation)) ||
1308 new_start_allocation = item_allocation;
1312 new_start_allocation.x = cur_x;
1313 new_start_allocation.y = cur_y;
1317 new_start_allocation.width = allocation.width -
1319 padding.left - padding.right;
1320 new_start_allocation.height = 0;
1324 new_start_allocation.width = 0;
1325 new_start_allocation.height = allocation.height -
1327 padding.top - padding.bottom;
1332 cur_y = new_start_allocation.y + new_start_allocation.height;
1334 cur_x = new_start_allocation.x;
1336 cur_x = new_start_allocation.x + new_start_allocation.width;
1338 toolbar_content_set_start_allocation (content, &new_start_allocation);
1341 /* This resize will run before the first idle handler. This
1342 * will make sure that items get the right goal allocation
1343 * so that the idle handler will not immediately return
1346 gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1347 g_timer_reset (priv->timer);
1351 gtk_toolbar_stop_sliding (GtkToolbar *toolbar)
1353 GtkToolbarPrivate *priv = toolbar->priv;
1355 if (priv->is_sliding)
1359 priv->is_sliding = FALSE;
1363 g_source_remove (priv->idle_id);
1367 list = priv->content;
1370 ToolbarContent *content = list->data;
1373 if (toolbar_content_is_placeholder (content))
1375 toolbar_content_remove (content, toolbar);
1376 toolbar_content_free (content);
1380 gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1385 remove_item (GtkWidget *menu_item,
1388 gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (menu_item)),
1393 menu_deactivated (GtkWidget *menu,
1394 GtkToolbar *toolbar)
1396 GtkToolbarPrivate *priv = toolbar->priv;
1398 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->arrow_button), FALSE);
1402 menu_detached (GtkWidget *widget,
1405 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1406 GtkToolbarPrivate *priv = toolbar->priv;
1412 rebuild_menu (GtkToolbar *toolbar)
1414 GtkToolbarPrivate *priv = toolbar->priv;
1415 GList *list, *children;
1419 priv->menu = GTK_MENU (gtk_menu_new());
1420 gtk_menu_attach_to_widget (priv->menu,
1421 GTK_WIDGET (toolbar),
1424 g_signal_connect (priv->menu, "deactivate",
1425 G_CALLBACK (menu_deactivated), toolbar);
1428 gtk_container_foreach (GTK_CONTAINER (priv->menu), remove_item, NULL);
1430 for (list = priv->content; list != NULL; list = list->next)
1432 ToolbarContent *content = list->data;
1434 if (toolbar_content_get_state (content) == OVERFLOWN &&
1435 !toolbar_content_is_placeholder (content))
1437 GtkWidget *menu_item = toolbar_content_retrieve_menu_item (content);
1441 g_assert (GTK_IS_MENU_ITEM (menu_item));
1442 gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menu_item);
1447 /* Remove leading and trailing separator items */
1448 children = gtk_container_get_children (GTK_CONTAINER (priv->menu));
1451 while (list && GTK_IS_SEPARATOR_MENU_ITEM (list->data))
1453 GtkWidget *child = list->data;
1455 gtk_container_remove (GTK_CONTAINER (priv->menu), child);
1458 g_list_free (children);
1460 /* Regenerate the list of children so we don't try to remove items twice */
1461 children = gtk_container_get_children (GTK_CONTAINER (priv->menu));
1463 list = g_list_last (children);
1464 while (list && GTK_IS_SEPARATOR_MENU_ITEM (list->data))
1466 GtkWidget *child = list->data;
1468 gtk_container_remove (GTK_CONTAINER (priv->menu), child);
1471 g_list_free (children);
1473 priv->need_rebuild = FALSE;
1477 gtk_toolbar_size_allocate (GtkWidget *widget,
1478 GtkAllocation *allocation)
1480 GtkAllocation widget_allocation;
1481 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1482 GtkToolbarPrivate *priv = toolbar->priv;
1483 GtkAllocation *allocations;
1484 ItemState *new_states;
1485 GtkAllocation arrow_allocation;
1486 GtkStyleContext *context;
1487 GtkStateFlags state;
1490 gint size, pos, short_size;
1493 gboolean need_arrow;
1494 gint n_expand_items;
1496 gint available_size;
1499 GtkRequisition arrow_requisition;
1500 gboolean overflowing;
1501 gboolean size_changed;
1502 GtkAllocation item_area;
1503 GtkShadowType shadow_type;
1505 context = gtk_widget_get_style_context (widget);
1506 state = gtk_widget_get_state_flags (widget);
1507 gtk_style_context_get_padding (context, state, &padding);
1509 gtk_widget_get_allocation (widget, &widget_allocation);
1510 size_changed = FALSE;
1511 if (widget_allocation.x != allocation->x ||
1512 widget_allocation.y != allocation->y ||
1513 widget_allocation.width != allocation->width ||
1514 widget_allocation.height != allocation->height)
1516 size_changed = TRUE;
1520 gtk_toolbar_stop_sliding (toolbar);
1522 gtk_widget_set_allocation (widget, allocation);
1524 border_width = gtk_container_get_border_width (GTK_CONTAINER (toolbar));
1526 if (gtk_widget_get_realized (widget))
1527 gdk_window_move_resize (priv->event_window,
1528 allocation->x + border_width,
1529 allocation->y + border_width,
1530 allocation->width - border_width * 2,
1531 allocation->height - border_width * 2);
1533 border_width += get_internal_padding (toolbar);
1535 gtk_widget_get_preferred_size (priv->arrow_button,
1536 &arrow_requisition, NULL);
1538 shadow_type = get_shadow_type (toolbar);
1540 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1542 available_size = size = allocation->width - 2 * border_width;
1543 short_size = allocation->height - 2 * border_width;
1544 arrow_size = arrow_requisition.width;
1546 if (shadow_type != GTK_SHADOW_NONE)
1548 available_size -= padding.left + padding.right;
1549 short_size -= padding.top + padding.bottom;
1554 available_size = size = allocation->height - 2 * border_width;
1555 short_size = allocation->width - 2 * border_width;
1556 arrow_size = arrow_requisition.height;
1558 if (shadow_type != GTK_SHADOW_NONE)
1560 available_size -= padding.top + padding.bottom;
1561 short_size -= padding.left + padding.right;
1565 n_items = g_list_length (priv->content);
1566 allocations = g_new0 (GtkAllocation, n_items);
1567 new_states = g_new0 (ItemState, n_items);
1571 for (list = priv->content; list != NULL; list = list->next)
1573 ToolbarContent *content = list->data;
1575 if (toolbar_content_visible (content, toolbar))
1577 needed_size += get_item_size (toolbar, content);
1579 /* Do we need an arrow?
1581 * Assume we don't, and see if any non-separator item
1582 * with a proxy menu item is then going to overflow.
1584 if (needed_size > available_size &&
1587 toolbar_content_has_proxy_menu_item (content) &&
1588 !toolbar_content_is_separator (content))
1596 size = available_size - arrow_size;
1598 size = available_size;
1600 /* calculate widths and states of items */
1601 overflowing = FALSE;
1602 for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1604 ToolbarContent *content = list->data;
1607 if (!toolbar_content_visible (content, toolbar))
1609 new_states[i] = HIDDEN;
1613 item_size = get_item_size (toolbar, content);
1614 if (item_size <= size && !overflowing)
1617 allocations[i].width = item_size;
1618 new_states[i] = NORMAL;
1623 new_states[i] = OVERFLOWN;
1624 allocations[i].width = item_size;
1628 /* calculate width of arrow */
1631 arrow_allocation.width = arrow_size;
1632 arrow_allocation.height = MAX (short_size, 1);
1635 /* expand expandable items */
1637 /* We don't expand when there is an overflow menu,
1638 * because that leads to weird jumps when items get
1639 * moved to the overflow menu and the expanding
1640 * items suddenly get a lot of extra space
1644 gint max_child_expand;
1647 for (i = 0, list = priv->content; list != NULL; list = list->next, ++i)
1649 ToolbarContent *content = list->data;
1651 if (toolbar_content_get_expand (content) && new_states[i] == NORMAL)
1655 max_child_expand = get_max_child_expand (toolbar);
1656 for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1658 ToolbarContent *content = list->data;
1660 if (toolbar_content_get_expand (content) && new_states[i] == NORMAL)
1662 gint extra = size / n_expand_items;
1663 if (size % n_expand_items != 0)
1666 if (extra > max_child_expand)
1667 extra = max_child_expand;
1669 allocations[i].width += extra;
1675 g_assert (n_expand_items == 0);
1678 /* position items */
1680 for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1682 /* Both NORMAL and OVERFLOWN items get a position.
1683 * This ensures that sliding will work for OVERFLOWN items too.
1685 if (new_states[i] == NORMAL || new_states[i] == OVERFLOWN)
1687 allocations[i].x = pos;
1688 allocations[i].y = border_width;
1689 allocations[i].height = short_size;
1691 pos += allocations[i].width;
1695 /* position arrow */
1698 arrow_allocation.x = available_size - border_width - arrow_allocation.width;
1699 arrow_allocation.y = border_width;
1702 item_area.x = border_width;
1703 item_area.y = border_width;
1704 item_area.width = available_size - (need_arrow? arrow_size : 0);
1705 item_area.height = short_size;
1707 /* fix up allocations in the vertical or RTL cases */
1708 if (priv->orientation == GTK_ORIENTATION_VERTICAL)
1710 for (i = 0; i < n_items; ++i)
1711 fixup_allocation_for_vertical (&(allocations[i]));
1714 fixup_allocation_for_vertical (&arrow_allocation);
1716 fixup_allocation_for_vertical (&item_area);
1718 else if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1720 for (i = 0; i < n_items; ++i)
1721 fixup_allocation_for_rtl (available_size, &(allocations[i]));
1724 fixup_allocation_for_rtl (available_size, &arrow_allocation);
1726 fixup_allocation_for_rtl (available_size, &item_area);
1729 /* translate the items by allocation->(x,y) */
1730 for (i = 0; i < n_items; ++i)
1732 allocations[i].x += allocation->x;
1733 allocations[i].y += allocation->y;
1735 if (shadow_type != GTK_SHADOW_NONE)
1737 allocations[i].x += padding.left;
1738 allocations[i].y += padding.top;
1744 arrow_allocation.x += allocation->x;
1745 arrow_allocation.y += allocation->y;
1747 if (shadow_type != GTK_SHADOW_NONE)
1749 arrow_allocation.x += padding.left;
1750 arrow_allocation.y += padding.top;
1754 item_area.x += allocation->x;
1755 item_area.y += allocation->y;
1756 if (shadow_type != GTK_SHADOW_NONE)
1758 item_area.x += padding.left;
1759 item_area.y += padding.top;
1762 /* did anything change? */
1763 for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1765 ToolbarContent *content = list->data;
1767 if (toolbar_content_get_state (content) == NORMAL &&
1768 new_states[i] != NORMAL)
1770 /* an item disappeared and we didn't change size, so begin sliding */
1772 gtk_toolbar_begin_sliding (toolbar);
1776 /* finally allocate the items */
1777 if (priv->is_sliding)
1779 for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1781 ToolbarContent *content = list->data;
1783 toolbar_content_set_goal_allocation (content, &(allocations[i]));
1787 for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1789 ToolbarContent *content = list->data;
1791 if (new_states[i] == OVERFLOWN || new_states[i] == NORMAL)
1793 GtkAllocation alloc;
1794 GtkAllocation start_allocation = { 0, };
1795 GtkAllocation goal_allocation;
1797 if (priv->is_sliding)
1799 toolbar_content_get_start_allocation (content, &start_allocation);
1800 toolbar_content_get_goal_allocation (content, &goal_allocation);
1802 compute_intermediate_allocation (toolbar,
1807 priv->need_sync = TRUE;
1811 alloc = allocations[i];
1814 if (alloc.width <= 0 || alloc.height <= 0)
1816 toolbar_content_set_child_visible (content, toolbar, FALSE);
1820 if (!rect_within (&alloc, &item_area))
1822 toolbar_content_set_child_visible (content, toolbar, FALSE);
1823 toolbar_content_size_allocate (content, &alloc);
1827 toolbar_content_set_child_visible (content, toolbar, TRUE);
1828 toolbar_content_size_allocate (content, &alloc);
1834 toolbar_content_set_child_visible (content, toolbar, FALSE);
1837 toolbar_content_set_state (content, new_states[i]);
1840 if (priv->menu && priv->need_rebuild)
1841 rebuild_menu (toolbar);
1845 gtk_widget_size_allocate (GTK_WIDGET (priv->arrow_button),
1847 gtk_widget_show (GTK_WIDGET (priv->arrow_button));
1851 gtk_widget_hide (GTK_WIDGET (priv->arrow_button));
1853 if (priv->menu && gtk_widget_get_visible (GTK_WIDGET (priv->menu)))
1854 gtk_menu_shell_deactivate (GTK_MENU_SHELL (priv->menu));
1857 g_free (allocations);
1858 g_free (new_states);
1862 gtk_toolbar_update_button_relief (GtkToolbar *toolbar)
1864 GtkToolbarPrivate *priv = toolbar->priv;
1865 GtkReliefStyle relief;
1867 relief = get_button_relief (toolbar);
1869 if (relief != gtk_button_get_relief (GTK_BUTTON (priv->arrow_button)))
1871 gtk_toolbar_reconfigured (toolbar);
1873 gtk_button_set_relief (GTK_BUTTON (priv->arrow_button), relief);
1878 gtk_toolbar_style_updated (GtkWidget *widget)
1880 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1881 GtkToolbarPrivate *priv = toolbar->priv;
1883 GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->style_updated (widget);
1885 priv->max_homogeneous_pixels = -1;
1887 if (gtk_widget_get_realized (widget))
1888 gtk_style_context_set_background (gtk_widget_get_style_context (widget),
1889 gtk_widget_get_window (widget));
1891 gtk_toolbar_update_button_relief (GTK_TOOLBAR (widget));
1895 gtk_toolbar_list_children_in_focus_order (GtkToolbar *toolbar,
1896 GtkDirectionType dir)
1898 GtkToolbarPrivate *priv = toolbar->priv;
1899 GList *result = NULL;
1903 /* generate list of children in reverse logical order */
1905 for (list = priv->content; list != NULL; list = list->next)
1907 ToolbarContent *content = list->data;
1910 widget = toolbar_content_get_widget (content);
1913 result = g_list_prepend (result, widget);
1916 result = g_list_prepend (result, priv->arrow_button);
1918 rtl = (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL);
1920 /* move in logical order when
1922 * - dir is TAB_FORWARD
1924 * - in RTL mode and moving left or up
1926 * - in LTR mode and moving right or down
1928 if (dir == GTK_DIR_TAB_FORWARD ||
1929 (rtl && (dir == GTK_DIR_UP || dir == GTK_DIR_LEFT)) ||
1930 (!rtl && (dir == GTK_DIR_DOWN || dir == GTK_DIR_RIGHT)))
1932 result = g_list_reverse (result);
1939 gtk_toolbar_focus_home_or_end (GtkToolbar *toolbar,
1940 gboolean focus_home)
1942 GList *children, *list;
1943 GtkDirectionType dir = focus_home? GTK_DIR_RIGHT : GTK_DIR_LEFT;
1945 children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1947 if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1949 children = g_list_reverse (children);
1951 dir = (dir == GTK_DIR_RIGHT)? GTK_DIR_LEFT : GTK_DIR_RIGHT;
1954 for (list = children; list != NULL; list = list->next)
1956 GtkWidget *child = list->data;
1958 if (gtk_container_get_focus_child (GTK_CONTAINER (toolbar)) == child)
1961 if (gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
1965 g_list_free (children);
1970 /* Keybinding handler. This function is called when the user presses
1971 * Ctrl TAB or an arrow key.
1974 gtk_toolbar_move_focus (GtkWidget *widget,
1975 GtkDirectionType dir)
1977 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1978 GtkContainer *container = GTK_CONTAINER (toolbar);
1979 GtkWidget *focus_child;
1981 gboolean try_focus = FALSE;
1984 focus_child = gtk_container_get_focus_child (container);
1986 if (focus_child && gtk_widget_child_focus (focus_child, dir))
1989 children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1991 for (list = children; list != NULL; list = list->next)
1993 GtkWidget *child = list->data;
1995 if (try_focus && gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
1998 if (child == focus_child)
2002 g_list_free (children);
2005 /* The focus handler for the toolbar. It called when the user presses
2006 * TAB or otherwise tries to focus the toolbar.
2009 gtk_toolbar_focus (GtkWidget *widget,
2010 GtkDirectionType dir)
2012 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
2013 GList *children, *list;
2014 gboolean result = FALSE;
2016 /* if focus is already somewhere inside the toolbar then return FALSE.
2017 * The only way focus can stay inside the toolbar is when the user presses
2018 * arrow keys or Ctrl TAB (both of which are handled by the
2019 * gtk_toolbar_move_focus() keybinding function.
2021 if (gtk_container_get_focus_child (GTK_CONTAINER (widget)))
2024 children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
2026 for (list = children; list != NULL; list = list->next)
2028 GtkWidget *child = list->data;
2030 if (gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
2037 g_list_free (children);
2042 static GtkSettings *
2043 toolbar_get_settings (GtkToolbar *toolbar)
2045 return toolbar->priv->settings;
2049 style_change_notify (GtkToolbar *toolbar)
2051 GtkToolbarPrivate *priv = toolbar->priv;
2053 if (!priv->style_set)
2055 /* pretend it was set, then unset, thus reverting to new default */
2056 priv->style_set = TRUE;
2057 gtk_toolbar_unset_style (toolbar);
2062 icon_size_change_notify (GtkToolbar *toolbar)
2064 GtkToolbarPrivate *priv = toolbar->priv;
2066 if (!priv->icon_size_set)
2068 /* pretend it was set, then unset, thus reverting to new default */
2069 priv->icon_size_set = TRUE;
2070 gtk_toolbar_unset_icon_size (toolbar);
2075 animation_change_notify (GtkToolbar *toolbar)
2077 GtkToolbarPrivate *priv = toolbar->priv;
2078 GtkSettings *settings = toolbar_get_settings (toolbar);
2082 g_object_get (settings,
2083 "gtk-enable-animations", &animation,
2086 animation = DEFAULT_ANIMATION_STATE;
2088 priv->animation = animation;
2092 settings_change_notify (GtkSettings *settings,
2093 const GParamSpec *pspec,
2094 GtkToolbar *toolbar)
2096 if (! strcmp (pspec->name, "gtk-toolbar-style"))
2097 style_change_notify (toolbar);
2098 else if (! strcmp (pspec->name, "gtk-toolbar-icon-size"))
2099 icon_size_change_notify (toolbar);
2100 else if (! strcmp (pspec->name, "gtk-enable-animations"))
2101 animation_change_notify (toolbar);
2105 gtk_toolbar_screen_changed (GtkWidget *widget,
2106 GdkScreen *previous_screen)
2108 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
2109 GtkToolbarPrivate *priv = toolbar->priv;
2110 GtkSettings *old_settings = toolbar_get_settings (toolbar);
2111 GtkSettings *settings;
2113 if (gtk_widget_has_screen (GTK_WIDGET (toolbar)))
2114 settings = gtk_widget_get_settings (GTK_WIDGET (toolbar));
2118 if (settings == old_settings)
2123 g_signal_handler_disconnect (old_settings, priv->settings_connection);
2125 g_object_unref (old_settings);
2130 priv->settings_connection =
2131 g_signal_connect (settings, "notify",
2132 G_CALLBACK (settings_change_notify),
2135 priv->settings = g_object_ref (settings);
2138 priv->settings = NULL;
2140 style_change_notify (toolbar);
2141 icon_size_change_notify (toolbar);
2142 animation_change_notify (toolbar);
2146 find_drop_index (GtkToolbar *toolbar,
2150 GtkToolbarPrivate *priv = toolbar->priv;
2151 GList *interesting_content;
2153 GtkOrientation orientation;
2154 GtkTextDirection direction;
2155 gint best_distance = G_MAXINT;
2159 ToolbarContent *best_content;
2160 GtkAllocation allocation;
2162 /* list items we care about wrt. drag and drop */
2163 interesting_content = NULL;
2164 for (list = priv->content; list != NULL; list = list->next)
2166 ToolbarContent *content = list->data;
2168 if (toolbar_content_get_state (content) == NORMAL)
2169 interesting_content = g_list_prepend (interesting_content, content);
2171 interesting_content = g_list_reverse (interesting_content);
2173 if (!interesting_content)
2176 orientation = priv->orientation;
2177 direction = gtk_widget_get_direction (GTK_WIDGET (toolbar));
2179 /* distance to first interesting item */
2180 best_content = interesting_content->data;
2181 toolbar_content_get_allocation (best_content, &allocation);
2183 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2187 if (direction == GTK_TEXT_DIR_LTR)
2190 pos = allocation.x + allocation.width;
2198 best_content = NULL;
2199 best_distance = ABS (pos - cursor);
2201 /* distance to far end of each item */
2202 for (list = interesting_content; list != NULL; list = list->next)
2204 ToolbarContent *content = list->data;
2206 toolbar_content_get_allocation (content, &allocation);
2208 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2210 if (direction == GTK_TEXT_DIR_LTR)
2211 pos = allocation.x + allocation.width;
2217 pos = allocation.y + allocation.height;
2220 distance = ABS (pos - cursor);
2222 if (distance < best_distance)
2224 best_distance = distance;
2225 best_content = content;
2229 g_list_free (interesting_content);
2234 return g_list_index (priv->content, best_content) + 1;
2238 reset_all_placeholders (GtkToolbar *toolbar)
2240 GtkToolbarPrivate *priv = toolbar->priv;
2243 for (list = priv->content; list != NULL; list = list->next)
2245 ToolbarContent *content = list->data;
2246 if (toolbar_content_is_placeholder (content))
2247 toolbar_content_set_disappearing (content, TRUE);
2252 physical_to_logical (GtkToolbar *toolbar,
2255 GtkToolbarPrivate *priv = toolbar->priv;
2259 g_assert (physical >= 0);
2262 for (list = priv->content; list && physical > 0; list = list->next)
2264 ToolbarContent *content = list->data;
2266 if (!toolbar_content_is_placeholder (content))
2271 g_assert (physical == 0);
2277 logical_to_physical (GtkToolbar *toolbar,
2280 GtkToolbarPrivate *priv = toolbar->priv;
2284 g_assert (logical >= 0);
2287 for (list = priv->content; list; list = list->next)
2289 ToolbarContent *content = list->data;
2291 if (!toolbar_content_is_placeholder (content))
2301 g_assert (logical == 0);
2307 * gtk_toolbar_set_drop_highlight_item:
2308 * @toolbar: a #GtkToolbar
2309 * @tool_item: (allow-none): a #GtkToolItem, or %NULL to turn of highlighting
2310 * @index_: a position on @toolbar
2312 * Highlights @toolbar to give an idea of what it would look like
2313 * if @item was added to @toolbar at the position indicated by @index_.
2314 * If @item is %NULL, highlighting is turned off. In that case @index_
2317 * The @tool_item passed to this function must not be part of any widget
2318 * hierarchy. When an item is set as drop highlight item it can not
2319 * added to any widget hierarchy or used as highlight item for another
2325 gtk_toolbar_set_drop_highlight_item (GtkToolbar *toolbar,
2326 GtkToolItem *tool_item,
2329 ToolbarContent *content;
2330 GtkToolbarPrivate *priv;
2332 GtkRequisition requisition;
2333 GtkRequisition old_requisition;
2334 gboolean restart_sliding;
2336 g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2337 g_return_if_fail (tool_item == NULL || GTK_IS_TOOL_ITEM (tool_item));
2339 priv = toolbar->priv;
2343 if (priv->highlight_tool_item)
2345 gtk_widget_unparent (GTK_WIDGET (priv->highlight_tool_item));
2346 g_object_unref (priv->highlight_tool_item);
2347 priv->highlight_tool_item = NULL;
2350 reset_all_placeholders (toolbar);
2351 gtk_toolbar_begin_sliding (toolbar);
2355 n_items = gtk_toolbar_get_n_items (toolbar);
2356 if (index_ < 0 || index_ > n_items)
2359 if (tool_item != priv->highlight_tool_item)
2361 if (priv->highlight_tool_item)
2362 g_object_unref (priv->highlight_tool_item);
2364 g_object_ref_sink (tool_item);
2366 priv->highlight_tool_item = tool_item;
2368 gtk_widget_set_parent (GTK_WIDGET (priv->highlight_tool_item),
2369 GTK_WIDGET (toolbar));
2372 index_ = logical_to_physical (toolbar, index_);
2374 content = g_list_nth_data (priv->content, index_);
2378 ToolbarContent *prev_content;
2380 prev_content = g_list_nth_data (priv->content, index_ - 1);
2382 if (prev_content && toolbar_content_is_placeholder (prev_content))
2383 content = prev_content;
2386 if (!content || !toolbar_content_is_placeholder (content))
2388 GtkWidget *placeholder;
2390 placeholder = GTK_WIDGET (gtk_separator_tool_item_new ());
2392 content = toolbar_content_new_tool_item (toolbar,
2393 GTK_TOOL_ITEM (placeholder),
2395 gtk_widget_show (placeholder);
2399 g_assert (toolbar_content_is_placeholder (content));
2401 gtk_widget_get_preferred_size (GTK_WIDGET (priv->highlight_tool_item),
2402 &requisition, NULL);
2404 toolbar_content_set_expand (content, gtk_tool_item_get_expand (tool_item));
2406 restart_sliding = FALSE;
2407 toolbar_content_size_request (content, toolbar, &old_requisition);
2408 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2410 requisition.height = -1;
2411 if (requisition.width != old_requisition.width)
2412 restart_sliding = TRUE;
2416 requisition.width = -1;
2417 if (requisition.height != old_requisition.height)
2418 restart_sliding = TRUE;
2421 if (toolbar_content_disappearing (content))
2422 restart_sliding = TRUE;
2424 reset_all_placeholders (toolbar);
2425 toolbar_content_set_disappearing (content, FALSE);
2427 toolbar_content_set_size_request (content,
2428 requisition.width, requisition.height);
2430 if (restart_sliding)
2431 gtk_toolbar_begin_sliding (toolbar);
2435 gtk_toolbar_get_child_property (GtkContainer *container,
2441 GtkToolItem *item = GTK_TOOL_ITEM (child);
2443 switch (property_id)
2445 case CHILD_PROP_HOMOGENEOUS:
2446 g_value_set_boolean (value, gtk_tool_item_get_homogeneous (item));
2449 case CHILD_PROP_EXPAND:
2450 g_value_set_boolean (value, gtk_tool_item_get_expand (item));
2454 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2460 gtk_toolbar_set_child_property (GtkContainer *container,
2463 const GValue *value,
2466 switch (property_id)
2468 case CHILD_PROP_HOMOGENEOUS:
2469 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2472 case CHILD_PROP_EXPAND:
2473 gtk_tool_item_set_expand (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2477 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2483 gtk_toolbar_show_all (GtkWidget *widget)
2485 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
2486 GtkToolbarPrivate *priv = toolbar->priv;
2489 for (list = priv->content; list != NULL; list = list->next)
2491 ToolbarContent *content = list->data;
2493 toolbar_content_show_all (content);
2496 gtk_widget_show (widget);
2500 gtk_toolbar_add (GtkContainer *container,
2503 GtkToolbar *toolbar = GTK_TOOLBAR (container);
2505 gtk_toolbar_insert (toolbar, GTK_TOOL_ITEM (widget), -1);
2509 gtk_toolbar_remove (GtkContainer *container,
2512 GtkToolbar *toolbar = GTK_TOOLBAR (container);
2513 GtkToolbarPrivate *priv = toolbar->priv;
2514 ToolbarContent *content_to_remove;
2517 content_to_remove = NULL;
2518 for (list = priv->content; list != NULL; list = list->next)
2520 ToolbarContent *content = list->data;
2523 child = toolbar_content_get_widget (content);
2524 if (child && child == widget)
2526 content_to_remove = content;
2531 g_return_if_fail (content_to_remove != NULL);
2533 toolbar_content_remove (content_to_remove, toolbar);
2534 toolbar_content_free (content_to_remove);
2538 gtk_toolbar_forall (GtkContainer *container,
2539 gboolean include_internals,
2540 GtkCallback callback,
2541 gpointer callback_data)
2543 GtkToolbar *toolbar = GTK_TOOLBAR (container);
2544 GtkToolbarPrivate *priv = toolbar->priv;
2547 g_return_if_fail (callback != NULL);
2549 list = priv->content;
2552 ToolbarContent *content = list->data;
2553 GList *next = list->next;
2555 if (include_internals || !toolbar_content_is_placeholder (content))
2557 GtkWidget *child = toolbar_content_get_widget (content);
2560 callback (child, callback_data);
2566 if (include_internals)
2567 callback (priv->arrow_button, callback_data);
2571 gtk_toolbar_child_type (GtkContainer *container)
2573 return GTK_TYPE_TOOL_ITEM;
2577 gtk_toolbar_reconfigured (GtkToolbar *toolbar)
2579 GtkToolbarPrivate *priv = toolbar->priv;
2582 list = priv->content;
2585 ToolbarContent *content = list->data;
2586 GList *next = list->next;
2588 toolbar_content_toolbar_reconfigured (content, toolbar);
2595 gtk_toolbar_orientation_changed (GtkToolbar *toolbar,
2596 GtkOrientation orientation)
2598 GtkToolbarPrivate *priv = toolbar->priv;
2600 if (priv->orientation != orientation)
2602 priv->orientation = orientation;
2604 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2605 gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
2607 gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
2609 gtk_toolbar_reconfigured (toolbar);
2611 gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2612 g_object_notify (G_OBJECT (toolbar), "orientation");
2617 gtk_toolbar_real_style_changed (GtkToolbar *toolbar,
2618 GtkToolbarStyle style)
2620 GtkToolbarPrivate *priv = toolbar->priv;
2622 if (priv->style != style)
2624 priv->style = style;
2626 gtk_toolbar_reconfigured (toolbar);
2628 gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2629 g_object_notify (G_OBJECT (toolbar), "toolbar-style");
2634 menu_position_func (GtkMenu *menu,
2640 GtkAllocation allocation;
2641 GtkToolbar *toolbar = GTK_TOOLBAR (user_data);
2642 GtkToolbarPrivate *priv = toolbar->priv;
2644 GtkRequisition menu_req;
2645 GdkRectangle monitor;
2649 gtk_widget_get_preferred_size (priv->arrow_button,
2651 gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2654 screen = gtk_widget_get_screen (GTK_WIDGET (menu));
2655 monitor_num = gdk_screen_get_monitor_at_window (screen,
2656 gtk_widget_get_window (priv->arrow_button));
2657 if (monitor_num < 0)
2659 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
2661 gtk_widget_get_allocation (priv->arrow_button, &allocation);
2663 gdk_window_get_origin (gtk_button_get_event_window (GTK_BUTTON (priv->arrow_button)), x, y);
2664 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2666 if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR)
2667 *x += allocation.width - req.width;
2669 *x += req.width - menu_req.width;
2671 if ((*y + allocation.height + menu_req.height) <= monitor.y + monitor.height)
2672 *y += allocation.height;
2673 else if ((*y - menu_req.height) >= monitor.y)
2674 *y -= menu_req.height;
2675 else if (monitor.y + monitor.height - (*y + allocation.height) > *y)
2676 *y += allocation.height;
2678 *y -= menu_req.height;
2682 if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR)
2683 *x += allocation.width;
2685 *x -= menu_req.width;
2687 if (*y + menu_req.height > monitor.y + monitor.height &&
2688 *y + allocation.height - monitor.y > monitor.y + monitor.height - *y)
2689 *y += allocation.height - menu_req.height;
2696 show_menu (GtkToolbar *toolbar,
2697 GdkEventButton *event)
2699 GtkToolbarPrivate *priv = toolbar->priv;
2701 rebuild_menu (toolbar);
2703 gtk_widget_show_all (GTK_WIDGET (priv->menu));
2705 gtk_menu_popup (priv->menu, NULL, NULL,
2706 menu_position_func, toolbar,
2707 event? event->button : 0,
2708 event? event->time : gtk_get_current_event_time());
2712 gtk_toolbar_arrow_button_clicked (GtkWidget *button,
2713 GtkToolbar *toolbar)
2715 GtkToolbarPrivate *priv = toolbar->priv;
2717 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->arrow_button)) &&
2718 (!priv->menu || !gtk_widget_get_visible (GTK_WIDGET (priv->menu))))
2720 /* We only get here when the button is clicked with the keyboard,
2721 * because mouse button presses result in the menu being shown so
2722 * that priv->menu would be non-NULL and visible.
2724 show_menu (toolbar, NULL);
2725 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2730 gtk_toolbar_arrow_button_press (GtkWidget *button,
2731 GdkEventButton *event,
2732 GtkToolbar *toolbar)
2734 show_menu (toolbar, event);
2735 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2741 gtk_toolbar_button_press (GtkWidget *toolbar,
2742 GdkEventButton *event)
2746 if (event->button == 3)
2748 gboolean return_value;
2750 g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2751 (int)event->x_root, (int)event->y_root, event->button,
2754 return return_value;
2757 window = gtk_widget_get_toplevel (toolbar);
2761 gboolean window_drag = FALSE;
2763 gtk_widget_style_get (toolbar,
2764 "window-dragging", &window_drag,
2769 gtk_window_begin_move_drag (GTK_WINDOW (window),
2783 gtk_toolbar_popup_menu (GtkWidget *toolbar)
2785 gboolean return_value;
2786 /* This function is the handler for the "popup menu" keybinding,
2787 * ie., it is called when the user presses Shift F10
2789 g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2790 -1, -1, -1, &return_value);
2792 return return_value;
2798 * Creates a new toolbar.
2800 * Return Value: the newly-created toolbar.
2803 gtk_toolbar_new (void)
2805 GtkToolbar *toolbar;
2807 toolbar = g_object_new (GTK_TYPE_TOOLBAR, NULL);
2809 return GTK_WIDGET (toolbar);
2813 * gtk_toolbar_insert:
2814 * @toolbar: a #GtkToolbar
2815 * @item: a #GtkToolItem
2816 * @pos: the position of the new item
2818 * Insert a #GtkToolItem into the toolbar at position @pos. If @pos is
2819 * 0 the item is prepended to the start of the toolbar. If @pos is
2820 * negative, the item is appended to the end of the toolbar.
2825 gtk_toolbar_insert (GtkToolbar *toolbar,
2829 g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2830 g_return_if_fail (GTK_IS_TOOL_ITEM (item));
2833 pos = logical_to_physical (toolbar, pos);
2835 toolbar_content_new_tool_item (toolbar, item, FALSE, pos);
2839 * gtk_toolbar_get_item_index:
2840 * @toolbar: a #GtkToolbar
2841 * @item: a #GtkToolItem that is a child of @toolbar
2843 * Returns the position of @item on the toolbar, starting from 0.
2844 * It is an error if @item is not a child of the toolbar.
2846 * Return value: the position of item on the toolbar.
2851 gtk_toolbar_get_item_index (GtkToolbar *toolbar,
2854 GtkToolbarPrivate *priv;
2858 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2859 g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1);
2860 g_return_val_if_fail (gtk_widget_get_parent (GTK_WIDGET (item)) == GTK_WIDGET (toolbar), -1);
2862 priv = toolbar->priv;
2865 for (list = priv->content; list != NULL; list = list->next)
2867 ToolbarContent *content = list->data;
2870 widget = toolbar_content_get_widget (content);
2872 if (item == GTK_TOOL_ITEM (widget))
2878 return physical_to_logical (toolbar, n);
2882 * gtk_toolbar_set_style:
2883 * @toolbar: a #GtkToolbar.
2884 * @style: the new style for @toolbar.
2886 * Alters the view of @toolbar to display either icons only, text only, or both.
2889 gtk_toolbar_set_style (GtkToolbar *toolbar,
2890 GtkToolbarStyle style)
2892 GtkToolbarPrivate *priv;
2894 g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2896 priv = toolbar->priv;
2898 priv->style_set = TRUE;
2899 g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2903 * gtk_toolbar_get_style:
2904 * @toolbar: a #GtkToolbar
2906 * Retrieves whether the toolbar has text, icons, or both . See
2907 * gtk_toolbar_set_style().
2909 * Return value: the current style of @toolbar
2912 gtk_toolbar_get_style (GtkToolbar *toolbar)
2914 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE);
2916 return toolbar->priv->style;
2920 * gtk_toolbar_unset_style:
2921 * @toolbar: a #GtkToolbar
2923 * Unsets a toolbar style set with gtk_toolbar_set_style(), so that
2924 * user preferences will be used to determine the toolbar style.
2927 gtk_toolbar_unset_style (GtkToolbar *toolbar)
2929 GtkToolbarPrivate *priv;
2930 GtkToolbarStyle style;
2932 g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2934 priv = toolbar->priv;
2936 if (priv->style_set)
2938 GtkSettings *settings = toolbar_get_settings (toolbar);
2941 g_object_get (settings,
2942 "gtk-toolbar-style", &style,
2945 style = DEFAULT_TOOLBAR_STYLE;
2947 if (style != priv->style)
2948 g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2950 priv->style_set = FALSE;
2955 * gtk_toolbar_get_n_items:
2956 * @toolbar: a #GtkToolbar
2958 * Returns the number of items on the toolbar.
2960 * Return value: the number of items on the toolbar
2965 gtk_toolbar_get_n_items (GtkToolbar *toolbar)
2967 GtkToolbarPrivate *priv;
2969 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2971 priv = toolbar->priv;
2973 return physical_to_logical (toolbar, g_list_length (priv->content));
2977 * gtk_toolbar_get_nth_item:
2978 * @toolbar: a #GtkToolbar
2979 * @n: A position on the toolbar
2981 * Returns the @n<!-- -->'th item on @toolbar, or %NULL if the
2982 * toolbar does not contain an @n<!-- -->'th item.
2984 * Return value: (transfer none): The @n<!-- -->'th #GtkToolItem on @toolbar,
2985 * or %NULL if there isn't an @n<!-- -->'th item.
2990 gtk_toolbar_get_nth_item (GtkToolbar *toolbar,
2993 GtkToolbarPrivate *priv;
2994 ToolbarContent *content;
2997 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
2999 priv = toolbar->priv;
3001 n_items = gtk_toolbar_get_n_items (toolbar);
3003 if (n < 0 || n >= n_items)
3006 content = g_list_nth_data (priv->content, logical_to_physical (toolbar, n));
3009 g_assert (!toolbar_content_is_placeholder (content));
3011 return GTK_TOOL_ITEM (toolbar_content_get_widget (content));
3015 * gtk_toolbar_get_icon_size:
3016 * @toolbar: a #GtkToolbar
3018 * Retrieves the icon size for the toolbar. See gtk_toolbar_set_icon_size().
3020 * Return value: (type int): the current icon size for the icons on
3024 gtk_toolbar_get_icon_size (GtkToolbar *toolbar)
3026 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_ICON_SIZE);
3028 return toolbar->priv->icon_size;
3032 * gtk_toolbar_get_relief_style:
3033 * @toolbar: a #GtkToolbar
3035 * Returns the relief style of buttons on @toolbar. See
3036 * gtk_button_set_relief().
3038 * Return value: The relief style of buttons on @toolbar.
3043 gtk_toolbar_get_relief_style (GtkToolbar *toolbar)
3045 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_RELIEF_NONE);
3047 return get_button_relief (toolbar);
3051 * gtk_toolbar_set_show_arrow:
3052 * @toolbar: a #GtkToolbar
3053 * @show_arrow: Whether to show an overflow menu
3055 * Sets whether to show an overflow menu when
3056 * @toolbar doesn't have room for all items on it. If %TRUE,
3057 * items that there are not room are available through an
3063 gtk_toolbar_set_show_arrow (GtkToolbar *toolbar,
3064 gboolean show_arrow)
3066 GtkToolbarPrivate *priv;
3068 g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3070 priv = toolbar->priv;
3072 show_arrow = show_arrow != FALSE;
3074 if (priv->show_arrow != show_arrow)
3076 priv->show_arrow = show_arrow;
3078 if (!priv->show_arrow)
3079 gtk_widget_hide (priv->arrow_button);
3081 gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3082 g_object_notify (G_OBJECT (toolbar), "show-arrow");
3087 * gtk_toolbar_get_show_arrow:
3088 * @toolbar: a #GtkToolbar
3090 * Returns whether the toolbar has an overflow menu.
3091 * See gtk_toolbar_set_show_arrow().
3093 * Return value: %TRUE if the toolbar has an overflow menu.
3098 gtk_toolbar_get_show_arrow (GtkToolbar *toolbar)
3100 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
3102 return toolbar->priv->show_arrow;
3106 * gtk_toolbar_get_drop_index:
3107 * @toolbar: a #GtkToolbar
3108 * @x: x coordinate of a point on the toolbar
3109 * @y: y coordinate of a point on the toolbar
3111 * Returns the position corresponding to the indicated point on
3112 * @toolbar. This is useful when dragging items to the toolbar:
3113 * this function returns the position a new item should be
3116 * @x and @y are in @toolbar coordinates.
3118 * Return value: The position corresponding to the point (@x, @y) on the toolbar.
3123 gtk_toolbar_get_drop_index (GtkToolbar *toolbar,
3127 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
3129 return physical_to_logical (toolbar, find_drop_index (toolbar, x, y));
3133 gtk_toolbar_finalize (GObject *object)
3136 GtkToolbar *toolbar = GTK_TOOLBAR (object);
3137 GtkToolbarPrivate *priv = toolbar->priv;
3139 if (priv->arrow_button)
3140 gtk_widget_unparent (priv->arrow_button);
3142 if (priv->sibling_path != NULL)
3144 gtk_widget_path_unref (priv->sibling_path);
3145 priv->sibling_path = NULL;
3148 for (list = priv->content; list != NULL; list = list->next)
3150 ToolbarContent *content = list->data;
3152 toolbar_content_free (content);
3155 g_list_free (priv->content);
3157 g_timer_destroy (priv->timer);
3161 g_signal_handlers_disconnect_by_func (priv->menu,
3162 menu_deactivated, toolbar);
3163 gtk_widget_destroy (GTK_WIDGET (priv->menu));
3167 g_source_remove (priv->idle_id);
3169 G_OBJECT_CLASS (gtk_toolbar_parent_class)->finalize (object);
3173 * gtk_toolbar_set_icon_size:
3174 * @toolbar: A #GtkToolbar
3175 * @icon_size: (type int): The #GtkIconSize that stock icons in the
3176 * toolbar shall have.
3178 * This function sets the size of stock icons in the toolbar. You
3179 * can call it both before you add the icons and after they've been
3180 * added. The size you set will override user preferences for the default
3183 * This should only be used for special-purpose toolbars, normal
3184 * application toolbars should respect the user preferences for the
3188 gtk_toolbar_set_icon_size (GtkToolbar *toolbar,
3189 GtkIconSize icon_size)
3191 GtkToolbarPrivate *priv;
3193 g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3194 g_return_if_fail (icon_size != GTK_ICON_SIZE_INVALID);
3196 priv = toolbar->priv;
3198 if (!priv->icon_size_set)
3200 priv->icon_size_set = TRUE;
3201 g_object_notify (G_OBJECT (toolbar), "icon-size-set");
3204 if (priv->icon_size == icon_size)
3207 priv->icon_size = icon_size;
3208 g_object_notify (G_OBJECT (toolbar), "icon-size");
3210 gtk_toolbar_reconfigured (toolbar);
3212 gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3216 * gtk_toolbar_unset_icon_size:
3217 * @toolbar: a #GtkToolbar
3219 * Unsets toolbar icon size set with gtk_toolbar_set_icon_size(), so that
3220 * user preferences will be used to determine the icon size.
3223 gtk_toolbar_unset_icon_size (GtkToolbar *toolbar)
3225 GtkToolbarPrivate *priv;
3228 g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3230 priv = toolbar->priv;
3232 if (priv->icon_size_set)
3234 GtkSettings *settings = toolbar_get_settings (toolbar);
3238 g_object_get (settings,
3239 "gtk-toolbar-icon-size", &size,
3243 size = DEFAULT_ICON_SIZE;
3245 if (size != priv->icon_size)
3247 gtk_toolbar_set_icon_size (toolbar, size);
3248 g_object_notify (G_OBJECT (toolbar), "icon-size");
3251 priv->icon_size_set = FALSE;
3252 g_object_notify (G_OBJECT (toolbar), "icon-size-set");
3257 * ToolbarContent methods
3265 struct _ToolbarContent
3270 GtkAllocation allocation;
3271 GtkAllocation start_allocation;
3272 GtkAllocation goal_allocation;
3273 guint is_placeholder : 1;
3274 guint disappearing : 1;
3279 toolbar_item_visiblity_notify_cb (GObject *obj,
3283 GtkToolbar *toolbar = user_data;
3285 gtk_toolbar_invalidate_order (toolbar);
3288 static ToolbarContent *
3289 toolbar_content_new_tool_item (GtkToolbar *toolbar,
3291 gboolean is_placeholder,
3294 GtkToolbarPrivate *priv = toolbar->priv;
3295 ToolbarContent *content;
3297 content = g_slice_new0 (ToolbarContent);
3299 content->state = NOT_ALLOCATED;
3300 content->item = item;
3301 content->is_placeholder = is_placeholder;
3303 priv->content = g_list_insert (priv->content, content, pos);
3305 gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar));
3306 gtk_toolbar_invalidate_order (toolbar);
3308 g_signal_connect (content->item, "notify::visible",
3309 G_CALLBACK (toolbar_item_visiblity_notify_cb), toolbar);
3311 if (!is_placeholder)
3313 priv->num_children++;
3315 gtk_toolbar_stop_sliding (toolbar);
3318 gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3319 priv->need_rebuild = TRUE;
3325 toolbar_content_remove (ToolbarContent *content,
3326 GtkToolbar *toolbar)
3328 GtkToolbarPrivate *priv = toolbar->priv;
3330 gtk_toolbar_invalidate_order (toolbar);
3331 gtk_widget_unparent (GTK_WIDGET (content->item));
3333 g_signal_handlers_disconnect_by_func (content->item,
3334 toolbar_item_visiblity_notify_cb,
3337 priv->content = g_list_remove (priv->content, content);
3339 if (!toolbar_content_is_placeholder (content))
3340 priv->num_children--;
3342 gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3343 priv->need_rebuild = TRUE;
3347 toolbar_content_free (ToolbarContent *content)
3349 g_slice_free (ToolbarContent, content);
3353 calculate_max_homogeneous_pixels (GtkWidget *widget)
3355 PangoContext *context;
3356 PangoFontMetrics *metrics;
3357 const PangoFontDescription *font_desc;
3358 GtkStyleContext *style_context;
3359 GtkStateFlags state;
3362 context = gtk_widget_get_pango_context (widget);
3363 style_context = gtk_widget_get_style_context (widget);
3364 state = gtk_widget_get_state_flags (widget);
3366 font_desc = gtk_style_context_get_font (style_context, state);
3368 metrics = pango_context_get_metrics (context, font_desc,
3369 pango_context_get_language (context));
3370 char_width = pango_font_metrics_get_approximate_char_width (metrics);
3371 pango_font_metrics_unref (metrics);
3373 return PANGO_PIXELS (MAX_HOMOGENEOUS_N_CHARS * char_width);
3377 toolbar_content_draw (ToolbarContent *content,
3378 GtkContainer *container,
3383 if (content->is_placeholder)
3386 widget = GTK_WIDGET (content->item);
3389 gtk_container_propagate_draw (container, widget, cr);
3393 toolbar_content_visible (ToolbarContent *content,
3394 GtkToolbar *toolbar)
3396 GtkToolbarPrivate *priv = toolbar->priv;
3399 item = content->item;
3401 if (!gtk_widget_get_visible (GTK_WIDGET (item)))
3404 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
3405 gtk_tool_item_get_visible_horizontal (item))
3408 if (priv->orientation == GTK_ORIENTATION_VERTICAL &&
3409 gtk_tool_item_get_visible_vertical (item))
3416 toolbar_content_size_request (ToolbarContent *content,
3417 GtkToolbar *toolbar,
3418 GtkRequisition *requisition)
3420 gtk_widget_get_preferred_size (GTK_WIDGET (content->item),
3422 if (content->is_placeholder &&
3423 content->disappearing)
3425 requisition->width = 0;
3426 requisition->height = 0;
3431 toolbar_content_is_homogeneous (ToolbarContent *content,
3432 GtkToolbar *toolbar)
3434 GtkToolbarPrivate *priv = toolbar->priv;
3435 GtkRequisition requisition;
3438 if (priv->max_homogeneous_pixels < 0)
3440 priv->max_homogeneous_pixels =
3441 calculate_max_homogeneous_pixels (GTK_WIDGET (toolbar));
3444 toolbar_content_size_request (content, toolbar, &requisition);
3446 if (requisition.width > priv->max_homogeneous_pixels)
3449 result = gtk_tool_item_get_homogeneous (content->item) &&
3450 !GTK_IS_SEPARATOR_TOOL_ITEM (content->item);
3452 if (gtk_tool_item_get_is_important (content->item) &&
3453 priv->style == GTK_TOOLBAR_BOTH_HORIZ &&
3454 priv->orientation == GTK_ORIENTATION_HORIZONTAL)
3463 toolbar_content_is_placeholder (ToolbarContent *content)
3465 if (content->is_placeholder)
3472 toolbar_content_disappearing (ToolbarContent *content)
3474 if (content->disappearing)
3481 toolbar_content_get_state (ToolbarContent *content)
3483 return content->state;
3487 toolbar_content_child_visible (ToolbarContent *content)
3489 return gtk_widget_get_child_visible (GTK_WIDGET (content->item));
3493 toolbar_content_get_goal_allocation (ToolbarContent *content,
3494 GtkAllocation *allocation)
3496 *allocation = content->goal_allocation;
3500 toolbar_content_get_allocation (ToolbarContent *content,
3501 GtkAllocation *allocation)
3503 *allocation = content->allocation;
3507 toolbar_content_set_start_allocation (ToolbarContent *content,
3508 GtkAllocation *allocation)
3510 content->start_allocation = *allocation;
3514 toolbar_content_get_expand (ToolbarContent *content)
3516 if (!content->disappearing &&
3517 gtk_tool_item_get_expand (content->item))
3524 toolbar_content_set_goal_allocation (ToolbarContent *content,
3525 GtkAllocation *allocation)
3527 content->goal_allocation = *allocation;
3531 toolbar_content_set_child_visible (ToolbarContent *content,
3532 GtkToolbar *toolbar,
3535 gtk_widget_set_child_visible (GTK_WIDGET (content->item),
3540 toolbar_content_get_start_allocation (ToolbarContent *content,
3541 GtkAllocation *start_allocation)
3543 *start_allocation = content->start_allocation;
3547 toolbar_content_size_allocate (ToolbarContent *content,
3548 GtkAllocation *allocation)
3550 content->allocation = *allocation;
3551 gtk_widget_size_allocate (GTK_WIDGET (content->item),
3556 toolbar_content_set_state (ToolbarContent *content,
3559 content->state = state;
3563 toolbar_content_get_widget (ToolbarContent *content)
3565 return GTK_WIDGET (content->item);
3570 toolbar_content_set_disappearing (ToolbarContent *content,
3571 gboolean disappearing)
3573 content->disappearing = disappearing;
3577 toolbar_content_set_size_request (ToolbarContent *content,
3581 gtk_widget_set_size_request (GTK_WIDGET (content->item),
3586 toolbar_content_toolbar_reconfigured (ToolbarContent *content,
3587 GtkToolbar *toolbar)
3589 gtk_tool_item_toolbar_reconfigured (content->item);
3593 toolbar_content_retrieve_menu_item (ToolbarContent *content)
3595 return gtk_tool_item_retrieve_proxy_menu_item (content->item);
3599 toolbar_content_has_proxy_menu_item (ToolbarContent *content)
3601 GtkWidget *menu_item;
3603 if (content->has_menu == YES)
3605 else if (content->has_menu == NO)
3608 menu_item = toolbar_content_retrieve_menu_item (content);
3610 content->has_menu = menu_item? YES : NO;
3612 return menu_item != NULL;
3616 toolbar_content_set_unknown_menu_status (ToolbarContent *content)
3618 content->has_menu = UNKNOWN;
3622 toolbar_content_is_separator (ToolbarContent *content)
3624 return GTK_IS_SEPARATOR_TOOL_ITEM (content->item);
3628 toolbar_content_set_expand (ToolbarContent *content,
3631 gtk_tool_item_set_expand (content->item, expand);
3635 toolbar_content_show_all (ToolbarContent *content)
3639 widget = toolbar_content_get_widget (content);
3641 gtk_widget_show_all (widget);
3647 static GtkReliefStyle
3648 get_button_relief (GtkToolbar *toolbar)
3650 GtkReliefStyle button_relief = GTK_RELIEF_NORMAL;
3652 gtk_widget_style_get (GTK_WIDGET (toolbar),
3653 "button-relief", &button_relief,
3656 return button_relief;
3660 get_internal_padding (GtkToolbar *toolbar)
3664 gtk_widget_style_get (GTK_WIDGET (toolbar),
3665 "internal-padding", &ipadding,
3672 get_max_child_expand (GtkToolbar *toolbar)
3674 gint mexpand = G_MAXINT;
3676 gtk_widget_style_get (GTK_WIDGET (toolbar),
3677 "max-child-expand", &mexpand,
3682 static GtkShadowType
3683 get_shadow_type (GtkToolbar *toolbar)
3685 GtkShadowType shadow_type;
3687 gtk_widget_style_get (GTK_WIDGET (toolbar),
3688 "shadow-type", &shadow_type,
3694 /* GTK+ internal methods */
3697 _gtk_toolbar_get_default_space_size (void)
3699 return DEFAULT_SPACE_SIZE;
3703 _gtk_toolbar_paint_space_line (GtkWidget *widget,
3704 GtkToolbar *toolbar,
3707 GtkOrientation orientation;
3708 GtkStyleContext *context;
3709 GtkStateFlags state;
3712 const gdouble start_fraction = (SPACE_LINE_START / SPACE_LINE_DIVISION);
3713 const gdouble end_fraction = (SPACE_LINE_END / SPACE_LINE_DIVISION);
3715 g_return_if_fail (GTK_IS_WIDGET (widget));
3717 orientation = toolbar ? toolbar->priv->orientation : GTK_ORIENTATION_HORIZONTAL;
3719 context = gtk_widget_get_style_context (widget);
3720 state = gtk_widget_get_state_flags (widget);
3721 width = gtk_widget_get_allocated_width (widget);
3722 height = gtk_widget_get_allocated_height (widget);
3723 gtk_style_context_get_padding (context, state, &padding);
3725 if (orientation == GTK_ORIENTATION_HORIZONTAL)
3727 gboolean wide_separators;
3728 gint separator_width;
3730 gtk_widget_style_get (widget,
3731 "wide-separators", &wide_separators,
3732 "separator-width", &separator_width,
3735 if (wide_separators)
3736 gtk_render_frame (context, cr,
3737 (width - separator_width) / 2,
3738 height * start_fraction,
3740 height * (end_fraction - start_fraction));
3742 gtk_render_line (context, cr,
3743 (width - padding.left) / 2,
3744 height * start_fraction,
3745 (width - padding.left) / 2,
3746 height * end_fraction);
3750 gboolean wide_separators;
3751 gint separator_height;
3753 gtk_widget_style_get (widget,
3754 "wide-separators", &wide_separators,
3755 "separator-height", &separator_height,
3758 if (wide_separators)
3759 gtk_render_frame (context, cr,
3760 width * start_fraction,
3761 (height - separator_height) / 2,
3762 width * (end_fraction - start_fraction),
3765 gtk_render_line (context, cr,
3766 width * start_fraction,
3767 (height - padding.top) / 2,
3768 width * end_fraction,
3769 (height - padding.top) / 2);
3774 _gtk_toolbar_elide_underscores (const gchar *original)
3777 const gchar *p, *end;
3779 gboolean last_underscore;
3784 len = strlen (original);
3785 q = result = g_malloc (len + 1);
3786 last_underscore = FALSE;
3788 end = original + len;
3789 for (p = original; p < end; p++)
3791 if (!last_underscore && *p == '_')
3792 last_underscore = TRUE;
3795 last_underscore = FALSE;
3796 if (original + 2 <= p && p + 1 <= end &&
3797 p[-2] == '(' && p[-1] == '_' && p[0] != '_' && p[1] == ')')
3808 if (last_underscore)
3817 toolbar_get_icon_size (GtkToolShell *shell)
3819 GtkToolbar *toolbar = GTK_TOOLBAR (shell);
3820 GtkToolbarPrivate *priv = toolbar->priv;
3822 return priv->icon_size;
3825 static GtkOrientation
3826 toolbar_get_orientation (GtkToolShell *shell)
3828 GtkToolbar *toolbar = GTK_TOOLBAR (shell);
3829 GtkToolbarPrivate *priv = toolbar->priv;
3831 return priv->orientation;
3834 static GtkToolbarStyle
3835 toolbar_get_style (GtkToolShell *shell)
3837 GtkToolbar *toolbar = GTK_TOOLBAR (shell);
3838 GtkToolbarPrivate *priv = toolbar->priv;
3843 static GtkReliefStyle
3844 toolbar_get_relief_style (GtkToolShell *shell)
3846 return get_button_relief (GTK_TOOLBAR (shell));
3850 toolbar_rebuild_menu (GtkToolShell *shell)
3852 GtkToolbar *toolbar = GTK_TOOLBAR (shell);
3853 GtkToolbarPrivate *priv = toolbar->priv;
3856 priv->need_rebuild = TRUE;
3858 for (list = priv->content; list != NULL; list = list->next)
3860 ToolbarContent *content = list->data;
3862 toolbar_content_set_unknown_menu_status (content);
3865 gtk_widget_queue_resize (GTK_WIDGET (shell));
3868 typedef struct _CountingData CountingData;
3869 struct _CountingData {
3877 count_widget_position (GtkWidget *widget,
3880 CountingData *count = data;
3882 if (!gtk_widget_get_visible (widget))
3885 if (count->widget == widget)
3886 count->found = TRUE;
3887 else if (count->found)
3894 gtk_toolbar_get_visible_position (GtkToolbar *toolbar,
3897 CountingData count = { child, FALSE, 0, 0 };
3899 /* foreach iterates in visible order */
3900 gtk_container_forall (GTK_CONTAINER (toolbar),
3901 count_widget_position,
3904 g_assert (count.found);
3906 if (toolbar->priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
3907 gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
3910 return count.before;
3914 add_widget_to_path (gpointer data,
3917 GtkWidget *widget = data;
3918 GtkWidgetPath *path = user_data;
3920 if (gtk_widget_get_visible (widget))
3921 gtk_widget_path_append_for_widget (path, widget);
3924 static GtkWidgetPath *
3925 gtk_toolbar_get_path_for_child (GtkContainer *container,
3928 GtkWidgetPath *path;
3929 GtkToolbar *toolbar;
3930 GtkToolbarPrivate *priv;
3933 toolbar = GTK_TOOLBAR (container);
3934 priv = toolbar->priv;
3936 if (priv->sibling_path == NULL)
3940 /* build a path for all the visible children;
3941 * get_children works in visible order
3943 priv->sibling_path = gtk_widget_path_new ();
3944 children = gtk_container_get_children (container);
3946 if (priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
3947 gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
3948 children = g_list_reverse (children);
3950 g_list_foreach (children, add_widget_to_path, priv->sibling_path);
3951 g_list_free (children);
3954 path = gtk_widget_path_copy (gtk_widget_get_path (GTK_WIDGET (container)));
3955 if (gtk_widget_get_visible (child))
3957 vis_index = gtk_toolbar_get_visible_position (toolbar, child);
3959 if (vis_index < gtk_widget_path_length (priv->sibling_path))
3960 gtk_widget_path_append_with_siblings (path,
3964 gtk_widget_path_append_for_widget (path, child);
3967 gtk_widget_path_append_for_widget (path, child);
3973 gtk_toolbar_invalidate_order (GtkToolbar *toolbar)
3975 GtkToolbarPrivate *priv = toolbar->priv;
3977 if (priv->sibling_path != NULL)
3979 gtk_widget_path_unref (priv->sibling_path);
3980 priv->sibling_path = NULL;
3982 gtk_container_foreach (GTK_CONTAINER (toolbar),
3983 (GtkCallback) gtk_widget_reset_style,