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