gtktoolbar.c 133 KB
Newer Older
1 2 3 4
/* GTK - The GIMP Toolkit
 * 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
20 21 22
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
23 24
 */

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

32
#undef GTK_DISABLE_DEPRECATED
33

34
#include <config.h>
35 36 37 38 39
#include "gtkarrow.h"
#include "gtktoolbar.h"
#include "gtkradiotoolbutton.h"
#include "gtkseparatortoolitem.h"
#include "gtkmenu.h"
40
#include "gtkradiobutton.h"
41
#include "gtktoolbar.h"
42 43 44 45
#include "gtkbindings.h"
#include <gdk/gdkkeysyms.h>
#include "gtkmarshalers.h"
#include "gtkmain.h"
46
#include "gtkstock.h"
47 48
#include "gtklabel.h"
#include "gtkprivate.h"
Havoc Pennington's avatar
Havoc Pennington committed
49
#include "gtkintl.h"
50
#include <string.h>
51 52 53
#include "gtkhbox.h"
#include "gtkvbox.h"
#include "gtkimage.h"
54
#include "gtkseparatormenuitem.h"
55
#include "gtkalias.h"
56
#include <math.h>
57

58 59
typedef struct _ToolbarContent ToolbarContent;

60
#define DEFAULT_IPADDING 0
61

62
#define DEFAULT_SPACE_SIZE  12
63
#define DEFAULT_SPACE_STYLE GTK_TOOLBAR_SPACE_LINE
64
#define SPACE_LINE_DIVISION 10.0
65 66
#define SPACE_LINE_START    2.0
#define SPACE_LINE_END      8.0
67

68
#define DEFAULT_ICON_SIZE GTK_ICON_SIZE_LARGE_TOOLBAR
69
#define DEFAULT_TOOLBAR_STYLE GTK_TOOLBAR_BOTH
70

71 72
#define MAX_HOMOGENEOUS_N_CHARS 13 /* Items that are wider than this do not participate
				    * in the homogeneous game. In units of
73 74
				    * pango_font_get_estimated_char_width().
				    */
75 76
#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 */
77

78 79 80 81
#define MIXED_API_WARNING						\
    "Mixing deprecated and non-deprecated GtkToolbar API is not allowed"


82
/* Properties */
83
enum {
84 85
  PROP_0,
  PROP_ORIENTATION,
86
  PROP_TOOLBAR_STYLE,
87
  PROP_SHOW_ARROW,
88 89 90
  PROP_TOOLTIPS,
  PROP_ICON_SIZE,
  PROP_ICON_SIZE_SET
91 92
};

93
/* Child properties */
94 95 96
enum {
  CHILD_PROP_0,
  CHILD_PROP_EXPAND,
97
  CHILD_PROP_HOMOGENEOUS
98 99
};

100
/* Signals */
101
enum {
102 103
  ORIENTATION_CHANGED,
  STYLE_CHANGED,
104 105
  POPUP_CONTEXT_MENU,
  MOVE_FOCUS,
106
  FOCUS_HOME_OR_END,
107
  LAST_SIGNAL
108 109
};

110
/* API mode */
111 112 113 114 115 116
typedef enum {
  DONT_KNOW,
  OLD_API,
  NEW_API
} ApiMode;

117
typedef enum {
118
  TOOL_ITEM,
119
  COMPATIBILITY
120
} ContentType;
121

122 123 124 125
typedef enum {
  NOT_ALLOCATED,
  NORMAL,
  HIDDEN,
126
  OVERFLOWN
127
} ItemState;
Matthias Clasen's avatar
Matthias Clasen committed
128

129 130
struct _GtkToolbarPrivate
{
131
  GList	*	content;
132
  
133 134 135
  GtkWidget *	arrow;
  GtkWidget *	arrow_button;
  GtkMenu *	menu;
136
  
137 138 139 140 141 142
  GdkWindow *	event_window;
  ApiMode	api_mode;
  GtkSettings *	settings;
  int		idle_id;
  GtkToolItem *	highlight_tool_item;
  gint		max_homogeneous_pixels;
143
  
144
  GTimer *	timer;
145 146 147 148
  
  guint		show_arrow : 1;
  guint		need_sync : 1;
  guint		is_sliding : 1;
149
  guint		need_rebuild : 1;	/* whether the overflow menu should be regenerated */
150
};
151

152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
static void       gtk_toolbar_init                 (GtkToolbar          *toolbar);
static void       gtk_toolbar_class_init           (GtkToolbarClass     *klass);
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);
static gint       gtk_toolbar_expose               (GtkWidget           *widget,
						    GdkEventExpose      *event);
static void       gtk_toolbar_realize              (GtkWidget           *widget);
static void       gtk_toolbar_unrealize            (GtkWidget           *widget);
static void       gtk_toolbar_size_request         (GtkWidget           *widget,
						    GtkRequisition      *requisition);
static void       gtk_toolbar_size_allocate        (GtkWidget           *widget,
						    GtkAllocation       *allocation);
static void       gtk_toolbar_style_set            (GtkWidget           *widget,
						    GtkStyle            *prev_style);
