gtktoolbar.c 111 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
2 3 4
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 * 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>
8
 *
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 12 13 14 15 16
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
20
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
21 22
 */

23
/*
24
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
25 26
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
27
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
28 29
 */

30

31
#include "config.h"
32 33 34 35

#include <math.h>
#include <string.h>

36
#include "gtktoolbar.h"
37

38 39
#include "gtkarrow.h"
#include "gtkbindings.h"
40
#include "gtkcontainerprivate.h"
41 42
#include "gtkimage.h"
#include "gtklabel.h"
43
#include "gtkmain.h"
44 45 46 47 48 49 50
#include "gtkmarshalers.h"
#include "gtkmenu.h"
#include "gtkorientable.h"
#include "gtkradiobutton.h"
#include "gtkradiotoolbutton.h"
#include "gtkseparatormenuitem.h"
#include "gtkseparatortoolitem.h"
51
#include "gtkstock.h"
52
#include "gtktoolshell.h"
Matthias Clasen's avatar
Matthias Clasen committed
53
#include "gtkbox.h"
54
#include "gtkprivate.h"
Havoc Pennington's avatar
Havoc Pennington committed
55
#include "gtkintl.h"
56
#include "gtktypebuiltins.h"
57
#include "gtkwidgetpath.h"
58
#include "gtkwidgetprivate.h"
59

60

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
/**
 * SECTION:gtktoolbar
 * @Short_description: Create bars of buttons and other widgets
 * @Title: GtkToolbar
 * @See_also: #GtkToolItem
 *
 * A toolbar is created with a call to gtk_toolbar_new().
 *
 * A toolbar can contain instances of a subclass of #GtkToolItem. To add
 * a #GtkToolItem to the a toolbar, use gtk_toolbar_insert(). To remove
 * an item from the toolbar use gtk_container_remove(). To add a button
 * to the toolbar, add an instance of #GtkToolButton.
 *
 * Toolbar items can be visually grouped by adding instances of
 * #GtkSeparatorToolItem to the toolbar. If the GtkToolbar child property
 * "expand" is #TRUE and the property #GtkSeparatorToolItem:draw is set to
 * #FALSE, the effect is to force all following items to the end of the toolbar.
 *
 * Creating a context menu for the toolbar can be done by connecting to
 * the #GtkToolbar::popup-context-menu signal.
 */


84 85
typedef struct _ToolbarContent ToolbarContent;

86
#define DEFAULT_IPADDING    0
87

88
#define DEFAULT_SPACE_SIZE  12
89
#define DEFAULT_SPACE_STYLE GTK_TOOLBAR_SPACE_LINE
90
#define SPACE_LINE_DIVISION 10.0
91 92
#define SPACE_LINE_START    2.0
#define SPACE_LINE_END      8.0
93

94
#define DEFAULT_ICON_SIZE GTK_ICON_SIZE_LARGE_TOOLBAR
95
#define DEFAULT_TOOLBAR_STYLE GTK_TOOLBAR_BOTH
96
#define DEFAULT_ANIMATION_STATE TRUE
97

98 99
#define MAX_HOMOGENEOUS_N_CHARS 13 /* Items that are wider than this do not participate
				    * in the homogeneous game. In units of
100 101
				    * pango_font_get_estimated_char_width().
				    */
102 103
#define SLIDE_SPEED 600.0	   /* How fast the items slide, in pixels per second */
#define ACCEL_THRESHOLD 0.18	   /* After how much time in seconds will items start speeding up */
104

105

106
struct _GtkToolbarPrivate
107 108 109
{
  GtkMenu         *menu;
  GtkSettings     *settings;
110 111

  GtkIconSize      icon_size;
112
  GtkToolbarStyle  style;
113

114 115 116 117 118 119 120 121 122 123
  GtkToolItem     *highlight_tool_item;
  GtkWidget       *arrow;
  GtkWidget       *arrow_button;

  GdkWindow       *event_window;

  GList           *content;

  GTimer          *timer;

124 125
  gulong           settings_connection;

126 127 128 129 130 131
  gint             idle_id;
  gint             button_maxw;         /* maximum width of homogeneous children */
  gint             button_maxh;         /* maximum height of homogeneous children */
  gint             max_homogeneous_pixels;
  gint             num_children;

132
  GtkOrientation   orientation;
133 134 135 136 137 138 139 140 141 142

  guint            animation : 1;
  guint            icon_size_set : 1;
  guint            is_sliding : 1;
  guint            need_rebuild : 1;  /* whether the overflow menu should be regenerated */
  guint            need_sync : 1;
  guint            show_arrow : 1;
  guint            style_set     : 1;
};

143
/* Properties */
144
enum {
145 146
  PROP_0,
  PROP_ORIENTATION,
147
  PROP_TOOLBAR_STYLE,
148
  PROP_SHOW_ARROW,
149 150 151
  PROP_TOOLTIPS,
  PROP_ICON_SIZE,
  PROP_ICON_SIZE_SET
152 153
};

154
/* Child properties */
155 156 157
enum {
  CHILD_PROP_0,
  CHILD_PROP_EXPAND,
158
  CHILD_PROP_HOMOGENEOUS
159 160
};

161
/* Signals */
162
enum {
163 164
  ORIENTATION_CHANGED,
  STYLE_CHANGED,
165
  POPUP_CONTEXT_MENU,
166
  FOCUS_HOME_OR_END,
167
  LAST_SIGNAL
168 169
};

170 171 172 173
typedef enum {
  NOT_ALLOCATED,
  NORMAL,
  HIDDEN,
174
  OVERFLOWN
175
} ItemState;
Matthias Clasen's avatar
Matthias Clasen committed
176

177

178 179 180 181 182 183 184 185
static void       gtk_toolbar_set_property         (GObject             *object,
						    guint                prop_id,
						    const GValue        *value,
						    GParamSpec          *pspec);
static void       gtk_toolbar_get_property         (GObject             *object,
						    guint                prop_id,
						    GValue              *value,
						    GParamSpec          *pspec);
186 187
static gint       gtk_toolbar_draw                 (GtkWidget           *widget,
                                                    cairo_t             *cr);
