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