static gboolean   gtk_toolbar_focus                (GtkWidget           *widget,
						    GtkDirectionType     dir);
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);
static void       gtk_toolbar_show_all             (GtkWidget           *widget);
static void       gtk_toolbar_hide_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);
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_move_focus           (GtkToolbar          *toolbar,
						    GtkDirectionType     dir);
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 GtkWidget *internal_insert_element          (GtkToolbar          *toolbar,
						    GtkToolbarChildType  type,
						    GtkWidget           *widget,
						    const char          *text,
						    const char          *tooltip_text,
						    const char          *tooltip_private_text,
						    GtkWidget           *icon,
						    GtkSignalFunc        callback,
						    gpointer             user_data,
						    gint                 position,
						    gboolean             use_stock);
static void       gtk_toolbar_reconfigured         (GtkToolbar          *toolbar);
static gboolean   gtk_toolbar_check_new_api        (GtkToolbar          *toolbar);
static gboolean   gtk_toolbar_check_old_api        (GtkToolbar          *toolbar);
231 232 233 234 235 236

static GtkReliefStyle       get_button_relief    (GtkToolbar *toolbar);
static gint                 get_internal_padding (GtkToolbar *toolbar);
static GtkShadowType        get_shadow_type      (GtkToolbar *toolbar);
static gint                 get_space_size       (GtkToolbar *toolbar);
static GtkToolbarSpaceStyle get_space_style      (GtkToolbar *toolbar);
237

238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
/* methods on ToolbarContent 'class' */
static ToolbarContent *toolbar_content_new_tool_item        (GtkToolbar          *toolbar,
							     GtkToolItem         *item,
							     gboolean             is_placeholder,
							     gint                 pos);
static ToolbarContent *toolbar_content_new_compatibility    (GtkToolbar          *toolbar,
							     GtkToolbarChildType  type,
							     GtkWidget           *widget,
							     GtkWidget           *icon,
							     GtkWidget           *label,
							     gint                 pos);
static void            toolbar_content_remove               (ToolbarContent      *content,
							     GtkToolbar          *toolbar);
static void            toolbar_content_free                 (ToolbarContent      *content);
static void            toolbar_content_expose               (ToolbarContent      *content,
							     GtkContainer        *container,
							     GdkEventExpose      *expose);
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);
293
static gboolean        toolbar_content_has_proxy_menu_item  (ToolbarContent	 *content);
294 295 296
static gboolean        toolbar_content_is_separator         (ToolbarContent      *content);
static void            toolbar_content_show_all             (ToolbarContent      *content);
static void            toolbar_content_hide_all             (ToolbarContent      *content);
297 298
static void	       toolbar_content_set_expand	    (ToolbarContent      *content,
							     gboolean		  expand);
299 300 301 302 303 304

#define GTK_TOOLBAR_GET_PRIVATE(o)  \
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_TOOLBAR, GtkToolbarPrivate))

static GtkContainerClass *	parent_class = NULL;
static guint			toolbar_signals [LAST_SIGNAL] = { 0 };
305

Manish Singh's avatar
Manish Singh committed
306
GType
307
gtk_toolbar_get_type (void)
308
{
309
  static GtkType type = 0;
310
  
311
  if (!type)
312
    {
313 314 315 316 317 318 319 320 321 322 323 324
      static const GTypeInfo type_info =
	{
	  sizeof (GtkToolbarClass),
	  (GBaseInitFunc) NULL,
	  (GBaseFinalizeFunc) NULL,
	  (GClassInitFunc) gtk_toolbar_class_init,
	  (GClassFinalizeFunc) NULL,
	  NULL,
	  sizeof (GtkToolbar),
	  0, /* n_preallocs */
	  (GInstanceInitFunc) gtk_toolbar_init,
	};
325
      
326
      type = g_type_register_static (GTK_TYPE_CONTAINER,
327
				     I_("GtkToolbar"),
328
				     &type_info, 0);
329
    }
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
  
  return type;
}

static void
add_arrow_bindings (GtkBindingSet   *binding_set,
		    guint            keysym,
		    GtkDirectionType dir)
{
  guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
  
  gtk_binding_entry_add_signal (binding_set, keysym, 0,
                                "move_focus", 1,
                                GTK_TYPE_DIRECTION_TYPE, dir);
  gtk_binding_entry_add_signal (binding_set, keypad_keysym, 0,
                                "move_focus", 1,
                                GTK_TYPE_DIRECTION_TYPE, dir);
}
348

349 350 351 352 353 354 355 356 357 358 359 360 361
static void
add_ctrl_tab_bindings (GtkBindingSet    *binding_set,
		       GdkModifierType   modifiers,
		       GtkDirectionType  direction)
{
  gtk_binding_entry_add_signal (binding_set,
				GDK_Tab, GDK_CONTROL_MASK | modifiers,
				"move_focus", 1,
				GTK_TYPE_DIRECTION_TYPE, direction);
  gtk_binding_entry_add_signal (binding_set,
				GDK_KP_Tab, GDK_CONTROL_MASK | modifiers,
				"move_focus", 1,
				GTK_TYPE_DIRECTION_TYPE, direction);
362 363 364
}

