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/.
32 #undef GTK_DISABLE_DEPRECATED
39 #include <gdk/gdkkeysyms.h>
42 #include "gtkbindings.h"
47 #include "gtkmarshalers.h"
49 #include "gtkorientable.h"
50 #include "gtkradiobutton.h"
51 #include "gtkradiotoolbutton.h"
52 #include "gtkseparatormenuitem.h"
53 #include "gtkseparatortoolitem.h"
55 #include "gtktoolbar.h"
56 #include "gtktoolshell.h"
58 #include "gtkprivate.h"
62 typedef struct _ToolbarContent ToolbarContent;
64 #define DEFAULT_IPADDING 0
66 #define DEFAULT_SPACE_SIZE 12
67 #define DEFAULT_SPACE_STYLE GTK_TOOLBAR_SPACE_LINE
68 #define SPACE_LINE_DIVISION 10.0
69 #define SPACE_LINE_START 2.0
70 #define SPACE_LINE_END 8.0
72 #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_LARGE_TOOLBAR
73 #define DEFAULT_TOOLBAR_STYLE GTK_TOOLBAR_BOTH
74 #define DEFAULT_ANIMATION_STATE TRUE
76 #define MAX_HOMOGENEOUS_N_CHARS 13 /* Items that are wider than this do not participate
77 * in the homogeneous game. In units of
78 * pango_font_get_estimated_char_width().
80 #define SLIDE_SPEED 600.0 /* How fast the items slide, in pixels per second */
81 #define ACCEL_THRESHOLD 0.18 /* After how much time in seconds will items start speeding up */
83 #define MIXED_API_WARNING \
84 "Mixing deprecated and non-deprecated GtkToolbar API is not allowed"
98 /* Child properties */
102 CHILD_PROP_HOMOGENEOUS
133 struct _GtkToolbarPrivate
138 GtkWidget * arrow_button;
141 GdkWindow * event_window;
143 GtkSettings * settings;
145 GtkToolItem * highlight_tool_item;
146 gint max_homogeneous_pixels;
150 gulong settings_connection;
152 guint show_arrow : 1;
154 guint is_sliding : 1;
155 guint need_rebuild : 1; /* whether the overflow menu should be regenerated */
159 static void gtk_toolbar_set_property (GObject *object,
163 static void gtk_toolbar_get_property (GObject *object,
167 static gint gtk_toolbar_expose (GtkWidget *widget,
168 GdkEventExpose *event);
169 static void gtk_toolbar_realize (GtkWidget *widget);
170 static void gtk_toolbar_unrealize (GtkWidget *widget);
171 static void gtk_toolbar_size_request (GtkWidget *widget,
172 GtkRequisition *requisition);
173 static void gtk_toolbar_size_allocate (GtkWidget *widget,
174 GtkAllocation *allocation);
175 static void gtk_toolbar_style_set (GtkWidget *widget,
176 GtkStyle *prev_style);
177 static gboolean gtk_toolbar_focus (GtkWidget *widget,
178 GtkDirectionType dir);
179 static void gtk_toolbar_move_focus (GtkWidget *widget,
180 GtkDirectionType dir);
181 static void gtk_toolbar_screen_changed (GtkWidget *widget,
182 GdkScreen *previous_screen);
183 static void gtk_toolbar_map (GtkWidget *widget);
184 static void gtk_toolbar_unmap (GtkWidget *widget);
185 static void gtk_toolbar_set_child_property (GtkContainer *container,
190 static void gtk_toolbar_get_child_property (GtkContainer *container,
195 static void gtk_toolbar_finalize (GObject *object);
196 static void gtk_toolbar_show_all (GtkWidget *widget);
197 static void gtk_toolbar_hide_all (GtkWidget *widget);
198 static void gtk_toolbar_add (GtkContainer *container,
200 static void gtk_toolbar_remove (GtkContainer *container,
202 static void gtk_toolbar_forall (GtkContainer *container,
203 gboolean include_internals,
204 GtkCallback callback,
205 gpointer callback_data);
206 static GType gtk_toolbar_child_type (GtkContainer *container);
207 static void gtk_toolbar_orientation_changed (GtkToolbar *toolbar,
208 GtkOrientation orientation);
209 static void gtk_toolbar_real_style_changed (GtkToolbar *toolbar,
210 GtkToolbarStyle style);
211 static gboolean gtk_toolbar_focus_home_or_end (GtkToolbar *toolbar,
212 gboolean focus_home);
213 static gboolean gtk_toolbar_button_press (GtkWidget *toolbar,
214 GdkEventButton *event);
215 static gboolean gtk_toolbar_arrow_button_press (GtkWidget *button,
216 GdkEventButton *event,
217 GtkToolbar *toolbar);
218 static void gtk_toolbar_arrow_button_clicked (GtkWidget *button,
219 GtkToolbar *toolbar);
220 static void gtk_toolbar_update_button_relief (GtkToolbar *toolbar);
221 static gboolean gtk_toolbar_popup_menu (GtkWidget *toolbar);
222 static GtkWidget *internal_insert_element (GtkToolbar *toolbar,
223 GtkToolbarChildType type,
226 const char *tooltip_text,
227 const char *tooltip_private_text,
233 static void gtk_toolbar_reconfigured (GtkToolbar *toolbar);
234 static gboolean gtk_toolbar_check_new_api (GtkToolbar *toolbar);
235 static gboolean gtk_toolbar_check_old_api (GtkToolbar *toolbar);
237 static GtkReliefStyle get_button_relief (GtkToolbar *toolbar);
238 static gint get_internal_padding (GtkToolbar *toolbar);
239 static gint get_max_child_expand (GtkToolbar *toolbar);
240 static GtkShadowType get_shadow_type (GtkToolbar *toolbar);
241 static gint get_space_size (GtkToolbar *toolbar);
242 static GtkToolbarSpaceStyle get_space_style (GtkToolbar *toolbar);
244 /* methods on ToolbarContent 'class' */
245 static ToolbarContent *toolbar_content_new_tool_item (GtkToolbar *toolbar,
247 gboolean is_placeholder,
249 static ToolbarContent *toolbar_content_new_compatibility (GtkToolbar *toolbar,
250 GtkToolbarChildType type,
255 static void toolbar_content_remove (ToolbarContent *content,
256 GtkToolbar *toolbar);
257 static void toolbar_content_free (ToolbarContent *content);
258 static void toolbar_content_expose (ToolbarContent *content,
259 GtkContainer *container,
260 GdkEventExpose *expose);
261 static gboolean toolbar_content_visible (ToolbarContent *content,
262 GtkToolbar *toolbar);
263 static void toolbar_content_size_request (ToolbarContent *content,
265 GtkRequisition *requisition);
266 static gboolean toolbar_content_is_homogeneous (ToolbarContent *content,
267 GtkToolbar *toolbar);
268 static gboolean toolbar_content_is_placeholder (ToolbarContent *content);
269 static gboolean toolbar_content_disappearing (ToolbarContent *content);
270 static ItemState toolbar_content_get_state (ToolbarContent *content);
271 static gboolean toolbar_content_child_visible (ToolbarContent *content);
272 static void toolbar_content_get_goal_allocation (ToolbarContent *content,
273 GtkAllocation *allocation);
274 static void toolbar_content_get_allocation (ToolbarContent *content,
275 GtkAllocation *allocation);
276 static void toolbar_content_set_start_allocation (ToolbarContent *content,
277 GtkAllocation *new_start_allocation);
278 static void toolbar_content_get_start_allocation (ToolbarContent *content,
279 GtkAllocation *start_allocation);
280 static gboolean toolbar_content_get_expand (ToolbarContent *content);
281 static void toolbar_content_set_goal_allocation (ToolbarContent *content,
282 GtkAllocation *allocation);
283 static void toolbar_content_set_child_visible (ToolbarContent *content,
286 static void toolbar_content_size_allocate (ToolbarContent *content,
287 GtkAllocation *allocation);
288 static void toolbar_content_set_state (ToolbarContent *content,
289 ItemState new_state);
290 static GtkWidget * toolbar_content_get_widget (ToolbarContent *content);
291 static void toolbar_content_set_disappearing (ToolbarContent *content,
292 gboolean disappearing);
293 static void toolbar_content_set_size_request (ToolbarContent *content,
296 static void toolbar_content_toolbar_reconfigured (ToolbarContent *content,
297 GtkToolbar *toolbar);
298 static GtkWidget * toolbar_content_retrieve_menu_item (ToolbarContent *content);
299 static gboolean toolbar_content_has_proxy_menu_item (ToolbarContent *content);
300 static gboolean toolbar_content_is_separator (ToolbarContent *content);
301 static void toolbar_content_show_all (ToolbarContent *content);
302 static void toolbar_content_hide_all (ToolbarContent *content);
303 static void toolbar_content_set_expand (ToolbarContent *content,
306 static void toolbar_tool_shell_iface_init (GtkToolShellIface *iface);
307 static GtkIconSize toolbar_get_icon_size (GtkToolShell *shell);
308 static GtkOrientation toolbar_get_orientation (GtkToolShell *shell);
309 static GtkToolbarStyle toolbar_get_style (GtkToolShell *shell);
310 static GtkReliefStyle toolbar_get_relief_style (GtkToolShell *shell);
311 static void toolbar_rebuild_menu (GtkToolShell *shell);
313 #define GTK_TOOLBAR_GET_PRIVATE(o) \
314 (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_TOOLBAR, GtkToolbarPrivate))
317 G_DEFINE_TYPE_WITH_CODE (GtkToolbar, gtk_toolbar, GTK_TYPE_CONTAINER,
318 G_IMPLEMENT_INTERFACE (GTK_TYPE_TOOL_SHELL,
319 toolbar_tool_shell_iface_init)
320 G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
323 static guint toolbar_signals[LAST_SIGNAL] = { 0 };
327 add_arrow_bindings (GtkBindingSet *binding_set,
329 GtkDirectionType dir)
331 guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
333 gtk_binding_entry_add_signal (binding_set, keysym, 0,
335 GTK_TYPE_DIRECTION_TYPE, dir);
336 gtk_binding_entry_add_signal (binding_set, keypad_keysym, 0,
338 GTK_TYPE_DIRECTION_TYPE, dir);
342 add_ctrl_tab_bindings (GtkBindingSet *binding_set,
343 GdkModifierType modifiers,
344 GtkDirectionType direction)
346 gtk_binding_entry_add_signal (binding_set,
347 GDK_Tab, GDK_CONTROL_MASK | modifiers,
349 GTK_TYPE_DIRECTION_TYPE, direction);
350 gtk_binding_entry_add_signal (binding_set,
351 GDK_KP_Tab, GDK_CONTROL_MASK | modifiers,
353 GTK_TYPE_DIRECTION_TYPE, direction);
357 gtk_toolbar_class_init (GtkToolbarClass *klass)
359 GObjectClass *gobject_class;
360 GtkWidgetClass *widget_class;
361 GtkContainerClass *container_class;
362 GtkBindingSet *binding_set;
364 gobject_class = (GObjectClass *)klass;
365 widget_class = (GtkWidgetClass *)klass;
366 container_class = (GtkContainerClass *)klass;
368 gobject_class->set_property = gtk_toolbar_set_property;
369 gobject_class->get_property = gtk_toolbar_get_property;
370 gobject_class->finalize = gtk_toolbar_finalize;
372 widget_class->button_press_event = gtk_toolbar_button_press;
373 widget_class->expose_event = gtk_toolbar_expose;
374 widget_class->size_request = gtk_toolbar_size_request;
375 widget_class->size_allocate = gtk_toolbar_size_allocate;
376 widget_class->style_set = gtk_toolbar_style_set;
377 widget_class->focus = gtk_toolbar_focus;
379 /* need to override the base class function via override_class_handler,
380 * because the signal slot is not available in GtkWidgetClass
382 g_signal_override_class_handler ("move-focus",
384 G_CALLBACK (gtk_toolbar_move_focus));
386 widget_class->screen_changed = gtk_toolbar_screen_changed;
387 widget_class->realize = gtk_toolbar_realize;
388 widget_class->unrealize = gtk_toolbar_unrealize;
389 widget_class->map = gtk_toolbar_map;
390 widget_class->unmap = gtk_toolbar_unmap;
391 widget_class->popup_menu = gtk_toolbar_popup_menu;
392 widget_class->show_all = gtk_toolbar_show_all;
393 widget_class->hide_all = gtk_toolbar_hide_all;
395 container_class->add = gtk_toolbar_add;
396 container_class->remove = gtk_toolbar_remove;
397 container_class->forall = gtk_toolbar_forall;
398 container_class->child_type = gtk_toolbar_child_type;
399 container_class->get_child_property = gtk_toolbar_get_child_property;
400 container_class->set_child_property = gtk_toolbar_set_child_property;
402 klass->orientation_changed = gtk_toolbar_orientation_changed;
403 klass->style_changed = gtk_toolbar_real_style_changed;
406 * GtkToolbar::orientation-changed:
407 * @toolbar: the object which emitted the signal
408 * @orientation: the new #GtkOrientation of the toolbar
410 * Emitted when the orientation of the toolbar changes.
412 toolbar_signals[ORIENTATION_CHANGED] =
413 g_signal_new (I_("orientation-changed"),
414 G_OBJECT_CLASS_TYPE (klass),
416 G_STRUCT_OFFSET (GtkToolbarClass, orientation_changed),
418 g_cclosure_marshal_VOID__ENUM,
420 GTK_TYPE_ORIENTATION);
422 * GtkToolbar::style-changed:
423 * @toolbar: The #GtkToolbar which emitted the signal
424 * @style: the new #GtkToolbarStyle of the toolbar
426 * Emitted when the style of the toolbar changes.
428 toolbar_signals[STYLE_CHANGED] =
429 g_signal_new (I_("style-changed"),
430 G_OBJECT_CLASS_TYPE (klass),
432 G_STRUCT_OFFSET (GtkToolbarClass, style_changed),
434 g_cclosure_marshal_VOID__ENUM,
436 GTK_TYPE_TOOLBAR_STYLE);
438 * GtkToolbar::popup-context-menu:
439 * @toolbar: the #GtkToolbar which emitted the signal
440 * @x: the x coordinate of the point where the menu should appear
441 * @y: the y coordinate of the point where the menu should appear
442 * @button: the mouse button the user pressed, or -1
444 * Emitted when the user right-clicks the toolbar or uses the
445 * keybinding to display a popup menu.
447 * Application developers should handle this signal if they want
448 * to display a context menu on the toolbar. The context-menu should
449 * appear at the coordinates given by @x and @y. The mouse button
450 * number is given by the @button parameter. If the menu was popped
451 * up using the keybaord, @button is -1.
453 * Return value: return %TRUE if the signal was handled, %FALSE if not
455 toolbar_signals[POPUP_CONTEXT_MENU] =
456 g_signal_new (I_("popup-context-menu"),
457 G_OBJECT_CLASS_TYPE (klass),
459 G_STRUCT_OFFSET (GtkToolbarClass, popup_context_menu),
460 _gtk_boolean_handled_accumulator, NULL,
461 _gtk_marshal_BOOLEAN__INT_INT_INT,
463 G_TYPE_INT, G_TYPE_INT,
467 * GtkToolbar::focus-home-or-end:
468 * @toolbar: the #GtkToolbar which emitted the signal
469 * @focus_home: %TRUE if the first item should be focused
471 * A keybinding signal used internally by GTK+. This signal can't
472 * be used in application code
474 * Return value: %TRUE if the signal was handled, %FALSE if not
476 toolbar_signals[FOCUS_HOME_OR_END] =
477 g_signal_new_class_handler (I_("focus-home-or-end"),
478 G_OBJECT_CLASS_TYPE (klass),
479 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
480 G_CALLBACK (gtk_toolbar_focus_home_or_end),
482 _gtk_marshal_BOOLEAN__BOOLEAN,
487 g_object_class_override_property (gobject_class,
491 g_object_class_install_property (gobject_class,
493 g_param_spec_enum ("toolbar-style",
495 P_("How to draw the toolbar"),
496 GTK_TYPE_TOOLBAR_STYLE,
497 DEFAULT_TOOLBAR_STYLE,
498 GTK_PARAM_READWRITE));
499 g_object_class_install_property (gobject_class,
501 g_param_spec_boolean ("show-arrow",
503 P_("If an arrow should be shown if the toolbar doesn't fit"),
505 GTK_PARAM_READWRITE));
508 * GtkToolbar:icon-size:
510 * The size of the icons in a toolbar is normally determined by
511 * the toolbar-icon-size setting. When this property is set, it
512 * overrides the setting.
514 * This should only be used for special-purpose toolbars, normal
515 * application toolbars should respect the user preferences for the
520 g_object_class_install_property (gobject_class,
522 g_param_spec_int ("icon-size",
524 P_("Size of icons in this toolbar"),
527 GTK_PARAM_READWRITE));
530 * GtkToolbar:icon-size-set:
532 * Is %TRUE if the icon-size property has been set.
536 g_object_class_install_property (gobject_class,
538 g_param_spec_boolean ("icon-size-set",
540 P_("Whether the icon-size property has been set"),
542 GTK_PARAM_READWRITE));
544 /* child properties */
545 gtk_container_class_install_child_property (container_class,
547 g_param_spec_boolean ("expand",
549 P_("Whether the item should receive extra space when the toolbar grows"),
551 GTK_PARAM_READWRITE));
553 gtk_container_class_install_child_property (container_class,
554 CHILD_PROP_HOMOGENEOUS,
555 g_param_spec_boolean ("homogeneous",
557 P_("Whether the item should be the same size as other homogeneous items"),
559 GTK_PARAM_READWRITE));
561 /* style properties */
562 gtk_widget_class_install_style_property (widget_class,
563 g_param_spec_int ("space-size",
565 P_("Size of spacers"),
569 GTK_PARAM_READABLE));
571 gtk_widget_class_install_style_property (widget_class,
572 g_param_spec_int ("internal-padding",
573 P_("Internal padding"),
574 P_("Amount of border space between the toolbar shadow and the buttons"),
578 GTK_PARAM_READABLE));
580 gtk_widget_class_install_style_property (widget_class,
581 g_param_spec_int ("max-child-expand",
582 P_("Maximum child expand"),
583 P_("Maximum amount of space an expandable item will be given"),
587 GTK_PARAM_READABLE));
589 gtk_widget_class_install_style_property (widget_class,
590 g_param_spec_enum ("space-style",
592 P_("Whether spacers are vertical lines or just blank"),
593 GTK_TYPE_TOOLBAR_SPACE_STYLE,
595 GTK_PARAM_READABLE));
597 gtk_widget_class_install_style_property (widget_class,
598 g_param_spec_enum ("button-relief",
600 P_("Type of bevel around toolbar buttons"),
601 GTK_TYPE_RELIEF_STYLE,
603 GTK_PARAM_READABLE));
604 gtk_widget_class_install_style_property (widget_class,
605 g_param_spec_enum ("shadow-type",
607 P_("Style of bevel around the toolbar"),
608 GTK_TYPE_SHADOW_TYPE,
610 GTK_PARAM_READABLE));
612 binding_set = gtk_binding_set_by_class (klass);
614 add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
615 add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
616 add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
617 add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
619 gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
620 "focus-home-or-end", 1,
621 G_TYPE_BOOLEAN, TRUE);
622 gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
623 "focus-home-or-end", 1,
624 G_TYPE_BOOLEAN, TRUE);
625 gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
626 "focus-home-or-end", 1,
627 G_TYPE_BOOLEAN, FALSE);
628 gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
629 "focus-home-or-end", 1,
630 G_TYPE_BOOLEAN, FALSE);
632 add_ctrl_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
633 add_ctrl_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
635 g_type_class_add_private (gobject_class, sizeof (GtkToolbarPrivate));
639 toolbar_tool_shell_iface_init (GtkToolShellIface *iface)
641 iface->get_icon_size = toolbar_get_icon_size;
642 iface->get_orientation = toolbar_get_orientation;
643 iface->get_style = toolbar_get_style;
644 iface->get_relief_style = toolbar_get_relief_style;
645 iface->rebuild_menu = toolbar_rebuild_menu;
649 gtk_toolbar_init (GtkToolbar *toolbar)
651 GtkToolbarPrivate *priv;
653 gtk_widget_set_can_focus (GTK_WIDGET (toolbar), FALSE);
654 gtk_widget_set_has_window (GTK_WIDGET (toolbar), FALSE);
656 priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
658 toolbar->orientation = GTK_ORIENTATION_HORIZONTAL;
659 toolbar->style = DEFAULT_TOOLBAR_STYLE;
660 toolbar->icon_size = DEFAULT_ICON_SIZE;
661 priv->animation = DEFAULT_ANIMATION_STATE;
662 toolbar->tooltips = NULL; /* FIXME: Remove this */
664 priv->arrow_button = gtk_toggle_button_new ();
665 g_signal_connect (priv->arrow_button, "button-press-event",
666 G_CALLBACK (gtk_toolbar_arrow_button_press), toolbar);
667 g_signal_connect (priv->arrow_button, "clicked",
668 G_CALLBACK (gtk_toolbar_arrow_button_clicked), toolbar);
669 gtk_button_set_relief (GTK_BUTTON (priv->arrow_button),
670 get_button_relief (toolbar));
672 priv->api_mode = DONT_KNOW;
674 gtk_button_set_focus_on_click (GTK_BUTTON (priv->arrow_button), FALSE);
676 priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
677 gtk_widget_set_name (priv->arrow, "gtk-toolbar-arrow");
678 gtk_widget_show (priv->arrow);
679 gtk_container_add (GTK_CONTAINER (priv->arrow_button), priv->arrow);
681 gtk_widget_set_parent (priv->arrow_button, GTK_WIDGET (toolbar));
683 /* which child position a drop will occur at */
685 priv->show_arrow = TRUE;
686 priv->settings = NULL;
688 priv->max_homogeneous_pixels = -1;
690 priv->timer = g_timer_new ();
694 gtk_toolbar_set_property (GObject *object,
699 GtkToolbar *toolbar = GTK_TOOLBAR (object);
703 case PROP_ORIENTATION:
704 g_signal_emit (toolbar, toolbar_signals[ORIENTATION_CHANGED], 0,
705 g_value_get_enum (value));
707 case PROP_TOOLBAR_STYLE:
708 gtk_toolbar_set_style (toolbar, g_value_get_enum (value));
710 case PROP_SHOW_ARROW:
711 gtk_toolbar_set_show_arrow (toolbar, g_value_get_boolean (value));
714 gtk_toolbar_set_icon_size (toolbar, g_value_get_int (value));
716 case PROP_ICON_SIZE_SET:
717 if (g_value_get_boolean (value))
718 toolbar->icon_size_set = TRUE;
720 gtk_toolbar_unset_icon_size (toolbar);
723 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
729 gtk_toolbar_get_property (GObject *object,
734 GtkToolbar *toolbar = GTK_TOOLBAR (object);
735 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
739 case PROP_ORIENTATION:
740 g_value_set_enum (value, toolbar->orientation);
742 case PROP_TOOLBAR_STYLE:
743 g_value_set_enum (value, toolbar->style);
745 case PROP_SHOW_ARROW:
746 g_value_set_boolean (value, priv->show_arrow);
749 g_value_set_int (value, gtk_toolbar_get_icon_size (toolbar));
751 case PROP_ICON_SIZE_SET:
752 g_value_set_boolean (value, toolbar->icon_size_set);
755 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
761 gtk_toolbar_map (GtkWidget *widget)
763 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
765 GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->map (widget);
767 if (priv->event_window)
768 gdk_window_show_unraised (priv->event_window);
772 gtk_toolbar_unmap (GtkWidget *widget)
774 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
776 if (priv->event_window)
777 gdk_window_hide (priv->event_window);
779 GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->unmap (widget);
783 gtk_toolbar_realize (GtkWidget *widget)
785 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
786 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
788 GdkWindowAttr attributes;
789 gint attributes_mask;
792 gtk_widget_set_realized (widget, TRUE);
794 border_width = GTK_CONTAINER (widget)->border_width;
796 attributes.wclass = GDK_INPUT_ONLY;
797 attributes.window_type = GDK_WINDOW_CHILD;
798 attributes.x = widget->allocation.x + border_width;
799 attributes.y = widget->allocation.y + border_width;
800 attributes.width = widget->allocation.width - border_width * 2;
801 attributes.height = widget->allocation.height - border_width * 2;
802 attributes.event_mask = gtk_widget_get_events (widget);
803 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
804 GDK_BUTTON_RELEASE_MASK |
805 GDK_ENTER_NOTIFY_MASK |
806 GDK_LEAVE_NOTIFY_MASK);
808 attributes_mask = GDK_WA_X | GDK_WA_Y;
810 widget->window = gtk_widget_get_parent_window (widget);
811 g_object_ref (widget->window);
812 widget->style = gtk_style_attach (widget->style, widget->window);
814 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
815 &attributes, attributes_mask);
816 gdk_window_set_user_data (priv->event_window, toolbar);
820 gtk_toolbar_unrealize (GtkWidget *widget)
822 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
824 if (priv->event_window)
826 gdk_window_set_user_data (priv->event_window, NULL);
827 gdk_window_destroy (priv->event_window);
828 priv->event_window = NULL;
831 GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->unrealize (widget);
835 gtk_toolbar_expose (GtkWidget *widget,
836 GdkEventExpose *event)
838 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
839 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
844 border_width = GTK_CONTAINER (widget)->border_width;
846 if (gtk_widget_is_drawable (widget))
848 gtk_paint_box (widget->style,
850 gtk_widget_get_state (widget),
851 get_shadow_type (toolbar),
852 &event->area, widget, "toolbar",
853 border_width + widget->allocation.x,
854 border_width + widget->allocation.y,
855 widget->allocation.width - 2 * border_width,
856 widget->allocation.height - 2 * border_width);
859 for (list = priv->content; list != NULL; list = list->next)
861 ToolbarContent *content = list->data;
863 toolbar_content_expose (content, GTK_CONTAINER (widget), event);
866 gtk_container_propagate_expose (GTK_CONTAINER (widget),
874 gtk_toolbar_size_request (GtkWidget *widget,
875 GtkRequisition *requisition)
877 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
878 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
880 gint max_child_height;
881 gint max_child_width;
882 gint max_homogeneous_child_width;
883 gint max_homogeneous_child_height;
884 gint homogeneous_size;
886 gint pack_front_size;
888 GtkRequisition arrow_requisition;
890 max_homogeneous_child_width = 0;
891 max_homogeneous_child_height = 0;
893 max_child_height = 0;
894 for (list = priv->content; list != NULL; list = list->next)
896 GtkRequisition requisition;
897 ToolbarContent *content = list->data;
899 if (!toolbar_content_visible (content, toolbar))
902 toolbar_content_size_request (content, toolbar, &requisition);
904 max_child_width = MAX (max_child_width, requisition.width);
905 max_child_height = MAX (max_child_height, requisition.height);
907 if (toolbar_content_is_homogeneous (content, toolbar))
909 max_homogeneous_child_width = MAX (max_homogeneous_child_width, requisition.width);
910 max_homogeneous_child_height = MAX (max_homogeneous_child_height, requisition.height);
914 if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
915 homogeneous_size = max_homogeneous_child_width;
917 homogeneous_size = max_homogeneous_child_height;
920 for (list = priv->content; list != NULL; list = list->next)
922 ToolbarContent *content = list->data;
925 if (!toolbar_content_visible (content, toolbar))
928 if (toolbar_content_is_homogeneous (content, toolbar))
930 size = homogeneous_size;
934 GtkRequisition requisition;
936 toolbar_content_size_request (content, toolbar, &requisition);
938 if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
939 size = requisition.width;
941 size = requisition.height;
944 pack_front_size += size;
947 if (priv->show_arrow && priv->api_mode == NEW_API)
949 gtk_widget_size_request (priv->arrow_button, &arrow_requisition);
951 if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
952 long_req = arrow_requisition.width;
954 long_req = arrow_requisition.height;
956 /* There is no point requesting space for the arrow if that would take
957 * up more space than all the items combined
959 long_req = MIN (long_req, pack_front_size);
963 arrow_requisition.height = 0;
964 arrow_requisition.width = 0;
966 long_req = pack_front_size;
969 if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
971 requisition->width = long_req;
972 requisition->height = MAX (max_child_height, arrow_requisition.height);
976 requisition->height = long_req;
977 requisition->width = MAX (max_child_width, arrow_requisition.width);
981 ipadding = get_internal_padding (toolbar);
983 requisition->width += 2 * (ipadding + GTK_CONTAINER (toolbar)->border_width);
984 requisition->height += 2 * (ipadding + GTK_CONTAINER (toolbar)->border_width);
986 if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
988 requisition->width += 2 * widget->style->xthickness;
989 requisition->height += 2 * widget->style->ythickness;
992 toolbar->button_maxw = max_homogeneous_child_width;
993 toolbar->button_maxh = max_homogeneous_child_height;
997 position (GtkToolbar *toolbar,
1004 if (! GTK_TOOLBAR_GET_PRIVATE (toolbar)->animation)
1007 if (elapsed <= ACCEL_THRESHOLD)
1009 n_pixels = SLIDE_SPEED * elapsed;
1013 /* The formula is a second degree polynomial in
1014 * @elapsed that has the line SLIDE_SPEED * @elapsed
1015 * as tangent for @elapsed == ACCEL_THRESHOLD.
1016 * This makes @n_pixels a smooth function of elapsed time.
1018 n_pixels = (SLIDE_SPEED / ACCEL_THRESHOLD) * elapsed * elapsed -
1019 SLIDE_SPEED * elapsed + SLIDE_SPEED * ACCEL_THRESHOLD;
1023 return MIN (from + n_pixels, to);
1025 return MAX (from - n_pixels, to);
1029 compute_intermediate_allocation (GtkToolbar *toolbar,
1030 const GtkAllocation *start,
1031 const GtkAllocation *goal,
1032 GtkAllocation *intermediate)
1034 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1035 gdouble elapsed = g_timer_elapsed (priv->timer, NULL);
1037 intermediate->x = position (toolbar, start->x, goal->x, elapsed);
1038 intermediate->y = position (toolbar, start->y, goal->y, elapsed);
1039 intermediate->width = position (toolbar, start->x + start->width,
1040 goal->x + goal->width,
1041 elapsed) - intermediate->x;
1042 intermediate->height = position (toolbar, start->y + start->height,
1043 goal->y + goal->height,
1044 elapsed) - intermediate->y;
1048 fixup_allocation_for_rtl (gint total_size,
1049 GtkAllocation *allocation)
1051 allocation->x += (total_size - (2 * allocation->x + allocation->width));
1055 fixup_allocation_for_vertical (GtkAllocation *allocation)
1059 tmp = allocation->x;
1060 allocation->x = allocation->y;
1061 allocation->y = tmp;
1063 tmp = allocation->width;
1064 allocation->width = allocation->height;
1065 allocation->height = tmp;
1069 get_item_size (GtkToolbar *toolbar,
1070 ToolbarContent *content)
1072 GtkRequisition requisition;
1074 toolbar_content_size_request (content, toolbar, &requisition);
1076 if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
1078 if (toolbar_content_is_homogeneous (content, toolbar))
1079 return toolbar->button_maxw;
1081 return requisition.width;
1085 if (toolbar_content_is_homogeneous (content, toolbar))
1086 return toolbar->button_maxh;
1088 return requisition.height;
1093 slide_idle_handler (gpointer data)
1095 GtkToolbar *toolbar = data;
1096 GtkToolbarPrivate *priv;
1099 priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1101 if (priv->need_sync)
1104 priv->need_sync = FALSE;
1107 for (list = priv->content; list != NULL; list = list->next)
1109 ToolbarContent *content = list->data;
1111 GtkAllocation goal_allocation;
1112 GtkAllocation allocation;
1115 state = toolbar_content_get_state (content);
1116 toolbar_content_get_goal_allocation (content, &goal_allocation);
1117 toolbar_content_get_allocation (content, &allocation);
1121 if (state == NOT_ALLOCATED)
1123 /* an unallocated item means that size allocate has to
1124 * called at least once more
1129 /* An invisible item with a goal allocation of
1130 * 0 is already at its goal.
1132 if ((state == NORMAL || state == OVERFLOWN) &&
1133 ((goal_allocation.width != 0 &&
1134 goal_allocation.height != 0) ||
1135 toolbar_content_child_visible (content)))
1137 if ((goal_allocation.x != allocation.x ||
1138 goal_allocation.y != allocation.y ||
1139 goal_allocation.width != allocation.width ||
1140 goal_allocation.height != allocation.height))
1142 /* An item is not in its right position yet. Note
1143 * that OVERFLOWN items do get an allocation in
1144 * gtk_toolbar_size_allocate(). This way you can see
1145 * them slide back in when you drag an item off the
1152 if (toolbar_content_is_placeholder (content) &&
1153 toolbar_content_disappearing (content) &&
1154 toolbar_content_child_visible (content))
1156 /* A disappearing placeholder is still visible.
1164 gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1170 gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1172 priv->is_sliding = FALSE;
1179 rect_within (GtkAllocation *a1,
1182 return (a1->x >= a2->x &&
1183 a1->x + a1->width <= a2->x + a2->width &&
1185 a1->y + a1->height <= a2->y + a2->height);
1189 gtk_toolbar_begin_sliding (GtkToolbar *toolbar)
1191 GtkWidget *widget = GTK_WIDGET (toolbar);
1192 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1200 /* Start the sliding. This function copies the allocation of every
1201 * item into content->start_allocation. For items that haven't
1202 * been allocated yet, we calculate their position and save that
1203 * in start_allocatino along with zero width and zero height.
1205 * FIXME: It would be nice if we could share this code with
1206 * the equivalent in gtk_widget_size_allocate().
1208 priv->is_sliding = TRUE;
1211 priv->idle_id = gdk_threads_add_idle (slide_idle_handler, toolbar);
1213 rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1214 vertical = (toolbar->orientation == GTK_ORIENTATION_VERTICAL);
1215 border_width = get_internal_padding (toolbar) + GTK_CONTAINER (toolbar)->border_width;
1219 cur_x = widget->allocation.width - border_width - widget->style->xthickness;
1220 cur_y = widget->allocation.height - border_width - widget->style->ythickness;
1224 cur_x = border_width + widget->style->xthickness;
1225 cur_y = border_width + widget->style->ythickness;
1228 cur_x += widget->allocation.x;
1229 cur_y += widget->allocation.y;
1231 for (list = priv->content; list != NULL; list = list->next)
1233 ToolbarContent *content = list->data;
1234 GtkAllocation new_start_allocation;
1235 GtkAllocation item_allocation;
1238 state = toolbar_content_get_state (content);
1239 toolbar_content_get_allocation (content, &item_allocation);
1241 if ((state == NORMAL &&
1242 rect_within (&item_allocation, &(widget->allocation))) ||
1245 new_start_allocation = item_allocation;
1249 new_start_allocation.x = cur_x;
1250 new_start_allocation.y = cur_y;
1254 new_start_allocation.width = widget->allocation.width -
1255 2 * border_width - 2 * widget->style->xthickness;
1256 new_start_allocation.height = 0;
1260 new_start_allocation.width = 0;
1261 new_start_allocation.height = widget->allocation.height -
1262 2 * border_width - 2 * widget->style->ythickness;
1267 cur_y = new_start_allocation.y + new_start_allocation.height;
1269 cur_x = new_start_allocation.x;
1271 cur_x = new_start_allocation.x + new_start_allocation.width;
1273 toolbar_content_set_start_allocation (content, &new_start_allocation);
1276 /* This resize will run before the first idle handler. This
1277 * will make sure that items get the right goal allocation
1278 * so that the idle handler will not immediately return
1281 gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1282 g_timer_reset (priv->timer);
1286 gtk_toolbar_stop_sliding (GtkToolbar *toolbar)
1288 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1290 if (priv->is_sliding)
1294 priv->is_sliding = FALSE;
1298 g_source_remove (priv->idle_id);
1302 list = priv->content;
1305 ToolbarContent *content = list->data;
1308 if (toolbar_content_is_placeholder (content))
1310 toolbar_content_remove (content, toolbar);
1311 toolbar_content_free (content);
1315 gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1320 remove_item (GtkWidget *menu_item,
1323 gtk_container_remove (GTK_CONTAINER (menu_item->parent), menu_item);
1327 menu_deactivated (GtkWidget *menu,
1328 GtkToolbar *toolbar)
1330 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1331 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->arrow_button), FALSE);
1335 menu_detached (GtkWidget *toolbar,
1338 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1343 rebuild_menu (GtkToolbar *toolbar)
1345 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1346 GList *list, *children;
1350 priv->menu = GTK_MENU (gtk_menu_new());
1351 gtk_menu_attach_to_widget (priv->menu,
1352 GTK_WIDGET (toolbar),
1355 g_signal_connect (priv->menu, "deactivate",
1356 G_CALLBACK (menu_deactivated), toolbar);
1359 gtk_container_foreach (GTK_CONTAINER (priv->menu), remove_item, NULL);
1361 for (list = priv->content; list != NULL; list = list->next)
1363 ToolbarContent *content = list->data;
1365 if (toolbar_content_get_state (content) == OVERFLOWN &&
1366 !toolbar_content_is_placeholder (content))
1368 GtkWidget *menu_item = toolbar_content_retrieve_menu_item (content);
1372 g_assert (GTK_IS_MENU_ITEM (menu_item));
1373 gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menu_item);
1378 /* Remove leading and trailing separator items */
1379 children = gtk_container_get_children (GTK_CONTAINER (priv->menu));
1382 while (list && GTK_IS_SEPARATOR_MENU_ITEM (list->data))
1384 GtkWidget *child = list->data;
1386 gtk_container_remove (GTK_CONTAINER (priv->menu), child);
1389 g_list_free (children);
1391 /* Regenerate the list of children so we don't try to remove items twice */
1392 children = gtk_container_get_children (GTK_CONTAINER (priv->menu));
1394 list = g_list_last (children);
1395 while (list && GTK_IS_SEPARATOR_MENU_ITEM (list->data))
1397 GtkWidget *child = list->data;
1399 gtk_container_remove (GTK_CONTAINER (priv->menu), child);
1402 g_list_free (children);
1404 priv->need_rebuild = FALSE;
1408 gtk_toolbar_size_allocate (GtkWidget *widget,
1409 GtkAllocation *allocation)
1411 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1412 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1413 GtkAllocation *allocations;
1414 ItemState *new_states;
1415 GtkAllocation arrow_allocation;
1417 gint size, pos, short_size;
1420 gboolean need_arrow;
1421 gint n_expand_items;
1423 gint available_size;
1426 GtkRequisition arrow_requisition;
1427 gboolean overflowing;
1428 gboolean size_changed;
1430 GtkAllocation item_area;
1431 GtkShadowType shadow_type;
1433 size_changed = FALSE;
1434 if (widget->allocation.x != allocation->x ||
1435 widget->allocation.y != allocation->y ||
1436 widget->allocation.width != allocation->width ||
1437 widget->allocation.height != allocation->height)
1439 size_changed = TRUE;
1443 gtk_toolbar_stop_sliding (toolbar);
1445 widget->allocation = *allocation;
1447 border_width = GTK_CONTAINER (toolbar)->border_width;
1449 if (gtk_widget_get_realized (widget))
1451 gdk_window_move_resize (priv->event_window,
1452 allocation->x + border_width,
1453 allocation->y + border_width,
1454 allocation->width - border_width * 2,
1455 allocation->height - border_width * 2);
1458 border_width += get_internal_padding (toolbar);
1460 gtk_widget_get_child_requisition (GTK_WIDGET (priv->arrow_button),
1461 &arrow_requisition);
1463 shadow_type = get_shadow_type (toolbar);
1465 if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
1467 available_size = size = allocation->width - 2 * border_width;
1468 short_size = allocation->height - 2 * border_width;
1469 arrow_size = arrow_requisition.width;
1471 if (shadow_type != GTK_SHADOW_NONE)
1473 available_size -= 2 * widget->style->xthickness;
1474 short_size -= 2 * widget->style->ythickness;
1479 available_size = size = allocation->height - 2 * border_width;
1480 short_size = allocation->width - 2 * border_width;
1481 arrow_size = arrow_requisition.height;
1483 if (shadow_type != GTK_SHADOW_NONE)
1485 available_size -= 2 * widget->style->ythickness;
1486 short_size -= 2 * widget->style->xthickness;
1490 n_items = g_list_length (priv->content);
1491 allocations = g_new0 (GtkAllocation, n_items);
1492 new_states = g_new0 (ItemState, n_items);
1496 for (list = priv->content; list != NULL; list = list->next)
1498 ToolbarContent *content = list->data;
1500 if (toolbar_content_visible (content, toolbar))
1502 needed_size += get_item_size (toolbar, content);
1504 /* Do we need an arrow?
1506 * Assume we don't, and see if any non-separator item with a
1507 * proxy menu item is then going to overflow.
1509 if (needed_size > available_size &&
1512 priv->api_mode == NEW_API &&
1513 toolbar_content_has_proxy_menu_item (content) &&
1514 !toolbar_content_is_separator (content))
1522 size = available_size - arrow_size;
1524 size = available_size;
1526 /* calculate widths and states of items */
1527 overflowing = FALSE;
1528 for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1530 ToolbarContent *content = list->data;
1533 if (!toolbar_content_visible (content, toolbar))
1535 new_states[i] = HIDDEN;
1539 item_size = get_item_size (toolbar, content);
1540 if (item_size <= size && !overflowing)
1543 allocations[i].width = item_size;
1544 new_states[i] = NORMAL;
1549 new_states[i] = OVERFLOWN;
1550 allocations[i].width = item_size;
1554 /* calculate width of arrow */
1557 arrow_allocation.width = arrow_size;
1558 arrow_allocation.height = MAX (short_size, 1);
1561 /* expand expandable items */
1563 /* We don't expand when there is an overflow menu, because that leads to
1564 * weird jumps when items get moved to the overflow menu and the expanding
1565 * items suddenly get a lot of extra space
1569 gint max_child_expand;
1572 for (i = 0, list = priv->content; list != NULL; list = list->next, ++i)
1574 ToolbarContent *content = list->data;
1576 if (toolbar_content_get_expand (content) && new_states[i] == NORMAL)
1580 max_child_expand = get_max_child_expand (toolbar);
1581 for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1583 ToolbarContent *content = list->data;
1585 if (toolbar_content_get_expand (content) && new_states[i] == NORMAL)
1587 gint extra = size / n_expand_items;
1588 if (size % n_expand_items != 0)
1591 if (extra > max_child_expand)
1592 extra = max_child_expand;
1594 allocations[i].width += extra;
1600 g_assert (n_expand_items == 0);
1603 /* position items */
1605 for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1607 /* both NORMAL and OVERFLOWN items get a position. This ensures
1608 * that sliding will work for OVERFLOWN items too
1610 if (new_states[i] == NORMAL ||
1611 new_states[i] == OVERFLOWN)
1613 allocations[i].x = pos;
1614 allocations[i].y = border_width;
1615 allocations[i].height = short_size;
1617 pos += allocations[i].width;
1621 /* position arrow */
1624 arrow_allocation.x = available_size - border_width - arrow_allocation.width;
1625 arrow_allocation.y = border_width;
1628 item_area.x = border_width;
1629 item_area.y = border_width;
1630 item_area.width = available_size - (need_arrow? arrow_size : 0);
1631 item_area.height = short_size;
1633 /* fix up allocations in the vertical or RTL cases */
1634 if (toolbar->orientation == GTK_ORIENTATION_VERTICAL)
1636 for (i = 0; i < n_items; ++i)
1637 fixup_allocation_for_vertical (&(allocations[i]));
1640 fixup_allocation_for_vertical (&arrow_allocation);
1642 fixup_allocation_for_vertical (&item_area);
1644 else if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1646 for (i = 0; i < n_items; ++i)
1647 fixup_allocation_for_rtl (available_size, &(allocations[i]));
1650 fixup_allocation_for_rtl (available_size, &arrow_allocation);
1652 fixup_allocation_for_rtl (available_size, &item_area);
1655 /* translate the items by allocation->(x,y) */
1656 for (i = 0; i < n_items; ++i)
1658 allocations[i].x += allocation->x;
1659 allocations[i].y += allocation->y;
1661 if (shadow_type != GTK_SHADOW_NONE)
1663 allocations[i].x += widget->style->xthickness;
1664 allocations[i].y += widget->style->ythickness;
1670 arrow_allocation.x += allocation->x;
1671 arrow_allocation.y += allocation->y;
1673 if (shadow_type != GTK_SHADOW_NONE)
1675 arrow_allocation.x += widget->style->xthickness;
1676 arrow_allocation.y += widget->style->ythickness;
1680 item_area.x += allocation->x;
1681 item_area.y += allocation->y;
1682 if (shadow_type != GTK_SHADOW_NONE)
1684 item_area.x += widget->style->xthickness;
1685 item_area.y += widget->style->ythickness;
1688 /* did anything change? */
1689 for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1691 ToolbarContent *content = list->data;
1693 if (toolbar_content_get_state (content) == NORMAL &&
1694 new_states[i] != NORMAL)
1696 /* an item disappeared and we didn't change size, so begin sliding */
1697 if (!size_changed && priv->api_mode == NEW_API)
1698 gtk_toolbar_begin_sliding (toolbar);
1702 /* finally allocate the items */
1703 if (priv->is_sliding)
1705 for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1707 ToolbarContent *content = list->data;
1709 toolbar_content_set_goal_allocation (content, &(allocations[i]));
1713 elapsed = g_timer_elapsed (priv->timer, NULL);
1714 for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1716 ToolbarContent *content = list->data;
1718 if (new_states[i] == OVERFLOWN ||
1719 new_states[i] == NORMAL)
1721 GtkAllocation alloc;
1722 GtkAllocation start_allocation = { 0, };
1723 GtkAllocation goal_allocation;
1725 if (priv->is_sliding)
1727 toolbar_content_get_start_allocation (content, &start_allocation);
1728 toolbar_content_get_goal_allocation (content, &goal_allocation);
1730 compute_intermediate_allocation (toolbar,
1735 priv->need_sync = TRUE;
1739 alloc = allocations[i];
1742 if (alloc.width <= 0 || alloc.height <= 0)
1744 toolbar_content_set_child_visible (content, toolbar, FALSE);
1748 if (!rect_within (&alloc, &item_area))
1750 toolbar_content_set_child_visible (content, toolbar, FALSE);
1751 toolbar_content_size_allocate (content, &alloc);
1755 toolbar_content_set_child_visible (content, toolbar, TRUE);
1756 toolbar_content_size_allocate (content, &alloc);
1762 toolbar_content_set_child_visible (content, toolbar, FALSE);
1765 toolbar_content_set_state (content, new_states[i]);
1768 if (priv->menu && priv->need_rebuild)
1769 rebuild_menu (toolbar);
1773 gtk_widget_size_allocate (GTK_WIDGET (priv->arrow_button),
1775 gtk_widget_show (GTK_WIDGET (priv->arrow_button));
1779 gtk_widget_hide (GTK_WIDGET (priv->arrow_button));
1781 if (priv->menu && gtk_widget_get_visible (GTK_WIDGET (priv->menu)))
1782 gtk_menu_shell_deactivate (GTK_MENU_SHELL (priv->menu));
1785 g_free (allocations);
1786 g_free (new_states);
1790 gtk_toolbar_update_button_relief (GtkToolbar *toolbar)
1792 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1793 GtkReliefStyle relief;
1795 relief = get_button_relief (toolbar);
1797 if (relief != gtk_button_get_relief (GTK_BUTTON (priv->arrow_button)))
1799 gtk_toolbar_reconfigured (toolbar);
1801 gtk_button_set_relief (GTK_BUTTON (priv->arrow_button), relief);
1806 gtk_toolbar_style_set (GtkWidget *widget,
1807 GtkStyle *prev_style)
1809 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
1811 priv->max_homogeneous_pixels = -1;
1813 if (gtk_widget_get_realized (widget))
1814 gtk_style_set_background (widget->style, widget->window, widget->state);
1817 gtk_toolbar_update_button_relief (GTK_TOOLBAR (widget));
1821 gtk_toolbar_list_children_in_focus_order (GtkToolbar *toolbar,
1822 GtkDirectionType dir)
1824 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1825 GList *result = NULL;
1829 /* generate list of children in reverse logical order */
1831 for (list = priv->content; list != NULL; list = list->next)
1833 ToolbarContent *content = list->data;
1836 widget = toolbar_content_get_widget (content);
1839 result = g_list_prepend (result, widget);
1842 result = g_list_prepend (result, priv->arrow_button);
1844 rtl = (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL);
1846 /* move in logical order when
1848 * - dir is TAB_FORWARD
1850 * - in RTL mode and moving left or up
1852 * - in LTR mode and moving right or down
1854 if (dir == GTK_DIR_TAB_FORWARD ||
1855 (rtl && (dir == GTK_DIR_UP || dir == GTK_DIR_LEFT)) ||
1856 (!rtl && (dir == GTK_DIR_DOWN || dir == GTK_DIR_RIGHT)))
1858 result = g_list_reverse (result);
1865 gtk_toolbar_focus_home_or_end (GtkToolbar *toolbar,
1866 gboolean focus_home)
1868 GList *children, *list;
1869 GtkDirectionType dir = focus_home? GTK_DIR_RIGHT : GTK_DIR_LEFT;
1871 children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1873 if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1875 children = g_list_reverse (children);
1877 dir = (dir == GTK_DIR_RIGHT)? GTK_DIR_LEFT : GTK_DIR_RIGHT;
1880 for (list = children; list != NULL; list = list->next)
1882 GtkWidget *child = list->data;
1884 if (GTK_CONTAINER (toolbar)->focus_child == child)
1887 if (gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
1891 g_list_free (children);
1896 /* Keybinding handler. This function is called when the user presses
1897 * Ctrl TAB or an arrow key.
1900 gtk_toolbar_move_focus (GtkWidget *widget,
1901 GtkDirectionType dir)
1903 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1904 GtkContainer *container = GTK_CONTAINER (toolbar);
1906 gboolean try_focus = FALSE;
1909 if (container->focus_child &&
1910 gtk_widget_child_focus (container->focus_child, dir))
1915 children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1917 for (list = children; list != NULL; list = list->next)
1919 GtkWidget *child = list->data;
1921 if (try_focus && gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
1924 if (child == GTK_CONTAINER (toolbar)->focus_child)
1928 g_list_free (children);
1931 /* The focus handler for the toolbar. It called when the user presses
1932 * TAB or otherwise tries to focus the toolbar.
1935 gtk_toolbar_focus (GtkWidget *widget,
1936 GtkDirectionType dir)
1938 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1939 GList *children, *list;
1940 gboolean result = FALSE;
1942 /* if focus is already somewhere inside the toolbar then return FALSE.
1943 * The only way focus can stay inside the toolbar is when the user presses
1944 * arrow keys or Ctrl TAB (both of which are handled by the
1945 * gtk_toolbar_move_focus() keybinding function.
1947 if (GTK_CONTAINER (widget)->focus_child)
1950 children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1952 for (list = children; list != NULL; list = list->next)
1954 GtkWidget *child = list->data;
1956 if (gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
1963 g_list_free (children);
1968 static GtkSettings *
1969 toolbar_get_settings (GtkToolbar *toolbar)
1971 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1972 return priv->settings;
1976 style_change_notify (GtkToolbar *toolbar)
1978 if (!toolbar->style_set)
1980 /* pretend it was set, then unset, thus reverting to new default */
1981 toolbar->style_set = TRUE;
1982 gtk_toolbar_unset_style (toolbar);
1987 icon_size_change_notify (GtkToolbar *toolbar)
1989 if (!toolbar->icon_size_set)
1991 /* pretend it was set, then unset, thus reverting to new default */
1992 toolbar->icon_size_set = TRUE;
1993 gtk_toolbar_unset_icon_size (toolbar);
1998 animation_change_notify (GtkToolbar *toolbar)
2000 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2001 GtkSettings *settings = toolbar_get_settings (toolbar);
2005 g_object_get (settings,
2006 "gtk-enable-animations", &animation,
2009 animation = DEFAULT_ANIMATION_STATE;
2011 priv->animation = animation;
2015 settings_change_notify (GtkSettings *settings,
2016 const GParamSpec *pspec,
2017 GtkToolbar *toolbar)
2019 if (! strcmp (pspec->name, "gtk-toolbar-style"))
2020 style_change_notify (toolbar);
2021 else if (! strcmp (pspec->name, "gtk-toolbar-icon-size"))
2022 icon_size_change_notify (toolbar);
2023 else if (! strcmp (pspec->name, "gtk-enable-animations"))
2024 animation_change_notify (toolbar);
2028 gtk_toolbar_screen_changed (GtkWidget *widget,
2029 GdkScreen *previous_screen)
2031 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
2032 GtkToolbar *toolbar = GTK_TOOLBAR (widget);
2033 GtkSettings *old_settings = toolbar_get_settings (toolbar);
2034 GtkSettings *settings;
2036 if (gtk_widget_has_screen (GTK_WIDGET (toolbar)))
2037 settings = gtk_widget_get_settings (GTK_WIDGET (toolbar));
2041 if (settings == old_settings)
2046 g_signal_handler_disconnect (old_settings, priv->settings_connection);
2048 g_object_unref (old_settings);
2053 priv->settings_connection =
2054 g_signal_connect (settings, "notify",
2055 G_CALLBACK (settings_change_notify),
2058 priv->settings = g_object_ref (settings);
2061 priv->settings = NULL;
2063 style_change_notify (toolbar);
2064 icon_size_change_notify (toolbar);
2065 animation_change_notify (toolbar);
2069 find_drop_index (GtkToolbar *toolbar,
2073 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2074 GList *interesting_content;
2076 GtkOrientation orientation;
2077 GtkTextDirection direction;
2078 gint best_distance = G_MAXINT;
2082 ToolbarContent *best_content;
2083 GtkAllocation allocation;
2085 /* list items we care about wrt. drag and drop */
2086 interesting_content = NULL;
2087 for (list = priv->content; list != NULL; list = list->next)
2089 ToolbarContent *content = list->data;
2091 if (toolbar_content_get_state (content) == NORMAL)
2092 interesting_content = g_list_prepend (interesting_content, content);
2094 interesting_content = g_list_reverse (interesting_content);
2096 if (!interesting_content)
2099 orientation = toolbar->orientation;
2100 direction = gtk_widget_get_direction (GTK_WIDGET (toolbar));
2102 /* distance to first interesting item */
2103 best_content = interesting_content->data;
2104 toolbar_content_get_allocation (best_content, &allocation);
2106 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2110 if (direction == GTK_TEXT_DIR_LTR)
2113 pos = allocation.x + allocation.width;
2121 best_content = NULL;
2122 best_distance = ABS (pos - cursor);
2124 /* distance to far end of each item */
2125 for (list = interesting_content; list != NULL; list = list->next)
2127 ToolbarContent *content = list->data;
2129 toolbar_content_get_allocation (content, &allocation);
2131 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2133 if (direction == GTK_TEXT_DIR_LTR)
2134 pos = allocation.x + allocation.width;
2140 pos = allocation.y + allocation.height;
2143 distance = ABS (pos - cursor);
2145 if (distance < best_distance)
2147 best_distance = distance;
2148 best_content = content;
2152 g_list_free (interesting_content);
2157 return g_list_index (priv->content, best_content) + 1;
2161 reset_all_placeholders (GtkToolbar *toolbar)
2163 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2166 for (list = priv->content; list != NULL; list = list->next)
2168 ToolbarContent *content = list->data;
2169 if (toolbar_content_is_placeholder (content))
2170 toolbar_content_set_disappearing (content, TRUE);
2175 physical_to_logical (GtkToolbar *toolbar,
2178 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2182 g_assert (physical >= 0);
2185 for (list = priv->content; list && physical > 0; list = list->next)
2187 ToolbarContent *content = list->data;
2189 if (!toolbar_content_is_placeholder (content))
2194 g_assert (physical == 0);
2200 logical_to_physical (GtkToolbar *toolbar,
2203 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2207 g_assert (logical >= 0);
2210 for (list = priv->content; list; list = list->next)
2212 ToolbarContent *content = list->data;
2214 if (!toolbar_content_is_placeholder (content))
2224 g_assert (logical == 0);
2230 * gtk_toolbar_set_drop_highlight_item:
2231 * @toolbar: a #GtkToolbar
2232 * @tool_item: (allow-none): a #GtkToolItem, or %NULL to turn of highlighting
2233 * @index_: a position on @toolbar
2235 * Highlights @toolbar to give an idea of what it would look like
2236 * if @item was added to @toolbar at the position indicated by @index_.
2237 * If @item is %NULL, highlighting is turned off. In that case @index_
2240 * The @tool_item passed to this function must not be part of any widget
2241 * hierarchy. When an item is set as drop highlight item it can not
2242 * added to any widget hierarchy or used as highlight item for another
2248 gtk_toolbar_set_drop_highlight_item (GtkToolbar *toolbar,
2249 GtkToolItem *tool_item,
2252 ToolbarContent *content;
2253 GtkToolbarPrivate *priv;
2255 GtkRequisition requisition;
2256 GtkRequisition old_requisition;
2257 gboolean restart_sliding;
2259 g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2260 g_return_if_fail (tool_item == NULL || GTK_IS_TOOL_ITEM (tool_item));
2262 gtk_toolbar_check_new_api (toolbar);
2264 priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2268 if (priv->highlight_tool_item)
2270 gtk_widget_unparent (GTK_WIDGET (priv->highlight_tool_item));
2271 g_object_unref (priv->highlight_tool_item);
2272 priv->highlight_tool_item = NULL;
2275 reset_all_placeholders (toolbar);
2276 gtk_toolbar_begin_sliding (toolbar);
2280 n_items = gtk_toolbar_get_n_items (toolbar);
2281 if (index_ < 0 || index_ > n_items)
2284 if (tool_item != priv->highlight_tool_item)
2286 if (priv->highlight_tool_item)
2287 g_object_unref (priv->highlight_tool_item);
2289 g_object_ref_sink (tool_item);
2291 priv->highlight_tool_item = tool_item;
2293 gtk_widget_set_parent (GTK_WIDGET (priv->highlight_tool_item),
2294 GTK_WIDGET (toolbar));
2297 index_ = logical_to_physical (toolbar, index_);
2299 content = g_list_nth_data (priv->content, index_);
2303 ToolbarContent *prev_content;
2305 prev_content = g_list_nth_data (priv->content, index_ - 1);
2307 if (prev_content && toolbar_content_is_placeholder (prev_content))
2308 content = prev_content;
2311 if (!content || !toolbar_content_is_placeholder (content))
2313 GtkWidget *placeholder;
2315 placeholder = GTK_WIDGET (gtk_separator_tool_item_new ());
2317 content = toolbar_content_new_tool_item (toolbar,
2318 GTK_TOOL_ITEM (placeholder),
2320 gtk_widget_show (placeholder);
2324 g_assert (toolbar_content_is_placeholder (content));
2326 gtk_widget_size_request (GTK_WIDGET (priv->highlight_tool_item),
2329 toolbar_content_set_expand (content, gtk_tool_item_get_expand (tool_item));
2331 restart_sliding = FALSE;
2332 toolbar_content_size_request (content, toolbar, &old_requisition);
2333 if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2335 requisition.height = -1;
2336 if (requisition.width != old_requisition.width)
2337 restart_sliding = TRUE;
2341 requisition.width = -1;
2342 if (requisition.height != old_requisition.height)
2343 restart_sliding = TRUE;
2346 if (toolbar_content_disappearing (content))
2347 restart_sliding = TRUE;
2349 reset_all_placeholders (toolbar);
2350 toolbar_content_set_disappearing (content, FALSE);
2352 toolbar_content_set_size_request (content,
2353 requisition.width, requisition.height);
2355 if (restart_sliding)
2356 gtk_toolbar_begin_sliding (toolbar);
2360 gtk_toolbar_get_child_property (GtkContainer *container,
2366 GtkToolItem *item = GTK_TOOL_ITEM (child);
2368 switch (property_id)
2370 case CHILD_PROP_HOMOGENEOUS:
2371 g_value_set_boolean (value, gtk_tool_item_get_homogeneous (item));
2374 case CHILD_PROP_EXPAND:
2375 g_value_set_boolean (value, gtk_tool_item_get_expand (item));
2379 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2385 gtk_toolbar_set_child_property (GtkContainer *container,
2388 const GValue *value,
2391 switch (property_id)
2393 case CHILD_PROP_HOMOGENEOUS:
2394 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2397 case CHILD_PROP_EXPAND:
2398 gtk_tool_item_set_expand (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2402 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2408 gtk_toolbar_show_all (GtkWidget *widget)
2410 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
2413 for (list = priv->content; list != NULL; list = list->next)
2415 ToolbarContent *content = list->data;
2417 toolbar_content_show_all (content);
2420 gtk_widget_show (widget);
2424 gtk_toolbar_hide_all (GtkWidget *widget)
2426 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
2429 for (list = priv->content; list != NULL; list = list->next)
2431 ToolbarContent *content = list->data;
2433 toolbar_content_hide_all (content);
2436 gtk_widget_hide (widget);
2440 gtk_toolbar_add (GtkContainer *container,
2443 GtkToolbar *toolbar = GTK_TOOLBAR (container);
2445 gtk_toolbar_insert (toolbar, GTK_TOOL_ITEM (widget), -1);
2449 gtk_toolbar_remove (GtkContainer *container,
2452 GtkToolbar *toolbar = GTK_TOOLBAR (container);
2453 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2454 ToolbarContent *content_to_remove;
2457 content_to_remove = NULL;
2458 for (list = priv->content; list != NULL; list = list->next)
2460 ToolbarContent *content = list->data;
2463 child = toolbar_content_get_widget (content);
2464 if (child && child == widget)
2466 content_to_remove = content;
2471 g_return_if_fail (content_to_remove != NULL);
2473 toolbar_content_remove (content_to_remove, toolbar);
2474 toolbar_content_free (content_to_remove);
2478 gtk_toolbar_forall (GtkContainer *container,
2479 gboolean include_internals,
2480 GtkCallback callback,
2481 gpointer callback_data)
2483 GtkToolbar *toolbar = GTK_TOOLBAR (container);
2484 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2487 g_return_if_fail (callback != NULL);
2489 list = priv->content;
2492 ToolbarContent *content = list->data;
2493 GList *next = list->next;
2495 if (include_internals || !toolbar_content_is_placeholder (content))
2497 GtkWidget *child = toolbar_content_get_widget (content);
2500 callback (child, callback_data);
2506 if (include_internals)
2507 callback (priv->arrow_button, callback_data);
2511 gtk_toolbar_child_type (GtkContainer *container)
2513 return GTK_TYPE_TOOL_ITEM;
2517 gtk_toolbar_reconfigured (GtkToolbar *toolbar)
2519 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2522 list = priv->content;
2525 ToolbarContent *content = list->data;
2526 GList *next = list->next;
2528 toolbar_content_toolbar_reconfigured (content, toolbar);
2535 gtk_toolbar_orientation_changed (GtkToolbar *toolbar,
2536 GtkOrientation orientation)
2538 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2539 if (toolbar->orientation != orientation)
2541 toolbar->orientation = orientation;
2543 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2544 gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
2546 gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
2548 gtk_toolbar_reconfigured (toolbar);
2550 gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2551 g_object_notify (G_OBJECT (toolbar), "orientation");
2556 gtk_toolbar_real_style_changed (GtkToolbar *toolbar,
2557 GtkToolbarStyle style)
2559 if (toolbar->style != style)
2561 toolbar->style = style;
2563 gtk_toolbar_reconfigured (toolbar);
2565 gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2566 g_object_notify (G_OBJECT (toolbar), "toolbar-style");
2571 menu_position_func (GtkMenu *menu,
2577 GtkToolbar *toolbar = GTK_TOOLBAR (user_data);
2578 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2580 GtkRequisition menu_req;
2581 GdkRectangle monitor;
2585 gtk_widget_size_request (priv->arrow_button, &req);
2586 gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
2588 screen = gtk_widget_get_screen (GTK_WIDGET (menu));
2589 monitor_num = gdk_screen_get_monitor_at_window (screen, priv->arrow_button->window);
2590 if (monitor_num < 0)
2592 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
2594 gdk_window_get_origin (GTK_BUTTON (priv->arrow_button)->event_window, x, y);
2595 if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2597 if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR)
2598 *x += priv->arrow_button->allocation.width - req.width;
2600 *x += req.width - menu_req.width;
2602 if ((*y + priv->arrow_button->allocation.height + menu_req.height) <= monitor.y + monitor.height)
2603 *y += priv->arrow_button->allocation.height;
2604 else if ((*y - menu_req.height) >= monitor.y)
2605 *y -= menu_req.height;
2606 else if (monitor.y + monitor.height - (*y + priv->arrow_button->allocation.height) > *y)
2607 *y += priv->arrow_button->allocation.height;
2609 *y -= menu_req.height;
2613 if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR)
2614 *x += priv->arrow_button->allocation.width;
2616 *x -= menu_req.width;
2618 if (*y + menu_req.height > monitor.y + monitor.height &&
2619 *y + priv->arrow_button->allocation.height - monitor.y > monitor.y + monitor.height - *y)
2620 *y += priv->arrow_button->allocation.height - menu_req.height;
2627 show_menu (GtkToolbar *toolbar,
2628 GdkEventButton *event)
2630 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2632 rebuild_menu (toolbar);
2634 gtk_widget_show_all (GTK_WIDGET (priv->menu));
2636 gtk_menu_popup (priv->menu, NULL, NULL,
2637 menu_position_func, toolbar,
2638 event? event->button : 0,
2639 event? event->time : gtk_get_current_event_time());
2643 gtk_toolbar_arrow_button_clicked (GtkWidget *button,
2644 GtkToolbar *toolbar)
2646 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2648 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->arrow_button)) &&
2649 (!priv->menu || !gtk_widget_get_visible (GTK_WIDGET (priv->menu))))
2651 /* We only get here when the button is clicked with the keyboard,
2652 * because mouse button presses result in the menu being shown so
2653 * that priv->menu would be non-NULL and visible.
2655 show_menu (toolbar, NULL);
2656 gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2661 gtk_toolbar_arrow_button_press (GtkWidget *button,
2662 GdkEventButton *event,
2663 GtkToolbar *toolbar)
2665 show_menu (toolbar, event);
2666 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2672 gtk_toolbar_button_press (GtkWidget *toolbar,
2673 GdkEventButton *event)
2675 if (event->button == 3)
2677 gboolean return_value;
2679 g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2680 (int)event->x_root, (int)event->y_root, event->button,
2683 return return_value;
2690 gtk_toolbar_popup_menu (GtkWidget *toolbar)
2692 gboolean return_value;
2693 /* This function is the handler for the "popup menu" keybinding,
2694 * ie., it is called when the user presses Shift F10
2696 g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2697 -1, -1, -1, &return_value);
2699 return return_value;
2705 * Creates a new toolbar.
2707 * Return Value: the newly-created toolbar.
2710 gtk_toolbar_new (void)
2712 GtkToolbar *toolbar;
2714 toolbar = g_object_new (GTK_TYPE_TOOLBAR, NULL);
2716 return GTK_WIDGET (toolbar);
2720 * gtk_toolbar_insert:
2721 * @toolbar: a #GtkToolbar
2722 * @item: a #GtkToolItem
2723 * @pos: the position of the new item
2725 * Insert a #GtkToolItem into the toolbar at position @pos. If @pos is
2726 * 0 the item is prepended to the start of the toolbar. If @pos is
2727 * negative, the item is appended to the end of the toolbar.
2732 gtk_toolbar_insert (GtkToolbar *toolbar,
2736 g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2737 g_return_if_fail (GTK_IS_TOOL_ITEM (item));
2739 if (!gtk_toolbar_check_new_api (toolbar))
2743 pos = logical_to_physical (toolbar, pos);
2745 toolbar_content_new_tool_item (toolbar, item, FALSE, pos);
2749 * gtk_toolbar_get_item_index:
2750 * @toolbar: a #GtkToolbar
2751 * @item: a #GtkToolItem that is a child of @toolbar
2753 * Returns the position of @item on the toolbar, starting from 0.
2754 * It is an error if @item is not a child of the toolbar.
2756 * Return value: the position of item on the toolbar.
2761 gtk_toolbar_get_item_index (GtkToolbar *toolbar,
2764 GtkToolbarPrivate *priv;
2768 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2769 g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1);
2770 g_return_val_if_fail (GTK_WIDGET (item)->parent == GTK_WIDGET (toolbar), -1);
2772 if (!gtk_toolbar_check_new_api (toolbar))
2775 priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2778 for (list = priv->content; list != NULL; list = list->next)
2780 ToolbarContent *content = list->data;
2783 widget = toolbar_content_get_widget (content);
2785 if (item == GTK_TOOL_ITEM (widget))
2791 return physical_to_logical (toolbar, n);
2795 * gtk_toolbar_set_style:
2796 * @toolbar: a #GtkToolbar.
2797 * @style: the new style for @toolbar.
2799 * Alters the view of @toolbar to display either icons only, text only, or both.
2802 gtk_toolbar_set_style (GtkToolbar *toolbar,
2803 GtkToolbarStyle style)
2805 g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2807 toolbar->style_set = TRUE;
2808 g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2812 * gtk_toolbar_get_style:
2813 * @toolbar: a #GtkToolbar
2815 * Retrieves whether the toolbar has text, icons, or both . See
2816 * gtk_toolbar_set_style().
2818 * Return value: the current style of @toolbar
2821 gtk_toolbar_get_style (GtkToolbar *toolbar)
2823 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE);
2825 return toolbar->style;
2829 * gtk_toolbar_unset_style:
2830 * @toolbar: a #GtkToolbar
2832 * Unsets a toolbar style set with gtk_toolbar_set_style(), so that
2833 * user preferences will be used to determine the toolbar style.
2836 gtk_toolbar_unset_style (GtkToolbar *toolbar)
2838 GtkToolbarStyle style;
2840 g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2842 if (toolbar->style_set)
2844 GtkSettings *settings = toolbar_get_settings (toolbar);
2847 g_object_get (settings,
2848 "gtk-toolbar-style", &style,
2851 style = DEFAULT_TOOLBAR_STYLE;
2853 if (style != toolbar->style)
2854 g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2856 toolbar->style_set = FALSE;
2861 * gtk_toolbar_get_n_items:
2862 * @toolbar: a #GtkToolbar
2864 * Returns the number of items on the toolbar.
2866 * Return value: the number of items on the toolbar
2871 gtk_toolbar_get_n_items (GtkToolbar *toolbar)
2873 GtkToolbarPrivate *priv;
2875 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2877 if (!gtk_toolbar_check_new_api (toolbar))
2880 priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2882 return physical_to_logical (toolbar, g_list_length (priv->content));
2886 * gtk_toolbar_get_nth_item:
2887 * @toolbar: a #GtkToolbar
2888 * @n: A position on the toolbar
2890 * Returns the @n<!-- -->'th item on @toolbar, or %NULL if the
2891 * toolbar does not contain an @n<!-- -->'th item.
2893 * Return value: The @n<!-- -->'th #GtkToolItem on @toolbar, or %NULL if there
2894 * isn't an @n<!-- -->'th item.
2899 gtk_toolbar_get_nth_item (GtkToolbar *toolbar,
2902 GtkToolbarPrivate *priv;
2903 ToolbarContent *content;
2906 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
2908 if (!gtk_toolbar_check_new_api (toolbar))
2911 n_items = gtk_toolbar_get_n_items (toolbar);
2913 if (n < 0 || n >= n_items)
2916 priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2918 content = g_list_nth_data (priv->content, logical_to_physical (toolbar, n));
2921 g_assert (!toolbar_content_is_placeholder (content));
2923 return GTK_TOOL_ITEM (toolbar_content_get_widget (content));
2927 * gtk_toolbar_get_icon_size:
2928 * @toolbar: a #GtkToolbar
2930 * Retrieves the icon size for the toolbar. See gtk_toolbar_set_icon_size().
2932 * Return value: (type int): the current icon size for the icons on
2936 gtk_toolbar_get_icon_size (GtkToolbar *toolbar)
2938 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_ICON_SIZE);
2940 return toolbar->icon_size;
2944 * gtk_toolbar_get_relief_style:
2945 * @toolbar: a #GtkToolbar
2947 * Returns the relief style of buttons on @toolbar. See
2948 * gtk_button_set_relief().
2950 * Return value: The relief style of buttons on @toolbar.
2955 gtk_toolbar_get_relief_style (GtkToolbar *toolbar)
2957 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_RELIEF_NONE);
2959 return get_button_relief (toolbar);
2963 * gtk_toolbar_set_show_arrow:
2964 * @toolbar: a #GtkToolbar
2965 * @show_arrow: Whether to show an overflow menu
2967 * Sets whether to show an overflow menu when
2968 * @toolbar doesn't have room for all items on it. If %TRUE,
2969 * items that there are not room are available through an
2975 gtk_toolbar_set_show_arrow (GtkToolbar *toolbar,
2976 gboolean show_arrow)
2978 GtkToolbarPrivate *priv;
2980 g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2982 priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2983 show_arrow = show_arrow != FALSE;
2985 if (priv->show_arrow != show_arrow)
2987 priv->show_arrow = show_arrow;
2989 if (!priv->show_arrow)
2990 gtk_widget_hide (priv->arrow_button);
2992 gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2993 g_object_notify (G_OBJECT (toolbar), "show-arrow");
2998 * gtk_toolbar_get_show_arrow:
2999 * @toolbar: a #GtkToolbar
3001 * Returns whether the toolbar has an overflow menu.
3002 * See gtk_toolbar_set_show_arrow().
3004 * Return value: %TRUE if the toolbar has an overflow menu.
3009 gtk_toolbar_get_show_arrow (GtkToolbar *toolbar)
3011 GtkToolbarPrivate *priv;
3013 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
3015 if (!gtk_toolbar_check_new_api (toolbar))
3018 priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3020 return priv->show_arrow;
3024 * gtk_toolbar_get_drop_index:
3025 * @toolbar: a #GtkToolbar
3026 * @x: x coordinate of a point on the toolbar
3027 * @y: y coordinate of a point on the toolbar
3029 * Returns the position corresponding to the indicated point on
3030 * @toolbar. This is useful when dragging items to the toolbar:
3031 * this function returns the position a new item should be
3034 * @x and @y are in @toolbar coordinates.
3036 * Return value: The position corresponding to the point (@x, @y) on the toolbar.
3041 gtk_toolbar_get_drop_index (GtkToolbar *toolbar,
3045 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
3047 if (!gtk_toolbar_check_new_api (toolbar))
3050 return physical_to_logical (toolbar, find_drop_index (toolbar, x, y));
3054 gtk_toolbar_finalize (GObject *object)
3057 GtkToolbar *toolbar = GTK_TOOLBAR (object);
3058 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3060 if (priv->arrow_button)
3061 gtk_widget_unparent (priv->arrow_button);
3063 for (list = priv->content; list != NULL; list = list->next)
3065 ToolbarContent *content = list->data;
3067 toolbar_content_free (content);
3070 g_list_free (priv->content);
3071 g_list_free (toolbar->children);
3073 g_timer_destroy (priv->timer);
3076 gtk_widget_destroy (GTK_WIDGET (priv->menu));
3079 g_source_remove (priv->idle_id);
3081 G_OBJECT_CLASS (gtk_toolbar_parent_class)->finalize (object);
3085 * gtk_toolbar_set_icon_size:
3086 * @toolbar: A #GtkToolbar
3087 * @icon_size: (type int): The #GtkIconSize that stock icons in the
3088 * toolbar shall have.
3090 * This function sets the size of stock icons in the toolbar. You
3091 * can call it both before you add the icons and after they've been
3092 * added. The size you set will override user preferences for the default
3095 * This should only be used for special-purpose toolbars, normal
3096 * application toolbars should respect the user preferences for the
3100 gtk_toolbar_set_icon_size (GtkToolbar *toolbar,
3101 GtkIconSize icon_size)
3103 g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3104 g_return_if_fail (icon_size != GTK_ICON_SIZE_INVALID);
3106 if (!toolbar->icon_size_set)
3108 toolbar->icon_size_set = TRUE;
3109 g_object_notify (G_OBJECT (toolbar), "icon-size-set");
3112 if (toolbar->icon_size == icon_size)
3115 toolbar->icon_size = icon_size;
3116 g_object_notify (G_OBJECT (toolbar), "icon-size");
3118 gtk_toolbar_reconfigured (toolbar);
3120 gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3124 * gtk_toolbar_unset_icon_size:
3125 * @toolbar: a #GtkToolbar
3127 * Unsets toolbar icon size set with gtk_toolbar_set_icon_size(), so that
3128 * user preferences will be used to determine the icon size.
3131 gtk_toolbar_unset_icon_size (GtkToolbar *toolbar)
3135 g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3137 if (toolbar->icon_size_set)
3139 GtkSettings *settings = toolbar_get_settings (toolbar);
3143 g_object_get (settings,
3144 "gtk-toolbar-icon-size", &size,
3148 size = DEFAULT_ICON_SIZE;
3150 if (size != toolbar->icon_size)
3152 gtk_toolbar_set_icon_size (toolbar, size);
3153 g_object_notify (G_OBJECT (toolbar), "icon-size");
3156 toolbar->icon_size_set = FALSE;
3157 g_object_notify (G_OBJECT (toolbar), "icon-size-set");
3162 set_child_packing_and_visibility(GtkToolbar *toolbar,
3163 GtkToolbarChild *child)
3168 box = gtk_bin_get_child (GTK_BIN (child->widget));
3170 g_return_if_fail (GTK_IS_BOX (box));
3174 expand = (toolbar->style != GTK_TOOLBAR_BOTH);
3176 gtk_box_set_child_packing (GTK_BOX (box), child->label,
3177 expand, expand, 0, GTK_PACK_END);
3179 if (toolbar->style != GTK_TOOLBAR_ICONS)
3180 gtk_widget_show (child->label);
3182 gtk_widget_hide (child->label);
3187 expand = (toolbar->style != GTK_TOOLBAR_BOTH_HORIZ);
3189 gtk_box_set_child_packing (GTK_BOX (box), child->icon,
3190 expand, expand, 0, GTK_PACK_END);
3192 if (toolbar->style != GTK_TOOLBAR_TEXT)
3193 gtk_widget_show (child->icon);
3195 gtk_widget_hide (child->icon);
3200 internal_insert_element (GtkToolbar *toolbar,
3201 GtkToolbarChildType type,
3204 const char *tooltip_text,
3205 const char *tooltip_private_text,
3213 ToolbarContent *content;
3214 char *free_me = NULL;
3216 GtkWidget *child_widget;
3217 GtkWidget *child_label;
3218 GtkWidget *child_icon;
3220 g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
3221 if (type == GTK_TOOLBAR_CHILD_WIDGET)
3222 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
3223 else if (type != GTK_TOOLBAR_CHILD_RADIOBUTTON)
3224 g_return_val_if_fail (widget == NULL, NULL);
3225 if (GTK_IS_TOOL_ITEM (widget))
3226 g_warning (MIXED_API_WARNING);
3228 if (!gtk_toolbar_check_old_api (toolbar))
3231 child_widget = NULL;
3237 case GTK_TOOLBAR_CHILD_SPACE:
3240 case GTK_TOOLBAR_CHILD_WIDGET:
3241 child_widget = widget;
3244 case GTK_TOOLBAR_CHILD_BUTTON:
3245 case GTK_TOOLBAR_CHILD_TOGGLEBUTTON:
3246 case GTK_TOOLBAR_CHILD_RADIOBUTTON:
3247 if (type == GTK_TOOLBAR_CHILD_BUTTON)
3249 child_widget = gtk_button_new ();
3251 else if (type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
3253 child_widget = gtk_toggle_button_new ();
3254 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child_widget), FALSE);
3256 else /* type == GTK_TOOLBAR_CHILD_RADIOBUTTON */
3258 GSList *group = NULL;
3261 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
3263 child_widget = gtk_radio_button_new (group);
3264 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child_widget), FALSE);
3267 gtk_button_set_relief (GTK_BUTTON (child_widget), get_button_relief (toolbar));
3268 gtk_button_set_focus_on_click (GTK_BUTTON (child_widget), FALSE);
3272 g_signal_connect (child_widget, "clicked",
3273 callback, user_data);
3276 if (toolbar->style == GTK_TOOLBAR_BOTH_HORIZ)
3277 box = gtk_hbox_new (FALSE, 0);
3279 box = gtk_vbox_new (FALSE, 0);
3281 gtk_container_add (GTK_CONTAINER (child_widget), box);
3282 gtk_widget_show (box);
3284 if (text && use_stock)
3286 GtkStockItem stock_item;
3287 if (gtk_stock_lookup (text, &stock_item))
3290 icon = gtk_image_new_from_stock (text, toolbar->icon_size);
3292 text = free_me = _gtk_toolbar_elide_underscores (stock_item.label);
3298 child_label = gtk_label_new (text);
3300 gtk_container_add (GTK_CONTAINER (box), child_label);
3305 child_icon = GTK_WIDGET (icon);
3306 gtk_container_add (GTK_CONTAINER (box), child_icon);
3309 gtk_widget_show (child_widget);
3313 g_assert_not_reached ();
3317 if ((type != GTK_TOOLBAR_CHILD_SPACE) && tooltip_text)
3319 gtk_widget_set_tooltip_text (child_widget, tooltip_text);
3322 content = toolbar_content_new_compatibility (toolbar, type, child_widget,
3323 child_icon, child_label, position);
3327 return child_widget;
3331 * ToolbarContent methods
3339 struct _ToolbarContent
3349 GtkAllocation start_allocation;
3350 GtkAllocation goal_allocation;
3351 guint is_placeholder : 1;
3352 guint disappearing : 1;
3358 GtkToolbarChild child;
3359 GtkAllocation space_allocation;
3360 guint space_visible : 1;
3365 static ToolbarContent *
3366 toolbar_content_new_tool_item (GtkToolbar *toolbar,
3368 gboolean is_placeholder,
3371 ToolbarContent *content;
3372 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3374 content = g_slice_new0 (ToolbarContent);
3376 content->type = TOOL_ITEM;
3377 content->state = NOT_ALLOCATED;
3378 content->u.tool_item.item = item;
3379 content->u.tool_item.is_placeholder = is_placeholder;
3381 gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar));
3383 priv->content = g_list_insert (priv->content, content, pos);
3385 if (!is_placeholder)
3387 toolbar->num_children++;
3389 gtk_toolbar_stop_sliding (toolbar);
3392 gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3393 priv->need_rebuild = TRUE;
3398 static ToolbarContent *
3399 toolbar_content_new_compatibility (GtkToolbar *toolbar,
3400 GtkToolbarChildType type,
3406 ToolbarContent *content;
3407 GtkToolbarChild *child;
3408 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3410 content = g_slice_new0 (ToolbarContent);
3412 child = &(content->u.compatibility.child);
3414 content->type = COMPATIBILITY;
3416 child->widget = widget;
3418 child->label = label;
3420 if (type != GTK_TOOLBAR_CHILD_SPACE)
3422 gtk_widget_set_parent (child->widget, GTK_WIDGET (toolbar));
3426 content->u.compatibility.space_visible = TRUE;
3427 gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3430 if (type == GTK_TOOLBAR_CHILD_BUTTON ||
3431 type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
3432 type == GTK_TOOLBAR_CHILD_RADIOBUTTON)
3434 set_child_packing_and_visibility (toolbar, child);
3437 priv->content = g_list_insert (priv->content, content, pos);
3438 toolbar->children = g_list_insert (toolbar->children, child, pos);
3439 priv->need_rebuild = TRUE;
3441 toolbar->num_children++;
3447 toolbar_content_remove (ToolbarContent *content,
3448 GtkToolbar *toolbar)
3450 GtkToolbarChild *child;
3451 GtkToolbarPrivate *priv;
3453 priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3455 switch (content->type)
3458 gtk_widget_unparent (GTK_WIDGET (content->u.tool_item.item));
3462 child = &(content->u.compatibility.child);
3464 if (child->type != GTK_TOOLBAR_CHILD_SPACE)
3466 g_object_ref (child->widget);
3467 gtk_widget_unparent (child->widget);
3468 gtk_widget_destroy (child->widget);
3469 g_object_unref (child->widget);
3472 toolbar->children = g_list_remove (toolbar->children, child);
3476 priv->content = g_list_remove (priv->content, content);
3478 if (!toolbar_content_is_placeholder (content))
3479 toolbar->num_children--;
3481 gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3482 priv->need_rebuild = TRUE;
3486 toolbar_content_free (ToolbarContent *content)
3488 g_slice_free (ToolbarContent, content);
3492 calculate_max_homogeneous_pixels (GtkWidget *widget)
3494 PangoContext *context;
3495 PangoFontMetrics *metrics;
3498 context = gtk_widget_get_pango_context (widget);
3499 metrics = pango_context_get_metrics (context,
3500 widget->style->font_desc,
3501 pango_context_get_language (context));
3502 char_width = pango_font_metrics_get_approximate_char_width (metrics);
3503 pango_font_metrics_unref (metrics);
3505 return PANGO_PIXELS (MAX_HOMOGENEOUS_N_CHARS * char_width);
3509 toolbar_content_expose (ToolbarContent *content,
3510 GtkContainer *container,
3511 GdkEventExpose *expose)
3513 GtkToolbar *toolbar = GTK_TOOLBAR (container);
3514 GtkToolbarChild *child;
3515 GtkWidget *widget = NULL; /* quiet gcc */
3517 switch (content->type)
3520 if (!content->u.tool_item.is_placeholder)
3521 widget = GTK_WIDGET (content->u.tool_item.item);
3525 child = &(content->u.compatibility.child);
3527 if (child->type == GTK_TOOLBAR_CHILD_SPACE)
3529 if (content->u.compatibility.space_visible &&
3530 get_space_style (toolbar) == GTK_TOOLBAR_SPACE_LINE)
3531 _gtk_toolbar_paint_space_line (GTK_WIDGET (toolbar), toolbar,
3533 &content->u.compatibility.space_allocation);
3537 widget = child->widget;
3542 gtk_container_propagate_expose (container, widget, expose);
3546 toolbar_content_visible (ToolbarContent *content,
3547 GtkToolbar *toolbar)
3551 switch (content->type)
3554 item = content->u.tool_item.item;
3556 if (!gtk_widget_get_visible (GTK_WIDGET (item)))
3559 if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL &&
3560 gtk_tool_item_get_visible_horizontal (item))
3563 if ((toolbar->orientation == GTK_ORIENTATION_VERTICAL &&
3564 gtk_tool_item_get_visible_vertical (item)))
3571 if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
3572 return gtk_widget_get_visible (content->u.compatibility.child.widget);
3578 g_assert_not_reached ();
3583 toolbar_content_size_request (ToolbarContent *content,
3584 GtkToolbar *toolbar,
3585 GtkRequisition *requisition)
3589 switch (content->type)
3592 gtk_widget_size_request (GTK_WIDGET (content->u.tool_item.item),
3594 if (content->u.tool_item.is_placeholder &&
3595 content->u.tool_item.disappearing)
3597 requisition->width = 0;
3598 requisition->height = 0;
3603 space_size = get_space_size (toolbar);
3605 if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
3607 gtk_widget_size_request (content->u.compatibility.child.widget,
3612 if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
3614 requisition->width = space_size;
3615 requisition->height = 0;
3619 requisition->height = space_size;
3620 requisition->width = 0;
3629 toolbar_content_is_homogeneous (ToolbarContent *content,
3630 GtkToolbar *toolbar)
3632 gboolean result = FALSE; /* quiet gcc */
3633 GtkRequisition requisition;
3634 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3636 if (priv->max_homogeneous_pixels < 0)
3638 priv->max_homogeneous_pixels =
3639 calculate_max_homogeneous_pixels (GTK_WIDGET (toolbar));
3642 toolbar_content_size_request (content, toolbar, &requisition);
3644 if (requisition.width > priv->max_homogeneous_pixels)
3647 switch (content->type)
3650 result = gtk_tool_item_get_homogeneous (content->u.tool_item.item) &&
3651 !GTK_IS_SEPARATOR_TOOL_ITEM (content->u.tool_item.item);
3653 if (gtk_tool_item_get_is_important (content->u.tool_item.item) &&
3654 toolbar->style == GTK_TOOLBAR_BOTH_HORIZ &&
3655 toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
3662 if (content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_BUTTON ||
3663 content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
3664 content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
3679 toolbar_content_is_placeholder (ToolbarContent *content)
3681 if (content->type == TOOL_ITEM && content->u.tool_item.is_placeholder)
3688 toolbar_content_disappearing (ToolbarContent *content)
3690 if (content->type == TOOL_ITEM && content->u.tool_item.disappearing)
3697 toolbar_content_get_state (ToolbarContent *content)
3699 return content->state;
3703 toolbar_content_child_visible (ToolbarContent *content)
3705 switch (content->type)
3708 return GTK_WIDGET_CHILD_VISIBLE (content->u.tool_item.item);
3712 if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
3714 return GTK_WIDGET_CHILD_VISIBLE (content->u.compatibility.child.widget);
3718 return content->u.compatibility.space_visible;
3723 return FALSE; /* quiet gcc */
3727 toolbar_content_get_goal_allocation (ToolbarContent *content,
3728 GtkAllocation *allocation)
3730 switch (content->type)
3733 *allocation = content->u.tool_item.goal_allocation;
3737 /* Goal allocations are only relevant when we are
3738 * using the new API, so we should never get here
3740 g_assert_not_reached ();
3744 g_assert_not_reached ();
3750 toolbar_content_get_allocation (ToolbarContent *content,
3751 GtkAllocation *allocation)
3753 GtkToolbarChild *child;
3755 switch (content->type)
3758 *allocation = GTK_WIDGET (content->u.tool_item.item)->allocation;
3762 child = &(content->u.compatibility.child);
3764 if (child->type == GTK_TOOLBAR_CHILD_SPACE)
3765 *allocation = content->u.compatibility.space_allocation;
3767 *allocation = child->widget->allocation;
3771 g_assert_not_reached ();
3777 toolbar_content_set_start_allocation (ToolbarContent *content,
3778 GtkAllocation *allocation)
3780 switch (content->type)
3783 content->u.tool_item.start_allocation = *allocation;
3787 /* start_allocation is only relevant when using the new API */
3788 g_assert_not_reached ();
3794 toolbar_content_get_expand (ToolbarContent *content)
3796 if (content->type == TOOL_ITEM &&
3797 gtk_tool_item_get_expand (content->u.tool_item.item) &&
3798 !content->u.tool_item.disappearing)
3807 toolbar_content_set_goal_allocation (ToolbarContent *content,
3808 GtkAllocation *allocation)
3810 switch (content->type)
3813 content->u.tool_item.goal_allocation = *allocation;
3817 /* Only relevant when using new API */
3818 g_assert_not_reached ();
3824 toolbar_content_set_child_visible (ToolbarContent *content,
3825 GtkToolbar *toolbar,
3828 GtkToolbarChild *child;
3830 switch (content->type)
3833 gtk_widget_set_child_visible (GTK_WIDGET (content->u.tool_item.item),
3838 child = &(content->u.compatibility.child);
3840 if (child->type != GTK_TOOLBAR_CHILD_SPACE)
3842 gtk_widget_set_child_visible (child->widget, visible);
3846 if (content->u.compatibility.space_visible != visible)
3848 content->u.compatibility.space_visible = visible;
3849 gtk_widget_queue_draw (GTK_WIDGET (toolbar));
3857 toolbar_content_get_start_allocation (ToolbarContent *content,
3858 GtkAllocation *start_allocation)
3860 switch (content->type)
3863 *start_allocation = content->u.tool_item.start_allocation;
3867 /* Only relevant for new API */
3868 g_assert_not_reached ();
3874 toolbar_content_size_allocate (ToolbarContent *content,
3875 GtkAllocation *allocation)
3877 switch (content->type)
3880 gtk_widget_size_allocate (GTK_WIDGET (content->u.tool_item.item),
3885 if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
3887 gtk_widget_size_allocate (content->u.compatibility.child.widget,
3892 content->u.compatibility.space_allocation = *allocation;
3899 toolbar_content_set_state (ToolbarContent *content,
3902 content->state = state;
3906 toolbar_content_get_widget (ToolbarContent *content)
3908 GtkToolbarChild *child;
3910 switch (content->type)
3913 return GTK_WIDGET (content->u.tool_item.item);
3917 child = &(content->u.compatibility.child);
3918 if (child->type != GTK_TOOLBAR_CHILD_SPACE)
3919 return child->widget;
3929 toolbar_content_set_disappearing (ToolbarContent *content,
3930 gboolean disappearing)
3932 switch (content->type)
3935 content->u.tool_item.disappearing = disappearing;
3939 /* Only relevant for new API */
3940 g_assert_not_reached ();
3946 toolbar_content_set_size_request (ToolbarContent *content,
3950 switch (content->type)
3953 gtk_widget_set_size_request (GTK_WIDGET (content->u.tool_item.item),
3958 /* Setting size requests only happens with sliding,
3959 * so not relevant here
3961 g_assert_not_reached ();
3967 toolbar_child_reconfigure (GtkToolbar *toolbar,
3968 GtkToolbarChild *child)
3972 GtkToolbarStyle style;
3973 GtkIconSize icon_size;
3974 GtkReliefStyle relief;
3977 style = gtk_toolbar_get_style (toolbar);
3978 icon_size = gtk_toolbar_get_icon_size (toolbar);
3979 relief = gtk_toolbar_get_relief_style (toolbar);
3982 if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
3983 child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
3984 child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
3986 box = gtk_bin_get_child (GTK_BIN (child->widget));
3988 if (style == GTK_TOOLBAR_BOTH && GTK_IS_HBOX (box))
3992 vbox = gtk_vbox_new (FALSE, 0);
3995 gtk_widget_reparent (child->label, vbox);
3997 gtk_widget_reparent (child->icon, vbox);
3999 gtk_widget_destroy (box);
4000 gtk_container_add (GTK_CONTAINER (child->widget), vbox);
4002 gtk_widget_show (vbox);
4004 else if (style == GTK_TOOLBAR_BOTH_HORIZ && GTK_IS_VBOX (box))
4008 hbox = gtk_hbox_new (FALSE, 0);
4011 gtk_widget_reparent (child->label, hbox);
4013 gtk_widget_reparent (child->icon, hbox);
4015 gtk_widget_destroy (box);
4016 gtk_container_add (GTK_CONTAINER (child->widget), hbox);
4018 gtk_widget_show (hbox);
4021 set_child_packing_and_visibility (toolbar, child);
4026 if ((child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4027 child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
4028 child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON) &&
4029 GTK_IS_IMAGE (child->icon))
4031 image = GTK_IMAGE (child->icon);
4032 if (gtk_image_get_storage_type (image) == GTK_IMAGE_STOCK)
4034 gtk_image_get_stock (image, &stock_id, NULL);
4035 stock_id = g_strdup (stock_id);
4036 gtk_image_set_from_stock (image,
4044 if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4045 child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4046 child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4048 gtk_button_set_relief (GTK_BUTTON (child->widget), relief);
4053 toolbar_content_toolbar_reconfigured (ToolbarContent *content,
4054 GtkToolbar *toolbar)
4056 switch (content->type)
4059 gtk_tool_item_toolbar_reconfigured (content->u.tool_item.item);
4063 toolbar_child_reconfigure (toolbar, &(content->u.compatibility.child));
4069 toolbar_content_retrieve_menu_item (ToolbarContent *content)
4071 if (content->type == TOOL_ITEM)
4072 return gtk_tool_item_retrieve_proxy_menu_item (content->u.tool_item.item);
4074 /* FIXME - we might actually be able to do something meaningful here */
4079 toolbar_content_has_proxy_menu_item (ToolbarContent *content)
4081 if (content->type == TOOL_ITEM)
4083 GtkWidget *menu_item;
4085 if (content->u.tool_item.has_menu == YES)
4087 else if (content->u.tool_item.has_menu == NO)
4090 menu_item = toolbar_content_retrieve_menu_item (content);
4092 content->u.tool_item.has_menu = menu_item? YES : NO;
4094 return menu_item != NULL;
4103 toolbar_content_set_unknown_menu_status (ToolbarContent *content)
4105 if (content->type == TOOL_ITEM)
4106 content->u.tool_item.has_menu = UNKNOWN;
4110 toolbar_content_is_separator (ToolbarContent *content)
4112 GtkToolbarChild *child;
4114 switch (content->type)
4117 return GTK_IS_SEPARATOR_TOOL_ITEM (content->u.tool_item.item);
4121 child = &(content->u.compatibility.child);
4122 return (child->type == GTK_TOOLBAR_CHILD_SPACE);
4130 toolbar_content_set_expand (ToolbarContent *content,
4133 if (content->type == TOOL_ITEM)
4134 gtk_tool_item_set_expand (content->u.tool_item.item, expand);
4138 ignore_show_and_hide_all (ToolbarContent *content)
4140 if (content->type == COMPATIBILITY)
4142 GtkToolbarChildType type = content->u.compatibility.child.type;
4144 if (type == GTK_TOOLBAR_CHILD_BUTTON ||
4145 type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
4146 type == GTK_TOOLBAR_CHILD_RADIOBUTTON)
4156 toolbar_content_show_all (ToolbarContent *content)
4160 if (ignore_show_and_hide_all (content))
4163 widget = toolbar_content_get_widget (content);
4165 gtk_widget_show_all (widget);
4169 toolbar_content_hide_all (ToolbarContent *content)
4173 if (ignore_show_and_hide_all (content))
4176 widget = toolbar_content_get_widget (content);
4178 gtk_widget_hide_all (widget);
4185 get_space_size (GtkToolbar *toolbar)
4187 gint space_size = DEFAULT_SPACE_SIZE;
4191 gtk_widget_style_get (GTK_WIDGET (toolbar),
4192 "space-size", &space_size,
4199 static GtkToolbarSpaceStyle
4200 get_space_style (GtkToolbar *toolbar)
4202 GtkToolbarSpaceStyle space_style = DEFAULT_SPACE_STYLE;
4206 gtk_widget_style_get (GTK_WIDGET (toolbar),
4207 "space-style", &space_style,
4214 static GtkReliefStyle
4215 get_button_relief (GtkToolbar *toolbar)
4217 GtkReliefStyle button_relief = GTK_RELIEF_NORMAL;
4219 gtk_widget_ensure_style (GTK_WIDGET (toolbar));
4221 gtk_widget_style_get (GTK_WIDGET (toolbar),
4222 "button-relief", &button_relief,
4225 return button_relief;
4229 get_internal_padding (GtkToolbar *toolbar)
4233 gtk_widget_style_get (GTK_WIDGET (toolbar),
4234 "internal-padding", &ipadding,
4241 get_max_child_expand (GtkToolbar *toolbar)
4243 gint mexpand = G_MAXINT;
4245 gtk_widget_style_get (GTK_WIDGET (toolbar),
4246 "max-child-expand", &mexpand,
4251 static GtkShadowType
4252 get_shadow_type (GtkToolbar *toolbar)
4254 GtkShadowType shadow_type;
4256 gtk_widget_style_get (GTK_WIDGET (toolbar),
4257 "shadow-type", &shadow_type,
4267 gtk_toolbar_check_old_api (GtkToolbar *toolbar)
4269 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4271 if (priv->api_mode == NEW_API)
4273 g_warning (MIXED_API_WARNING);
4277 priv->api_mode = OLD_API;
4282 gtk_toolbar_check_new_api (GtkToolbar *toolbar)
4284 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4286 if (priv->api_mode == OLD_API)
4288 g_warning (MIXED_API_WARNING);
4292 priv->api_mode = NEW_API;
4296 /* GTK+ internal methods */
4299 _gtk_toolbar_get_default_space_size (void)
4301 return DEFAULT_SPACE_SIZE;
4305 _gtk_toolbar_paint_space_line (GtkWidget *widget,
4306 GtkToolbar *toolbar,
4307 const GdkRectangle *area,
4308 const GtkAllocation *allocation)
4310 const double start_fraction = (SPACE_LINE_START / SPACE_LINE_DIVISION);
4311 const double end_fraction = (SPACE_LINE_END / SPACE_LINE_DIVISION);
4313 GtkOrientation orientation;
4315 g_return_if_fail (GTK_IS_WIDGET (widget));
4317 orientation = toolbar? toolbar->orientation : GTK_ORIENTATION_HORIZONTAL;
4319 if (orientation == GTK_ORIENTATION_HORIZONTAL)
4321 gboolean wide_separators;
4322 gint separator_width;
4324 gtk_widget_style_get (widget,
4325 "wide-separators", &wide_separators,
4326 "separator-width", &separator_width,
4329 if (wide_separators)
4330 gtk_paint_box (widget->style, widget->window,
4331 gtk_widget_get_state (widget), GTK_SHADOW_ETCHED_OUT,
4332 area, widget, "vseparator",
4333 allocation->x + (allocation->width - separator_width) / 2,
4334 allocation->y + allocation->height * start_fraction,
4336 allocation->height * (end_fraction - start_fraction));
4338 gtk_paint_vline (widget->style, widget->window,
4339 gtk_widget_get_state (widget), area, widget,
4341 allocation->y + allocation->height * start_fraction,
4342 allocation->y + allocation->height * end_fraction,
4343 allocation->x + (allocation->width - widget->style->xthickness) / 2);
4347 gboolean wide_separators;
4348 gint separator_height;
4350 gtk_widget_style_get (widget,
4351 "wide-separators", &wide_separators,
4352 "separator-height", &separator_height,
4355 if (wide_separators)
4356 gtk_paint_box (widget->style, widget->window,
4357 gtk_widget_get_state (widget), GTK_SHADOW_ETCHED_OUT,
4358 area, widget, "hseparator",
4359 allocation->x + allocation->width * start_fraction,
4360 allocation->y + (allocation->height - separator_height) / 2,
4361 allocation->width * (end_fraction - start_fraction),
4364 gtk_paint_hline (widget->style, widget->window,
4365 gtk_widget_get_state (widget), area, widget,
4367 allocation->x + allocation->width * start_fraction,
4368 allocation->x + allocation->width * end_fraction,
4369 allocation->y + (allocation->height - widget->style->ythickness) / 2);
4374 _gtk_toolbar_elide_underscores (const gchar *original)
4377 const gchar *p, *end;
4379 gboolean last_underscore;
4384 len = strlen (original);
4385 q = result = g_malloc (len + 1);
4386 last_underscore = FALSE;
4388 end = original + len;
4389 for (p = original; p < end; p++)
4391 if (!last_underscore && *p == '_')
4392 last_underscore = TRUE;
4395 last_underscore = FALSE;
4396 if (original + 2 <= p && p + 1 <= end &&
4397 p[-2] == '(' && p[-1] == '_' && p[0] != '_' && p[1] == ')')
4408 if (last_underscore)
4417 toolbar_get_icon_size (GtkToolShell *shell)
4419 return GTK_TOOLBAR (shell)->icon_size;
4422 static GtkOrientation
4423 toolbar_get_orientation (GtkToolShell *shell)
4425 return GTK_TOOLBAR (shell)->orientation;
4428 static GtkToolbarStyle
4429 toolbar_get_style (GtkToolShell *shell)
4431 return GTK_TOOLBAR (shell)->style;
4434 static GtkReliefStyle
4435 toolbar_get_relief_style (GtkToolShell *shell)
4437 return get_button_relief (GTK_TOOLBAR (shell));
4441 toolbar_rebuild_menu (GtkToolShell *shell)
4443 GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (shell);
4446 priv->need_rebuild = TRUE;
4448 for (list = priv->content; list != NULL; list = list->next)
4450 ToolbarContent *content = list->data;
4452 toolbar_content_set_unknown_menu_status (content);
4455 gtk_widget_queue_resize (GTK_WIDGET (shell));
4458 #define __GTK_TOOLBAR_C__
4459 #include "gtkaliasdef.c"