]> Pileus Git - ~andy/gtk/blob - gtk/gtktoolbar.c
toolbar: don't request CSS padding twice
[~andy/gtk] / gtk / gtktoolbar.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * GtkToolbar copyright (C) Federico Mena
4  *
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  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
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  * file for a list of people on the GTK+ Team.  See the ChangeLog
26  * 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 #include <math.h>
34 #include <string.h>
35
36 #include "gtktoolbar.h"
37
38 #include "gtkarrow.h"
39 #include "gtkbindings.h"
40 #include "gtkcontainerprivate.h"
41 #include "gtkimage.h"
42 #include "gtklabel.h"
43 #include "gtkmain.h"
44 #include "gtkmarshalers.h"
45 #include "gtkmenu.h"
46 #include "gtkorientable.h"
47 #include "gtkradiobutton.h"
48 #include "gtkradiotoolbutton.h"
49 #include "gtkseparatormenuitem.h"
50 #include "gtkseparatortoolitem.h"
51 #include "gtkstock.h"
52 #include "gtktoolshell.h"
53 #include "gtkbox.h"
54 #include "gtkprivate.h"
55 #include "gtkintl.h"
56 #include "gtktypebuiltins.h"
57 #include "gtkwidgetpath.h"
58 #include "gtkwidgetprivate.h"
59
60
61 /**
62  * SECTION:gtktoolbar
63  * @Short_description: Create bars of buttons and other widgets
64  * @Title: GtkToolbar
65  * @See_also: #GtkToolItem
66  *
67  * A toolbar is created with a call to gtk_toolbar_new().
68  *
69  * A toolbar can contain instances of a subclass of #GtkToolItem. To add
70  * a #GtkToolItem to the a toolbar, use gtk_toolbar_insert(). To remove
71  * an item from the toolbar use gtk_container_remove(). To add a button
72  * to the toolbar, add an instance of #GtkToolButton.
73  *
74  * Toolbar items can be visually grouped by adding instances of
75  * #GtkSeparatorToolItem to the toolbar. If the GtkToolbar child property
76  * "expand" is #TRUE and the property #GtkSeparatorToolItem:draw is set to
77  * #FALSE, the effect is to force all following items to the end of the toolbar.
78  *
79  * Creating a context menu for the toolbar can be done by connecting to
80  * the #GtkToolbar::popup-context-menu signal.
81  */
82
83
84 typedef struct _ToolbarContent ToolbarContent;
85
86 #define DEFAULT_SPACE_SIZE  12
87 #define DEFAULT_SPACE_STYLE GTK_TOOLBAR_SPACE_LINE
88 #define SPACE_LINE_DIVISION 10.0
89 #define SPACE_LINE_START    2.0
90 #define SPACE_LINE_END      8.0
91
92 #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_LARGE_TOOLBAR
93 #define DEFAULT_TOOLBAR_STYLE GTK_TOOLBAR_BOTH
94 #define DEFAULT_ANIMATION_STATE TRUE
95
96 #define MAX_HOMOGENEOUS_N_CHARS 13 /* Items that are wider than this do not participate
97                                     * in the homogeneous game. In units of
98                                     * pango_font_get_estimated_char_width().
99                                     */
100 #define SLIDE_SPEED 600.0          /* How fast the items slide, in pixels per second */
101 #define ACCEL_THRESHOLD 0.18       /* After how much time in seconds will items start speeding up */
102
103
104 struct _GtkToolbarPrivate
105 {
106   GtkMenu         *menu;
107   GtkSettings     *settings;
108
109   GtkIconSize      icon_size;
110   GtkToolbarStyle  style;
111
112   GtkToolItem     *highlight_tool_item;
113   GtkWidget       *arrow;
114   GtkWidget       *arrow_button;
115
116   GdkWindow       *event_window;
117
118   GList           *content;
119
120   GTimer          *timer;
121
122   gulong           settings_connection;
123
124   gint             idle_id;
125   gint             button_maxw;         /* maximum width of homogeneous children */
126   gint             button_maxh;         /* maximum height of homogeneous children */
127   gint             max_homogeneous_pixels;
128   gint             num_children;
129
130   GtkOrientation   orientation;
131
132   guint            animation : 1;
133   guint            icon_size_set : 1;
134   guint            is_sliding : 1;
135   guint            need_rebuild : 1;  /* whether the overflow menu should be regenerated */
136   guint            need_sync : 1;
137   guint            show_arrow : 1;
138   guint            style_set     : 1;
139 };
140
141 /* Properties */
142 enum {
143   PROP_0,
144   PROP_ORIENTATION,
145   PROP_TOOLBAR_STYLE,
146   PROP_SHOW_ARROW,
147   PROP_TOOLTIPS,
148   PROP_ICON_SIZE,
149   PROP_ICON_SIZE_SET
150 };
151
152 /* Child properties */
153 enum {
154   CHILD_PROP_0,
155   CHILD_PROP_EXPAND,
156   CHILD_PROP_HOMOGENEOUS
157 };
158
159 /* Signals */
160 enum {
161   ORIENTATION_CHANGED,
162   STYLE_CHANGED,
163   POPUP_CONTEXT_MENU,
164   FOCUS_HOME_OR_END,
165   LAST_SIGNAL
166 };
167
168 typedef enum {
169   NOT_ALLOCATED,
170   NORMAL,
171   HIDDEN,
172   OVERFLOWN
173 } ItemState;
174
175
176 static void       gtk_toolbar_set_property         (GObject             *object,
177                                                     guint                prop_id,
178                                                     const GValue        *value,
179                                                     GParamSpec          *pspec);
180 static void       gtk_toolbar_get_property         (GObject             *object,
181                                                     guint                prop_id,
182                                                     GValue              *value,
183                                                     GParamSpec          *pspec);
184 static gint       gtk_toolbar_draw                 (GtkWidget           *widget,
185                                                     cairo_t             *cr);
186 static void       gtk_toolbar_realize              (GtkWidget           *widget);
187 static void       gtk_toolbar_unrealize            (GtkWidget           *widget);
188 static void       gtk_toolbar_get_preferred_width  (GtkWidget           *widget,
189                                                     gint                *minimum,
190                                                     gint                *natural);
191 static void       gtk_toolbar_get_preferred_height (GtkWidget           *widget,
192                                                     gint                *minimum,
193                                                     gint                *natural);
194
195 static void       gtk_toolbar_size_allocate        (GtkWidget           *widget,
196                                                     GtkAllocation       *allocation);
197 static void       gtk_toolbar_style_updated        (GtkWidget           *widget);
198 static gboolean   gtk_toolbar_focus                (GtkWidget           *widget,
199                                                     GtkDirectionType     dir);
200 static void       gtk_toolbar_move_focus           (GtkWidget           *widget,
201                                                     GtkDirectionType     dir);
202 static void       gtk_toolbar_screen_changed       (GtkWidget           *widget,
203                                                     GdkScreen           *previous_screen);
204 static void       gtk_toolbar_map                  (GtkWidget           *widget);
205 static void       gtk_toolbar_unmap                (GtkWidget           *widget);
206 static void       gtk_toolbar_set_child_property   (GtkContainer        *container,
207                                                     GtkWidget           *child,
208                                                     guint                property_id,
209                                                     const GValue        *value,
210                                                     GParamSpec          *pspec);
211 static void       gtk_toolbar_get_child_property   (GtkContainer        *container,
212                                                     GtkWidget           *child,
213                                                     guint                property_id,
214                                                     GValue              *value,
215                                                     GParamSpec          *pspec);
216 static void       gtk_toolbar_finalize             (GObject             *object);
217 static void       gtk_toolbar_dispose              (GObject             *object);
218 static void       gtk_toolbar_show_all             (GtkWidget           *widget);
219 static void       gtk_toolbar_add                  (GtkContainer        *container,
220                                                     GtkWidget           *widget);
221 static void       gtk_toolbar_remove               (GtkContainer        *container,
222                                                     GtkWidget           *widget);
223 static void       gtk_toolbar_forall               (GtkContainer        *container,
224                                                     gboolean             include_internals,
225                                                     GtkCallback          callback,
226                                                     gpointer             callback_data);
227 static GType      gtk_toolbar_child_type           (GtkContainer        *container);
228 static GtkWidgetPath * gtk_toolbar_get_path_for_child
229                                                   (GtkContainer        *container,
230                                                    GtkWidget           *child);
231 static void       gtk_toolbar_invalidate_order    (GtkToolbar           *toolbar);
232
233 static void       gtk_toolbar_direction_changed    (GtkWidget           *widget,
234                                                     GtkTextDirection     previous_direction);
235 static void       gtk_toolbar_orientation_changed  (GtkToolbar          *toolbar,
236                                                     GtkOrientation       orientation);
237 static void       gtk_toolbar_real_style_changed   (GtkToolbar          *toolbar,
238                                                     GtkToolbarStyle      style);
239 static gboolean   gtk_toolbar_focus_home_or_end    (GtkToolbar          *toolbar,
240                                                     gboolean             focus_home);
241 static gboolean   gtk_toolbar_button_press         (GtkWidget           *toolbar,
242                                                     GdkEventButton      *event);
243 static gboolean   gtk_toolbar_arrow_button_press   (GtkWidget           *button,
244                                                     GdkEventButton      *event,
245                                                     GtkToolbar          *toolbar);
246 static void       gtk_toolbar_arrow_button_clicked (GtkWidget           *button,
247                                                     GtkToolbar          *toolbar);
248 static void       gtk_toolbar_update_button_relief (GtkToolbar          *toolbar);
249 static gboolean   gtk_toolbar_popup_menu           (GtkWidget           *toolbar);
250 static void       gtk_toolbar_reconfigured         (GtkToolbar          *toolbar);
251
252 static GtkReliefStyle       get_button_relief    (GtkToolbar *toolbar);
253 static gint                 get_max_child_expand (GtkToolbar *toolbar);
254 static GtkShadowType        get_shadow_type      (GtkToolbar *toolbar);
255
256 /* methods on ToolbarContent 'class' */
257 static ToolbarContent *toolbar_content_new_tool_item        (GtkToolbar          *toolbar,
258                                                              GtkToolItem         *item,
259                                                              gboolean             is_placeholder,
260                                                              gint                 pos);
261 static void            toolbar_content_remove               (ToolbarContent      *content,
262                                                              GtkToolbar          *toolbar);
263 static void            toolbar_content_free                 (ToolbarContent      *content);
264 static void            toolbar_content_draw                 (ToolbarContent      *content,
265                                                              GtkContainer        *container,
266                                                              cairo_t             *cr);
267 static gboolean        toolbar_content_visible              (ToolbarContent      *content,
268                                                              GtkToolbar          *toolbar);
269 static void            toolbar_content_size_request         (ToolbarContent      *content,
270                                                              GtkToolbar          *toolbar,
271                                                              GtkRequisition      *requisition);
272 static gboolean        toolbar_content_is_homogeneous       (ToolbarContent      *content,
273                                                              GtkToolbar          *toolbar);
274 static gboolean        toolbar_content_is_placeholder       (ToolbarContent      *content);
275 static gboolean        toolbar_content_disappearing         (ToolbarContent      *content);
276 static ItemState       toolbar_content_get_state            (ToolbarContent      *content);
277 static gboolean        toolbar_content_child_visible        (ToolbarContent      *content);
278 static void            toolbar_content_get_goal_allocation  (ToolbarContent      *content,
279                                                              GtkAllocation       *allocation);
280 static void            toolbar_content_get_allocation       (ToolbarContent      *content,
281                                                              GtkAllocation       *allocation);
282 static void            toolbar_content_set_start_allocation (ToolbarContent      *content,
283                                                              GtkAllocation       *new_start_allocation);
284 static void            toolbar_content_get_start_allocation (ToolbarContent      *content,
285                                                              GtkAllocation       *start_allocation);
286 static gboolean        toolbar_content_get_expand           (ToolbarContent      *content);
287 static void            toolbar_content_set_goal_allocation  (ToolbarContent      *content,
288                                                              GtkAllocation       *allocation);
289 static void            toolbar_content_set_child_visible    (ToolbarContent      *content,
290                                                              GtkToolbar          *toolbar,
291                                                              gboolean             visible);
292 static void            toolbar_content_size_allocate        (ToolbarContent      *content,
293                                                              GtkAllocation       *allocation);
294 static void            toolbar_content_set_state            (ToolbarContent      *content,
295                                                              ItemState            new_state);
296 static GtkWidget *     toolbar_content_get_widget           (ToolbarContent      *content);
297 static void            toolbar_content_set_disappearing     (ToolbarContent      *content,
298                                                              gboolean             disappearing);
299 static void            toolbar_content_set_size_request     (ToolbarContent      *content,
300                                                              gint                 width,
301                                                              gint                 height);
302 static void            toolbar_content_toolbar_reconfigured (ToolbarContent      *content,
303                                                              GtkToolbar          *toolbar);
304 static GtkWidget *     toolbar_content_retrieve_menu_item   (ToolbarContent      *content);
305 static gboolean        toolbar_content_has_proxy_menu_item  (ToolbarContent      *content);
306 static gboolean        toolbar_content_is_separator         (ToolbarContent      *content);
307 static void            toolbar_content_show_all             (ToolbarContent      *content);
308 static void            toolbar_content_set_expand           (ToolbarContent      *content,
309                                                              gboolean             expand);
310
311 static void            toolbar_tool_shell_iface_init        (GtkToolShellIface   *iface);
312 static GtkIconSize     toolbar_get_icon_size                (GtkToolShell        *shell);
313 static GtkOrientation  toolbar_get_orientation              (GtkToolShell        *shell);
314 static GtkToolbarStyle toolbar_get_style                    (GtkToolShell        *shell);
315 static GtkReliefStyle  toolbar_get_relief_style             (GtkToolShell        *shell);
316 static void            toolbar_rebuild_menu                 (GtkToolShell        *shell);
317
318
319 G_DEFINE_TYPE_WITH_CODE (GtkToolbar, gtk_toolbar, GTK_TYPE_CONTAINER,
320                          G_IMPLEMENT_INTERFACE (GTK_TYPE_TOOL_SHELL,
321                                                 toolbar_tool_shell_iface_init)
322                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
323                                                 NULL))
324
325 static guint toolbar_signals[LAST_SIGNAL] = { 0 };
326
327
328 static void
329 add_arrow_bindings (GtkBindingSet   *binding_set,
330                     guint            keysym,
331                     GtkDirectionType dir)
332 {
333   guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
334   
335   gtk_binding_entry_add_signal (binding_set, keysym, 0,
336                                 "move-focus", 1,
337                                 GTK_TYPE_DIRECTION_TYPE, dir);
338   gtk_binding_entry_add_signal (binding_set, keypad_keysym, 0,
339                                 "move-focus", 1,
340                                 GTK_TYPE_DIRECTION_TYPE, dir);
341 }
342
343 static void
344 add_ctrl_tab_bindings (GtkBindingSet    *binding_set,
345                        GdkModifierType   modifiers,
346                        GtkDirectionType  direction)
347 {
348   gtk_binding_entry_add_signal (binding_set,
349                                 GDK_KEY_Tab, GDK_CONTROL_MASK | modifiers,
350                                 "move-focus", 1,
351                                 GTK_TYPE_DIRECTION_TYPE, direction);
352   gtk_binding_entry_add_signal (binding_set,
353                                 GDK_KEY_KP_Tab, GDK_CONTROL_MASK | modifiers,
354                                 "move-focus", 1,
355                                 GTK_TYPE_DIRECTION_TYPE, direction);
356 }
357
358 static void
359 gtk_toolbar_class_init (GtkToolbarClass *klass)
360 {
361   GObjectClass *gobject_class;
362   GtkWidgetClass *widget_class;
363   GtkContainerClass *container_class;
364   GtkBindingSet *binding_set;
365   
366   gobject_class = (GObjectClass *)klass;
367   widget_class = (GtkWidgetClass *)klass;
368   container_class = (GtkContainerClass *)klass;
369   
370   gobject_class->set_property = gtk_toolbar_set_property;
371   gobject_class->get_property = gtk_toolbar_get_property;
372   gobject_class->finalize = gtk_toolbar_finalize;
373   gobject_class->dispose = gtk_toolbar_dispose;
374   
375   widget_class->button_press_event = gtk_toolbar_button_press;
376   widget_class->draw = gtk_toolbar_draw;
377   widget_class->get_preferred_width = gtk_toolbar_get_preferred_width;
378   widget_class->get_preferred_height = gtk_toolbar_get_preferred_height;
379   widget_class->size_allocate = gtk_toolbar_size_allocate;
380   widget_class->style_updated = gtk_toolbar_style_updated;
381   widget_class->focus = gtk_toolbar_focus;
382
383   gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_TOOL_BAR);
384
385   /* need to override the base class function via override_class_handler,
386    * because the signal slot is not available in GtkWidgetClass
387    */
388   g_signal_override_class_handler ("move-focus",
389                                    GTK_TYPE_TOOLBAR,
390                                    G_CALLBACK (gtk_toolbar_move_focus));
391
392   widget_class->screen_changed = gtk_toolbar_screen_changed;
393   widget_class->realize = gtk_toolbar_realize;
394   widget_class->unrealize = gtk_toolbar_unrealize;
395   widget_class->map = gtk_toolbar_map;
396   widget_class->unmap = gtk_toolbar_unmap;
397   widget_class->popup_menu = gtk_toolbar_popup_menu;
398   widget_class->show_all = gtk_toolbar_show_all;
399   widget_class->direction_changed = gtk_toolbar_direction_changed;
400   
401   container_class->add    = gtk_toolbar_add;
402   container_class->remove = gtk_toolbar_remove;
403   container_class->forall = gtk_toolbar_forall;
404   container_class->child_type = gtk_toolbar_child_type;
405   container_class->get_child_property = gtk_toolbar_get_child_property;
406   container_class->set_child_property = gtk_toolbar_set_child_property;
407   container_class->get_path_for_child = gtk_toolbar_get_path_for_child;
408
409   klass->orientation_changed = gtk_toolbar_orientation_changed;
410   klass->style_changed = gtk_toolbar_real_style_changed;
411   
412   /**
413    * GtkToolbar::orientation-changed:
414    * @toolbar: the object which emitted the signal
415    * @orientation: the new #GtkOrientation of the toolbar
416    *
417    * Emitted when the orientation of the toolbar changes.
418    */
419   toolbar_signals[ORIENTATION_CHANGED] =
420     g_signal_new (I_("orientation-changed"),
421                   G_OBJECT_CLASS_TYPE (klass),
422                   G_SIGNAL_RUN_FIRST,
423                   G_STRUCT_OFFSET (GtkToolbarClass, orientation_changed),
424                   NULL, NULL,
425                   g_cclosure_marshal_VOID__ENUM,
426                   G_TYPE_NONE, 1,
427                   GTK_TYPE_ORIENTATION);
428   /**
429    * GtkToolbar::style-changed:
430    * @toolbar: The #GtkToolbar which emitted the signal
431    * @style: the new #GtkToolbarStyle of the toolbar
432    *
433    * Emitted when the style of the toolbar changes. 
434    */
435   toolbar_signals[STYLE_CHANGED] =
436     g_signal_new (I_("style-changed"),
437                   G_OBJECT_CLASS_TYPE (klass),
438                   G_SIGNAL_RUN_FIRST,
439                   G_STRUCT_OFFSET (GtkToolbarClass, style_changed),
440                   NULL, NULL,
441                   g_cclosure_marshal_VOID__ENUM,
442                   G_TYPE_NONE, 1,
443                   GTK_TYPE_TOOLBAR_STYLE);
444   /**
445    * GtkToolbar::popup-context-menu:
446    * @toolbar: the #GtkToolbar which emitted the signal
447    * @x: the x coordinate of the point where the menu should appear
448    * @y: the y coordinate of the point where the menu should appear
449    * @button: the mouse button the user pressed, or -1
450    *
451    * Emitted when the user right-clicks the toolbar or uses the
452    * keybinding to display a popup menu.
453    *
454    * Application developers should handle this signal if they want
455    * to display a context menu on the toolbar. The context-menu should
456    * appear at the coordinates given by @x and @y. The mouse button
457    * number is given by the @button parameter. If the menu was popped
458    * up using the keybaord, @button is -1.
459    *
460    * Return value: return %TRUE if the signal was handled, %FALSE if not
461    */
462   toolbar_signals[POPUP_CONTEXT_MENU] =
463     g_signal_new (I_("popup-context-menu"),
464                   G_OBJECT_CLASS_TYPE (klass),
465                   G_SIGNAL_RUN_LAST,
466                   G_STRUCT_OFFSET (GtkToolbarClass, popup_context_menu),
467                   _gtk_boolean_handled_accumulator, NULL,
468                   _gtk_marshal_BOOLEAN__INT_INT_INT,
469                   G_TYPE_BOOLEAN, 3,
470                   G_TYPE_INT, G_TYPE_INT,
471                   G_TYPE_INT);
472
473   /**
474    * GtkToolbar::focus-home-or-end:
475    * @toolbar: the #GtkToolbar which emitted the signal
476    * @focus_home: %TRUE if the first item should be focused
477    *
478    * A keybinding signal used internally by GTK+. This signal can't
479    * be used in application code
480    *
481    * Return value: %TRUE if the signal was handled, %FALSE if not
482    */
483   toolbar_signals[FOCUS_HOME_OR_END] =
484     g_signal_new_class_handler (I_("focus-home-or-end"),
485                                 G_OBJECT_CLASS_TYPE (klass),
486                                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
487                                 G_CALLBACK (gtk_toolbar_focus_home_or_end),
488                                 NULL, NULL,
489                                 _gtk_marshal_BOOLEAN__BOOLEAN,
490                                 G_TYPE_BOOLEAN, 1,
491                                 G_TYPE_BOOLEAN);
492
493   /* properties */
494   g_object_class_override_property (gobject_class,
495                                     PROP_ORIENTATION,
496                                     "orientation");
497
498   g_object_class_install_property (gobject_class,
499                                    PROP_TOOLBAR_STYLE,
500                                    g_param_spec_enum ("toolbar-style",
501                                                       P_("Toolbar Style"),
502                                                       P_("How to draw the toolbar"),
503                                                       GTK_TYPE_TOOLBAR_STYLE,
504                                                       DEFAULT_TOOLBAR_STYLE,
505                                                       GTK_PARAM_READWRITE));
506   g_object_class_install_property (gobject_class,
507                                    PROP_SHOW_ARROW,
508                                    g_param_spec_boolean ("show-arrow",
509                                                          P_("Show Arrow"),
510                                                          P_("If an arrow should be shown if the toolbar doesn't fit"),
511                                                          TRUE,
512                                                          GTK_PARAM_READWRITE));
513
514   /**
515    * GtkToolbar:icon-size:
516    *
517    * The size of the icons in a toolbar is normally determined by
518    * the toolbar-icon-size setting. When this property is set, it 
519    * overrides the setting. 
520    * 
521    * This should only be used for special-purpose toolbars, normal
522    * application toolbars should respect the user preferences for the
523    * size of icons.
524    *
525    * Since: 2.10
526    */
527   g_object_class_install_property (gobject_class,
528                                    PROP_ICON_SIZE,
529                                    g_param_spec_int ("icon-size",
530                                                      P_("Icon size"),
531                                                      P_("Size of icons in this toolbar"),
532                                                      0, G_MAXINT,
533                                                      DEFAULT_ICON_SIZE,
534                                                      GTK_PARAM_READWRITE));  
535
536   /**
537    * GtkToolbar:icon-size-set:
538    *
539    * Is %TRUE if the icon-size property has been set.
540    *
541    * Since: 2.10
542    */
543   g_object_class_install_property (gobject_class,
544                                    PROP_ICON_SIZE_SET,
545                                    g_param_spec_boolean ("icon-size-set",
546                                                          P_("Icon size set"),
547                                                          P_("Whether the icon-size property has been set"),
548                                                          FALSE,
549                                                          GTK_PARAM_READWRITE));  
550
551   /* child properties */
552   gtk_container_class_install_child_property (container_class,
553                                               CHILD_PROP_EXPAND,
554                                               g_param_spec_boolean ("expand", 
555                                                                     P_("Expand"), 
556                                                                     P_("Whether the item should receive extra space when the toolbar grows"),
557                                                                     FALSE,
558                                                                     GTK_PARAM_READWRITE));
559   
560   gtk_container_class_install_child_property (container_class,
561                                               CHILD_PROP_HOMOGENEOUS,
562                                               g_param_spec_boolean ("homogeneous", 
563                                                                     P_("Homogeneous"), 
564                                                                     P_("Whether the item should be the same size as other homogeneous items"),
565                                                                     FALSE,
566                                                                     GTK_PARAM_READWRITE));
567   
568   /* style properties */
569   gtk_widget_class_install_style_property (widget_class,
570                                            g_param_spec_int ("space-size",
571                                                              P_("Spacer size"),
572                                                              P_("Size of spacers"),
573                                                              0,
574                                                              G_MAXINT,
575                                                              DEFAULT_SPACE_SIZE,
576                                                              GTK_PARAM_READABLE));
577   
578   /**
579    * GtkToolbar:internal-padding:
580    *
581    * Amount of border space between the toolbar shadow and the buttons.
582    *
583    * Deprecated: 3.6: Use the standard padding CSS property
584    *   (through objects like #GtkStyleContext and #GtkCssProvider); the value
585    *   of this style property is ignored.
586    */
587   gtk_widget_class_install_style_property (widget_class,
588                                            g_param_spec_int ("internal-padding",
589                                                              P_("Internal padding"),
590                                                              P_("Amount of border space between the toolbar shadow and the buttons"),
591                                                              0,
592                                                              G_MAXINT,
593                                                              0,
594                                                              GTK_PARAM_READABLE));
595
596   gtk_widget_class_install_style_property (widget_class,
597                                            g_param_spec_int ("max-child-expand",
598                                                              P_("Maximum child expand"),
599                                                              P_("Maximum amount of space an expandable item will be given"),
600                                                              0,
601                                                              G_MAXINT,
602                                                              G_MAXINT,
603                                                              GTK_PARAM_READABLE));
604
605   gtk_widget_class_install_style_property (widget_class,
606                                            g_param_spec_enum ("space-style",
607                                                               P_("Space style"),
608                                                               P_("Whether spacers are vertical lines or just blank"),
609                                                               GTK_TYPE_TOOLBAR_SPACE_STYLE,
610                                                               DEFAULT_SPACE_STYLE,
611                                                               GTK_PARAM_READABLE));
612   
613   gtk_widget_class_install_style_property (widget_class,
614                                            g_param_spec_enum ("button-relief",
615                                                               P_("Button relief"),
616                                                               P_("Type of bevel around toolbar buttons"),
617                                                               GTK_TYPE_RELIEF_STYLE,
618                                                               GTK_RELIEF_NONE,
619                                                               GTK_PARAM_READABLE));
620   gtk_widget_class_install_style_property (widget_class,
621                                            g_param_spec_enum ("shadow-type",
622                                                               P_("Shadow type"),
623                                                               P_("Style of bevel around the toolbar"),
624                                                               GTK_TYPE_SHADOW_TYPE,
625                                                               GTK_SHADOW_OUT,
626                                                               GTK_PARAM_READABLE));
627
628   binding_set = gtk_binding_set_by_class (klass);
629   
630   add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
631   add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);
632   add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
633   add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
634   
635   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Home, 0,
636                                 "focus-home-or-end", 1,
637                                 G_TYPE_BOOLEAN, TRUE);
638   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Home, 0,
639                                 "focus-home-or-end", 1,
640                                 G_TYPE_BOOLEAN, TRUE);
641   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_End, 0,
642                                 "focus-home-or-end", 1,
643                                 G_TYPE_BOOLEAN, FALSE);
644   gtk_binding_entry_add_signal (binding_set, GDK_KEY_End, 0,
645                                 "focus-home-or-end", 1,
646                                 G_TYPE_BOOLEAN, FALSE);
647   
648   add_ctrl_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
649   add_ctrl_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
650
651   g_type_class_add_private (gobject_class, sizeof (GtkToolbarPrivate));
652 }
653
654 static void
655 toolbar_tool_shell_iface_init (GtkToolShellIface *iface)
656 {
657   iface->get_icon_size    = toolbar_get_icon_size;
658   iface->get_orientation  = toolbar_get_orientation;
659   iface->get_style        = toolbar_get_style;
660   iface->get_relief_style = toolbar_get_relief_style;
661   iface->rebuild_menu     = toolbar_rebuild_menu;
662 }
663
664 static void
665 gtk_toolbar_init (GtkToolbar *toolbar)
666 {
667   GtkToolbarPrivate *priv;
668   GtkStyleContext *context;
669
670   toolbar->priv = G_TYPE_INSTANCE_GET_PRIVATE (toolbar,
671                                                GTK_TYPE_TOOLBAR,
672                                                GtkToolbarPrivate);
673   priv = toolbar->priv;
674
675   gtk_widget_set_can_focus (GTK_WIDGET (toolbar), FALSE);
676   gtk_widget_set_has_window (GTK_WIDGET (toolbar), FALSE);
677
678   priv->orientation = GTK_ORIENTATION_HORIZONTAL;
679   priv->style = DEFAULT_TOOLBAR_STYLE;
680   priv->icon_size = DEFAULT_ICON_SIZE;
681   priv->animation = DEFAULT_ANIMATION_STATE;
682
683   priv->arrow_button = gtk_toggle_button_new ();
684   g_signal_connect (priv->arrow_button, "button-press-event",
685                     G_CALLBACK (gtk_toolbar_arrow_button_press), toolbar);
686   g_signal_connect (priv->arrow_button, "clicked",
687                     G_CALLBACK (gtk_toolbar_arrow_button_clicked), toolbar);
688   gtk_button_set_relief (GTK_BUTTON (priv->arrow_button),
689                          get_button_relief (toolbar));
690
691   gtk_button_set_focus_on_click (GTK_BUTTON (priv->arrow_button), FALSE);
692
693   priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
694   gtk_widget_set_name (priv->arrow, "gtk-toolbar-arrow");
695   gtk_widget_show (priv->arrow);
696   gtk_container_add (GTK_CONTAINER (priv->arrow_button), priv->arrow);
697   
698   gtk_widget_set_parent (priv->arrow_button, GTK_WIDGET (toolbar));
699   
700   /* which child position a drop will occur at */
701   priv->menu = NULL;
702   priv->show_arrow = TRUE;
703   priv->settings = NULL;
704   
705   priv->max_homogeneous_pixels = -1;
706   
707   priv->timer = g_timer_new ();
708
709   context = gtk_widget_get_style_context (GTK_WIDGET (toolbar));
710   gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOOLBAR);
711 }
712
713 static void
714 gtk_toolbar_set_property (GObject      *object,
715                           guint         prop_id,
716                           const GValue *value,
717                           GParamSpec   *pspec)
718 {
719   GtkToolbar *toolbar = GTK_TOOLBAR (object);
720   GtkToolbarPrivate *priv = toolbar->priv;
721
722   switch (prop_id)
723     {
724     case PROP_ORIENTATION:
725       g_signal_emit (toolbar, toolbar_signals[ORIENTATION_CHANGED], 0,
726                      g_value_get_enum (value));
727       break;
728     case PROP_TOOLBAR_STYLE:
729       gtk_toolbar_set_style (toolbar, g_value_get_enum (value));
730       break;
731     case PROP_SHOW_ARROW:
732       gtk_toolbar_set_show_arrow (toolbar, g_value_get_boolean (value));
733       break;
734     case PROP_ICON_SIZE:
735       gtk_toolbar_set_icon_size (toolbar, g_value_get_int (value));
736       break;
737     case PROP_ICON_SIZE_SET:
738       if (g_value_get_boolean (value))
739         priv->icon_size_set = TRUE;
740       else
741         gtk_toolbar_unset_icon_size (toolbar);
742       break;
743     default:
744       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
745       break;
746     }
747 }
748
749 static void
750 gtk_toolbar_get_property (GObject    *object,
751                           guint       prop_id,
752                           GValue     *value,
753                           GParamSpec *pspec)
754 {
755   GtkToolbar *toolbar = GTK_TOOLBAR (object);
756   GtkToolbarPrivate *priv = toolbar->priv;
757
758   switch (prop_id)
759     {
760     case PROP_ORIENTATION:
761       g_value_set_enum (value, priv->orientation);
762       break;
763     case PROP_TOOLBAR_STYLE:
764       g_value_set_enum (value, priv->style);
765       break;
766     case PROP_SHOW_ARROW:
767       g_value_set_boolean (value, priv->show_arrow);
768       break;
769     case PROP_ICON_SIZE:
770       g_value_set_int (value, gtk_toolbar_get_icon_size (toolbar));
771       break;
772     case PROP_ICON_SIZE_SET:
773       g_value_set_boolean (value, priv->icon_size_set);
774       break;
775     default:
776       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
777       break;
778     }
779 }
780
781 static void
782 gtk_toolbar_map (GtkWidget *widget)
783 {
784   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
785   GtkToolbarPrivate *priv = toolbar->priv;
786
787   GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->map (widget);
788
789   if (priv->event_window)
790     gdk_window_show_unraised (priv->event_window);
791 }
792
793 static void
794 gtk_toolbar_unmap (GtkWidget *widget)
795 {
796   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
797   GtkToolbarPrivate *priv = toolbar->priv;
798
799   if (priv->event_window)
800     gdk_window_hide (priv->event_window);
801   
802   GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->unmap (widget);
803 }
804
805 static void
806 gtk_toolbar_realize (GtkWidget *widget)
807 {
808   GtkAllocation allocation;
809   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
810   GtkToolbarPrivate *priv = toolbar->priv;
811   GdkWindow *window;
812   GdkWindowAttr attributes;
813   gint attributes_mask;
814   guint border_width;
815
816   gtk_widget_set_realized (widget, TRUE);
817
818   gtk_widget_get_allocation (widget, &allocation);
819   border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
820
821   attributes.wclass = GDK_INPUT_ONLY;
822   attributes.window_type = GDK_WINDOW_CHILD;
823   attributes.x = allocation.x + border_width;
824   attributes.y = allocation.y + border_width;
825   attributes.width = allocation.width - border_width * 2;
826   attributes.height = allocation.height - border_width * 2;
827   attributes.event_mask = gtk_widget_get_events (widget);
828   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
829                             GDK_BUTTON_RELEASE_MASK |
830                             GDK_ENTER_NOTIFY_MASK |
831                             GDK_LEAVE_NOTIFY_MASK);
832
833   attributes_mask = GDK_WA_X | GDK_WA_Y;
834
835   window = gtk_widget_get_parent_window (widget);
836   gtk_widget_set_window (widget, window);
837   g_object_ref (window);
838
839   priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
840                                        &attributes, attributes_mask);
841   gdk_window_set_user_data (priv->event_window, toolbar);
842 }
843
844 static void
845 gtk_toolbar_unrealize (GtkWidget *widget)
846 {
847   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
848   GtkToolbarPrivate *priv = toolbar->priv;
849
850   if (priv->event_window)
851     {
852       gdk_window_set_user_data (priv->event_window, NULL);
853       gdk_window_destroy (priv->event_window);
854       priv->event_window = NULL;
855     }
856
857   GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->unrealize (widget);
858 }
859
860 static gint
861 gtk_toolbar_draw (GtkWidget *widget,
862                   cairo_t   *cr)
863 {
864   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
865   GtkToolbarPrivate *priv = toolbar->priv;
866   GtkStyleContext *context;
867   GList *list;
868   guint border_width;
869
870   border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
871   context = gtk_widget_get_style_context (widget);
872
873   gtk_render_background (context, cr, border_width, border_width,
874                          gtk_widget_get_allocated_width (widget) - 2 * border_width,
875                          gtk_widget_get_allocated_height (widget) - 2 * border_width);
876   gtk_render_frame (context, cr, border_width, border_width,
877                     gtk_widget_get_allocated_width (widget) - 2 * border_width,
878                     gtk_widget_get_allocated_height (widget) - 2 * border_width);
879
880   for (list = priv->content; list != NULL; list = list->next)
881     {
882       ToolbarContent *content = list->data;
883       
884       toolbar_content_draw (content, GTK_CONTAINER (widget), cr);
885     }
886   
887   gtk_container_propagate_draw (GTK_CONTAINER (widget),
888                                 priv->arrow_button,
889                                 cr);
890
891   return FALSE;
892 }
893
894 static void
895 get_widget_padding_and_border (GtkWidget *widget,
896                                GtkBorder *padding)
897 {
898   GtkStyleContext *context;
899   GtkStateFlags state;
900   GtkBorder tmp;
901
902   context = gtk_widget_get_style_context (widget);
903   state = gtk_style_context_get_state (context);
904
905   gtk_style_context_get_padding (context, state, padding);
906   gtk_style_context_get_border (context, state, &tmp);
907
908   padding->top += tmp.top;
909   padding->right += tmp.right;
910   padding->bottom += tmp.bottom;
911   padding->left += tmp.left;
912 }
913
914 static void
915 gtk_toolbar_size_request (GtkWidget      *widget,
916                           GtkRequisition *requisition)
917 {
918   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
919   GtkToolbarPrivate *priv = toolbar->priv;
920   GList *list;
921   gint max_child_height;
922   gint max_child_width;
923   gint max_homogeneous_child_width;
924   gint max_homogeneous_child_height;
925   gint homogeneous_size;
926   gint long_req;
927   gint pack_front_size;
928   GtkBorder padding;
929   guint border_width;
930   GtkRequisition arrow_requisition;
931   
932   max_homogeneous_child_width = 0;
933   max_homogeneous_child_height = 0;
934   max_child_width = 0;
935   max_child_height = 0;
936   for (list = priv->content; list != NULL; list = list->next)
937     {
938       GtkRequisition requisition;
939       ToolbarContent *content = list->data;
940       
941       if (!toolbar_content_visible (content, toolbar))
942         continue;
943       
944       toolbar_content_size_request (content, toolbar, &requisition);
945
946       max_child_width = MAX (max_child_width, requisition.width);
947       max_child_height = MAX (max_child_height, requisition.height);
948       
949       if (toolbar_content_is_homogeneous (content, toolbar))
950         {
951           max_homogeneous_child_width = MAX (max_homogeneous_child_width, requisition.width);
952           max_homogeneous_child_height = MAX (max_homogeneous_child_height, requisition.height);
953         }
954     }
955   
956   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
957     homogeneous_size = max_homogeneous_child_width;
958   else
959     homogeneous_size = max_homogeneous_child_height;
960   
961   pack_front_size = 0;
962   for (list = priv->content; list != NULL; list = list->next)
963     {
964       ToolbarContent *content = list->data;
965       guint size;
966       
967       if (!toolbar_content_visible (content, toolbar))
968         continue;
969
970       if (toolbar_content_is_homogeneous (content, toolbar))
971         {
972           size = homogeneous_size;
973         }
974       else
975         {
976           GtkRequisition requisition;
977           
978           toolbar_content_size_request (content, toolbar, &requisition);
979           
980           if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
981             size = requisition.width;
982           else
983             size = requisition.height;
984         }
985
986       pack_front_size += size;
987     }
988   
989   if (priv->show_arrow)
990     {
991       gtk_widget_get_preferred_size (priv->arrow_button,
992                                      &arrow_requisition, NULL);
993
994       if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
995         long_req = arrow_requisition.width;
996       else
997         long_req = arrow_requisition.height;
998       
999       /* There is no point requesting space for the arrow if that would take
1000        * up more space than all the items combined
1001        */
1002       long_req = MIN (long_req, pack_front_size);
1003     }
1004   else
1005     {
1006       arrow_requisition.height = 0;
1007       arrow_requisition.width = 0;
1008       
1009       long_req = pack_front_size;
1010     }
1011   
1012   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1013     {
1014       requisition->width = long_req;
1015       requisition->height = MAX (max_child_height, arrow_requisition.height);
1016     }
1017   else
1018     {
1019       requisition->height = long_req;
1020       requisition->width = MAX (max_child_width, arrow_requisition.width);
1021     }
1022
1023   /* Extra spacing */
1024   border_width = gtk_container_get_border_width (GTK_CONTAINER (toolbar));
1025
1026   requisition->width += 2 * border_width;
1027   requisition->height += 2 * border_width;
1028
1029   if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1030     {
1031       get_widget_padding_and_border (widget, &padding);
1032
1033       requisition->width += padding.left + padding.right;
1034       requisition->height += padding.top + padding.bottom;
1035     }
1036   
1037   priv->button_maxw = max_homogeneous_child_width;
1038   priv->button_maxh = max_homogeneous_child_height;
1039 }
1040
1041 static void
1042 gtk_toolbar_get_preferred_width (GtkWidget *widget,
1043                                  gint      *minimum,
1044                                  gint      *natural)
1045 {
1046   GtkRequisition requisition;
1047
1048   gtk_toolbar_size_request (widget, &requisition);
1049
1050   *minimum = *natural = requisition.width;
1051 }
1052
1053 static void
1054 gtk_toolbar_get_preferred_height (GtkWidget *widget,
1055                                   gint      *minimum,
1056                                   gint      *natural)
1057 {
1058   GtkRequisition requisition;
1059
1060   gtk_toolbar_size_request (widget, &requisition);
1061
1062   *minimum = *natural = requisition.height;
1063 }
1064
1065 static gint
1066 position (GtkToolbar *toolbar,
1067           gint        from,
1068           gint        to,
1069           gdouble     elapsed)
1070 {
1071   GtkToolbarPrivate *priv = toolbar->priv;
1072   gint n_pixels;
1073
1074   if (!priv->animation)
1075     return to;
1076
1077   if (elapsed <= ACCEL_THRESHOLD)
1078     {
1079       n_pixels = SLIDE_SPEED * elapsed;
1080     }
1081   else
1082     {
1083       /* The formula is a second degree polynomial in
1084        * @elapsed that has the line SLIDE_SPEED * @elapsed
1085        * as tangent for @elapsed == ACCEL_THRESHOLD.
1086        * This makes @n_pixels a smooth function of elapsed time.
1087        */
1088       n_pixels = (SLIDE_SPEED / ACCEL_THRESHOLD) * elapsed * elapsed -
1089         SLIDE_SPEED * elapsed + SLIDE_SPEED * ACCEL_THRESHOLD;
1090     }
1091
1092   if (to > from)
1093     return MIN (from + n_pixels, to);
1094   else
1095     return MAX (from - n_pixels, to);
1096 }
1097
1098 static void
1099 compute_intermediate_allocation (GtkToolbar          *toolbar,
1100                                  const GtkAllocation *start,
1101                                  const GtkAllocation *goal,
1102                                  GtkAllocation       *intermediate)
1103 {
1104   GtkToolbarPrivate *priv = toolbar->priv;
1105   gdouble elapsed = g_timer_elapsed (priv->timer, NULL);
1106
1107   intermediate->x      = position (toolbar, start->x, goal->x, elapsed);
1108   intermediate->y      = position (toolbar, start->y, goal->y, elapsed);
1109   intermediate->width  = position (toolbar, start->x + start->width,
1110                                    goal->x + goal->width,
1111                                    elapsed) - intermediate->x;
1112   intermediate->height = position (toolbar, start->y + start->height,
1113                                    goal->y + goal->height,
1114                                    elapsed) - intermediate->y;
1115 }
1116
1117 static void
1118 fixup_allocation_for_rtl (gint           total_size,
1119                           GtkAllocation *allocation)
1120 {
1121   allocation->x += (total_size - (2 * allocation->x + allocation->width));
1122 }
1123
1124 static void
1125 fixup_allocation_for_vertical (GtkAllocation *allocation)
1126 {
1127   gint tmp;
1128   
1129   tmp = allocation->x;
1130   allocation->x = allocation->y;
1131   allocation->y = tmp;
1132   
1133   tmp = allocation->width;
1134   allocation->width = allocation->height;
1135   allocation->height = tmp;
1136 }
1137
1138 static gint
1139 get_item_size (GtkToolbar     *toolbar,
1140                ToolbarContent *content)
1141 {
1142   GtkToolbarPrivate *priv = toolbar->priv;
1143   GtkRequisition requisition;
1144   
1145   toolbar_content_size_request (content, toolbar, &requisition);
1146
1147   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1148     {
1149       if (toolbar_content_is_homogeneous (content, toolbar))
1150         return priv->button_maxw;
1151       else
1152         return requisition.width;
1153     }
1154   else
1155     {
1156       if (toolbar_content_is_homogeneous (content, toolbar))
1157         return priv->button_maxh;
1158       else
1159         return requisition.height;
1160     }
1161 }
1162
1163 static gboolean
1164 slide_idle_handler (gpointer data)
1165 {
1166   GtkToolbar *toolbar = GTK_TOOLBAR (data);
1167   GtkToolbarPrivate *priv = toolbar->priv;
1168   GList *list;
1169
1170   if (priv->need_sync)
1171     {
1172       gdk_flush ();
1173       priv->need_sync = FALSE;
1174     }
1175   
1176   for (list = priv->content; list != NULL; list = list->next)
1177     {
1178       ToolbarContent *content = list->data;
1179       ItemState state;
1180       GtkAllocation goal_allocation;
1181       GtkAllocation allocation;
1182       gboolean cont;
1183
1184       state = toolbar_content_get_state (content);
1185       toolbar_content_get_goal_allocation (content, &goal_allocation);
1186       toolbar_content_get_allocation (content, &allocation);
1187       
1188       cont = FALSE;
1189       
1190       if (state == NOT_ALLOCATED)
1191         {
1192           /* an unallocated item means that size allocate has to
1193            * called at least once more
1194            */
1195           cont = TRUE;
1196         }
1197
1198       /* An invisible item with a goal allocation of
1199        * 0 is already at its goal.
1200        */
1201       if ((state == NORMAL || state == OVERFLOWN) &&
1202           ((goal_allocation.width != 0 &&
1203             goal_allocation.height != 0) ||
1204            toolbar_content_child_visible (content)))
1205         {
1206           if ((goal_allocation.x != allocation.x ||
1207                goal_allocation.y != allocation.y ||
1208                goal_allocation.width != allocation.width ||
1209                goal_allocation.height != allocation.height))
1210             {
1211               /* An item is not in its right position yet. Note
1212                * that OVERFLOWN items do get an allocation in
1213                * gtk_toolbar_size_allocate(). This way you can see
1214                * them slide back in when you drag an item off the
1215                * toolbar.
1216                */
1217               cont = TRUE;
1218             }
1219         }
1220
1221       if (toolbar_content_is_placeholder (content) &&
1222           toolbar_content_disappearing (content) &&
1223           toolbar_content_child_visible (content))
1224         {
1225           /* A disappearing placeholder is still visible.
1226            */
1227              
1228           cont = TRUE;
1229         }
1230       
1231       if (cont)
1232         {
1233           gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1234           
1235           return TRUE;
1236         }
1237     }
1238   
1239   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1240
1241   priv->is_sliding = FALSE;
1242   priv->idle_id = 0;
1243
1244   return FALSE;
1245 }
1246
1247 static gboolean
1248 rect_within (GtkAllocation *a1,
1249              GtkAllocation *a2)
1250 {
1251   return (a1->x >= a2->x                         &&
1252           a1->x + a1->width <= a2->x + a2->width &&
1253           a1->y >= a2->y                         &&
1254           a1->y + a1->height <= a2->y + a2->height);
1255 }
1256
1257 static void
1258 gtk_toolbar_begin_sliding (GtkToolbar *toolbar)
1259 {
1260   GtkAllocation allocation;
1261   GtkWidget *widget = GTK_WIDGET (toolbar);
1262   GtkToolbarPrivate *priv = toolbar->priv;
1263   GList *list;
1264   gint cur_x;
1265   gint cur_y;
1266   gint border_width;
1267   GtkBorder padding;
1268   gboolean rtl;
1269   gboolean vertical;
1270   
1271   /* Start the sliding. This function copies the allocation of every
1272    * item into content->start_allocation. For items that haven't
1273    * been allocated yet, we calculate their position and save that
1274    * in start_allocatino along with zero width and zero height.
1275    *
1276    * FIXME: It would be nice if we could share this code with
1277    * the equivalent in gtk_widget_size_allocate().
1278    */
1279   priv->is_sliding = TRUE;
1280   
1281   if (!priv->idle_id)
1282     priv->idle_id = gdk_threads_add_idle (slide_idle_handler, toolbar);
1283
1284   gtk_widget_get_allocation (widget, &allocation);
1285
1286   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1287   vertical = (priv->orientation == GTK_ORIENTATION_VERTICAL);
1288
1289   border_width = gtk_container_get_border_width (GTK_CONTAINER (toolbar));
1290   get_widget_padding_and_border (GTK_WIDGET (toolbar), &padding);
1291
1292   if (rtl)
1293     {
1294       cur_x = allocation.width - border_width - padding.right;
1295       cur_y = allocation.height - border_width - padding.top;
1296     }
1297   else
1298     {
1299       cur_x = border_width + padding.left;
1300       cur_y = border_width + padding.top;
1301     }
1302
1303   cur_x += allocation.x;
1304   cur_y += allocation.y;
1305
1306   for (list = priv->content; list != NULL; list = list->next)
1307     {
1308       ToolbarContent *content = list->data;
1309       GtkAllocation new_start_allocation;
1310       GtkAllocation item_allocation;
1311       ItemState state;
1312       
1313       state = toolbar_content_get_state (content);
1314       toolbar_content_get_allocation (content, &item_allocation);
1315       
1316       if ((state == NORMAL &&
1317            rect_within (&item_allocation, &allocation)) ||
1318           state == OVERFLOWN)
1319         {
1320           new_start_allocation = item_allocation;
1321         }
1322       else
1323         {
1324           new_start_allocation.x = cur_x;
1325           new_start_allocation.y = cur_y;
1326           
1327           if (vertical)
1328             {
1329               new_start_allocation.width = allocation.width -
1330                                            2 * border_width -
1331                                            padding.left - padding.right;
1332               new_start_allocation.height = 0;
1333             }
1334           else
1335             {
1336               new_start_allocation.width = 0;
1337               new_start_allocation.height = allocation.height -
1338                                             2 * border_width -
1339                                             padding.top - padding.bottom;
1340             }
1341         }
1342       
1343       if (vertical)
1344         cur_y = new_start_allocation.y + new_start_allocation.height;
1345       else if (rtl)
1346         cur_x = new_start_allocation.x;
1347       else
1348         cur_x = new_start_allocation.x + new_start_allocation.width;
1349       
1350       toolbar_content_set_start_allocation (content, &new_start_allocation);
1351     }
1352
1353   /* This resize will run before the first idle handler. This
1354    * will make sure that items get the right goal allocation
1355    * so that the idle handler will not immediately return
1356    * FALSE
1357    */
1358   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1359   g_timer_reset (priv->timer);
1360 }
1361
1362 static void
1363 gtk_toolbar_stop_sliding (GtkToolbar *toolbar)
1364 {
1365   GtkToolbarPrivate *priv = toolbar->priv;
1366
1367   if (priv->is_sliding)
1368     {
1369       GList *list;
1370       
1371       priv->is_sliding = FALSE;
1372       
1373       if (priv->idle_id)
1374         {
1375           g_source_remove (priv->idle_id);
1376           priv->idle_id = 0;
1377         }
1378       
1379       list = priv->content;
1380       while (list)
1381         {
1382           ToolbarContent *content = list->data;
1383           list = list->next;
1384
1385           if (toolbar_content_is_placeholder (content))
1386             {
1387               toolbar_content_remove (content, toolbar);
1388               toolbar_content_free (content);
1389             }
1390         }
1391       
1392       gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1393     }
1394 }
1395
1396 static void
1397 remove_item (GtkWidget *menu_item,
1398              gpointer   data)
1399 {
1400   gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (menu_item)),
1401                         menu_item);
1402 }
1403
1404 static void
1405 menu_deactivated (GtkWidget  *menu,
1406                   GtkToolbar *toolbar)
1407 {
1408   GtkToolbarPrivate *priv = toolbar->priv;
1409
1410   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->arrow_button), FALSE);
1411 }
1412
1413 static void
1414 menu_detached (GtkWidget  *widget,
1415                GtkMenu    *menu)
1416 {
1417   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1418   GtkToolbarPrivate *priv = toolbar->priv;
1419
1420   priv->menu = NULL;
1421 }
1422
1423 static void
1424 rebuild_menu (GtkToolbar *toolbar)
1425 {
1426   GtkToolbarPrivate *priv = toolbar->priv;
1427   GList *list, *children;
1428
1429   if (!priv->menu)
1430     {
1431       priv->menu = GTK_MENU (gtk_menu_new());
1432       gtk_menu_attach_to_widget (priv->menu,
1433                                  GTK_WIDGET (toolbar),
1434                                  menu_detached);
1435
1436       g_signal_connect (priv->menu, "deactivate",
1437                         G_CALLBACK (menu_deactivated), toolbar);
1438     }
1439
1440   gtk_container_foreach (GTK_CONTAINER (priv->menu), remove_item, NULL);
1441   
1442   for (list = priv->content; list != NULL; list = list->next)
1443     {
1444       ToolbarContent *content = list->data;
1445       
1446       if (toolbar_content_get_state (content) == OVERFLOWN &&
1447           !toolbar_content_is_placeholder (content))
1448         {
1449           GtkWidget *menu_item = toolbar_content_retrieve_menu_item (content);
1450           
1451           if (menu_item)
1452             {
1453               g_assert (GTK_IS_MENU_ITEM (menu_item));
1454               gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menu_item);
1455             }
1456         }
1457     }
1458
1459   /* Remove leading and trailing separator items */
1460   children = gtk_container_get_children (GTK_CONTAINER (priv->menu));
1461   
1462   list = children;
1463   while (list && GTK_IS_SEPARATOR_MENU_ITEM (list->data))
1464     {
1465       GtkWidget *child = list->data;
1466       
1467       gtk_container_remove (GTK_CONTAINER (priv->menu), child);
1468       list = list->next;
1469     }
1470   g_list_free (children);
1471
1472   /* Regenerate the list of children so we don't try to remove items twice */
1473   children = gtk_container_get_children (GTK_CONTAINER (priv->menu));
1474
1475   list = g_list_last (children);
1476   while (list && GTK_IS_SEPARATOR_MENU_ITEM (list->data))
1477     {
1478       GtkWidget *child = list->data;
1479
1480       gtk_container_remove (GTK_CONTAINER (priv->menu), child);
1481       list = list->prev;
1482     }
1483   g_list_free (children);
1484
1485   priv->need_rebuild = FALSE;
1486 }
1487
1488 static void
1489 gtk_toolbar_size_allocate (GtkWidget     *widget,
1490                            GtkAllocation *allocation)
1491 {
1492   GtkAllocation widget_allocation;
1493   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1494   GtkToolbarPrivate *priv = toolbar->priv;
1495   GtkAllocation *allocations;
1496   ItemState *new_states;
1497   GtkAllocation arrow_allocation;
1498   GtkBorder padding;
1499   gint arrow_size;
1500   gint size, pos, short_size;
1501   GList *list;
1502   gint i;
1503   gboolean need_arrow;
1504   gint n_expand_items;
1505   gint border_width;
1506   gint available_size;
1507   gint n_items;
1508   gint needed_size;
1509   GtkRequisition arrow_requisition;
1510   gboolean overflowing;
1511   gboolean size_changed;
1512   GtkAllocation item_area;
1513   GtkShadowType shadow_type;
1514
1515   gtk_widget_get_allocation (widget, &widget_allocation);
1516   size_changed = FALSE;
1517   if (widget_allocation.x != allocation->x ||
1518       widget_allocation.y != allocation->y ||
1519       widget_allocation.width != allocation->width ||
1520       widget_allocation.height != allocation->height)
1521     {
1522       size_changed = TRUE;
1523     }
1524
1525   if (size_changed)
1526     gtk_toolbar_stop_sliding (toolbar);
1527
1528   gtk_widget_set_allocation (widget, allocation);
1529
1530   border_width = gtk_container_get_border_width (GTK_CONTAINER (toolbar));
1531
1532   if (gtk_widget_get_realized (widget))
1533     gdk_window_move_resize (priv->event_window,
1534                             allocation->x + border_width,
1535                             allocation->y + border_width,
1536                             allocation->width - border_width * 2,
1537                             allocation->height - border_width * 2);
1538
1539
1540   gtk_widget_get_preferred_size (priv->arrow_button,
1541                                  &arrow_requisition, NULL);
1542
1543   shadow_type = get_shadow_type (toolbar);
1544
1545   get_widget_padding_and_border (widget, &padding);
1546
1547   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1548     {
1549       available_size = size = allocation->width - 2 * border_width;
1550       short_size = allocation->height - 2 * border_width;
1551       arrow_size = arrow_requisition.width;
1552
1553       if (shadow_type != GTK_SHADOW_NONE)
1554         {
1555           available_size -= padding.left + padding.right;
1556           short_size -= padding.top + padding.bottom;
1557         }
1558     }
1559   else
1560     {
1561       available_size = size = allocation->height - 2 * border_width;
1562       short_size = allocation->width - 2 * border_width;
1563       arrow_size = arrow_requisition.height;
1564
1565       if (shadow_type != GTK_SHADOW_NONE)
1566         {
1567           available_size -= padding.top + padding.bottom;
1568           short_size -= padding.left + padding.right;
1569         }
1570     }
1571
1572   n_items = g_list_length (priv->content);
1573   allocations = g_new0 (GtkAllocation, n_items);
1574   new_states = g_new0 (ItemState, n_items);
1575
1576   needed_size = 0;
1577   need_arrow = FALSE;
1578   for (list = priv->content; list != NULL; list = list->next)
1579     {
1580       ToolbarContent *content = list->data;
1581
1582       if (toolbar_content_visible (content, toolbar))
1583         {
1584           needed_size += get_item_size (toolbar, content);
1585
1586           /* Do we need an arrow?
1587            *
1588            * Assume we don't, and see if any non-separator item
1589            * with a proxy menu item is then going to overflow.
1590            */
1591           if (needed_size > available_size &&
1592               !need_arrow &&
1593               priv->show_arrow &&
1594               toolbar_content_has_proxy_menu_item (content) &&
1595               !toolbar_content_is_separator (content))
1596             {
1597               need_arrow = TRUE;
1598             }
1599         }
1600     }
1601
1602   if (need_arrow)
1603     size = available_size - arrow_size;
1604   else
1605     size = available_size;
1606
1607   /* calculate widths and states of items */
1608   overflowing = FALSE;
1609   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1610     {
1611       ToolbarContent *content = list->data;
1612       gint item_size;
1613
1614       if (!toolbar_content_visible (content, toolbar))
1615         {
1616           new_states[i] = HIDDEN;
1617           continue;
1618         }
1619
1620       item_size = get_item_size (toolbar, content);
1621       if (item_size <= size && !overflowing)
1622         {
1623           size -= item_size;
1624           allocations[i].width = item_size;
1625           new_states[i] = NORMAL;
1626         }
1627       else
1628         {
1629           overflowing = TRUE;
1630           new_states[i] = OVERFLOWN;
1631           allocations[i].width = item_size;
1632         }
1633     }
1634
1635   /* calculate width of arrow */
1636   if (need_arrow)
1637     {
1638       arrow_allocation.width = arrow_size;
1639       arrow_allocation.height = MAX (short_size, 1);
1640     }
1641
1642   /* expand expandable items */
1643
1644   /* We don't expand when there is an overflow menu,
1645    * because that leads to weird jumps when items get
1646    * moved to the overflow menu and the expanding
1647    * items suddenly get a lot of extra space
1648    */
1649   if (!overflowing)
1650     {
1651       gint max_child_expand;
1652       n_expand_items = 0;
1653
1654       for (i = 0, list = priv->content; list != NULL; list = list->next, ++i)
1655         {
1656           ToolbarContent *content = list->data;
1657
1658           if (toolbar_content_get_expand (content) && new_states[i] == NORMAL)
1659             n_expand_items++;
1660         }
1661
1662       max_child_expand = get_max_child_expand (toolbar);
1663       for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1664         {
1665           ToolbarContent *content = list->data;
1666
1667           if (toolbar_content_get_expand (content) && new_states[i] == NORMAL)
1668             {
1669               gint extra = size / n_expand_items;
1670               if (size % n_expand_items != 0)
1671                 extra++;
1672
1673               if (extra > max_child_expand)
1674                 extra = max_child_expand;
1675
1676               allocations[i].width += extra;
1677               size -= extra;
1678               n_expand_items--;
1679             }
1680         }
1681
1682       g_assert (n_expand_items == 0);
1683     }
1684
1685   /* position items */
1686   pos = border_width;
1687   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1688     {
1689       /* Both NORMAL and OVERFLOWN items get a position.
1690        * This ensures that sliding will work for OVERFLOWN items too.
1691        */
1692       if (new_states[i] == NORMAL || new_states[i] == OVERFLOWN)
1693         {
1694           allocations[i].x = pos;
1695           allocations[i].y = border_width;
1696           allocations[i].height = short_size;
1697
1698           pos += allocations[i].width;
1699         }
1700     }
1701
1702   /* position arrow */
1703   if (need_arrow)
1704     {
1705       arrow_allocation.x = available_size - border_width - arrow_allocation.width;
1706       arrow_allocation.y = border_width;
1707     }
1708
1709   item_area.x = border_width;
1710   item_area.y = border_width;
1711   item_area.width = available_size - (need_arrow? arrow_size : 0);
1712   item_area.height = short_size;
1713
1714   /* fix up allocations in the vertical or RTL cases */
1715   if (priv->orientation == GTK_ORIENTATION_VERTICAL)
1716     {
1717       for (i = 0; i < n_items; ++i)
1718         fixup_allocation_for_vertical (&(allocations[i]));
1719
1720       if (need_arrow)
1721         fixup_allocation_for_vertical (&arrow_allocation);
1722
1723       fixup_allocation_for_vertical (&item_area);
1724     }
1725   else if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1726     {
1727       for (i = 0; i < n_items; ++i)
1728         fixup_allocation_for_rtl (available_size, &(allocations[i]));
1729
1730       if (need_arrow)
1731         fixup_allocation_for_rtl (available_size, &arrow_allocation);
1732
1733       fixup_allocation_for_rtl (available_size, &item_area);
1734     }
1735
1736   /* translate the items by allocation->(x,y) */
1737   for (i = 0; i < n_items; ++i)
1738     {
1739       allocations[i].x += allocation->x;
1740       allocations[i].y += allocation->y;
1741
1742       if (shadow_type != GTK_SHADOW_NONE)
1743         {
1744           allocations[i].x += padding.left;
1745           allocations[i].y += padding.top;
1746         }
1747     }
1748
1749   if (need_arrow)
1750     {
1751       arrow_allocation.x += allocation->x;
1752       arrow_allocation.y += allocation->y;
1753
1754       if (shadow_type != GTK_SHADOW_NONE)
1755         {
1756           arrow_allocation.x += padding.left;
1757           arrow_allocation.y += padding.top;
1758         }
1759     }
1760
1761   item_area.x += allocation->x;
1762   item_area.y += allocation->y;
1763   if (shadow_type != GTK_SHADOW_NONE)
1764     {
1765       item_area.x += padding.left;
1766       item_area.y += padding.top;
1767     }
1768
1769   /* did anything change? */
1770   for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1771     {
1772       ToolbarContent *content = list->data;
1773
1774       if (toolbar_content_get_state (content) == NORMAL &&
1775           new_states[i] != NORMAL)
1776         {
1777           /* an item disappeared and we didn't change size, so begin sliding */
1778           if (!size_changed)
1779             gtk_toolbar_begin_sliding (toolbar);
1780         }
1781     }
1782
1783   /* finally allocate the items */
1784   if (priv->is_sliding)
1785     {
1786       for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1787         {
1788           ToolbarContent *content = list->data;
1789
1790           toolbar_content_set_goal_allocation (content, &(allocations[i]));
1791         }
1792     }
1793
1794   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1795     {
1796       ToolbarContent *content = list->data;
1797
1798       if (new_states[i] == OVERFLOWN || new_states[i] == NORMAL)
1799         {
1800           GtkAllocation alloc;
1801           GtkAllocation start_allocation = { 0, };
1802           GtkAllocation goal_allocation;
1803
1804           if (priv->is_sliding)
1805             {
1806               toolbar_content_get_start_allocation (content, &start_allocation);
1807               toolbar_content_get_goal_allocation (content, &goal_allocation);
1808
1809               compute_intermediate_allocation (toolbar,
1810                                                &start_allocation,
1811                                                &goal_allocation,
1812                                                &alloc);
1813
1814               priv->need_sync = TRUE;
1815             }
1816           else
1817             {
1818               alloc = allocations[i];
1819             }
1820
1821           if (alloc.width <= 0 || alloc.height <= 0)
1822             {
1823               toolbar_content_set_child_visible (content, toolbar, FALSE);
1824             }
1825           else
1826             {
1827               if (!rect_within (&alloc, &item_area))
1828                 {
1829                   toolbar_content_set_child_visible (content, toolbar, FALSE);
1830                   toolbar_content_size_allocate (content, &alloc);
1831                 }
1832               else
1833                 {
1834                   toolbar_content_set_child_visible (content, toolbar, TRUE);
1835                   toolbar_content_size_allocate (content, &alloc);
1836                 }
1837             }
1838         }
1839       else
1840         {
1841           toolbar_content_set_child_visible (content, toolbar, FALSE);
1842         }
1843
1844       toolbar_content_set_state (content, new_states[i]);
1845     }
1846
1847   if (priv->menu && priv->need_rebuild)
1848     rebuild_menu (toolbar);
1849
1850   if (need_arrow)
1851     {
1852       gtk_widget_size_allocate (GTK_WIDGET (priv->arrow_button),
1853                                 &arrow_allocation);
1854       gtk_widget_show (GTK_WIDGET (priv->arrow_button));
1855     }
1856   else
1857     {
1858       gtk_widget_hide (GTK_WIDGET (priv->arrow_button));
1859
1860       if (priv->menu && gtk_widget_get_visible (GTK_WIDGET (priv->menu)))
1861         gtk_menu_shell_deactivate (GTK_MENU_SHELL (priv->menu));
1862     }
1863
1864   g_free (allocations);
1865   g_free (new_states);
1866 }
1867
1868 static void
1869 gtk_toolbar_update_button_relief (GtkToolbar *toolbar)
1870 {
1871   GtkToolbarPrivate *priv = toolbar->priv;
1872   GtkReliefStyle relief;
1873
1874   relief = get_button_relief (toolbar);
1875
1876   if (relief != gtk_button_get_relief (GTK_BUTTON (priv->arrow_button)))
1877     {
1878       gtk_toolbar_reconfigured (toolbar);
1879   
1880       gtk_button_set_relief (GTK_BUTTON (priv->arrow_button), relief);
1881     }
1882 }
1883
1884 static void
1885 gtk_toolbar_style_updated (GtkWidget *widget)
1886 {
1887   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1888   GtkToolbarPrivate *priv = toolbar->priv;
1889
1890   GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->style_updated (widget);
1891
1892   priv->max_homogeneous_pixels = -1;
1893   gtk_toolbar_update_button_relief (GTK_TOOLBAR (widget));
1894 }
1895
1896 static GList *
1897 gtk_toolbar_list_children_in_focus_order (GtkToolbar       *toolbar,
1898                                           GtkDirectionType  dir)
1899 {
1900   GtkToolbarPrivate *priv = toolbar->priv;
1901   GList *result = NULL;
1902   GList *list;
1903   gboolean rtl;
1904   
1905   /* generate list of children in reverse logical order */
1906   
1907   for (list = priv->content; list != NULL; list = list->next)
1908     {
1909       ToolbarContent *content = list->data;
1910       GtkWidget *widget;
1911       
1912       widget = toolbar_content_get_widget (content);
1913       
1914       if (widget)
1915         result = g_list_prepend (result, widget);
1916     }
1917   
1918   result = g_list_prepend (result, priv->arrow_button);
1919   
1920   rtl = (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL);
1921   
1922   /* move in logical order when
1923    *
1924    *    - dir is TAB_FORWARD
1925    *
1926    *    - in RTL mode and moving left or up
1927    *
1928    *    - in LTR mode and moving right or down
1929    */
1930   if (dir == GTK_DIR_TAB_FORWARD                                        ||
1931       (rtl  && (dir == GTK_DIR_UP   || dir == GTK_DIR_LEFT))            ||
1932       (!rtl && (dir == GTK_DIR_DOWN || dir == GTK_DIR_RIGHT)))
1933     {
1934       result = g_list_reverse (result);
1935     }
1936   
1937   return result;
1938 }
1939
1940 static gboolean
1941 gtk_toolbar_focus_home_or_end (GtkToolbar *toolbar,
1942                                gboolean    focus_home)
1943 {
1944   GList *children, *list;
1945   GtkDirectionType dir = focus_home? GTK_DIR_RIGHT : GTK_DIR_LEFT;
1946   
1947   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1948   
1949   if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1950     {
1951       children = g_list_reverse (children);
1952       
1953       dir = (dir == GTK_DIR_RIGHT)? GTK_DIR_LEFT : GTK_DIR_RIGHT;
1954     }
1955   
1956   for (list = children; list != NULL; list = list->next)
1957     {
1958       GtkWidget *child = list->data;
1959
1960       if (gtk_container_get_focus_child (GTK_CONTAINER (toolbar)) == child)
1961         break;
1962       
1963       if (gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
1964         break;
1965     }
1966   
1967   g_list_free (children);
1968   
1969   return TRUE;
1970 }   
1971
1972 /* Keybinding handler. This function is called when the user presses
1973  * Ctrl TAB or an arrow key.
1974  */
1975 static void
1976 gtk_toolbar_move_focus (GtkWidget        *widget,
1977                         GtkDirectionType  dir)
1978 {
1979   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1980   GtkContainer *container = GTK_CONTAINER (toolbar);
1981   GtkWidget *focus_child;
1982   GList *list;
1983   gboolean try_focus = FALSE;
1984   GList *children;
1985
1986   focus_child = gtk_container_get_focus_child (container);
1987
1988   if (focus_child && gtk_widget_child_focus (focus_child, dir))
1989     return;
1990   
1991   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1992   
1993   for (list = children; list != NULL; list = list->next)
1994     {
1995       GtkWidget *child = list->data;
1996       
1997       if (try_focus && gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
1998         break;
1999       
2000       if (child == focus_child)
2001         try_focus = TRUE;
2002     }
2003   
2004   g_list_free (children);
2005 }
2006
2007 /* The focus handler for the toolbar. It called when the user presses
2008  * TAB or otherwise tries to focus the toolbar.
2009  */
2010 static gboolean
2011 gtk_toolbar_focus (GtkWidget        *widget,
2012                    GtkDirectionType  dir)
2013 {
2014   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
2015   GList *children, *list;
2016   gboolean result = FALSE;
2017
2018   /* if focus is already somewhere inside the toolbar then return FALSE.
2019    * The only way focus can stay inside the toolbar is when the user presses
2020    * arrow keys or Ctrl TAB (both of which are handled by the
2021    * gtk_toolbar_move_focus() keybinding function.
2022    */
2023   if (gtk_container_get_focus_child (GTK_CONTAINER (widget)))
2024     return FALSE;
2025
2026   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
2027
2028   for (list = children; list != NULL; list = list->next)
2029     {
2030       GtkWidget *child = list->data;
2031       
2032       if (gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
2033         {
2034           result = TRUE;
2035           break;
2036         }
2037     }
2038
2039   g_list_free (children);
2040
2041   return result;
2042 }
2043
2044 static GtkSettings *
2045 toolbar_get_settings (GtkToolbar *toolbar)
2046 {
2047   return toolbar->priv->settings;
2048 }
2049
2050 static void
2051 style_change_notify (GtkToolbar *toolbar)
2052 {
2053   GtkToolbarPrivate *priv = toolbar->priv;
2054
2055   if (!priv->style_set)
2056     {
2057       /* pretend it was set, then unset, thus reverting to new default */
2058       priv->style_set = TRUE;
2059       gtk_toolbar_unset_style (toolbar);
2060     }
2061 }
2062
2063 static void
2064 icon_size_change_notify (GtkToolbar *toolbar)
2065 {
2066   GtkToolbarPrivate *priv = toolbar->priv;
2067
2068   if (!priv->icon_size_set)
2069     {
2070       /* pretend it was set, then unset, thus reverting to new default */
2071       priv->icon_size_set = TRUE;
2072       gtk_toolbar_unset_icon_size (toolbar);
2073     }
2074 }
2075
2076 static void
2077 animation_change_notify (GtkToolbar *toolbar)
2078 {
2079   GtkToolbarPrivate *priv = toolbar->priv;
2080   GtkSettings *settings = toolbar_get_settings (toolbar);
2081   gboolean animation;
2082
2083   if (settings)
2084     g_object_get (settings,
2085                   "gtk-enable-animations", &animation,
2086                   NULL);
2087   else
2088     animation = DEFAULT_ANIMATION_STATE;
2089
2090   priv->animation = animation;
2091 }
2092
2093 static void
2094 settings_change_notify (GtkSettings      *settings,
2095                         const GParamSpec *pspec,
2096                         GtkToolbar       *toolbar)
2097 {
2098   if (! strcmp (pspec->name, "gtk-toolbar-style"))
2099     style_change_notify (toolbar);
2100   else if (! strcmp (pspec->name, "gtk-toolbar-icon-size"))
2101     icon_size_change_notify (toolbar);
2102   else if (! strcmp (pspec->name, "gtk-enable-animations"))
2103     animation_change_notify (toolbar);
2104 }
2105
2106 static void
2107 gtk_toolbar_screen_changed (GtkWidget *widget,
2108                             GdkScreen *previous_screen)
2109 {
2110   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
2111   GtkToolbarPrivate *priv = toolbar->priv;
2112   GtkSettings *old_settings = toolbar_get_settings (toolbar);
2113   GtkSettings *settings;
2114   
2115   if (gtk_widget_has_screen (GTK_WIDGET (toolbar)))
2116     settings = gtk_widget_get_settings (GTK_WIDGET (toolbar));
2117   else
2118     settings = NULL;
2119   
2120   if (settings == old_settings)
2121     return;
2122   
2123   if (old_settings)
2124     {
2125       g_signal_handler_disconnect (old_settings, priv->settings_connection);
2126
2127       g_object_unref (old_settings);
2128     }
2129
2130   if (settings)
2131     {
2132       priv->settings_connection =
2133         g_signal_connect (settings, "notify",
2134                           G_CALLBACK (settings_change_notify),
2135                           toolbar);
2136
2137       priv->settings = g_object_ref (settings);
2138     }
2139   else
2140     priv->settings = NULL;
2141
2142   style_change_notify (toolbar);
2143   icon_size_change_notify (toolbar);
2144   animation_change_notify (toolbar);
2145 }
2146
2147 static int
2148 find_drop_index (GtkToolbar *toolbar,
2149                  gint        x,
2150                  gint        y)
2151 {
2152   GtkToolbarPrivate *priv = toolbar->priv;
2153   GList *interesting_content;
2154   GList *list;
2155   GtkOrientation orientation;
2156   GtkTextDirection direction;
2157   gint best_distance = G_MAXINT;
2158   gint distance;
2159   gint cursor;
2160   gint pos;
2161   ToolbarContent *best_content;
2162   GtkAllocation allocation;
2163   
2164   /* list items we care about wrt. drag and drop */
2165   interesting_content = NULL;
2166   for (list = priv->content; list != NULL; list = list->next)
2167     {
2168       ToolbarContent *content = list->data;
2169       
2170       if (toolbar_content_get_state (content) == NORMAL)
2171         interesting_content = g_list_prepend (interesting_content, content);
2172     }
2173   interesting_content = g_list_reverse (interesting_content);
2174   
2175   if (!interesting_content)
2176     return 0;
2177   
2178   orientation = priv->orientation;
2179   direction = gtk_widget_get_direction (GTK_WIDGET (toolbar));
2180   
2181   /* distance to first interesting item */
2182   best_content = interesting_content->data;
2183   toolbar_content_get_allocation (best_content, &allocation);
2184   
2185   if (orientation == GTK_ORIENTATION_HORIZONTAL)
2186     {
2187       cursor = x;
2188       
2189       if (direction == GTK_TEXT_DIR_LTR)
2190         pos = allocation.x;
2191       else
2192         pos = allocation.x + allocation.width;
2193     }
2194   else
2195     {
2196       cursor = y;
2197       pos = allocation.y;
2198     }
2199   
2200   best_content = NULL;
2201   best_distance = ABS (pos - cursor);
2202   
2203   /* distance to far end of each item */
2204   for (list = interesting_content; list != NULL; list = list->next)
2205     {
2206       ToolbarContent *content = list->data;
2207       
2208       toolbar_content_get_allocation (content, &allocation);
2209       
2210       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2211         {
2212           if (direction == GTK_TEXT_DIR_LTR)
2213             pos = allocation.x + allocation.width;
2214           else
2215             pos = allocation.x;
2216         }
2217       else
2218         {
2219           pos = allocation.y + allocation.height;
2220         }
2221       
2222       distance = ABS (pos - cursor);
2223       
2224       if (distance < best_distance)
2225         {
2226           best_distance = distance;
2227           best_content = content;
2228         }
2229     }
2230   
2231   g_list_free (interesting_content);
2232   
2233   if (!best_content)
2234     return 0;
2235   else
2236     return g_list_index (priv->content, best_content) + 1;
2237 }
2238
2239 static void
2240 reset_all_placeholders (GtkToolbar *toolbar)
2241 {
2242   GtkToolbarPrivate *priv = toolbar->priv;
2243   GList *list;
2244   
2245   for (list = priv->content; list != NULL; list = list->next)
2246     {
2247       ToolbarContent *content = list->data;
2248       if (toolbar_content_is_placeholder (content))
2249         toolbar_content_set_disappearing (content, TRUE);
2250     }
2251 }
2252
2253 static gint
2254 physical_to_logical (GtkToolbar *toolbar,
2255                      gint        physical)
2256 {
2257   GtkToolbarPrivate *priv = toolbar->priv;
2258   GList *list;
2259   int logical;
2260   
2261   g_assert (physical >= 0);
2262   
2263   logical = 0;
2264   for (list = priv->content; list && physical > 0; list = list->next)
2265     {
2266       ToolbarContent *content = list->data;
2267       
2268       if (!toolbar_content_is_placeholder (content))
2269         logical++;
2270       physical--;
2271     }
2272   
2273   g_assert (physical == 0);
2274   
2275   return logical;
2276 }
2277
2278 static gint
2279 logical_to_physical (GtkToolbar *toolbar,
2280                      gint        logical)
2281 {
2282   GtkToolbarPrivate *priv = toolbar->priv;
2283   GList *list;
2284   gint physical;
2285   
2286   g_assert (logical >= 0);
2287   
2288   physical = 0;
2289   for (list = priv->content; list; list = list->next)
2290     {
2291       ToolbarContent *content = list->data;
2292       
2293       if (!toolbar_content_is_placeholder (content))
2294         {
2295           if (logical == 0)
2296             break;
2297           logical--;
2298         }
2299       
2300       physical++;
2301     }
2302   
2303   g_assert (logical == 0);
2304   
2305   return physical;
2306 }
2307
2308 /**
2309  * gtk_toolbar_set_drop_highlight_item:
2310  * @toolbar: a #GtkToolbar
2311  * @tool_item: (allow-none): a #GtkToolItem, or %NULL to turn of highlighting
2312  * @index_: a position on @toolbar
2313  *
2314  * Highlights @toolbar to give an idea of what it would look like
2315  * if @item was added to @toolbar at the position indicated by @index_.
2316  * If @item is %NULL, highlighting is turned off. In that case @index_ 
2317  * is ignored.
2318  *
2319  * The @tool_item passed to this function must not be part of any widget
2320  * hierarchy. When an item is set as drop highlight item it can not
2321  * added to any widget hierarchy or used as highlight item for another
2322  * toolbar.
2323  * 
2324  * Since: 2.4
2325  **/
2326 void
2327 gtk_toolbar_set_drop_highlight_item (GtkToolbar  *toolbar,
2328                                      GtkToolItem *tool_item,
2329                                      gint         index_)
2330 {
2331   ToolbarContent *content;
2332   GtkToolbarPrivate *priv;
2333   gint n_items;
2334   GtkRequisition requisition;
2335   GtkRequisition old_requisition;
2336   gboolean restart_sliding;
2337   
2338   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2339   g_return_if_fail (tool_item == NULL || GTK_IS_TOOL_ITEM (tool_item));
2340
2341   priv = toolbar->priv;
2342
2343   if (!tool_item)
2344     {
2345       if (priv->highlight_tool_item)
2346         {
2347           gtk_widget_unparent (GTK_WIDGET (priv->highlight_tool_item));
2348           g_object_unref (priv->highlight_tool_item);
2349           priv->highlight_tool_item = NULL;
2350         }
2351       
2352       reset_all_placeholders (toolbar);
2353       gtk_toolbar_begin_sliding (toolbar);
2354       return;
2355     }
2356   
2357   n_items = gtk_toolbar_get_n_items (toolbar);
2358   if (index_ < 0 || index_ > n_items)
2359     index_ = n_items;
2360   
2361   if (tool_item != priv->highlight_tool_item)
2362     {
2363       if (priv->highlight_tool_item)
2364         g_object_unref (priv->highlight_tool_item);
2365       
2366       g_object_ref_sink (tool_item);
2367       
2368       priv->highlight_tool_item = tool_item;
2369       
2370       gtk_widget_set_parent (GTK_WIDGET (priv->highlight_tool_item),
2371                              GTK_WIDGET (toolbar));
2372     }
2373   
2374   index_ = logical_to_physical (toolbar, index_);
2375   
2376   content = g_list_nth_data (priv->content, index_);
2377   
2378   if (index_ > 0)
2379     {
2380       ToolbarContent *prev_content;
2381       
2382       prev_content = g_list_nth_data (priv->content, index_ - 1);
2383       
2384       if (prev_content && toolbar_content_is_placeholder (prev_content))
2385         content = prev_content;
2386     }
2387   
2388   if (!content || !toolbar_content_is_placeholder (content))
2389     {
2390       GtkWidget *placeholder;
2391       
2392       placeholder = GTK_WIDGET (gtk_separator_tool_item_new ());
2393
2394       content = toolbar_content_new_tool_item (toolbar,
2395                                                GTK_TOOL_ITEM (placeholder),
2396                                                TRUE, index_);
2397       gtk_widget_show (placeholder);
2398     }
2399   
2400   g_assert (content);
2401   g_assert (toolbar_content_is_placeholder (content));
2402
2403   gtk_widget_get_preferred_size (GTK_WIDGET (priv->highlight_tool_item),
2404                                  &requisition, NULL);
2405
2406   toolbar_content_set_expand (content, gtk_tool_item_get_expand (tool_item));
2407   
2408   restart_sliding = FALSE;
2409   toolbar_content_size_request (content, toolbar, &old_requisition);
2410   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2411     {
2412       requisition.height = -1;
2413       if (requisition.width != old_requisition.width)
2414         restart_sliding = TRUE;
2415     }
2416   else
2417     {
2418       requisition.width = -1;
2419       if (requisition.height != old_requisition.height)
2420         restart_sliding = TRUE;
2421     }
2422
2423   if (toolbar_content_disappearing (content))
2424     restart_sliding = TRUE;
2425   
2426   reset_all_placeholders (toolbar);
2427   toolbar_content_set_disappearing (content, FALSE);
2428   
2429   toolbar_content_set_size_request (content,
2430                                     requisition.width, requisition.height);
2431   
2432   if (restart_sliding)
2433     gtk_toolbar_begin_sliding (toolbar);
2434 }
2435
2436 static void
2437 gtk_toolbar_get_child_property (GtkContainer *container,
2438                                 GtkWidget    *child,
2439                                 guint         property_id,
2440                                 GValue       *value,
2441                                 GParamSpec   *pspec)
2442 {
2443   GtkToolItem *item = GTK_TOOL_ITEM (child);
2444   
2445   switch (property_id)
2446     {
2447     case CHILD_PROP_HOMOGENEOUS:
2448       g_value_set_boolean (value, gtk_tool_item_get_homogeneous (item));
2449       break;
2450       
2451     case CHILD_PROP_EXPAND:
2452       g_value_set_boolean (value, gtk_tool_item_get_expand (item));
2453       break;
2454       
2455     default:
2456       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2457       break;
2458     }
2459 }
2460
2461 static void
2462 gtk_toolbar_set_child_property (GtkContainer *container,
2463                                 GtkWidget    *child,
2464                                 guint         property_id,
2465                                 const GValue *value,
2466                                 GParamSpec   *pspec)
2467 {
2468   switch (property_id)
2469     {
2470     case CHILD_PROP_HOMOGENEOUS:
2471       gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2472       break;
2473       
2474     case CHILD_PROP_EXPAND:
2475       gtk_tool_item_set_expand (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2476       break;
2477       
2478     default:
2479       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2480       break;
2481     }
2482 }
2483
2484 static void
2485 gtk_toolbar_show_all (GtkWidget *widget)
2486 {
2487   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
2488   GtkToolbarPrivate *priv = toolbar->priv;
2489   GList *list;
2490
2491   for (list = priv->content; list != NULL; list = list->next)
2492     {
2493       ToolbarContent *content = list->data;
2494       
2495       toolbar_content_show_all (content);
2496     }
2497   
2498   gtk_widget_show (widget);
2499 }
2500
2501 static void
2502 gtk_toolbar_add (GtkContainer *container,
2503                  GtkWidget    *widget)
2504 {
2505   GtkToolbar *toolbar = GTK_TOOLBAR (container);
2506
2507   gtk_toolbar_insert (toolbar, GTK_TOOL_ITEM (widget), -1);
2508 }
2509
2510 static void
2511 gtk_toolbar_remove (GtkContainer *container,
2512                     GtkWidget    *widget)
2513 {
2514   GtkToolbar *toolbar = GTK_TOOLBAR (container);
2515   GtkToolbarPrivate *priv = toolbar->priv;
2516   ToolbarContent *content_to_remove;
2517   GList *list;
2518
2519   content_to_remove = NULL;
2520   for (list = priv->content; list != NULL; list = list->next)
2521     {
2522       ToolbarContent *content = list->data;
2523       GtkWidget *child;
2524       
2525       child = toolbar_content_get_widget (content);
2526       if (child && child == widget)
2527         {
2528           content_to_remove = content;
2529           break;
2530         }
2531     }
2532   
2533   g_return_if_fail (content_to_remove != NULL);
2534   
2535   toolbar_content_remove (content_to_remove, toolbar);
2536   toolbar_content_free (content_to_remove);
2537 }
2538
2539 static void
2540 gtk_toolbar_forall (GtkContainer *container,
2541                     gboolean      include_internals,
2542                     GtkCallback   callback,
2543                     gpointer      callback_data)
2544 {
2545   GtkToolbar *toolbar = GTK_TOOLBAR (container);
2546   GtkToolbarPrivate *priv = toolbar->priv;
2547   GList *list;
2548
2549   g_return_if_fail (callback != NULL);
2550
2551   list = priv->content;
2552   while (list)
2553     {
2554       ToolbarContent *content = list->data;
2555       GList *next = list->next;
2556
2557       if (include_internals || !toolbar_content_is_placeholder (content))
2558         {
2559           GtkWidget *child = toolbar_content_get_widget (content);
2560
2561           if (child)
2562             callback (child, callback_data);
2563         }
2564
2565       list = next;
2566     }
2567
2568   if (include_internals && priv->arrow_button)
2569     callback (priv->arrow_button, callback_data);
2570 }
2571
2572 static GType
2573 gtk_toolbar_child_type (GtkContainer *container)
2574 {
2575   return GTK_TYPE_TOOL_ITEM;
2576 }
2577
2578 static void
2579 gtk_toolbar_reconfigured (GtkToolbar *toolbar)
2580 {
2581   GtkToolbarPrivate *priv = toolbar->priv;
2582   GList *list;
2583   
2584   list = priv->content;
2585   while (list)
2586     {
2587       ToolbarContent *content = list->data;
2588       GList *next = list->next;
2589       
2590       toolbar_content_toolbar_reconfigured (content, toolbar);
2591       
2592       list = next;
2593     }
2594 }
2595
2596 static void
2597 gtk_toolbar_orientation_changed (GtkToolbar    *toolbar,
2598                                  GtkOrientation orientation)
2599 {
2600   GtkToolbarPrivate *priv = toolbar->priv;
2601
2602   if (priv->orientation != orientation)
2603     {
2604       priv->orientation = orientation;
2605       
2606       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2607         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
2608       else
2609         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
2610       
2611       gtk_toolbar_reconfigured (toolbar);
2612       
2613       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2614       g_object_notify (G_OBJECT (toolbar), "orientation");
2615     }
2616 }
2617
2618 static void
2619 gtk_toolbar_real_style_changed (GtkToolbar     *toolbar,
2620                                 GtkToolbarStyle style)
2621 {
2622   GtkToolbarPrivate *priv = toolbar->priv;
2623
2624   if (priv->style != style)
2625     {
2626       priv->style = style;
2627
2628       gtk_toolbar_reconfigured (toolbar);
2629       
2630       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2631       g_object_notify (G_OBJECT (toolbar), "toolbar-style");
2632     }
2633 }
2634
2635 static void
2636 menu_position_func (GtkMenu  *menu,
2637                     gint     *x,
2638                     gint     *y,
2639                     gboolean *push_in,
2640                     gpointer  user_data)
2641 {
2642   GtkAllocation allocation;
2643   GtkToolbar *toolbar = GTK_TOOLBAR (user_data);
2644   GtkToolbarPrivate *priv = toolbar->priv;
2645   GtkRequisition req;
2646   GtkRequisition menu_req;
2647   GdkRectangle monitor;
2648   gint monitor_num;
2649   GdkScreen *screen;
2650
2651   gtk_widget_get_preferred_size (priv->arrow_button,
2652                                  &req, NULL);
2653   gtk_widget_get_preferred_size (GTK_WIDGET (menu),
2654                                  &menu_req, NULL);
2655
2656   screen = gtk_widget_get_screen (GTK_WIDGET (menu));
2657   monitor_num = gdk_screen_get_monitor_at_window (screen,
2658                                                   gtk_widget_get_window (priv->arrow_button));
2659   if (monitor_num < 0)
2660     monitor_num = 0;
2661   gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
2662
2663   gtk_widget_get_allocation (priv->arrow_button, &allocation);
2664
2665   gdk_window_get_origin (gtk_button_get_event_window (GTK_BUTTON (priv->arrow_button)), x, y);
2666   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2667     {
2668       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2669         *x += allocation.width - req.width;
2670       else 
2671         *x += req.width - menu_req.width;
2672
2673       if ((*y + allocation.height + menu_req.height) <= monitor.y + monitor.height)
2674         *y += allocation.height;
2675       else if ((*y - menu_req.height) >= monitor.y)
2676         *y -= menu_req.height;
2677       else if (monitor.y + monitor.height - (*y + allocation.height) > *y)
2678         *y += allocation.height;
2679       else
2680         *y -= menu_req.height;
2681     }
2682   else 
2683     {
2684       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2685         *x += allocation.width;
2686       else 
2687         *x -= menu_req.width;
2688
2689       if (*y + menu_req.height > monitor.y + monitor.height &&
2690           *y + allocation.height - monitor.y > monitor.y + monitor.height - *y)
2691         *y += allocation.height - menu_req.height;
2692     }
2693
2694   *push_in = FALSE;
2695 }
2696
2697 static void
2698 show_menu (GtkToolbar     *toolbar,
2699            GdkEventButton *event)
2700 {
2701   GtkToolbarPrivate *priv = toolbar->priv;
2702
2703   rebuild_menu (toolbar);
2704
2705   gtk_widget_show_all (GTK_WIDGET (priv->menu));
2706
2707   gtk_menu_popup (priv->menu, NULL, NULL,
2708                   menu_position_func, toolbar,
2709                   event? event->button : 0,
2710                   event? event->time : gtk_get_current_event_time());
2711 }
2712
2713 static void
2714 gtk_toolbar_arrow_button_clicked (GtkWidget  *button,
2715                                   GtkToolbar *toolbar)
2716 {
2717   GtkToolbarPrivate *priv = toolbar->priv;
2718
2719   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->arrow_button)) &&
2720       (!priv->menu || !gtk_widget_get_visible (GTK_WIDGET (priv->menu))))
2721     {
2722       /* We only get here when the button is clicked with the keyboard,
2723        * because mouse button presses result in the menu being shown so
2724        * that priv->menu would be non-NULL and visible.
2725        */
2726       show_menu (toolbar, NULL);
2727       gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2728     }
2729 }
2730
2731 static gboolean
2732 gtk_toolbar_arrow_button_press (GtkWidget      *button,
2733                                 GdkEventButton *event,
2734                                 GtkToolbar     *toolbar)
2735 {
2736   show_menu (toolbar, event);
2737   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2738   
2739   return TRUE;
2740 }
2741
2742 static gboolean
2743 gtk_toolbar_button_press (GtkWidget      *toolbar,
2744                           GdkEventButton *event)
2745 {
2746   GtkWidget *window;
2747
2748   if (gdk_event_triggers_context_menu ((GdkEvent *) event))
2749     {
2750       gboolean return_value;
2751
2752       g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2753                      (int)event->x_root, (int)event->y_root, event->button,
2754                      &return_value);
2755
2756       return return_value;
2757     }
2758
2759   if (event->type != GDK_BUTTON_PRESS)
2760     return FALSE;
2761
2762   window = gtk_widget_get_toplevel (toolbar);
2763
2764   if (window)
2765     {
2766       gboolean window_drag = FALSE;
2767
2768       gtk_widget_style_get (toolbar,
2769                             "window-dragging", &window_drag,
2770                             NULL);
2771
2772       if (window_drag)
2773         {
2774           gtk_window_begin_move_drag (GTK_WINDOW (window),
2775                                       event->button,
2776                                       event->x_root,
2777                                       event->y_root,
2778                                       event->time);
2779
2780           return TRUE;
2781         }
2782     }
2783
2784   return FALSE;
2785 }
2786
2787 static gboolean
2788 gtk_toolbar_popup_menu (GtkWidget *toolbar)
2789 {
2790   gboolean return_value;
2791   /* This function is the handler for the "popup menu" keybinding,
2792    * ie., it is called when the user presses Shift F10
2793    */
2794   g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2795                  -1, -1, -1, &return_value);
2796   
2797   return return_value;
2798 }
2799
2800 /**
2801  * gtk_toolbar_new:
2802  * 
2803  * Creates a new toolbar. 
2804  
2805  * Return Value: the newly-created toolbar.
2806  **/
2807 GtkWidget *
2808 gtk_toolbar_new (void)
2809 {
2810   GtkToolbar *toolbar;
2811   
2812   toolbar = g_object_new (GTK_TYPE_TOOLBAR, NULL);
2813   
2814   return GTK_WIDGET (toolbar);
2815 }
2816
2817 /**
2818  * gtk_toolbar_insert:
2819  * @toolbar: a #GtkToolbar
2820  * @item: a #GtkToolItem
2821  * @pos: the position of the new item
2822  *
2823  * Insert a #GtkToolItem into the toolbar at position @pos. If @pos is
2824  * 0 the item is prepended to the start of the toolbar. If @pos is
2825  * negative, the item is appended to the end of the toolbar.
2826  *
2827  * Since: 2.4
2828  **/
2829 void
2830 gtk_toolbar_insert (GtkToolbar  *toolbar,
2831                     GtkToolItem *item,
2832                     gint         pos)
2833 {
2834   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2835   g_return_if_fail (GTK_IS_TOOL_ITEM (item));
2836   
2837   if (pos >= 0)
2838     pos = logical_to_physical (toolbar, pos);
2839
2840   toolbar_content_new_tool_item (toolbar, item, FALSE, pos);
2841 }
2842
2843 /**
2844  * gtk_toolbar_get_item_index:
2845  * @toolbar: a #GtkToolbar
2846  * @item: a #GtkToolItem that is a child of @toolbar
2847  * 
2848  * Returns the position of @item on the toolbar, starting from 0.
2849  * It is an error if @item is not a child of the toolbar.
2850  * 
2851  * Return value: the position of item on the toolbar.
2852  * 
2853  * Since: 2.4
2854  **/
2855 gint
2856 gtk_toolbar_get_item_index (GtkToolbar  *toolbar,
2857                             GtkToolItem *item)
2858 {
2859   GtkToolbarPrivate *priv;
2860   GList *list;
2861   int n;
2862   
2863   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2864   g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1);
2865   g_return_val_if_fail (gtk_widget_get_parent (GTK_WIDGET (item)) == GTK_WIDGET (toolbar), -1);
2866
2867   priv = toolbar->priv;
2868
2869   n = 0;
2870   for (list = priv->content; list != NULL; list = list->next)
2871     {
2872       ToolbarContent *content = list->data;
2873       GtkWidget *widget;
2874       
2875       widget = toolbar_content_get_widget (content);
2876       
2877       if (item == GTK_TOOL_ITEM (widget))
2878         break;
2879       
2880       ++n;
2881     }
2882   
2883   return physical_to_logical (toolbar, n);
2884 }
2885
2886 /**
2887  * gtk_toolbar_set_style:
2888  * @toolbar: a #GtkToolbar.
2889  * @style: the new style for @toolbar.
2890  * 
2891  * Alters the view of @toolbar to display either icons only, text only, or both.
2892  **/
2893 void
2894 gtk_toolbar_set_style (GtkToolbar      *toolbar,
2895                        GtkToolbarStyle  style)
2896 {
2897   GtkToolbarPrivate *priv;
2898
2899   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2900
2901   priv = toolbar->priv;
2902
2903   priv->style_set = TRUE;
2904   g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2905 }
2906
2907 /**
2908  * gtk_toolbar_get_style:
2909  * @toolbar: a #GtkToolbar
2910  *
2911  * Retrieves whether the toolbar has text, icons, or both . See
2912  * gtk_toolbar_set_style().
2913  
2914  * Return value: the current style of @toolbar
2915  **/
2916 GtkToolbarStyle
2917 gtk_toolbar_get_style (GtkToolbar *toolbar)
2918 {
2919   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE);
2920
2921   return toolbar->priv->style;
2922 }
2923
2924 /**
2925  * gtk_toolbar_unset_style:
2926  * @toolbar: a #GtkToolbar
2927  * 
2928  * Unsets a toolbar style set with gtk_toolbar_set_style(), so that
2929  * user preferences will be used to determine the toolbar style.
2930  **/
2931 void
2932 gtk_toolbar_unset_style (GtkToolbar *toolbar)
2933 {
2934   GtkToolbarPrivate *priv;
2935   GtkToolbarStyle style;
2936   
2937   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2938
2939   priv = toolbar->priv;
2940
2941   if (priv->style_set)
2942     {
2943       GtkSettings *settings = toolbar_get_settings (toolbar);
2944       
2945       if (settings)
2946         g_object_get (settings,
2947                       "gtk-toolbar-style", &style,
2948                       NULL);
2949       else
2950         style = DEFAULT_TOOLBAR_STYLE;
2951
2952       if (style != priv->style)
2953         g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2954
2955       priv->style_set = FALSE;
2956     }
2957 }
2958
2959 /**
2960  * gtk_toolbar_get_n_items:
2961  * @toolbar: a #GtkToolbar
2962  * 
2963  * Returns the number of items on the toolbar.
2964  * 
2965  * Return value: the number of items on the toolbar
2966  * 
2967  * Since: 2.4
2968  **/
2969 gint
2970 gtk_toolbar_get_n_items (GtkToolbar *toolbar)
2971 {
2972   GtkToolbarPrivate *priv;
2973
2974   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2975
2976   priv = toolbar->priv;
2977
2978   return physical_to_logical (toolbar, g_list_length (priv->content));
2979 }
2980
2981 /**
2982  * gtk_toolbar_get_nth_item:
2983  * @toolbar: a #GtkToolbar
2984  * @n: A position on the toolbar
2985  *
2986  * Returns the @n<!-- -->'th item on @toolbar, or %NULL if the
2987  * toolbar does not contain an @n<!-- -->'th item.
2988  *
2989  * Return value: (transfer none): The @n<!-- -->'th #GtkToolItem on @toolbar,
2990  *     or %NULL if there isn't an @n<!-- -->'th item.
2991  *
2992  * Since: 2.4
2993  **/
2994 GtkToolItem *
2995 gtk_toolbar_get_nth_item (GtkToolbar *toolbar,
2996                           gint        n)
2997 {
2998   GtkToolbarPrivate *priv;
2999   ToolbarContent *content;
3000   gint n_items;
3001   
3002   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
3003
3004   priv = toolbar->priv;
3005
3006   n_items = gtk_toolbar_get_n_items (toolbar);
3007   
3008   if (n < 0 || n >= n_items)
3009     return NULL;
3010
3011   content = g_list_nth_data (priv->content, logical_to_physical (toolbar, n));
3012   
3013   g_assert (content);
3014   g_assert (!toolbar_content_is_placeholder (content));
3015   
3016   return GTK_TOOL_ITEM (toolbar_content_get_widget (content));
3017 }
3018
3019 /**
3020  * gtk_toolbar_get_icon_size:
3021  * @toolbar: a #GtkToolbar
3022  *
3023  * Retrieves the icon size for the toolbar. See gtk_toolbar_set_icon_size().
3024  *
3025  * Return value: (type int): the current icon size for the icons on
3026  * the toolbar.
3027  **/
3028 GtkIconSize
3029 gtk_toolbar_get_icon_size (GtkToolbar *toolbar)
3030 {
3031   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_ICON_SIZE);
3032
3033   return toolbar->priv->icon_size;
3034 }
3035
3036 /**
3037  * gtk_toolbar_get_relief_style:
3038  * @toolbar: a #GtkToolbar
3039  * 
3040  * Returns the relief style of buttons on @toolbar. See
3041  * gtk_button_set_relief().
3042  * 
3043  * Return value: The relief style of buttons on @toolbar.
3044  * 
3045  * Since: 2.4
3046  **/
3047 GtkReliefStyle
3048 gtk_toolbar_get_relief_style (GtkToolbar *toolbar)
3049 {
3050   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_RELIEF_NONE);
3051   
3052   return get_button_relief (toolbar);
3053 }
3054
3055 /**
3056  * gtk_toolbar_set_show_arrow:
3057  * @toolbar: a #GtkToolbar
3058  * @show_arrow: Whether to show an overflow menu
3059  * 
3060  * Sets whether to show an overflow menu when
3061  * @toolbar doesn't have room for all items on it. If %TRUE,
3062  * items that there are not room are available through an
3063  * overflow menu.
3064  * 
3065  * Since: 2.4
3066  **/
3067 void
3068 gtk_toolbar_set_show_arrow (GtkToolbar *toolbar,
3069                             gboolean    show_arrow)
3070 {
3071   GtkToolbarPrivate *priv;
3072
3073   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3074
3075   priv = toolbar->priv;
3076
3077   show_arrow = show_arrow != FALSE;
3078   
3079   if (priv->show_arrow != show_arrow)
3080     {
3081       priv->show_arrow = show_arrow;
3082       
3083       if (!priv->show_arrow)
3084         gtk_widget_hide (priv->arrow_button);
3085       
3086       gtk_widget_queue_resize (GTK_WIDGET (toolbar));      
3087       g_object_notify (G_OBJECT (toolbar), "show-arrow");
3088     }
3089 }
3090
3091 /**
3092  * gtk_toolbar_get_show_arrow:
3093  * @toolbar: a #GtkToolbar
3094  * 
3095  * Returns whether the toolbar has an overflow menu.
3096  * See gtk_toolbar_set_show_arrow().
3097  * 
3098  * Return value: %TRUE if the toolbar has an overflow menu.
3099  * 
3100  * Since: 2.4
3101  **/
3102 gboolean
3103 gtk_toolbar_get_show_arrow (GtkToolbar *toolbar)
3104 {
3105   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
3106
3107   return toolbar->priv->show_arrow;
3108 }
3109
3110 /**
3111  * gtk_toolbar_get_drop_index:
3112  * @toolbar: a #GtkToolbar
3113  * @x: x coordinate of a point on the toolbar
3114  * @y: y coordinate of a point on the toolbar
3115  *
3116  * Returns the position corresponding to the indicated point on
3117  * @toolbar. This is useful when dragging items to the toolbar:
3118  * this function returns the position a new item should be
3119  * inserted.
3120  *
3121  * @x and @y are in @toolbar coordinates.
3122  * 
3123  * Return value: The position corresponding to the point (@x, @y) on the toolbar.
3124  * 
3125  * Since: 2.4
3126  **/
3127 gint
3128 gtk_toolbar_get_drop_index (GtkToolbar *toolbar,
3129                             gint        x,
3130                             gint        y)
3131 {
3132   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
3133   
3134   return physical_to_logical (toolbar, find_drop_index (toolbar, x, y));
3135 }
3136
3137 static void
3138 gtk_toolbar_dispose (GObject *object)
3139 {
3140   GtkToolbar *toolbar = GTK_TOOLBAR (object);
3141   GtkToolbarPrivate *priv = toolbar->priv;
3142
3143   if (priv->arrow_button)
3144     {
3145       gtk_widget_unparent (priv->arrow_button);
3146       priv->arrow_button = NULL;
3147     }
3148
3149   if (priv->menu)
3150     {
3151       g_signal_handlers_disconnect_by_func (priv->menu,
3152                                             menu_deactivated, toolbar);
3153       gtk_widget_destroy (GTK_WIDGET (priv->menu));
3154       priv->menu = NULL;
3155     }
3156
3157  G_OBJECT_CLASS (gtk_toolbar_parent_class)->dispose (object);
3158 }
3159
3160 static void
3161 gtk_toolbar_finalize (GObject *object)
3162 {
3163   GtkToolbar *toolbar = GTK_TOOLBAR (object);
3164   GtkToolbarPrivate *priv = toolbar->priv;
3165
3166   g_list_free_full (priv->content, (GDestroyNotify)toolbar_content_free);
3167
3168   g_timer_destroy (priv->timer);
3169
3170   if (priv->idle_id)
3171     g_source_remove (priv->idle_id);
3172
3173   G_OBJECT_CLASS (gtk_toolbar_parent_class)->finalize (object);
3174 }
3175
3176 /**
3177  * gtk_toolbar_set_icon_size:
3178  * @toolbar: A #GtkToolbar
3179  * @icon_size: (type int): The #GtkIconSize that stock icons in the
3180  *     toolbar shall have.
3181  *
3182  * This function sets the size of stock icons in the toolbar. You
3183  * can call it both before you add the icons and after they've been
3184  * added. The size you set will override user preferences for the default
3185  * icon size.
3186  * 
3187  * This should only be used for special-purpose toolbars, normal
3188  * application toolbars should respect the user preferences for the
3189  * size of icons.
3190  **/
3191 void
3192 gtk_toolbar_set_icon_size (GtkToolbar  *toolbar,
3193                            GtkIconSize  icon_size)
3194 {
3195   GtkToolbarPrivate *priv;
3196
3197   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3198   g_return_if_fail (icon_size != GTK_ICON_SIZE_INVALID);
3199
3200   priv = toolbar->priv;
3201
3202   if (!priv->icon_size_set)
3203     {
3204       priv->icon_size_set = TRUE;
3205       g_object_notify (G_OBJECT (toolbar), "icon-size-set");
3206     }
3207
3208   if (priv->icon_size == icon_size)
3209     return;
3210
3211   priv->icon_size = icon_size;
3212   g_object_notify (G_OBJECT (toolbar), "icon-size");
3213   
3214   gtk_toolbar_reconfigured (toolbar);
3215   
3216   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3217 }
3218
3219 /**
3220  * gtk_toolbar_unset_icon_size:
3221  * @toolbar: a #GtkToolbar
3222  * 
3223  * Unsets toolbar icon size set with gtk_toolbar_set_icon_size(), so that
3224  * user preferences will be used to determine the icon size.
3225  **/
3226 void
3227 gtk_toolbar_unset_icon_size (GtkToolbar *toolbar)
3228 {
3229   GtkToolbarPrivate *priv;
3230   GtkIconSize size;
3231
3232   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3233
3234   priv = toolbar->priv;
3235
3236   if (priv->icon_size_set)
3237     {
3238       GtkSettings *settings = toolbar_get_settings (toolbar);
3239       
3240       if (settings)
3241         {
3242           g_object_get (settings,
3243                         "gtk-toolbar-icon-size", &size,
3244                         NULL);
3245         }
3246       else
3247         size = DEFAULT_ICON_SIZE;
3248
3249       if (size != priv->icon_size)
3250         {
3251           gtk_toolbar_set_icon_size (toolbar, size);
3252           g_object_notify (G_OBJECT (toolbar), "icon-size");      
3253         }
3254
3255       priv->icon_size_set = FALSE;
3256       g_object_notify (G_OBJECT (toolbar), "icon-size-set");      
3257     }
3258 }
3259
3260 /*
3261  * ToolbarContent methods
3262  */
3263 typedef enum {
3264   UNKNOWN,
3265   YES,
3266   NO
3267 } TriState;
3268
3269 struct _ToolbarContent
3270 {
3271   ItemState      state;
3272
3273   GtkToolItem   *item;
3274   GtkAllocation  allocation;
3275   GtkAllocation  start_allocation;
3276   GtkAllocation  goal_allocation;
3277   guint          is_placeholder : 1;
3278   guint          disappearing : 1;
3279   guint          has_menu : 2;
3280 };
3281
3282 static void
3283 toolbar_item_visiblity_notify_cb (GObject *obj,
3284                                   GParamSpec *pspec,
3285                                   gpointer user_data)
3286 {
3287   GtkToolbar *toolbar = user_data;
3288
3289   gtk_toolbar_invalidate_order (toolbar);
3290 }
3291
3292 static ToolbarContent *
3293 toolbar_content_new_tool_item (GtkToolbar  *toolbar,
3294                                GtkToolItem *item,
3295                                gboolean     is_placeholder,
3296                                gint         pos)
3297 {
3298   GtkToolbarPrivate *priv = toolbar->priv;
3299   ToolbarContent *content;
3300
3301   content = g_slice_new0 (ToolbarContent);
3302   
3303   content->state = NOT_ALLOCATED;
3304   content->item = item;
3305   content->is_placeholder = is_placeholder;
3306
3307   priv->content = g_list_insert (priv->content, content, pos);
3308
3309   gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar));
3310   gtk_toolbar_invalidate_order (toolbar);
3311
3312   g_signal_connect (content->item, "notify::visible",
3313                     G_CALLBACK (toolbar_item_visiblity_notify_cb), toolbar);
3314
3315   if (!is_placeholder)
3316     {
3317       priv->num_children++;
3318
3319       gtk_toolbar_stop_sliding (toolbar);
3320     }
3321
3322   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3323   priv->need_rebuild = TRUE;
3324   
3325   return content;
3326 }
3327
3328 static void
3329 toolbar_content_remove (ToolbarContent *content,
3330                         GtkToolbar     *toolbar)
3331 {
3332   GtkToolbarPrivate *priv = toolbar->priv;
3333
3334   gtk_toolbar_invalidate_order (toolbar);
3335   gtk_widget_unparent (GTK_WIDGET (content->item));
3336
3337   g_signal_handlers_disconnect_by_func (content->item,
3338                                         toolbar_item_visiblity_notify_cb,
3339                                         toolbar);
3340
3341   priv->content = g_list_remove (priv->content, content);
3342
3343   if (!toolbar_content_is_placeholder (content))
3344     priv->num_children--;
3345
3346   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3347   priv->need_rebuild = TRUE;
3348 }
3349
3350 static void
3351 toolbar_content_free (ToolbarContent *content)
3352 {
3353   g_slice_free (ToolbarContent, content);
3354 }
3355
3356 static gint
3357 calculate_max_homogeneous_pixels (GtkWidget *widget)
3358 {
3359   PangoContext *context;
3360   PangoFontMetrics *metrics;
3361   const PangoFontDescription *font_desc;
3362   GtkStyleContext *style_context;
3363   GtkStateFlags state;
3364   gint char_width;
3365   
3366   context = gtk_widget_get_pango_context (widget);
3367   style_context = gtk_widget_get_style_context (widget);
3368   state = gtk_widget_get_state_flags (widget);
3369
3370   font_desc = gtk_style_context_get_font (style_context, state);
3371
3372   metrics = pango_context_get_metrics (context, font_desc,
3373                                        pango_context_get_language (context));
3374   char_width = pango_font_metrics_get_approximate_char_width (metrics);
3375   pango_font_metrics_unref (metrics);
3376   
3377   return PANGO_PIXELS (MAX_HOMOGENEOUS_N_CHARS * char_width);
3378 }
3379
3380 static void
3381 toolbar_content_draw (ToolbarContent *content,
3382                       GtkContainer   *container,
3383                       cairo_t        *cr)
3384 {
3385   GtkWidget *widget;
3386
3387   if (content->is_placeholder)
3388     return;
3389   
3390   widget = GTK_WIDGET (content->item);
3391
3392   if (widget)
3393     gtk_container_propagate_draw (container, widget, cr);
3394 }
3395
3396 static gboolean
3397 toolbar_content_visible (ToolbarContent *content,
3398                          GtkToolbar     *toolbar)
3399 {
3400   GtkToolbarPrivate *priv = toolbar->priv;
3401   GtkToolItem *item;
3402
3403   item = content->item;
3404
3405   if (!gtk_widget_get_visible (GTK_WIDGET (item)))
3406     return FALSE;
3407
3408   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
3409       gtk_tool_item_get_visible_horizontal (item))
3410     return TRUE;
3411
3412   if (priv->orientation == GTK_ORIENTATION_VERTICAL &&
3413       gtk_tool_item_get_visible_vertical (item))
3414     return TRUE;
3415       
3416   return FALSE;
3417 }
3418
3419 static void
3420 toolbar_content_size_request (ToolbarContent *content,
3421                               GtkToolbar     *toolbar,
3422                               GtkRequisition *requisition)
3423 {
3424   gtk_widget_get_preferred_size (GTK_WIDGET (content->item),
3425                                  requisition, NULL);
3426   if (content->is_placeholder &&
3427       content->disappearing)
3428     {
3429       requisition->width = 0;
3430       requisition->height = 0;
3431     }
3432 }
3433
3434 static gboolean
3435 toolbar_content_is_homogeneous (ToolbarContent *content,
3436                                 GtkToolbar     *toolbar)
3437 {
3438   GtkToolbarPrivate *priv = toolbar->priv;
3439   GtkRequisition requisition;
3440   gboolean result;
3441   
3442   if (priv->max_homogeneous_pixels < 0)
3443     {
3444       priv->max_homogeneous_pixels =
3445         calculate_max_homogeneous_pixels (GTK_WIDGET (toolbar));
3446     }
3447   
3448   toolbar_content_size_request (content, toolbar, &requisition);
3449   
3450   if (requisition.width > priv->max_homogeneous_pixels)
3451     return FALSE;
3452
3453   result = gtk_tool_item_get_homogeneous (content->item) &&
3454            !GTK_IS_SEPARATOR_TOOL_ITEM (content->item);
3455
3456   if (gtk_tool_item_get_is_important (content->item) &&
3457       priv->style == GTK_TOOLBAR_BOTH_HORIZ &&
3458       priv->orientation == GTK_ORIENTATION_HORIZONTAL)
3459     {
3460       result = FALSE;
3461     }
3462
3463   return result;
3464 }
3465
3466 static gboolean
3467 toolbar_content_is_placeholder (ToolbarContent *content)
3468 {
3469   if (content->is_placeholder)
3470     return TRUE;
3471   
3472   return FALSE;
3473 }
3474
3475 static gboolean
3476 toolbar_content_disappearing (ToolbarContent *content)
3477 {
3478   if (content->disappearing)
3479     return TRUE;
3480   
3481   return FALSE;
3482 }
3483
3484 static ItemState
3485 toolbar_content_get_state (ToolbarContent *content)
3486 {
3487   return content->state;
3488 }
3489
3490 static gboolean
3491 toolbar_content_child_visible (ToolbarContent *content)
3492 {
3493   return gtk_widget_get_child_visible (GTK_WIDGET (content->item));
3494 }
3495
3496 static void
3497 toolbar_content_get_goal_allocation (ToolbarContent *content,
3498                                      GtkAllocation  *allocation)
3499 {
3500   *allocation = content->goal_allocation;
3501 }
3502
3503 static void
3504 toolbar_content_get_allocation (ToolbarContent *content,
3505                                 GtkAllocation  *allocation)
3506 {
3507   *allocation = content->allocation;
3508 }
3509
3510 static void
3511 toolbar_content_set_start_allocation (ToolbarContent *content,
3512                                       GtkAllocation  *allocation)
3513 {
3514   content->start_allocation = *allocation;
3515 }
3516
3517 static gboolean
3518 toolbar_content_get_expand (ToolbarContent *content)
3519 {
3520   if (!content->disappearing &&
3521       gtk_tool_item_get_expand (content->item))
3522     return TRUE;
3523
3524   return FALSE;
3525 }
3526
3527 static void
3528 toolbar_content_set_goal_allocation (ToolbarContent *content,
3529                                      GtkAllocation  *allocation)
3530 {
3531   content->goal_allocation = *allocation;
3532 }
3533
3534 static void
3535 toolbar_content_set_child_visible (ToolbarContent *content,
3536                                    GtkToolbar     *toolbar,
3537                                    gboolean        visible)
3538 {
3539   gtk_widget_set_child_visible (GTK_WIDGET (content->item),
3540                                 visible);
3541 }
3542
3543 static void
3544 toolbar_content_get_start_allocation (ToolbarContent *content,
3545                                       GtkAllocation  *start_allocation)
3546 {
3547   *start_allocation = content->start_allocation;
3548 }
3549
3550 static void
3551 toolbar_content_size_allocate (ToolbarContent *content,
3552                                GtkAllocation  *allocation)
3553 {
3554   content->allocation = *allocation;
3555   gtk_widget_size_allocate (GTK_WIDGET (content->item),
3556                             allocation);
3557 }
3558
3559 static void
3560 toolbar_content_set_state (ToolbarContent *content,
3561                            ItemState       state)
3562 {
3563   content->state = state;
3564 }
3565
3566 static GtkWidget *
3567 toolbar_content_get_widget (ToolbarContent *content)
3568 {
3569   return GTK_WIDGET (content->item);
3570 }
3571
3572
3573 static void
3574 toolbar_content_set_disappearing (ToolbarContent *content,
3575                                   gboolean        disappearing)
3576 {
3577   content->disappearing = disappearing;
3578 }
3579
3580 static void
3581 toolbar_content_set_size_request (ToolbarContent *content,
3582                                   gint            width,
3583                                   gint            height)
3584 {
3585   gtk_widget_set_size_request (GTK_WIDGET (content->item),
3586                                width, height);
3587 }
3588
3589 static void
3590 toolbar_content_toolbar_reconfigured (ToolbarContent *content,
3591                                       GtkToolbar     *toolbar)
3592 {
3593   gtk_tool_item_toolbar_reconfigured (content->item);
3594 }
3595
3596 static GtkWidget *
3597 toolbar_content_retrieve_menu_item (ToolbarContent *content)
3598 {
3599   return gtk_tool_item_retrieve_proxy_menu_item (content->item);
3600 }
3601
3602 static gboolean
3603 toolbar_content_has_proxy_menu_item (ToolbarContent *content)
3604 {
3605   GtkWidget *menu_item;
3606
3607   if (content->has_menu == YES)
3608     return TRUE;
3609   else if (content->has_menu == NO)
3610     return FALSE;
3611
3612   menu_item = toolbar_content_retrieve_menu_item (content);
3613
3614   content->has_menu = menu_item? YES : NO;
3615
3616   return menu_item != NULL;
3617 }
3618
3619 static void
3620 toolbar_content_set_unknown_menu_status (ToolbarContent *content)
3621 {
3622   content->has_menu = UNKNOWN;
3623 }
3624
3625 static gboolean
3626 toolbar_content_is_separator (ToolbarContent *content)
3627 {
3628   return GTK_IS_SEPARATOR_TOOL_ITEM (content->item);
3629 }
3630
3631 static void
3632 toolbar_content_set_expand (ToolbarContent *content,
3633                             gboolean        expand)
3634 {
3635   gtk_tool_item_set_expand (content->item, expand);
3636 }
3637
3638 static void
3639 toolbar_content_show_all (ToolbarContent  *content)
3640 {
3641   GtkWidget *widget;
3642   
3643   widget = toolbar_content_get_widget (content);
3644   if (widget)
3645     gtk_widget_show_all (widget);
3646 }
3647
3648 /*
3649  * Getters
3650  */
3651 static GtkReliefStyle
3652 get_button_relief (GtkToolbar *toolbar)
3653 {
3654   GtkReliefStyle button_relief = GTK_RELIEF_NORMAL;
3655
3656   gtk_widget_style_get (GTK_WIDGET (toolbar),
3657                         "button-relief", &button_relief,
3658                         NULL);
3659   
3660   return button_relief;
3661 }
3662
3663 static gint
3664 get_max_child_expand (GtkToolbar *toolbar)
3665 {
3666   gint mexpand = G_MAXINT;
3667
3668   gtk_widget_style_get (GTK_WIDGET (toolbar),
3669                         "max-child-expand", &mexpand,
3670                         NULL);
3671   return mexpand;
3672 }
3673
3674 static GtkShadowType
3675 get_shadow_type (GtkToolbar *toolbar)
3676 {
3677   GtkShadowType shadow_type;
3678   
3679   gtk_widget_style_get (GTK_WIDGET (toolbar),
3680                         "shadow-type", &shadow_type,
3681                         NULL);
3682   
3683   return shadow_type;
3684 }
3685
3686 /* GTK+ internal methods */
3687
3688 gint
3689 _gtk_toolbar_get_default_space_size (void)
3690 {
3691   return DEFAULT_SPACE_SIZE;
3692 }
3693
3694 void
3695 _gtk_toolbar_paint_space_line (GtkWidget           *widget,
3696                                GtkToolbar          *toolbar,
3697                                cairo_t             *cr)
3698 {
3699   GtkOrientation orientation;
3700   GtkStyleContext *context;
3701   GtkStateFlags state;
3702   GtkBorder padding;
3703   gint width, height;
3704   const gdouble start_fraction = (SPACE_LINE_START / SPACE_LINE_DIVISION);
3705   const gdouble end_fraction = (SPACE_LINE_END / SPACE_LINE_DIVISION);
3706
3707   g_return_if_fail (GTK_IS_WIDGET (widget));
3708
3709   orientation = toolbar ? toolbar->priv->orientation : GTK_ORIENTATION_HORIZONTAL;
3710
3711   context = gtk_widget_get_style_context (widget);
3712   state = gtk_widget_get_state_flags (widget);
3713   width = gtk_widget_get_allocated_width (widget);
3714   height = gtk_widget_get_allocated_height (widget);
3715   gtk_style_context_get_padding (context, state, &padding);
3716
3717   if (orientation == GTK_ORIENTATION_HORIZONTAL)
3718     {
3719       gboolean wide_separators;
3720       gint     separator_width;
3721
3722       gtk_widget_style_get (widget,
3723                             "wide-separators", &wide_separators,
3724                             "separator-width", &separator_width,
3725                             NULL);
3726
3727       if (wide_separators)
3728         gtk_render_frame (context, cr,
3729                           (width - separator_width) / 2,
3730                           height * start_fraction,
3731                           separator_width,
3732                           height * (end_fraction - start_fraction));
3733       else
3734         gtk_render_line (context, cr,
3735                          (width - padding.left) / 2,
3736                          height * start_fraction,
3737                          (width - padding.left) / 2,
3738                          height * end_fraction);
3739     }
3740   else
3741     {
3742       gboolean wide_separators;
3743       gint     separator_height;
3744
3745       gtk_widget_style_get (widget,
3746                             "wide-separators",  &wide_separators,
3747                             "separator-height", &separator_height,
3748                             NULL);
3749
3750       if (wide_separators)
3751         gtk_render_frame (context, cr,
3752                           width * start_fraction,
3753                           (height - separator_height) / 2,
3754                           width * (end_fraction - start_fraction),
3755                           separator_height);
3756       else
3757         gtk_render_line (context, cr,
3758                          width * start_fraction,
3759                          (height - padding.top) / 2,
3760                          width * end_fraction,
3761                          (height - padding.top) / 2);
3762     }
3763 }
3764
3765 gchar *
3766 _gtk_toolbar_elide_underscores (const gchar *original)
3767 {
3768   gchar *q, *result;
3769   const gchar *p, *end;
3770   gsize len;
3771   gboolean last_underscore;
3772   
3773   if (!original)
3774     return NULL;
3775
3776   len = strlen (original);
3777   q = result = g_malloc (len + 1);
3778   last_underscore = FALSE;
3779   
3780   end = original + len;
3781   for (p = original; p < end; p++)
3782     {
3783       if (!last_underscore && *p == '_')
3784         last_underscore = TRUE;
3785       else
3786         {
3787           last_underscore = FALSE;
3788           if (original + 2 <= p && p + 1 <= end && 
3789               p[-2] == '(' && p[-1] == '_' && p[0] != '_' && p[1] == ')')
3790             {
3791               q--;
3792               *q = '\0';
3793               p++;
3794             }
3795           else
3796             *q++ = *p;
3797         }
3798     }
3799
3800   if (last_underscore)
3801     *q++ = '_';
3802   
3803   *q = '\0';
3804   
3805   return result;
3806 }
3807
3808 static GtkIconSize
3809 toolbar_get_icon_size (GtkToolShell *shell)
3810 {
3811   GtkToolbar *toolbar = GTK_TOOLBAR (shell);
3812   GtkToolbarPrivate *priv = toolbar->priv;
3813
3814   return priv->icon_size;
3815 }
3816
3817 static GtkOrientation
3818 toolbar_get_orientation (GtkToolShell *shell)
3819 {
3820   GtkToolbar *toolbar = GTK_TOOLBAR (shell);
3821   GtkToolbarPrivate *priv = toolbar->priv;
3822
3823   return priv->orientation;
3824 }
3825
3826 static GtkToolbarStyle
3827 toolbar_get_style (GtkToolShell *shell)
3828 {
3829   GtkToolbar *toolbar = GTK_TOOLBAR (shell);
3830   GtkToolbarPrivate *priv = toolbar->priv;
3831
3832   return priv->style;
3833 }
3834
3835 static GtkReliefStyle
3836 toolbar_get_relief_style (GtkToolShell *shell)
3837 {
3838   return get_button_relief (GTK_TOOLBAR (shell));
3839 }
3840
3841 static void
3842 toolbar_rebuild_menu (GtkToolShell *shell)
3843 {
3844   GtkToolbar *toolbar = GTK_TOOLBAR (shell);
3845   GtkToolbarPrivate *priv = toolbar->priv;
3846   GList *list;
3847
3848   priv->need_rebuild = TRUE;
3849
3850   for (list = priv->content; list != NULL; list = list->next)
3851     {
3852       ToolbarContent *content = list->data;
3853
3854       toolbar_content_set_unknown_menu_status (content);
3855     }
3856   
3857   gtk_widget_queue_resize (GTK_WIDGET (shell));
3858 }
3859
3860 typedef struct _CountingData CountingData;
3861 struct _CountingData {
3862   GtkWidget *widget;
3863   gboolean found;
3864   guint before;
3865   guint after;
3866 };
3867
3868 static void
3869 count_widget_position (GtkWidget *widget,
3870                        gpointer   data)
3871 {
3872   CountingData *count = data;
3873
3874   if (!gtk_widget_get_visible (widget))
3875     return;
3876
3877   if (count->widget == widget)
3878     count->found = TRUE;
3879   else if (count->found)
3880     count->after++;
3881   else
3882     count->before++;
3883 }
3884
3885 static guint
3886 gtk_toolbar_get_visible_position (GtkToolbar *toolbar,
3887                                   GtkWidget  *child)
3888 {
3889   CountingData count = { child, FALSE, 0, 0 };
3890
3891   if (child == (GtkWidget*)toolbar->priv->highlight_tool_item)
3892     return 0;
3893
3894   /* foreach iterates in visible order */
3895   gtk_container_forall (GTK_CONTAINER (toolbar),
3896                         count_widget_position,
3897                         &count);
3898
3899   g_assert (count.found);
3900
3901   if (toolbar->priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
3902       gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
3903     return count.after;
3904
3905   return count.before;
3906 }
3907
3908 static void
3909 add_widget_to_path (gpointer data,
3910                     gpointer user_data)
3911 {
3912   GtkWidget *widget = data;
3913   GtkWidgetPath *path = user_data;
3914
3915   if (gtk_widget_get_visible (widget))
3916     gtk_widget_path_append_for_widget (path, widget);
3917 }
3918
3919 static GtkWidgetPath *
3920 gtk_toolbar_get_path_for_child (GtkContainer *container,
3921                                 GtkWidget    *child)
3922 {
3923   GtkWidgetPath *path;
3924   GtkToolbar *toolbar;
3925   GtkToolbarPrivate *priv;
3926   GtkWidgetPath *sibling_path;
3927   gint vis_index;
3928   GList *children;
3929
3930   toolbar = GTK_TOOLBAR (container);
3931   priv = toolbar->priv;
3932
3933   /* build a path for all the visible children;
3934    * get_children works in visible order
3935    */
3936   sibling_path = gtk_widget_path_new ();
3937   children = _gtk_container_get_all_children (container);
3938
3939   if (priv->orientation != GTK_ORIENTATION_HORIZONTAL ||
3940       gtk_widget_get_direction (GTK_WIDGET (toolbar)) != GTK_TEXT_DIR_RTL)
3941     children = g_list_reverse (children);
3942
3943   g_list_foreach (children, add_widget_to_path, sibling_path);
3944   g_list_free (children);
3945
3946   path = _gtk_widget_create_path (GTK_WIDGET (container));
3947   if (gtk_widget_get_visible (child))
3948     {
3949       vis_index = gtk_toolbar_get_visible_position (toolbar, child);
3950
3951       if (vis_index < gtk_widget_path_length (sibling_path))
3952         gtk_widget_path_append_with_siblings (path,
3953                                               sibling_path,
3954                                               vis_index);
3955       else
3956         gtk_widget_path_append_for_widget (path, child);
3957     }
3958   else
3959     gtk_widget_path_append_for_widget (path, child);
3960
3961   gtk_widget_path_unref (sibling_path);
3962   return path;
3963 }
3964
3965 static void
3966 gtk_toolbar_invalidate_order_foreach (GtkWidget *widget)
3967 {
3968   _gtk_widget_invalidate_style_context (widget, GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_SIBLING_POSITION);
3969 }
3970
3971 static void
3972 gtk_toolbar_invalidate_order (GtkToolbar *toolbar)
3973 {
3974   gtk_container_forall (GTK_CONTAINER (toolbar),
3975                         (GtkCallback) gtk_toolbar_invalidate_order_foreach,
3976                         NULL);
3977 }
3978
3979 static void
3980 gtk_toolbar_direction_changed (GtkWidget        *widget,
3981                                GtkTextDirection  previous_direction)
3982 {
3983   GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->direction_changed (widget, previous_direction);
3984
3985   gtk_toolbar_invalidate_order (GTK_TOOLBAR (widget));
3986 }
3987