static void
365
gtk_toolbar_class_init (GtkToolbarClass *klass)
366
{
367
  GObjectClass *gobject_class;
368 369
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;
370
  GtkBindingSet *binding_set;
371
  
372 373 374 375 376 377
  parent_class = g_type_class_peek_parent (klass);
  
  gobject_class = (GObjectClass *)klass;
  widget_class = (GtkWidgetClass *)klass;
  container_class = (GtkContainerClass *)klass;
  
378 379
  gobject_class->set_property = gtk_toolbar_set_property;
  gobject_class->get_property = gtk_toolbar_get_property;
380
  gobject_class->finalize = gtk_toolbar_finalize;
381
  
382
  widget_class->button_press_event = gtk_toolbar_button_press;
383 384 385
  widget_class->expose_event = gtk_toolbar_expose;
  widget_class->size_request = gtk_toolbar_size_request;
  widget_class->size_allocate = gtk_toolbar_size_allocate;
Havoc Pennington's avatar
Havoc Pennington committed
386
  widget_class->style_set = gtk_toolbar_style_set;
387
  widget_class->focus = gtk_toolbar_focus;
388
  widget_class->screen_changed = gtk_toolbar_screen_changed;
389 390 391 392
  widget_class->realize = gtk_toolbar_realize;
  widget_class->unrealize = gtk_toolbar_unrealize;
  widget_class->map = gtk_toolbar_map;
  widget_class->unmap = gtk_toolbar_unmap;
393
  widget_class->popup_menu = gtk_toolbar_popup_menu;
394 395
  widget_class->show_all = gtk_toolbar_show_all;
  widget_class->hide_all = gtk_toolbar_hide_all;
Havoc Pennington's avatar
Havoc Pennington committed
396
  
397
  container_class->add    = gtk_toolbar_add;
398
  container_class->remove = gtk_toolbar_remove;
399
  container_class->forall = gtk_toolbar_forall;
400 401 402 403
  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;
  
404
  klass->orientation_changed = gtk_toolbar_orientation_changed;
405
  klass->style_changed = gtk_toolbar_real_style_changed;
406
  
407 408 409 410 411 412 413
  /**
   * 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.
   */
414
  toolbar_signals[ORIENTATION_CHANGED] =
415
    g_signal_new (I_("orientation-changed"),
416
		  G_OBJECT_CLASS_TYPE (klass),
Manish Singh's avatar
Manish Singh committed
417 418 419
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkToolbarClass, orientation_changed),
		  NULL, NULL,
420
		  g_cclosure_marshal_VOID__ENUM,
Manish Singh's avatar
Manish Singh committed
421 422
		  G_TYPE_NONE, 1,
		  GTK_TYPE_ORIENTATION);
423 424 425 426 427 428 429
  /**
   * 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. 
   */
430
  toolbar_signals[STYLE_CHANGED] =
431
    g_signal_new (I_("style-changed"),
432
		  G_OBJECT_CLASS_TYPE (klass),
Manish Singh's avatar
Manish Singh committed
433 434 435
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkToolbarClass, style_changed),
		  NULL, NULL,
436
		  g_cclosure_marshal_VOID__ENUM,
Manish Singh's avatar
Manish Singh committed
437 438
		  G_TYPE_NONE, 1,
		  GTK_TYPE_TOOLBAR_STYLE);
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
  /**
   * 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
   */
457
  toolbar_signals[POPUP_CONTEXT_MENU] =
458
    g_signal_new (I_("popup_context_menu"),
459
		  G_OBJECT_CLASS_TYPE (klass),
460
		  G_SIGNAL_RUN_LAST,
461
		  G_STRUCT_OFFSET (GtkToolbarClass, popup_context_menu),
462 463 464 465 466
		  _gtk_boolean_handled_accumulator, NULL,
		  _gtk_marshal_BOOLEAN__INT_INT_INT,
		  G_TYPE_BOOLEAN, 3,
		  G_TYPE_INT, G_TYPE_INT,
		  G_TYPE_INT);
467 468 469 470 471 472 473 474 475 476
  /**
   * GtkToolbar::move-focus:
   * @toolbar: the #GtkToolbar which emitted the signal
   * @dir: a #GtkDirection
   *
   * 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
   */
477
  toolbar_signals[MOVE_FOCUS] =
478
    _gtk_binding_signal_new (I_("move_focus"),
479 480 481 482 483 484 485
			     G_TYPE_FROM_CLASS (klass),
			     G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
			     G_CALLBACK (gtk_toolbar_move_focus),
			     NULL, NULL,
			     _gtk_marshal_BOOLEAN__ENUM,
			     G_TYPE_BOOLEAN, 1,
			     GTK_TYPE_DIRECTION_TYPE);
486 487 488 489 490 491 492 493 494 495
  /**
   * 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
   */
496
  toolbar_signals[FOCUS_HOME_OR_END] =
497
    _gtk_binding_signal_new (I_("focus_home_or_end"),
498 499
			     G_OBJECT_CLASS_TYPE (klass),
			     G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
500
			     G_CALLBACK (gtk_toolbar_focus_home_or_end),
501 502 503 504
			     NULL, NULL,
			     _gtk_marshal_BOOLEAN__BOOLEAN,
			     G_TYPE_BOOLEAN, 1,
			     G_TYPE_BOOLEAN);
