]> Pileus Git - ~andy/gtk/blob - gtk/gtktoolbar.c
remove _gtk_binding_signal_new().
[~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     g_signal_new_class_handler (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                                                                     FALSE,
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                                                                     FALSE,
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  * Deprecated: 2.14: The toolkit-wide #GtkSettings:gtk-enable-tooltips property
2938  * is now used instead.
2939  **/
2940 void
2941 gtk_toolbar_set_tooltips (GtkToolbar *toolbar,
2942                           gboolean    enable)
2943 {
2944   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2945   
2946   if (enable)
2947     gtk_tooltips_enable (toolbar->tooltips);
2948   else
2949     gtk_tooltips_disable (toolbar->tooltips);
2950
2951   g_object_notify (G_OBJECT (toolbar), "tooltips");
2952 }
2953
2954 /**
2955  * gtk_toolbar_get_tooltips:
2956  * @toolbar: a #GtkToolbar
2957  *
2958  * Retrieves whether tooltips are enabled. See
2959  * gtk_toolbar_set_tooltips().
2960  *
2961  * Return value: %TRUE if tooltips are enabled
2962  *
2963  * Deprecated: 2.14: The toolkit-wide #GtkSettings:gtk-enable-tooltips property
2964  * is now used instead.
2965  **/
2966 gboolean
2967 gtk_toolbar_get_tooltips (GtkToolbar *toolbar)
2968 {
2969   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2970   
2971   return TRUE;
2972 }
2973
2974 /**
2975  * gtk_toolbar_get_n_items:
2976  * @toolbar: a #GtkToolbar
2977  * 
2978  * Returns the number of items on the toolbar.
2979  * 
2980  * Return value: the number of items on the toolbar
2981  * 
2982  * Since: 2.4
2983  **/
2984 gint
2985 gtk_toolbar_get_n_items (GtkToolbar *toolbar)
2986 {
2987   GtkToolbarPrivate *priv;
2988   
2989   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2990   
2991   if (!gtk_toolbar_check_new_api (toolbar))
2992     return -1;
2993   
2994   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2995   
2996   return physical_to_logical (toolbar, g_list_length (priv->content));
2997 }
2998
2999 /**
3000  * gtk_toolbar_get_nth_item:
3001  * @toolbar: a #GtkToolbar
3002  * @n: A position on the toolbar
3003  *
3004  * Returns the @n<!-- -->'th item on @toolbar, or %NULL if the
3005  * toolbar does not contain an @n<!-- -->'th item.
3006  * 
3007  * Return value: The @n<!-- -->'th #GtkToolItem on @toolbar, or %NULL if there
3008  * isn't an @n<!-- -->'th item.
3009  * 
3010  * Since: 2.4
3011  **/
3012 GtkToolItem *
3013 gtk_toolbar_get_nth_item (GtkToolbar *toolbar,
3014                           gint        n)
3015 {
3016   GtkToolbarPrivate *priv;
3017   ToolbarContent *content;
3018   gint n_items;
3019   
3020   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
3021   
3022   if (!gtk_toolbar_check_new_api (toolbar))
3023     return NULL;
3024   
3025   n_items = gtk_toolbar_get_n_items (toolbar);
3026   
3027   if (n < 0 || n >= n_items)
3028     return NULL;
3029   
3030   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3031   
3032   content = g_list_nth_data (priv->content, logical_to_physical (toolbar, n));
3033   
3034   g_assert (content);
3035   g_assert (!toolbar_content_is_placeholder (content));
3036   
3037   return GTK_TOOL_ITEM (toolbar_content_get_widget (content));
3038 }
3039
3040 /**
3041  * gtk_toolbar_get_icon_size:
3042  * @toolbar: a #GtkToolbar
3043  *
3044  * Retrieves the icon size for the toolbar. See gtk_toolbar_set_icon_size().
3045  *
3046  * Return value: the current icon size for the icons on the toolbar.
3047  **/
3048 GtkIconSize
3049 gtk_toolbar_get_icon_size (GtkToolbar *toolbar)
3050 {
3051   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_ICON_SIZE);
3052   
3053   return toolbar->icon_size;
3054 }
3055
3056 /**
3057  * gtk_toolbar_get_relief_style:
3058  * @toolbar: a #GtkToolbar
3059  * 
3060  * Returns the relief style of buttons on @toolbar. See
3061  * gtk_button_set_relief().
3062  * 
3063  * Return value: The relief style of buttons on @toolbar.
3064  * 
3065  * Since: 2.4
3066  **/
3067 GtkReliefStyle
3068 gtk_toolbar_get_relief_style (GtkToolbar *toolbar)
3069 {
3070   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_RELIEF_NONE);
3071   
3072   return get_button_relief (toolbar);
3073 }
3074
3075 /**
3076  * gtk_toolbar_set_show_arrow:
3077  * @toolbar: a #GtkToolbar
3078  * @show_arrow: Whether to show an overflow menu
3079  * 
3080  * Sets whether to show an overflow menu when
3081  * @toolbar doesn't have room for all items on it. If %TRUE,
3082  * items that there are not room are available through an
3083  * overflow menu.
3084  * 
3085  * Since: 2.4
3086  **/
3087 void
3088 gtk_toolbar_set_show_arrow (GtkToolbar *toolbar,
3089                             gboolean    show_arrow)
3090 {
3091   GtkToolbarPrivate *priv;
3092   
3093   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3094   
3095   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3096   show_arrow = show_arrow != FALSE;
3097   
3098   if (priv->show_arrow != show_arrow)
3099     {
3100       priv->show_arrow = show_arrow;
3101       
3102       if (!priv->show_arrow)
3103         gtk_widget_hide (priv->arrow_button);
3104       
3105       gtk_widget_queue_resize (GTK_WIDGET (toolbar));      
3106       g_object_notify (G_OBJECT (toolbar), "show-arrow");
3107     }
3108 }
3109
3110 /**
3111  * gtk_toolbar_get_show_arrow:
3112  * @toolbar: a #GtkToolbar
3113  * 
3114  * Returns whether the toolbar has an overflow menu.
3115  * See gtk_toolbar_set_show_arrow().
3116  * 
3117  * Return value: %TRUE if the toolbar has an overflow menu.
3118  * 
3119  * Since: 2.4
3120  **/
3121 gboolean
3122 gtk_toolbar_get_show_arrow (GtkToolbar *toolbar)
3123 {
3124   GtkToolbarPrivate *priv;
3125   
3126   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
3127   
3128   if (!gtk_toolbar_check_new_api (toolbar))
3129     return FALSE;
3130   
3131   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3132   
3133   return priv->show_arrow;
3134 }
3135
3136 /**
3137  * gtk_toolbar_get_drop_index:
3138  * @toolbar: a #GtkToolbar
3139  * @x: x coordinate of a point on the toolbar
3140  * @y: y coordinate of a point on the toolbar
3141  *
3142  * Returns the position corresponding to the indicated point on
3143  * @toolbar. This is useful when dragging items to the toolbar:
3144  * this function returns the position a new item should be
3145  * inserted.
3146  *
3147  * @x and @y are in @toolbar coordinates.
3148  * 
3149  * Return value: The position corresponding to the point (@x, @y) on the toolbar.
3150  * 
3151  * Since: 2.4
3152  **/
3153 gint
3154 gtk_toolbar_get_drop_index (GtkToolbar *toolbar,
3155                             gint        x,
3156                             gint        y)
3157 {
3158   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
3159   
3160   if (!gtk_toolbar_check_new_api (toolbar))
3161     return -1;
3162   
3163   return physical_to_logical (toolbar, find_drop_index (toolbar, x, y));
3164 }
3165
3166 static void
3167 gtk_toolbar_finalize (GObject *object)
3168 {
3169   GList *list;
3170   GtkToolbar *toolbar = GTK_TOOLBAR (object);
3171   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3172   
3173   if (toolbar->tooltips)
3174     g_object_unref (toolbar->tooltips);
3175   
3176   if (priv->arrow_button)
3177     gtk_widget_unparent (priv->arrow_button);
3178
3179   for (list = priv->content; list != NULL; list = list->next)
3180     {
3181       ToolbarContent *content = list->data;
3182
3183       toolbar_content_free (content);
3184     }
3185   
3186   g_list_free (priv->content);
3187   g_list_free (toolbar->children);
3188   
3189   g_timer_destroy (priv->timer);
3190   
3191   if (priv->menu)
3192     gtk_widget_destroy (GTK_WIDGET (priv->menu));
3193   
3194   if (priv->idle_id)
3195     g_source_remove (priv->idle_id);
3196
3197   G_OBJECT_CLASS (gtk_toolbar_parent_class)->finalize (object);
3198 }
3199
3200 /**
3201  * gtk_toolbar_set_icon_size:
3202  * @toolbar: A #GtkToolbar
3203  * @icon_size: The #GtkIconSize that stock icons in the toolbar shall have.
3204  *
3205  * This function sets the size of stock icons in the toolbar. You
3206  * can call it both before you add the icons and after they've been
3207  * added. The size you set will override user preferences for the default
3208  * icon size.
3209  * 
3210  * This should only be used for special-purpose toolbars, normal
3211  * application toolbars should respect the user preferences for the
3212  * size of icons.
3213  **/
3214 void
3215 gtk_toolbar_set_icon_size (GtkToolbar  *toolbar,
3216                            GtkIconSize  icon_size)
3217 {
3218   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3219   g_return_if_fail (icon_size != GTK_ICON_SIZE_INVALID);
3220   
3221   if (!toolbar->icon_size_set)
3222     {
3223       toolbar->icon_size_set = TRUE;  
3224       g_object_notify (G_OBJECT (toolbar), "icon-size-set");
3225     }
3226
3227   if (toolbar->icon_size == icon_size)
3228     return;
3229   
3230   toolbar->icon_size = icon_size;
3231   g_object_notify (G_OBJECT (toolbar), "icon-size");
3232   
3233   gtk_toolbar_reconfigured (toolbar);
3234   
3235   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3236 }
3237
3238 /**
3239  * gtk_toolbar_unset_icon_size:
3240  * @toolbar: a #GtkToolbar
3241  * 
3242  * Unsets toolbar icon size set with gtk_toolbar_set_icon_size(), so that
3243  * user preferences will be used to determine the icon size.
3244  **/
3245 void
3246 gtk_toolbar_unset_icon_size (GtkToolbar *toolbar)
3247 {
3248   GtkIconSize size;
3249   
3250   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3251   
3252   if (toolbar->icon_size_set)
3253     {
3254       GtkSettings *settings = toolbar_get_settings (toolbar);
3255       
3256       if (settings)
3257         {
3258           g_object_get (settings,
3259                         "gtk-toolbar-icon-size", &size,
3260                         NULL);
3261         }
3262       else
3263         size = DEFAULT_ICON_SIZE;
3264       
3265       if (size != toolbar->icon_size)
3266         {
3267           gtk_toolbar_set_icon_size (toolbar, size);
3268           g_object_notify (G_OBJECT (toolbar), "icon-size");      
3269         }
3270       
3271       toolbar->icon_size_set = FALSE;
3272       g_object_notify (G_OBJECT (toolbar), "icon-size-set");      
3273     }
3274 }
3275
3276 /*
3277  * Deprecated API
3278  */
3279
3280 /**
3281  * gtk_toolbar_append_item:
3282  * @toolbar: a #GtkToolbar.
3283  * @text: give your toolbar button a label.
3284  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3285  * @tooltip_private_text: use with #GtkTipsQuery.
3286  * @icon: a #GtkWidget that should be used as the button's icon.
3287  * @callback: the function to be executed when the button is pressed.
3288  * @user_data: a pointer to any data you wish to be passed to the callback.
3289  * 
3290  * Inserts a new item into the toolbar. You must specify the position
3291  * in the toolbar where it will be inserted.
3292  *
3293  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3294  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3295  *
3296  * Return value: the new toolbar item as a #GtkWidget.
3297  **/
3298 GtkWidget *
3299 gtk_toolbar_append_item (GtkToolbar    *toolbar,
3300                          const char    *text,
3301                          const char    *tooltip_text,
3302                          const char    *tooltip_private_text,
3303                          GtkWidget     *icon,
3304                          GtkSignalFunc  callback,
3305                          gpointer       user_data)
3306 {
3307   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3308                                      NULL, text,
3309                                      tooltip_text, tooltip_private_text,
3310                                      icon, callback, user_data,
3311                                      toolbar->num_children);
3312 }
3313
3314 /**
3315  * gtk_toolbar_prepend_item:
3316  * @toolbar: a #GtkToolbar.
3317  * @text: give your toolbar button a label.
3318  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3319  * @tooltip_private_text: use with #GtkTipsQuery.
3320  * @icon: a #GtkWidget that should be used as the button's icon.
3321  * @callback: the function to be executed when the button is pressed.
3322  * @user_data: a pointer to any data you wish to be passed to the callback.
3323  * 
3324  * Adds a new button to the beginning (top or left edges) of the given toolbar.
3325  *
3326  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3327  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3328  *
3329  * Return value: the new toolbar item as a #GtkWidget.
3330  **/
3331 GtkWidget *
3332 gtk_toolbar_prepend_item (GtkToolbar    *toolbar,
3333                           const char    *text,
3334                           const char    *tooltip_text,
3335                           const char    *tooltip_private_text,
3336                           GtkWidget     *icon,
3337                           GtkSignalFunc  callback,
3338                           gpointer       user_data)
3339 {
3340   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3341                                      NULL, text,
3342                                      tooltip_text, tooltip_private_text,
3343                                      icon, callback, user_data,
3344                                      0);
3345 }
3346
3347 /**
3348  * gtk_toolbar_insert_item:
3349  * @toolbar: a #GtkToolbar.
3350  * @text: give your toolbar button a label.
3351  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3352  * @tooltip_private_text: use with #GtkTipsQuery.
3353  * @icon: a #GtkWidget that should be used as the button's icon.
3354  * @callback: the function to be executed when the button is pressed.
3355  * @user_data: a pointer to any data you wish to be passed to the callback.
3356  * @position: the number of widgets to insert this item after.
3357  * 
3358  * Inserts a new item into the toolbar. You must specify the position in the
3359  * toolbar where it will be inserted.
3360  *
3361  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3362  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3363  *
3364  * Return value: the new toolbar item as a #GtkWidget.
3365  **/
3366 GtkWidget *
3367 gtk_toolbar_insert_item (GtkToolbar    *toolbar,
3368                          const char    *text,
3369                          const char    *tooltip_text,
3370                          const char    *tooltip_private_text,
3371                          GtkWidget     *icon,
3372                          GtkSignalFunc  callback,
3373                          gpointer       user_data,
3374                          gint           position)
3375 {
3376   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3377                                      NULL, text,
3378                                      tooltip_text, tooltip_private_text,
3379                                      icon, callback, user_data,
3380                                      position);
3381 }
3382
3383 /**
3384  * gtk_toolbar_insert_stock:
3385  * @toolbar: A #GtkToolbar
3386  * @stock_id: The id of the stock item you want to insert
3387  * @tooltip_text: The text in the tooltip of the toolbar button
3388  * @tooltip_private_text: The private text of the tooltip
3389  * @callback: The callback called when the toolbar button is clicked.
3390  * @user_data: user data passed to callback
3391  * @position: The position the button shall be inserted at.
3392  *            -1 means at the end.
3393  *
3394  * Inserts a stock item at the specified position of the toolbar.  If
3395  * @stock_id is not a known stock item ID, it's inserted verbatim,
3396  * except that underscores used to mark mnemonics are removed.
3397  *
3398  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3399  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3400  *
3401  * Returns: the inserted widget
3402  */
3403 GtkWidget*
3404 gtk_toolbar_insert_stock (GtkToolbar      *toolbar,
3405                           const gchar     *stock_id,
3406                           const char      *tooltip_text,
3407                           const char      *tooltip_private_text,
3408                           GtkSignalFunc    callback,
3409                           gpointer         user_data,
3410                           gint             position)
3411 {
3412   return internal_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3413                                   NULL, stock_id,
3414                                   tooltip_text, tooltip_private_text,
3415                                   NULL, callback, user_data,
3416                                   position, TRUE);
3417 }
3418
3419 /**
3420  * gtk_toolbar_append_space:
3421  * @toolbar: a #GtkToolbar.
3422  * 
3423  * Adds a new space to the end of the toolbar.
3424  **/
3425 void
3426 gtk_toolbar_append_space (GtkToolbar *toolbar)
3427 {
3428   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3429                               NULL, NULL,
3430                               NULL, NULL,
3431                               NULL, NULL, NULL,
3432                               toolbar->num_children);
3433 }
3434
3435 /**
3436  * gtk_toolbar_prepend_space:
3437  * @toolbar: a #GtkToolbar.
3438  * 
3439  * Adds a new space to the beginning of the toolbar.
3440  **/
3441 void
3442 gtk_toolbar_prepend_space (GtkToolbar *toolbar)
3443 {
3444   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3445                               NULL, NULL,
3446                               NULL, NULL,
3447                               NULL, NULL, NULL,
3448                               0);
3449 }
3450
3451 /**
3452  * gtk_toolbar_insert_space:
3453  * @toolbar: a #GtkToolbar
3454  * @position: the number of widgets after which a space should be inserted.
3455  * 
3456  * Inserts a new space in the toolbar at the specified position.
3457  **/
3458 void
3459 gtk_toolbar_insert_space (GtkToolbar *toolbar,
3460                           gint        position)
3461 {
3462   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3463                               NULL, NULL,
3464                               NULL, NULL,
3465                               NULL, NULL, NULL,
3466                               position);
3467 }
3468
3469 /**
3470  * gtk_toolbar_remove_space:
3471  * @toolbar: a #GtkToolbar.
3472  * @position: the index of the space to remove.
3473  * 
3474  * Removes a space from the specified position.
3475  **/
3476 void
3477 gtk_toolbar_remove_space (GtkToolbar *toolbar,
3478                           gint        position)
3479 {
3480   GtkToolbarPrivate *priv;
3481   ToolbarContent *content;
3482   
3483   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3484   
3485   if (!gtk_toolbar_check_old_api (toolbar))
3486     return;
3487   
3488   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3489   
3490   content = g_list_nth_data (priv->content, position);
3491   
3492   if (!content)
3493     {
3494       g_warning ("Toolbar position %d doesn't exist", position);
3495       return;
3496     }
3497   
3498   if (!toolbar_content_is_separator (content))
3499     {
3500       g_warning ("Toolbar position %d is not a space", position);
3501       return;
3502     }
3503   
3504   toolbar_content_remove (content, toolbar);
3505   toolbar_content_free (content);
3506 }
3507
3508 /**
3509  * gtk_toolbar_append_widget:
3510  * @toolbar: a #GtkToolbar.
3511  * @widget: a #GtkWidget to add to the toolbar. 
3512  * @tooltip_text: the element's tooltip.
3513  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3514  * 
3515  * Adds a widget to the end of the given toolbar.
3516  **/ 
3517 void
3518 gtk_toolbar_append_widget (GtkToolbar  *toolbar,
3519                            GtkWidget   *widget,
3520                            const gchar *tooltip_text,
3521                            const gchar *tooltip_private_text)
3522 {
3523   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3524                               widget, NULL,
3525                               tooltip_text, tooltip_private_text,
3526                               NULL, NULL, NULL,
3527                               toolbar->num_children);
3528 }
3529
3530 /**
3531  * gtk_toolbar_prepend_widget:
3532  * @toolbar: a #GtkToolbar.
3533  * @widget: a #GtkWidget to add to the toolbar. 
3534  * @tooltip_text: the element's tooltip.
3535  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3536  * 
3537  * Adds a widget to the beginning of the given toolbar.
3538  **/ 
3539 void
3540 gtk_toolbar_prepend_widget (GtkToolbar  *toolbar,
3541                             GtkWidget   *widget,
3542                             const gchar *tooltip_text,
3543                             const gchar *tooltip_private_text)
3544 {
3545   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3546                               widget, NULL,
3547                               tooltip_text, tooltip_private_text,
3548                               NULL, NULL, NULL,
3549                               0);
3550 }
3551
3552 /**
3553  * gtk_toolbar_insert_widget:
3554  * @toolbar: a #GtkToolbar.
3555  * @widget: a #GtkWidget to add to the toolbar. 
3556  * @tooltip_text: the element's tooltip.
3557  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3558  * @position: the number of widgets to insert this widget after.
3559  * 
3560  * Inserts a widget in the toolbar at the given position.
3561  **/ 
3562 void
3563 gtk_toolbar_insert_widget (GtkToolbar *toolbar,
3564                            GtkWidget  *widget,
3565                            const char *tooltip_text,
3566                            const char *tooltip_private_text,
3567                            gint        position)
3568 {
3569   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3570                               widget, NULL,
3571                               tooltip_text, tooltip_private_text,
3572                               NULL, NULL, NULL,
3573                               position);
3574 }
3575
3576 /**
3577  * gtk_toolbar_append_element:
3578  * @toolbar: a #GtkToolbar.
3579  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3580  * @widget: a #GtkWidget, or %NULL.
3581  * @text: the element's label.
3582  * @tooltip_text: the element's tooltip.
3583  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3584  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3585  * @callback: the function to be executed when the button is pressed.
3586  * @user_data: any data you wish to pass to the callback.
3587  * 
3588  * Adds a new element to the end of a toolbar.
3589  * 
3590  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3591  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3592  * the radio group for the new element. In all other cases, @widget must
3593  * be %NULL.
3594  * 
3595  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3596  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3597  *
3598  * Return value: the new toolbar element as a #GtkWidget.
3599  **/
3600 GtkWidget*
3601 gtk_toolbar_append_element (GtkToolbar          *toolbar,
3602                             GtkToolbarChildType  type,
3603                             GtkWidget           *widget,
3604                             const char          *text,
3605                             const char          *tooltip_text,
3606                             const char          *tooltip_private_text,
3607                             GtkWidget           *icon,
3608                             GtkSignalFunc        callback,
3609                             gpointer             user_data)
3610 {
3611   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3612                                      tooltip_text, tooltip_private_text,
3613                                      icon, callback, user_data,
3614                                      toolbar->num_children);
3615 }
3616
3617 /**
3618  * gtk_toolbar_prepend_element:
3619  * @toolbar: a #GtkToolbar.
3620  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3621  * @widget: a #GtkWidget, or %NULL
3622  * @text: the element's label.
3623  * @tooltip_text: the element's tooltip.
3624  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3625  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3626  * @callback: the function to be executed when the button is pressed.
3627  * @user_data: any data you wish to pass to the callback.
3628  *  
3629  * Adds a new element to the beginning of a toolbar.
3630  * 
3631  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3632  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3633  * the radio group for the new element. In all other cases, @widget must
3634  * be %NULL.
3635  * 
3636  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3637  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3638  *
3639  * Return value: the new toolbar element as a #GtkWidget.
3640  **/
3641 GtkWidget *
3642 gtk_toolbar_prepend_element (GtkToolbar          *toolbar,
3643                              GtkToolbarChildType  type,
3644                              GtkWidget           *widget,
3645                              const char          *text,
3646                              const char          *tooltip_text,
3647                              const char          *tooltip_private_text,
3648                              GtkWidget           *icon,
3649                              GtkSignalFunc        callback,
3650                              gpointer             user_data)
3651 {
3652   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3653                                      tooltip_text, tooltip_private_text,
3654                                      icon, callback, user_data, 0);
3655 }
3656
3657 /**
3658  * gtk_toolbar_insert_element:
3659  * @toolbar: a #GtkToolbar.
3660  * @type: a value of type #GtkToolbarChildType that determines what @widget
3661  *   will be.
3662  * @widget: a #GtkWidget, or %NULL. 
3663  * @text: the element's label.
3664  * @tooltip_text: the element's tooltip.
3665  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3666  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3667  * @callback: the function to be executed when the button is pressed.
3668  * @user_data: any data you wish to pass to the callback.
3669  * @position: the number of widgets to insert this element after.
3670  *
3671  * Inserts a new element in the toolbar at the given position. 
3672  *
3673  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3674  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3675  * the radio group for the new element. In all other cases, @widget must
3676  * be %NULL.
3677  *
3678  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3679  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3680  *
3681  * Return value: the new toolbar element as a #GtkWidget.
3682  **/
3683 GtkWidget *
3684 gtk_toolbar_insert_element (GtkToolbar          *toolbar,
3685                             GtkToolbarChildType  type,
3686                             GtkWidget           *widget,
3687                             const char          *text,
3688                             const char          *tooltip_text,
3689                             const char          *tooltip_private_text,
3690                             GtkWidget           *icon,
3691                             GtkSignalFunc        callback,
3692                             gpointer             user_data,
3693                             gint                 position)
3694 {
3695   return internal_insert_element (toolbar, type, widget, text,
3696                                   tooltip_text, tooltip_private_text,
3697                                   icon, callback, user_data, position, FALSE);
3698 }
3699
3700 static void
3701 set_child_packing_and_visibility(GtkToolbar      *toolbar,
3702                                  GtkToolbarChild *child)
3703 {
3704   GtkWidget *box;
3705   gboolean   expand;
3706
3707   box = gtk_bin_get_child (GTK_BIN (child->widget));
3708   
3709   g_return_if_fail (GTK_IS_BOX (box));
3710   
3711   if (child->label)
3712     {
3713       expand = (toolbar->style != GTK_TOOLBAR_BOTH);
3714       
3715       gtk_box_set_child_packing (GTK_BOX (box), child->label,
3716                                  expand, expand, 0, GTK_PACK_END);
3717       
3718       if (toolbar->style != GTK_TOOLBAR_ICONS)
3719         gtk_widget_show (child->label);
3720       else
3721         gtk_widget_hide (child->label);
3722     }
3723   
3724   if (child->icon)
3725     {
3726       expand = (toolbar->style != GTK_TOOLBAR_BOTH_HORIZ);
3727       
3728       gtk_box_set_child_packing (GTK_BOX (box), child->icon,
3729                                  expand, expand, 0, GTK_PACK_END);
3730       
3731       if (toolbar->style != GTK_TOOLBAR_TEXT)
3732         gtk_widget_show (child->icon);
3733       else
3734         gtk_widget_hide (child->icon);
3735     }
3736 }
3737
3738 static GtkWidget *
3739 internal_insert_element (GtkToolbar          *toolbar,
3740                          GtkToolbarChildType  type,
3741                          GtkWidget           *widget,
3742                          const char          *text,
3743                          const char          *tooltip_text,
3744                          const char          *tooltip_private_text,
3745                          GtkWidget           *icon,
3746                          GtkSignalFunc        callback,
3747                          gpointer             user_data,
3748                          gint                 position,
3749                          gboolean             use_stock)
3750 {
3751   GtkWidget *box;
3752   ToolbarContent *content;
3753   char *free_me = NULL;
3754
3755   GtkWidget *child_widget;
3756   GtkWidget *child_label;
3757   GtkWidget *child_icon;
3758
3759   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
3760   if (type == GTK_TOOLBAR_CHILD_WIDGET)
3761     g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
3762   else if (type != GTK_TOOLBAR_CHILD_RADIOBUTTON)
3763     g_return_val_if_fail (widget == NULL, NULL);
3764   if (GTK_IS_TOOL_ITEM (widget))
3765     g_warning (MIXED_API_WARNING);
3766   
3767   if (!gtk_toolbar_check_old_api (toolbar))
3768     return NULL;
3769   
3770   child_widget = NULL;
3771   child_label = NULL;
3772   child_icon = NULL;
3773   
3774   switch (type)
3775     {
3776     case GTK_TOOLBAR_CHILD_SPACE:
3777       break;
3778       
3779     case GTK_TOOLBAR_CHILD_WIDGET:
3780       child_widget = widget;
3781       break;
3782       
3783     case GTK_TOOLBAR_CHILD_BUTTON:
3784     case GTK_TOOLBAR_CHILD_TOGGLEBUTTON:
3785     case GTK_TOOLBAR_CHILD_RADIOBUTTON:
3786       if (type == GTK_TOOLBAR_CHILD_BUTTON)
3787         {
3788           child_widget = gtk_button_new ();
3789         }
3790       else if (type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
3791         {
3792           child_widget = gtk_toggle_button_new ();
3793           gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child_widget), FALSE);
3794         }
3795       else /* type == GTK_TOOLBAR_CHILD_RADIOBUTTON */
3796         {
3797           GSList *group = NULL;
3798
3799           if (widget)
3800             group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
3801           
3802           child_widget = gtk_radio_button_new (group);
3803           gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child_widget), FALSE);
3804         }
3805
3806       gtk_button_set_relief (GTK_BUTTON (child_widget), get_button_relief (toolbar));
3807       gtk_button_set_focus_on_click (GTK_BUTTON (child_widget), FALSE);
3808       
3809       if (callback)
3810         {
3811           g_signal_connect (child_widget, "clicked",
3812                             callback, user_data);
3813         }
3814       
3815       if (toolbar->style == GTK_TOOLBAR_BOTH_HORIZ)
3816         box = gtk_hbox_new (FALSE, 0);
3817       else
3818         box = gtk_vbox_new (FALSE, 0);
3819
3820       gtk_container_add (GTK_CONTAINER (child_widget), box);
3821       gtk_widget_show (box);
3822       
3823       if (text && use_stock)
3824         {
3825           GtkStockItem stock_item;
3826           if (gtk_stock_lookup (text, &stock_item))
3827             {
3828               if (!icon)
3829                 icon = gtk_image_new_from_stock (text, toolbar->icon_size);
3830           
3831               text = free_me = _gtk_toolbar_elide_underscores (stock_item.label);
3832             }
3833         }
3834       
3835       if (text)
3836         {
3837           child_label = gtk_label_new (text);
3838           
3839           gtk_container_add (GTK_CONTAINER (box), child_label);
3840         }
3841       
3842       if (icon)
3843         {
3844           child_icon = GTK_WIDGET (icon);
3845           gtk_container_add (GTK_CONTAINER (box), child_icon);
3846         }
3847       
3848       gtk_widget_show (child_widget);
3849       break;
3850       
3851     default:
3852       g_assert_not_reached ();
3853       break;
3854     }
3855   
3856   if ((type != GTK_TOOLBAR_CHILD_SPACE) && tooltip_text)
3857     {
3858       gtk_tooltips_set_tip (toolbar->tooltips, child_widget,
3859                             tooltip_text, tooltip_private_text);
3860     }
3861   
3862   content = toolbar_content_new_compatibility (toolbar, type, child_widget,
3863                                                child_icon, child_label, position);
3864   
3865   g_free (free_me);
3866   
3867   return child_widget;
3868 }
3869
3870 /*
3871  * ToolbarContent methods
3872  */
3873 typedef enum {
3874   UNKNOWN,
3875   YES,
3876   NO
3877 } TriState;
3878
3879 struct _ToolbarContent
3880 {
3881   ContentType   type;
3882   ItemState     state;
3883   
3884   union
3885   {
3886     struct
3887     {
3888       GtkToolItem *     item;
3889       GtkAllocation     start_allocation;
3890       GtkAllocation     goal_allocation;
3891       guint             is_placeholder : 1;
3892       guint             disappearing : 1;
3893       guint             has_menu : 2;
3894     } tool_item;
3895     
3896     struct
3897     {
3898       GtkToolbarChild   child;
3899       GtkAllocation     space_allocation;
3900       guint             space_visible : 1;
3901     } compatibility;
3902   } u;
3903 };
3904
3905 static ToolbarContent *
3906 toolbar_content_new_tool_item (GtkToolbar  *toolbar,
3907                                GtkToolItem *item,
3908                                gboolean     is_placeholder,
3909                                gint         pos)
3910 {
3911   ToolbarContent *content;
3912   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3913   
3914   content = g_slice_new0 (ToolbarContent);
3915   
3916   content->type = TOOL_ITEM;
3917   content->state = NOT_ALLOCATED;
3918   content->u.tool_item.item = item;
3919   content->u.tool_item.is_placeholder = is_placeholder;
3920   
3921   gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar));
3922
3923   priv->content = g_list_insert (priv->content, content, pos);
3924   
3925   if (!is_placeholder)
3926     {
3927       toolbar->num_children++;
3928
3929       gtk_toolbar_stop_sliding (toolbar);
3930     }
3931
3932   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3933   priv->need_rebuild = TRUE;
3934   
3935   return content;
3936 }
3937
3938 static ToolbarContent *
3939 toolbar_content_new_compatibility (GtkToolbar          *toolbar,
3940                                    GtkToolbarChildType  type,
3941                                    GtkWidget            *widget,
3942                                    GtkWidget            *icon,
3943                                    GtkWidget            *label,
3944                                    gint                  pos)
3945 {
3946   ToolbarContent *content;
3947   GtkToolbarChild *child;
3948   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3949   
3950   content = g_slice_new0 (ToolbarContent);
3951
3952   child = &(content->u.compatibility.child);
3953   
3954   content->type = COMPATIBILITY;
3955   child->type = type;
3956   child->widget = widget;
3957   child->icon = icon;
3958   child->label = label;
3959   
3960   if (type != GTK_TOOLBAR_CHILD_SPACE)
3961     {
3962       gtk_widget_set_parent (child->widget, GTK_WIDGET (toolbar));
3963     }
3964   else
3965     {
3966       content->u.compatibility.space_visible = TRUE;
3967       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3968     }
3969  
3970   if (type == GTK_TOOLBAR_CHILD_BUTTON ||
3971       type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
3972       type == GTK_TOOLBAR_CHILD_RADIOBUTTON)
3973     {
3974       set_child_packing_and_visibility (toolbar, child);
3975     }
3976
3977   priv->content = g_list_insert (priv->content, content, pos);
3978   toolbar->children = g_list_insert (toolbar->children, child, pos);
3979   priv->need_rebuild = TRUE;
3980   
3981   toolbar->num_children++;
3982   
3983   return content;
3984 }
3985
3986 static void
3987 toolbar_content_remove (ToolbarContent *content,
3988                         GtkToolbar     *toolbar)
3989 {
3990   GtkToolbarChild *child;
3991   GtkToolbarPrivate *priv;
3992
3993   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3994   
3995   switch (content->type)
3996     {
3997     case TOOL_ITEM:
3998       gtk_widget_unparent (GTK_WIDGET (content->u.tool_item.item));
3999       break;
4000       
4001     case COMPATIBILITY:
4002       child = &(content->u.compatibility.child);
4003       
4004       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
4005         {
4006           g_object_ref (child->widget);
4007           gtk_widget_unparent (child->widget);
4008           gtk_widget_destroy (child->widget);
4009           g_object_unref (child->widget);
4010         }
4011       
4012       toolbar->children = g_list_remove (toolbar->children, child);
4013       break;
4014     }
4015
4016   priv->content = g_list_remove (priv->content, content);
4017
4018   if (!toolbar_content_is_placeholder (content))
4019     toolbar->num_children--;
4020
4021   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
4022   priv->need_rebuild = TRUE;
4023 }
4024
4025 static void
4026 toolbar_content_free (ToolbarContent *content)
4027 {
4028   g_slice_free (ToolbarContent, content);
4029 }
4030
4031 static gint
4032 calculate_max_homogeneous_pixels (GtkWidget *widget)
4033 {
4034   PangoContext *context;
4035   PangoFontMetrics *metrics;
4036   gint char_width;
4037   
4038   context = gtk_widget_get_pango_context (widget);
4039   metrics = pango_context_get_metrics (context,
4040                                        widget->style->font_desc,
4041                                        pango_context_get_language (context));
4042   char_width = pango_font_metrics_get_approximate_char_width (metrics);
4043   pango_font_metrics_unref (metrics);
4044   
4045   return PANGO_PIXELS (MAX_HOMOGENEOUS_N_CHARS * char_width);
4046 }
4047
4048 static void
4049 toolbar_content_expose (ToolbarContent *content,
4050                         GtkContainer   *container,
4051                         GdkEventExpose *expose)
4052 {
4053   GtkToolbar *toolbar = GTK_TOOLBAR (container);
4054   GtkToolbarChild *child;
4055   GtkWidget *widget = NULL; /* quiet gcc */
4056   
4057   switch (content->type)
4058     {
4059     case TOOL_ITEM:
4060       if (!content->u.tool_item.is_placeholder)
4061         widget = GTK_WIDGET (content->u.tool_item.item);
4062       break;
4063       
4064     case COMPATIBILITY:
4065       child = &(content->u.compatibility.child);
4066       
4067       if (child->type == GTK_TOOLBAR_CHILD_SPACE)
4068         {
4069           if (content->u.compatibility.space_visible &&
4070               get_space_style (toolbar) == GTK_TOOLBAR_SPACE_LINE)
4071              _gtk_toolbar_paint_space_line (GTK_WIDGET (toolbar), toolbar,
4072                                             &expose->area,
4073                                             &content->u.compatibility.space_allocation);
4074           return;
4075         }
4076       
4077       widget = child->widget;
4078       break;
4079     }
4080   
4081   if (widget)
4082     gtk_container_propagate_expose (container, widget, expose);
4083 }
4084
4085 static gboolean
4086 toolbar_content_visible (ToolbarContent *content,
4087                          GtkToolbar     *toolbar)
4088 {
4089   GtkToolItem *item;
4090   
4091   switch (content->type)
4092     {
4093     case TOOL_ITEM:
4094       item = content->u.tool_item.item;
4095       
4096       if (!GTK_WIDGET_VISIBLE (item))
4097         return FALSE;
4098       
4099       if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL &&
4100           gtk_tool_item_get_visible_horizontal (item))
4101         return TRUE;
4102       
4103       if ((toolbar->orientation == GTK_ORIENTATION_VERTICAL &&
4104            gtk_tool_item_get_visible_vertical (item)))
4105         return TRUE;
4106       
4107       return FALSE;
4108       break;
4109       
4110     case COMPATIBILITY:
4111       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4112         return GTK_WIDGET_VISIBLE (content->u.compatibility.child.widget);
4113       else
4114         return TRUE;
4115       break;
4116     }
4117   
4118   g_assert_not_reached ();
4119   return FALSE;
4120 }
4121
4122 static void
4123 toolbar_content_size_request (ToolbarContent *content,
4124                               GtkToolbar     *toolbar,
4125                               GtkRequisition *requisition)
4126 {
4127   gint space_size;
4128   
4129   switch (content->type)
4130     {
4131     case TOOL_ITEM:
4132       gtk_widget_size_request (GTK_WIDGET (content->u.tool_item.item),
4133                                requisition);
4134       if (content->u.tool_item.is_placeholder &&
4135           content->u.tool_item.disappearing)
4136         {
4137           requisition->width = 0;
4138           requisition->height = 0;
4139         }
4140       break;
4141       
4142     case COMPATIBILITY:
4143       space_size = get_space_size (toolbar);
4144       
4145       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4146         {
4147           gtk_widget_size_request (content->u.compatibility.child.widget,
4148                                    requisition);
4149         }
4150       else
4151         {
4152           if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
4153             {
4154               requisition->width = space_size;
4155               requisition->height = 0;
4156             }
4157           else
4158             {
4159               requisition->height = space_size;
4160               requisition->width = 0;
4161             }
4162         }
4163       
4164       break;
4165     }
4166 }
4167
4168 static gboolean
4169 toolbar_content_is_homogeneous (ToolbarContent *content,
4170                                 GtkToolbar     *toolbar)
4171 {
4172   gboolean result = FALSE;      /* quiet gcc */
4173   GtkRequisition requisition;
4174   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4175   
4176   if (priv->max_homogeneous_pixels < 0)
4177     {
4178       priv->max_homogeneous_pixels =
4179         calculate_max_homogeneous_pixels (GTK_WIDGET (toolbar));
4180     }
4181   
4182   toolbar_content_size_request (content, toolbar, &requisition);
4183   
4184   if (requisition.width > priv->max_homogeneous_pixels)
4185     return FALSE;
4186   
4187   switch (content->type)
4188     {
4189     case TOOL_ITEM:
4190       result = gtk_tool_item_get_homogeneous (content->u.tool_item.item) &&
4191         !GTK_IS_SEPARATOR_TOOL_ITEM (content->u.tool_item.item);
4192       
4193       if (gtk_tool_item_get_is_important (content->u.tool_item.item) &&
4194           toolbar->style == GTK_TOOLBAR_BOTH_HORIZ &&
4195           toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
4196         {
4197           result = FALSE;
4198         }
4199       break;
4200       
4201     case COMPATIBILITY:
4202       if (content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_BUTTON ||
4203           content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4204           content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4205         {
4206           result = TRUE;
4207         }
4208       else
4209         {
4210           result = FALSE;
4211         }
4212       break;
4213     }
4214   
4215   return result;
4216 }
4217
4218 static gboolean
4219 toolbar_content_is_placeholder (ToolbarContent *content)
4220 {
4221   if (content->type == TOOL_ITEM && content->u.tool_item.is_placeholder)
4222     return TRUE;
4223   
4224   return FALSE;
4225 }
4226
4227 static gboolean
4228 toolbar_content_disappearing (ToolbarContent *content)
4229 {
4230   if (content->type == TOOL_ITEM && content->u.tool_item.disappearing)
4231     return TRUE;
4232   
4233   return FALSE;
4234 }
4235
4236 static ItemState
4237 toolbar_content_get_state (ToolbarContent *content)
4238 {
4239   return content->state;
4240 }
4241
4242 static gboolean
4243 toolbar_content_child_visible (ToolbarContent *content)
4244 {
4245   switch (content->type)
4246     {
4247     case TOOL_ITEM:
4248       return GTK_WIDGET_CHILD_VISIBLE (content->u.tool_item.item);
4249       break;
4250       
4251     case COMPATIBILITY:
4252       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4253         {
4254           return GTK_WIDGET_CHILD_VISIBLE (content->u.compatibility.child.widget);
4255         }
4256       else
4257         {
4258           return content->u.compatibility.space_visible;
4259         }
4260       break;
4261     }
4262   
4263   return FALSE; /* quiet gcc */
4264 }
4265
4266 static void
4267 toolbar_content_get_goal_allocation (ToolbarContent *content,
4268                                      GtkAllocation  *allocation)
4269 {
4270   switch (content->type)
4271     {
4272     case TOOL_ITEM:
4273       *allocation = content->u.tool_item.goal_allocation;
4274       break;
4275       
4276     case COMPATIBILITY:
4277       /* Goal allocations are only relevant when we are
4278        * using the new API, so we should never get here
4279        */
4280       g_assert_not_reached ();
4281       break;
4282     }
4283 }
4284
4285 static void
4286 toolbar_content_get_allocation (ToolbarContent *content,
4287                                 GtkAllocation  *allocation)
4288 {
4289   GtkToolbarChild *child;
4290   
4291   switch (content->type)
4292     {
4293     case TOOL_ITEM:
4294       *allocation = GTK_WIDGET (content->u.tool_item.item)->allocation;
4295       break;
4296       
4297     case COMPATIBILITY:
4298       child = &(content->u.compatibility.child);
4299       
4300       if (child->type == GTK_TOOLBAR_CHILD_SPACE)
4301         *allocation = content->u.compatibility.space_allocation;
4302       else
4303         *allocation = child->widget->allocation;
4304       break;
4305     }
4306 }
4307
4308 static void
4309 toolbar_content_set_start_allocation (ToolbarContent *content,
4310                                       GtkAllocation  *allocation)
4311 {
4312   switch (content->type)
4313     {
4314     case TOOL_ITEM:
4315       content->u.tool_item.start_allocation = *allocation;
4316       break;
4317       
4318     case COMPATIBILITY:
4319       /* start_allocation is only relevant when using the new API */
4320       g_assert_not_reached ();
4321       break;
4322     }
4323 }
4324
4325 static gboolean
4326 toolbar_content_get_expand (ToolbarContent *content)
4327 {
4328   if (content->type == TOOL_ITEM &&
4329       gtk_tool_item_get_expand (content->u.tool_item.item) &&
4330       !content->u.tool_item.disappearing)
4331     {
4332       return TRUE;
4333     }
4334   
4335   return FALSE;
4336 }
4337
4338 static void
4339 toolbar_content_set_goal_allocation (ToolbarContent *content,
4340                                      GtkAllocation  *allocation)
4341 {
4342   switch (content->type)
4343     {
4344     case TOOL_ITEM:
4345       content->u.tool_item.goal_allocation = *allocation;
4346       break;
4347       
4348     case COMPATIBILITY:
4349       /* Only relevant when using new API */
4350       g_assert_not_reached ();
4351       break;
4352     }
4353 }
4354
4355 static void
4356 toolbar_content_set_child_visible (ToolbarContent *content,
4357                                    GtkToolbar     *toolbar,
4358                                    gboolean        visible)
4359 {
4360   GtkToolbarChild *child;
4361   
4362   switch (content->type)
4363     {
4364     case TOOL_ITEM:
4365       gtk_widget_set_child_visible (GTK_WIDGET (content->u.tool_item.item),
4366                                     visible);
4367       break;
4368       
4369     case COMPATIBILITY:
4370       child = &(content->u.compatibility.child);
4371       
4372       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
4373         {
4374           gtk_widget_set_child_visible (child->widget, visible);
4375         }
4376       else
4377         {
4378           if (content->u.compatibility.space_visible != visible)
4379             {
4380               content->u.compatibility.space_visible = visible;
4381               gtk_widget_queue_draw (GTK_WIDGET (toolbar));
4382             }
4383         }
4384       break;
4385     }
4386 }
4387
4388 static void
4389 toolbar_content_get_start_allocation (ToolbarContent *content,
4390                                       GtkAllocation  *start_allocation)
4391 {
4392   switch (content->type)
4393     {
4394     case TOOL_ITEM:
4395       *start_allocation = content->u.tool_item.start_allocation;
4396       break;
4397       
4398     case COMPATIBILITY:
4399       /* Only relevant for new API */
4400       g_assert_not_reached ();
4401       break;
4402     }
4403 }
4404
4405 static void
4406 toolbar_content_size_allocate (ToolbarContent *content,
4407                                GtkAllocation  *allocation)
4408 {
4409   switch (content->type)
4410     {
4411     case TOOL_ITEM:
4412       gtk_widget_size_allocate (GTK_WIDGET (content->u.tool_item.item),
4413                                 allocation);
4414       break;
4415       
4416     case COMPATIBILITY:
4417       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4418         {
4419           gtk_widget_size_allocate (content->u.compatibility.child.widget,
4420                                     allocation);
4421         }
4422       else
4423         {
4424           content->u.compatibility.space_allocation = *allocation;
4425         }
4426       break;
4427     }
4428 }
4429
4430 static void
4431 toolbar_content_set_state (ToolbarContent *content,
4432                            ItemState       state)
4433 {
4434   content->state = state;
4435 }
4436
4437 static GtkWidget *
4438 toolbar_content_get_widget (ToolbarContent *content)
4439 {
4440   GtkToolbarChild *child;
4441   
4442   switch (content->type)
4443     {
4444     case TOOL_ITEM:
4445       return GTK_WIDGET (content->u.tool_item.item);
4446       break;
4447       
4448     case COMPATIBILITY:
4449       child = &(content->u.compatibility.child);
4450       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
4451         return child->widget;
4452       else
4453         return NULL;
4454       break;
4455     }
4456   
4457   return NULL;
4458 }
4459
4460 static void
4461 toolbar_content_set_disappearing (ToolbarContent *content,
4462                                   gboolean        disappearing)
4463 {
4464   switch (content->type)
4465     {
4466     case TOOL_ITEM:
4467       content->u.tool_item.disappearing = disappearing;
4468       break;
4469       
4470     case COMPATIBILITY:
4471       /* Only relevant for new API */
4472       g_assert_not_reached ();
4473       break;
4474     }
4475 }
4476
4477 static void
4478 toolbar_content_set_size_request (ToolbarContent *content,
4479                                   gint            width,
4480                                   gint            height)
4481 {
4482   switch (content->type)
4483     {
4484     case TOOL_ITEM:
4485       gtk_widget_set_size_request (GTK_WIDGET (content->u.tool_item.item),
4486                                    width, height);
4487       break;
4488       
4489     case COMPATIBILITY:
4490       /* Setting size requests only happens with sliding,
4491        * so not relevant here
4492        */
4493       g_assert_not_reached ();
4494       break;
4495     }
4496 }
4497
4498 static void
4499 toolbar_child_reconfigure (GtkToolbar      *toolbar,
4500                            GtkToolbarChild *child)
4501 {
4502   GtkWidget *box;
4503   GtkImage *image;
4504   GtkToolbarStyle style;
4505   GtkIconSize icon_size;
4506   GtkReliefStyle relief;
4507   gchar *stock_id;
4508   
4509   style = gtk_toolbar_get_style (toolbar);
4510   icon_size = gtk_toolbar_get_icon_size (toolbar);
4511   relief = gtk_toolbar_get_relief_style (toolbar);
4512   
4513   /* style */
4514   if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4515       child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4516       child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4517     {
4518       box = gtk_bin_get_child (GTK_BIN (child->widget));
4519       
4520       if (style == GTK_TOOLBAR_BOTH && GTK_IS_HBOX (box))
4521         {
4522           GtkWidget *vbox;
4523           
4524           vbox = gtk_vbox_new (FALSE, 0);
4525           
4526           if (child->label)
4527             gtk_widget_reparent (child->label, vbox);
4528           if (child->icon)
4529             gtk_widget_reparent (child->icon, vbox);
4530           
4531           gtk_widget_destroy (box);
4532           gtk_container_add (GTK_CONTAINER (child->widget), vbox);
4533           
4534           gtk_widget_show (vbox);
4535         }
4536       else if (style == GTK_TOOLBAR_BOTH_HORIZ && GTK_IS_VBOX (box))
4537         {
4538           GtkWidget *hbox;
4539           
4540           hbox = gtk_hbox_new (FALSE, 0);
4541           
4542           if (child->label)
4543             gtk_widget_reparent (child->label, hbox);
4544           if (child->icon)
4545             gtk_widget_reparent (child->icon, hbox);
4546           
4547           gtk_widget_destroy (box);
4548           gtk_container_add (GTK_CONTAINER (child->widget), hbox);
4549           
4550           gtk_widget_show (hbox);
4551         }
4552
4553       set_child_packing_and_visibility (toolbar, child);
4554     }
4555   
4556   /* icon size */
4557   
4558   if ((child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4559        child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
4560        child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON) &&
4561       GTK_IS_IMAGE (child->icon))
4562     {
4563       image = GTK_IMAGE (child->icon);
4564       if (gtk_image_get_storage_type (image) == GTK_IMAGE_STOCK)
4565         {
4566           gtk_image_get_stock (image, &stock_id, NULL);
4567           stock_id = g_strdup (stock_id);
4568           gtk_image_set_from_stock (image,
4569                                     stock_id,
4570                                     icon_size);
4571           g_free (stock_id);
4572         }
4573     }
4574   
4575   /* relief */
4576   if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4577       child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4578       child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4579     {
4580       gtk_button_set_relief (GTK_BUTTON (child->widget), relief);
4581     }
4582 }
4583
4584 static void
4585 toolbar_content_toolbar_reconfigured (ToolbarContent *content,
4586                                       GtkToolbar     *toolbar)
4587 {
4588   switch (content->type)
4589     {
4590     case TOOL_ITEM:
4591       gtk_tool_item_toolbar_reconfigured (content->u.tool_item.item);
4592       break;
4593       
4594     case COMPATIBILITY:
4595       toolbar_child_reconfigure (toolbar, &(content->u.compatibility.child));
4596       break;
4597     }
4598 }
4599
4600 static GtkWidget *
4601 toolbar_content_retrieve_menu_item (ToolbarContent *content)
4602 {
4603   if (content->type == TOOL_ITEM)
4604     return gtk_tool_item_retrieve_proxy_menu_item (content->u.tool_item.item);
4605   
4606   /* FIXME - we might actually be able to do something meaningful here */
4607   return NULL; 
4608 }
4609
4610 static gboolean
4611 toolbar_content_has_proxy_menu_item (ToolbarContent *content)
4612 {
4613   if (content->type == TOOL_ITEM)
4614     {
4615       GtkWidget *menu_item;
4616
4617       if (content->u.tool_item.has_menu == YES)
4618         return TRUE;
4619       else if (content->u.tool_item.has_menu == NO)
4620         return FALSE;
4621
4622       menu_item = toolbar_content_retrieve_menu_item (content);
4623
4624       content->u.tool_item.has_menu = menu_item? YES : NO;
4625       
4626       return menu_item != NULL;
4627     }
4628   else
4629     {
4630       return FALSE;
4631     }
4632 }
4633
4634 static void
4635 toolbar_content_set_unknown_menu_status (ToolbarContent *content)
4636 {
4637   if (content->type == TOOL_ITEM)
4638     content->u.tool_item.has_menu = UNKNOWN;
4639 }
4640
4641 static gboolean
4642 toolbar_content_is_separator (ToolbarContent *content)
4643 {
4644   GtkToolbarChild *child;
4645   
4646   switch (content->type)
4647     {
4648     case TOOL_ITEM:
4649       return GTK_IS_SEPARATOR_TOOL_ITEM (content->u.tool_item.item);
4650       break;
4651       
4652     case COMPATIBILITY:
4653       child = &(content->u.compatibility.child);
4654       return (child->type == GTK_TOOLBAR_CHILD_SPACE);
4655       break;
4656     }
4657   
4658   return FALSE;
4659 }
4660
4661 static void
4662 toolbar_content_set_expand (ToolbarContent *content,
4663                             gboolean        expand)
4664 {
4665   if (content->type == TOOL_ITEM)
4666     gtk_tool_item_set_expand (content->u.tool_item.item, expand);
4667 }
4668
4669 static gboolean
4670 ignore_show_and_hide_all (ToolbarContent *content)
4671 {
4672   if (content->type == COMPATIBILITY)
4673     {
4674       GtkToolbarChildType type = content->u.compatibility.child.type;
4675       
4676       if (type == GTK_TOOLBAR_CHILD_BUTTON ||
4677           type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
4678           type == GTK_TOOLBAR_CHILD_RADIOBUTTON)
4679         {
4680           return TRUE;
4681         }
4682     }
4683   
4684   return FALSE;
4685 }
4686
4687 static void
4688 toolbar_content_show_all (ToolbarContent  *content)
4689 {
4690   GtkWidget *widget;
4691   
4692   if (ignore_show_and_hide_all (content))
4693     return;
4694
4695   widget = toolbar_content_get_widget (content);
4696   if (widget)
4697     gtk_widget_show_all (widget);
4698 }
4699
4700 static void
4701 toolbar_content_hide_all (ToolbarContent  *content)
4702 {
4703   GtkWidget *widget;
4704   
4705   if (ignore_show_and_hide_all (content))
4706     return;
4707
4708   widget = toolbar_content_get_widget (content);
4709   if (widget)
4710     gtk_widget_hide_all (widget);
4711 }
4712
4713 /*
4714  * Getters
4715  */
4716 static gint
4717 get_space_size (GtkToolbar *toolbar)
4718 {
4719   gint space_size = DEFAULT_SPACE_SIZE;
4720   
4721   if (toolbar)
4722     {
4723       gtk_widget_style_get (GTK_WIDGET (toolbar),
4724                             "space-size", &space_size,
4725                             NULL);
4726     }
4727   
4728   return space_size;
4729 }
4730
4731 static GtkToolbarSpaceStyle
4732 get_space_style (GtkToolbar *toolbar)
4733 {
4734   GtkToolbarSpaceStyle space_style = DEFAULT_SPACE_STYLE;
4735
4736   if (toolbar)
4737     {
4738       gtk_widget_style_get (GTK_WIDGET (toolbar),
4739                             "space-style", &space_style,
4740                             NULL);
4741     }
4742   
4743   return space_style;  
4744 }
4745
4746 static GtkReliefStyle
4747 get_button_relief (GtkToolbar *toolbar)
4748 {
4749   GtkReliefStyle button_relief = GTK_RELIEF_NORMAL;
4750   
4751   gtk_widget_ensure_style (GTK_WIDGET (toolbar));
4752   
4753   gtk_widget_style_get (GTK_WIDGET (toolbar),
4754                         "button-relief", &button_relief,
4755                         NULL);
4756   
4757   return button_relief;
4758 }
4759
4760 static gint
4761 get_internal_padding (GtkToolbar *toolbar)
4762 {
4763   gint ipadding = 0;
4764   
4765   gtk_widget_style_get (GTK_WIDGET (toolbar),
4766                         "internal-padding", &ipadding,
4767                         NULL);
4768   
4769   return ipadding;
4770 }
4771
4772 static gint
4773 get_max_child_expand (GtkToolbar *toolbar)
4774 {
4775   gint mexpand = G_MAXINT;
4776
4777   gtk_widget_style_get (GTK_WIDGET (toolbar),
4778                         "max-child-expand", &mexpand,
4779                         NULL);
4780   return mexpand;
4781 }
4782
4783 static GtkShadowType
4784 get_shadow_type (GtkToolbar *toolbar)
4785 {
4786   GtkShadowType shadow_type;
4787   
4788   gtk_widget_style_get (GTK_WIDGET (toolbar),
4789                         "shadow-type", &shadow_type,
4790                         NULL);
4791   
4792   return shadow_type;
4793 }
4794
4795 /*
4796  * API checks
4797  */
4798 static gboolean
4799 gtk_toolbar_check_old_api (GtkToolbar *toolbar)
4800 {
4801   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4802   
4803   if (priv->api_mode == NEW_API)
4804     {
4805       g_warning (MIXED_API_WARNING);
4806       return FALSE;
4807     }
4808   
4809   priv->api_mode = OLD_API;
4810   return TRUE;
4811 }
4812
4813 static gboolean
4814 gtk_toolbar_check_new_api (GtkToolbar *toolbar)
4815 {
4816   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4817   
4818   if (priv->api_mode == OLD_API)
4819     {
4820       g_warning (MIXED_API_WARNING);
4821       return FALSE;
4822     }
4823   
4824   priv->api_mode = NEW_API;
4825   return TRUE;
4826 }
4827
4828 /* GTK+ internal methods */
4829
4830 gint
4831 _gtk_toolbar_get_default_space_size (void)
4832 {
4833   return DEFAULT_SPACE_SIZE;
4834 }
4835
4836 void
4837 _gtk_toolbar_paint_space_line (GtkWidget           *widget,
4838                                GtkToolbar          *toolbar,
4839                                const GdkRectangle  *area,
4840                                const GtkAllocation *allocation)
4841 {
4842   const double start_fraction = (SPACE_LINE_START / SPACE_LINE_DIVISION);
4843   const double end_fraction = (SPACE_LINE_END / SPACE_LINE_DIVISION);
4844   
4845   GtkOrientation orientation;
4846
4847   g_return_if_fail (GTK_IS_WIDGET (widget));
4848   
4849   orientation = toolbar? toolbar->orientation : GTK_ORIENTATION_HORIZONTAL;
4850
4851   if (orientation == GTK_ORIENTATION_HORIZONTAL)
4852     {
4853       gboolean wide_separators;
4854       gint     separator_width;
4855
4856       gtk_widget_style_get (widget,
4857                             "wide-separators", &wide_separators,
4858                             "separator-width", &separator_width,
4859                             NULL);
4860
4861       if (wide_separators)
4862         gtk_paint_box (widget->style, widget->window,
4863                        GTK_WIDGET_STATE (widget), GTK_SHADOW_ETCHED_OUT,
4864                        area, widget, "vseparator",
4865                        allocation->x + (allocation->width - separator_width) / 2,
4866                        allocation->y + allocation->height * start_fraction,
4867                        separator_width,
4868                        allocation->height * (end_fraction - start_fraction));
4869       else
4870         gtk_paint_vline (widget->style, widget->window,
4871                          GTK_WIDGET_STATE (widget), area, widget,
4872                          "toolbar",
4873                          allocation->y + allocation->height * start_fraction,
4874                          allocation->y + allocation->height * end_fraction,
4875                          allocation->x + (allocation->width - widget->style->xthickness) / 2);
4876     }
4877   else
4878     {
4879       gboolean wide_separators;
4880       gint     separator_height;
4881
4882       gtk_widget_style_get (widget,
4883                             "wide-separators",  &wide_separators,
4884                             "separator-height", &separator_height,
4885                             NULL);
4886
4887       if (wide_separators)
4888         gtk_paint_box (widget->style, widget->window,
4889                        GTK_WIDGET_STATE (widget), GTK_SHADOW_ETCHED_OUT,
4890                        area, widget, "hseparator",
4891                        allocation->x + allocation->width * start_fraction,
4892                        allocation->y + (allocation->height - separator_height) / 2,
4893                        allocation->width * (end_fraction - start_fraction),
4894                        separator_height);
4895       else
4896         gtk_paint_hline (widget->style, widget->window,
4897                          GTK_WIDGET_STATE (widget), area, widget,
4898                          "toolbar",
4899                          allocation->x + allocation->width * start_fraction,
4900                          allocation->x + allocation->width * end_fraction,
4901                          allocation->y + (allocation->height - widget->style->ythickness) / 2);
4902     }
4903 }
4904
4905 gchar *
4906 _gtk_toolbar_elide_underscores (const gchar *original)
4907 {
4908   gchar *q, *result;
4909   const gchar *p, *end;
4910   gsize len;
4911   gboolean last_underscore;
4912   
4913   if (!original)
4914     return NULL;
4915
4916   len = strlen (original);
4917   q = result = g_malloc (len + 1);
4918   last_underscore = FALSE;
4919   
4920   end = original + len;
4921   for (p = original; p < end; p++)
4922     {
4923       if (!last_underscore && *p == '_')
4924         last_underscore = TRUE;
4925       else
4926         {
4927           last_underscore = FALSE;
4928           if (original + 2 <= p && p + 1 <= end && 
4929               p[-2] == '(' && p[-1] == '_' && p[0] != '_' && p[1] == ')')
4930             {
4931               q--;
4932               *q = '\0';
4933               p++;
4934             }
4935           else
4936             *q++ = *p;
4937         }
4938     }
4939
4940   if (last_underscore)
4941     *q++ = '_';
4942   
4943   *q = '\0';
4944   
4945   return result;
4946 }
4947
4948 static GtkIconSize
4949 toolbar_get_icon_size (GtkToolShell *shell)
4950 {
4951   return GTK_TOOLBAR (shell)->icon_size;
4952 }
4953
4954 static GtkOrientation
4955 toolbar_get_orientation (GtkToolShell *shell)
4956 {
4957   return GTK_TOOLBAR (shell)->orientation;
4958 }
4959
4960 static GtkToolbarStyle
4961 toolbar_get_style (GtkToolShell *shell)
4962 {
4963   return GTK_TOOLBAR (shell)->style;
4964 }
4965
4966 static GtkReliefStyle
4967 toolbar_get_relief_style (GtkToolShell *shell)
4968 {
4969   return get_button_relief (GTK_TOOLBAR (shell));
4970 }
4971
4972 static void
4973 toolbar_rebuild_menu (GtkToolShell *shell)
4974 {
4975   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (shell);
4976   GList *list;
4977
4978   priv->need_rebuild = TRUE;
4979
4980   for (list = priv->content; list != NULL; list = list->next)
4981     {
4982       ToolbarContent *content = list->data;
4983
4984       toolbar_content_set_unknown_menu_status (content);
4985     }
4986   
4987   gtk_widget_queue_resize (GTK_WIDGET (shell));
4988 }
4989
4990 #define __GTK_TOOLBAR_C__
4991 #include "gtkaliasdef.c"