188 189
static void       gtk_toolbar_realize              (GtkWidget           *widget);
static void       gtk_toolbar_unrealize            (GtkWidget           *widget);
190 191 192 193 194 195 196
static void       gtk_toolbar_get_preferred_width  (GtkWidget           *widget,
                                                    gint                *minimum,
                                                    gint                *natural);
static void       gtk_toolbar_get_preferred_height (GtkWidget           *widget,
                                                    gint                *minimum,
                                                    gint                *natural);

197 198
static void       gtk_toolbar_size_allocate        (GtkWidget           *widget,
						    GtkAllocation       *allocation);
199
static void       gtk_toolbar_style_updated        (GtkWidget           *widget);
200 201
static gboolean   gtk_toolbar_focus                (GtkWidget           *widget,
						    GtkDirectionType     dir);
202 203
static void       gtk_toolbar_move_focus           (GtkWidget           *widget,
						    GtkDirectionType     dir);
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
static void       gtk_toolbar_screen_changed       (GtkWidget           *widget,
						    GdkScreen           *previous_screen);
static void       gtk_toolbar_map                  (GtkWidget           *widget);
static void       gtk_toolbar_unmap                (GtkWidget           *widget);
static void       gtk_toolbar_set_child_property   (GtkContainer        *container,
						    GtkWidget           *child,
						    guint                property_id,
						    const GValue        *value,
						    GParamSpec          *pspec);
static void       gtk_toolbar_get_child_property   (GtkContainer        *container,
						    GtkWidget           *child,
						    guint                property_id,
						    GValue              *value,
						    GParamSpec          *pspec);
static void       gtk_toolbar_finalize             (GObject             *object);
219
static void       gtk_toolbar_dispose              (GObject             *object);
220 221 222 223 224 225 226 227 228 229
static void       gtk_toolbar_show_all             (GtkWidget           *widget);
static void       gtk_toolbar_add                  (GtkContainer        *container,
						    GtkWidget           *widget);
static void       gtk_toolbar_remove               (GtkContainer        *container,
						    GtkWidget           *widget);
static void       gtk_toolbar_forall               (GtkContainer        *container,
						    gboolean             include_internals,
						    GtkCallback          callback,
						    gpointer             callback_data);
static GType      gtk_toolbar_child_type           (GtkContainer        *container);
230 231 232 233 234
static GtkWidgetPath * gtk_toolbar_get_path_for_child
                                                  (GtkContainer        *container,
                                                   GtkWidget           *child);
static void       gtk_toolbar_invalidate_order    (GtkToolbar           *toolbar);

235 236
static void       gtk_toolbar_direction_changed    (GtkWidget           *widget,
                                                    GtkTextDirection     previous_direction);
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
static void       gtk_toolbar_orientation_changed  (GtkToolbar          *toolbar,
						    GtkOrientation       orientation);
static void       gtk_toolbar_real_style_changed   (GtkToolbar          *toolbar,
						    GtkToolbarStyle      style);
static gboolean   gtk_toolbar_focus_home_or_end    (GtkToolbar          *toolbar,
						    gboolean             focus_home);
static gboolean   gtk_toolbar_button_press         (GtkWidget           *toolbar,
						    GdkEventButton      *event);
static gboolean   gtk_toolbar_arrow_button_press   (GtkWidget           *button,
						    GdkEventButton      *event,
						    GtkToolbar          *toolbar);
static void       gtk_toolbar_arrow_button_clicked (GtkWidget           *button,
						    GtkToolbar          *toolbar);
static void       gtk_toolbar_update_button_relief (GtkToolbar          *toolbar);
static gboolean   gtk_toolbar_popup_menu           (GtkWidget           *toolbar);
static void       gtk_toolbar_reconfigured         (GtkToolbar          *toolbar);
253 254 255

static GtkReliefStyle       get_button_relief    (GtkToolbar *toolbar);
static gint                 get_internal_padding (GtkToolbar *toolbar);
256
static gint                 get_max_child_expand (GtkToolbar *toolbar);
257
static GtkShadowType        get_shadow_type      (GtkToolbar *toolbar);
258

259 260 261 262 263 264 265 266
/* methods on ToolbarContent 'class' */
static ToolbarContent *toolbar_content_new_tool_item        (GtkToolbar          *toolbar,
							     GtkToolItem         *item,
							     gboolean             is_placeholder,
							     gint                 pos);
static void            toolbar_content_remove               (ToolbarContent      *content,
							     GtkToolbar          *toolbar);
static void            toolbar_content_free                 (ToolbarContent      *content);
267
static void            toolbar_content_draw                 (ToolbarContent      *content,
268
							     GtkContainer        *container,
269
                                                             cairo_t             *cr);
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
static gboolean        toolbar_content_visible              (ToolbarContent      *content,
							     GtkToolbar          *toolbar);
static void            toolbar_content_size_request         (ToolbarContent      *content,
							     GtkToolbar          *toolbar,
							     GtkRequisition      *requisition);
static gboolean        toolbar_content_is_homogeneous       (ToolbarContent      *content,
							     GtkToolbar          *toolbar);
static gboolean        toolbar_content_is_placeholder       (ToolbarContent      *content);
static gboolean        toolbar_content_disappearing         (ToolbarContent      *content);
static ItemState       toolbar_content_get_state            (ToolbarContent      *content);
static gboolean        toolbar_content_child_visible        (ToolbarContent      *content);
static void            toolbar_content_get_goal_allocation  (ToolbarContent      *content,
							     GtkAllocation       *allocation);
static void            toolbar_content_get_allocation       (ToolbarContent      *content,
							     GtkAllocation       *allocation);
static void            toolbar_content_set_start_allocation (ToolbarContent      *content,
							     GtkAllocation       *new_start_allocation);
static void            toolbar_content_get_start_allocation (ToolbarContent      *content,
							     GtkAllocation       *start_allocation);
static gboolean        toolbar_content_get_expand           (ToolbarContent      *content);
static void            toolbar_content_set_goal_allocation  (ToolbarContent      *content,
							     GtkAllocation       *allocation);