505
  
506
  /* properties */
507 508 509
  g_object_class_install_property (gobject_class,
				   PROP_ORIENTATION,
				   g_param_spec_enum ("orientation",
510 511
 						      P_("Orientation"),
 						      P_("The orientation of the toolbar"),
512 513
 						      GTK_TYPE_ORIENTATION,
 						      GTK_ORIENTATION_HORIZONTAL,
514
 						      GTK_PARAM_READWRITE));
515
  
516 517
  g_object_class_install_property (gobject_class,
				   PROP_TOOLBAR_STYLE,
518
				   g_param_spec_enum ("toolbar-style",
519 520
 						      P_("Toolbar Style"),
 						      P_("How to draw the toolbar"),
521 522
 						      GTK_TYPE_TOOLBAR_STYLE,
 						      GTK_TOOLBAR_ICONS,
523
 						      GTK_PARAM_READWRITE));
524 525
  g_object_class_install_property (gobject_class,
				   PROP_SHOW_ARROW,
526
				   g_param_spec_boolean ("show-arrow",
527 528
							 P_("Show Arrow"),
							 P_("If an arrow should be shown if the toolbar doesn't fit"),
529
							 TRUE,
530
							 GTK_PARAM_READWRITE));
531
  
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547

  /**
   * GtkToolbar:tooltips:
   * 
   * If the tooltips of the toolbar should be active or not.
   * 
   * Since: 2.8
   */
  g_object_class_install_property (gobject_class,
				   PROP_TOOLTIPS,
				   g_param_spec_boolean ("tooltips",
							 P_("Tooltips"),
							 P_("If the tooltips of the toolbar should be active or not"),
							 TRUE,
							 GTK_PARAM_READWRITE));
  
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585

  /**
   * 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,
				   g_param_spec_enum ("icon-size",
						      P_("Icon size"),
						      P_("Size of icons in this toolbar"),
						      GTK_TYPE_ICON_SIZE,
						      DEFAULT_ICON_SIZE,
						      GTK_PARAM_READWRITE));  

  /**
   * 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));  

586 587 588 589
  /* child properties */
  gtk_container_class_install_child_property (container_class,
					      CHILD_PROP_EXPAND,
					      g_param_spec_boolean ("expand", 
590 591
								    P_("Expand"), 
								    P_("Whether the item should receive extra space when the toolbar grows"),
592
								    TRUE,
593
								    GTK_PARAM_READWRITE));
594
  
595 596 597
  gtk_container_class_install_child_property (container_class,
					      CHILD_PROP_HOMOGENEOUS,
					      g_param_spec_boolean ("homogeneous", 
598 599
								    P_("Homogeneous"), 
								    P_("Whether the item should be the same size as other homogeneous items"),
600
								    TRUE,
601
								    GTK_PARAM_READWRITE));
602
  
603
  /* style properties */
Havoc Pennington's avatar
Havoc Pennington committed
604
  gtk_widget_class_install_style_property (widget_class,
605
					   g_param_spec_int ("space-size",
606 607
							     P_("Spacer size"),
							     P_("Size of spacers"),
Havoc Pennington's avatar
Havoc Pennington committed
608 609 610
							     0,
							     G_MAXINT,
                                                             DEFAULT_SPACE_SIZE,
611
							     GTK_PARAM_READABLE));
612
  
613
  gtk_widget_class_install_style_property (widget_class,
614
					   g_param_spec_int ("internal-padding",
615 616
							     P_("Internal padding"),
							     P_("Amount of border space between the toolbar shadow and the buttons"),
617 618 619
							     0,
							     G_MAXINT,
                                                             DEFAULT_IPADDING,
620
                                                             GTK_PARAM_READABLE));
621
  
Havoc Pennington's avatar
Havoc Pennington committed
622
  gtk_widget_class_install_style_property (widget_class,
623
					   g_param_spec_enum ("space-style",
624 625
							      P_("Space style"),
							      P_("Whether spacers are vertical lines or just blank"),
Havoc Pennington's avatar
Havoc Pennington committed
626 627
                                                              GTK_TYPE_TOOLBAR_SPACE_STYLE,
                                                              DEFAULT_SPACE_STYLE,
628
                                                              GTK_PARAM_READABLE));
629
  
Havoc Pennington's avatar
Havoc Pennington committed
630
  gtk_widget_class_install_style_property (widget_class,
631
					   g_param_spec_enum ("button-relief",
632 633
							      P_("Button relief"),
							      P_("Type of bevel around toolbar buttons"),
Havoc Pennington's avatar
Havoc Pennington committed
634
                                                              GTK_TYPE_RELIEF_STYLE,
635
                                                              GTK_RELIEF_NONE,
636
                                                              GTK_PARAM_READABLE));
637
  gtk_widget_class_install_style_property (widget_class,
638
                                           g_param_spec_enum ("shadow-type",
639 640
                                                              P_("Shadow type"),
                                                              P_("Style of bevel around the toolbar"),
641 642
                                                              GTK_TYPE_SHADOW_TYPE,
                                                              GTK_SHADOW_OUT,
643
                                                              GTK_PARAM_READABLE));
