]> Pileus Git - ~andy/gtk/blob - gtk/gtktoolbar.c
Use gtk_size_request_get_size() instead deprecated gtk_widget_get_child_requisition()
[~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_widget_size_request (priv->arrow_button, &arrow_requisition);
932       
933       if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
934         long_req = arrow_requisition.width;
935       else
936         long_req = arrow_requisition.height;
937       
938       /* There is no point requesting space for the arrow if that would take
939        * up more space than all the items combined
940        */
941       long_req = MIN (long_req, pack_front_size);
942     }
943   else
944     {
945       arrow_requisition.height = 0;
946       arrow_requisition.width = 0;
947       
948       long_req = pack_front_size;
949     }
950   
951   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
952     {
953       requisition->width = long_req;
954       requisition->height = MAX (max_child_height, arrow_requisition.height);
955     }
956   else
957     {
958       requisition->height = long_req;
959       requisition->width = MAX (max_child_width, arrow_requisition.width);
960     }
961   
962   /* Extra spacing */
963   ipadding = get_internal_padding (toolbar);
964
965   border_width = gtk_container_get_border_width (GTK_CONTAINER (toolbar));
966   requisition->width += 2 * (ipadding + border_width);
967   requisition->height += 2 * (ipadding + border_width);
968   
969   if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
970     {
971       GtkStyle *style;
972
973       style = gtk_widget_get_style (widget);
974       requisition->width += 2 * style->xthickness;
975       requisition->height += 2 * style->ythickness;
976     }
977   
978   priv->button_maxw = max_homogeneous_child_width;
979   priv->button_maxh = max_homogeneous_child_height;
980 }
981
982 static gint
983 position (GtkToolbar *toolbar,
984           gint        from,
985           gint        to,
986           gdouble     elapsed)
987 {
988   GtkToolbarPrivate *priv = toolbar->priv;
989   gint n_pixels;
990
991   if (!priv->animation)
992     return to;
993
994   if (elapsed <= ACCEL_THRESHOLD)
995     {
996       n_pixels = SLIDE_SPEED * elapsed;
997     }
998   else
999     {
1000       /* The formula is a second degree polynomial in
1001        * @elapsed that has the line SLIDE_SPEED * @elapsed
1002        * as tangent for @elapsed == ACCEL_THRESHOLD.
1003        * This makes @n_pixels a smooth function of elapsed time.
1004        */
1005       n_pixels = (SLIDE_SPEED / ACCEL_THRESHOLD) * elapsed * elapsed -
1006         SLIDE_SPEED * elapsed + SLIDE_SPEED * ACCEL_THRESHOLD;
1007     }
1008
1009   if (to > from)
1010     return MIN (from + n_pixels, to);
1011   else
1012     return MAX (from - n_pixels, to);
1013 }
1014
1015 static void
1016 compute_intermediate_allocation (GtkToolbar          *toolbar,
1017                                  const GtkAllocation *start,
1018                                  const GtkAllocation *goal,
1019                                  GtkAllocation       *intermediate)
1020 {
1021   GtkToolbarPrivate *priv = toolbar->priv;
1022   gdouble elapsed = g_timer_elapsed (priv->timer, NULL);
1023
1024   intermediate->x      = position (toolbar, start->x, goal->x, elapsed);
1025   intermediate->y      = position (toolbar, start->y, goal->y, elapsed);
1026   intermediate->width  = position (toolbar, start->x + start->width,
1027                                    goal->x + goal->width,
1028                                    elapsed) - intermediate->x;
1029   intermediate->height = position (toolbar, start->y + start->height,
1030                                    goal->y + goal->height,
1031                                    elapsed) - intermediate->y;
1032 }
1033
1034 static void
1035 fixup_allocation_for_rtl (gint           total_size,
1036                           GtkAllocation *allocation)
1037 {
1038   allocation->x += (total_size - (2 * allocation->x + allocation->width));
1039 }
1040
1041 static void
1042 fixup_allocation_for_vertical (GtkAllocation *allocation)
1043 {
1044   gint tmp;
1045   
1046   tmp = allocation->x;
1047   allocation->x = allocation->y;
1048   allocation->y = tmp;
1049   
1050   tmp = allocation->width;
1051   allocation->width = allocation->height;
1052   allocation->height = tmp;
1053 }
1054
1055 static gint
1056 get_item_size (GtkToolbar     *toolbar,
1057                ToolbarContent *content)
1058 {
1059   GtkToolbarPrivate *priv = toolbar->priv;
1060   GtkRequisition requisition;
1061   
1062   toolbar_content_size_request (content, toolbar, &requisition);
1063
1064   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1065     {
1066       if (toolbar_content_is_homogeneous (content, toolbar))
1067         return priv->button_maxw;
1068       else
1069         return requisition.width;
1070     }
1071   else
1072     {
1073       if (toolbar_content_is_homogeneous (content, toolbar))
1074         return priv->button_maxh;
1075       else
1076         return requisition.height;
1077     }
1078 }
1079
1080 static gboolean
1081 slide_idle_handler (gpointer data)
1082 {
1083   GtkToolbar *toolbar = GTK_TOOLBAR (data);
1084   GtkToolbarPrivate *priv = toolbar->priv;
1085   GList *list;
1086
1087   if (priv->need_sync)
1088     {
1089       gdk_flush ();
1090       priv->need_sync = FALSE;
1091     }
1092   
1093   for (list = priv->content; list != NULL; list = list->next)
1094     {
1095       ToolbarContent *content = list->data;
1096       ItemState state;
1097       GtkAllocation goal_allocation;
1098       GtkAllocation allocation;
1099       gboolean cont;
1100
1101       state = toolbar_content_get_state (content);
1102       toolbar_content_get_goal_allocation (content, &goal_allocation);
1103       toolbar_content_get_allocation (content, &allocation);
1104       
1105       cont = FALSE;
1106       
1107       if (state == NOT_ALLOCATED)
1108         {
1109           /* an unallocated item means that size allocate has to
1110            * called at least once more
1111            */
1112           cont = TRUE;
1113         }
1114
1115       /* An invisible item with a goal allocation of
1116        * 0 is already at its goal.
1117        */
1118       if ((state == NORMAL || state == OVERFLOWN) &&
1119           ((goal_allocation.width != 0 &&
1120             goal_allocation.height != 0) ||
1121            toolbar_content_child_visible (content)))
1122         {
1123           if ((goal_allocation.x != allocation.x ||
1124                goal_allocation.y != allocation.y ||
1125                goal_allocation.width != allocation.width ||
1126                goal_allocation.height != allocation.height))
1127             {
1128               /* An item is not in its right position yet. Note
1129                * that OVERFLOWN items do get an allocation in
1130                * gtk_toolbar_size_allocate(). This way you can see
1131                * them slide back in when you drag an item off the
1132                * toolbar.
1133                */
1134               cont = TRUE;
1135             }
1136         }
1137
1138       if (toolbar_content_is_placeholder (content) &&
1139           toolbar_content_disappearing (content) &&
1140           toolbar_content_child_visible (content))
1141         {
1142           /* A disappearing placeholder is still visible.
1143            */
1144              
1145           cont = TRUE;
1146         }
1147       
1148       if (cont)
1149         {
1150           gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1151           
1152           return TRUE;
1153         }
1154     }
1155   
1156   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1157
1158   priv->is_sliding = FALSE;
1159   priv->idle_id = 0;
1160
1161   return FALSE;
1162 }
1163
1164 static gboolean
1165 rect_within (GtkAllocation *a1,
1166              GtkAllocation *a2)
1167 {
1168   return (a1->x >= a2->x                         &&
1169           a1->x + a1->width <= a2->x + a2->width &&
1170           a1->y >= a2->y                         &&
1171           a1->y + a1->height <= a2->y + a2->height);
1172 }
1173
1174 static void
1175 gtk_toolbar_begin_sliding (GtkToolbar *toolbar)
1176 {
1177   GtkAllocation allocation;
1178   GtkWidget *widget = GTK_WIDGET (toolbar);
1179   GtkToolbarPrivate *priv = toolbar->priv;
1180   GtkStyle *style;
1181   GList *list;
1182   gint cur_x;
1183   gint cur_y;
1184   gint border_width;
1185   gboolean rtl;
1186   gboolean vertical;
1187   
1188   /* Start the sliding. This function copies the allocation of every
1189    * item into content->start_allocation. For items that haven't
1190    * been allocated yet, we calculate their position and save that
1191    * in start_allocatino along with zero width and zero height.
1192    *
1193    * FIXME: It would be nice if we could share this code with
1194    * the equivalent in gtk_widget_size_allocate().
1195    */
1196   priv->is_sliding = TRUE;
1197   
1198   if (!priv->idle_id)
1199     priv->idle_id = gdk_threads_add_idle (slide_idle_handler, toolbar);
1200
1201   gtk_widget_get_allocation (widget, &allocation);
1202   style = gtk_widget_get_style (widget);
1203
1204   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1205   vertical = (priv->orientation == GTK_ORIENTATION_VERTICAL);
1206   border_width = get_internal_padding (toolbar) + gtk_container_get_border_width (GTK_CONTAINER (toolbar));
1207   
1208   if (rtl)
1209     {
1210       cur_x = allocation.width - border_width - style->xthickness;
1211       cur_y = allocation.height - border_width - style->ythickness;
1212     }
1213   else
1214     {
1215       cur_x = border_width + style->xthickness;
1216       cur_y = border_width + style->ythickness;
1217     }
1218
1219   cur_x += allocation.x;
1220   cur_y += allocation.y;
1221
1222   for (list = priv->content; list != NULL; list = list->next)
1223     {
1224       ToolbarContent *content = list->data;
1225       GtkAllocation new_start_allocation;
1226       GtkAllocation item_allocation;
1227       ItemState state;
1228       
1229       state = toolbar_content_get_state (content);
1230       toolbar_content_get_allocation (content, &item_allocation);
1231       
1232       if ((state == NORMAL &&
1233            rect_within (&item_allocation, &allocation)) ||
1234           state == OVERFLOWN)
1235         {
1236           new_start_allocation = item_allocation;
1237         }
1238       else
1239         {
1240           new_start_allocation.x = cur_x;
1241           new_start_allocation.y = cur_y;
1242           
1243           if (vertical)
1244             {
1245               new_start_allocation.width = allocation.width -
1246                                            2 * border_width - 2 * style->xthickness;
1247               new_start_allocation.height = 0;
1248             }
1249           else
1250             {
1251               new_start_allocation.width = 0;
1252               new_start_allocation.height = allocation.height -
1253                                             2 * border_width - 2 * style->ythickness;
1254             }
1255         }
1256       
1257       if (vertical)
1258         cur_y = new_start_allocation.y + new_start_allocation.height;
1259       else if (rtl)
1260         cur_x = new_start_allocation.x;
1261       else
1262         cur_x = new_start_allocation.x + new_start_allocation.width;
1263       
1264       toolbar_content_set_start_allocation (content, &new_start_allocation);
1265     }
1266
1267   /* This resize will run before the first idle handler. This
1268    * will make sure that items get the right goal allocation
1269    * so that the idle handler will not immediately return
1270    * FALSE
1271    */
1272   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1273   g_timer_reset (priv->timer);
1274 }
1275
1276 static void
1277 gtk_toolbar_stop_sliding (GtkToolbar *toolbar)
1278 {
1279   GtkToolbarPrivate *priv = toolbar->priv;
1280
1281   if (priv->is_sliding)
1282     {
1283       GList *list;
1284       
1285       priv->is_sliding = FALSE;
1286       
1287       if (priv->idle_id)
1288         {
1289           g_source_remove (priv->idle_id);
1290           priv->idle_id = 0;
1291         }
1292       
1293       list = priv->content;
1294       while (list)
1295         {
1296           ToolbarContent *content = list->data;
1297           list = list->next;
1298
1299           if (toolbar_content_is_placeholder (content))
1300             {
1301               toolbar_content_remove (content, toolbar);
1302               toolbar_content_free (content);
1303             }
1304         }
1305       
1306       gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1307     }
1308 }
1309
1310 static void
1311 remove_item (GtkWidget *menu_item,
1312              gpointer   data)
1313 {
1314   gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (menu_item)),
1315                         menu_item);
1316 }
1317
1318 static void
1319 menu_deactivated (GtkWidget  *menu,
1320                   GtkToolbar *toolbar)
1321 {
1322   GtkToolbarPrivate *priv = toolbar->priv;
1323
1324   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->arrow_button), FALSE);
1325 }
1326
1327 static void
1328 menu_detached (GtkWidget  *widget,
1329                GtkMenu    *menu)
1330 {
1331   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1332   GtkToolbarPrivate *priv = toolbar->priv;
1333
1334   priv->menu = NULL;
1335 }
1336
1337 static void
1338 rebuild_menu (GtkToolbar *toolbar)
1339 {
1340   GtkToolbarPrivate *priv = toolbar->priv;
1341   GList *list, *children;
1342
1343   if (!priv->menu)
1344     {
1345       priv->menu = GTK_MENU (gtk_menu_new());
1346       gtk_menu_attach_to_widget (priv->menu,
1347                                  GTK_WIDGET (toolbar),
1348                                  menu_detached);
1349
1350       g_signal_connect (priv->menu, "deactivate",
1351                         G_CALLBACK (menu_deactivated), toolbar);
1352     }
1353
1354   gtk_container_foreach (GTK_CONTAINER (priv->menu), remove_item, NULL);
1355   
1356   for (list = priv->content; list != NULL; list = list->next)
1357     {
1358       ToolbarContent *content = list->data;
1359       
1360       if (toolbar_content_get_state (content) == OVERFLOWN &&
1361           !toolbar_content_is_placeholder (content))
1362         {
1363           GtkWidget *menu_item = toolbar_content_retrieve_menu_item (content);
1364           
1365           if (menu_item)
1366             {
1367               g_assert (GTK_IS_MENU_ITEM (menu_item));
1368               gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menu_item);
1369             }
1370         }
1371     }
1372
1373   /* Remove leading and trailing separator items */
1374   children = gtk_container_get_children (GTK_CONTAINER (priv->menu));
1375   
1376   list = children;
1377   while (list && GTK_IS_SEPARATOR_MENU_ITEM (list->data))
1378     {
1379       GtkWidget *child = list->data;
1380       
1381       gtk_container_remove (GTK_CONTAINER (priv->menu), child);
1382       list = list->next;
1383     }
1384   g_list_free (children);
1385
1386   /* Regenerate the list of children so we don't try to remove items twice */
1387   children = gtk_container_get_children (GTK_CONTAINER (priv->menu));
1388
1389   list = g_list_last (children);
1390   while (list && GTK_IS_SEPARATOR_MENU_ITEM (list->data))
1391     {
1392       GtkWidget *child = list->data;
1393
1394       gtk_container_remove (GTK_CONTAINER (priv->menu), child);
1395       list = list->prev;
1396     }
1397   g_list_free (children);
1398
1399   priv->need_rebuild = FALSE;
1400 }
1401
1402 static void
1403 gtk_toolbar_size_allocate (GtkWidget     *widget,
1404                            GtkAllocation *allocation)
1405 {
1406   GtkAllocation widget_allocation;
1407   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1408   GtkToolbarPrivate *priv = toolbar->priv;
1409   GtkAllocation *allocations;
1410   ItemState *new_states;
1411   GtkAllocation arrow_allocation;
1412   GtkStyle *style;
1413   gint arrow_size;
1414   gint size, pos, short_size;
1415   GList *list;
1416   gint i;
1417   gboolean need_arrow;
1418   gint n_expand_items;
1419   gint border_width;
1420   gint available_size;
1421   gint n_items;
1422   gint needed_size;
1423   GtkRequisition arrow_requisition;
1424   gboolean overflowing;
1425   gboolean size_changed;
1426   gdouble elapsed;
1427   GtkAllocation item_area;
1428   GtkShadowType shadow_type;
1429
1430   style = gtk_widget_get_style (widget);
1431
1432   gtk_widget_get_allocation (widget, &widget_allocation);
1433   size_changed = FALSE;
1434   if (widget_allocation.x != allocation->x              ||
1435       widget_allocation.y != allocation->y              ||
1436       widget_allocation.width != allocation->width      ||
1437       widget_allocation.height != allocation->height)
1438     {
1439       size_changed = TRUE;
1440     }
1441   
1442   if (size_changed)
1443     gtk_toolbar_stop_sliding (toolbar);
1444
1445   gtk_widget_set_allocation (widget, allocation);
1446
1447   border_width = gtk_container_get_border_width (GTK_CONTAINER (toolbar));
1448
1449   if (gtk_widget_get_realized (widget))
1450     {
1451       gdk_window_move_resize (priv->event_window,
1452                               allocation->x + border_width,
1453                               allocation->y + border_width,
1454                               allocation->width - border_width * 2,
1455                               allocation->height - border_width * 2);
1456     }
1457   
1458   border_width += get_internal_padding (toolbar);
1459
1460   gtk_size_request_get_size (GTK_SIZE_REQUEST (priv->arrow_button),
1461                              &arrow_requisition, NULL);
1462
1463   shadow_type = get_shadow_type (toolbar);
1464
1465   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1466     {
1467       available_size = size = allocation->width - 2 * border_width;
1468       short_size = allocation->height - 2 * border_width;
1469       arrow_size = arrow_requisition.width;
1470       
1471       if (shadow_type != GTK_SHADOW_NONE)
1472         {
1473           available_size -= 2 * style->xthickness;
1474           short_size -= 2 * style->ythickness;
1475         }
1476     }
1477   else
1478     {
1479       available_size = size = allocation->height - 2 * border_width;
1480       short_size = allocation->width - 2 * border_width;
1481       arrow_size = arrow_requisition.height;
1482       
1483       if (shadow_type != GTK_SHADOW_NONE)
1484         {
1485           available_size -= 2 * style->ythickness;
1486           short_size -= 2 * style->xthickness;
1487         }
1488     }
1489   
1490   n_items = g_list_length (priv->content);
1491   allocations = g_new0 (GtkAllocation, n_items);
1492   new_states = g_new0 (ItemState, n_items);
1493   
1494   needed_size = 0;
1495   need_arrow = FALSE;
1496   for (list = priv->content; list != NULL; list = list->next)
1497     {
1498       ToolbarContent *content = list->data;
1499       
1500       if (toolbar_content_visible (content, toolbar))
1501         {
1502           needed_size += get_item_size (toolbar, content);
1503
1504           /* Do we need an arrow?
1505            *
1506            * Assume we don't, and see if any non-separator item with a
1507            * proxy menu item is then going to overflow.
1508            */
1509           if (needed_size > available_size                      &&
1510               !need_arrow                                       &&
1511               priv->show_arrow                                  &&
1512               toolbar_content_has_proxy_menu_item (content)     &&
1513               !toolbar_content_is_separator (content))
1514             {
1515               need_arrow = TRUE;
1516             }
1517         }
1518     }
1519   
1520   if (need_arrow)
1521     size = available_size - arrow_size;
1522   else
1523     size = available_size;
1524   
1525   /* calculate widths and states of items */
1526   overflowing = FALSE;
1527   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1528     {
1529       ToolbarContent *content = list->data;
1530       gint item_size;
1531       
1532       if (!toolbar_content_visible (content, toolbar))
1533         {
1534           new_states[i] = HIDDEN;
1535           continue;
1536         }
1537       
1538       item_size = get_item_size (toolbar, content);
1539       if (item_size <= size && !overflowing)
1540         {
1541           size -= item_size;
1542           allocations[i].width = item_size;
1543           new_states[i] = NORMAL;
1544         }
1545       else
1546         {
1547           overflowing = TRUE;
1548           new_states[i] = OVERFLOWN;
1549           allocations[i].width = item_size;
1550         }
1551     }
1552   
1553   /* calculate width of arrow */  
1554   if (need_arrow)
1555     {
1556       arrow_allocation.width = arrow_size;
1557       arrow_allocation.height = MAX (short_size, 1);
1558     }
1559   
1560   /* expand expandable items */
1561   
1562   /* We don't expand when there is an overflow menu, because that leads to
1563    * weird jumps when items get moved to the overflow menu and the expanding
1564    * items suddenly get a lot of extra space
1565    */
1566   if (!overflowing)
1567     {
1568       gint max_child_expand;
1569       n_expand_items = 0;
1570       
1571       for (i = 0, list = priv->content; list != NULL; list = list->next, ++i)
1572         {
1573           ToolbarContent *content = list->data;
1574           
1575           if (toolbar_content_get_expand (content) && new_states[i] == NORMAL)
1576             n_expand_items++;
1577         }
1578       
1579       max_child_expand = get_max_child_expand (toolbar);
1580       for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1581         {
1582           ToolbarContent *content = list->data;
1583           
1584           if (toolbar_content_get_expand (content) && new_states[i] == NORMAL)
1585             {
1586               gint extra = size / n_expand_items;
1587               if (size % n_expand_items != 0)
1588                 extra++;
1589
1590               if (extra > max_child_expand)
1591                 extra = max_child_expand;
1592
1593               allocations[i].width += extra;
1594               size -= extra;
1595               n_expand_items--;
1596             }
1597         }
1598       
1599       g_assert (n_expand_items == 0);
1600     }
1601   
1602   /* position items */
1603   pos = border_width;
1604   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1605     {
1606       /* both NORMAL and OVERFLOWN items get a position. This ensures
1607        * that sliding will work for OVERFLOWN items too
1608        */
1609       if (new_states[i] == NORMAL ||
1610           new_states[i] == OVERFLOWN)
1611         {
1612           allocations[i].x = pos;
1613           allocations[i].y = border_width;
1614           allocations[i].height = short_size;
1615           
1616           pos += allocations[i].width;
1617         }
1618     }
1619   
1620   /* position arrow */
1621   if (need_arrow)
1622     {
1623       arrow_allocation.x = available_size - border_width - arrow_allocation.width;
1624       arrow_allocation.y = border_width;
1625     }
1626   
1627   item_area.x = border_width;
1628   item_area.y = border_width;
1629   item_area.width = available_size - (need_arrow? arrow_size : 0);
1630   item_area.height = short_size;
1631
1632   /* fix up allocations in the vertical or RTL cases */
1633   if (priv->orientation == GTK_ORIENTATION_VERTICAL)
1634     {
1635       for (i = 0; i < n_items; ++i)
1636         fixup_allocation_for_vertical (&(allocations[i]));
1637       
1638       if (need_arrow)
1639         fixup_allocation_for_vertical (&arrow_allocation);
1640
1641       fixup_allocation_for_vertical (&item_area);
1642     }
1643   else if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1644     {
1645       for (i = 0; i < n_items; ++i)
1646         fixup_allocation_for_rtl (available_size, &(allocations[i]));
1647       
1648       if (need_arrow)
1649         fixup_allocation_for_rtl (available_size, &arrow_allocation);
1650
1651       fixup_allocation_for_rtl (available_size, &item_area);
1652     }
1653   
1654   /* translate the items by allocation->(x,y) */
1655   for (i = 0; i < n_items; ++i)
1656     {
1657       allocations[i].x += allocation->x;
1658       allocations[i].y += allocation->y;
1659       
1660       if (shadow_type != GTK_SHADOW_NONE)
1661         {
1662           allocations[i].x += style->xthickness;
1663           allocations[i].y += style->ythickness;
1664         }
1665     }
1666   
1667   if (need_arrow)
1668     {
1669       arrow_allocation.x += allocation->x;
1670       arrow_allocation.y += allocation->y;
1671       
1672       if (shadow_type != GTK_SHADOW_NONE)
1673         {
1674           arrow_allocation.x += style->xthickness;
1675           arrow_allocation.y += style->ythickness;
1676         }
1677     }
1678
1679   item_area.x += allocation->x;
1680   item_area.y += allocation->y;
1681   if (shadow_type != GTK_SHADOW_NONE)
1682     {
1683       item_area.x += style->xthickness;
1684       item_area.y += style->ythickness;
1685     }
1686
1687   /* did anything change? */
1688   for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1689     {
1690       ToolbarContent *content = list->data;
1691       
1692       if (toolbar_content_get_state (content) == NORMAL &&
1693           new_states[i] != NORMAL)
1694         {
1695           /* an item disappeared and we didn't change size, so begin sliding */
1696           if (!size_changed)
1697             gtk_toolbar_begin_sliding (toolbar);
1698         }
1699     }
1700   
1701   /* finally allocate the items */
1702   if (priv->is_sliding)
1703     {
1704       for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1705         {
1706           ToolbarContent *content = list->data;
1707           
1708           toolbar_content_set_goal_allocation (content, &(allocations[i]));
1709         }
1710     }
1711
1712   elapsed = g_timer_elapsed (priv->timer, NULL);
1713   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1714     {
1715       ToolbarContent *content = list->data;
1716
1717       if (new_states[i] == OVERFLOWN ||
1718           new_states[i] == NORMAL)
1719         {
1720           GtkAllocation alloc;
1721           GtkAllocation start_allocation = { 0, };
1722           GtkAllocation goal_allocation;
1723
1724           if (priv->is_sliding)
1725             {
1726               toolbar_content_get_start_allocation (content, &start_allocation);
1727               toolbar_content_get_goal_allocation (content, &goal_allocation);
1728               
1729               compute_intermediate_allocation (toolbar,
1730                                                &start_allocation,
1731                                                &goal_allocation,
1732                                                &alloc);
1733
1734               priv->need_sync = TRUE;
1735             }
1736           else
1737             {
1738               alloc = allocations[i];
1739             }
1740
1741           if (alloc.width <= 0 || alloc.height <= 0)
1742             {
1743               toolbar_content_set_child_visible (content, toolbar, FALSE);
1744             }
1745           else
1746             {
1747               if (!rect_within (&alloc, &item_area))
1748                 {
1749                   toolbar_content_set_child_visible (content, toolbar, FALSE);
1750                   toolbar_content_size_allocate (content, &alloc);
1751                 }
1752               else
1753                 {
1754                   toolbar_content_set_child_visible (content, toolbar, TRUE);
1755                   toolbar_content_size_allocate (content, &alloc);
1756                 }
1757             }
1758         }
1759       else
1760         {
1761           toolbar_content_set_child_visible (content, toolbar, FALSE);
1762         }
1763           
1764       toolbar_content_set_state (content, new_states[i]);
1765     }
1766   
1767   if (priv->menu && priv->need_rebuild)
1768     rebuild_menu (toolbar);
1769   
1770   if (need_arrow)
1771     {
1772       gtk_widget_size_allocate (GTK_WIDGET (priv->arrow_button),
1773                                 &arrow_allocation);
1774       gtk_widget_show (GTK_WIDGET (priv->arrow_button));
1775     }
1776   else
1777     {
1778       gtk_widget_hide (GTK_WIDGET (priv->arrow_button));
1779
1780       if (priv->menu && gtk_widget_get_visible (GTK_WIDGET (priv->menu)))
1781         gtk_menu_shell_deactivate (GTK_MENU_SHELL (priv->menu));
1782     }
1783
1784   g_free (allocations);
1785   g_free (new_states);
1786 }
1787
1788 static void
1789 gtk_toolbar_update_button_relief (GtkToolbar *toolbar)
1790 {
1791   GtkToolbarPrivate *priv = toolbar->priv;
1792   GtkReliefStyle relief;
1793
1794   relief = get_button_relief (toolbar);
1795
1796   if (relief != gtk_button_get_relief (GTK_BUTTON (priv->arrow_button)))
1797     {
1798       gtk_toolbar_reconfigured (toolbar);
1799   
1800       gtk_button_set_relief (GTK_BUTTON (priv->arrow_button), relief);
1801     }
1802 }
1803
1804 static void
1805 gtk_toolbar_style_set (GtkWidget *widget,
1806                        GtkStyle  *prev_style)
1807 {
1808   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1809   GtkToolbarPrivate *priv = toolbar->priv;
1810
1811   priv->max_homogeneous_pixels = -1;
1812
1813   if (gtk_widget_get_realized (widget))
1814     gtk_style_set_background (gtk_widget_get_style (widget),
1815                               gtk_widget_get_window (widget),
1816                               gtk_widget_get_state (widget));
1817
1818   if (prev_style)
1819     gtk_toolbar_update_button_relief (GTK_TOOLBAR (widget));
1820 }
1821
1822 static GList *
1823 gtk_toolbar_list_children_in_focus_order (GtkToolbar       *toolbar,
1824                                           GtkDirectionType  dir)
1825 {
1826   GtkToolbarPrivate *priv = toolbar->priv;
1827   GList *result = NULL;
1828   GList *list;
1829   gboolean rtl;
1830   
1831   /* generate list of children in reverse logical order */
1832   
1833   for (list = priv->content; list != NULL; list = list->next)
1834     {
1835       ToolbarContent *content = list->data;
1836       GtkWidget *widget;
1837       
1838       widget = toolbar_content_get_widget (content);
1839       
1840       if (widget)
1841         result = g_list_prepend (result, widget);
1842     }
1843   
1844   result = g_list_prepend (result, priv->arrow_button);
1845   
1846   rtl = (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL);
1847   
1848   /* move in logical order when
1849    *
1850    *    - dir is TAB_FORWARD
1851    *
1852    *    - in RTL mode and moving left or up
1853    *
1854    *    - in LTR mode and moving right or down
1855    */
1856   if (dir == GTK_DIR_TAB_FORWARD                                        ||
1857       (rtl  && (dir == GTK_DIR_UP   || dir == GTK_DIR_LEFT))            ||
1858       (!rtl && (dir == GTK_DIR_DOWN || dir == GTK_DIR_RIGHT)))
1859     {
1860       result = g_list_reverse (result);
1861     }
1862   
1863   return result;
1864 }
1865
1866 static gboolean
1867 gtk_toolbar_focus_home_or_end (GtkToolbar *toolbar,
1868                                gboolean    focus_home)
1869 {
1870   GList *children, *list;
1871   GtkDirectionType dir = focus_home? GTK_DIR_RIGHT : GTK_DIR_LEFT;
1872   
1873   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1874   
1875   if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1876     {
1877       children = g_list_reverse (children);
1878       
1879       dir = (dir == GTK_DIR_RIGHT)? GTK_DIR_LEFT : GTK_DIR_RIGHT;
1880     }
1881   
1882   for (list = children; list != NULL; list = list->next)
1883     {
1884       GtkWidget *child = list->data;
1885
1886       if (gtk_container_get_focus_child (GTK_CONTAINER (toolbar)) == child)
1887         break;
1888       
1889       if (gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
1890         break;
1891     }
1892   
1893   g_list_free (children);
1894   
1895   return TRUE;
1896 }   
1897
1898 /* Keybinding handler. This function is called when the user presses
1899  * Ctrl TAB or an arrow key.
1900  */
1901 static void
1902 gtk_toolbar_move_focus (GtkWidget        *widget,
1903                         GtkDirectionType  dir)
1904 {
1905   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1906   GtkContainer *container = GTK_CONTAINER (toolbar);
1907   GtkWidget *focus_child;
1908   GList *list;
1909   gboolean try_focus = FALSE;
1910   GList *children;
1911
1912   focus_child = gtk_container_get_focus_child (container);
1913
1914   if (focus_child && gtk_widget_child_focus (focus_child, dir))
1915     return;
1916   
1917   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1918   
1919   for (list = children; list != NULL; list = list->next)
1920     {
1921       GtkWidget *child = list->data;
1922       
1923       if (try_focus && gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
1924         break;
1925       
1926       if (child == focus_child)
1927         try_focus = TRUE;
1928     }
1929   
1930   g_list_free (children);
1931 }
1932
1933 /* The focus handler for the toolbar. It called when the user presses
1934  * TAB or otherwise tries to focus the toolbar.
1935  */
1936 static gboolean
1937 gtk_toolbar_focus (GtkWidget        *widget,
1938                    GtkDirectionType  dir)
1939 {
1940   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1941   GList *children, *list;
1942   gboolean result = FALSE;
1943
1944   /* if focus is already somewhere inside the toolbar then return FALSE.
1945    * The only way focus can stay inside the toolbar is when the user presses
1946    * arrow keys or Ctrl TAB (both of which are handled by the
1947    * gtk_toolbar_move_focus() keybinding function.
1948    */
1949   if (gtk_container_get_focus_child (GTK_CONTAINER (widget)))
1950     return FALSE;
1951
1952   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1953
1954   for (list = children; list != NULL; list = list->next)
1955     {
1956       GtkWidget *child = list->data;
1957       
1958       if (gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
1959         {
1960           result = TRUE;
1961           break;
1962         }
1963     }
1964
1965   g_list_free (children);
1966
1967   return result;
1968 }
1969
1970 static GtkSettings *
1971 toolbar_get_settings (GtkToolbar *toolbar)
1972 {
1973   return toolbar->priv->settings;
1974 }
1975
1976 static void
1977 style_change_notify (GtkToolbar *toolbar)
1978 {
1979   GtkToolbarPrivate *priv = toolbar->priv;
1980
1981   if (!priv->style_set)
1982     {
1983       /* pretend it was set, then unset, thus reverting to new default */
1984       priv->style_set = TRUE;
1985       gtk_toolbar_unset_style (toolbar);
1986     }
1987 }
1988
1989 static void
1990 icon_size_change_notify (GtkToolbar *toolbar)
1991 {
1992   GtkToolbarPrivate *priv = toolbar->priv;
1993
1994   if (!priv->icon_size_set)
1995     {
1996       /* pretend it was set, then unset, thus reverting to new default */
1997       priv->icon_size_set = TRUE;
1998       gtk_toolbar_unset_icon_size (toolbar);
1999     }
2000 }
2001
2002 static void
2003 animation_change_notify (GtkToolbar *toolbar)
2004 {
2005   GtkToolbarPrivate *priv = toolbar->priv;
2006   GtkSettings *settings = toolbar_get_settings (toolbar);
2007   gboolean animation;
2008
2009   if (settings)
2010     g_object_get (settings,
2011                   "gtk-enable-animations", &animation,
2012                   NULL);
2013   else
2014     animation = DEFAULT_ANIMATION_STATE;
2015
2016   priv->animation = animation;
2017 }
2018
2019 static void
2020 settings_change_notify (GtkSettings      *settings,
2021                         const GParamSpec *pspec,
2022                         GtkToolbar       *toolbar)
2023 {
2024   if (! strcmp (pspec->name, "gtk-toolbar-style"))
2025     style_change_notify (toolbar);
2026   else if (! strcmp (pspec->name, "gtk-toolbar-icon-size"))
2027     icon_size_change_notify (toolbar);
2028   else if (! strcmp (pspec->name, "gtk-enable-animations"))
2029     animation_change_notify (toolbar);
2030 }
2031
2032 static void
2033 gtk_toolbar_screen_changed (GtkWidget *widget,
2034                             GdkScreen *previous_screen)
2035 {
2036   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
2037   GtkToolbarPrivate *priv = toolbar->priv;
2038   GtkSettings *old_settings = toolbar_get_settings (toolbar);
2039   GtkSettings *settings;
2040   
2041   if (gtk_widget_has_screen (GTK_WIDGET (toolbar)))
2042     settings = gtk_widget_get_settings (GTK_WIDGET (toolbar));
2043   else
2044     settings = NULL;
2045   
2046   if (settings == old_settings)
2047     return;
2048   
2049   if (old_settings)
2050     {
2051       g_signal_handler_disconnect (old_settings, priv->settings_connection);
2052
2053       g_object_unref (old_settings);
2054     }
2055
2056   if (settings)
2057     {
2058       priv->settings_connection =
2059         g_signal_connect (settings, "notify",
2060                           G_CALLBACK (settings_change_notify),
2061                           toolbar);
2062
2063       priv->settings = g_object_ref (settings);
2064     }
2065   else
2066     priv->settings = NULL;
2067
2068   style_change_notify (toolbar);
2069   icon_size_change_notify (toolbar);
2070   animation_change_notify (toolbar);
2071 }
2072
2073 static int
2074 find_drop_index (GtkToolbar *toolbar,
2075                  gint        x,
2076                  gint        y)
2077 {
2078   GtkToolbarPrivate *priv = toolbar->priv;
2079   GList *interesting_content;
2080   GList *list;
2081   GtkOrientation orientation;
2082   GtkTextDirection direction;
2083   gint best_distance = G_MAXINT;
2084   gint distance;
2085   gint cursor;
2086   gint pos;
2087   ToolbarContent *best_content;
2088   GtkAllocation allocation;
2089   
2090   /* list items we care about wrt. drag and drop */
2091   interesting_content = NULL;
2092   for (list = priv->content; list != NULL; list = list->next)
2093     {
2094       ToolbarContent *content = list->data;
2095       
2096       if (toolbar_content_get_state (content) == NORMAL)
2097         interesting_content = g_list_prepend (interesting_content, content);
2098     }
2099   interesting_content = g_list_reverse (interesting_content);
2100   
2101   if (!interesting_content)
2102     return 0;
2103   
2104   orientation = priv->orientation;
2105   direction = gtk_widget_get_direction (GTK_WIDGET (toolbar));
2106   
2107   /* distance to first interesting item */
2108   best_content = interesting_content->data;
2109   toolbar_content_get_allocation (best_content, &allocation);
2110   
2111   if (orientation == GTK_ORIENTATION_HORIZONTAL)
2112     {
2113       cursor = x;
2114       
2115       if (direction == GTK_TEXT_DIR_LTR)
2116         pos = allocation.x;
2117       else
2118         pos = allocation.x + allocation.width;
2119     }
2120   else
2121     {
2122       cursor = y;
2123       pos = allocation.y;
2124     }
2125   
2126   best_content = NULL;
2127   best_distance = ABS (pos - cursor);
2128   
2129   /* distance to far end of each item */
2130   for (list = interesting_content; list != NULL; list = list->next)
2131     {
2132       ToolbarContent *content = list->data;
2133       
2134       toolbar_content_get_allocation (content, &allocation);
2135       
2136       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2137         {
2138           if (direction == GTK_TEXT_DIR_LTR)
2139             pos = allocation.x + allocation.width;
2140           else
2141             pos = allocation.x;
2142         }
2143       else
2144         {
2145           pos = allocation.y + allocation.height;
2146         }
2147       
2148       distance = ABS (pos - cursor);
2149       
2150       if (distance < best_distance)
2151         {
2152           best_distance = distance;
2153           best_content = content;
2154         }
2155     }
2156   
2157   g_list_free (interesting_content);
2158   
2159   if (!best_content)
2160     return 0;
2161   else
2162     return g_list_index (priv->content, best_content) + 1;
2163 }
2164
2165 static void
2166 reset_all_placeholders (GtkToolbar *toolbar)
2167 {
2168   GtkToolbarPrivate *priv = toolbar->priv;
2169   GList *list;
2170   
2171   for (list = priv->content; list != NULL; list = list->next)
2172     {
2173       ToolbarContent *content = list->data;
2174       if (toolbar_content_is_placeholder (content))
2175         toolbar_content_set_disappearing (content, TRUE);
2176     }
2177 }
2178
2179 static gint
2180 physical_to_logical (GtkToolbar *toolbar,
2181                      gint        physical)
2182 {
2183   GtkToolbarPrivate *priv = toolbar->priv;
2184   GList *list;
2185   int logical;
2186   
2187   g_assert (physical >= 0);
2188   
2189   logical = 0;
2190   for (list = priv->content; list && physical > 0; list = list->next)
2191     {
2192       ToolbarContent *content = list->data;
2193       
2194       if (!toolbar_content_is_placeholder (content))
2195         logical++;
2196       physical--;
2197     }
2198   
2199   g_assert (physical == 0);
2200   
2201   return logical;
2202 }
2203
2204 static gint
2205 logical_to_physical (GtkToolbar *toolbar,
2206                      gint        logical)
2207 {
2208   GtkToolbarPrivate *priv = toolbar->priv;
2209   GList *list;
2210   gint physical;
2211   
2212   g_assert (logical >= 0);
2213   
2214   physical = 0;
2215   for (list = priv->content; list; list = list->next)
2216     {
2217       ToolbarContent *content = list->data;
2218       
2219       if (!toolbar_content_is_placeholder (content))
2220         {
2221           if (logical == 0)
2222             break;
2223           logical--;
2224         }
2225       
2226       physical++;
2227     }
2228   
2229   g_assert (logical == 0);
2230   
2231   return physical;
2232 }
2233
2234 /**
2235  * gtk_toolbar_set_drop_highlight_item:
2236  * @toolbar: a #GtkToolbar
2237  * @tool_item: (allow-none): a #GtkToolItem, or %NULL to turn of highlighting
2238  * @index_: a position on @toolbar
2239  *
2240  * Highlights @toolbar to give an idea of what it would look like
2241  * if @item was added to @toolbar at the position indicated by @index_.
2242  * If @item is %NULL, highlighting is turned off. In that case @index_ 
2243  * is ignored.
2244  *
2245  * The @tool_item passed to this function must not be part of any widget
2246  * hierarchy. When an item is set as drop highlight item it can not
2247  * added to any widget hierarchy or used as highlight item for another
2248  * toolbar.
2249  * 
2250  * Since: 2.4
2251  **/
2252 void
2253 gtk_toolbar_set_drop_highlight_item (GtkToolbar  *toolbar,
2254                                      GtkToolItem *tool_item,
2255                                      gint         index_)
2256 {
2257   ToolbarContent *content;
2258   GtkToolbarPrivate *priv;
2259   gint n_items;
2260   GtkRequisition requisition;
2261   GtkRequisition old_requisition;
2262   gboolean restart_sliding;
2263   
2264   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2265   g_return_if_fail (tool_item == NULL || GTK_IS_TOOL_ITEM (tool_item));
2266
2267   priv = toolbar->priv;
2268
2269   if (!tool_item)
2270     {
2271       if (priv->highlight_tool_item)
2272         {
2273           gtk_widget_unparent (GTK_WIDGET (priv->highlight_tool_item));
2274           g_object_unref (priv->highlight_tool_item);
2275           priv->highlight_tool_item = NULL;
2276         }
2277       
2278       reset_all_placeholders (toolbar);
2279       gtk_toolbar_begin_sliding (toolbar);
2280       return;
2281     }
2282   
2283   n_items = gtk_toolbar_get_n_items (toolbar);
2284   if (index_ < 0 || index_ > n_items)
2285     index_ = n_items;
2286   
2287   if (tool_item != priv->highlight_tool_item)
2288     {
2289       if (priv->highlight_tool_item)
2290         g_object_unref (priv->highlight_tool_item);
2291       
2292       g_object_ref_sink (tool_item);
2293       
2294       priv->highlight_tool_item = tool_item;
2295       
2296       gtk_widget_set_parent (GTK_WIDGET (priv->highlight_tool_item),
2297                              GTK_WIDGET (toolbar));
2298     }
2299   
2300   index_ = logical_to_physical (toolbar, index_);
2301   
2302   content = g_list_nth_data (priv->content, index_);
2303   
2304   if (index_ > 0)
2305     {
2306       ToolbarContent *prev_content;
2307       
2308       prev_content = g_list_nth_data (priv->content, index_ - 1);
2309       
2310       if (prev_content && toolbar_content_is_placeholder (prev_content))
2311         content = prev_content;
2312     }
2313   
2314   if (!content || !toolbar_content_is_placeholder (content))
2315     {
2316       GtkWidget *placeholder;
2317       
2318       placeholder = GTK_WIDGET (gtk_separator_tool_item_new ());
2319
2320       content = toolbar_content_new_tool_item (toolbar,
2321                                                GTK_TOOL_ITEM (placeholder),
2322                                                TRUE, index_);
2323       gtk_widget_show (placeholder);
2324     }
2325   
2326   g_assert (content);
2327   g_assert (toolbar_content_is_placeholder (content));
2328   
2329   gtk_widget_size_request (GTK_WIDGET (priv->highlight_tool_item),
2330                            &requisition);
2331
2332   toolbar_content_set_expand (content, gtk_tool_item_get_expand (tool_item));
2333   
2334   restart_sliding = FALSE;
2335   toolbar_content_size_request (content, toolbar, &old_requisition);
2336   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2337     {
2338       requisition.height = -1;
2339       if (requisition.width != old_requisition.width)
2340         restart_sliding = TRUE;
2341     }
2342   else
2343     {
2344       requisition.width = -1;
2345       if (requisition.height != old_requisition.height)
2346         restart_sliding = TRUE;
2347     }
2348
2349   if (toolbar_content_disappearing (content))
2350     restart_sliding = TRUE;
2351   
2352   reset_all_placeholders (toolbar);
2353   toolbar_content_set_disappearing (content, FALSE);
2354   
2355   toolbar_content_set_size_request (content,
2356                                     requisition.width, requisition.height);
2357   
2358   if (restart_sliding)
2359     gtk_toolbar_begin_sliding (toolbar);
2360 }
2361
2362 static void
2363 gtk_toolbar_get_child_property (GtkContainer *container,
2364                                 GtkWidget    *child,
2365                                 guint         property_id,
2366                                 GValue       *value,
2367                                 GParamSpec   *pspec)
2368 {
2369   GtkToolItem *item = GTK_TOOL_ITEM (child);
2370   
2371   switch (property_id)
2372     {
2373     case CHILD_PROP_HOMOGENEOUS:
2374       g_value_set_boolean (value, gtk_tool_item_get_homogeneous (item));
2375       break;
2376       
2377     case CHILD_PROP_EXPAND:
2378       g_value_set_boolean (value, gtk_tool_item_get_expand (item));
2379       break;
2380       
2381     default:
2382       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2383       break;
2384     }
2385 }
2386
2387 static void
2388 gtk_toolbar_set_child_property (GtkContainer *container,
2389                                 GtkWidget    *child,
2390                                 guint         property_id,
2391                                 const GValue *value,
2392                                 GParamSpec   *pspec)
2393 {
2394   switch (property_id)
2395     {
2396     case CHILD_PROP_HOMOGENEOUS:
2397       gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2398       break;
2399       
2400     case CHILD_PROP_EXPAND:
2401       gtk_tool_item_set_expand (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2402       break;
2403       
2404     default:
2405       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2406       break;
2407     }
2408 }
2409
2410 static void
2411 gtk_toolbar_show_all (GtkWidget *widget)
2412 {
2413   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
2414   GtkToolbarPrivate *priv = toolbar->priv;
2415   GList *list;
2416
2417   for (list = priv->content; list != NULL; list = list->next)
2418     {
2419       ToolbarContent *content = list->data;
2420       
2421       toolbar_content_show_all (content);
2422     }
2423   
2424   gtk_widget_show (widget);
2425 }
2426
2427 static void
2428 gtk_toolbar_hide_all (GtkWidget *widget)
2429 {
2430   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
2431   GtkToolbarPrivate *priv = toolbar->priv;
2432   GList *list;
2433
2434   for (list = priv->content; list != NULL; list = list->next)
2435     {
2436       ToolbarContent *content = list->data;
2437       
2438       toolbar_content_hide_all (content);
2439     }
2440
2441   gtk_widget_hide (widget);
2442 }
2443
2444 static void
2445 gtk_toolbar_add (GtkContainer *container,
2446                  GtkWidget    *widget)
2447 {
2448   GtkToolbar *toolbar = GTK_TOOLBAR (container);
2449
2450   gtk_toolbar_insert (toolbar, GTK_TOOL_ITEM (widget), -1);
2451 }
2452
2453 static void
2454 gtk_toolbar_remove (GtkContainer *container,
2455                     GtkWidget    *widget)
2456 {
2457   GtkToolbar *toolbar = GTK_TOOLBAR (container);
2458   GtkToolbarPrivate *priv = toolbar->priv;
2459   ToolbarContent *content_to_remove;
2460   GList *list;
2461
2462   content_to_remove = NULL;
2463   for (list = priv->content; list != NULL; list = list->next)
2464     {
2465       ToolbarContent *content = list->data;
2466       GtkWidget *child;
2467       
2468       child = toolbar_content_get_widget (content);
2469       if (child && child == widget)
2470         {
2471           content_to_remove = content;
2472           break;
2473         }
2474     }
2475   
2476   g_return_if_fail (content_to_remove != NULL);
2477   
2478   toolbar_content_remove (content_to_remove, toolbar);
2479   toolbar_content_free (content_to_remove);
2480 }
2481
2482 static void
2483 gtk_toolbar_forall (GtkContainer *container,
2484                     gboolean      include_internals,
2485                     GtkCallback   callback,
2486                     gpointer      callback_data)
2487 {
2488   GtkToolbar *toolbar = GTK_TOOLBAR (container);
2489   GtkToolbarPrivate *priv = toolbar->priv;
2490   GList *list;
2491   
2492   g_return_if_fail (callback != NULL);
2493   
2494   list = priv->content;
2495   while (list)
2496     {
2497       ToolbarContent *content = list->data;
2498       GList *next = list->next;
2499       
2500       if (include_internals || !toolbar_content_is_placeholder (content))
2501         {
2502           GtkWidget *child = toolbar_content_get_widget (content);
2503           
2504           if (child)
2505             callback (child, callback_data);
2506         }
2507       
2508       list = next;
2509     }
2510   
2511   if (include_internals)
2512     callback (priv->arrow_button, callback_data);
2513 }
2514
2515 static GType
2516 gtk_toolbar_child_type (GtkContainer *container)
2517 {
2518   return GTK_TYPE_TOOL_ITEM;
2519 }
2520
2521 static void
2522 gtk_toolbar_reconfigured (GtkToolbar *toolbar)
2523 {
2524   GtkToolbarPrivate *priv = toolbar->priv;
2525   GList *list;
2526   
2527   list = priv->content;
2528   while (list)
2529     {
2530       ToolbarContent *content = list->data;
2531       GList *next = list->next;
2532       
2533       toolbar_content_toolbar_reconfigured (content, toolbar);
2534       
2535       list = next;
2536     }
2537 }
2538
2539 static void
2540 gtk_toolbar_orientation_changed (GtkToolbar    *toolbar,
2541                                  GtkOrientation orientation)
2542 {
2543   GtkToolbarPrivate *priv = toolbar->priv;
2544
2545   if (priv->orientation != orientation)
2546     {
2547       priv->orientation = orientation;
2548       
2549       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2550         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
2551       else
2552         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
2553       
2554       gtk_toolbar_reconfigured (toolbar);
2555       
2556       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2557       g_object_notify (G_OBJECT (toolbar), "orientation");
2558     }
2559 }
2560
2561 static void
2562 gtk_toolbar_real_style_changed (GtkToolbar     *toolbar,
2563                                 GtkToolbarStyle style)
2564 {
2565   GtkToolbarPrivate *priv = toolbar->priv;
2566
2567   if (priv->style != style)
2568     {
2569       priv->style = style;
2570
2571       gtk_toolbar_reconfigured (toolbar);
2572       
2573       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2574       g_object_notify (G_OBJECT (toolbar), "toolbar-style");
2575     }
2576 }
2577
2578 static void
2579 menu_position_func (GtkMenu  *menu,
2580                     gint     *x,
2581                     gint     *y,
2582                     gboolean *push_in,
2583                     gpointer  user_data)
2584 {
2585   GtkAllocation allocation;
2586   GtkToolbar *toolbar = GTK_TOOLBAR (user_data);
2587   GtkToolbarPrivate *priv = toolbar->priv;
2588   GtkRequisition req;
2589   GtkRequisition menu_req;
2590   GdkRectangle monitor;
2591   gint monitor_num;
2592   GdkScreen *screen;
2593   
2594   gtk_widget_size_request (priv->arrow_button, &req);
2595   gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
2596   
2597   screen = gtk_widget_get_screen (GTK_WIDGET (menu));
2598   monitor_num = gdk_screen_get_monitor_at_window (screen,
2599                                                   gtk_widget_get_window (priv->arrow_button));
2600   if (monitor_num < 0)
2601     monitor_num = 0;
2602   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
2603
2604   gtk_widget_get_allocation (priv->arrow_button, &allocation);
2605
2606   gdk_window_get_origin (GTK_BUTTON (priv->arrow_button)->event_window, x, y);
2607   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
2608     {
2609       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2610         *x += allocation.width - req.width;
2611       else 
2612         *x += req.width - menu_req.width;
2613
2614       if ((*y + allocation.height + menu_req.height) <= monitor.y + monitor.height)
2615         *y += allocation.height;
2616       else if ((*y - menu_req.height) >= monitor.y)
2617         *y -= menu_req.height;
2618       else if (monitor.y + monitor.height - (*y + allocation.height) > *y)
2619         *y += allocation.height;
2620       else
2621         *y -= menu_req.height;
2622     }
2623   else 
2624     {
2625       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2626         *x += allocation.width;
2627       else 
2628         *x -= menu_req.width;
2629
2630       if (*y + menu_req.height > monitor.y + monitor.height &&
2631           *y + allocation.height - monitor.y > monitor.y + monitor.height - *y)
2632         *y += allocation.height - menu_req.height;
2633     }
2634
2635   *push_in = FALSE;
2636 }
2637
2638 static void
2639 show_menu (GtkToolbar     *toolbar,
2640            GdkEventButton *event)
2641 {
2642   GtkToolbarPrivate *priv = toolbar->priv;
2643
2644   rebuild_menu (toolbar);
2645
2646   gtk_widget_show_all (GTK_WIDGET (priv->menu));
2647
2648   gtk_menu_popup (priv->menu, NULL, NULL,
2649                   menu_position_func, toolbar,
2650                   event? event->button : 0,
2651                   event? event->time : gtk_get_current_event_time());
2652 }
2653
2654 static void
2655 gtk_toolbar_arrow_button_clicked (GtkWidget  *button,
2656                                   GtkToolbar *toolbar)
2657 {
2658   GtkToolbarPrivate *priv = toolbar->priv;
2659
2660   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->arrow_button)) &&
2661       (!priv->menu || !gtk_widget_get_visible (GTK_WIDGET (priv->menu))))
2662     {
2663       /* We only get here when the button is clicked with the keyboard,
2664        * because mouse button presses result in the menu being shown so
2665        * that priv->menu would be non-NULL and visible.
2666        */
2667       show_menu (toolbar, NULL);
2668       gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2669     }
2670 }
2671
2672 static gboolean
2673 gtk_toolbar_arrow_button_press (GtkWidget      *button,
2674                                 GdkEventButton *event,
2675                                 GtkToolbar     *toolbar)
2676 {
2677   show_menu (toolbar, event);
2678   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2679   
2680   return TRUE;
2681 }
2682
2683 static gboolean
2684 gtk_toolbar_button_press (GtkWidget      *toolbar,
2685                           GdkEventButton *event)
2686 {
2687   GtkWidget *window;
2688
2689   if (event->button == 3)
2690     {
2691       gboolean return_value;
2692
2693       g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2694                      (int)event->x_root, (int)event->y_root, event->button,
2695                      &return_value);
2696
2697       return return_value;
2698     }
2699
2700   window = gtk_widget_get_toplevel (toolbar);
2701
2702   if (window)
2703     {
2704       gboolean window_drag = FALSE;
2705
2706       gtk_widget_style_get (toolbar,
2707                             "window-dragging", &window_drag,
2708                             NULL);
2709
2710       if (window_drag)
2711         {
2712           gtk_window_begin_move_drag (GTK_WINDOW (window),
2713                                       event->button,
2714                                       event->x_root,
2715                                       event->y_root,
2716                                       event->time);
2717
2718           return TRUE;
2719         }
2720     }
2721
2722   return FALSE;
2723 }
2724
2725 static gboolean
2726 gtk_toolbar_popup_menu (GtkWidget *toolbar)
2727 {
2728   gboolean return_value;
2729   /* This function is the handler for the "popup menu" keybinding,
2730    * ie., it is called when the user presses Shift F10
2731    */
2732   g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2733                  -1, -1, -1, &return_value);
2734   
2735   return return_value;
2736 }
2737
2738 /**
2739  * gtk_toolbar_new:
2740  * 
2741  * Creates a new toolbar. 
2742  
2743  * Return Value: the newly-created toolbar.
2744  **/
2745 GtkWidget *
2746 gtk_toolbar_new (void)
2747 {
2748   GtkToolbar *toolbar;
2749   
2750   toolbar = g_object_new (GTK_TYPE_TOOLBAR, NULL);
2751   
2752   return GTK_WIDGET (toolbar);
2753 }
2754
2755 /**
2756  * gtk_toolbar_insert:
2757  * @toolbar: a #GtkToolbar
2758  * @item: a #GtkToolItem
2759  * @pos: the position of the new item
2760  *
2761  * Insert a #GtkToolItem into the toolbar at position @pos. If @pos is
2762  * 0 the item is prepended to the start of the toolbar. If @pos is
2763  * negative, the item is appended to the end of the toolbar.
2764  *
2765  * Since: 2.4
2766  **/
2767 void
2768 gtk_toolbar_insert (GtkToolbar  *toolbar,
2769                     GtkToolItem *item,
2770                     gint         pos)
2771 {
2772   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2773   g_return_if_fail (GTK_IS_TOOL_ITEM (item));
2774   
2775   if (pos >= 0)
2776     pos = logical_to_physical (toolbar, pos);
2777
2778   toolbar_content_new_tool_item (toolbar, item, FALSE, pos);
2779 }
2780
2781 /**
2782  * gtk_toolbar_get_item_index:
2783  * @toolbar: a #GtkToolbar
2784  * @item: a #GtkToolItem that is a child of @toolbar
2785  * 
2786  * Returns the position of @item on the toolbar, starting from 0.
2787  * It is an error if @item is not a child of the toolbar.
2788  * 
2789  * Return value: the position of item on the toolbar.
2790  * 
2791  * Since: 2.4
2792  **/
2793 gint
2794 gtk_toolbar_get_item_index (GtkToolbar  *toolbar,
2795                             GtkToolItem *item)
2796 {
2797   GtkToolbarPrivate *priv;
2798   GList *list;
2799   int n;
2800   
2801   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2802   g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1);
2803   g_return_val_if_fail (gtk_widget_get_parent (GTK_WIDGET (item)) == GTK_WIDGET (toolbar), -1);
2804
2805   priv = toolbar->priv;
2806
2807   n = 0;
2808   for (list = priv->content; list != NULL; list = list->next)
2809     {
2810       ToolbarContent *content = list->data;
2811       GtkWidget *widget;
2812       
2813       widget = toolbar_content_get_widget (content);
2814       
2815       if (item == GTK_TOOL_ITEM (widget))
2816         break;
2817       
2818       ++n;
2819     }
2820   
2821   return physical_to_logical (toolbar, n);
2822 }
2823
2824 /**
2825  * gtk_toolbar_set_style:
2826  * @toolbar: a #GtkToolbar.
2827  * @style: the new style for @toolbar.
2828  * 
2829  * Alters the view of @toolbar to display either icons only, text only, or both.
2830  **/
2831 void
2832 gtk_toolbar_set_style (GtkToolbar      *toolbar,
2833                        GtkToolbarStyle  style)
2834 {
2835   GtkToolbarPrivate *priv;
2836
2837   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2838
2839   priv = toolbar->priv;
2840
2841   priv->style_set = TRUE;
2842   g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2843 }
2844
2845 /**
2846  * gtk_toolbar_get_style:
2847  * @toolbar: a #GtkToolbar
2848  *
2849  * Retrieves whether the toolbar has text, icons, or both . See
2850  * gtk_toolbar_set_style().
2851  
2852  * Return value: the current style of @toolbar
2853  **/
2854 GtkToolbarStyle
2855 gtk_toolbar_get_style (GtkToolbar *toolbar)
2856 {
2857   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE);
2858
2859   return toolbar->priv->style;
2860 }
2861
2862 /**
2863  * gtk_toolbar_unset_style:
2864  * @toolbar: a #GtkToolbar
2865  * 
2866  * Unsets a toolbar style set with gtk_toolbar_set_style(), so that
2867  * user preferences will be used to determine the toolbar style.
2868  **/
2869 void
2870 gtk_toolbar_unset_style (GtkToolbar *toolbar)
2871 {
2872   GtkToolbarPrivate *priv;
2873   GtkToolbarStyle style;
2874   
2875   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2876
2877   priv = toolbar->priv;
2878
2879   if (priv->style_set)
2880     {
2881       GtkSettings *settings = toolbar_get_settings (toolbar);
2882       
2883       if (settings)
2884         g_object_get (settings,
2885                       "gtk-toolbar-style", &style,
2886                       NULL);
2887       else
2888         style = DEFAULT_TOOLBAR_STYLE;
2889
2890       if (style != priv->style)
2891         g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2892
2893       priv->style_set = FALSE;
2894     }
2895 }
2896
2897 /**
2898  * gtk_toolbar_get_n_items:
2899  * @toolbar: a #GtkToolbar
2900  * 
2901  * Returns the number of items on the toolbar.
2902  * 
2903  * Return value: the number of items on the toolbar
2904  * 
2905  * Since: 2.4
2906  **/
2907 gint
2908 gtk_toolbar_get_n_items (GtkToolbar *toolbar)
2909 {
2910   GtkToolbarPrivate *priv;
2911
2912   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2913
2914   priv = toolbar->priv;
2915
2916   return physical_to_logical (toolbar, g_list_length (priv->content));
2917 }
2918
2919 /**
2920  * gtk_toolbar_get_nth_item:
2921  * @toolbar: a #GtkToolbar
2922  * @n: A position on the toolbar
2923  *
2924  * Returns the @n<!-- -->'th item on @toolbar, or %NULL if the
2925  * toolbar does not contain an @n<!-- -->'th item.
2926  * 
2927  * Return value: The @n<!-- -->'th #GtkToolItem on @toolbar, or %NULL if there
2928  * isn't an @n<!-- -->'th item.
2929  * 
2930  * Since: 2.4
2931  **/
2932 GtkToolItem *
2933 gtk_toolbar_get_nth_item (GtkToolbar *toolbar,
2934                           gint        n)
2935 {
2936   GtkToolbarPrivate *priv;
2937   ToolbarContent *content;
2938   gint n_items;
2939   
2940   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
2941
2942   priv = toolbar->priv;
2943
2944   n_items = gtk_toolbar_get_n_items (toolbar);
2945   
2946   if (n < 0 || n >= n_items)
2947     return NULL;
2948
2949   content = g_list_nth_data (priv->content, logical_to_physical (toolbar, n));
2950   
2951   g_assert (content);
2952   g_assert (!toolbar_content_is_placeholder (content));
2953   
2954   return GTK_TOOL_ITEM (toolbar_content_get_widget (content));
2955 }
2956
2957 /**
2958  * gtk_toolbar_get_icon_size:
2959  * @toolbar: a #GtkToolbar
2960  *
2961  * Retrieves the icon size for the toolbar. See gtk_toolbar_set_icon_size().
2962  *
2963  * Return value: (type int): the current icon size for the icons on
2964  * the toolbar.
2965  **/
2966 GtkIconSize
2967 gtk_toolbar_get_icon_size (GtkToolbar *toolbar)
2968 {
2969   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_ICON_SIZE);
2970
2971   return toolbar->priv->icon_size;
2972 }
2973
2974 /**
2975  * gtk_toolbar_get_relief_style:
2976  * @toolbar: a #GtkToolbar
2977  * 
2978  * Returns the relief style of buttons on @toolbar. See
2979  * gtk_button_set_relief().
2980  * 
2981  * Return value: The relief style of buttons on @toolbar.
2982  * 
2983  * Since: 2.4
2984  **/
2985 GtkReliefStyle
2986 gtk_toolbar_get_relief_style (GtkToolbar *toolbar)
2987 {
2988   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_RELIEF_NONE);
2989   
2990   return get_button_relief (toolbar);
2991 }
2992
2993 /**
2994  * gtk_toolbar_set_show_arrow:
2995  * @toolbar: a #GtkToolbar
2996  * @show_arrow: Whether to show an overflow menu
2997  * 
2998  * Sets whether to show an overflow menu when
2999  * @toolbar doesn't have room for all items on it. If %TRUE,
3000  * items that there are not room are available through an
3001  * overflow menu.
3002  * 
3003  * Since: 2.4
3004  **/
3005 void
3006 gtk_toolbar_set_show_arrow (GtkToolbar *toolbar,
3007                             gboolean    show_arrow)
3008 {
3009   GtkToolbarPrivate *priv;
3010
3011   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3012
3013   priv = toolbar->priv;
3014
3015   show_arrow = show_arrow != FALSE;
3016   
3017   if (priv->show_arrow != show_arrow)
3018     {
3019       priv->show_arrow = show_arrow;
3020       
3021       if (!priv->show_arrow)
3022         gtk_widget_hide (priv->arrow_button);
3023       
3024       gtk_widget_queue_resize (GTK_WIDGET (toolbar));      
3025       g_object_notify (G_OBJECT (toolbar), "show-arrow");
3026     }
3027 }
3028
3029 /**
3030  * gtk_toolbar_get_show_arrow:
3031  * @toolbar: a #GtkToolbar
3032  * 
3033  * Returns whether the toolbar has an overflow menu.
3034  * See gtk_toolbar_set_show_arrow().
3035  * 
3036  * Return value: %TRUE if the toolbar has an overflow menu.
3037  * 
3038  * Since: 2.4
3039  **/
3040 gboolean
3041 gtk_toolbar_get_show_arrow (GtkToolbar *toolbar)
3042 {
3043   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
3044
3045   return toolbar->priv->show_arrow;
3046 }
3047
3048 /**
3049  * gtk_toolbar_get_drop_index:
3050  * @toolbar: a #GtkToolbar
3051  * @x: x coordinate of a point on the toolbar
3052  * @y: y coordinate of a point on the toolbar
3053  *
3054  * Returns the position corresponding to the indicated point on
3055  * @toolbar. This is useful when dragging items to the toolbar:
3056  * this function returns the position a new item should be
3057  * inserted.
3058  *
3059  * @x and @y are in @toolbar coordinates.
3060  * 
3061  * Return value: The position corresponding to the point (@x, @y) on the toolbar.
3062  * 
3063  * Since: 2.4
3064  **/
3065 gint
3066 gtk_toolbar_get_drop_index (GtkToolbar *toolbar,
3067                             gint        x,
3068                             gint        y)
3069 {
3070   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
3071   
3072   return physical_to_logical (toolbar, find_drop_index (toolbar, x, y));
3073 }
3074
3075 static void
3076 gtk_toolbar_finalize (GObject *object)
3077 {
3078   GList *list;
3079   GtkToolbar *toolbar = GTK_TOOLBAR (object);
3080   GtkToolbarPrivate *priv = toolbar->priv;
3081
3082   if (priv->arrow_button)
3083     gtk_widget_unparent (priv->arrow_button);
3084
3085   for (list = priv->content; list != NULL; list = list->next)
3086     {
3087       ToolbarContent *content = list->data;
3088
3089       toolbar_content_free (content);
3090     }
3091   
3092   g_list_free (priv->content);
3093   g_list_free (priv->children);
3094   
3095   g_timer_destroy (priv->timer);
3096   
3097   if (priv->menu)
3098     gtk_widget_destroy (GTK_WIDGET (priv->menu));
3099   
3100   if (priv->idle_id)
3101     g_source_remove (priv->idle_id);
3102
3103   G_OBJECT_CLASS (gtk_toolbar_parent_class)->finalize (object);
3104 }
3105
3106 /**
3107  * gtk_toolbar_set_icon_size:
3108  * @toolbar: A #GtkToolbar
3109  * @icon_size: (type int): The #GtkIconSize that stock icons in the
3110  *     toolbar shall have.
3111  *
3112  * This function sets the size of stock icons in the toolbar. You
3113  * can call it both before you add the icons and after they've been
3114  * added. The size you set will override user preferences for the default
3115  * icon size.
3116  * 
3117  * This should only be used for special-purpose toolbars, normal
3118  * application toolbars should respect the user preferences for the
3119  * size of icons.
3120  **/
3121 void
3122 gtk_toolbar_set_icon_size (GtkToolbar  *toolbar,
3123                            GtkIconSize  icon_size)
3124 {
3125   GtkToolbarPrivate *priv;
3126
3127   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3128   g_return_if_fail (icon_size != GTK_ICON_SIZE_INVALID);
3129
3130   priv = toolbar->priv;
3131
3132   if (!priv->icon_size_set)
3133     {
3134       priv->icon_size_set = TRUE;
3135       g_object_notify (G_OBJECT (toolbar), "icon-size-set");
3136     }
3137
3138   if (priv->icon_size == icon_size)
3139     return;
3140
3141   priv->icon_size = icon_size;
3142   g_object_notify (G_OBJECT (toolbar), "icon-size");
3143   
3144   gtk_toolbar_reconfigured (toolbar);
3145   
3146   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3147 }
3148
3149 /**
3150  * gtk_toolbar_unset_icon_size:
3151  * @toolbar: a #GtkToolbar
3152  * 
3153  * Unsets toolbar icon size set with gtk_toolbar_set_icon_size(), so that
3154  * user preferences will be used to determine the icon size.
3155  **/
3156 void
3157 gtk_toolbar_unset_icon_size (GtkToolbar *toolbar)
3158 {
3159   GtkToolbarPrivate *priv;
3160   GtkIconSize size;
3161
3162   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3163
3164   priv = toolbar->priv;
3165
3166   if (priv->icon_size_set)
3167     {
3168       GtkSettings *settings = toolbar_get_settings (toolbar);
3169       
3170       if (settings)
3171         {
3172           g_object_get (settings,
3173                         "gtk-toolbar-icon-size", &size,
3174                         NULL);
3175         }
3176       else
3177         size = DEFAULT_ICON_SIZE;
3178
3179       if (size != priv->icon_size)
3180         {
3181           gtk_toolbar_set_icon_size (toolbar, size);
3182           g_object_notify (G_OBJECT (toolbar), "icon-size");      
3183         }
3184
3185       priv->icon_size_set = FALSE;
3186       g_object_notify (G_OBJECT (toolbar), "icon-size-set");      
3187     }
3188 }
3189
3190 /*
3191  * ToolbarContent methods
3192  */
3193 typedef enum {
3194   UNKNOWN,
3195   YES,
3196   NO
3197 } TriState;
3198
3199 struct _ToolbarContent
3200 {
3201   ItemState      state;
3202
3203   GtkToolItem   *item;
3204   GtkAllocation  start_allocation;
3205   GtkAllocation  goal_allocation;
3206   guint          is_placeholder : 1;
3207   guint          disappearing : 1;
3208   guint          has_menu : 2;
3209 };
3210
3211 static ToolbarContent *
3212 toolbar_content_new_tool_item (GtkToolbar  *toolbar,
3213                                GtkToolItem *item,
3214                                gboolean     is_placeholder,
3215                                gint         pos)
3216 {
3217   GtkToolbarPrivate *priv = toolbar->priv;
3218   ToolbarContent *content;
3219
3220   content = g_slice_new0 (ToolbarContent);
3221   
3222   content->state = NOT_ALLOCATED;
3223   content->item = item;
3224   content->is_placeholder = is_placeholder;
3225   
3226   gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar));
3227
3228   priv->content = g_list_insert (priv->content, content, pos);
3229   
3230   if (!is_placeholder)
3231     {
3232       priv->num_children++;
3233
3234       gtk_toolbar_stop_sliding (toolbar);
3235     }
3236
3237   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3238   priv->need_rebuild = TRUE;
3239   
3240   return content;
3241 }
3242
3243 static void
3244 toolbar_content_remove (ToolbarContent *content,
3245                         GtkToolbar     *toolbar)
3246 {
3247   GtkToolbarPrivate *priv = toolbar->priv;
3248
3249   gtk_widget_unparent (GTK_WIDGET (content->item));
3250
3251   priv->content = g_list_remove (priv->content, content);
3252
3253   if (!toolbar_content_is_placeholder (content))
3254     priv->num_children--;
3255
3256   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3257   priv->need_rebuild = TRUE;
3258 }
3259
3260 static void
3261 toolbar_content_free (ToolbarContent *content)
3262 {
3263   g_slice_free (ToolbarContent, content);
3264 }
3265
3266 static gint
3267 calculate_max_homogeneous_pixels (GtkWidget *widget)
3268 {
3269   PangoContext *context;
3270   PangoFontMetrics *metrics;
3271   gint char_width;
3272   
3273   context = gtk_widget_get_pango_context (widget);
3274   metrics = pango_context_get_metrics (context,
3275                                        gtk_widget_get_style (widget)->font_desc,
3276                                        pango_context_get_language (context));
3277   char_width = pango_font_metrics_get_approximate_char_width (metrics);
3278   pango_font_metrics_unref (metrics);
3279   
3280   return PANGO_PIXELS (MAX_HOMOGENEOUS_N_CHARS * char_width);
3281 }
3282
3283 static void
3284 toolbar_content_expose (ToolbarContent *content,
3285                         GtkContainer   *container,
3286                         GdkEventExpose *expose)
3287 {
3288   GtkWidget *widget;
3289
3290   if (!content->is_placeholder)
3291     widget = GTK_WIDGET (content->item);
3292
3293   if (widget)
3294     gtk_container_propagate_expose (container, widget, expose);
3295 }
3296
3297 static gboolean
3298 toolbar_content_visible (ToolbarContent *content,
3299                          GtkToolbar     *toolbar)
3300 {
3301   GtkToolbarPrivate *priv = toolbar->priv;
3302   GtkToolItem *item;
3303
3304   item = content->item;
3305
3306   if (!gtk_widget_get_visible (GTK_WIDGET (item)))
3307     return FALSE;
3308
3309   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
3310       gtk_tool_item_get_visible_horizontal (item))
3311     return TRUE;
3312
3313   if (priv->orientation == GTK_ORIENTATION_VERTICAL &&
3314       gtk_tool_item_get_visible_vertical (item))
3315     return TRUE;
3316       
3317   return FALSE;
3318 }
3319
3320 static void
3321 toolbar_content_size_request (ToolbarContent *content,
3322                               GtkToolbar     *toolbar,
3323                               GtkRequisition *requisition)
3324 {
3325   gtk_widget_size_request (GTK_WIDGET (content->item),
3326                            requisition);
3327   if (content->is_placeholder &&
3328       content->disappearing)
3329     {
3330       requisition->width = 0;
3331       requisition->height = 0;
3332     }
3333 }
3334
3335 static gboolean
3336 toolbar_content_is_homogeneous (ToolbarContent *content,
3337                                 GtkToolbar     *toolbar)
3338 {
3339   GtkToolbarPrivate *priv = toolbar->priv;
3340   GtkRequisition requisition;
3341   gboolean result;
3342   
3343   if (priv->max_homogeneous_pixels < 0)
3344     {
3345       priv->max_homogeneous_pixels =
3346         calculate_max_homogeneous_pixels (GTK_WIDGET (toolbar));
3347     }
3348   
3349   toolbar_content_size_request (content, toolbar, &requisition);
3350   
3351   if (requisition.width > priv->max_homogeneous_pixels)
3352     return FALSE;
3353
3354   result = gtk_tool_item_get_homogeneous (content->item) &&
3355            !GTK_IS_SEPARATOR_TOOL_ITEM (content->item);
3356
3357   if (gtk_tool_item_get_is_important (content->item) &&
3358       priv->style == GTK_TOOLBAR_BOTH_HORIZ &&
3359       priv->orientation == GTK_ORIENTATION_HORIZONTAL)
3360     {
3361       result = FALSE;
3362     }
3363
3364   return result;
3365 }
3366
3367 static gboolean
3368 toolbar_content_is_placeholder (ToolbarContent *content)
3369 {
3370   if (content->is_placeholder)
3371     return TRUE;
3372   
3373   return FALSE;
3374 }
3375
3376 static gboolean
3377 toolbar_content_disappearing (ToolbarContent *content)
3378 {
3379   if (content->disappearing)
3380     return TRUE;
3381   
3382   return FALSE;
3383 }
3384
3385 static ItemState
3386 toolbar_content_get_state (ToolbarContent *content)
3387 {
3388   return content->state;
3389 }
3390
3391 static gboolean
3392 toolbar_content_child_visible (ToolbarContent *content)
3393 {
3394   return GTK_WIDGET_CHILD_VISIBLE (content->item);
3395 }
3396
3397 static void
3398 toolbar_content_get_goal_allocation (ToolbarContent *content,
3399                                      GtkAllocation  *allocation)
3400 {
3401   *allocation = content->goal_allocation;
3402 }
3403
3404 static void
3405 toolbar_content_get_allocation (ToolbarContent *content,
3406                                 GtkAllocation  *allocation)
3407 {
3408   gtk_widget_get_allocation (GTK_WIDGET (content->item), allocation);
3409 }
3410
3411 static void
3412 toolbar_content_set_start_allocation (ToolbarContent *content,
3413                                       GtkAllocation  *allocation)
3414 {
3415   content->start_allocation = *allocation;
3416 }
3417
3418 static gboolean
3419 toolbar_content_get_expand (ToolbarContent *content)
3420 {
3421   if (!content->disappearing &&
3422       gtk_tool_item_get_expand (content->item))
3423     return TRUE;
3424
3425   return FALSE;
3426 }
3427
3428 static void
3429 toolbar_content_set_goal_allocation (ToolbarContent *content,
3430                                      GtkAllocation  *allocation)
3431 {
3432   content->goal_allocation = *allocation;
3433 }
3434
3435 static void
3436 toolbar_content_set_child_visible (ToolbarContent *content,
3437                                    GtkToolbar     *toolbar,
3438                                    gboolean        visible)
3439 {
3440   gtk_widget_set_child_visible (GTK_WIDGET (content->item),
3441                                 visible);
3442 }
3443
3444 static void
3445 toolbar_content_get_start_allocation (ToolbarContent *content,
3446                                       GtkAllocation  *start_allocation)
3447 {
3448   *start_allocation = content->start_allocation;
3449 }
3450
3451 static void
3452 toolbar_content_size_allocate (ToolbarContent *content,
3453                                GtkAllocation  *allocation)
3454 {
3455   gtk_widget_size_allocate (GTK_WIDGET (content->item),
3456                             allocation);
3457 }
3458
3459 static void
3460 toolbar_content_set_state (ToolbarContent *content,
3461                            ItemState       state)
3462 {
3463   content->state = state;
3464 }
3465
3466 static GtkWidget *
3467 toolbar_content_get_widget (ToolbarContent *content)
3468 {
3469   return GTK_WIDGET (content->item);
3470 }
3471
3472
3473 static void
3474 toolbar_content_set_disappearing (ToolbarContent *content,
3475                                   gboolean        disappearing)
3476 {
3477   content->disappearing = disappearing;
3478 }
3479
3480 static void
3481 toolbar_content_set_size_request (ToolbarContent *content,
3482                                   gint            width,
3483                                   gint            height)
3484 {
3485   gtk_widget_set_size_request (GTK_WIDGET (content->item),
3486                                width, height);
3487 }
3488
3489 static void
3490 toolbar_content_toolbar_reconfigured (ToolbarContent *content,
3491                                       GtkToolbar     *toolbar)
3492 {
3493   gtk_tool_item_toolbar_reconfigured (content->item);
3494 }
3495
3496 static GtkWidget *
3497 toolbar_content_retrieve_menu_item (ToolbarContent *content)
3498 {
3499   return gtk_tool_item_retrieve_proxy_menu_item (content->item);
3500 }
3501
3502 static gboolean
3503 toolbar_content_has_proxy_menu_item (ToolbarContent *content)
3504 {
3505   GtkWidget *menu_item;
3506
3507   if (content->has_menu == YES)
3508     return TRUE;
3509   else if (content->has_menu == NO)
3510     return FALSE;
3511
3512   menu_item = toolbar_content_retrieve_menu_item (content);
3513
3514   content->has_menu = menu_item? YES : NO;
3515
3516   return menu_item != NULL;
3517 }
3518
3519 static void
3520 toolbar_content_set_unknown_menu_status (ToolbarContent *content)
3521 {
3522   content->has_menu = UNKNOWN;
3523 }
3524
3525 static gboolean
3526 toolbar_content_is_separator (ToolbarContent *content)
3527 {
3528   return GTK_IS_SEPARATOR_TOOL_ITEM (content->item);
3529 }
3530
3531 static void
3532 toolbar_content_set_expand (ToolbarContent *content,
3533                             gboolean        expand)
3534 {
3535   gtk_tool_item_set_expand (content->item, expand);
3536 }
3537
3538 static void
3539 toolbar_content_show_all (ToolbarContent  *content)
3540 {
3541   GtkWidget *widget;
3542   
3543   widget = toolbar_content_get_widget (content);
3544   if (widget)
3545     gtk_widget_show_all (widget);
3546 }
3547
3548 static void
3549 toolbar_content_hide_all (ToolbarContent  *content)
3550 {
3551   GtkWidget *widget;
3552   
3553   widget = toolbar_content_get_widget (content);
3554   if (widget)
3555     gtk_widget_hide_all (widget);
3556 }
3557
3558 /*
3559  * Getters
3560  */
3561 static GtkReliefStyle
3562 get_button_relief (GtkToolbar *toolbar)
3563 {
3564   GtkReliefStyle button_relief = GTK_RELIEF_NORMAL;
3565   
3566   gtk_widget_ensure_style (GTK_WIDGET (toolbar));
3567   
3568   gtk_widget_style_get (GTK_WIDGET (toolbar),
3569                         "button-relief", &button_relief,
3570                         NULL);
3571   
3572   return button_relief;
3573 }
3574
3575 static gint
3576 get_internal_padding (GtkToolbar *toolbar)
3577 {
3578   gint ipadding = 0;
3579   
3580   gtk_widget_style_get (GTK_WIDGET (toolbar),
3581                         "internal-padding", &ipadding,
3582                         NULL);
3583   
3584   return ipadding;
3585 }
3586
3587 static gint
3588 get_max_child_expand (GtkToolbar *toolbar)
3589 {
3590   gint mexpand = G_MAXINT;
3591
3592   gtk_widget_style_get (GTK_WIDGET (toolbar),
3593                         "max-child-expand", &mexpand,
3594                         NULL);
3595   return mexpand;
3596 }
3597
3598 static GtkShadowType
3599 get_shadow_type (GtkToolbar *toolbar)
3600 {
3601   GtkShadowType shadow_type;
3602   
3603   gtk_widget_style_get (GTK_WIDGET (toolbar),
3604                         "shadow-type", &shadow_type,
3605                         NULL);
3606   
3607   return shadow_type;
3608 }
3609
3610 /* GTK+ internal methods */
3611
3612 gint
3613 _gtk_toolbar_get_default_space_size (void)
3614 {
3615   return DEFAULT_SPACE_SIZE;
3616 }
3617
3618 void
3619 _gtk_toolbar_paint_space_line (GtkWidget           *widget,
3620                                GtkToolbar          *toolbar,
3621                                const GdkRectangle  *area,
3622                                const GtkAllocation *allocation)
3623 {
3624   GtkToolbarPrivate *priv = toolbar->priv;
3625   GtkOrientation orientation;
3626   GtkStateType  state;
3627   GtkStyle     *style;
3628   GdkWindow    *window;
3629   const double start_fraction = (SPACE_LINE_START / SPACE_LINE_DIVISION);
3630   const double end_fraction = (SPACE_LINE_END / SPACE_LINE_DIVISION);
3631
3632   g_return_if_fail (GTK_IS_WIDGET (widget));
3633
3634   orientation = toolbar? priv->orientation : GTK_ORIENTATION_HORIZONTAL;
3635
3636   style = gtk_widget_get_style (widget);
3637   window = gtk_widget_get_window (widget);
3638   state = gtk_widget_get_state (widget);
3639
3640   if (orientation == GTK_ORIENTATION_HORIZONTAL)
3641     {
3642       gboolean wide_separators;
3643       gint     separator_width;
3644
3645       gtk_widget_style_get (widget,
3646                             "wide-separators", &wide_separators,
3647                             "separator-width", &separator_width,
3648                             NULL);
3649
3650       if (wide_separators)
3651         gtk_paint_box (style, window,
3652                        state, GTK_SHADOW_ETCHED_OUT,
3653                        area, widget, "vseparator",
3654                        allocation->x + (allocation->width - separator_width) / 2,
3655                        allocation->y + allocation->height * start_fraction,
3656                        separator_width,
3657                        allocation->height * (end_fraction - start_fraction));
3658       else
3659         gtk_paint_vline (style, window,
3660                          state, area, widget,
3661                          "toolbar",
3662                          allocation->y + allocation->height * start_fraction,
3663                          allocation->y + allocation->height * end_fraction,
3664                          allocation->x + (allocation->width - style->xthickness) / 2);
3665     }
3666   else
3667     {
3668       gboolean wide_separators;
3669       gint     separator_height;
3670
3671       gtk_widget_style_get (widget,
3672                             "wide-separators",  &wide_separators,
3673                             "separator-height", &separator_height,
3674                             NULL);
3675
3676       if (wide_separators)
3677         gtk_paint_box (style, window,
3678                        state, GTK_SHADOW_ETCHED_OUT,
3679                        area, widget, "hseparator",
3680                        allocation->x + allocation->width * start_fraction,
3681                        allocation->y + (allocation->height - separator_height) / 2,
3682                        allocation->width * (end_fraction - start_fraction),
3683                        separator_height);
3684       else
3685         gtk_paint_hline (style, window,
3686                          state, area, widget,
3687                          "toolbar",
3688                          allocation->x + allocation->width * start_fraction,
3689                          allocation->x + allocation->width * end_fraction,
3690                          allocation->y + (allocation->height - style->ythickness) / 2);
3691     }
3692 }
3693
3694 gchar *
3695 _gtk_toolbar_elide_underscores (const gchar *original)
3696 {
3697   gchar *q, *result;
3698   const gchar *p, *end;
3699   gsize len;
3700   gboolean last_underscore;
3701   
3702   if (!original)
3703     return NULL;
3704
3705   len = strlen (original);
3706   q = result = g_malloc (len + 1);
3707   last_underscore = FALSE;
3708   
3709   end = original + len;
3710   for (p = original; p < end; p++)
3711     {
3712       if (!last_underscore && *p == '_')
3713         last_underscore = TRUE;
3714       else
3715         {
3716           last_underscore = FALSE;
3717           if (original + 2 <= p && p + 1 <= end && 
3718               p[-2] == '(' && p[-1] == '_' && p[0] != '_' && p[1] == ')')
3719             {
3720               q--;
3721               *q = '\0';
3722               p++;
3723             }
3724           else
3725             *q++ = *p;
3726         }
3727     }
3728
3729   if (last_underscore)
3730     *q++ = '_';
3731   
3732   *q = '\0';
3733   
3734   return result;
3735 }
3736
3737 static GtkIconSize
3738 toolbar_get_icon_size (GtkToolShell *shell)
3739 {
3740   GtkToolbar *toolbar = GTK_TOOLBAR (shell);
3741   GtkToolbarPrivate *priv = toolbar->priv;
3742
3743   return priv->icon_size;
3744 }
3745
3746 static GtkOrientation
3747 toolbar_get_orientation (GtkToolShell *shell)
3748 {
3749   GtkToolbar *toolbar = GTK_TOOLBAR (shell);
3750   GtkToolbarPrivate *priv = toolbar->priv;
3751
3752   return priv->orientation;
3753 }
3754
3755 static GtkToolbarStyle
3756 toolbar_get_style (GtkToolShell *shell)
3757 {
3758   GtkToolbar *toolbar = GTK_TOOLBAR (shell);
3759   GtkToolbarPrivate *priv = toolbar->priv;
3760
3761   return priv->style;
3762 }
3763
3764 static GtkReliefStyle
3765 toolbar_get_relief_style (GtkToolShell *shell)
3766 {
3767   return get_button_relief (GTK_TOOLBAR (shell));
3768 }
3769
3770 static void
3771 toolbar_rebuild_menu (GtkToolShell *shell)
3772 {
3773   GtkToolbar *toolbar = GTK_TOOLBAR (shell);
3774   GtkToolbarPrivate *priv = toolbar->priv;
3775   GList *list;
3776
3777   priv->need_rebuild = TRUE;
3778
3779   for (list = priv->content; list != NULL; list = list->next)
3780     {
3781       ToolbarContent *content = list->data;
3782
3783       toolbar_content_set_unknown_menu_status (content);
3784     }
3785   
3786   gtk_widget_queue_resize (GTK_WIDGET (shell));
3787 }