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