static void            toolbar_content_set_child_visible    (ToolbarContent      *content,
							     GtkToolbar          *toolbar,
							     gboolean             visible);
static void            toolbar_content_size_allocate        (ToolbarContent      *content,
							     GtkAllocation       *allocation);
static void            toolbar_content_set_state            (ToolbarContent      *content,
							     ItemState            new_state);
static GtkWidget *     toolbar_content_get_widget           (ToolbarContent      *content);
static void            toolbar_content_set_disappearing     (ToolbarContent      *content,
							     gboolean             disappearing);
static void            toolbar_content_set_size_request     (ToolbarContent      *content,
							     gint                 width,
							     gint                 height);
static void            toolbar_content_toolbar_reconfigured (ToolbarContent      *content,
							     GtkToolbar          *toolbar);
static GtkWidget *     toolbar_content_retrieve_menu_item   (ToolbarContent      *content);
308
static gboolean        toolbar_content_has_proxy_menu_item  (ToolbarContent	 *content);
309 310
static gboolean        toolbar_content_is_separator         (ToolbarContent      *content);
static void            toolbar_content_show_all             (ToolbarContent      *content);
311 312
static void	       toolbar_content_set_expand	    (ToolbarContent      *content,
							     gboolean		  expand);
313

314 315 316 317 318 319 320
static void            toolbar_tool_shell_iface_init        (GtkToolShellIface   *iface);
static GtkIconSize     toolbar_get_icon_size                (GtkToolShell        *shell);
static GtkOrientation  toolbar_get_orientation              (GtkToolShell        *shell);
static GtkToolbarStyle toolbar_get_style                    (GtkToolShell        *shell);
static GtkReliefStyle  toolbar_get_relief_style             (GtkToolShell        *shell);
static void            toolbar_rebuild_menu                 (GtkToolShell        *shell);

321

322
G_DEFINE_TYPE_WITH_CODE (GtkToolbar, gtk_toolbar, GTK_TYPE_CONTAINER,
323 324 325 326 327 328 329
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TOOL_SHELL,
                                                toolbar_tool_shell_iface_init)
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
                                                NULL))

static guint toolbar_signals[LAST_SIGNAL] = { 0 };

330 331 332 333 334 335

static void
add_arrow_bindings (GtkBindingSet   *binding_set,
		    guint            keysym,
		    GtkDirectionType dir)
{
336
  guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
337 338
  
  gtk_binding_entry_add_signal (binding_set, keysym, 0,
339
                                "move-focus", 1,
340 341
                                GTK_TYPE_DIRECTION_TYPE, dir);
  gtk_binding_entry_add_signal (binding_set, keypad_keysym, 0,
342
                                "move-focus", 1,
343 344
                                GTK_TYPE_DIRECTION_TYPE, dir);
}
345

346 347 348 349 350 351
static void
add_ctrl_tab_bindings (GtkBindingSet    *binding_set,
		       GdkModifierType   modifiers,
		       GtkDirectionType  direction)
{
  gtk_binding_entry_add_signal (binding_set,
352
				GDK_KEY_Tab, GDK_CONTROL_MASK | modifiers,
353
				"move-focus", 1,
354 355
				GTK_TYPE_DIRECTION_TYPE, direction);
  gtk_binding_entry_add_signal (binding_set,
356
				GDK_KEY_KP_Tab, GDK_CONTROL_MASK | modifiers,
357
				"move-focus", 1,
358
				GTK_TYPE_DIRECTION_TYPE, direction);
359 360 361
}

static void
362
gtk_toolbar_class_init (GtkToolbarClass *klass)
363
{
364
  GObjectClass *gobject_class;
365 366
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;
367
  GtkBindingSet *binding_set;
368
  
369 370 371 372
  gobject_class = (GObjectClass *)klass;
  widget_class = (GtkWidgetClass *)klass;
  container_class = (GtkContainerClass *)klass;
  
373 374
  gobject_class->set_property = gtk_toolbar_set_property;
  gobject_class->get_property = gtk_toolbar_get_property;
375
  gobject_class->finalize = gtk_toolbar_finalize;
376
  gobject_class->dispose = gtk_toolbar_dispose;
377
  
378
  widget_class->button_press_event = gtk_toolbar_button_press;
379
  widget_class->draw = gtk_toolbar_draw;
380 381
  widget_class->get_preferred_width = gtk_toolbar_get_preferred_width;
  widget_class->get_preferred_height = gtk_toolbar_get_preferred_height;
382
  widget_class->size_allocate = gtk_toolbar_size_allocate;
383
  widget_class->style_updated = gtk_toolbar_style_updated;
384
  widget_class->focus = gtk_toolbar_focus;
385

386 387
  gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_TOOL_BAR);

388
  /* need to override the base class function via override_class_handler,
389 390
   * because the signal slot is not available in GtkWidgetClass
   */
391
  g_signal_override_class_handler ("move-focus",
392
                                   GTK_TYPE_TOOLBAR,
393
                                   G_CALLBACK (gtk_toolbar_move_focus));
394

395
  widget_class->screen_changed = gtk_toolbar_screen_changed;
396 397 398 399
  widget_class->realize = gtk_toolbar_realize;
  widget_class->unrealize = gtk_toolbar_unrealize;
  widget_class->map = gtk_toolbar_map;
  widget_class->unmap = gtk_toolbar_unmap;
400
  widget_class->popup_menu = gtk_toolbar_popup_menu;
401
  widget_class->show_all = gtk_toolbar_show_all;
402
  widget_class->direction_changed = gtk_toolbar_direction_changed;
Havoc Pennington's avatar
Havoc Pennington committed
403
  
404
  container_class->add    = gtk_toolbar_add;
405
  container_class->remove = gtk_toolbar_remove;
406
  container_class->forall = gtk_toolbar_forall;
407 408 409
  container_class->child_type = gtk_toolbar_child_type;
  container_class->get_child_property = gtk_toolbar_get_child_property;
  container_class->set_child_property = gtk_toolbar_set_child_property;
410 411
  container_class->get_path_for_child = gtk_toolbar_get_path_for_child;

