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