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