412
  klass->orientation_changed = gtk_toolbar_orientation_changed;
413
  klass->style_changed = gtk_toolbar_real_style_changed;
414
  
415 416 417 418 419 420 421
  /**
   * GtkToolbar::orientation-changed:
   * @toolbar: the object which emitted the signal
   * @orientation: the new #GtkOrientation of the toolbar
   *
   * Emitted when the orientation of the toolbar changes.
   */
422
  toolbar_signals[ORIENTATION_CHANGED] =
423
    g_signal_new (I_("orientation-changed"),
424
		  G_OBJECT_CLASS_TYPE (klass),
Manish Singh's avatar
Manish Singh committed
425 426 427
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkToolbarClass, orientation_changed),
		  NULL, NULL,
428
		  g_cclosure_marshal_VOID__ENUM,
Manish Singh's avatar
Manish Singh committed
429 430
		  G_TYPE_NONE, 1,
		  GTK_TYPE_ORIENTATION);
431 432 433 434 435 436 437
  /**
   * GtkToolbar::style-changed:
   * @toolbar: The #GtkToolbar which emitted the signal
   * @style: the new #GtkToolbarStyle of the toolbar
   *
   * Emitted when the style of the toolbar changes. 
   */
438
  toolbar_signals[STYLE_CHANGED] =
439
    g_signal_new (I_("style-changed"),
440
		  G_OBJECT_CLASS_TYPE (klass),
Manish Singh's avatar
Manish Singh committed
441 442 443
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkToolbarClass, style_changed),
		  NULL, NULL,
444
		  g_cclosure_marshal_VOID__ENUM,
Manish Singh's avatar
Manish Singh committed
445 446
		  G_TYPE_NONE, 1,
		  GTK_TYPE_TOOLBAR_STYLE);
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
  /**
   * GtkToolbar::popup-context-menu:
   * @toolbar: the #GtkToolbar which emitted the signal
   * @x: the x coordinate of the point where the menu should appear
   * @y: the y coordinate of the point where the menu should appear
   * @button: the mouse button the user pressed, or -1
   *
   * Emitted when the user right-clicks the toolbar or uses the
   * keybinding to display a popup menu.
   *
   * Application developers should handle this signal if they want
   * to display a context menu on the toolbar. The context-menu should
   * appear at the coordinates given by @x and @y. The mouse button
   * number is given by the @button parameter. If the menu was popped
   * up using the keybaord, @button is -1.
   *
   * Return value: return %TRUE if the signal was handled, %FALSE if not
   */
465
  toolbar_signals[POPUP_CONTEXT_MENU] =
466
    g_signal_new (I_("popup-context-menu"),
467
		  G_OBJECT_CLASS_TYPE (klass),
468
		  G_SIGNAL_RUN_LAST,
469
		  G_STRUCT_OFFSET (GtkToolbarClass, popup_context_menu),
470 471 472 473 474
		  _gtk_boolean_handled_accumulator, NULL,
		  _gtk_marshal_BOOLEAN__INT_INT_INT,
		  G_TYPE_BOOLEAN, 3,
		  G_TYPE_INT, G_TYPE_INT,
		  G_TYPE_INT);
475

476 477 478 479 480 481 482 483 484 485
  /**
   * GtkToolbar::focus-home-or-end:
   * @toolbar: the #GtkToolbar which emitted the signal
   * @focus_home: %TRUE if the first item should be focused
   *
   * A keybinding signal used internally by GTK+. This signal can't
   * be used in application code
   *
   * Return value: %TRUE if the signal was handled, %FALSE if not
   */
486
  toolbar_signals[FOCUS_HOME_OR_END] =
487
    g_signal_new_class_handler (I_("focus-home-or-end"),
488 489 490 491 492 493 494 495
                                G_OBJECT_CLASS_TYPE (klass),
                                G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                                G_CALLBACK (gtk_toolbar_focus_home_or_end),
                                NULL, NULL,
                                _gtk_marshal_BOOLEAN__BOOLEAN,
                                G_TYPE_BOOLEAN, 1,
                                G_TYPE_BOOLEAN);

496
  /* properties */
497 498 499 500
  g_object_class_override_property (gobject_class,
                                    PROP_ORIENTATION,
                                    "orientation");

501 502
  g_object_class_install_property (gobject_class,
				   PROP_TOOLBAR_STYLE,
503
				   g_param_spec_enum ("toolbar-style",
504 505
 						      P_("Toolbar Style"),
 						      P_("How to draw the toolbar"),
506
 						      GTK_TYPE_TOOLBAR_STYLE,
507
 						      DEFAULT_TOOLBAR_STYLE,
508
 						      GTK_PARAM_READWRITE));
509 510
  g_object_class_install_property (gobject_class,
				   PROP_SHOW_ARROW,
511
				   g_param_spec_boolean ("show-arrow",
512 513
							 P_("Show Arrow"),
							 P_("If an arrow should be shown if the toolbar doesn't fit"),
514
							 TRUE,
515
							 GTK_PARAM_READWRITE));
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531

  /**
   * GtkToolbar:icon-size:
   *
   * The size of the icons in a toolbar is normally determined by
   * the toolbar-icon-size setting. When this property is set, it 
   * overrides the setting. 
   * 
   * This should only be used for special-purpose toolbars, normal
   * application toolbars should respect the user preferences for the
   * size of icons.
   *
   * Since: 2.10
   */
  g_object_class_install_property (gobject_class,
				   PROP_ICON_SIZE,
532 533 534 535 536 537
				   g_param_spec_int ("icon-size",
						     P_("Icon size"),
						     P_("Size of icons in this toolbar"),
						     0, G_MAXINT,
						     DEFAULT_ICON_SIZE,
						     GTK_PARAM_READWRITE));  
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553

  /**
   * GtkToolbar:icon-size-set:
   *
   * Is %TRUE if the icon-size property has been set.
   *
   * Since: 2.10
   */
  g_object_class_install_property (gobject_class,
				   PROP_ICON_SIZE_SET,
				   g_param_spec_boolean ("icon-size-set",
							 P_("Icon size set"),
							 P_("Whether the icon-size property has been set"),
							 FALSE,
							 GTK_PARAM_READWRITE));  