644
  
645
  gtk_settings_install_property (g_param_spec_enum ("gtk-toolbar-style",
646 647
                                                    P_("Toolbar style"),
                                                    P_("Whether default toolbars have text only, text and icons, icons only, etc."),
648
                                                    GTK_TYPE_TOOLBAR_STYLE,
649
                                                    DEFAULT_TOOLBAR_STYLE,
650
                                                    GTK_PARAM_READWRITE));
651
  
652
  gtk_settings_install_property (g_param_spec_enum ("gtk-toolbar-icon-size",
653 654
                                                    P_("Toolbar icon size"),
                                                    P_("Size of icons in default toolbars"),
655
                                                    GTK_TYPE_ICON_SIZE,
656
                                                    DEFAULT_ICON_SIZE,
657
                                                    GTK_PARAM_READWRITE));  
658
  
659
  binding_set = gtk_binding_set_by_class (klass);
660
  
661 662 663 664
  add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
  add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
  add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
  add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
665
  
666
  gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
667
                                "focus_home_or_end", 1,
668 669
				G_TYPE_BOOLEAN, TRUE);
  gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
670
                                "focus_home_or_end", 1,
671 672
				G_TYPE_BOOLEAN, TRUE);
  gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
673
                                "focus_home_or_end", 1,
674 675
				G_TYPE_BOOLEAN, FALSE);
  gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
676
                                "focus_home_or_end", 1,
677
				G_TYPE_BOOLEAN, FALSE);
678
  
679 680
  add_ctrl_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
  add_ctrl_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
681
  
682
  g_type_class_add_private (gobject_class, sizeof (GtkToolbarPrivate));  
683 684
}

685
static void
686
gtk_toolbar_init (GtkToolbar *toolbar)
687
{
688 689 690 691
  GtkToolbarPrivate *priv;
  
  GTK_WIDGET_UNSET_FLAGS (toolbar, GTK_CAN_FOCUS);
  GTK_WIDGET_SET_FLAGS (toolbar, GTK_NO_WINDOW);
692
  
693
  priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
694
  
695 696 697 698 699 700 701 702 703 704 705 706 707 708
  toolbar->orientation = GTK_ORIENTATION_HORIZONTAL;
  toolbar->style = DEFAULT_TOOLBAR_STYLE;
  toolbar->icon_size = DEFAULT_ICON_SIZE;
  toolbar->tooltips = gtk_tooltips_new ();
  g_object_ref (toolbar->tooltips);
  gtk_object_sink (GTK_OBJECT (toolbar->tooltips));
  
  priv->arrow_button = gtk_toggle_button_new ();
  g_signal_connect (priv->arrow_button, "button_press_event",
		    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));
709
  
710 711 712 713 714
  priv->api_mode = DONT_KNOW;
  
  gtk_button_set_focus_on_click (GTK_BUTTON (priv->arrow_button), FALSE);
  
  priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
715
  gtk_widget_set_name (priv->arrow, "gtk-toolbar-arrow");
716 717 718 719
  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));
720
  
721 722
  /* which child position a drop will occur at */
  priv->menu = NULL;
723
  priv->show_arrow = TRUE;
724
  priv->settings = NULL;
725
  
726 727
  priv->max_homogeneous_pixels = -1;
  
728
  priv->timer = g_timer_new ();
729 730
}

731
static void
732 733
gtk_toolbar_set_property (GObject      *object,
			  guint         prop_id,
734 735
			  const GValue *value,
			  GParamSpec   *pspec)
736 737
{
  GtkToolbar *toolbar = GTK_TOOLBAR (object);
738
  
739
  switch (prop_id)
740
    {
741 742
    case PROP_ORIENTATION:
      gtk_toolbar_set_orientation (toolbar, g_value_get_enum (value));
743
      break;
744 745
    case PROP_TOOLBAR_STYLE:
      gtk_toolbar_set_style (toolbar, g_value_get_enum (value));
746
      break;
747 748 749
    case PROP_SHOW_ARROW:
      gtk_toolbar_set_show_arrow (toolbar, g_value_get_boolean (value));
      break;
750 751 752
    case PROP_TOOLTIPS:
      gtk_toolbar_set_tooltips (toolbar, g_value_get_boolean (value));
      break;
753 754 755 756 757 758 759 760 761
    case PROP_ICON_SIZE:
      gtk_toolbar_set_icon_size (toolbar, g_value_get_enum (value));
      break;
    case PROP_ICON_SIZE_SET:
      if (g_value_get_boolean (value))
	toolbar->icon_size_set = TRUE;
      else
	gtk_toolbar_unset_icon_size (toolbar);
      break;
762 763 764
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
765 766 767 768
    }
}

static void
769 770 771 772
gtk_toolbar_get_property (GObject    *object,
			  guint       prop_id,
			  GValue     *value,
			  GParamSpec *pspec)
