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