554 555 556 557
  /* child properties */
  gtk_container_class_install_child_property (container_class,
					      CHILD_PROP_EXPAND,
					      g_param_spec_boolean ("expand", 
558 559
								    P_("Expand"), 
								    P_("Whether the item should receive extra space when the toolbar grows"),
560
								    FALSE,
561
								    GTK_PARAM_READWRITE));
562
  
563 564 565
  gtk_container_class_install_child_property (container_class,
					      CHILD_PROP_HOMOGENEOUS,
					      g_param_spec_boolean ("homogeneous", 
566 567
								    P_("Homogeneous"), 
								    P_("Whether the item should be the same size as other homogeneous items"),
568
								    FALSE,
569
								    GTK_PARAM_READWRITE));
570
  
571
  /* style properties */
Havoc Pennington's avatar
Havoc Pennington committed
572
  gtk_widget_class_install_style_property (widget_class,
573
					   g_param_spec_int ("space-size",
574 575
							     P_("Spacer size"),
							     P_("Size of spacers"),
Havoc Pennington's avatar
Havoc Pennington committed
576 577 578
							     0,
							     G_MAXINT,
                                                             DEFAULT_SPACE_SIZE,
579
							     GTK_PARAM_READABLE));
580
  
581
  gtk_widget_class_install_style_property (widget_class,
582
					   g_param_spec_int ("internal-padding",
583 584
							     P_("Internal padding"),
							     P_("Amount of border space between the toolbar shadow and the buttons"),
585 586 587
							     0,
							     G_MAXINT,
                                                             DEFAULT_IPADDING,
588
                                                             GTK_PARAM_READABLE));
589 590 591

  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_int ("max-child-expand",
592 593
                                                             P_("Maximum child expand"),
                                                             P_("Maximum amount of space an expandable item will be given"),
594 595 596 597 598
                                                             0,
                                                             G_MAXINT,
                                                             G_MAXINT,
                                                             GTK_PARAM_READABLE));

Havoc Pennington's avatar
Havoc Pennington committed
599
  gtk_widget_class_install_style_property (widget_class,
600
					   g_param_spec_enum ("space-style",
601 602
							      P_("Space style"),
							      P_("Whether spacers are vertical lines or just blank"),
Havoc Pennington's avatar
Havoc Pennington committed
603 604
                                                              GTK_TYPE_TOOLBAR_SPACE_STYLE,
                                                              DEFAULT_SPACE_STYLE,
605
                                                              GTK_PARAM_READABLE));
606
  
Havoc Pennington's avatar
Havoc Pennington committed
607
  gtk_widget_class_install_style_property (widget_class,
608
					   g_param_spec_enum ("button-relief",
609 610
							      P_("Button relief"),
							      P_("Type of bevel around toolbar buttons"),
Havoc Pennington's avatar
Havoc Pennington committed
611
                                                              GTK_TYPE_RELIEF_STYLE,
612
                                                              GTK_RELIEF_NONE,
613
                                                              GTK_PARAM_READABLE));
614
  gtk_widget_class_install_style_property (widget_class,
615
                                           g_param_spec_enum ("shadow-type",
616 617
                                                              P_("Shadow type"),
                                                              P_("Style of bevel around the toolbar"),
618 619
                                                              GTK_TYPE_SHADOW_TYPE,
                                                              GTK_SHADOW_OUT,
620
                                                              GTK_PARAM_READABLE));
621

622
  binding_set = gtk_binding_set_by_class (klass);
623
  
624 625 626 627
  add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
  add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
  add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
  add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
628
  
629
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Home, 0,
630
                                "focus-home-or-end", 1,
631
				G_TYPE_BOOLEAN, TRUE);
632
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Home, 0,
633
                                "focus-home-or-end", 1,
634
				G_TYPE_BOOLEAN, TRUE);
635
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_End, 0,
636
                                "focus-home-or-end", 1,
637
				G_TYPE_BOOLEAN, FALSE);
638
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_End, 0,
639
                                "focus-home-or-end", 1,
640
				G_TYPE_BOOLEAN, FALSE);
641
  
642 643
  add_ctrl_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
  add_ctrl_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
644

645
  g_type_class_add_private (gobject_class, sizeof (GtkToolbarPrivate));
646 647
}

648 649 650 651 652 653 654 655 656 657
static void
toolbar_tool_shell_iface_init (GtkToolShellIface *iface)
{
  iface->get_icon_size    = toolbar_get_icon_size;
  iface->get_orientation  = toolbar_get_orientation;
  iface->get_style        = toolbar_get_style;
  iface->get_relief_style = toolbar_get_relief_style;
  iface->rebuild_menu     = toolbar_rebuild_menu;
}

658
static void
659
gtk_toolbar_init (GtkToolbar *toolbar)
660
{
661
  GtkToolbarPrivate *priv;
662
  GtkStyleContext *context;
663 664 665

  toolbar->priv = G_TYPE_INSTANCE_GET_PRIVATE (toolbar,
                                               GTK_TYPE_TOOLBAR,
666
                                               GtkToolbarPrivate);
667 668
  priv = toolbar->priv;

669
  gtk_widget_set_can_focus (GTK_WIDGET (toolbar), FALSE);
670
  gtk_widget_set_has_window (GTK_WIDGET (toolbar), FALSE);
671 672 673 674

  priv->orientation = GTK_ORIENTATION_HORIZONTAL;
  priv->style = DEFAULT_TOOLBAR_STYLE;
  priv->icon_size = DEFAULT_ICON_SIZE;
675
  priv->animation = DEFAULT_ANIMATION_STATE;
676

677
  priv->arrow_button = gtk_toggle_button_new ();
678
  g_signal_connect (priv->arrow_button, "button-press-event",
679 680 681 682 683
		    G_CALLBACK (gtk_toolbar_arrow_button_press), toolbar);
  g_signal_connect (priv->arrow_button, "clicked",
		    G_CALLBACK (gtk_toolbar_arrow_button_clicked), toolbar);
  gtk_button_set_relief (GTK_BUTTON (priv->arrow_button),
			 get_button_relief (toolbar));
684

685
  gtk_button_set_focus_on_click (GTK_BUTTON (priv->arrow_button), FALSE);
686

687
  priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
688
  gtk_widget_set_name (priv->arrow, "gtk-toolbar-arrow");
689 690 691 692
  gtk_widget_show (priv->arrow);
  gtk_container_add (GTK_CONTAINER (priv->arrow_button), priv->arrow);
  
  gtk_widget_set_parent (priv->arrow_button, GTK_WIDGET (toolbar));
693
  
694 695
  /* which child position a drop will occur at */
  priv->menu = NULL;
696
  priv->show_arrow = TRUE;
697
  priv->settings = NULL;
698
  
699 700
  priv->max_homogeneous_pixels = -1;
  
701
  priv->timer = g_timer_new ();
702 703 704

  context = gtk_widget_get_style_context (GTK_WIDGET (toolbar));
  gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOOLBAR);