773 774
{
  GtkToolbar *toolbar = GTK_TOOLBAR (object);
775 776
  GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
  
777
  switch (prop_id)
778
    {
779 780
    case PROP_ORIENTATION:
      g_value_set_enum (value, toolbar->orientation);
781
      break;
782 783
    case PROP_TOOLBAR_STYLE:
      g_value_set_enum (value, toolbar->style);
784
      break;
785 786 787
    case PROP_SHOW_ARROW:
      g_value_set_boolean (value, priv->show_arrow);
      break;
788 789 790
    case PROP_TOOLTIPS:
      g_value_set_boolean (value, gtk_toolbar_get_tooltips (toolbar));
      break;
791 792 793 794 795 796
    case PROP_ICON_SIZE:
      g_value_set_enum (value, gtk_toolbar_get_icon_size (toolbar));
      break;
    case PROP_ICON_SIZE_SET:
      g_value_set_boolean (value, toolbar->icon_size_set);
      break;
797
    default:
798
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
799 800 801 802
      break;
    }
}

803 804
static void
gtk_toolbar_map (GtkWidget *widget)
805
{
806
  GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
807
  
808
  GTK_WIDGET_CLASS (parent_class)->map (widget);
809
  
810 811
  if (priv->event_window)
    gdk_window_show_unraised (priv->event_window);
812 813 814
}

static void
815
gtk_toolbar_unmap (GtkWidget *widget)
816
{
817
  GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
818
  
819 820
  if (priv->event_window)
    gdk_window_hide (priv->event_window);
821
  
822
  GTK_WIDGET_CLASS (parent_class)->unmap (widget);
823 824
}

825 826 827 828 829
static void
gtk_toolbar_realize (GtkWidget *widget)
{
  GtkToolbar *toolbar = GTK_TOOLBAR (widget);
  GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
830
  
831 832 833
  GdkWindowAttr attributes;
  gint attributes_mask;
  gint border_width;
834
  
835
  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
836
  
837
  border_width = GTK_CONTAINER (widget)->border_width;
838
  
839 840 841 842 843 844 845
  attributes.wclass = GDK_INPUT_ONLY;
  attributes.window_type = GDK_WINDOW_CHILD;
  attributes.x = widget->allocation.x + border_width;
  attributes.y = widget->allocation.y + border_width;
  attributes.width = widget->allocation.width - border_width * 2;
  attributes.height = widget->allocation.height - border_width * 2;
  attributes.event_mask = gtk_widget_get_events (widget);
846
  attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
847 848 849
			    GDK_BUTTON_RELEASE_MASK |
			    GDK_ENTER_NOTIFY_MASK |
			    GDK_LEAVE_NOTIFY_MASK);
850
  
851
  attributes_mask = GDK_WA_X | GDK_WA_Y;
852
  
853 854
  widget->window = gtk_widget_get_parent_window (widget);
  g_object_ref (widget->window);
855
  widget->style = gtk_style_attach (widget->style, widget->window);
856 857 858 859 860 861 862 863 864 865
  
  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)
{
  GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
866
  
867 868 869 870 871 872
  if (priv->event_window)
    {
      gdk_window_set_user_data (priv->event_window, NULL);
      gdk_window_destroy (priv->event_window);
      priv->event_window = NULL;
    }
873
  
874 875
  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
876 877
}

878
static gint
879 880
gtk_toolbar_expose (GtkWidget      *widget,
		    GdkEventExpose *event)
881
{
882 883 884
  GtkToolbar *toolbar = GTK_TOOLBAR (widget);
  GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
  
885
  GList *list;
886
  gint border_width;
887
  
888 889
  border_width = GTK_CONTAINER (widget)->border_width;
  
890 891
  if (GTK_WIDGET_DRAWABLE (widget))
    {
892 893 894
      gtk_paint_box (widget->style,
		     widget->window,
                     GTK_WIDGET_STATE (widget),
895
                     get_shadow_type (toolbar),
896
		     &event->area, widget, "toolbar",
897 898
		     border_width + widget->allocation.x,
                     border_width + widget->allocation.y,
899 900
		     widget->allocation.width - 2 * border_width,
                     widget->allocation.height - 2 * border_width);
901
    }
902
  
903
  for (list = priv->content; list != NULL; list = list->next)
904
    {
905
      ToolbarContent *content = list->data;
906
      
907
      toolbar_content_expose (content, GTK_CONTAINER (widget), event);
908
    }
909
  
910 911 912
  gtk_container_propagate_expose (GTK_CONTAINER (widget),
				  priv->arrow_button,
				  event);
913
  
914
  return FALSE;
915 916 917
}

