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