705 706
}

707
static void
708 709
gtk_toolbar_set_property (GObject      *object,
			  guint         prop_id,
710 711
			  const GValue *value,
			  GParamSpec   *pspec)
712 713
{
  GtkToolbar *toolbar = GTK_TOOLBAR (object);
714
  GtkToolbarPrivate *priv = toolbar->priv;
715

716
  switch (prop_id)
717
    {
718
    case PROP_ORIENTATION:
719 720
      g_signal_emit (toolbar, toolbar_signals[ORIENTATION_CHANGED], 0,
                     g_value_get_enum (value));
721
      break;
722 723
    case PROP_TOOLBAR_STYLE:
      gtk_toolbar_set_style (toolbar, g_value_get_enum (value));
724
      break;
725 726 727
    case PROP_SHOW_ARROW:
      gtk_toolbar_set_show_arrow (toolbar, g_value_get_boolean (value));
      break;
728
    case PROP_ICON_SIZE:
729
      gtk_toolbar_set_icon_size (toolbar, g_value_get_int (value));
730 731 732
      break;
    case PROP_ICON_SIZE_SET:
      if (g_value_get_boolean (value))
733
	priv->icon_size_set = TRUE;
734 735 736
      else
	gtk_toolbar_unset_icon_size (toolbar);
      break;
737 738 739
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
740 741 742 743
    }
}

static void
744 745 746 747
gtk_toolbar_get_property (GObject    *object,
			  guint       prop_id,
			  GValue     *value,
			  GParamSpec *pspec)
748 749
{
  GtkToolbar *toolbar = GTK_TOOLBAR (object);
750
  GtkToolbarPrivate *priv = toolbar->priv;
751

752
  switch (prop_id)
753
    {
754
    case PROP_ORIENTATION:
755
      g_value_set_enum (value, priv->orientation);
756
      break;
757
    case PROP_TOOLBAR_STYLE:
758
      g_value_set_enum (value, priv->style);
759
      break;
760 761 762
    case PROP_SHOW_ARROW:
      g_value_set_boolean (value, priv->show_arrow);
      break;
763
    case PROP_ICON_SIZE:
764
      g_value_set_int (value, gtk_toolbar_get_icon_size (toolbar));
765 766
      break;
    case PROP_ICON_SIZE_SET:
767
      g_value_set_boolean (value, priv->icon_size_set);
768
      break;
769
    default:
770
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
771 772 773 774
      break;
    }
}

775 776
static void
gtk_toolbar_map (GtkWidget *widget)
777
{
778
  GtkToolbar *toolbar = GTK_TOOLBAR (widget);
779
  GtkToolbarPrivate *priv = toolbar->priv;
780

Matthias Clasen's avatar
Matthias Clasen committed
781
  GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->map (widget);
782

783 784
  if (priv->event_window)
    gdk_window_show_unraised (priv->event_window);
785 786 787
}

static void
788
gtk_toolbar_unmap (GtkWidget *widget)
789
{
790
  GtkToolbar *toolbar = GTK_TOOLBAR (widget);
791
  GtkToolbarPrivate *priv = toolbar->priv;
792

793 794
  if (priv->event_window)
    gdk_window_hide (priv->event_window);
795
  
Matthias Clasen's avatar
Matthias Clasen committed
796
  GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->unmap (widget);
797 798
}

799 800 801
static void
gtk_toolbar_realize (GtkWidget *widget)
{
802
  GtkAllocation allocation;
803
  GtkToolbar *toolbar = GTK_TOOLBAR (widget);
804
  GtkToolbarPrivate *priv = toolbar->priv;
805
  GdkWindow *window;
806 807
  GdkWindowAttr attributes;
  gint attributes_mask;
808 809
  guint border_width;

810
  gtk_widget_set_realized (widget, TRUE);
811

812
  gtk_widget_get_allocation (widget, &allocation);
813 814
  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));

815 816
  attributes.wclass = GDK_INPUT_ONLY;
  attributes.window_type = GDK_WINDOW_CHILD;
817 818 819 820
  attributes.x = allocation.x + border_width;
  attributes.y = allocation.y + border_width;
  attributes.width = allocation.width - border_width * 2;
  attributes.height = allocation.height - border_width * 2;
821
  attributes.event_mask = gtk_widget_get_events (widget);
822
  attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
823 824 825
			    GDK_BUTTON_RELEASE_MASK |
			    GDK_ENTER_NOTIFY_MASK |
			    GDK_LEAVE_NOTIFY_MASK);
826

827
  attributes_mask = GDK_WA_X | GDK_WA_Y;
828

829 830 831 832
  window = gtk_widget_get_parent_window (widget);
  gtk_widget_set_window (widget, window);
  g_object_ref (window);

833 834 835 836 837 838 839 840
  priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
				       &attributes, attributes_mask);
  gdk_window_set_user_data (priv->event_window, toolbar);
}