static void
918 919 920
gtk_toolbar_size_request (GtkWidget      *widget,
			  GtkRequisition *requisition)
{
921 922 923 924 925 926 927 928 929 930
  GtkToolbar *toolbar = GTK_TOOLBAR (widget);
  GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
  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;
931
  gint ipadding;
932
  GtkRequisition arrow_requisition;
933
  
934 935 936 937
  max_homogeneous_child_width = 0;
  max_homogeneous_child_height = 0;
  max_child_width = 0;
  max_child_height = 0;
938
  for (list = priv->content; list != NULL; list = list->next)
939
    {
940
      GtkRequisition requisition;
941
      ToolbarContent *content = list->data;
942
      
943
      if (!toolbar_content_visible (content, toolbar))
944
	continue;
945
      
946
      toolbar_content_size_request (content, toolbar, &requisition);
947

948 949
      max_child_width = MAX (max_child_width, requisition.width);
      max_child_height = MAX (max_child_height, requisition.height);
950
      
951
      if (toolbar_content_is_homogeneous (content, toolbar))
952 953 954
	{
	  max_homogeneous_child_width = MAX (max_homogeneous_child_width, requisition.width);
	  max_homogeneous_child_height = MAX (max_homogeneous_child_height, requisition.height);
955
	}
956
    }
957
  
958
  if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
959
    homogeneous_size = max_homogeneous_child_width;
960
  else
961 962 963
    homogeneous_size = max_homogeneous_child_height;
  
  pack_front_size = 0;
964
  for (list = priv->content; list != NULL; list = list->next)
965
    {
966
      ToolbarContent *content = list->data;
967
      guint size;
968
      
969
      if (!toolbar_content_visible (content, toolbar))
970
	continue;
971

972
      if (toolbar_content_is_homogeneous (content, toolbar))
973 974 975 976 977 978 979
	{
	  size = homogeneous_size;
	}
      else
	{
	  GtkRequisition requisition;
	  
980
	  toolbar_content_size_request (content, toolbar, &requisition);
981
	  
982 983 984 985 986
	  if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
	    size = requisition.width;
	  else
	    size = requisition.height;
	}
987

988
      pack_front_size += size;
989
    }
990
  
991
  if (priv->show_arrow && priv->api_mode == NEW_API)
992 993 994 995 996 997 998
    {
      gtk_widget_size_request (priv->arrow_button, &arrow_requisition);
      
      if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
	long_req = arrow_requisition.width;
      else
	long_req = arrow_requisition.height;
999
      
1000 1001 1002
      /* There is no point requesting space for the arrow if that would take
       * up more space than all the items combined
       */
1003
      long_req = MIN (long_req, pack_front_size);
1004 1005 1006 1007 1008 1009
    }
  else
    {
      arrow_requisition.height = 0;
      arrow_requisition.width = 0;
      
1010
      long_req = pack_front_size;
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
    }
  
  if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
    {
      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);
    }
  
1024
  /* Extra spacing */
1025
  ipadding = get_internal_padding (toolbar);
1026
  
1027 1028
  requisition->width += 2 * (ipadding + GTK_CONTAINER (toolbar)->border_width);
  requisition->height += 2 * (ipadding + GTK_CONTAINER (toolbar)->border_width);
1029
  
1030 1031 1032 1033 1034
  if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
    {
      requisition->width += 2 * widget->style->xthickness;
      requisition->height += 2 * widget->style->ythickness;
    }
1035 1036 1037 1038 1039
  
  toolbar->button_maxw = max_homogeneous_child_width;
  toolbar->button_maxh = max_homogeneous_child_height;
}

1040 1041 1042
static gint
position (gint from, gint to, gdouble elapsed)
{
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
  gint n_pixels;

  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;
    }
  
1060
  if (to > from)
1061
    return MIN (from + n_pixels, to);
1062
  else
1063
    return MAX (from - n_pixels, to);
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
}

static void
compute_intermediate_allocation (GtkToolbar          *toolbar,
				 const GtkAllocation *start,
				 const GtkAllocation *goal,
				 GtkAllocation       *intermediate)
{
  GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
  gdouble elapsed = g_timer_elapsed (priv->timer, NULL);
1074
  
1075 1076 1077 1078 1079 1080 1081 1082
  intermediate->x = position (start->x, goal->x, elapsed);
  intermediate->y = position (start->y, goal->y, elapsed);
  intermediate->width =
    position (start->x + start->width, goal->x + goal->width, elapsed) - intermediate->x;
  intermediate->height =
    position (start->y + start->height, goal->y + goal->height, elapsed) - intermediate->y;
}

1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
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;
1094
  
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
  tmp = allocation->x;
  allocation->x = allocation->y;
  allocation->y = tmp;
  
  tmp = allocation->width;
  allocation->width = allocation->height;
  allocation->height = tmp;
}

static gint
1105 1106
get_item_size (GtkToolbar     *toolbar,
	       ToolbarContent *content)
1107 1108
{
  GtkRequisition requisition;
1109
  
1110
  toolbar_content_size_request (content, toolbar, &requisition);
1111
  
1112
  if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
1113
    {
1114
      if (toolbar_content_is_homogeneous (content, toolbar))
1115 1116 1117 1118 1119 1120
	return toolbar->button_maxw;
      else
	return requisition.width;
    }
  else
    {
1121
      if (toolbar_content_is_homogeneous (content, toolbar))
1122 1123 1124 1125
	return toolbar->button_maxh;
      else
	return requisition.height;
    }
1126 1127
}

