]> Pileus Git - ~andy/gtk/blob - gtk/gtktoolbar.c
The first part of the fix for #114351 (see also gdk-pixbuf/ChangeLog and
[~andy/gtk] / gtk / gtktoolbar.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * GtkToolbar copyright (C) Federico Mena
4  *
5  * Copyright (C) 2002 Anders Carlsson <andersca@gnome.org>
6  * Copyright (C) 2002 James Henstridge <james@daa.com.au>
7  * Copyright (C) 2003 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 "gtkarrow.h"
35 #include "gtktoolbar.h"
36 #include "gtkradiotoolbutton.h"
37 #include "gtkseparatortoolitem.h"
38 #include "gtkmenu.h"
39 #include "gtkradiobutton.h"
40 #include "gtktoolbar.h"
41 #include "gtkbindings.h"
42 #include <gdk/gdkkeysyms.h>
43 #include "gtkmarshalers.h"
44 #include "gtkmain.h"
45 #include "gtkstock.h"
46 #include "gtklabel.h"
47 #include "gtkprivate.h"
48 #include "gtkintl.h"
49 #include <string.h>
50
51 #define DEFAULT_IPADDING 0
52
53 /* note: keep in sync with DEFAULT_SPACE_SIZE and DEFAULT_SPACE_STYLE in gtkseparatortoolitem.c */
54 #define DEFAULT_SPACE_SIZE  4
55 #define DEFAULT_SPACE_STYLE GTK_TOOLBAR_SPACE_LINE
56
57 #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_LARGE_TOOLBAR
58 #define DEFAULT_TOOLBAR_STYLE GTK_TOOLBAR_BOTH
59
60 #define MAX_HOMOGENEOUS_N_CHARS 13 /* Items that are wider than this do not participate
61                                     * in the homogeneous game. In units of
62                                     * pango_font_get_estimated_char_width().
63                                     */
64
65 enum {
66   PROP_0,
67   PROP_ORIENTATION,
68   PROP_TOOLBAR_STYLE,
69   PROP_SHOW_ARROW
70 };
71
72 enum {
73   CHILD_PROP_0,
74   CHILD_PROP_EXPAND,
75   CHILD_PROP_HOMOGENEOUS
76 };
77
78 enum {
79   ORIENTATION_CHANGED,
80   STYLE_CHANGED,
81   POPUP_CONTEXT_MENU,
82   MOVE_FOCUS,
83   FOCUS_HOME_OR_END,
84   LAST_SIGNAL
85 };
86
87 static void gtk_toolbar_init       (GtkToolbar      *toolbar);
88 static void gtk_toolbar_class_init (GtkToolbarClass *klass);
89
90 static void gtk_toolbar_set_property (GObject      *object,
91                                       guint         prop_id,
92                                       const GValue *value,
93                                       GParamSpec   *pspec);
94 static void gtk_toolbar_get_property (GObject      *object,
95                                       guint         prop_id,
96                                       GValue       *value,
97                                       GParamSpec   *pspec);
98
99 static gint     gtk_toolbar_expose         (GtkWidget        *widget,
100                                             GdkEventExpose   *event);
101 static void     gtk_toolbar_realize        (GtkWidget        *widget);
102 static void     gtk_toolbar_unrealize      (GtkWidget        *widget);
103 static void     gtk_toolbar_size_request   (GtkWidget        *widget,
104                                             GtkRequisition   *requisition);
105 static void     gtk_toolbar_size_allocate  (GtkWidget        *widget,
106                                             GtkAllocation    *allocation);
107 static void     gtk_toolbar_style_set      (GtkWidget        *widget,
108                                             GtkStyle         *prev_style);
109 static void     gtk_toolbar_direction_changed (GtkWidget        *widget,
110                                                GtkTextDirection  previous_direction);
111 static gboolean gtk_toolbar_focus          (GtkWidget        *widget,
112                                             GtkDirectionType  dir);
113 static void     gtk_toolbar_screen_changed (GtkWidget        *widget,
114                                             GdkScreen        *previous_screen);
115 static void     gtk_toolbar_map            (GtkWidget        *widget);
116 static void     gtk_toolbar_unmap          (GtkWidget        *widget);
117
118 static void     gtk_toolbar_set_child_property (GtkContainer    *container,
119                                                 GtkWidget       *child,
120                                                 guint            property_id,
121                                                 const GValue    *value,
122                                                 GParamSpec      *pspec);
123 static void    gtk_toolbar_get_child_property (GtkContainer    *container,
124                                                GtkWidget       *child,
125                                                guint            property_id,
126                                                GValue          *value,
127                                                GParamSpec      *pspec);
128 static void gtk_toolbar_finalize (GObject *object);
129
130
131 static void  gtk_toolbar_add        (GtkContainer *container,
132                                      GtkWidget    *widget);
133 static void  gtk_toolbar_remove     (GtkContainer *container,
134                                      GtkWidget    *widget);
135 static void  gtk_toolbar_forall     (GtkContainer *container,
136                                      gboolean      include_internals,
137                                      GtkCallback   callback,
138                                      gpointer      callback_data);
139 static GType gtk_toolbar_child_type (GtkContainer *container);
140
141 static void gtk_toolbar_real_orientation_changed (GtkToolbar      *toolbar,
142                                                   GtkOrientation   orientation);
143 static void gtk_toolbar_real_style_changed       (GtkToolbar      *toolbar,
144                                                   GtkToolbarStyle  style);
145
146 static gboolean gtk_toolbar_move_focus        (GtkToolbar       *toolbar,
147                                                GtkDirectionType  dir);
148 static gboolean gtk_toolbar_focus_home_or_end (GtkToolbar       *toolbar,
149                                                gboolean          focus_home);
150
151 static gboolean             gtk_toolbar_button_press         (GtkWidget      *toolbar,
152                                                               GdkEventButton *event);
153 static gboolean             gtk_toolbar_arrow_button_press (GtkWidget      *button,
154                                                               GdkEventButton *event,
155                                                               GtkToolbar     *toolbar);
156 static void                 gtk_toolbar_arrow_button_clicked (GtkWidget      *button,
157                                                                GtkToolbar     *toolbar);
158 static void                 gtk_toolbar_update_button_relief (GtkToolbar     *toolbar);
159 static GtkReliefStyle       get_button_relief                (GtkToolbar     *toolbar);
160 static gint                 get_internal_padding             (GtkToolbar     *toolbar);
161 static GtkShadowType        get_shadow_type                  (GtkToolbar     *toolbar);
162 static void                 gtk_toolbar_remove_tool_item     (GtkToolbar     *toolbar,
163                                                               GtkToolItem    *item);
164 static gboolean             gtk_toolbar_popup_menu           (GtkWidget      *toolbar);
165
166 static GtkWidget *gtk_toolbar_internal_insert_element (GtkToolbar          *toolbar,
167                                                        GtkToolbarChildType  type,
168                                                        GtkWidget           *widget,
169                                                        const char          *text,
170                                                        const char          *tooltip_text,
171                                                        const char          *tooltip_private_text,
172                                                        GtkWidget           *icon,
173                                                        GtkSignalFunc        callback,
174                                                        gpointer             user_data,
175                                                        gint                 position,
176                                                        gboolean             use_stock);
177
178 typedef struct _ToolbarContent ToolbarContent;
179
180 static ToolbarContent *gtk_toolbar_insert_tool_item (GtkToolbar  *toolbar,
181                                                      GtkToolItem *item,
182                                                      gint         pos,
183                                                      gboolean     is_placeholder);
184
185 static gboolean gtk_toolbar_check_new_api (GtkToolbar *toolbar);
186
187 typedef enum {
188   DONT_KNOW,
189   OLD_API,
190   NEW_API
191 } ApiMode;
192
193 #define GTK_TOOLBAR_GET_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_TOOLBAR, GtkToolbarPrivate))
194
195 typedef enum {
196   NOT_ALLOCATED,
197   NORMAL,
198   HIDDEN,
199   OVERFLOWN,
200 } ItemState;
201
202 struct _ToolbarContent
203 {
204   GtkToolItem * item;
205   guint         is_placeholder : 1;
206   guint         disappearing : 1;
207   GtkAllocation start_allocation;
208   GtkAllocation goal_allocation;
209   ItemState     state;
210 };
211
212 struct _GtkToolbarPrivate
213 {
214   GList *       content;
215   
216   GtkWidget *   arrow;
217   GtkWidget *   arrow_button;
218   
219   gboolean      show_arrow;
220
221   GtkMenu *     menu;
222
223   GdkWindow *   event_window;
224   ApiMode       api_mode;
225   GtkSettings * settings;
226   int           idle_id;
227   gboolean      need_sync;
228   GtkToolItem * highlight_tool_item;
229   gint          max_homogeneous_pixels;
230
231   GTimer *      timer;
232   gboolean      is_sliding;
233 };
234
235 static GtkContainerClass *parent_class = NULL;
236 static guint toolbar_signals [LAST_SIGNAL] = { 0 };
237
238 GType
239 gtk_toolbar_get_type (void)
240 {
241   static GtkType type = 0;
242
243   if (!type)
244     {
245       static const GTypeInfo type_info =
246         {
247           sizeof (GtkToolbarClass),
248           (GBaseInitFunc) NULL,
249           (GBaseFinalizeFunc) NULL,
250           (GClassInitFunc) gtk_toolbar_class_init,
251           (GClassFinalizeFunc) NULL,
252           NULL,
253           sizeof (GtkToolbar),
254           0, /* n_preallocs */
255           (GInstanceInitFunc) gtk_toolbar_init,
256         };
257
258       type = g_type_register_static (GTK_TYPE_CONTAINER,
259                                      "GtkToolbar",
260                                      &type_info, 0);
261     }
262   
263   return type;
264 }
265
266 static void
267 add_arrow_bindings (GtkBindingSet   *binding_set,
268                     guint            keysym,
269                     GtkDirectionType dir)
270 {
271   guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
272   
273   gtk_binding_entry_add_signal (binding_set, keysym, 0,
274                                 "move_focus", 1,
275                                 GTK_TYPE_DIRECTION_TYPE, dir);
276   gtk_binding_entry_add_signal (binding_set, keypad_keysym, 0,
277                                 "move_focus", 1,
278                                 GTK_TYPE_DIRECTION_TYPE, dir);
279 }
280
281 static void
282 add_ctrl_tab_bindings (GtkBindingSet    *binding_set,
283                        GdkModifierType   modifiers,
284                        GtkDirectionType  direction)
285 {
286   gtk_binding_entry_add_signal (binding_set,
287                                 GDK_Tab, GDK_CONTROL_MASK | modifiers,
288                                 "move_focus", 1,
289                                 GTK_TYPE_DIRECTION_TYPE, direction);
290   gtk_binding_entry_add_signal (binding_set,
291                                 GDK_KP_Tab, GDK_CONTROL_MASK | modifiers,
292                                 "move_focus", 1,
293                                 GTK_TYPE_DIRECTION_TYPE, direction);
294 }
295
296 static void
297 gtk_toolbar_class_init (GtkToolbarClass *klass)
298 {
299   GObjectClass *gobject_class;
300   GtkWidgetClass *widget_class;
301   GtkContainerClass *container_class;
302   GtkBindingSet *binding_set;
303
304   parent_class = g_type_class_peek_parent (klass);
305   
306   gobject_class = (GObjectClass *)klass;
307   widget_class = (GtkWidgetClass *)klass;
308   container_class = (GtkContainerClass *)klass;
309   
310   gobject_class->set_property = gtk_toolbar_set_property;
311   gobject_class->get_property = gtk_toolbar_get_property;
312   gobject_class->finalize = gtk_toolbar_finalize;
313
314   widget_class->button_press_event = gtk_toolbar_button_press;
315   widget_class->expose_event = gtk_toolbar_expose;
316   widget_class->size_request = gtk_toolbar_size_request;
317   widget_class->size_allocate = gtk_toolbar_size_allocate;
318   widget_class->style_set = gtk_toolbar_style_set;
319   widget_class->direction_changed = gtk_toolbar_direction_changed;
320   widget_class->focus = gtk_toolbar_focus;
321   widget_class->screen_changed = gtk_toolbar_screen_changed;
322   widget_class->realize = gtk_toolbar_realize;
323   widget_class->unrealize = gtk_toolbar_unrealize;
324   widget_class->map = gtk_toolbar_map;
325   widget_class->unmap = gtk_toolbar_unmap;
326   widget_class->popup_menu = gtk_toolbar_popup_menu;
327   
328   container_class->add    = gtk_toolbar_add;
329   container_class->remove = gtk_toolbar_remove;
330   container_class->forall = gtk_toolbar_forall;
331   container_class->child_type = gtk_toolbar_child_type;
332   container_class->get_child_property = gtk_toolbar_get_child_property;
333   container_class->set_child_property = gtk_toolbar_set_child_property;
334   
335   klass->orientation_changed = gtk_toolbar_real_orientation_changed;
336   klass->style_changed = gtk_toolbar_real_style_changed;
337   
338 /**
339  * GtkToolbar::orientation-changed:
340  * @toolbar: the object which emitted the signal
341  * @orientation: the new #GtkOrientation of the toolbar
342  *
343  * Emitted when the orientation of the toolbar changes.
344  */
345   toolbar_signals[ORIENTATION_CHANGED] =
346     g_signal_new ("orientation-changed",
347                   G_OBJECT_CLASS_TYPE (klass),
348                   G_SIGNAL_RUN_FIRST,
349                   G_STRUCT_OFFSET (GtkToolbarClass, orientation_changed),
350                   NULL, NULL,
351                   g_cclosure_marshal_VOID__ENUM,
352                   G_TYPE_NONE, 1,
353                   GTK_TYPE_ORIENTATION);
354 /**
355  * GtkToolbar::style-changed:
356  * @toolbar: The #GtkToolbar which emitted the signal
357  * @style: the new #GtkToolbarStyle of the toolbar
358  *
359  * Emitted when the style of the toolbar changes. 
360  */
361   toolbar_signals[STYLE_CHANGED] =
362     g_signal_new ("style-changed",
363                   G_OBJECT_CLASS_TYPE (klass),
364                   G_SIGNAL_RUN_FIRST,
365                   G_STRUCT_OFFSET (GtkToolbarClass, style_changed),
366                   NULL, NULL,
367                   g_cclosure_marshal_VOID__ENUM,
368                   G_TYPE_NONE, 1,
369                   GTK_TYPE_TOOLBAR_STYLE);
370 /**
371  * GtkToolbar::popup-context-menu:
372  * @toolbar: the #GtkToolbar which emitted the signal
373  * @x: the x coordinate of the point where the menu should appear
374  * @y: the y coordinate of the point where the menu should appear
375  * @button: the mouse button the user pressed, or -1
376  *
377  * Emitted when the user right-clicks the toolbar or uses the
378  * keybinding to display a popup menu.
379  *
380  * Application developers should handle this signal if they want
381  * to display a context menu on the toolbar. The context-menu should
382  * appear at the coordinates given by @x and @y. The mouse button
383  * number is given by the @button parameter. If the menu was popped
384  * up using the keybaord, @button is -1.
385  *
386  * Return value: return %TRUE if the signal was handled, %FALSE if not
387  */
388   toolbar_signals[POPUP_CONTEXT_MENU] =
389     g_signal_new ("popup_context_menu",
390                   G_OBJECT_CLASS_TYPE (klass),
391                   G_SIGNAL_RUN_LAST,
392                   G_STRUCT_OFFSET (GtkToolbarClass, popup_context_menu),
393                   _gtk_boolean_handled_accumulator, NULL,
394                   _gtk_marshal_BOOLEAN__INT_INT_INT,
395                   G_TYPE_BOOLEAN, 3,
396                   G_TYPE_INT, G_TYPE_INT,
397                   G_TYPE_INT);
398 /**
399  * GtkToolbar::move-focus:
400  * @toolbar: the #GtkToolbar which emitted the signal
401  * @dir: a #GtkDirection
402  *
403  * A keybinding signal used internally by GTK+. This signal can't
404  * be used in application code.
405  *
406  * Return value: %TRUE if the signal was handled, %FALSE if not
407  */
408   toolbar_signals[MOVE_FOCUS] =
409     _gtk_binding_signal_new ("move_focus",
410                              G_TYPE_FROM_CLASS (klass),
411                              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
412                              G_CALLBACK (gtk_toolbar_move_focus),
413                              NULL, NULL,
414                              _gtk_marshal_BOOLEAN__ENUM,
415                              G_TYPE_BOOLEAN, 1,
416                              GTK_TYPE_DIRECTION_TYPE);
417 /**
418  * GtkToolbar::focus-home-or-end:
419  * @toolbar: the #GtkToolbar which emitted the signal
420  * @focus_home: %TRUE if the first item should be focused
421  *
422  * A keybinding signal used internally by GTK+. This signal can't
423  * be used in application code
424  *
425  * Return value: %TRUE if the signal was handled, %FALSE if not
426  */
427   toolbar_signals[FOCUS_HOME_OR_END] =
428     _gtk_binding_signal_new ("focus_home_or_end",
429                              G_OBJECT_CLASS_TYPE (klass),
430                              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
431                              G_CALLBACK (gtk_toolbar_focus_home_or_end),
432                              NULL, NULL,
433                              _gtk_marshal_BOOLEAN__BOOLEAN,
434                              G_TYPE_BOOLEAN, 1,
435                              G_TYPE_BOOLEAN);
436
437   /* properties */
438   g_object_class_install_property (gobject_class,
439                                    PROP_ORIENTATION,
440                                    g_param_spec_enum ("orientation",
441                                                       P_("Orientation"),
442                                                       P_("The orientation of the toolbar"),
443                                                       GTK_TYPE_ORIENTATION,
444                                                       GTK_ORIENTATION_HORIZONTAL,
445                                                       G_PARAM_READWRITE));
446
447   g_object_class_install_property (gobject_class,
448                                    PROP_TOOLBAR_STYLE,
449                                    g_param_spec_enum ("toolbar_style",
450                                                       P_("Toolbar Style"),
451                                                       P_("How to draw the toolbar"),
452                                                       GTK_TYPE_TOOLBAR_STYLE,
453                                                       GTK_TOOLBAR_ICONS,
454                                                       G_PARAM_READWRITE));
455   g_object_class_install_property (gobject_class,
456                                    PROP_SHOW_ARROW,
457                                    g_param_spec_boolean ("show_arrow",
458                                                          P_("Show Arrow"),
459                                                          P_("If an arrow should be shown if the toolbar doesn't fit"),
460                                                          TRUE,
461                                                          G_PARAM_READWRITE));
462
463   /* child properties */
464   gtk_container_class_install_child_property (container_class,
465                                               CHILD_PROP_EXPAND,
466                                               g_param_spec_boolean ("expand", 
467                                                                     P_("Expand"), 
468                                                                     P_("Whether the item should receive extra space when the toolbar grows"),
469                                                                     TRUE,
470                                                                     G_PARAM_READWRITE));
471
472   gtk_container_class_install_child_property (container_class,
473                                               CHILD_PROP_HOMOGENEOUS,
474                                               g_param_spec_boolean ("homogeneous", 
475                                                                     P_("Homogeneous"), 
476                                                                     P_("Whether the item should be the same size as other homogeneous items"),
477                                                                     TRUE,
478                                                                     G_PARAM_READWRITE));
479
480   /* style properties */
481   gtk_widget_class_install_style_property (widget_class,
482                                            g_param_spec_int ("space_size",
483                                                              P_("Spacer size"),
484                                                              P_("Size of spacers"),
485                                                              0,
486                                                              G_MAXINT,
487                                                              DEFAULT_SPACE_SIZE,
488                                                              G_PARAM_READABLE));
489   
490   gtk_widget_class_install_style_property (widget_class,
491                                            g_param_spec_int ("internal_padding",
492                                                              P_("Internal padding"),
493                                                              P_("Amount of border space between the toolbar shadow and the buttons"),
494                                                              0,
495                                                              G_MAXINT,
496                                                              DEFAULT_IPADDING,
497                                                              G_PARAM_READABLE));
498
499   gtk_widget_class_install_style_property (widget_class,
500                                            g_param_spec_enum ("space_style",
501                                                              P_("Space style"),
502                                                              P_("Whether spacers are vertical lines or just blank"),
503                                                               GTK_TYPE_TOOLBAR_SPACE_STYLE,
504                                                               DEFAULT_SPACE_STYLE,
505                                                               G_PARAM_READABLE));
506   
507   gtk_widget_class_install_style_property (widget_class,
508                                            g_param_spec_enum ("button_relief",
509                                                               P_("Button relief"),
510                                                               P_("Type of bevel around toolbar buttons"),
511                                                               GTK_TYPE_RELIEF_STYLE,
512                                                               GTK_RELIEF_NONE,
513                                                               G_PARAM_READABLE));
514   gtk_widget_class_install_style_property (widget_class,
515                                            g_param_spec_enum ("shadow_type",
516                                                               P_("Shadow type"),
517                                                               P_("Style of bevel around the toolbar"),
518                                                               GTK_TYPE_SHADOW_TYPE,
519                                                               GTK_SHADOW_OUT,
520                                                               G_PARAM_READABLE));
521
522   gtk_settings_install_property (g_param_spec_enum ("gtk-toolbar-style",
523                                                     P_("Toolbar style"),
524                                                     P_("Whether default toolbars have text only, text and icons, icons only, etc."),
525                                                     GTK_TYPE_TOOLBAR_STYLE,
526                                                     DEFAULT_TOOLBAR_STYLE,
527                                                     G_PARAM_READWRITE));
528
529   gtk_settings_install_property (g_param_spec_enum ("gtk-toolbar-icon-size",
530                                                     P_("Toolbar icon size"),
531                                                     P_("Size of icons in default toolbars"),
532                                                     GTK_TYPE_ICON_SIZE,
533                                                     DEFAULT_ICON_SIZE,
534                                                     G_PARAM_READWRITE));  
535
536   binding_set = gtk_binding_set_by_class (klass);
537
538   add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
539   add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
540   add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
541   add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
542
543   gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
544                                 "focus_home_or_end", 1,
545                                 G_TYPE_BOOLEAN, TRUE);
546   gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
547                                 "focus_home_or_end", 1,
548                                 G_TYPE_BOOLEAN, TRUE);
549   gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
550                                 "focus_home_or_end", 1,
551                                 G_TYPE_BOOLEAN, FALSE);
552   gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
553                                 "focus_home_or_end", 1,
554                                 G_TYPE_BOOLEAN, FALSE);
555
556   add_ctrl_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
557   add_ctrl_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
558
559   g_type_class_add_private (gobject_class, sizeof (GtkToolbarPrivate));  
560 }
561
562 static void
563 gtk_toolbar_init (GtkToolbar *toolbar)
564 {
565   GtkToolbarPrivate *priv;
566   
567   GTK_WIDGET_UNSET_FLAGS (toolbar, GTK_CAN_FOCUS);
568   GTK_WIDGET_SET_FLAGS (toolbar, GTK_NO_WINDOW);
569
570   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
571   
572   toolbar->orientation = GTK_ORIENTATION_HORIZONTAL;
573   toolbar->style = DEFAULT_TOOLBAR_STYLE;
574   toolbar->icon_size = DEFAULT_ICON_SIZE;
575   toolbar->tooltips = gtk_tooltips_new ();
576   g_object_ref (toolbar->tooltips);
577   gtk_object_sink (GTK_OBJECT (toolbar->tooltips));
578   
579   priv->arrow_button = gtk_toggle_button_new ();
580   g_signal_connect (priv->arrow_button, "button_press_event",
581                     G_CALLBACK (gtk_toolbar_arrow_button_press), toolbar);
582   g_signal_connect (priv->arrow_button, "clicked",
583                     G_CALLBACK (gtk_toolbar_arrow_button_clicked), toolbar);
584   gtk_button_set_relief (GTK_BUTTON (priv->arrow_button),
585                          get_button_relief (toolbar));
586
587   priv->api_mode = DONT_KNOW;
588   
589   gtk_button_set_focus_on_click (GTK_BUTTON (priv->arrow_button), FALSE);
590   
591   priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
592   gtk_widget_set_name (priv->arrow, "gtk-toolbar-arrow");
593   gtk_widget_show (priv->arrow);
594   gtk_container_add (GTK_CONTAINER (priv->arrow_button), priv->arrow);
595   
596   gtk_widget_set_parent (priv->arrow_button, GTK_WIDGET (toolbar));
597
598   /* which child position a drop will occur at */
599   priv->menu = NULL;
600   priv->show_arrow = TRUE;
601   priv->settings = NULL;
602
603   priv->max_homogeneous_pixels = -1;
604   
605   priv->timer = g_timer_new ();
606 }
607
608 static gboolean
609 toolbar_item_visible (GtkToolbar  *toolbar,
610                       GtkToolItem *item)
611 {
612   if (GTK_WIDGET_VISIBLE (item) &&
613       ((toolbar->orientation == GTK_ORIENTATION_HORIZONTAL &&
614         gtk_tool_item_get_visible_horizontal (item)) ||
615        (toolbar->orientation == GTK_ORIENTATION_VERTICAL &&
616         gtk_tool_item_get_visible_vertical (item))))
617     {
618       GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
619       
620       /* With the old toolbar you could hide a button by calling gtk_widget_hide()
621        * on it. This doesn't work with the new API because the GtkToolItem will not be
622        * hidden.
623        */
624       if (priv->api_mode == OLD_API)
625         {
626           GtkWidget *bin_child = GTK_BIN (item)->child;
627           
628           if (bin_child && !GTK_WIDGET_VISIBLE (bin_child))
629             return FALSE;
630         }
631       
632       return TRUE;
633     }
634   
635   return FALSE;
636 }
637
638 static gint
639 calculate_max_homogeneous_pixels (GtkWidget *widget)
640 {
641   PangoContext *context;
642   PangoFontMetrics *metrics;
643   gint char_width;
644
645   context = gtk_widget_get_pango_context (widget);
646   metrics = pango_context_get_metrics (context,
647                                        widget->style->font_desc,
648                                        pango_context_get_language (context));
649   char_width = pango_font_metrics_get_approximate_char_width (metrics);
650   pango_font_metrics_unref (metrics);
651       
652   return PANGO_PIXELS (MAX_HOMOGENEOUS_N_CHARS * char_width);
653 }
654
655 static gboolean
656 toolbar_item_is_homogeneous (GtkToolbar  *toolbar,
657                              GtkToolItem *item)
658 {
659   gboolean result;
660   GtkRequisition requisition;
661   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
662
663   if (priv->max_homogeneous_pixels < 0)
664     {
665       priv->max_homogeneous_pixels =
666         calculate_max_homogeneous_pixels (GTK_WIDGET (toolbar));
667     }
668
669   result = gtk_tool_item_get_homogeneous (item) &&
670     !GTK_IS_SEPARATOR_TOOL_ITEM (item);
671
672   gtk_widget_size_request (GTK_WIDGET (item), &requisition);
673
674   if ((gtk_tool_item_get_is_important (item) &&
675        toolbar->style == GTK_TOOLBAR_BOTH_HORIZ &&
676        toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) ||
677       requisition.width > priv->max_homogeneous_pixels)
678     {
679       result = FALSE;
680     }
681
682   return result;
683 }
684
685 static void
686 gtk_toolbar_set_property (GObject     *object,
687                           guint        prop_id,
688                           const GValue *value,
689                           GParamSpec   *pspec)
690 {
691   GtkToolbar *toolbar = GTK_TOOLBAR (object);
692
693   switch (prop_id)
694     {
695     case PROP_ORIENTATION:
696       gtk_toolbar_set_orientation (toolbar, g_value_get_enum (value));
697       break;
698     case PROP_TOOLBAR_STYLE:
699       gtk_toolbar_set_style (toolbar, g_value_get_enum (value));
700       break;
701     case PROP_SHOW_ARROW:
702       gtk_toolbar_set_show_arrow (toolbar, g_value_get_boolean (value));
703       break;
704     default:
705       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
706       break;
707     }
708 }
709
710 static void
711 gtk_toolbar_get_property (GObject    *object,
712                           guint       prop_id,
713                           GValue     *value,
714                           GParamSpec *pspec)
715 {
716   GtkToolbar *toolbar = GTK_TOOLBAR (object);
717   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
718   
719   switch (prop_id)
720     {
721     case PROP_ORIENTATION:
722       g_value_set_enum (value, toolbar->orientation);
723       break;
724     case PROP_TOOLBAR_STYLE:
725       g_value_set_enum (value, toolbar->style);
726       break;
727     case PROP_SHOW_ARROW:
728       g_value_set_boolean (value, priv->show_arrow);
729       break;
730     default:
731       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
732       break;
733     }
734 }
735
736 static void
737 gtk_toolbar_map (GtkWidget *widget)
738 {
739   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
740
741   GTK_WIDGET_CLASS (parent_class)->map (widget);
742
743   if (priv->event_window)
744     gdk_window_show_unraised (priv->event_window);
745 }
746
747 static void
748 gtk_toolbar_unmap (GtkWidget *widget)
749 {
750   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
751
752   if (priv->event_window)
753     gdk_window_hide (priv->event_window);
754
755   GTK_WIDGET_CLASS (parent_class)->unmap (widget);
756 }
757
758 static void
759 gtk_toolbar_realize (GtkWidget *widget)
760 {
761   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
762   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
763
764   GdkWindowAttr attributes;
765   gint attributes_mask;
766   gint border_width;
767
768   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
769
770   border_width = GTK_CONTAINER (widget)->border_width;
771
772   attributes.wclass = GDK_INPUT_ONLY;
773   attributes.window_type = GDK_WINDOW_CHILD;
774   attributes.x = widget->allocation.x + border_width;
775   attributes.y = widget->allocation.y + border_width;
776   attributes.width = widget->allocation.width - border_width * 2;
777   attributes.height = widget->allocation.height - border_width * 2;
778   attributes.event_mask = gtk_widget_get_events (widget);
779   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
780                             GDK_BUTTON_RELEASE_MASK |
781                             GDK_ENTER_NOTIFY_MASK |
782                             GDK_LEAVE_NOTIFY_MASK);
783
784   attributes_mask = GDK_WA_X | GDK_WA_Y;
785
786   widget->window = gtk_widget_get_parent_window (widget);
787   g_object_ref (widget->window);
788   widget->style = gtk_style_attach (widget->style, widget->window);
789   
790   priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
791                                        &attributes, attributes_mask);
792   gdk_window_set_user_data (priv->event_window, toolbar);
793 }
794
795 static void
796 gtk_toolbar_unrealize (GtkWidget *widget)
797 {
798   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
799
800   if (priv->event_window)
801     {
802       gdk_window_set_user_data (priv->event_window, NULL);
803       gdk_window_destroy (priv->event_window);
804       priv->event_window = NULL;
805     }
806
807   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
808     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
809 }
810
811 static gint
812 gtk_toolbar_expose (GtkWidget      *widget,
813                     GdkEventExpose *event)
814 {
815   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
816   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
817   
818   GList *list;
819   gint border_width;
820   
821   border_width = GTK_CONTAINER (widget)->border_width;
822   
823   if (GTK_WIDGET_DRAWABLE (widget))
824     {
825       gtk_paint_box (widget->style,
826                      widget->window,
827                      GTK_WIDGET_STATE (widget),
828                      get_shadow_type (toolbar),
829                      &event->area, widget, "toolbar",
830                      border_width + widget->allocation.x,
831                      border_width + widget->allocation.y,
832                      widget->allocation.width - 2 * border_width,
833                      widget->allocation.height - 2 * border_width);
834     }
835
836   for (list = priv->content; list != NULL; list = list->next)
837     {
838       ToolbarContent *content = list->data;
839       GtkToolItem *item = content->item;
840
841       if (!content->is_placeholder)
842         gtk_container_propagate_expose (GTK_CONTAINER (widget),
843                                         GTK_WIDGET (item),
844                                         event);
845     }
846
847   gtk_container_propagate_expose (GTK_CONTAINER (widget),
848                                   priv->arrow_button,
849                                   event);
850
851   return FALSE;
852 }
853
854 static void
855 gtk_toolbar_size_request (GtkWidget      *widget,
856                           GtkRequisition *requisition)
857 {
858   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
859   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
860   GList *list;
861   gint max_child_height;
862   gint max_child_width;
863   gint max_homogeneous_child_width;
864   gint max_homogeneous_child_height;
865   gint homogeneous_size;
866   gint long_req;
867   gint pack_front_size;
868   gint ipadding;
869   GtkRequisition arrow_requisition;
870
871   max_homogeneous_child_width = 0;
872   max_homogeneous_child_height = 0;
873   max_child_width = 0;
874   max_child_height = 0;
875   for (list = priv->content; list != NULL; list = list->next)
876     {
877       GtkRequisition requisition;
878       ToolbarContent *content = list->data;
879       GtkToolItem *item = content->item;
880       
881       if (!toolbar_item_visible (toolbar, item))
882         continue;
883
884       gtk_widget_size_request (GTK_WIDGET (item), &requisition);
885       
886       max_child_width = MAX (max_child_width, requisition.width);
887       max_child_height = MAX (max_child_height, requisition.height);
888
889       if (toolbar_item_is_homogeneous (toolbar, item))
890         {
891           max_homogeneous_child_width = MAX (max_homogeneous_child_width, requisition.width);
892           max_homogeneous_child_height = MAX (max_homogeneous_child_height, requisition.height);
893         }
894     }
895   
896   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
897     homogeneous_size = max_homogeneous_child_width;
898   else
899     homogeneous_size = max_homogeneous_child_height;
900   
901   pack_front_size = 0;
902   for (list = priv->content; list != NULL; list = list->next)
903     {
904       ToolbarContent *content = list->data;
905       GtkToolItem *item = content->item;
906       guint size;
907       
908       if (!toolbar_item_visible (toolbar, item))
909         continue;
910       
911       if (toolbar_item_is_homogeneous (toolbar, item))
912         {
913           size = homogeneous_size;
914         }
915       else
916         {
917           GtkRequisition requisition;
918           
919           gtk_widget_size_request (GTK_WIDGET (item), &requisition);
920
921           if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
922             size = requisition.width;
923           else
924             size = requisition.height;
925         }
926       
927       pack_front_size += size;
928     }
929   
930   if (priv->show_arrow && priv->api_mode == NEW_API)
931     {
932       gtk_widget_size_request (priv->arrow_button, &arrow_requisition);
933       
934       if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
935         long_req = arrow_requisition.width;
936       else
937         long_req = arrow_requisition.height;
938
939       /* There is no point requesting space for the arrow if that would take
940        * up more space than all the items combined
941        */
942       long_req = MIN (long_req, pack_front_size);
943     }
944   else
945     {
946       arrow_requisition.height = 0;
947       arrow_requisition.width = 0;
948       
949       long_req = pack_front_size;
950     }
951   
952   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
953     {
954       requisition->width = long_req;
955       requisition->height = MAX (max_child_height, arrow_requisition.height);
956     }
957   else
958     {
959       requisition->height = long_req;
960       requisition->width = MAX (max_child_width, arrow_requisition.width);
961     }
962   
963   /* Extra spacing */
964   ipadding = get_internal_padding (toolbar);
965
966   requisition->width += 2 * (ipadding + GTK_CONTAINER (toolbar)->border_width);
967   requisition->height += 2 * (ipadding + GTK_CONTAINER (toolbar)->border_width);
968
969   if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
970     {
971       requisition->width += 2 * widget->style->xthickness;
972       requisition->height += 2 * widget->style->ythickness;
973     }
974   
975   toolbar->button_maxw = max_homogeneous_child_width;
976   toolbar->button_maxh = max_homogeneous_child_height;
977 }
978
979 #define SLIDE_SPEED 600         /* pixels per second */
980
981 static gint
982 position (gint from, gint to, gdouble elapsed)
983 {
984   if (to > from)
985     return MIN (from + SLIDE_SPEED * elapsed, to);
986   else
987     return MAX (from - SLIDE_SPEED * elapsed, to);
988 }
989
990 static void
991 compute_intermediate_allocation (GtkToolbar          *toolbar,
992                                  const GtkAllocation *start,
993                                  const GtkAllocation *goal,
994                                  GtkAllocation       *intermediate)
995 {
996   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
997   gdouble elapsed = g_timer_elapsed (priv->timer, NULL);
998
999   intermediate->x = position (start->x, goal->x, elapsed);
1000   intermediate->y = position (start->y, goal->y, elapsed);
1001   intermediate->width =
1002     position (start->x + start->width, goal->x + goal->width, elapsed) - intermediate->x;
1003   intermediate->height =
1004     position (start->y + start->height, goal->y + goal->height, elapsed) - intermediate->y;
1005 }
1006
1007 static void
1008 fixup_allocation_for_rtl (gint           total_size,
1009                           GtkAllocation *allocation)
1010 {
1011   allocation->x += (total_size - (2 * allocation->x + allocation->width));
1012 }
1013
1014 static void
1015 fixup_allocation_for_vertical (GtkAllocation *allocation)
1016 {
1017   gint tmp;
1018   
1019   tmp = allocation->x;
1020   allocation->x = allocation->y;
1021   allocation->y = tmp;
1022   
1023   tmp = allocation->width;
1024   allocation->width = allocation->height;
1025   allocation->height = tmp;
1026 }
1027
1028 static gint
1029 get_item_size (GtkToolbar     *toolbar,
1030                ToolbarContent *content)
1031 {
1032   GtkRequisition requisition;
1033   GtkToolItem *item = content->item;
1034
1035   gtk_widget_get_child_requisition (GTK_WIDGET (item), &requisition);
1036
1037   if (content->is_placeholder && content->disappearing)
1038     {
1039       return 0;
1040     }
1041   else if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
1042     {
1043       if (toolbar_item_is_homogeneous (toolbar, item))
1044         return toolbar->button_maxw;
1045       else
1046         return requisition.width;
1047     }
1048   else
1049     {
1050       if (toolbar_item_is_homogeneous (toolbar, item))
1051         return toolbar->button_maxh;
1052       else
1053         return requisition.height;
1054     }
1055 }
1056
1057 static gboolean
1058 slide_idle_handler (gpointer data)
1059 {
1060   GtkToolbar *toolbar = data;
1061   GtkToolbarPrivate *priv;
1062   GList *list;
1063
1064   GDK_THREADS_ENTER ();
1065
1066   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1067
1068   if (priv->need_sync)
1069     {
1070       gdk_flush ();
1071       priv->need_sync = FALSE;
1072     }
1073   
1074   for (list = priv->content; list != NULL; list = list->next)
1075     {
1076       ToolbarContent *content = list->data;
1077       GtkWidget *widget = GTK_WIDGET (content->item);
1078
1079       if ((content->state == NOT_ALLOCATED) ||
1080           (content->state == NORMAL &&
1081            GTK_WIDGET_CHILD_VISIBLE (content->item) &&
1082            ((content->goal_allocation.x != widget->allocation.x ||
1083              content->goal_allocation.y != widget->allocation.y ||
1084              content->goal_allocation.width != widget->allocation.width ||
1085              content->goal_allocation.height != widget->allocation.height))) ||
1086           (content->is_placeholder && content->disappearing &&
1087            GTK_WIDGET_CHILD_VISIBLE (content->item)))
1088         {
1089           gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1090
1091           GDK_THREADS_LEAVE ();
1092           return TRUE;
1093         }
1094     }
1095
1096   priv->is_sliding = FALSE;
1097   priv->idle_id = 0;
1098
1099   GDK_THREADS_LEAVE();
1100   return FALSE;
1101 }
1102
1103 static gboolean
1104 rect_within (GtkAllocation *a1, GtkAllocation *a2)
1105 {
1106   return (a1->x >= a2->x                         &&
1107           a1->x + a1->width <= a2->x + a2->width &&
1108           a1->y >= a2->y                         &&
1109           a1->y + a1->height <= a2->y + a2->height);
1110 }
1111
1112 static void
1113 gtk_toolbar_begin_sliding (GtkToolbar *toolbar)
1114 {
1115   GtkWidget *widget = GTK_WIDGET (toolbar);
1116   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1117   GList *list;
1118   gint cur_x;
1119   gint cur_y;
1120   gint border_width;
1121   gboolean rtl;
1122   gboolean vertical;
1123
1124   /* Start the sliding. This function copies the allocation of every
1125    * item into content->start_allocation. For items that haven't
1126    * been allocated yet, we calculate their position and save that
1127    * in start_allocatino along with zero width and zero height.
1128    */
1129   priv->is_sliding = TRUE;
1130   
1131   if (!priv->idle_id)
1132     priv->idle_id = g_idle_add (slide_idle_handler, toolbar);
1133
1134   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1135   vertical = (toolbar->orientation == GTK_ORIENTATION_VERTICAL);
1136   border_width = get_internal_padding (toolbar) + GTK_CONTAINER (toolbar)->border_width;
1137
1138   if (rtl)
1139     {
1140       cur_x = widget->allocation.width - border_width - widget->style->xthickness;
1141       cur_y = widget->allocation.height - border_width - widget->style->ythickness;
1142     }
1143   else
1144     {
1145       cur_x = border_width + widget->style->xthickness;
1146       cur_y = border_width + widget->style->ythickness;
1147     }
1148
1149   cur_x += widget->allocation.x;
1150   cur_y += widget->allocation.y;
1151   
1152   for (list = priv->content; list != NULL; list = list->next)
1153     {
1154       ToolbarContent *content = list->data;
1155       GtkWidget *item = GTK_WIDGET (content->item);
1156       GtkAllocation *alloc = &(content->start_allocation);
1157
1158       if (content->state == NORMAL && rect_within (&(item->allocation), &(widget->allocation)))
1159         {
1160           *alloc = item->allocation;
1161         }
1162       else
1163         {
1164           alloc->x = cur_x;
1165           alloc->y = cur_y;
1166
1167           if (vertical)
1168             {
1169               alloc->width = widget->allocation.width -
1170                 2 * border_width - 2 * widget->style->xthickness;
1171               alloc->height = 0;
1172             }
1173           else
1174             {
1175               alloc->width = 0;;
1176               alloc->height = widget->allocation.height -
1177                 2 * border_width - 2 * widget->style->ythickness;
1178             }
1179         }
1180
1181       if (vertical)
1182         cur_y = alloc->y + alloc->height;
1183       else if (rtl)
1184         cur_x = alloc->x;
1185       else
1186         cur_x = alloc->x + alloc->width;
1187     }
1188
1189   g_timer_reset (priv->timer);
1190 }
1191
1192 static void
1193 gtk_toolbar_stop_sliding (GtkToolbar *toolbar)
1194 {
1195   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1196
1197   if (priv->is_sliding)
1198     {
1199       GList *list;
1200       
1201       priv->is_sliding = FALSE;
1202       
1203       if (priv->idle_id)
1204         {
1205           g_source_remove (priv->idle_id);
1206           priv->idle_id = 0;
1207         }
1208
1209       list = priv->content;
1210       while (list)
1211         {
1212           ToolbarContent *content = list->data;
1213           list = list->next;
1214
1215           if (content->is_placeholder)
1216             gtk_toolbar_remove_tool_item (toolbar, content->item);
1217         }
1218       
1219       gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1220     }
1221 }
1222
1223 static void
1224 gtk_toolbar_size_allocate (GtkWidget     *widget,
1225                            GtkAllocation *allocation)
1226 {
1227   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1228   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1229   GtkAllocation *allocations;
1230   ItemState *new_states;
1231   GtkAllocation arrow_allocation;
1232   gint arrow_size;
1233   gint size, pos, short_size;
1234   GList *list;
1235   gint i;
1236   gboolean need_arrow;
1237   gint n_expand_items;
1238   gint border_width;
1239   gint available_size;
1240   gint n_items;
1241   gint needed_size;
1242   GtkRequisition arrow_requisition;
1243   gboolean overflowing;
1244   gboolean size_changed;
1245   gdouble elapsed;
1246
1247   size_changed = FALSE;
1248   if (widget->allocation.x != allocation->x             ||
1249       widget->allocation.y != allocation->y             ||
1250       widget->allocation.width != allocation->width     ||
1251       widget->allocation.height != allocation->height)
1252     {
1253       size_changed = TRUE;
1254     }
1255
1256   if (size_changed)
1257     gtk_toolbar_stop_sliding (toolbar);
1258   
1259   widget->allocation = *allocation;
1260
1261   border_width = GTK_CONTAINER (toolbar)->border_width;
1262
1263   if (GTK_WIDGET_REALIZED (widget))
1264     {
1265       gdk_window_move_resize (priv->event_window,
1266                               allocation->x + border_width,
1267                               allocation->y + border_width,
1268                               allocation->width - border_width * 2,
1269                               allocation->height - border_width * 2);
1270     }
1271   
1272   border_width += get_internal_padding (toolbar);
1273   
1274   gtk_widget_get_child_requisition (GTK_WIDGET (priv->arrow_button),
1275                                     &arrow_requisition);
1276   
1277   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
1278     {
1279       available_size = size = allocation->width - 2 * border_width;
1280       short_size = allocation->height - 2 * border_width;
1281       arrow_size = arrow_requisition.width;
1282
1283       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1284         {
1285           available_size -= 2 * widget->style->xthickness;
1286           short_size -= 2 * widget->style->ythickness;
1287         }
1288     }
1289   else
1290     {
1291       available_size = size = allocation->height - 2 * border_width;
1292       short_size = allocation->width - 2 * border_width;
1293       arrow_size = arrow_requisition.height;
1294
1295       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1296         {
1297           available_size -= 2 * widget->style->ythickness;
1298           short_size -= 2 * widget->style->xthickness;
1299         }
1300     }
1301
1302   n_items = g_list_length (priv->content);
1303   allocations = g_new0 (GtkAllocation, n_items);
1304   new_states = g_new0 (ItemState, n_items);
1305
1306   needed_size = 0;
1307   for (list = priv->content; list != NULL; list = list->next)
1308     {
1309       ToolbarContent *content = list->data;
1310       
1311       if (toolbar_item_visible (toolbar, content->item))
1312         needed_size += get_item_size (toolbar, content);
1313     }
1314
1315   need_arrow = (needed_size > available_size) && priv->show_arrow && priv->api_mode == NEW_API;
1316
1317   if (need_arrow)
1318     size = available_size - arrow_size;
1319   else
1320     size = available_size;
1321
1322   /* calculate widths of items */
1323   overflowing = FALSE;
1324   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1325     {
1326       ToolbarContent *content = list->data;
1327       GtkToolItem *item = content->item;
1328       gint item_size;
1329
1330       if (!toolbar_item_visible (toolbar, item))
1331         {
1332           new_states[i] = HIDDEN;
1333           continue;
1334         }
1335
1336       item_size = get_item_size (toolbar, content);
1337       if (item_size <= size && !overflowing)
1338         {
1339           size -= item_size;
1340           allocations[i].width = item_size;
1341           new_states[i] = NORMAL;
1342         }
1343       else
1344         {
1345           overflowing = TRUE;
1346           new_states[i] = OVERFLOWN;
1347         }
1348     }
1349
1350   /* calculate width of arrow */  
1351   if (need_arrow)
1352     {
1353       arrow_allocation.width = arrow_size;
1354       arrow_allocation.height = short_size;
1355     }
1356   
1357   /* expand expandable items */
1358
1359   /* We don't expand when there is an overflow menu, because that leads to
1360    * weird jumps when items get moved to the overflow menu and the expanding
1361    * items suddenly get a lot of extra space
1362    */
1363   if (!overflowing)
1364     {
1365       n_expand_items = 0;
1366       for (i = 0, list = priv->content; list != NULL; list = list->next, ++i)
1367         {
1368           ToolbarContent *content = list->data;
1369           GtkToolItem *item = content->item;
1370           
1371           if (gtk_tool_item_get_expand (item) && new_states[i] == NORMAL)
1372             n_expand_items++;
1373         }
1374       
1375       for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1376         {
1377           ToolbarContent *content = list->data;
1378           GtkToolItem *item = content->item;
1379           
1380           if (gtk_tool_item_get_expand (item) && new_states[i] == NORMAL)
1381             {
1382               gint extra = size / n_expand_items;
1383               if (size % n_expand_items != 0)
1384                 extra++;
1385               
1386               allocations[i].width += extra;
1387               size -= extra;
1388               n_expand_items--;
1389             }
1390         }
1391       
1392       g_assert (n_expand_items == 0);
1393     }
1394   
1395   /* position items */
1396   pos = border_width;
1397   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1398     {
1399       if (new_states[i] == NORMAL)
1400         {
1401           allocations[i].x = pos;
1402           allocations[i].y = border_width;
1403           allocations[i].height = short_size;
1404
1405           pos += allocations[i].width;
1406         }
1407     }
1408
1409   /* position arrow */
1410   if (need_arrow)
1411     {
1412       arrow_allocation.x = available_size - border_width - arrow_allocation.width;
1413       arrow_allocation.y = border_width;
1414     }
1415   
1416   /* fix up allocations in the vertical or RTL cases */
1417   if (toolbar->orientation == GTK_ORIENTATION_VERTICAL)
1418     {
1419       for (i = 0; i < n_items; ++i)
1420         fixup_allocation_for_vertical (&(allocations[i]));
1421       
1422       if (need_arrow)
1423         fixup_allocation_for_vertical (&arrow_allocation);
1424     }
1425   else if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1426     {
1427       for (i = 0; i < n_items; ++i)
1428         fixup_allocation_for_rtl (available_size, &(allocations[i]));
1429
1430       if (need_arrow)
1431         fixup_allocation_for_rtl (available_size, &arrow_allocation);
1432     }
1433   
1434   /* translate the items by allocation->(x,y) */
1435   for (i = 0; i < n_items; ++i)
1436     {
1437       allocations[i].x += allocation->x;
1438       allocations[i].y += allocation->y;
1439
1440       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1441         {
1442           allocations[i].x += widget->style->xthickness;
1443           allocations[i].y += widget->style->ythickness;
1444         }
1445     }
1446
1447   if (need_arrow)
1448     {
1449       arrow_allocation.x += allocation->x;
1450       arrow_allocation.y += allocation->y;
1451
1452       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1453         {
1454           arrow_allocation.x += widget->style->xthickness;
1455           arrow_allocation.y += widget->style->ythickness;
1456         }
1457     }
1458
1459   /* did anything change? */
1460   for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1461     {
1462       ToolbarContent *content = list->data;
1463
1464       if (content->state == NORMAL && new_states[i] != NORMAL)
1465         {
1466           /* an item disappeared, begin sliding */
1467           if (!size_changed)
1468             gtk_toolbar_begin_sliding (toolbar);
1469         }
1470     }
1471
1472   /* finally allocate the items */
1473   for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1474     {
1475       ToolbarContent *content = list->data;
1476
1477       content->goal_allocation = allocations[i];
1478     }
1479   
1480   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1481     {
1482       ToolbarContent *content = list->data;
1483       GtkToolItem *item = content->item;
1484       
1485       if (new_states[i] != NORMAL)
1486         {
1487           gtk_widget_set_child_visible (GTK_WIDGET (item), FALSE);
1488         }
1489       else
1490         {
1491           GtkAllocation alloc;
1492           elapsed = g_timer_elapsed (priv->timer, NULL);
1493           
1494           if (priv->is_sliding)
1495             {
1496               /* FIXME: we should use the same "elapsed" for all items */
1497               compute_intermediate_allocation (toolbar,
1498                                                &(content->start_allocation),
1499                                                &(content->goal_allocation),
1500                                                &alloc);
1501
1502               priv->need_sync = TRUE;
1503             }
1504           else
1505             {
1506               alloc = allocations[i];
1507             }
1508
1509           if (alloc.width == 0 || alloc.height == 0)
1510             {
1511               gtk_widget_set_child_visible (GTK_WIDGET (item), FALSE);
1512             }
1513           else
1514             {
1515               gtk_widget_set_child_visible (GTK_WIDGET (item), TRUE);
1516               gtk_widget_size_allocate (GTK_WIDGET (item), &alloc);
1517             }
1518         }
1519       
1520       content->state = new_states[i];
1521     }
1522
1523   if (need_arrow)
1524     {
1525       gtk_widget_size_allocate (GTK_WIDGET (priv->arrow_button),
1526                                 &arrow_allocation);
1527       gtk_widget_show (GTK_WIDGET (priv->arrow_button));
1528     }
1529   else
1530     {
1531       gtk_widget_hide (GTK_WIDGET (priv->arrow_button));
1532     }
1533   
1534   g_free (allocations);
1535   g_free (new_states);
1536 }
1537
1538 static void
1539 gtk_toolbar_style_set (GtkWidget *widget,
1540                        GtkStyle  *prev_style)
1541 {
1542   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
1543
1544   priv->max_homogeneous_pixels = -1;
1545   
1546   if (GTK_WIDGET_REALIZED (widget))
1547     gtk_style_set_background (widget->style, widget->window, widget->state);
1548
1549   if (prev_style)
1550     gtk_toolbar_update_button_relief (GTK_TOOLBAR (widget));
1551 }
1552
1553 static void 
1554 gtk_toolbar_direction_changed (GtkWidget        *widget,
1555                                GtkTextDirection  previous_dir)
1556 {
1557   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1558   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1559   
1560   if (toolbar->orientation == GTK_ORIENTATION_VERTICAL)
1561     {
1562       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1563         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
1564       else 
1565         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_LEFT, GTK_SHADOW_NONE);
1566     }
1567
1568   GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
1569 }
1570
1571 static GList *
1572 gtk_toolbar_list_children_in_focus_order (GtkToolbar       *toolbar,
1573                                           GtkDirectionType  dir)
1574 {
1575   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1576   GList *result = NULL;
1577   GList *list;
1578   gboolean rtl;
1579
1580   /* generate list of children in reverse logical order */
1581   
1582   for (list = priv->content; list != NULL; list = list->next)
1583     {
1584       ToolbarContent *content = list->data;
1585       GtkToolItem *item = content->item;
1586       
1587       result = g_list_prepend (result, item);
1588     }
1589
1590   result = g_list_prepend (result, priv->arrow_button);
1591
1592   rtl = (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL);
1593   
1594   /* move in logical order when
1595    *
1596    *    - dir is TAB_FORWARD
1597    *
1598    *    - in RTL mode and moving left or up
1599    *
1600    *    - in LTR mode and moving right or down
1601    */
1602   if (dir == GTK_DIR_TAB_FORWARD                                        ||
1603       (rtl  && (dir == GTK_DIR_UP   || dir == GTK_DIR_LEFT))            ||
1604       (!rtl && (dir == GTK_DIR_DOWN || dir == GTK_DIR_RIGHT)))
1605     {
1606       result = g_list_reverse (result);
1607     }
1608
1609   return result;
1610 }
1611
1612 static gboolean
1613 gtk_toolbar_focus_home_or_end (GtkToolbar *toolbar,
1614                                gboolean    focus_home)
1615 {
1616   GList *children, *list;
1617   GtkDirectionType dir = focus_home? GTK_DIR_RIGHT : GTK_DIR_LEFT;
1618
1619   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1620
1621   if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1622     {
1623       children = g_list_reverse (children);
1624       
1625       dir = (dir == GTK_DIR_RIGHT)? GTK_DIR_LEFT : GTK_DIR_RIGHT;
1626     }
1627
1628   for (list = children; list != NULL; list = list->next)
1629     {
1630       GtkWidget *child = list->data;
1631       
1632       if (GTK_CONTAINER (toolbar)->focus_child == child)
1633         break;
1634
1635       if (GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir))
1636         break;
1637     }
1638
1639   g_list_free (children);
1640   
1641   return TRUE;
1642 }   
1643
1644 /* Keybinding handler. This function is called when the user presses
1645  * Ctrl TAB or an arrow key.
1646  */
1647 static gboolean
1648 gtk_toolbar_move_focus (GtkToolbar       *toolbar,
1649                         GtkDirectionType  dir)
1650 {
1651   GList *list;
1652   gboolean try_focus = FALSE;
1653   GList *children;
1654   GtkContainer *container = GTK_CONTAINER (toolbar);
1655
1656   if (container->focus_child &&
1657       gtk_widget_child_focus (container->focus_child, dir))
1658     {
1659       return TRUE;
1660     }
1661   
1662   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1663
1664   for (list = children; list != NULL; list = list->next)
1665     {
1666       GtkWidget *child = list->data;
1667       
1668       if (try_focus && GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir))
1669         break;
1670
1671       if (child == GTK_CONTAINER (toolbar)->focus_child)
1672         try_focus = TRUE;
1673     }
1674
1675   g_list_free (children);
1676
1677   return FALSE;
1678 }
1679
1680 /* The focus handler for the toolbar. It called when the user presses
1681  * TAB or otherwise tries to focus the toolbar.
1682  */
1683 static gboolean
1684 gtk_toolbar_focus (GtkWidget        *widget,
1685                    GtkDirectionType  dir)
1686 {
1687   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1688   GList *children, *list;
1689  
1690   /* if focus is already somewhere inside the toolbar then return FALSE.
1691    * The only way focus can stay inside the toolbar is when the user presses
1692    * arrow keys or Ctrl TAB (both of which are handled by the
1693    * gtk_toolbar_move_focus() keybinding function.
1694    */
1695   if (GTK_CONTAINER (widget)->focus_child)
1696     return FALSE;
1697
1698   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1699
1700   for (list = children; list != NULL; list = list->next)
1701     {
1702       GtkWidget *child = list->data;
1703       
1704       if (GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir))
1705         return TRUE;
1706     }
1707
1708   g_list_free (children);
1709   
1710   return FALSE;
1711 }
1712
1713 static void
1714 style_change_notify (GtkToolbar *toolbar)
1715 {
1716   if (!toolbar->style_set)
1717     {
1718       /* pretend it was set, then unset, thus reverting to new default */
1719       toolbar->style_set = TRUE; 
1720       gtk_toolbar_unset_style (toolbar);
1721     }
1722 }
1723
1724 static void
1725 icon_size_change_notify (GtkToolbar *toolbar)
1726
1727   if (!toolbar->icon_size_set)
1728     {
1729       /* pretend it was set, then unset, thus reverting to new default */
1730       toolbar->icon_size_set = TRUE; 
1731       gtk_toolbar_unset_icon_size (toolbar);
1732     }
1733 }
1734
1735 static GtkSettings *
1736 toolbar_get_settings (GtkToolbar *toolbar)
1737 {
1738   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1739   return priv->settings;
1740 }
1741
1742 static void
1743 gtk_toolbar_screen_changed (GtkWidget *widget,
1744                             GdkScreen *previous_screen)
1745 {
1746   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
1747   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1748   GtkSettings *old_settings = toolbar_get_settings (toolbar);
1749   GtkSettings *settings;
1750
1751   if (gtk_widget_has_screen (GTK_WIDGET (toolbar)))
1752     settings = gtk_widget_get_settings (GTK_WIDGET (toolbar));
1753   else
1754     settings = NULL;
1755
1756   if (settings == old_settings)
1757     return;
1758
1759   if (old_settings)
1760     {
1761       g_signal_handler_disconnect (old_settings, toolbar->style_set_connection);
1762       g_signal_handler_disconnect (old_settings, toolbar->icon_size_connection);
1763
1764       g_object_unref (old_settings);
1765     }
1766
1767   if (settings)
1768     {
1769       toolbar->style_set_connection =
1770         g_signal_connect_swapped (settings,
1771                                   "notify::gtk-toolbar-style",
1772                                   G_CALLBACK (style_change_notify),
1773                                   toolbar);
1774       toolbar->icon_size_connection =
1775         g_signal_connect_swapped (settings,
1776                                   "notify::gtk-toolbar-icon-size",
1777                                   G_CALLBACK (icon_size_change_notify),
1778                                   toolbar);
1779
1780       g_object_ref (settings);
1781       priv->settings = settings;
1782     }
1783   else
1784     priv->settings = NULL;
1785
1786   style_change_notify (toolbar);
1787   icon_size_change_notify (toolbar);
1788 }
1789
1790 static int
1791 find_drop_index (GtkToolbar *toolbar,
1792                  gint        x,
1793                  gint        y)
1794 {
1795   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1796   GList *interesting_content;
1797   GList *list;
1798   GtkOrientation orientation;
1799   GtkTextDirection direction;
1800   gint best_distance = G_MAXINT;
1801   gint distance;
1802   gint cursor;
1803   gint pos;
1804   ToolbarContent *best_content;
1805   
1806   /* list items we care about wrt. drag and drop */
1807   interesting_content = NULL;
1808   for (list = priv->content; list != NULL; list = list->next)
1809     {
1810       ToolbarContent *content = list->data;
1811
1812       if (content->state == NORMAL)
1813         interesting_content = g_list_prepend (interesting_content, content);
1814     }
1815   interesting_content = g_list_reverse (interesting_content);
1816
1817   if (!interesting_content)
1818     return 0;
1819
1820   orientation = toolbar->orientation;
1821   direction = gtk_widget_get_direction (GTK_WIDGET (toolbar));
1822
1823   /* distance to first interesting item */
1824   best_content = interesting_content->data;
1825
1826   if (orientation == GTK_ORIENTATION_HORIZONTAL)
1827     {
1828       cursor = x;
1829       
1830       if (direction == GTK_TEXT_DIR_LTR)
1831         pos = GTK_WIDGET (best_content->item)->allocation.x;
1832       else
1833         pos = GTK_WIDGET (best_content->item)->allocation.x +
1834           GTK_WIDGET (best_content->item)->allocation.width;
1835     }
1836   else
1837     {
1838       cursor = y;
1839       pos = GTK_WIDGET (best_content->item)->allocation.y;
1840     }
1841
1842   best_content = NULL;
1843   best_distance = ABS (pos - cursor);
1844     
1845   /* distance to far end of each item */
1846   for (list = interesting_content; list != NULL; list = list->next)
1847     {
1848       ToolbarContent *content = list->data;
1849       GtkWidget *widget = GTK_WIDGET (content->item);
1850
1851       if (orientation == GTK_ORIENTATION_HORIZONTAL)
1852         {
1853           if (direction == GTK_TEXT_DIR_LTR)
1854             pos = widget->allocation.x + widget->allocation.width;
1855           else
1856             pos = widget->allocation.x;
1857         }
1858       else
1859         {
1860           pos = widget->allocation.y + widget->allocation.height;
1861         }
1862       
1863       distance = ABS (pos - cursor);
1864       
1865       if (distance < best_distance)
1866         {
1867           best_distance = distance;
1868           best_content = content;
1869         }
1870     }
1871
1872   g_list_free (interesting_content);
1873
1874   if (!best_content)
1875     return 0;
1876   else
1877     return g_list_index (priv->content, best_content) + 1;
1878 }
1879
1880 static void
1881 reset_all_placeholders (GtkToolbar *toolbar)
1882 {
1883   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1884   GList *list;
1885
1886   for (list = priv->content; list != NULL; list = list->next)
1887     {
1888       ToolbarContent *content = list->data;
1889       if (content->is_placeholder)
1890         content->disappearing = TRUE;
1891     }
1892 }
1893
1894 static gint
1895 physical_to_logical (GtkToolbar *toolbar, gint physical)
1896 {
1897   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1898   GList *list;
1899   int logical;
1900
1901   g_assert (physical >= 0);
1902   
1903   logical = 0;
1904   for (list = priv->content; list && physical > 0; list = list->next)
1905     {
1906       ToolbarContent *content = list->data;
1907       
1908       if (!content->is_placeholder)
1909         logical++;
1910       physical--;
1911     }
1912
1913   g_assert (physical == 0);
1914   
1915   return logical;
1916 }
1917
1918 static gint
1919 logical_to_physical (GtkToolbar *toolbar, gint logical)
1920 {
1921   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1922   GList *list;
1923   gint physical;
1924
1925   g_assert (logical >= 0);
1926   
1927   physical = 0;
1928   for (list = priv->content; list; list = list->next)
1929     {
1930       ToolbarContent *content = list->data;
1931
1932       if (!content->is_placeholder)
1933         {
1934           if (logical == 0)
1935             break;
1936           logical--;
1937         }
1938       
1939       physical++;
1940     }
1941
1942   g_assert (logical == 0);
1943   
1944   return physical;
1945 }
1946
1947 /**
1948  * gtk_toolbar_set_drop_highlight_item:
1949  * @toolbar: a #GtkToolbar
1950  * @item: a #GtkToolItem, or %NULL to turn of highlighting
1951  * @index: a position on @toolbar
1952  * 
1953  * Highlights @toolbar to give an idea of what it would look like
1954  * if @item was added to @toolbar at position indicated by @index. If @item
1955  * is %NULL, highlighting is turned off. In that case @index is ignored.
1956  *
1957  * The @tool_item passed to this function must not be part of any widget
1958  * hierarchy. When an item is set as drop highlight item it can not
1959  * added to any widget hierarchy or used as highlight item for another
1960  * toolbar.
1961  * 
1962  * Since: 2.4
1963  **/
1964 void
1965 gtk_toolbar_set_drop_highlight_item (GtkToolbar  *toolbar,
1966                                      GtkToolItem *tool_item,
1967                                      gint         index)
1968 {
1969   ToolbarContent *content;
1970   GtkToolbarPrivate *priv;
1971   gint n_items;
1972   GtkRequisition requisition;
1973
1974   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
1975   g_return_if_fail (tool_item == NULL || GTK_IS_TOOL_ITEM (tool_item));
1976
1977   gtk_toolbar_check_new_api (toolbar);
1978   
1979   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1980
1981   if (!tool_item)
1982     {
1983       if (priv->highlight_tool_item)
1984         {
1985           gtk_widget_unparent (GTK_WIDGET (priv->highlight_tool_item));
1986           g_object_unref (priv->highlight_tool_item);
1987           priv->highlight_tool_item = NULL;
1988         }
1989       
1990       reset_all_placeholders (toolbar);
1991       gtk_toolbar_begin_sliding (toolbar);
1992       return;
1993     }
1994
1995   if (tool_item != priv->highlight_tool_item)
1996     {
1997       if (priv->highlight_tool_item)
1998         g_object_unref (priv->highlight_tool_item);
1999
2000       g_object_ref (tool_item);
2001       gtk_object_sink (GTK_OBJECT (tool_item));
2002
2003       priv->highlight_tool_item = tool_item;
2004       
2005       gtk_widget_set_parent (GTK_WIDGET (priv->highlight_tool_item),
2006                              GTK_WIDGET (toolbar));
2007     }
2008
2009   n_items = gtk_toolbar_get_n_items (toolbar);
2010   if (index < 0 || index > n_items)
2011     index = n_items;
2012   
2013   index = logical_to_physical (toolbar, index);
2014   
2015   content = g_list_nth_data (priv->content, index);
2016
2017   if (index > 0)
2018     {
2019       ToolbarContent *prev_content;
2020
2021       prev_content = g_list_nth_data (priv->content, index - 1);
2022
2023       if (prev_content && prev_content->is_placeholder)
2024         content = prev_content;
2025     }
2026   
2027   if (!content || !content->is_placeholder)
2028     {
2029       GtkWidget *placeholder;
2030
2031       placeholder = GTK_WIDGET (gtk_separator_tool_item_new ());
2032       content = gtk_toolbar_insert_tool_item (toolbar,
2033                                               GTK_TOOL_ITEM (placeholder),
2034                                               index, TRUE);
2035       gtk_widget_show (placeholder);
2036     }
2037
2038   g_assert (content);
2039   g_assert (content->is_placeholder);
2040
2041   reset_all_placeholders (toolbar);
2042   
2043   content->disappearing = FALSE;
2044   
2045   gtk_widget_size_request (GTK_WIDGET (priv->highlight_tool_item),
2046                            &requisition);
2047
2048   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2049     requisition.height = -1;
2050   else
2051     requisition.width = -1;
2052   
2053   gtk_widget_set_size_request (GTK_WIDGET (content->item),
2054                                requisition.width,
2055                                requisition.height);
2056
2057   gtk_toolbar_begin_sliding (toolbar);
2058 }
2059
2060 static void
2061 gtk_toolbar_get_child_property (GtkContainer *container,
2062                                 GtkWidget    *child,
2063                                 guint         property_id,
2064                                 GValue       *value,
2065                                 GParamSpec   *pspec)
2066 {
2067   GtkToolItem *item = GTK_TOOL_ITEM (child);
2068   
2069   switch (property_id)
2070     {
2071     case CHILD_PROP_HOMOGENEOUS:
2072       g_value_set_boolean (value, gtk_tool_item_get_homogeneous (item));
2073       break;
2074
2075     case CHILD_PROP_EXPAND:
2076       g_value_set_boolean (value, gtk_tool_item_get_expand (item));
2077       break;
2078
2079     default:
2080       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2081       break;
2082     }
2083 }
2084
2085 static void
2086 gtk_toolbar_set_child_property (GtkContainer *container,
2087                                 GtkWidget    *child,
2088                                 guint         property_id,
2089                                 const GValue *value,
2090                                 GParamSpec   *pspec)
2091 {
2092   switch (property_id)
2093     {
2094     case CHILD_PROP_HOMOGENEOUS:
2095       gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2096       break;
2097
2098     case CHILD_PROP_EXPAND:
2099       gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2100       break;
2101
2102     default:
2103       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2104       break;
2105     }
2106 }
2107
2108 static void
2109 gtk_toolbar_add (GtkContainer *container,
2110                  GtkWidget    *widget)
2111 {
2112   GtkToolbar *toolbar;
2113   
2114   g_return_if_fail (GTK_IS_TOOLBAR (container));
2115   g_return_if_fail (widget != NULL);
2116
2117   toolbar = GTK_TOOLBAR (container);
2118   
2119   if (GTK_IS_TOOL_ITEM (widget))
2120     gtk_toolbar_insert (toolbar, GTK_TOOL_ITEM (widget), 0);
2121   else
2122     gtk_toolbar_append_widget (toolbar, widget, NULL, NULL);
2123 }
2124
2125 static void
2126 gtk_toolbar_remove (GtkContainer *container,
2127                     GtkWidget    *widget)
2128 {
2129   GtkToolbar *toolbar;
2130   GtkToolItem *item = NULL;
2131   
2132   g_return_if_fail (GTK_IS_TOOLBAR (container));
2133   g_return_if_fail (GTK_IS_WIDGET (widget));
2134
2135   toolbar = GTK_TOOLBAR (container);
2136
2137   if (GTK_IS_TOOL_ITEM (widget))
2138     {
2139       item = GTK_TOOL_ITEM (widget);
2140     }
2141   else
2142     {
2143       GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2144       GList *list;
2145       
2146       for (list = priv->content; list != NULL; list = list->next)
2147         {
2148           ToolbarContent *content = list->data;
2149           
2150           if (GTK_BIN (content->item)->child == widget)
2151             {
2152               item = content->item;
2153               break;
2154             }
2155         }
2156     }
2157
2158   g_return_if_fail (item != NULL);
2159
2160   gtk_toolbar_remove_tool_item (GTK_TOOLBAR (container), item);
2161 }
2162
2163 static void
2164 gtk_toolbar_forall (GtkContainer *container,
2165                     gboolean      include_internals,
2166                     GtkCallback   callback,
2167                     gpointer      callback_data)
2168 {
2169   GtkToolbar *toolbar = GTK_TOOLBAR (container);
2170   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2171   GList *list;
2172
2173   g_return_if_fail (callback != NULL);
2174
2175   list = priv->content;
2176   while (list)
2177     {
2178       ToolbarContent *content = list->data;
2179       GList *next = list->next;
2180
2181       if (!content->is_placeholder || include_internals)
2182         (*callback) (GTK_WIDGET (content->item), callback_data);
2183       
2184       list = next;
2185     }
2186   
2187   if (include_internals)
2188     (* callback) (priv->arrow_button, callback_data);
2189 }
2190
2191 static GType
2192 gtk_toolbar_child_type (GtkContainer *container)
2193 {
2194   return GTK_TYPE_TOOL_ITEM;
2195 }
2196
2197 static void
2198 gtk_toolbar_reconfigured (GtkToolbar *toolbar)
2199 {
2200   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2201   GList *list;
2202
2203   list = priv->content;
2204   while (list)
2205     {
2206       ToolbarContent *content = list->data;
2207       GList *next = list->next;
2208       
2209       _gtk_tool_item_toolbar_reconfigured (content->item);
2210       
2211       list = next;
2212     }
2213 }
2214
2215 static void
2216 gtk_toolbar_real_orientation_changed (GtkToolbar    *toolbar,
2217                                       GtkOrientation orientation)
2218 {
2219   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2220   if (toolbar->orientation != orientation)
2221     {
2222       toolbar->orientation = orientation;
2223
2224       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2225         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
2226       else if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR)
2227         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
2228       else 
2229         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_LEFT, GTK_SHADOW_NONE);
2230
2231       gtk_toolbar_reconfigured (toolbar);
2232
2233       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2234       g_object_notify (G_OBJECT (toolbar), "orientation");
2235     }
2236 }
2237
2238 static void
2239 gtk_toolbar_real_style_changed (GtkToolbar     *toolbar,
2240                                 GtkToolbarStyle style)
2241 {
2242   if (toolbar->style != style)
2243     {
2244       toolbar->style = style;
2245
2246       gtk_toolbar_reconfigured (toolbar);
2247
2248       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2249       g_object_notify (G_OBJECT (toolbar), "toolbar_style");
2250     }
2251 }
2252
2253 static void
2254 menu_position_func (GtkMenu  *menu,
2255                     gint     *x,
2256                     gint     *y,
2257                     gboolean *push_in,
2258                     gpointer  user_data)
2259 {
2260   GtkToolbar *toolbar = GTK_TOOLBAR (user_data);
2261   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2262   GtkRequisition req;
2263   GtkRequisition menu_req;
2264   
2265   gdk_window_get_origin (GTK_BUTTON (priv->arrow_button)->event_window, x, y);
2266   gtk_widget_size_request (priv->arrow_button, &req);
2267   gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
2268   
2269   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2270     {
2271       *y += priv->arrow_button->allocation.height;
2272       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2273         *x += priv->arrow_button->allocation.width - req.width;
2274       else 
2275         *x += req.width - menu_req.width;
2276     }
2277   else 
2278     {
2279       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2280         *x += priv->arrow_button->allocation.width;
2281       else 
2282         *x -= menu_req.width;
2283       *y += priv->arrow_button->allocation.height - req.height;      
2284     }
2285   
2286   *push_in = TRUE;
2287 }
2288
2289 static void
2290 menu_deactivated (GtkWidget  *menu,
2291                   GtkToolbar *toolbar)
2292 {
2293   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2294   
2295   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->arrow_button), FALSE);
2296 }
2297
2298 static void
2299 remove_item (GtkWidget *menu_item,
2300              gpointer   data)
2301 {
2302   gtk_container_remove (GTK_CONTAINER (menu_item->parent), menu_item);
2303 }
2304
2305 static void
2306 show_menu (GtkToolbar     *toolbar,
2307            GdkEventButton *event)
2308 {
2309   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2310   GList *list;
2311   
2312   if (priv->menu)
2313     {
2314       gtk_container_foreach (GTK_CONTAINER (priv->menu), remove_item, NULL);
2315       gtk_widget_destroy (GTK_WIDGET (priv->menu));
2316     }
2317
2318   priv->menu = GTK_MENU (gtk_menu_new ());
2319   g_signal_connect (priv->menu, "deactivate", G_CALLBACK (menu_deactivated), toolbar);
2320
2321   for (list = priv->content; list != NULL; list = list->next)
2322     {
2323       ToolbarContent *content = list->data;
2324       GtkToolItem *item = content->item;
2325
2326       if (content->state == OVERFLOWN)
2327         {
2328           GtkWidget *menu_item = gtk_tool_item_retrieve_proxy_menu_item (item);
2329
2330           if (menu_item)
2331             {
2332               g_assert (GTK_IS_MENU_ITEM (menu_item));
2333               gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menu_item);
2334             }
2335         }
2336     }
2337
2338   gtk_widget_show_all (GTK_WIDGET (priv->menu));
2339
2340   gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2341                   menu_position_func, toolbar,
2342                   event? event->button : 0, event? event->time : gtk_get_current_event_time());
2343 }
2344
2345 static void
2346 gtk_toolbar_arrow_button_clicked (GtkWidget  *button,
2347                                   GtkToolbar *toolbar)
2348 {
2349   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);  
2350
2351   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->arrow_button)) &&
2352       (!priv->menu || !GTK_WIDGET_VISIBLE (GTK_WIDGET (priv->menu))))
2353     {
2354       /* We only get here when the button is clicked with the keybaord,
2355        * because mouse button presses result in the menu being shown so
2356        * that priv->menu would be non-NULL and visible.
2357        */
2358       show_menu (toolbar, NULL);
2359       gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2360     }
2361 }
2362
2363 static gboolean
2364 gtk_toolbar_arrow_button_press (GtkWidget      *button,
2365                                 GdkEventButton *event,
2366                                 GtkToolbar     *toolbar)
2367 {
2368   show_menu (toolbar, event);
2369   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2370  
2371   return TRUE;
2372 }
2373
2374 static gboolean
2375 gtk_toolbar_button_press (GtkWidget      *toolbar,
2376                           GdkEventButton *event)
2377 {
2378   if (event->button == 3)
2379     {
2380       gboolean return_value;
2381     
2382       g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2383                      (int)event->x_root, (int)event->y_root, event->button,
2384                      &return_value);
2385
2386       return return_value;
2387     }
2388
2389   return FALSE;
2390 }
2391
2392 static gboolean
2393 gtk_toolbar_popup_menu (GtkWidget *toolbar)
2394 {
2395   gboolean return_value;
2396   /* This function is the handler for the "popup menu" keybinding,
2397    * ie., it is called when the user presses Shift F10
2398    */
2399   g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2400                  -1, -1, -1, &return_value);
2401
2402   return return_value;
2403 }
2404
2405 static void
2406 gtk_toolbar_update_button_relief (GtkToolbar *toolbar)
2407 {
2408   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2409
2410   gtk_toolbar_reconfigured (toolbar);
2411
2412   gtk_button_set_relief (GTK_BUTTON (priv->arrow_button), get_button_relief (toolbar));
2413 }
2414
2415 static GtkReliefStyle
2416 get_button_relief (GtkToolbar *toolbar)
2417 {
2418   GtkReliefStyle button_relief = GTK_RELIEF_NORMAL;
2419
2420   gtk_widget_ensure_style (GTK_WIDGET (toolbar));
2421   
2422   gtk_widget_style_get (GTK_WIDGET (toolbar),
2423                         "button_relief", &button_relief,
2424                         NULL);
2425
2426   return button_relief;
2427 }
2428
2429 static gint
2430 get_internal_padding (GtkToolbar *toolbar)
2431 {
2432   gint ipadding = 0;
2433
2434   gtk_widget_style_get (GTK_WIDGET (toolbar),
2435                         "internal_padding", &ipadding,
2436                         NULL);
2437
2438   return ipadding;
2439 }
2440
2441 static GtkShadowType
2442 get_shadow_type (GtkToolbar *toolbar)
2443 {
2444   GtkShadowType shadow_type;
2445
2446   gtk_widget_style_get (GTK_WIDGET (toolbar),
2447                         "shadow_type", &shadow_type,
2448                         NULL);
2449
2450   return shadow_type;
2451 }
2452
2453 static gboolean
2454 gtk_toolbar_check_old_api (GtkToolbar *toolbar)
2455 {
2456   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2457
2458   if (priv->api_mode == NEW_API)
2459     {
2460       g_warning ("mixing deprecated and non-deprecated GtkToolbar API is not allowed");
2461       return FALSE;
2462     }
2463
2464   priv->api_mode = OLD_API;
2465   return TRUE;
2466 }
2467
2468 static gboolean
2469 gtk_toolbar_check_new_api (GtkToolbar *toolbar)
2470 {
2471   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2472
2473   if (priv->api_mode == OLD_API)
2474     {
2475       g_warning ("mixing deprecated and non-deprecated GtkToolbar API is not allowed");
2476       return FALSE;
2477     }
2478   
2479   priv->api_mode = NEW_API;
2480   return TRUE;
2481 }
2482
2483 static ToolbarContent *
2484 gtk_toolbar_insert_tool_item (GtkToolbar  *toolbar,
2485                               GtkToolItem *item,
2486                               gint         pos,
2487                               gboolean     is_placeholder)
2488 {
2489   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2490   ToolbarContent *content = g_new0 (ToolbarContent, 1);
2491
2492   content->is_placeholder = is_placeholder;
2493   content->item = item;
2494   content->state = NOT_ALLOCATED;
2495   toolbar->num_children++;
2496
2497   priv->content = g_list_insert (priv->content, content, pos);
2498   
2499   gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar));
2500
2501   if (!content->is_placeholder)
2502     gtk_toolbar_stop_sliding (toolbar);
2503
2504   return content;
2505 }
2506
2507 static void
2508 gtk_toolbar_remove_tool_item (GtkToolbar  *toolbar,
2509                               GtkToolItem *item)
2510 {
2511   GtkToolbarPrivate *priv;
2512   GList *tmp;
2513   gint nth_child;
2514   ToolbarContent *content = NULL;
2515
2516   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2517   g_return_if_fail (GTK_IS_TOOL_ITEM (item));
2518   
2519   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2520   
2521   nth_child = 0;
2522
2523   for (tmp = priv->content; tmp != NULL; tmp = tmp->next)
2524     {
2525       content = tmp->data;
2526       if (content->item == item)
2527         break;
2528
2529       nth_child++;
2530     }
2531
2532   g_return_if_fail (content != NULL);
2533
2534   g_free (content);
2535   
2536   priv->content = g_list_remove (priv->content, content);
2537
2538   gtk_widget_unparent (GTK_WIDGET (item));
2539
2540   if (priv->api_mode == OLD_API)
2541     {
2542       GtkToolbarChild *toolbar_child;
2543
2544       toolbar_child = g_list_nth_data (toolbar->children, nth_child);
2545       toolbar->children = g_list_remove (toolbar->children, toolbar_child);
2546
2547       g_free (toolbar_child);
2548     }
2549
2550   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2551 }
2552
2553 /**
2554  * gtk_toolbar_new:
2555  * 
2556  * Creates a new toolbar. 
2557
2558  * Return Value: the newly-created toolbar.
2559  **/
2560 GtkWidget *
2561 gtk_toolbar_new (void)
2562 {
2563   GtkToolbar *toolbar;
2564
2565   toolbar = g_object_new (GTK_TYPE_TOOLBAR, NULL);
2566
2567   return GTK_WIDGET (toolbar);
2568 }
2569
2570 /**
2571  * gtk_toolbar_insert:
2572  * @toolbar: a #GtkToolbar
2573  * @item: a #GtkToolItem
2574  * @pos: the position of the new item
2575  *
2576  * Insert a #GtkToolItem into the toolbar at position @pos. If @pos is
2577  * 0 the item is prepended to the start of the toolbar. If @pos is
2578  * negative, the item is appended to the end of the toolbar.
2579  *
2580  * Since: 2.4
2581  **/
2582 void
2583 gtk_toolbar_insert (GtkToolbar  *toolbar,
2584                     GtkToolItem *item,
2585                     gint         pos)
2586 {
2587   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2588   g_return_if_fail (GTK_IS_TOOL_ITEM (item));
2589
2590   if (!gtk_toolbar_check_new_api (toolbar))
2591     return;
2592
2593   if (pos >= 0)
2594     pos = logical_to_physical (toolbar, pos);
2595   
2596   gtk_toolbar_insert_tool_item (toolbar, item, pos, FALSE);
2597 }
2598
2599 /**
2600  * gtk_toolbar_get_item_index:
2601  * @toolbar: a #GtkToolbar
2602  * @item: a #GtkToolItem that is a child of @toolbar
2603  * 
2604  * Returns the position of @item on the toolbar, starting from 0.
2605  * It is an error if @item is not a child of the toolbar.
2606  * 
2607  * Return value: the position of item on the toolbar.
2608  * 
2609  * Since: 2.4
2610  **/
2611 gint
2612 gtk_toolbar_get_item_index (GtkToolbar  *toolbar,
2613                             GtkToolItem *item)
2614 {
2615   GtkToolbarPrivate *priv;
2616   GList *list;
2617   int n;
2618
2619   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2620   g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1);
2621   g_return_val_if_fail (GTK_WIDGET (item)->parent == GTK_WIDGET (toolbar), -1);
2622
2623   if (!gtk_toolbar_check_new_api (toolbar))
2624     return -1;
2625   
2626   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2627
2628   n = 0;
2629   for (list = priv->content; list != NULL; list = list->next)
2630     {
2631       ToolbarContent *content = list->data;
2632
2633       if (content->item == item)
2634         break;
2635       
2636       ++n;
2637     }
2638
2639   return physical_to_logical (toolbar, n);
2640 }
2641
2642 /**
2643  * gtk_toolbar_set_orientation:
2644  * @toolbar: a #GtkToolbar.
2645  * @orientation: a new #GtkOrientation.
2646  * 
2647  * Sets whether a toolbar should appear horizontally or vertically.
2648  **/
2649 void
2650 gtk_toolbar_set_orientation (GtkToolbar     *toolbar,
2651                              GtkOrientation  orientation)
2652 {
2653   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2654
2655   g_signal_emit (toolbar, toolbar_signals[ORIENTATION_CHANGED], 0, orientation);
2656 }
2657
2658 /**
2659  * gtk_toolbar_get_orientation:
2660  * @toolbar: a #GtkToolbar
2661  * 
2662  * Retrieves the current orientation of the toolbar. See
2663  * gtk_toolbar_set_orientation().
2664  *
2665  * Return value: the orientation
2666  **/
2667 GtkOrientation
2668 gtk_toolbar_get_orientation (GtkToolbar *toolbar)
2669 {
2670   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL);
2671
2672   return toolbar->orientation;
2673 }
2674
2675 /**
2676  * gtk_toolbar_set_style:
2677  * @toolbar: a #GtkToolbar.
2678  * @style: the new style for @toolbar.
2679  * 
2680  * Alters the view of @toolbar to display either icons only, text only, or both.
2681  **/
2682 void
2683 gtk_toolbar_set_style (GtkToolbar      *toolbar,
2684                        GtkToolbarStyle  style)
2685 {
2686   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2687
2688   toolbar->style_set = TRUE;  
2689   g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2690 }
2691
2692 /**
2693  * gtk_toolbar_get_style:
2694  * @toolbar: a #GtkToolbar
2695  *
2696  * Retrieves whether the toolbar has text, icons, or both . See
2697  * gtk_toolbar_set_style().
2698  
2699  * Return value: the current style of @toolbar
2700  **/
2701 GtkToolbarStyle
2702 gtk_toolbar_get_style (GtkToolbar *toolbar)
2703 {
2704   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE);
2705
2706   return toolbar->style;
2707 }
2708
2709 /**
2710  * gtk_toolbar_unset_style:
2711  * @toolbar: a #GtkToolbar
2712  * 
2713  * Unsets a toolbar style set with gtk_toolbar_set_style(), so that
2714  * user preferences will be used to determine the toolbar style.
2715  **/
2716 void
2717 gtk_toolbar_unset_style (GtkToolbar *toolbar)
2718 {
2719   GtkToolbarStyle style;
2720
2721   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2722
2723   if (toolbar->style_set)
2724     {
2725       GtkSettings *settings = toolbar_get_settings (toolbar);
2726
2727       if (settings)
2728         g_object_get (settings,
2729                       "gtk-toolbar-style", &style,
2730                       NULL);
2731       else
2732         style = DEFAULT_TOOLBAR_STYLE;
2733
2734       if (style != toolbar->style)
2735         g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2736
2737       toolbar->style_set = FALSE;
2738     }
2739 }
2740
2741 /**
2742  * gtk_toolbar_set_tooltips:
2743  * @toolbar: a #GtkToolbar.
2744  * @enable: set to %FALSE to disable the tooltips, or %TRUE to enable them.
2745  * 
2746  * Sets if the tooltips of a toolbar should be active or not.
2747  **/
2748 void
2749 gtk_toolbar_set_tooltips (GtkToolbar *toolbar,
2750                           gboolean    enable)
2751 {
2752   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2753
2754   if (enable)
2755     gtk_tooltips_enable (toolbar->tooltips);
2756   else
2757     gtk_tooltips_disable (toolbar->tooltips);
2758 }
2759
2760 /**
2761  * gtk_toolbar_get_tooltips:
2762  * @toolbar: a #GtkToolbar
2763  *
2764  * Retrieves whether tooltips are enabled. See
2765  * gtk_toolbar_set_tooltips().
2766  *
2767  * Return value: %TRUE if tooltips are enabled
2768  **/
2769 gboolean
2770 gtk_toolbar_get_tooltips (GtkToolbar *toolbar)
2771 {
2772   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2773
2774   return toolbar->tooltips->enabled;
2775 }
2776
2777 /**
2778  * gtk_toolbar_get_n_items:
2779  * @toolbar: a #GtkToolbar
2780  * 
2781  * Returns the number of items on the toolbar.
2782  * 
2783  * Return value: the number of items on the toolbar
2784  * 
2785  * Since: 2.4
2786  **/
2787 gint
2788 gtk_toolbar_get_n_items (GtkToolbar *toolbar)
2789 {
2790   GtkToolbarPrivate *priv;
2791
2792   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2793
2794   if (!gtk_toolbar_check_new_api (toolbar))
2795     return -1;
2796   
2797   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2798
2799   return physical_to_logical (toolbar, g_list_length (priv->content));
2800 }
2801
2802 /**
2803  * gtk_toolbar_get_nth_item:
2804  * @toolbar: a #GtkToolbar
2805  * @n: A position on the toolbar
2806  *
2807  * Returns the @n<!-- -->'s item on @toolbar, or %NULL if the
2808  * toolbar does not contain an @n<!-- -->'th item.
2809  * 
2810  * Return value: The @n<!-- -->'th #GtkToolItem on @toolbar, or %NULL if there
2811  * isn't an @n<!-- -->th item.
2812  * 
2813  * Since: 2.4
2814  **/
2815 GtkToolItem *
2816 gtk_toolbar_get_nth_item (GtkToolbar *toolbar,
2817                           gint        n)
2818 {
2819   GtkToolbarPrivate *priv;
2820   ToolbarContent *content;
2821   gint n_items;
2822   
2823   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
2824
2825   if (!gtk_toolbar_check_new_api (toolbar))
2826     return NULL;
2827
2828   n_items = gtk_toolbar_get_n_items (toolbar);
2829
2830   if (n < 0 || n >= n_items)
2831     return NULL;
2832   
2833   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2834
2835   content = g_list_nth_data (priv->content, logical_to_physical (toolbar, n));
2836
2837   g_assert (content);
2838   g_assert (!content->is_placeholder);
2839
2840   return content->item;
2841 }
2842
2843 /**
2844  * gtk_toolbar_set_icon_size:
2845  * @toolbar: A #GtkToolbar
2846  * @icon_size: The #GtkIconSize that stock icons in the toolbar shall have.
2847  *
2848  * This function sets the size of stock icons in the toolbar. You
2849  * can call it both before you add the icons and after they've been
2850  * added. The size you set will override user preferences for the default
2851  * icon size.
2852  **/
2853 void
2854 gtk_toolbar_set_icon_size (GtkToolbar  *toolbar,
2855                            GtkIconSize  icon_size)
2856 {
2857   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2858
2859   toolbar->icon_size_set = TRUE;
2860
2861   if (toolbar->icon_size == icon_size)
2862     return;
2863
2864   toolbar->icon_size = icon_size;
2865
2866   gtk_toolbar_reconfigured (toolbar);
2867
2868   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2869 }
2870
2871 /**
2872  * gtk_toolbar_get_icon_size:
2873  * @toolbar: a #GtkToolbar
2874  *
2875  * Retrieves the icon size fo the toolbar. See gtk_toolbar_set_icon_size().
2876  *
2877  * Return value: the current icon size for the icons on the toolbar.
2878  **/
2879 GtkIconSize
2880 gtk_toolbar_get_icon_size (GtkToolbar *toolbar)
2881 {
2882   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_ICON_SIZE);
2883
2884   return toolbar->icon_size;
2885 }
2886
2887 /**
2888  * gtk_toolbar_get_relief_style:
2889  * @toolbar: a #GtkToolbar
2890  * 
2891  * Returns the relief style of buttons on @toolbar. See
2892  * gtk_button_set_relief_style().
2893  * 
2894  * Return value: The relief style of buttons on @toolbar.
2895  * 
2896  * Since: 2.4
2897  **/
2898 GtkReliefStyle
2899 gtk_toolbar_get_relief_style (GtkToolbar *toolbar)
2900 {
2901   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_RELIEF_NONE);
2902
2903   return get_button_relief (toolbar);
2904 }
2905
2906 /**
2907  * gtk_toolbar_unset_icon_size:
2908  * @toolbar: a #GtkToolbar
2909  * 
2910  * Unsets toolbar icon size set with gtk_toolbar_set_icon_size(), so that
2911  * user preferences will be used to determine the icon size.
2912  **/
2913 void
2914 gtk_toolbar_unset_icon_size (GtkToolbar *toolbar)
2915 {
2916   GtkIconSize size;
2917
2918   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2919   
2920   if (toolbar->icon_size_set)
2921     {
2922       GtkSettings *settings = toolbar_get_settings (toolbar);
2923
2924       if (settings)
2925         {
2926           g_object_get (settings,
2927                         "gtk-toolbar-icon-size", &size,
2928                         NULL);
2929         }
2930       else
2931         size = DEFAULT_ICON_SIZE;
2932
2933       if (size != toolbar->icon_size)
2934         gtk_toolbar_set_icon_size (toolbar, size);
2935
2936       toolbar->icon_size_set = FALSE;
2937     }
2938 }
2939
2940 /**
2941  * gtk_toolbar_set_show_arrow:
2942  * @toolbar: a #GtkToolbar
2943  * @show_arrow: Whether to show an overflow menu
2944  * 
2945  * Sets whether to show an overflow menu when
2946  * @toolbar doesn't have room for all items on it. If %TRUE,
2947  * items that there are not room are available through an
2948  * overflow menu.
2949  * 
2950  * Since: 2.4
2951  **/
2952 void
2953 gtk_toolbar_set_show_arrow (GtkToolbar *toolbar,
2954                             gboolean    show_arrow)
2955 {
2956   GtkToolbarPrivate *priv;
2957   
2958   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2959
2960   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2961   show_arrow = show_arrow != FALSE;
2962
2963   if (priv->show_arrow != show_arrow)
2964     {
2965       priv->show_arrow = show_arrow;
2966       
2967       if (!priv->show_arrow)
2968         gtk_widget_hide (priv->arrow_button);
2969       
2970       gtk_widget_queue_resize (GTK_WIDGET (toolbar));      
2971       g_object_notify (G_OBJECT (toolbar), "show_arrow");
2972     }
2973 }
2974
2975 /**
2976  * gtk_toolbar_get_show_arrow:
2977  * @toolbar: a #GtkToolbar
2978  * 
2979  * Returns whether the toolbar has an overflow menu.
2980  * See gtk_toolbar_set_show_arrow()
2981  * 
2982  * Return value: 
2983  * 
2984  * Since: 2.4
2985  **/
2986 gboolean
2987 gtk_toolbar_get_show_arrow (GtkToolbar *toolbar)
2988 {
2989   GtkToolbarPrivate *priv;
2990
2991   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2992
2993   if (!gtk_toolbar_check_new_api (toolbar))
2994     return FALSE;
2995   
2996   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2997   
2998   return priv->show_arrow;
2999 }
3000
3001 /**
3002  * gtk_toolbar_get_drop_index:
3003  * @toolbar: a #GtkToolbar
3004  * @x: x coordinate of a point on the toolbar
3005  * @y: y coordinate of a point on the toolbar
3006  *
3007  * Returns the position corresponding to the indicated point on
3008  * @toolbar. This is useful when dragging items to the toolbar:
3009  * this function returns the position a new item should be
3010  * inserted.
3011  *
3012  * @x and @y are in @toolbar coordinates.
3013  * 
3014  * Return value: The position corresponding to the point (@x, @y) on the toolbar.
3015  * 
3016  * Since: 2.4
3017  **/
3018 gint
3019 gtk_toolbar_get_drop_index (GtkToolbar *toolbar,
3020                             gint        x,
3021                             gint        y)
3022 {
3023   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
3024
3025   if (!gtk_toolbar_check_new_api (toolbar))
3026     return -1;
3027
3028   return physical_to_logical (toolbar, find_drop_index (toolbar, x, y));
3029 }
3030
3031 /**
3032  * gtk_toolbar_append_item:
3033  * @toolbar: a #GtkToolbar.
3034  * @text: give your toolbar button a label.
3035  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3036  * @tooltip_private_text: use with #GtkTipsQuery.
3037  * @icon: a #GtkWidget that should be used as the button's icon.
3038  * @callback: the function to be executed when the button is pressed.
3039  * @user_data: a pointer to any data you wish to be passed to the callback.
3040  * 
3041  * Inserts a new item into the toolbar. You must specify the position
3042  * in the toolbar where it will be inserted.
3043  *
3044  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3045  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3046  *
3047  * Return value: the new toolbar item as a #GtkWidget.
3048  **/
3049 GtkWidget *
3050 gtk_toolbar_append_item (GtkToolbar    *toolbar,
3051                          const char    *text,
3052                          const char    *tooltip_text,
3053                          const char    *tooltip_private_text,
3054                          GtkWidget     *icon,
3055                          GtkSignalFunc  callback,
3056                          gpointer       user_data)
3057 {
3058   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3059                                      NULL, text,
3060                                      tooltip_text, tooltip_private_text,
3061                                      icon, callback, user_data,
3062                                      toolbar->num_children);
3063 }
3064
3065 /**
3066  * gtk_toolbar_prepend_item:
3067  * @toolbar: a #GtkToolbar.
3068  * @text: give your toolbar button a label.
3069  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3070  * @tooltip_private_text: use with #GtkTipsQuery.
3071  * @icon: a #GtkWidget that should be used as the button's icon.
3072  * @callback: the function to be executed when the button is pressed.
3073  * @user_data: a pointer to any data you wish to be passed to the callback.
3074  * 
3075  * Adds a new button to the beginning (top or left edges) of the given toolbar.
3076  *
3077  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3078  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3079  *
3080  * Return value: the new toolbar item as a #GtkWidget.
3081  **/
3082 GtkWidget *
3083 gtk_toolbar_prepend_item (GtkToolbar    *toolbar,
3084                           const char    *text,
3085                           const char    *tooltip_text,
3086                           const char    *tooltip_private_text,
3087                           GtkWidget     *icon,
3088                           GtkSignalFunc  callback,
3089                           gpointer       user_data)
3090 {
3091   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3092                                      NULL, text,
3093                                      tooltip_text, tooltip_private_text,
3094                                      icon, callback, user_data,
3095                                      0);
3096 }
3097
3098 /**
3099  * gtk_toolbar_insert_item:
3100  * @toolbar: a #GtkToolbar.
3101  * @text: give your toolbar button a label.
3102  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3103  * @tooltip_private_text: use with #GtkTipsQuery.
3104  * @icon: a #GtkWidget that should be used as the button's icon.
3105  * @callback: the function to be executed when the button is pressed.
3106  * @user_data: a pointer to any data you wish to be passed to the callback.
3107  * @position: the number of widgets to insert this item after.
3108  * 
3109  * Inserts a new item into the toolbar. You must specify the position in the
3110  * toolbar where it will be inserted.
3111  *
3112  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3113  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3114  *
3115  * Return value: the new toolbar item as a #GtkWidget.
3116  **/
3117 GtkWidget *
3118 gtk_toolbar_insert_item (GtkToolbar    *toolbar,
3119                          const char    *text,
3120                          const char    *tooltip_text,
3121                          const char    *tooltip_private_text,
3122                          GtkWidget     *icon,
3123                          GtkSignalFunc  callback,
3124                          gpointer       user_data,
3125                          gint           position)
3126 {
3127   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3128                                      NULL, text,
3129                                      tooltip_text, tooltip_private_text,
3130                                      icon, callback, user_data,
3131                                      position);
3132 }
3133
3134 /**
3135  * gtk_toolbar_insert_stock:
3136  * @toolbar: A #GtkToolbar
3137  * @stock_id: The id of the stock item you want to insert
3138  * @tooltip_text: The text in the tooltip of the toolbar button
3139  * @tooltip_private_text: The private text of the tooltip
3140  * @callback: The callback called when the toolbar button is clicked.
3141  * @user_data: user data passed to callback
3142  * @position: The position the button shall be inserted at.
3143  *            -1 means at the end.
3144  *
3145  * Inserts a stock item at the specified position of the toolbar.  If
3146  * @stock_id is not a known stock item ID, it's inserted verbatim,
3147  * except that underscores used to mark mnemonics are removed.
3148  *
3149  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3150  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3151  *
3152  * Returns: the inserted widget
3153  */
3154 GtkWidget*
3155 gtk_toolbar_insert_stock (GtkToolbar      *toolbar,
3156                           const gchar     *stock_id,
3157                           const char      *tooltip_text,
3158                           const char      *tooltip_private_text,
3159                           GtkSignalFunc    callback,
3160                           gpointer         user_data,
3161                           gint             position)
3162 {
3163   return gtk_toolbar_internal_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3164                                               NULL, stock_id,
3165                                               tooltip_text, tooltip_private_text,
3166                                               NULL, callback, user_data,
3167                                               position, TRUE);
3168 }
3169
3170 /**
3171  * gtk_toolbar_append_space:
3172  * @toolbar: a #GtkToolbar.
3173  * 
3174  * Adds a new space to the end of the toolbar.
3175  **/
3176 void
3177 gtk_toolbar_append_space (GtkToolbar *toolbar)
3178 {
3179   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3180                               NULL, NULL,
3181                               NULL, NULL,
3182                               NULL, NULL, NULL,
3183                               toolbar->num_children);
3184 }
3185
3186 /**
3187  * gtk_toolbar_prepend_space:
3188  * @toolbar: a #GtkToolbar.
3189  * 
3190  * Adds a new space to the beginning of the toolbar.
3191  **/
3192 void
3193 gtk_toolbar_prepend_space (GtkToolbar *toolbar)
3194 {
3195   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3196                               NULL, NULL,
3197                               NULL, NULL,
3198                               NULL, NULL, NULL,
3199                               0);
3200 }
3201
3202 /**
3203  * gtk_toolbar_insert_space:
3204  * @toolbar: a #GtkToolbar
3205  * @position: the number of widgets after which a space should be inserted.
3206  * 
3207  * Inserts a new space in the toolbar at the specified position.
3208  **/
3209 void
3210 gtk_toolbar_insert_space (GtkToolbar *toolbar,
3211                           gint        position)
3212 {
3213   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3214                               NULL, NULL,
3215                               NULL, NULL,
3216                               NULL, NULL, NULL,
3217                               position);
3218 }
3219
3220 /**
3221  * gtk_toolbar_remove_space:
3222  * @toolbar: a #GtkToolbar.
3223  * @position: the index of the space to remove.
3224  * 
3225  * Removes a space from the specified position.
3226  **/
3227 void
3228 gtk_toolbar_remove_space (GtkToolbar *toolbar,
3229                           gint        position)
3230 {
3231   GtkToolItem *item;
3232
3233   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3234
3235   if (!gtk_toolbar_check_old_api (toolbar))
3236     return;
3237   
3238   item = g_list_nth_data (toolbar->children, position);
3239
3240   if (!item)
3241     {
3242       g_warning ("Toolbar position %d doesn't exist", position);
3243       return;
3244     }
3245
3246   if (!GTK_IS_SEPARATOR_TOOL_ITEM (item))
3247     {
3248       g_warning ("Toolbar position %d is not a space", position);
3249       return;
3250     }
3251
3252   gtk_toolbar_remove_tool_item (toolbar, item);
3253 }
3254
3255 /**
3256  * gtk_toolbar_append_widget:
3257  * @toolbar: a #GtkToolbar.
3258  * @widget: a #GtkWidget to add to the toolbar. 
3259  * @tooltip_text: the element's tooltip.
3260  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3261  * 
3262  * Adds a widget to the end of the given toolbar.
3263  **/ 
3264 void
3265 gtk_toolbar_append_widget (GtkToolbar  *toolbar,
3266                            GtkWidget   *widget,
3267                            const gchar *tooltip_text,
3268                            const gchar *tooltip_private_text)
3269 {
3270   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3271                               widget, NULL,
3272                               tooltip_text, tooltip_private_text,
3273                               NULL, NULL, NULL,
3274                               toolbar->num_children);
3275 }
3276
3277 /**
3278  * gtk_toolbar_prepend_widget:
3279  * @toolbar: a #GtkToolbar.
3280  * @widget: a #GtkWidget to add to the toolbar. 
3281  * @tooltip_text: the element's tooltip.
3282  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3283  * 
3284  * Adds a widget to the beginning of the given toolbar.
3285  **/ 
3286 void
3287 gtk_toolbar_prepend_widget (GtkToolbar  *toolbar,
3288                             GtkWidget   *widget,
3289                             const gchar *tooltip_text,
3290                             const gchar *tooltip_private_text)
3291 {
3292   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3293                               widget, NULL,
3294                               tooltip_text, tooltip_private_text,
3295                               NULL, NULL, NULL,
3296                               0);
3297 }
3298
3299 /**
3300  * gtk_toolbar_insert_widget:
3301  * @toolbar: a #GtkToolbar.
3302  * @widget: a #GtkWidget to add to the toolbar. 
3303  * @tooltip_text: the element's tooltip.
3304  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3305  * @position: the number of widgets to insert this widget after.
3306  * 
3307  * Inserts a widget in the toolbar at the given position.
3308  **/ 
3309 void
3310 gtk_toolbar_insert_widget (GtkToolbar *toolbar,
3311                            GtkWidget  *widget,
3312                            const char *tooltip_text,
3313                            const char *tooltip_private_text,
3314                            gint        position)
3315 {
3316   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3317                               widget, NULL,
3318                               tooltip_text, tooltip_private_text,
3319                               NULL, NULL, NULL,
3320                               position);
3321 }
3322
3323 /**
3324  * gtk_toolbar_append_element:
3325  * @toolbar: a #GtkToolbar.
3326  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3327  * @widget: a #GtkWidget, or %NULL.
3328  * @text: the element's label.
3329  * @tooltip_text: the element's tooltip.
3330  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3331  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3332  * @callback: the function to be executed when the button is pressed.
3333  * @user_data: any data you wish to pass to the callback.
3334  * 
3335  * Adds a new element to the end of a toolbar.
3336  * 
3337  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3338  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3339  * the radio group for the new element. In all other cases, @widget must
3340  * be %NULL.
3341  * 
3342  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3343  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3344  *
3345  * Return value: the new toolbar element as a #GtkWidget.
3346  **/
3347 GtkWidget*
3348 gtk_toolbar_append_element (GtkToolbar          *toolbar,
3349                             GtkToolbarChildType  type,
3350                             GtkWidget           *widget,
3351                             const char          *text,
3352                             const char          *tooltip_text,
3353                             const char          *tooltip_private_text,
3354                             GtkWidget           *icon,
3355                             GtkSignalFunc        callback,
3356                             gpointer             user_data)
3357 {
3358   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3359                                      tooltip_text, tooltip_private_text,
3360                                      icon, callback, user_data,
3361                                      toolbar->num_children);
3362 }
3363
3364 /**
3365  * gtk_toolbar_prepend_element:
3366  * @toolbar: a #GtkToolbar.
3367  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3368  * @widget: a #GtkWidget, or %NULL
3369  * @text: the element's label.
3370  * @tooltip_text: the element's tooltip.
3371  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3372  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3373  * @callback: the function to be executed when the button is pressed.
3374  * @user_data: any data you wish to pass to the callback.
3375  *  
3376  * Adds a new element to the beginning of a toolbar.
3377  * 
3378  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3379  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3380  * the radio group for the new element. In all other cases, @widget must
3381  * be %NULL.
3382  * 
3383  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3384  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3385  *
3386  * Return value: the new toolbar element as a #GtkWidget.
3387  **/
3388 GtkWidget *
3389 gtk_toolbar_prepend_element (GtkToolbar          *toolbar,
3390                              GtkToolbarChildType  type,
3391                              GtkWidget           *widget,
3392                              const char          *text,
3393                              const char          *tooltip_text,
3394                              const char          *tooltip_private_text,
3395                              GtkWidget           *icon,
3396                              GtkSignalFunc        callback,
3397                              gpointer             user_data)
3398 {
3399   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3400                                      tooltip_text, tooltip_private_text,
3401                                      icon, callback, user_data, 0);
3402 }
3403
3404 /**
3405  * gtk_toolbar_insert_element:
3406  * @toolbar: a #GtkToolbar.
3407  * @type: a value of type #GtkToolbarChildType that determines what @widget
3408  *   will be.
3409  * @widget: a #GtkWidget, or %NULL. 
3410  * @text: the element's label.
3411  * @tooltip_text: the element's tooltip.
3412  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3413  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3414  * @callback: the function to be executed when the button is pressed.
3415  * @user_data: any data you wish to pass to the callback.
3416  * @position: the number of widgets to insert this element after.
3417  *
3418  * Inserts a new element in the toolbar at the given position. 
3419  *
3420  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3421  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3422  * the radio group for the new element. In all other cases, @widget must
3423  * be %NULL.
3424  *
3425  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3426  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3427  *
3428  * Return value: the new toolbar element as a #GtkWidget.
3429  **/
3430 GtkWidget *
3431 gtk_toolbar_insert_element (GtkToolbar          *toolbar,
3432                             GtkToolbarChildType  type,
3433                             GtkWidget           *widget,
3434                             const char          *text,
3435                             const char          *tooltip_text,
3436                             const char          *tooltip_private_text,
3437                             GtkWidget           *icon,
3438                             GtkSignalFunc        callback,
3439                             gpointer             user_data,
3440                             gint                 position)
3441 {
3442   return gtk_toolbar_internal_insert_element (toolbar, type, widget, text,
3443                                               tooltip_text, tooltip_private_text,
3444                                               icon, callback, user_data, position, FALSE);
3445 }
3446
3447 gchar *
3448 _gtk_toolbar_elide_underscores (const gchar *original)
3449 {
3450   gchar *q, *result;
3451   const gchar *p;
3452   gboolean last_underscore;
3453
3454   q = result = g_malloc (strlen (original) + 1);
3455   last_underscore = FALSE;
3456   
3457   for (p = original; *p; p++)
3458     {
3459       if (!last_underscore && *p == '_')
3460         last_underscore = TRUE;
3461       else
3462         {
3463           last_underscore = FALSE;
3464           *q++ = *p;
3465         }
3466     }
3467   
3468   *q = '\0';
3469   
3470   return result;
3471 }
3472
3473 static GtkWidget *
3474 gtk_toolbar_internal_insert_element (GtkToolbar          *toolbar,
3475                                      GtkToolbarChildType  type,
3476                                      GtkWidget           *widget,
3477                                      const char          *text,
3478                                      const char          *tooltip_text,
3479                                      const char          *tooltip_private_text,
3480                                      GtkWidget           *icon,
3481                                      GtkSignalFunc        callback,
3482                                      gpointer             user_data,
3483                                      gint                 position,
3484                                      gboolean             use_stock)
3485 {
3486   GtkToolbarChild *child;
3487   GtkToolItem *item = NULL;
3488   
3489   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
3490   
3491   if (!gtk_toolbar_check_old_api (toolbar))
3492     return NULL;
3493   
3494   if (type == GTK_TOOLBAR_CHILD_WIDGET)
3495     g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
3496   else if (type != GTK_TOOLBAR_CHILD_RADIOBUTTON)
3497     g_return_val_if_fail (widget == NULL, NULL);
3498
3499   child = g_new (GtkToolbarChild, 1);
3500
3501   child->type = type;
3502   child->icon = NULL;
3503   child->label = NULL;
3504
3505   switch (type)
3506     {
3507     case GTK_TOOLBAR_CHILD_SPACE:
3508       item = gtk_separator_tool_item_new ();
3509       child->widget = NULL;
3510       break;
3511
3512     case GTK_TOOLBAR_CHILD_WIDGET:
3513       item = gtk_tool_item_new ();
3514       child->widget = widget;
3515       gtk_container_add (GTK_CONTAINER (item), child->widget);
3516       break;
3517
3518     case GTK_TOOLBAR_CHILD_BUTTON:
3519       item = gtk_tool_button_new (NULL, NULL);
3520       child->widget = _gtk_tool_button_get_button (GTK_TOOL_BUTTON (item));
3521       break;
3522       
3523     case GTK_TOOLBAR_CHILD_TOGGLEBUTTON:
3524       item = gtk_toggle_tool_button_new ();
3525       child->widget = _gtk_tool_button_get_button (GTK_TOOL_BUTTON (item));
3526       break;
3527
3528     case GTK_TOOLBAR_CHILD_RADIOBUTTON:
3529       item = gtk_radio_tool_button_new (widget
3530                                         ? gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget))
3531                                         : NULL);
3532       child->widget = _gtk_tool_button_get_button (GTK_TOOL_BUTTON (item));
3533       break;
3534     }
3535
3536   /*
3537    * When we are using the old API, consider all items "is_important". That
3538    * way BOTH_HORIZ will continue to show both icon and label in old API mode
3539    */
3540   gtk_tool_item_set_is_important (item, TRUE);
3541
3542   gtk_widget_show (GTK_WIDGET (item));
3543   
3544   if (type == GTK_TOOLBAR_CHILD_BUTTON ||
3545       type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
3546       type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
3547     {
3548       if (text)
3549         {
3550           if (use_stock)
3551             {
3552               GtkStockItem stock_item;
3553               gchar *label_text;
3554
3555               gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (item), text);
3556
3557               gtk_stock_lookup (text, &stock_item);
3558               label_text = _gtk_toolbar_elide_underscores (stock_item.label);
3559               child->label = GTK_WIDGET (gtk_label_new (label_text));
3560               g_free (label_text);
3561             }
3562           else
3563             {
3564               child->label = gtk_label_new (text);
3565             }
3566           gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (item), child->label);
3567           gtk_widget_show (child->label);
3568         }
3569
3570       if (icon)
3571         {
3572           child->icon = icon;
3573           gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (item), icon);
3574
3575           /* Applications depend on the toolbar showing the widget for them */
3576           gtk_widget_show (GTK_WIDGET (icon));
3577         }
3578
3579       /*
3580        * We need to connect to the button's clicked callback because some
3581        * programs may rely on that the widget in the callback is a GtkButton
3582        */
3583       if (callback)
3584         g_signal_connect (child->widget, "clicked",
3585                           callback, user_data);
3586     }
3587
3588   if ((type != GTK_TOOLBAR_CHILD_SPACE) && tooltip_text)
3589     gtk_tool_item_set_tooltip (item, toolbar->tooltips,
3590                                tooltip_text, tooltip_private_text);
3591   
3592   toolbar->children = g_list_insert (toolbar->children, child, position);
3593
3594   gtk_toolbar_insert_tool_item (toolbar, item, position, FALSE);
3595
3596   return child->widget;
3597 }
3598
3599 static void
3600 gtk_toolbar_finalize (GObject *object)
3601 {
3602   GList *list;
3603   GtkToolbar *toolbar = GTK_TOOLBAR (object);
3604   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3605   
3606   if (toolbar->tooltips)
3607     g_object_unref (toolbar->tooltips);
3608
3609   for (list = toolbar->children; list != NULL; list = list->next)
3610     g_free (list->data);
3611
3612   g_list_free (toolbar->children);
3613
3614   for (list = priv->content; list != NULL; list = list->next)
3615     g_free (list->data);
3616
3617   g_list_free (priv->content);
3618
3619   g_timer_destroy (priv->timer);
3620
3621   if (priv->idle_id)
3622     g_source_remove (priv->idle_id);
3623   
3624   G_OBJECT_CLASS (parent_class)->finalize (object);
3625 }