static void
gtk_toolbar_unrealize (GtkWidget *widget)
{
841
  GtkToolbar *toolbar = GTK_TOOLBAR (widget);
842
  GtkToolbarPrivate *priv = toolbar->priv;
843

844 845 846 847 848 849
  if (priv->event_window)
    {
      gdk_window_set_user_data (priv->event_window, NULL);
      gdk_window_destroy (priv->event_window);
      priv->event_window = NULL;
    }
850 851

  GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->unrealize (widget);
852 853
}

854
static gint
855 856
gtk_toolbar_draw (GtkWidget *widget,
                  cairo_t   *cr)
857
{
858
  GtkToolbar *toolbar = GTK_TOOLBAR (widget);
859
  GtkToolbarPrivate *priv = toolbar->priv;
860
  GtkStyleContext *context;
861
  GList *list;
862 863 864
  guint border_width;

  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
865 866 867 868 869 870 871 872
  context = gtk_widget_get_style_context (widget);

  gtk_render_background (context, cr, border_width, border_width,
                         gtk_widget_get_allocated_width (widget) - 2 * border_width,
                         gtk_widget_get_allocated_height (widget) - 2 * border_width);
  gtk_render_frame (context, cr, border_width, border_width,
                    gtk_widget_get_allocated_width (widget) - 2 * border_width,
                    gtk_widget_get_allocated_height (widget) - 2 * border_width);
873

874
  for (list = priv->content; list != NULL; list = list->next)
875
    {
876
      ToolbarContent *content = list->data;
877
      
878
      toolbar_content_draw (content, GTK_CONTAINER (widget), cr);
879
    }
880
  
881 882 883
  gtk_container_propagate_draw (GTK_CONTAINER (widget),
				priv->arrow_button,
				cr);
884

885
  return FALSE;
886 887 888
}

static void
889 890 891
gtk_toolbar_size_request (GtkWidget      *widget,
			  GtkRequisition *requisition)
{
892
  GtkToolbar *toolbar = GTK_TOOLBAR (widget);
893
  GtkToolbarPrivate *priv = toolbar->priv;
894 895 896 897 898 899 900 901
  GList *list;
  gint max_child_height;
  gint max_child_width;
  gint max_homogeneous_child_width;
  gint max_homogeneous_child_height;
  gint homogeneous_size;
  gint long_req;
  gint pack_front_size;
902
  gint ipadding;
903
  guint border_width;
904
  GtkRequisition arrow_requisition;
905
  
906 907 908 909
  max_homogeneous_child_width = 0;
  max_homogeneous_child_height = 0;
  max_child_width = 0;
  max_child_height = 0;
910
  for (list = priv->content; list != NULL; list = list->next)
911
    {
912
      GtkRequisition requisition;
913
      ToolbarContent *content = list->data;
914
      
915
      if (!toolbar_content_visible (content, toolbar))
916
	continue;
917
      
918
      toolbar_content_size_request (content, toolbar, &requisition);
919

920 921
      max_child_width = MAX (max_child_width, requisition.width);
      max_child_height = MAX (max_child_height, requisition.height);
922
      
923
      if (toolbar_content_is_homogeneous (content, toolbar))
924 925 926
	{
	  max_homogeneous_child_width = MAX (max_homogeneous_child_width, requisition.width);
	  max_homogeneous_child_height = MAX (max_homogeneous_child_height, requisition.height);
927
	}
928
    }
929
  
930
  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
931
    homogeneous_size = max_homogeneous_child_width;
932
  else
933 934 935
    homogeneous_size = max_homogeneous_child_height;
  
  pack_front_size = 0;
936
  for (list = priv->content; list != NULL; list = list->next)
937
    {
938
      ToolbarContent *content = list->data;
939
      guint size;
940
      
941
      if (!toolbar_content_visible (content, toolbar))
942
	continue;
943

944
      if (toolbar_content_is_homogeneous (content, toolbar))
945 946 947 948 949 950 951
	{
	  size = homogeneous_size;
	}
      else
	{
	  GtkRequisition requisition;
	  
952
	  toolbar_content_size_request (content, toolbar, &requisition);
953
	  
954
	  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
955 956 957 958
	    size = requisition.width;
	  else
	    size = requisition.height;
	}
959

960
      pack_front_size += size;
961
    }
962
  
963
  if (priv->show_arrow)
964
    {
965 966
      gtk_widget_get_preferred_size (priv->arrow_button,
                                     &arrow_requisition, NULL);
967

968
      if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
969 970 971
	long_req = arrow_requisition.width;
      else
	long_req = arrow_requisition.height;
972
      
973 974 975
      /* There is no point requesting space for the arrow if that would take
       * up more space than all the items combined
       */
976
      long_req = MIN (long_req, pack_front_size);
977 978 979 980 981 982
    }
  else
    {
      arrow_requisition.height = 0;
      arrow_requisition.width = 0;
      
983
      long_req = pack_front_size;
984 985
    }
  
986
  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
987 988 989 990 991 992 993 994 995 996
    {
      requisition->width = long_req;
      requisition->height = MAX (max_child_height, arrow_requisition.height);
    }
  else
    {
      requisition->height = long_req;
      requisition->width = MAX (max_child_width, arrow_requisition.width);
    }
  
997
  /* Extra spacing */
998
  ipadding = get_internal_padding (toolbar);
999 1000 1001 1002

  border_width = gtk_container_get_border_width (GTK_CONTAINER (toolbar));
  requisition->width += 2 * (ipadding + border_width);
  requisition->height += 2 * (ipadding + border_width);
1003
  
1004 1005
  if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
    {
1006 1007 1008 1009 1010 1011 1012
      GtkStyleContext *context;
      GtkStateFlags state;
      GtkBorder padding;

      context = gtk_widget_get_style_context (widget);
      state = gtk_widget_get_state_flags (widget);
      gtk_style_context_get_padding (context, state, &padding);
1013

1014 1015
      requisition->width += padding.left + padding.right;
      requisition->height += padding.top + padding.bottom;
1016
    }
1017
  
1018 1019
  priv->button_maxw = max_homogeneous_child_width;
  priv->button_maxh = max_homogeneous_child_height;
1020 1021
}