1128 1129 1130 1131
static gboolean
slide_idle_handler (gpointer data)
{
  GtkToolbar *toolbar = data;
1132
  GtkToolbarPrivate *priv;
1133
  GList *list;
1134
  
1135
  GDK_THREADS_ENTER ();
1136
  
1137
  priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1138
  
1139 1140 1141 1142 1143 1144 1145 1146 1147
  if (priv->need_sync)
    {
      gdk_flush ();
      priv->need_sync = FALSE;
    }
  
  for (list = priv->content; list != NULL; list = list->next)
    {
      ToolbarContent *content = list->data;
1148 1149 1150
      ItemState state;
      GtkAllocation goal_allocation;
      GtkAllocation allocation;
1151 1152
      gboolean cont;

1153 1154 1155 1156
      state = toolbar_content_get_state (content);
      toolbar_content_get_goal_allocation (content, &goal_allocation);
      toolbar_content_get_allocation (content, &allocation);
      
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
      cont = FALSE;
      
      if (state == NOT_ALLOCATED)
	{
	  /* an unallocated item means that size allocate has to
	   * called at least once more
	   */
	  cont = TRUE;
	}

1167 1168 1169 1170 1171 1172 1173
      /* 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)))
1174 1175 1176 1177 1178 1179
	{
	  if ((goal_allocation.x != allocation.x ||
	       goal_allocation.y != allocation.y ||
	       goal_allocation.width != allocation.width ||
	       goal_allocation.height != allocation.height))
	    {
1180 1181
	      /* An item is not in its right position yet. Note
	       * that OVERFLOWN items do get an allocation in
1182
	       * gtk_toolbar_size_allocate(). This way you can see
1183 1184
	       * them slide back in when you drag an item off the
	       * toolbar.
1185 1186 1187 1188 1189
	       */
	      cont = TRUE;
	    }
	}

1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
      if (toolbar_content_is_placeholder (content) &&
	  toolbar_content_disappearing (content) &&
	  toolbar_content_child_visible (content))
	{
	  /* A disappearing placeholder is still visible.
	   */
	     
	  cont = TRUE;
	}
      
1200
      if (cont)
1201 1202
	{
	  gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1203
	  
1204
	  GDK_THREADS_LEAVE ();
1205 1206 1207
	  return TRUE;
	}
    }
1208
  
1209 1210
  priv->is_sliding = FALSE;
  priv->idle_id = 0;
1211

1212
  GDK_THREADS_LEAVE();
1213 1214 1215 1216
  return FALSE;
}

static gboolean
1217 1218
rect_within (GtkAllocation *a1,
	     GtkAllocation *a2)
1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236
{
  return (a1->x >= a2->x                         &&
	  a1->x + a1->width <= a2->x + a2->width &&
	  a1->y >= a2->y			 &&
	  a1->y + a1->height <= a2->y + a2->height);
}

static void
gtk_toolbar_begin_sliding (GtkToolbar *toolbar)
{
  GtkWidget *widget = GTK_WIDGET (toolbar);
  GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
  GList *list;
  gint cur_x;
  gint cur_y;
  gint border_width;
  gboolean rtl;
  gboolean vertical;
1237
  
1238 1239 1240 1241
  /* Start the sliding. This function copies the allocation of every
   * item into content->start_allocation. For items that haven't
   * been allocated yet, we calculate their position and save that
   * in start_allocatino along with zero width and zero height.
1242 1243 1244
   *
   * FIXME: It would be nice if we could share this code with
   * the equivalent in gtk_widget_size_allocate().
1245 1246 1247 1248 1249
   */
  priv->is_sliding = TRUE;
  
  if (!priv->idle_id)
    priv->idle_id = g_idle_add (slide_idle_handler, toolbar);
1250
  
1251 1252 1253
  rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
  vertical = (toolbar->orientation == GTK_ORIENTATION_VERTICAL);
  border_width = get_internal_padding (toolbar) + GTK_CONTAINER (toolbar)->border_width;
1254
  
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264
  if (rtl)
    {
      cur_x = widget->allocation.width - border_width - widget->style->xthickness;
      cur_y = widget->allocation.height - border_width - widget->style->ythickness;
    }
  else
    {
      cur_x = border_width + widget->style->xthickness;
      cur_y = border_width + widget->style->ythickness;
    }
1265
  
1266 1267 1268 1269 1270 1271
  cur_x += widget->allocation.x;
  cur_y += widget->allocation.y;
  
  for (list = priv->content; list != NULL; list = list->next)
    {
      ToolbarContent *content = list->data;
1272 1273
      GtkAllocation new_start_allocation;
      GtkAllocation item_allocation;
1274
      ItemState state;
1275
      
1276 1277 1278
      state = toolbar_content_get_state (content);
      toolbar_content_get_allocation (content, &item_allocation);
      
1279 1280 1281
      if ((state == NORMAL &&
	   rect_within (&item_allocation, &(widget->allocation))) ||
	  state == OVERFLOWN)
1282
	{
1283
	  new_start_allocation = item_allocation;
1284 1285 1286
	}
      else
	{
1287 1288
	  new_start_allocation.x = cur_x;
	  new_start_allocation.y = cur_y;
1289
	  
1290 1291
	  if (vertical)
	    {
1292
	      new_start_allocation.width = widget->allocation.width -
1293
		2 * border_width - 2 * widget->style->xthickness;
1294
	      new_start_allocation.height = 0;
1295 1296 1297
	    }
	  else
	    {
1298 1299
	      new_start_allocation.width = 0;
	      new_start_allocation.height = widget->allocation.height -