1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
static void
gtk_toolbar_get_preferred_width (GtkWidget *widget,
                                 gint      *minimum,
                                 gint      *natural)
{
  GtkRequisition requisition;

  gtk_toolbar_size_request (widget, &requisition);

  *minimum = *natural = requisition.width;
}

static void
gtk_toolbar_get_preferred_height (GtkWidget *widget,
                                  gint      *minimum,
                                  gint      *natural)
{
  GtkRequisition requisition;

  gtk_toolbar_size_request (widget, &requisition);

  *minimum = *natural = requisition.height;
}

1046
static gint
1047 1048 1049 1050
position (GtkToolbar *toolbar,
          gint        from,
          gint        to,
          gdouble     elapsed)
1051
{
1052
  GtkToolbarPrivate *priv = toolbar->priv;
1053 1054
  gint n_pixels;

1055
  if (!priv->animation)
1056 1057
    return to;

1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071
  if (elapsed <= ACCEL_THRESHOLD)
    {
      n_pixels = SLIDE_SPEED * elapsed;
    }
  else
    {
      /* The formula is a second degree polynomial in
       * @elapsed that has the line SLIDE_SPEED * @elapsed
       * as tangent for @elapsed == ACCEL_THRESHOLD.
       * This makes @n_pixels a smooth function of elapsed time.
       */
      n_pixels = (SLIDE_SPEED / ACCEL_THRESHOLD) * elapsed * elapsed -
	SLIDE_SPEED * elapsed + SLIDE_SPEED * ACCEL_THRESHOLD;
    }
1072

1073
  if (to > from)
1074
    return MIN (from + n_pixels, to);
1075
  else
1076
    return MAX (from - n_pixels, to);
1077 1078 1079 1080 1081 1082 1083 1084
}

static void
compute_intermediate_allocation (GtkToolbar          *toolbar,
				 const GtkAllocation *start,
				 const GtkAllocation *goal,
				 GtkAllocation       *intermediate)
{
1085
  GtkToolbarPrivate *priv = toolbar->priv;
1086
  gdouble elapsed = g_timer_elapsed (priv->timer, NULL);
1087 1088 1089 1090 1091 1092 1093 1094 1095

  intermediate->x      = position (toolbar, start->x, goal->x, elapsed);
  intermediate->y      = position (toolbar, start->y, goal->y, elapsed);
  intermediate->width  = position (toolbar, start->x + start->width,
                                   goal->x + goal->width,
                                   elapsed) - intermediate->x;
  intermediate->height = position (toolbar, start->y + start->height,
                                   goal->y + goal->height,
                                   elapsed) - intermediate->y;
1096 1097
}

1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
static void
fixup_allocation_for_rtl (gint           total_size,
			  GtkAllocation *allocation)
{
  allocation->x += (total_size - (2 * allocation->x + allocation->width));
}

static void
fixup_allocation_for_vertical (GtkAllocation *allocation)
{
  gint tmp;
1109
  
1110 1111 1112 1113 1114 1115 1116 1117 1118 1119
  tmp = allocation->x;
  allocation->x = allocation->y;
  allocation->y = tmp;
  
  tmp = allocation->width;
  allocation->width = allocation->height;
  allocation->height = tmp;
}

static gint
1120 1121
get_item_size (GtkToolbar     *toolbar,
	       ToolbarContent *content)
1122
{
1123
  GtkToolbarPrivate *priv = toolbar->priv;
1124
  GtkRequisition requisition;
1125
  
1126
  toolbar_content_size_request (content, toolbar, &requisition);
1127 1128

  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1129
    {
1130
      if (toolbar_content_is_homogeneous (content, toolbar))
1131
	return priv->button_maxw;
1132 1133 1134 1135 1136
      else
	return requisition.width;
    }
  else
    {
1137
      if (toolbar_content_is_homogeneous (content, toolbar))
1138
	return priv->button_maxh;
1139 1140 1141
      else
	return requisition.height;
    }
1142 1143
}

1144 1145 1146
static gboolean
slide_idle_handler (gpointer data)
{
1147
  GtkToolbar *toolbar = GTK_TOOLBAR (data);
1148
  GtkToolbarPrivate *priv = toolbar->priv;
1149
  GList *list;
1150

1151 1152 1153 1154 1155 1156 1157 1158 1159
  if (priv->need_sync)
    {
      gdk_flush ();
      priv->need_sync = FALSE;
    }
  
  for (list = priv->content; list != NULL; list = list->next)
    {
      ToolbarContent *content = list->data;
1160 1161 1162
      ItemState state;
      GtkAllocation goal_allocation;
      GtkAllocation allocation;
1163 1164
      gboolean cont;

1165 1166 1167 1168
      state = toolbar_content_get_state (content);
      toolbar_content_get_goal_allocation (content, &goal_allocation);
      toolbar_content_get_allocation (content, &allocation);
      
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178
      cont = FALSE;
      
      if (state == NOT_ALLOCATED)
	{
	  /* an unallocated item means that size allocate has to
	   * called at least once more
	   */
	  cont = TRUE;
	}

1179 1180 1181 1182 1183 1184 1185
      /* An invisible item with a goal allocation of
       * 0 is already at its goal.
       */
      if ((state == NORMAL || state == OVERFLOWN) &&
	  ((goal_allocation.width != 0 &&
	    goal_allocation.height != 0) ||
	   toolbar_content_child_visible (content)))
1186 1187 1188 1189 1190 1191
	{
	  if ((goal_allocation.x != allocation.x ||
	       goal_allocation.y != allocation.y ||
	       goal_allocation.width != allocation.width ||
	       goal_allocation.height != allocation.height))
	    {
1192 1193
	      /* An item is not in its right position yet. Note
	       * that OVERFLOWN items do get an allocation in
1194
	       * gtk_toolbar_size_allocate(). This way you can see
1195 1196
	       * them slide back in when you drag an item off the
	       * toolbar.
1197 1198 1199 1200 1201
	       */
	      cont = TRUE;
	    }
	}

1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
      if (toolbar_content_is_placeholder (content) &&
	  toolbar_content_disappearing (content) &&
	  toolbar_content_child_visible (content))