]> Pileus Git - ~andy/gtk/blob - gtk/gtktoolbar.c
Update my e-mail address.
[~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                                                       _("Orientation"),
442                                                       _("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                                                       _("Toolbar Style"),
451                                                       _("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                                                          _("Show Arrow"),
459                                                          _("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                                                                     _("Expand"), 
468                                                                     _("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                                                                     _("Homogeneous"), 
476                                                                     _("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                                                              _("Spacer size"),
484                                                              _("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                                                              _("Internal padding"),
493                                                              _("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                                                              _("Space style"),
502                                                              _("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                                                               _("Button relief"),
510                                                               _("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                                                               _("Shadow type"),
517                                                               _("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                                                     _("Toolbar style"),
524                                                     _("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                                                     _("Toolbar icon size"),
531                                                     _("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 = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1062   GList *list;
1063
1064   if (priv->need_sync)
1065     {
1066       gdk_flush ();
1067       priv->need_sync = FALSE;
1068     }
1069   
1070   for (list = priv->content; list != NULL; list = list->next)
1071     {
1072       ToolbarContent *content = list->data;
1073       GtkWidget *widget = GTK_WIDGET (content->item);
1074
1075       if ((content->state == NOT_ALLOCATED) ||
1076           (content->state == NORMAL &&
1077            GTK_WIDGET_CHILD_VISIBLE (content->item) &&
1078            ((content->goal_allocation.x != widget->allocation.x ||
1079              content->goal_allocation.y != widget->allocation.y ||
1080              content->goal_allocation.width != widget->allocation.width ||
1081              content->goal_allocation.height != widget->allocation.height))) ||
1082           (content->is_placeholder && content->disappearing &&
1083            GTK_WIDGET_CHILD_VISIBLE (content->item)))
1084         {
1085           gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1086           return TRUE;
1087         }
1088     }
1089
1090   priv->is_sliding = FALSE;
1091   priv->idle_id = 0;
1092   
1093   return FALSE;
1094 }
1095
1096 static gboolean
1097 rect_within (GtkAllocation *a1, GtkAllocation *a2)
1098 {
1099   return (a1->x >= a2->x                         &&
1100           a1->x + a1->width <= a2->x + a2->width &&
1101           a1->y >= a2->y                         &&
1102           a1->y + a1->height <= a2->y + a2->height);
1103 }
1104
1105 static void
1106 gtk_toolbar_begin_sliding (GtkToolbar *toolbar)
1107 {
1108   GtkWidget *widget = GTK_WIDGET (toolbar);
1109   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1110   GList *list;
1111   gint cur_x;
1112   gint cur_y;
1113   gint border_width;
1114   gboolean rtl;
1115   gboolean vertical;
1116
1117   /* Start the sliding. This function copies the allocation of every
1118    * item into content->start_allocation. For items that haven't
1119    * been allocated yet, we calculate their position and save that
1120    * in start_allocatino along with zero width and zero height.
1121    */
1122   priv->is_sliding = TRUE;
1123   
1124   if (!priv->idle_id)
1125     priv->idle_id = g_idle_add (slide_idle_handler, toolbar);
1126
1127   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1128   vertical = (toolbar->orientation == GTK_ORIENTATION_VERTICAL);
1129   border_width = get_internal_padding (toolbar) + GTK_CONTAINER (toolbar)->border_width;
1130
1131   if (rtl)
1132     {
1133       cur_x = widget->allocation.width - border_width - widget->style->xthickness;
1134       cur_y = widget->allocation.height - border_width - widget->style->ythickness;
1135     }
1136   else
1137     {
1138       cur_x = border_width + widget->style->xthickness;
1139       cur_y = border_width + widget->style->ythickness;
1140     }
1141
1142   cur_x += widget->allocation.x;
1143   cur_y += widget->allocation.y;
1144   
1145   for (list = priv->content; list != NULL; list = list->next)
1146     {
1147       ToolbarContent *content = list->data;
1148       GtkWidget *item = GTK_WIDGET (content->item);
1149       GtkAllocation *alloc = &(content->start_allocation);
1150
1151       if (content->state == NORMAL && rect_within (&(item->allocation), &(widget->allocation)))
1152         {
1153           *alloc = item->allocation;
1154         }
1155       else
1156         {
1157           alloc->x = cur_x;
1158           alloc->y = cur_y;
1159
1160           if (vertical)
1161             {
1162               alloc->width = widget->allocation.width -
1163                 2 * border_width - 2 * widget->style->xthickness;
1164               alloc->height = 0;
1165             }
1166           else
1167             {
1168               alloc->width = 0;;
1169               alloc->height = widget->allocation.height -
1170                 2 * border_width - 2 * widget->style->ythickness;
1171             }
1172         }
1173
1174       if (vertical)
1175         cur_y = alloc->y + alloc->height;
1176       else if (rtl)
1177         cur_x = alloc->x;
1178       else
1179         cur_x = alloc->x + alloc->width;
1180     }
1181
1182   g_timer_reset (priv->timer);
1183 }
1184
1185 static void
1186 gtk_toolbar_stop_sliding (GtkToolbar *toolbar)
1187 {
1188   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1189
1190   if (priv->is_sliding)
1191     {
1192       GList *list;
1193       
1194       priv->is_sliding = FALSE;
1195       
1196       if (priv->idle_id)
1197         {
1198           g_source_remove (priv->idle_id);
1199           priv->idle_id = 0;
1200         }
1201
1202       list = priv->content;
1203       while (list)
1204         {
1205           ToolbarContent *content = list->data;
1206           list = list->next;
1207
1208           if (content->is_placeholder)
1209             gtk_toolbar_remove_tool_item (toolbar, content->item);
1210         }
1211       
1212       gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1213     }
1214 }
1215
1216 static void
1217 gtk_toolbar_size_allocate (GtkWidget     *widget,
1218                            GtkAllocation *allocation)
1219 {
1220   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1221   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1222   GtkAllocation *allocations;
1223   ItemState *new_states;
1224   GtkAllocation arrow_allocation;
1225   gint arrow_size;
1226   gint size, pos, short_size;
1227   GList *list;
1228   gint i;
1229   gboolean need_arrow;
1230   gint n_expand_items;
1231   gint border_width;
1232   gint available_size;
1233   gint n_items;
1234   gint needed_size;
1235   GtkRequisition arrow_requisition;
1236   gboolean overflowing;
1237   gboolean size_changed;
1238   gdouble elapsed;
1239
1240   size_changed = FALSE;
1241   if (widget->allocation.x != allocation->x             ||
1242       widget->allocation.y != allocation->y             ||
1243       widget->allocation.width != allocation->width     ||
1244       widget->allocation.height != allocation->height)
1245     {
1246       size_changed = TRUE;
1247     }
1248
1249   if (size_changed)
1250     gtk_toolbar_stop_sliding (toolbar);
1251   
1252   widget->allocation = *allocation;
1253
1254   border_width = GTK_CONTAINER (toolbar)->border_width;
1255
1256   if (GTK_WIDGET_REALIZED (widget))
1257     {
1258       gdk_window_move_resize (priv->event_window,
1259                               allocation->x + border_width,
1260                               allocation->y + border_width,
1261                               allocation->width - border_width * 2,
1262                               allocation->height - border_width * 2);
1263     }
1264   
1265   border_width += get_internal_padding (toolbar);
1266   
1267   gtk_widget_get_child_requisition (GTK_WIDGET (priv->arrow_button),
1268                                     &arrow_requisition);
1269   
1270   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
1271     {
1272       available_size = size = allocation->width - 2 * border_width;
1273       short_size = allocation->height - 2 * border_width;
1274       arrow_size = arrow_requisition.width;
1275
1276       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1277         {
1278           available_size -= 2 * widget->style->xthickness;
1279           short_size -= 2 * widget->style->ythickness;
1280         }
1281     }
1282   else
1283     {
1284       available_size = size = allocation->height - 2 * border_width;
1285       short_size = allocation->width - 2 * border_width;
1286       arrow_size = arrow_requisition.height;
1287
1288       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1289         {
1290           available_size -= 2 * widget->style->ythickness;
1291           short_size -= 2 * widget->style->xthickness;
1292         }
1293     }
1294
1295   n_items = g_list_length (priv->content);
1296   allocations = g_new0 (GtkAllocation, n_items);
1297   new_states = g_new0 (ItemState, n_items);
1298
1299   needed_size = 0;
1300   for (list = priv->content; list != NULL; list = list->next)
1301     {
1302       ToolbarContent *content = list->data;
1303       
1304       if (toolbar_item_visible (toolbar, content->item))
1305         needed_size += get_item_size (toolbar, content);
1306     }
1307
1308   need_arrow = (needed_size > available_size) && priv->show_arrow && priv->api_mode == NEW_API;
1309
1310   if (need_arrow)
1311     size = available_size - arrow_size;
1312   else
1313     size = available_size;
1314
1315   /* calculate widths of items */
1316   overflowing = FALSE;
1317   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1318     {
1319       ToolbarContent *content = list->data;
1320       GtkToolItem *item = content->item;
1321       gint item_size;
1322
1323       if (!toolbar_item_visible (toolbar, item))
1324         {
1325           new_states[i] = HIDDEN;
1326           continue;
1327         }
1328
1329       item_size = get_item_size (toolbar, content);
1330       if (item_size <= size && !overflowing)
1331         {
1332           size -= item_size;
1333           allocations[i].width = item_size;
1334           new_states[i] = NORMAL;
1335         }
1336       else
1337         {
1338           overflowing = TRUE;
1339           new_states[i] = OVERFLOWN;
1340         }
1341     }
1342
1343   /* calculate width of arrow */  
1344   if (need_arrow)
1345     {
1346       arrow_allocation.width = arrow_size;
1347       arrow_allocation.height = short_size;
1348     }
1349   
1350   /* expand expandable items */
1351
1352   /* We don't expand when there is an overflow menu, because that leads to
1353    * weird jumps when items get moved to the overflow menu and the expanding
1354    * items suddenly get a lot of extra space
1355    */
1356   if (!overflowing)
1357     {
1358       n_expand_items = 0;
1359       for (i = 0, list = priv->content; list != NULL; list = list->next, ++i)
1360         {
1361           ToolbarContent *content = list->data;
1362           GtkToolItem *item = content->item;
1363           
1364           if (gtk_tool_item_get_expand (item) && new_states[i] == NORMAL)
1365             n_expand_items++;
1366         }
1367       
1368       for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1369         {
1370           ToolbarContent *content = list->data;
1371           GtkToolItem *item = content->item;
1372           
1373           if (gtk_tool_item_get_expand (item) && new_states[i] == NORMAL)
1374             {
1375               gint extra = size / n_expand_items;
1376               if (size % n_expand_items != 0)
1377                 extra++;
1378               
1379               allocations[i].width += extra;
1380               size -= extra;
1381               n_expand_items--;
1382             }
1383         }
1384       
1385       g_assert (n_expand_items == 0);
1386     }
1387   
1388   /* position items */
1389   pos = border_width;
1390   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1391     {
1392       if (new_states[i] == NORMAL)
1393         {
1394           allocations[i].x = pos;
1395           allocations[i].y = border_width;
1396           allocations[i].height = short_size;
1397
1398           pos += allocations[i].width;
1399         }
1400     }
1401
1402   /* position arrow */
1403   if (need_arrow)
1404     {
1405       arrow_allocation.x = available_size - border_width - arrow_allocation.width;
1406       arrow_allocation.y = border_width;
1407     }
1408   
1409   /* fix up allocations in the vertical or RTL cases */
1410   if (toolbar->orientation == GTK_ORIENTATION_VERTICAL)
1411     {
1412       for (i = 0; i < n_items; ++i)
1413         fixup_allocation_for_vertical (&(allocations[i]));
1414       
1415       if (need_arrow)
1416         fixup_allocation_for_vertical (&arrow_allocation);
1417     }
1418   else if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1419     {
1420       for (i = 0; i < n_items; ++i)
1421         fixup_allocation_for_rtl (available_size, &(allocations[i]));
1422
1423       if (need_arrow)
1424         fixup_allocation_for_rtl (available_size, &arrow_allocation);
1425     }
1426   
1427   /* translate the items by allocation->(x,y) */
1428   for (i = 0; i < n_items; ++i)
1429     {
1430       allocations[i].x += allocation->x;
1431       allocations[i].y += allocation->y;
1432
1433       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1434         {
1435           allocations[i].x += widget->style->xthickness;
1436           allocations[i].y += widget->style->ythickness;
1437         }
1438     }
1439
1440   if (need_arrow)
1441     {
1442       arrow_allocation.x += allocation->x;
1443       arrow_allocation.y += allocation->y;
1444
1445       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1446         {
1447           arrow_allocation.x += widget->style->xthickness;
1448           arrow_allocation.y += widget->style->ythickness;
1449         }
1450     }
1451
1452   /* did anything change? */
1453   for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1454     {
1455       ToolbarContent *content = list->data;
1456
1457       if (content->state == NORMAL && new_states[i] != NORMAL)
1458         {
1459           /* an item disappeared, begin sliding */
1460           if (!size_changed)
1461             gtk_toolbar_begin_sliding (toolbar);
1462         }
1463     }
1464
1465   /* finally allocate the items */
1466   for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1467     {
1468       ToolbarContent *content = list->data;
1469
1470       content->goal_allocation = allocations[i];
1471     }
1472   
1473   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1474     {
1475       ToolbarContent *content = list->data;
1476       GtkToolItem *item = content->item;
1477       
1478       if (new_states[i] != NORMAL)
1479         {
1480           gtk_widget_set_child_visible (GTK_WIDGET (item), FALSE);
1481         }
1482       else
1483         {
1484           GtkAllocation alloc;
1485           elapsed = g_timer_elapsed (priv->timer, NULL);
1486           
1487           if (priv->is_sliding)
1488             {
1489               /* FIXME: we should use the same "elapsed" for all items */
1490               compute_intermediate_allocation (toolbar,
1491                                                &(content->start_allocation),
1492                                                &(content->goal_allocation),
1493                                                &alloc);
1494
1495               priv->need_sync = TRUE;
1496             }
1497           else
1498             {
1499               alloc = allocations[i];
1500             }
1501
1502           if (alloc.width == 0 || alloc.height == 0)
1503             {
1504               gtk_widget_set_child_visible (GTK_WIDGET (item), FALSE);
1505             }
1506           else
1507             {
1508               gtk_widget_set_child_visible (GTK_WIDGET (item), TRUE);
1509               gtk_widget_size_allocate (GTK_WIDGET (item), &alloc);
1510             }
1511         }
1512       
1513       content->state = new_states[i];
1514     }
1515
1516   if (need_arrow)
1517     {
1518       gtk_widget_size_allocate (GTK_WIDGET (priv->arrow_button),
1519                                 &arrow_allocation);
1520       gtk_widget_show (GTK_WIDGET (priv->arrow_button));
1521     }
1522   else
1523     {
1524       gtk_widget_hide (GTK_WIDGET (priv->arrow_button));
1525     }
1526   
1527   g_free (allocations);
1528   g_free (new_states);
1529 }
1530
1531 static void
1532 gtk_toolbar_style_set (GtkWidget *widget,
1533                        GtkStyle  *prev_style)
1534 {
1535   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
1536
1537   priv->max_homogeneous_pixels = -1;
1538   
1539   if (GTK_WIDGET_REALIZED (widget))
1540     gtk_style_set_background (widget->style, widget->window, widget->state);
1541
1542   if (prev_style)
1543     gtk_toolbar_update_button_relief (GTK_TOOLBAR (widget));
1544 }
1545
1546 static void 
1547 gtk_toolbar_direction_changed (GtkWidget        *widget,
1548                                GtkTextDirection  previous_dir)
1549 {
1550   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1551   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1552   
1553   if (toolbar->orientation == GTK_ORIENTATION_VERTICAL)
1554     {
1555       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1556         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
1557       else 
1558         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_LEFT, GTK_SHADOW_NONE);
1559     }
1560
1561   GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
1562 }
1563
1564 static GList *
1565 gtk_toolbar_list_children_in_focus_order (GtkToolbar       *toolbar,
1566                                           GtkDirectionType  dir)
1567 {
1568   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1569   GList *result = NULL;
1570   GList *list;
1571   gboolean rtl;
1572
1573   /* generate list of children in reverse logical order */
1574   
1575   for (list = priv->content; list != NULL; list = list->next)
1576     {
1577       ToolbarContent *content = list->data;
1578       GtkToolItem *item = content->item;
1579       
1580       result = g_list_prepend (result, item);
1581     }
1582
1583   result = g_list_prepend (result, priv->arrow_button);
1584
1585   rtl = (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL);
1586   
1587   /* move in logical order when
1588    *
1589    *    - dir is TAB_FORWARD
1590    *
1591    *    - in RTL mode and moving left or up
1592    *
1593    *    - in LTR mode and moving right or down
1594    */
1595   if (dir == GTK_DIR_TAB_FORWARD                                        ||
1596       (rtl  && (dir == GTK_DIR_UP   || dir == GTK_DIR_LEFT))            ||
1597       (!rtl && (dir == GTK_DIR_DOWN || dir == GTK_DIR_RIGHT)))
1598     {
1599       result = g_list_reverse (result);
1600     }
1601
1602   return result;
1603 }
1604
1605 static gboolean
1606 gtk_toolbar_focus_home_or_end (GtkToolbar *toolbar,
1607                                gboolean    focus_home)
1608 {
1609   GList *children, *list;
1610   GtkDirectionType dir = focus_home? GTK_DIR_RIGHT : GTK_DIR_LEFT;
1611
1612   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1613
1614   if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1615     {
1616       children = g_list_reverse (children);
1617       
1618       dir = (dir == GTK_DIR_RIGHT)? GTK_DIR_LEFT : GTK_DIR_RIGHT;
1619     }
1620
1621   for (list = children; list != NULL; list = list->next)
1622     {
1623       GtkWidget *child = list->data;
1624       
1625       if (GTK_CONTAINER (toolbar)->focus_child == child)
1626         break;
1627
1628       if (GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir))
1629         break;
1630     }
1631
1632   g_list_free (children);
1633   
1634   return TRUE;
1635 }   
1636
1637 /* Keybinding handler. This function is called when the user presses
1638  * Ctrl TAB or an arrow key.
1639  */
1640 static gboolean
1641 gtk_toolbar_move_focus (GtkToolbar       *toolbar,
1642                         GtkDirectionType  dir)
1643 {
1644   GList *list;
1645   gboolean try_focus = FALSE;
1646   GList *children;
1647   GtkContainer *container = GTK_CONTAINER (toolbar);
1648
1649   if (container->focus_child &&
1650       gtk_widget_child_focus (container->focus_child, dir))
1651     {
1652       return TRUE;
1653     }
1654   
1655   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1656
1657   for (list = children; list != NULL; list = list->next)
1658     {
1659       GtkWidget *child = list->data;
1660       
1661       if (try_focus && GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir))
1662         break;
1663
1664       if (child == GTK_CONTAINER (toolbar)->focus_child)
1665         try_focus = TRUE;
1666     }
1667
1668   g_list_free (children);
1669
1670   return FALSE;
1671 }
1672
1673 /* The focus handler for the toolbar. It called when the user presses
1674  * TAB or otherwise tries to focus the toolbar.
1675  */
1676 static gboolean
1677 gtk_toolbar_focus (GtkWidget        *widget,
1678                    GtkDirectionType  dir)
1679 {
1680   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1681   GList *children, *list;
1682  
1683   /* if focus is already somewhere inside the toolbar then return FALSE.
1684    * The only way focus can stay inside the toolbar is when the user presses
1685    * arrow keys or Ctrl TAB (both of which are handled by the
1686    * gtk_toolbar_move_focus() keybinding function.
1687    */
1688   if (GTK_CONTAINER (widget)->focus_child)
1689     return FALSE;
1690
1691   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1692
1693   for (list = children; list != NULL; list = list->next)
1694     {
1695       GtkWidget *child = list->data;
1696       
1697       if (GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir))
1698         return TRUE;
1699     }
1700
1701   g_list_free (children);
1702   
1703   return FALSE;
1704 }
1705
1706 static void
1707 style_change_notify (GtkToolbar *toolbar)
1708 {
1709   if (!toolbar->style_set)
1710     {
1711       /* pretend it was set, then unset, thus reverting to new default */
1712       toolbar->style_set = TRUE; 
1713       gtk_toolbar_unset_style (toolbar);
1714     }
1715 }
1716
1717 static void
1718 icon_size_change_notify (GtkToolbar *toolbar)
1719
1720   if (!toolbar->icon_size_set)
1721     {
1722       /* pretend it was set, then unset, thus reverting to new default */
1723       toolbar->icon_size_set = TRUE; 
1724       gtk_toolbar_unset_icon_size (toolbar);
1725     }
1726 }
1727
1728 static GtkSettings *
1729 toolbar_get_settings (GtkToolbar *toolbar)
1730 {
1731   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1732   return priv->settings;
1733 }
1734
1735 static void
1736 gtk_toolbar_screen_changed (GtkWidget *widget,
1737                             GdkScreen *previous_screen)
1738 {
1739   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
1740   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1741   GtkSettings *old_settings = toolbar_get_settings (toolbar);
1742   GtkSettings *settings;
1743
1744   if (gtk_widget_has_screen (GTK_WIDGET (toolbar)))
1745     settings = gtk_widget_get_settings (GTK_WIDGET (toolbar));
1746   else
1747     settings = NULL;
1748
1749   if (settings == old_settings)
1750     return;
1751
1752   if (old_settings)
1753     {
1754       g_signal_handler_disconnect (old_settings, toolbar->style_set_connection);
1755       g_signal_handler_disconnect (old_settings, toolbar->icon_size_connection);
1756
1757       g_object_unref (old_settings);
1758     }
1759
1760   if (settings)
1761     {
1762       toolbar->style_set_connection =
1763         g_signal_connect_swapped (settings,
1764                                   "notify::gtk-toolbar-style",
1765                                   G_CALLBACK (style_change_notify),
1766                                   toolbar);
1767       toolbar->icon_size_connection =
1768         g_signal_connect_swapped (settings,
1769                                   "notify::gtk-toolbar-icon-size",
1770                                   G_CALLBACK (icon_size_change_notify),
1771                                   toolbar);
1772
1773       g_object_ref (settings);
1774       priv->settings = settings;
1775     }
1776   else
1777     priv->settings = NULL;
1778
1779   style_change_notify (toolbar);
1780   icon_size_change_notify (toolbar);
1781 }
1782
1783 static int
1784 find_drop_index (GtkToolbar *toolbar,
1785                  gint        x,
1786                  gint        y)
1787 {
1788   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1789   GList *interesting_content;
1790   GList *list;
1791   GtkOrientation orientation;
1792   GtkTextDirection direction;
1793   gint best_distance = G_MAXINT;
1794   gint distance;
1795   gint cursor;
1796   gint pos;
1797   ToolbarContent *best_content;
1798   
1799   /* list items we care about wrt. drag and drop */
1800   interesting_content = NULL;
1801   for (list = priv->content; list != NULL; list = list->next)
1802     {
1803       ToolbarContent *content = list->data;
1804
1805       if (content->state == NORMAL)
1806         interesting_content = g_list_prepend (interesting_content, content);
1807     }
1808   interesting_content = g_list_reverse (interesting_content);
1809
1810   if (!interesting_content)
1811     return 0;
1812
1813   orientation = toolbar->orientation;
1814   direction = gtk_widget_get_direction (GTK_WIDGET (toolbar));
1815
1816   /* distance to first interesting item */
1817   best_content = interesting_content->data;
1818
1819   if (orientation == GTK_ORIENTATION_HORIZONTAL)
1820     {
1821       cursor = x;
1822       
1823       if (direction == GTK_TEXT_DIR_LTR)
1824         pos = GTK_WIDGET (best_content->item)->allocation.x;
1825       else
1826         pos = GTK_WIDGET (best_content->item)->allocation.x +
1827           GTK_WIDGET (best_content->item)->allocation.width;
1828     }
1829   else
1830     {
1831       cursor = y;
1832       pos = GTK_WIDGET (best_content->item)->allocation.y;
1833     }
1834
1835   best_content = NULL;
1836   best_distance = ABS (pos - cursor);
1837     
1838   /* distance to far end of each item */
1839   for (list = interesting_content; list != NULL; list = list->next)
1840     {
1841       ToolbarContent *content = list->data;
1842       GtkWidget *widget = GTK_WIDGET (content->item);
1843
1844       if (orientation == GTK_ORIENTATION_HORIZONTAL)
1845         {
1846           if (direction == GTK_TEXT_DIR_LTR)
1847             pos = widget->allocation.x + widget->allocation.width;
1848           else
1849             pos = widget->allocation.x;
1850         }
1851       else
1852         {
1853           pos = widget->allocation.y + widget->allocation.height;
1854         }
1855       
1856       distance = ABS (pos - cursor);
1857       
1858       if (distance < best_distance)
1859         {
1860           best_distance = distance;
1861           best_content = content;
1862         }
1863     }
1864
1865   g_list_free (interesting_content);
1866
1867   if (!best_content)
1868     return 0;
1869   else
1870     return g_list_index (priv->content, best_content) + 1;
1871 }
1872
1873 static void
1874 reset_all_placeholders (GtkToolbar *toolbar)
1875 {
1876   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1877   GList *list;
1878
1879   for (list = priv->content; list != NULL; list = list->next)
1880     {
1881       ToolbarContent *content = list->data;
1882       if (content->is_placeholder)
1883         content->disappearing = TRUE;
1884     }
1885 }
1886
1887 static gint
1888 physical_to_logical (GtkToolbar *toolbar, gint physical)
1889 {
1890   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1891   GList *list;
1892   int logical;
1893
1894   g_assert (physical >= 0);
1895   
1896   logical = 0;
1897   for (list = priv->content; list && physical > 0; list = list->next)
1898     {
1899       ToolbarContent *content = list->data;
1900       
1901       if (!content->is_placeholder)
1902         logical++;
1903       physical--;
1904     }
1905
1906   g_assert (physical == 0);
1907   
1908   return logical;
1909 }
1910
1911 static gint
1912 logical_to_physical (GtkToolbar *toolbar, gint logical)
1913 {
1914   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1915   GList *list;
1916   gint physical;
1917
1918   g_assert (logical >= 0);
1919   
1920   physical = 0;
1921   for (list = priv->content; list; list = list->next)
1922     {
1923       ToolbarContent *content = list->data;
1924
1925       if (!content->is_placeholder)
1926         {
1927           if (logical == 0)
1928             break;
1929           logical--;
1930         }
1931       
1932       physical++;
1933     }
1934
1935   g_assert (logical == 0);
1936   
1937   return physical;
1938 }
1939
1940 /**
1941  * gtk_toolbar_set_drop_highlight_item:
1942  * @toolbar: a #GtkToolbar
1943  * @item: a #GtkToolItem, or %NULL to turn of highlighting
1944  * @index: a position on @toolbar
1945  * 
1946  * Highlights @toolbar to give an idea of what it would look like
1947  * if @item was added to @toolbar at position indicated by @index. If @item
1948  * is %NULL, highlighting is turned off. In that case @index is ignored.
1949  *
1950  * The @tool_item passed to this function must not be part of any widget
1951  * hierarchy. When an item is set as drop highlight item it can not
1952  * added to any widget hierarchy or used as highlight item for another
1953  * toolbar.
1954  * 
1955  * Since: 2.4
1956  **/
1957 void
1958 gtk_toolbar_set_drop_highlight_item (GtkToolbar  *toolbar,
1959                                      GtkToolItem *tool_item,
1960                                      gint         index)
1961 {
1962   ToolbarContent *content;
1963   GtkToolbarPrivate *priv;
1964   gint n_items;
1965   GtkRequisition requisition;
1966
1967   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
1968   g_return_if_fail (tool_item == NULL || GTK_IS_TOOL_ITEM (tool_item));
1969
1970   gtk_toolbar_check_new_api (toolbar);
1971   
1972   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1973
1974   if (!tool_item)
1975     {
1976       if (priv->highlight_tool_item)
1977         {
1978           gtk_widget_unparent (GTK_WIDGET (priv->highlight_tool_item));
1979           g_object_unref (priv->highlight_tool_item);
1980           priv->highlight_tool_item = NULL;
1981         }
1982       
1983       reset_all_placeholders (toolbar);
1984       gtk_toolbar_begin_sliding (toolbar);
1985       return;
1986     }
1987
1988   if (tool_item != priv->highlight_tool_item)
1989     {
1990       if (priv->highlight_tool_item)
1991         g_object_unref (priv->highlight_tool_item);
1992
1993       g_object_ref (tool_item);
1994       gtk_object_sink (GTK_OBJECT (tool_item));
1995
1996       priv->highlight_tool_item = tool_item;
1997       
1998       gtk_widget_set_parent (GTK_WIDGET (priv->highlight_tool_item),
1999                              GTK_WIDGET (toolbar));
2000     }
2001
2002   n_items = gtk_toolbar_get_n_items (toolbar);
2003   if (index < 0 || index > n_items)
2004     index = n_items;
2005   
2006   index = logical_to_physical (toolbar, index);
2007   
2008   content = g_list_nth_data (priv->content, index);
2009
2010   if (index > 0)
2011     {
2012       ToolbarContent *prev_content;
2013
2014       prev_content = g_list_nth_data (priv->content, index - 1);
2015
2016       if (prev_content && prev_content->is_placeholder)
2017         content = prev_content;
2018     }
2019   
2020   if (!content || !content->is_placeholder)
2021     {
2022       GtkWidget *placeholder;
2023
2024       placeholder = GTK_WIDGET (gtk_separator_tool_item_new ());
2025       content = gtk_toolbar_insert_tool_item (toolbar,
2026                                               GTK_TOOL_ITEM (placeholder),
2027                                               index, TRUE);
2028       gtk_widget_show (placeholder);
2029     }
2030
2031   g_assert (content);
2032   g_assert (content->is_placeholder);
2033
2034   reset_all_placeholders (toolbar);
2035   
2036   content->disappearing = FALSE;
2037   
2038   gtk_widget_size_request (GTK_WIDGET (priv->highlight_tool_item),
2039                            &requisition);
2040
2041   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2042     requisition.height = -1;
2043   else
2044     requisition.width = -1;
2045   
2046   gtk_widget_set_size_request (GTK_WIDGET (content->item),
2047                                requisition.width,
2048                                requisition.height);
2049
2050   gtk_toolbar_begin_sliding (toolbar);
2051 }
2052
2053 static void
2054 gtk_toolbar_get_child_property (GtkContainer *container,
2055                                 GtkWidget    *child,
2056                                 guint         property_id,
2057                                 GValue       *value,
2058                                 GParamSpec   *pspec)
2059 {
2060   GtkToolItem *item = GTK_TOOL_ITEM (child);
2061   
2062   switch (property_id)
2063     {
2064     case CHILD_PROP_HOMOGENEOUS:
2065       g_value_set_boolean (value, gtk_tool_item_get_homogeneous (item));
2066       break;
2067
2068     case CHILD_PROP_EXPAND:
2069       g_value_set_boolean (value, gtk_tool_item_get_expand (item));
2070       break;
2071
2072     default:
2073       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2074       break;
2075     }
2076 }
2077
2078 static void
2079 gtk_toolbar_set_child_property (GtkContainer *container,
2080                                 GtkWidget    *child,
2081                                 guint         property_id,
2082                                 const GValue *value,
2083                                 GParamSpec   *pspec)
2084 {
2085   switch (property_id)
2086     {
2087     case CHILD_PROP_HOMOGENEOUS:
2088       gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2089       break;
2090
2091     case CHILD_PROP_EXPAND:
2092       gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2093       break;
2094
2095     default:
2096       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2097       break;
2098     }
2099 }
2100
2101 static void
2102 gtk_toolbar_add (GtkContainer *container,
2103                  GtkWidget    *widget)
2104 {
2105   GtkToolbar *toolbar;
2106   
2107   g_return_if_fail (GTK_IS_TOOLBAR (container));
2108   g_return_if_fail (widget != NULL);
2109
2110   toolbar = GTK_TOOLBAR (container);
2111   
2112   if (GTK_IS_TOOL_ITEM (widget))
2113     gtk_toolbar_insert (toolbar, GTK_TOOL_ITEM (widget), 0);
2114   else
2115     gtk_toolbar_append_widget (toolbar, widget, NULL, NULL);
2116 }
2117
2118 static void
2119 gtk_toolbar_remove (GtkContainer *container,
2120                     GtkWidget    *widget)
2121 {
2122   GtkToolbar *toolbar;
2123   GtkToolItem *item = NULL;
2124   
2125   g_return_if_fail (GTK_IS_TOOLBAR (container));
2126   g_return_if_fail (GTK_IS_WIDGET (widget));
2127
2128   toolbar = GTK_TOOLBAR (container);
2129
2130   if (GTK_IS_TOOL_ITEM (widget))
2131     {
2132       item = GTK_TOOL_ITEM (widget);
2133     }
2134   else
2135     {
2136       GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2137       GList *list;
2138       
2139       for (list = priv->content; list != NULL; list = list->next)
2140         {
2141           ToolbarContent *content = list->data;
2142           
2143           if (GTK_BIN (content->item)->child == widget)
2144             {
2145               item = content->item;
2146               break;
2147             }
2148         }
2149     }
2150
2151   g_return_if_fail (item != NULL);
2152
2153   gtk_toolbar_remove_tool_item (GTK_TOOLBAR (container), item);
2154 }
2155
2156 static void
2157 gtk_toolbar_forall (GtkContainer *container,
2158                     gboolean      include_internals,
2159                     GtkCallback   callback,
2160                     gpointer      callback_data)
2161 {
2162   GtkToolbar *toolbar = GTK_TOOLBAR (container);
2163   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2164   GList *list;
2165
2166   g_return_if_fail (callback != NULL);
2167
2168   list = priv->content;
2169   while (list)
2170     {
2171       ToolbarContent *content = list->data;
2172       GList *next = list->next;
2173
2174       if (!content->is_placeholder || include_internals)
2175         (*callback) (GTK_WIDGET (content->item), callback_data);
2176       
2177       list = next;
2178     }
2179   
2180   if (include_internals)
2181     (* callback) (priv->arrow_button, callback_data);
2182 }
2183
2184 static GType
2185 gtk_toolbar_child_type (GtkContainer *container)
2186 {
2187   return GTK_TYPE_TOOL_ITEM;
2188 }
2189
2190 static void
2191 gtk_toolbar_reconfigured (GtkToolbar *toolbar)
2192 {
2193   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2194   GList *list;
2195
2196   list = priv->content;
2197   while (list)
2198     {
2199       ToolbarContent *content = list->data;
2200       GList *next = list->next;
2201       
2202       _gtk_tool_item_toolbar_reconfigured (content->item);
2203       
2204       list = next;
2205     }
2206 }
2207
2208 static void
2209 gtk_toolbar_real_orientation_changed (GtkToolbar    *toolbar,
2210                                       GtkOrientation orientation)
2211 {
2212   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2213   if (toolbar->orientation != orientation)
2214     {
2215       toolbar->orientation = orientation;
2216
2217       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2218         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
2219       else if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR)
2220         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
2221       else 
2222         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_LEFT, GTK_SHADOW_NONE);
2223
2224       gtk_toolbar_reconfigured (toolbar);
2225
2226       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2227       g_object_notify (G_OBJECT (toolbar), "orientation");
2228     }
2229 }
2230
2231 static void
2232 gtk_toolbar_real_style_changed (GtkToolbar     *toolbar,
2233                                 GtkToolbarStyle style)
2234 {
2235   if (toolbar->style != style)
2236     {
2237       toolbar->style = style;
2238
2239       gtk_toolbar_reconfigured (toolbar);
2240
2241       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2242       g_object_notify (G_OBJECT (toolbar), "toolbar_style");
2243     }
2244 }
2245
2246 static void
2247 menu_position_func (GtkMenu  *menu,
2248                     gint     *x,
2249                     gint     *y,
2250                     gboolean *push_in,
2251                     gpointer  user_data)
2252 {
2253   GtkToolbar *toolbar = GTK_TOOLBAR (user_data);
2254   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2255   GtkRequisition req;
2256   GtkRequisition menu_req;
2257   
2258   gdk_window_get_origin (GTK_BUTTON (priv->arrow_button)->event_window, x, y);
2259   gtk_widget_size_request (priv->arrow_button, &req);
2260   gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
2261   
2262   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2263     {
2264       *y += priv->arrow_button->allocation.height;
2265       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2266         *x += priv->arrow_button->allocation.width - req.width;
2267       else 
2268         *x += req.width - menu_req.width;
2269     }
2270   else 
2271     {
2272       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2273         *x += priv->arrow_button->allocation.width;
2274       else 
2275         *x -= menu_req.width;
2276       *y += priv->arrow_button->allocation.height - req.height;      
2277     }
2278   
2279   *push_in = TRUE;
2280 }
2281
2282 static void
2283 menu_deactivated (GtkWidget  *menu,
2284                   GtkToolbar *toolbar)
2285 {
2286   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2287   
2288   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->arrow_button), FALSE);
2289 }
2290
2291 static void
2292 remove_item (GtkWidget *menu_item,
2293              gpointer   data)
2294 {
2295   gtk_container_remove (GTK_CONTAINER (menu_item->parent), menu_item);
2296 }
2297
2298 static void
2299 show_menu (GtkToolbar     *toolbar,
2300            GdkEventButton *event)
2301 {
2302   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2303   GList *list;
2304   
2305   if (priv->menu)
2306     {
2307       gtk_container_foreach (GTK_CONTAINER (priv->menu), remove_item, NULL);
2308       gtk_widget_destroy (GTK_WIDGET (priv->menu));
2309     }
2310
2311   priv->menu = GTK_MENU (gtk_menu_new ());
2312   g_signal_connect (priv->menu, "deactivate", G_CALLBACK (menu_deactivated), toolbar);
2313
2314   for (list = priv->content; list != NULL; list = list->next)
2315     {
2316       ToolbarContent *content = list->data;
2317       GtkToolItem *item = content->item;
2318
2319       if (content->state == OVERFLOWN)
2320         {
2321           GtkWidget *menu_item = gtk_tool_item_retrieve_proxy_menu_item (item);
2322
2323           if (menu_item)
2324             {
2325               g_assert (GTK_IS_MENU_ITEM (menu_item));
2326               gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menu_item);
2327             }
2328         }
2329     }
2330
2331   gtk_widget_show_all (GTK_WIDGET (priv->menu));
2332
2333   gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2334                   menu_position_func, toolbar,
2335                   event? event->button : 0, event? event->time : gtk_get_current_event_time());
2336 }
2337
2338 static void
2339 gtk_toolbar_arrow_button_clicked (GtkWidget  *button,
2340                                   GtkToolbar *toolbar)
2341 {
2342   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);  
2343
2344   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->arrow_button)) &&
2345       (!priv->menu || !GTK_WIDGET_VISIBLE (GTK_WIDGET (priv->menu))))
2346     {
2347       /* We only get here when the button is clicked with the keybaord,
2348        * because mouse button presses result in the menu being shown so
2349        * that priv->menu would be non-NULL and visible.
2350        */
2351       show_menu (toolbar, NULL);
2352       gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2353     }
2354 }
2355
2356 static gboolean
2357 gtk_toolbar_arrow_button_press (GtkWidget      *button,
2358                                 GdkEventButton *event,
2359                                 GtkToolbar     *toolbar)
2360 {
2361   show_menu (toolbar, event);
2362   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2363  
2364   return TRUE;
2365 }
2366
2367 static gboolean
2368 gtk_toolbar_button_press (GtkWidget      *toolbar,
2369                           GdkEventButton *event)
2370 {
2371   if (event->button == 3)
2372     {
2373       gboolean return_value;
2374     
2375       g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2376                      (int)event->x_root, (int)event->y_root, event->button,
2377                      &return_value);
2378
2379       return return_value;
2380     }
2381
2382   return FALSE;
2383 }
2384
2385 static gboolean
2386 gtk_toolbar_popup_menu (GtkWidget *toolbar)
2387 {
2388   gboolean return_value;
2389   /* This function is the handler for the "popup menu" keybinding,
2390    * ie., it is called when the user presses Shift F10
2391    */
2392   g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2393                  -1, -1, -1, &return_value);
2394
2395   return return_value;
2396 }
2397
2398 static void
2399 gtk_toolbar_update_button_relief (GtkToolbar *toolbar)
2400 {
2401   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2402
2403   gtk_toolbar_reconfigured (toolbar);
2404
2405   gtk_button_set_relief (GTK_BUTTON (priv->arrow_button), get_button_relief (toolbar));
2406 }
2407
2408 static GtkReliefStyle
2409 get_button_relief (GtkToolbar *toolbar)
2410 {
2411   GtkReliefStyle button_relief = GTK_RELIEF_NORMAL;
2412
2413   gtk_widget_ensure_style (GTK_WIDGET (toolbar));
2414   
2415   gtk_widget_style_get (GTK_WIDGET (toolbar),
2416                         "button_relief", &button_relief,
2417                         NULL);
2418
2419   return button_relief;
2420 }
2421
2422 static gint
2423 get_internal_padding (GtkToolbar *toolbar)
2424 {
2425   gint ipadding = 0;
2426
2427   gtk_widget_style_get (GTK_WIDGET (toolbar),
2428                         "internal_padding", &ipadding,
2429                         NULL);
2430
2431   return ipadding;
2432 }
2433
2434 static GtkShadowType
2435 get_shadow_type (GtkToolbar *toolbar)
2436 {
2437   GtkShadowType shadow_type;
2438
2439   gtk_widget_style_get (GTK_WIDGET (toolbar),
2440                         "shadow_type", &shadow_type,
2441                         NULL);
2442
2443   return shadow_type;
2444 }
2445
2446 static gboolean
2447 gtk_toolbar_check_old_api (GtkToolbar *toolbar)
2448 {
2449   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2450
2451   if (priv->api_mode == NEW_API)
2452     {
2453       g_warning ("mixing deprecated and non-deprecated GtkToolbar API is not allowed");
2454       return FALSE;
2455     }
2456
2457   priv->api_mode = OLD_API;
2458   return TRUE;
2459 }
2460
2461 static gboolean
2462 gtk_toolbar_check_new_api (GtkToolbar *toolbar)
2463 {
2464   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2465
2466   if (priv->api_mode == OLD_API)
2467     {
2468       g_warning ("mixing deprecated and non-deprecated GtkToolbar API is not allowed");
2469       return FALSE;
2470     }
2471   
2472   priv->api_mode = NEW_API;
2473   return TRUE;
2474 }
2475
2476 static ToolbarContent *
2477 gtk_toolbar_insert_tool_item (GtkToolbar  *toolbar,
2478                               GtkToolItem *item,
2479                               gint         pos,
2480                               gboolean     is_placeholder)
2481 {
2482   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2483   ToolbarContent *content = g_new0 (ToolbarContent, 1);
2484
2485   content->is_placeholder = is_placeholder;
2486   content->item = item;
2487   content->state = NOT_ALLOCATED;
2488   toolbar->num_children++;
2489
2490   priv->content = g_list_insert (priv->content, content, pos);
2491   
2492   gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar));
2493
2494   if (!content->is_placeholder)
2495     gtk_toolbar_stop_sliding (toolbar);
2496
2497   return content;
2498 }
2499
2500 static void
2501 gtk_toolbar_remove_tool_item (GtkToolbar  *toolbar,
2502                               GtkToolItem *item)
2503 {
2504   GtkToolbarPrivate *priv;
2505   GList *tmp;
2506   gint nth_child;
2507   ToolbarContent *content = NULL;
2508
2509   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2510   g_return_if_fail (GTK_IS_TOOL_ITEM (item));
2511   
2512   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2513   
2514   nth_child = 0;
2515
2516   for (tmp = priv->content; tmp != NULL; tmp = tmp->next)
2517     {
2518       content = tmp->data;
2519       if (content->item == item)
2520         break;
2521
2522       nth_child++;
2523     }
2524
2525   g_return_if_fail (content != NULL);
2526
2527   g_free (content);
2528   
2529   priv->content = g_list_remove (priv->content, content);
2530
2531   gtk_widget_unparent (GTK_WIDGET (item));
2532
2533   if (priv->api_mode == OLD_API)
2534     {
2535       GtkToolbarChild *toolbar_child;
2536
2537       toolbar_child = g_list_nth_data (toolbar->children, nth_child);
2538       toolbar->children = g_list_remove (toolbar->children, toolbar_child);
2539
2540       g_free (toolbar_child);
2541     }
2542
2543   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2544 }
2545
2546 /**
2547  * gtk_toolbar_new:
2548  * 
2549  * Creates a new toolbar. 
2550
2551  * Return Value: the newly-created toolbar.
2552  **/
2553 GtkWidget *
2554 gtk_toolbar_new (void)
2555 {
2556   GtkToolbar *toolbar;
2557
2558   toolbar = g_object_new (GTK_TYPE_TOOLBAR, NULL);
2559
2560   return GTK_WIDGET (toolbar);
2561 }
2562
2563 /**
2564  * gtk_toolbar_insert:
2565  * @toolbar: a #GtkToolbar
2566  * @item: a #GtkToolItem
2567  * @pos: the position of the new item
2568  *
2569  * Insert a #GtkToolItem into the toolbar at position @pos. If @pos is
2570  * 0 the item is prepended to the start of the toolbar. If @pos is
2571  * negative, the item is appended to the end of the toolbar.
2572  *
2573  * Since: 2.4
2574  **/
2575 void
2576 gtk_toolbar_insert (GtkToolbar  *toolbar,
2577                     GtkToolItem *item,
2578                     gint         pos)
2579 {
2580   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2581   g_return_if_fail (GTK_IS_TOOL_ITEM (item));
2582
2583   if (!gtk_toolbar_check_new_api (toolbar))
2584     return;
2585
2586   if (pos >= 0)
2587     pos = logical_to_physical (toolbar, pos);
2588   
2589   gtk_toolbar_insert_tool_item (toolbar, item, pos, FALSE);
2590 }
2591
2592 /**
2593  * gtk_toolbar_get_item_index:
2594  * @toolbar: a #GtkToolbar
2595  * @item: a #GtkToolItem that is a child of @toolbar
2596  * 
2597  * Returns the position of @item on the toolbar, starting from 0.
2598  * It is an error if @item is not a child of the toolbar.
2599  * 
2600  * Return value: the position of item on the toolbar.
2601  * 
2602  * Since: 2.4
2603  **/
2604 gint
2605 gtk_toolbar_get_item_index (GtkToolbar  *toolbar,
2606                             GtkToolItem *item)
2607 {
2608   GtkToolbarPrivate *priv;
2609   GList *list;
2610   int n;
2611
2612   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2613   g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1);
2614   g_return_val_if_fail (GTK_WIDGET (item)->parent == GTK_WIDGET (toolbar), -1);
2615
2616   if (!gtk_toolbar_check_new_api (toolbar))
2617     return -1;
2618   
2619   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2620
2621   n = 0;
2622   for (list = priv->content; list != NULL; list = list->next)
2623     {
2624       ToolbarContent *content = list->data;
2625
2626       if (content->item == item)
2627         break;
2628       
2629       ++n;
2630     }
2631
2632   return physical_to_logical (toolbar, n);
2633 }
2634
2635 /**
2636  * gtk_toolbar_set_orientation:
2637  * @toolbar: a #GtkToolbar.
2638  * @orientation: a new #GtkOrientation.
2639  * 
2640  * Sets whether a toolbar should appear horizontally or vertically.
2641  **/
2642 void
2643 gtk_toolbar_set_orientation (GtkToolbar     *toolbar,
2644                              GtkOrientation  orientation)
2645 {
2646   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2647
2648   g_signal_emit (toolbar, toolbar_signals[ORIENTATION_CHANGED], 0, orientation);
2649 }
2650
2651 /**
2652  * gtk_toolbar_get_orientation:
2653  * @toolbar: a #GtkToolbar
2654  * 
2655  * Retrieves the current orientation of the toolbar. See
2656  * gtk_toolbar_set_orientation().
2657  *
2658  * Return value: the orientation
2659  **/
2660 GtkOrientation
2661 gtk_toolbar_get_orientation (GtkToolbar *toolbar)
2662 {
2663   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL);
2664
2665   return toolbar->orientation;
2666 }
2667
2668 /**
2669  * gtk_toolbar_set_style:
2670  * @toolbar: a #GtkToolbar.
2671  * @style: the new style for @toolbar.
2672  * 
2673  * Alters the view of @toolbar to display either icons only, text only, or both.
2674  **/
2675 void
2676 gtk_toolbar_set_style (GtkToolbar      *toolbar,
2677                        GtkToolbarStyle  style)
2678 {
2679   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2680
2681   toolbar->style_set = TRUE;  
2682   g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2683 }
2684
2685 /**
2686  * gtk_toolbar_get_style:
2687  * @toolbar: a #GtkToolbar
2688  *
2689  * Retrieves whether the toolbar has text, icons, or both . See
2690  * gtk_toolbar_set_style().
2691  
2692  * Return value: the current style of @toolbar
2693  **/
2694 GtkToolbarStyle
2695 gtk_toolbar_get_style (GtkToolbar *toolbar)
2696 {
2697   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE);
2698
2699   return toolbar->style;
2700 }
2701
2702 /**
2703  * gtk_toolbar_unset_style:
2704  * @toolbar: a #GtkToolbar
2705  * 
2706  * Unsets a toolbar style set with gtk_toolbar_set_style(), so that
2707  * user preferences will be used to determine the toolbar style.
2708  **/
2709 void
2710 gtk_toolbar_unset_style (GtkToolbar *toolbar)
2711 {
2712   GtkToolbarStyle style;
2713
2714   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2715
2716   if (toolbar->style_set)
2717     {
2718       GtkSettings *settings = toolbar_get_settings (toolbar);
2719
2720       if (settings)
2721         g_object_get (settings,
2722                       "gtk-toolbar-style", &style,
2723                       NULL);
2724       else
2725         style = DEFAULT_TOOLBAR_STYLE;
2726
2727       if (style != toolbar->style)
2728         g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2729
2730       toolbar->style_set = FALSE;
2731     }
2732 }
2733
2734 /**
2735  * gtk_toolbar_set_tooltips:
2736  * @toolbar: a #GtkToolbar.
2737  * @enable: set to %FALSE to disable the tooltips, or %TRUE to enable them.
2738  * 
2739  * Sets if the tooltips of a toolbar should be active or not.
2740  **/
2741 void
2742 gtk_toolbar_set_tooltips (GtkToolbar *toolbar,
2743                           gboolean    enable)
2744 {
2745   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2746
2747   if (enable)
2748     gtk_tooltips_enable (toolbar->tooltips);
2749   else
2750     gtk_tooltips_disable (toolbar->tooltips);
2751 }
2752
2753 /**
2754  * gtk_toolbar_get_tooltips:
2755  * @toolbar: a #GtkToolbar
2756  *
2757  * Retrieves whether tooltips are enabled. See
2758  * gtk_toolbar_set_tooltips().
2759  *
2760  * Return value: %TRUE if tooltips are enabled
2761  **/
2762 gboolean
2763 gtk_toolbar_get_tooltips (GtkToolbar *toolbar)
2764 {
2765   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2766
2767   return toolbar->tooltips->enabled;
2768 }
2769
2770 /**
2771  * gtk_toolbar_get_n_items:
2772  * @toolbar: a #GtkToolbar
2773  * 
2774  * Returns the number of items on the toolbar.
2775  * 
2776  * Return value: the number of items on the toolbar
2777  * 
2778  * Since: 2.4
2779  **/
2780 gint
2781 gtk_toolbar_get_n_items (GtkToolbar *toolbar)
2782 {
2783   GtkToolbarPrivate *priv;
2784
2785   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2786
2787   if (!gtk_toolbar_check_new_api (toolbar))
2788     return -1;
2789   
2790   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2791
2792   return physical_to_logical (toolbar, g_list_length (priv->content));
2793 }
2794
2795 /**
2796  * gtk_toolbar_get_nth_item:
2797  * @toolbar: a #GtkToolbar
2798  * @n: A position on the toolbar
2799  *
2800  * Returns the @n<!-- -->'s item on @toolbar, or %NULL if the
2801  * toolbar does not contain an @n<!-- -->'th item.
2802  * 
2803  * Return value: The @n<!-- -->'th #GtkToolItem on @toolbar, or %NULL if there
2804  * isn't an @n<!-- -->th item.
2805  * 
2806  * Since: 2.4
2807  **/
2808 GtkToolItem *
2809 gtk_toolbar_get_nth_item (GtkToolbar *toolbar,
2810                           gint        n)
2811 {
2812   GtkToolbarPrivate *priv;
2813   ToolbarContent *content;
2814   gint n_items;
2815   
2816   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
2817
2818   if (!gtk_toolbar_check_new_api (toolbar))
2819     return NULL;
2820
2821   n_items = gtk_toolbar_get_n_items (toolbar);
2822
2823   if (n < 0 || n >= n_items)
2824     return NULL;
2825   
2826   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2827
2828   content = g_list_nth_data (priv->content, logical_to_physical (toolbar, n));
2829
2830   g_assert (content);
2831   g_assert (!content->is_placeholder);
2832
2833   return content->item;
2834 }
2835
2836 /**
2837  * gtk_toolbar_set_icon_size:
2838  * @toolbar: A #GtkToolbar
2839  * @icon_size: The #GtkIconSize that stock icons in the toolbar shall have.
2840  *
2841  * This function sets the size of stock icons in the toolbar. You
2842  * can call it both before you add the icons and after they've been
2843  * added. The size you set will override user preferences for the default
2844  * icon size.
2845  **/
2846 void
2847 gtk_toolbar_set_icon_size (GtkToolbar  *toolbar,
2848                            GtkIconSize  icon_size)
2849 {
2850   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2851
2852   toolbar->icon_size_set = TRUE;
2853
2854   if (toolbar->icon_size == icon_size)
2855     return;
2856
2857   toolbar->icon_size = icon_size;
2858
2859   gtk_toolbar_reconfigured (toolbar);
2860
2861   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2862 }
2863
2864 /**
2865  * gtk_toolbar_get_icon_size:
2866  * @toolbar: a #GtkToolbar
2867  *
2868  * Retrieves the icon size fo the toolbar. See gtk_toolbar_set_icon_size().
2869  *
2870  * Return value: the current icon size for the icons on the toolbar.
2871  **/
2872 GtkIconSize
2873 gtk_toolbar_get_icon_size (GtkToolbar *toolbar)
2874 {
2875   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_ICON_SIZE);
2876
2877   return toolbar->icon_size;
2878 }
2879
2880 /**
2881  * gtk_toolbar_get_relief_style:
2882  * @toolbar: a #GtkToolbar
2883  * 
2884  * Returns the relief style of buttons on @toolbar. See
2885  * gtk_button_set_relief_style().
2886  * 
2887  * Return value: The relief style of buttons on @toolbar.
2888  * 
2889  * Since: 2.4
2890  **/
2891 GtkReliefStyle
2892 gtk_toolbar_get_relief_style (GtkToolbar *toolbar)
2893 {
2894   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_RELIEF_NONE);
2895
2896   return get_button_relief (toolbar);
2897 }
2898
2899 /**
2900  * gtk_toolbar_unset_icon_size:
2901  * @toolbar: a #GtkToolbar
2902  * 
2903  * Unsets toolbar icon size set with gtk_toolbar_set_icon_size(), so that
2904  * user preferences will be used to determine the icon size.
2905  **/
2906 void
2907 gtk_toolbar_unset_icon_size (GtkToolbar *toolbar)
2908 {
2909   GtkIconSize size;
2910
2911   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2912   
2913   if (toolbar->icon_size_set)
2914     {
2915       GtkSettings *settings = toolbar_get_settings (toolbar);
2916
2917       if (settings)
2918         {
2919           g_object_get (settings,
2920                         "gtk-toolbar-icon-size", &size,
2921                         NULL);
2922         }
2923       else
2924         size = DEFAULT_ICON_SIZE;
2925
2926       if (size != toolbar->icon_size)
2927         gtk_toolbar_set_icon_size (toolbar, size);
2928
2929       toolbar->icon_size_set = FALSE;
2930     }
2931 }
2932
2933 /**
2934  * gtk_toolbar_set_show_arrow:
2935  * @toolbar: a #GtkToolbar
2936  * @show_arrow: Whether to show an overflow menu
2937  * 
2938  * Sets whether to show an overflow menu when
2939  * @toolbar doesn't have room for all items on it. If %TRUE,
2940  * items that there are not room are available through an
2941  * overflow menu.
2942  * 
2943  * Since: 2.4
2944  **/
2945 void
2946 gtk_toolbar_set_show_arrow (GtkToolbar *toolbar,
2947                             gboolean    show_arrow)
2948 {
2949   GtkToolbarPrivate *priv;
2950   
2951   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2952
2953   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2954   show_arrow = show_arrow != FALSE;
2955
2956   if (priv->show_arrow != show_arrow)
2957     {
2958       priv->show_arrow = show_arrow;
2959       
2960       if (!priv->show_arrow)
2961         gtk_widget_hide (priv->arrow_button);
2962       
2963       gtk_widget_queue_resize (GTK_WIDGET (toolbar));      
2964       g_object_notify (G_OBJECT (toolbar), "show_arrow");
2965     }
2966 }
2967
2968 /**
2969  * gtk_toolbar_get_show_arrow:
2970  * @toolbar: a #GtkToolbar
2971  * 
2972  * Returns whether the toolbar has an overflow menu.
2973  * See gtk_toolbar_set_show_arrow()
2974  * 
2975  * Return value: 
2976  * 
2977  * Since: 2.4
2978  **/
2979 gboolean
2980 gtk_toolbar_get_show_arrow (GtkToolbar *toolbar)
2981 {
2982   GtkToolbarPrivate *priv;
2983
2984   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2985
2986   if (!gtk_toolbar_check_new_api (toolbar))
2987     return FALSE;
2988   
2989   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2990   
2991   return priv->show_arrow;
2992 }
2993
2994 /**
2995  * gtk_toolbar_get_drop_index:
2996  * @toolbar: a #GtkToolbar
2997  * @x: x coordinate of a point on the toolbar
2998  * @y: y coordinate of a point on the toolbar
2999  *
3000  * Returns the position corresponding to the indicated point on
3001  * @toolbar. This is useful when dragging items to the toolbar:
3002  * this function returns the position a new item should be
3003  * inserted.
3004  *
3005  * @x and @y are in @toolbar coordinates.
3006  * 
3007  * Return value: The position corresponding to the point (@x, @y) on the toolbar.
3008  * 
3009  * Since: 2.4
3010  **/
3011 gint
3012 gtk_toolbar_get_drop_index (GtkToolbar *toolbar,
3013                             gint        x,
3014                             gint        y)
3015 {
3016   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
3017
3018   if (!gtk_toolbar_check_new_api (toolbar))
3019     return -1;
3020
3021   return physical_to_logical (toolbar, find_drop_index (toolbar, x, y));
3022 }
3023
3024 /**
3025  * gtk_toolbar_append_item:
3026  * @toolbar: a #GtkToolbar.
3027  * @text: give your toolbar button a label.
3028  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3029  * @tooltip_private_text: use with #GtkTipsQuery.
3030  * @icon: a #GtkWidget that should be used as the button's icon.
3031  * @callback: the function to be executed when the button is pressed.
3032  * @user_data: a pointer to any data you wish to be passed to the callback.
3033  * 
3034  * Inserts a new item into the toolbar. You must specify the position
3035  * in the toolbar where it will be inserted.
3036  *
3037  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3038  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3039  *
3040  * Return value: the new toolbar item as a #GtkWidget.
3041  **/
3042 GtkWidget *
3043 gtk_toolbar_append_item (GtkToolbar    *toolbar,
3044                          const char    *text,
3045                          const char    *tooltip_text,
3046                          const char    *tooltip_private_text,
3047                          GtkWidget     *icon,
3048                          GtkSignalFunc  callback,
3049                          gpointer       user_data)
3050 {
3051   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3052                                      NULL, text,
3053                                      tooltip_text, tooltip_private_text,
3054                                      icon, callback, user_data,
3055                                      toolbar->num_children);
3056 }
3057
3058 /**
3059  * gtk_toolbar_prepend_item:
3060  * @toolbar: a #GtkToolbar.
3061  * @text: give your toolbar button a label.
3062  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3063  * @tooltip_private_text: use with #GtkTipsQuery.
3064  * @icon: a #GtkWidget that should be used as the button's icon.
3065  * @callback: the function to be executed when the button is pressed.
3066  * @user_data: a pointer to any data you wish to be passed to the callback.
3067  * 
3068  * Adds a new button to the beginning (top or left edges) of the given toolbar.
3069  *
3070  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3071  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3072  *
3073  * Return value: the new toolbar item as a #GtkWidget.
3074  **/
3075 GtkWidget *
3076 gtk_toolbar_prepend_item (GtkToolbar    *toolbar,
3077                           const char    *text,
3078                           const char    *tooltip_text,
3079                           const char    *tooltip_private_text,
3080                           GtkWidget     *icon,
3081                           GtkSignalFunc  callback,
3082                           gpointer       user_data)
3083 {
3084   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3085                                      NULL, text,
3086                                      tooltip_text, tooltip_private_text,
3087                                      icon, callback, user_data,
3088                                      0);
3089 }
3090
3091 /**
3092  * gtk_toolbar_insert_item:
3093  * @toolbar: a #GtkToolbar.
3094  * @text: give your toolbar button a label.
3095  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3096  * @tooltip_private_text: use with #GtkTipsQuery.
3097  * @icon: a #GtkWidget that should be used as the button's icon.
3098  * @callback: the function to be executed when the button is pressed.
3099  * @user_data: a pointer to any data you wish to be passed to the callback.
3100  * @position: the number of widgets to insert this item after.
3101  * 
3102  * Inserts a new item into the toolbar. You must specify the position in the
3103  * toolbar where it will be inserted.
3104  *
3105  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3106  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3107  *
3108  * Return value: the new toolbar item as a #GtkWidget.
3109  **/
3110 GtkWidget *
3111 gtk_toolbar_insert_item (GtkToolbar    *toolbar,
3112                          const char    *text,
3113                          const char    *tooltip_text,
3114                          const char    *tooltip_private_text,
3115                          GtkWidget     *icon,
3116                          GtkSignalFunc  callback,
3117                          gpointer       user_data,
3118                          gint           position)
3119 {
3120   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3121                                      NULL, text,
3122                                      tooltip_text, tooltip_private_text,
3123                                      icon, callback, user_data,
3124                                      position);
3125 }
3126
3127 /**
3128  * gtk_toolbar_insert_stock:
3129  * @toolbar: A #GtkToolbar
3130  * @stock_id: The id of the stock item you want to insert
3131  * @tooltip_text: The text in the tooltip of the toolbar button
3132  * @tooltip_private_text: The private text of the tooltip
3133  * @callback: The callback called when the toolbar button is clicked.
3134  * @user_data: user data passed to callback
3135  * @position: The position the button shall be inserted at.
3136  *            -1 means at the end.
3137  *
3138  * Inserts a stock item at the specified position of the toolbar.  If
3139  * @stock_id is not a known stock item ID, it's inserted verbatim,
3140  * except that underscores used to mark mnemonics are removed.
3141  *
3142  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3143  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3144  *
3145  * Returns: the inserted widget
3146  */
3147 GtkWidget*
3148 gtk_toolbar_insert_stock (GtkToolbar      *toolbar,
3149                           const gchar     *stock_id,
3150                           const char      *tooltip_text,
3151                           const char      *tooltip_private_text,
3152                           GtkSignalFunc    callback,
3153                           gpointer         user_data,
3154                           gint             position)
3155 {
3156   return gtk_toolbar_internal_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3157                                               NULL, stock_id,
3158                                               tooltip_text, tooltip_private_text,
3159                                               NULL, callback, user_data,
3160                                               position, TRUE);
3161 }
3162
3163 /**
3164  * gtk_toolbar_append_space:
3165  * @toolbar: a #GtkToolbar.
3166  * 
3167  * Adds a new space to the end of the toolbar.
3168  **/
3169 void
3170 gtk_toolbar_append_space (GtkToolbar *toolbar)
3171 {
3172   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3173                               NULL, NULL,
3174                               NULL, NULL,
3175                               NULL, NULL, NULL,
3176                               toolbar->num_children);
3177 }
3178
3179 /**
3180  * gtk_toolbar_prepend_space:
3181  * @toolbar: a #GtkToolbar.
3182  * 
3183  * Adds a new space to the beginning of the toolbar.
3184  **/
3185 void
3186 gtk_toolbar_prepend_space (GtkToolbar *toolbar)
3187 {
3188   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3189                               NULL, NULL,
3190                               NULL, NULL,
3191                               NULL, NULL, NULL,
3192                               0);
3193 }
3194
3195 /**
3196  * gtk_toolbar_insert_space:
3197  * @toolbar: a #GtkToolbar
3198  * @position: the number of widgets after which a space should be inserted.
3199  * 
3200  * Inserts a new space in the toolbar at the specified position.
3201  **/
3202 void
3203 gtk_toolbar_insert_space (GtkToolbar *toolbar,
3204                           gint        position)
3205 {
3206   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3207                               NULL, NULL,
3208                               NULL, NULL,
3209                               NULL, NULL, NULL,
3210                               position);
3211 }
3212
3213 /**
3214  * gtk_toolbar_remove_space:
3215  * @toolbar: a #GtkToolbar.
3216  * @position: the index of the space to remove.
3217  * 
3218  * Removes a space from the specified position.
3219  **/
3220 void
3221 gtk_toolbar_remove_space (GtkToolbar *toolbar,
3222                           gint        position)
3223 {
3224   GtkToolItem *item;
3225
3226   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3227
3228   if (!gtk_toolbar_check_old_api (toolbar))
3229     return;
3230   
3231   item = g_list_nth_data (toolbar->children, position);
3232
3233   if (!item)
3234     {
3235       g_warning ("Toolbar position %d doesn't exist", position);
3236       return;
3237     }
3238
3239   if (!GTK_IS_SEPARATOR_TOOL_ITEM (item))
3240     {
3241       g_warning ("Toolbar position %d is not a space", position);
3242       return;
3243     }
3244
3245   gtk_toolbar_remove_tool_item (toolbar, item);
3246 }
3247
3248 /**
3249  * gtk_toolbar_append_widget:
3250  * @toolbar: a #GtkToolbar.
3251  * @widget: a #GtkWidget to add to the toolbar. 
3252  * @tooltip_text: the element's tooltip.
3253  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3254  * 
3255  * Adds a widget to the end of the given toolbar.
3256  **/ 
3257 void
3258 gtk_toolbar_append_widget (GtkToolbar  *toolbar,
3259                            GtkWidget   *widget,
3260                            const gchar *tooltip_text,
3261                            const gchar *tooltip_private_text)
3262 {
3263   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3264                               widget, NULL,
3265                               tooltip_text, tooltip_private_text,
3266                               NULL, NULL, NULL,
3267                               toolbar->num_children);
3268 }
3269
3270 /**
3271  * gtk_toolbar_prepend_widget:
3272  * @toolbar: a #GtkToolbar.
3273  * @widget: a #GtkWidget to add to the toolbar. 
3274  * @tooltip_text: the element's tooltip.
3275  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3276  * 
3277  * Adds a widget to the beginning of the given toolbar.
3278  **/ 
3279 void
3280 gtk_toolbar_prepend_widget (GtkToolbar  *toolbar,
3281                             GtkWidget   *widget,
3282                             const gchar *tooltip_text,
3283                             const gchar *tooltip_private_text)
3284 {
3285   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3286                               widget, NULL,
3287                               tooltip_text, tooltip_private_text,
3288                               NULL, NULL, NULL,
3289                               0);
3290 }
3291
3292 /**
3293  * gtk_toolbar_insert_widget:
3294  * @toolbar: a #GtkToolbar.
3295  * @widget: a #GtkWidget to add to the toolbar. 
3296  * @tooltip_text: the element's tooltip.
3297  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3298  * @position: the number of widgets to insert this widget after.
3299  * 
3300  * Inserts a widget in the toolbar at the given position.
3301  **/ 
3302 void
3303 gtk_toolbar_insert_widget (GtkToolbar *toolbar,
3304                            GtkWidget  *widget,
3305                            const char *tooltip_text,
3306                            const char *tooltip_private_text,
3307                            gint        position)
3308 {
3309   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3310                               widget, NULL,
3311                               tooltip_text, tooltip_private_text,
3312                               NULL, NULL, NULL,
3313                               position);
3314 }
3315
3316 /**
3317  * gtk_toolbar_append_element:
3318  * @toolbar: a #GtkToolbar.
3319  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3320  * @widget: a #GtkWidget, or %NULL.
3321  * @text: the element's label.
3322  * @tooltip_text: the element's tooltip.
3323  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3324  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3325  * @callback: the function to be executed when the button is pressed.
3326  * @user_data: any data you wish to pass to the callback.
3327  * 
3328  * Adds a new element to the end of a toolbar.
3329  * 
3330  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3331  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3332  * the radio group for the new element. In all other cases, @widget must
3333  * be %NULL.
3334  * 
3335  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3336  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3337  *
3338  * Return value: the new toolbar element as a #GtkWidget.
3339  **/
3340 GtkWidget*
3341 gtk_toolbar_append_element (GtkToolbar          *toolbar,
3342                             GtkToolbarChildType  type,
3343                             GtkWidget           *widget,
3344                             const char          *text,
3345                             const char          *tooltip_text,
3346                             const char          *tooltip_private_text,
3347                             GtkWidget           *icon,
3348                             GtkSignalFunc        callback,
3349                             gpointer             user_data)
3350 {
3351   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3352                                      tooltip_text, tooltip_private_text,
3353                                      icon, callback, user_data,
3354                                      toolbar->num_children);
3355 }
3356
3357 /**
3358  * gtk_toolbar_prepend_element:
3359  * @toolbar: a #GtkToolbar.
3360  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3361  * @widget: a #GtkWidget, or %NULL
3362  * @text: the element's label.
3363  * @tooltip_text: the element's tooltip.
3364  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3365  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3366  * @callback: the function to be executed when the button is pressed.
3367  * @user_data: any data you wish to pass to the callback.
3368  *  
3369  * Adds a new element to the beginning of a toolbar.
3370  * 
3371  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3372  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3373  * the radio group for the new element. In all other cases, @widget must
3374  * be %NULL.
3375  * 
3376  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3377  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3378  *
3379  * Return value: the new toolbar element as a #GtkWidget.
3380  **/
3381 GtkWidget *
3382 gtk_toolbar_prepend_element (GtkToolbar          *toolbar,
3383                              GtkToolbarChildType  type,
3384                              GtkWidget           *widget,
3385                              const char          *text,
3386                              const char          *tooltip_text,
3387                              const char          *tooltip_private_text,
3388                              GtkWidget           *icon,
3389                              GtkSignalFunc        callback,
3390                              gpointer             user_data)
3391 {
3392   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3393                                      tooltip_text, tooltip_private_text,
3394                                      icon, callback, user_data, 0);
3395 }
3396
3397 /**
3398  * gtk_toolbar_insert_element:
3399  * @toolbar: a #GtkToolbar.
3400  * @type: a value of type #GtkToolbarChildType that determines what @widget
3401  *   will be.
3402  * @widget: a #GtkWidget, or %NULL. 
3403  * @text: the element's label.
3404  * @tooltip_text: the element's tooltip.
3405  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3406  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3407  * @callback: the function to be executed when the button is pressed.
3408  * @user_data: any data you wish to pass to the callback.
3409  * @position: the number of widgets to insert this element after.
3410  *
3411  * Inserts a new element in the toolbar at the given position. 
3412  *
3413  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3414  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3415  * the radio group for the new element. In all other cases, @widget must
3416  * be %NULL.
3417  *
3418  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3419  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3420  *
3421  * Return value: the new toolbar element as a #GtkWidget.
3422  **/
3423 GtkWidget *
3424 gtk_toolbar_insert_element (GtkToolbar          *toolbar,
3425                             GtkToolbarChildType  type,
3426                             GtkWidget           *widget,
3427                             const char          *text,
3428                             const char          *tooltip_text,
3429                             const char          *tooltip_private_text,
3430                             GtkWidget           *icon,
3431                             GtkSignalFunc        callback,
3432                             gpointer             user_data,
3433                             gint                 position)
3434 {
3435   return gtk_toolbar_internal_insert_element (toolbar, type, widget, text,
3436                                               tooltip_text, tooltip_private_text,
3437                                               icon, callback, user_data, position, FALSE);
3438 }
3439
3440 gchar *
3441 _gtk_toolbar_elide_underscores (const gchar *original)
3442 {
3443   gchar *q, *result;
3444   const gchar *p;
3445   gboolean last_underscore;
3446
3447   q = result = g_malloc (strlen (original) + 1);
3448   last_underscore = FALSE;
3449   
3450   for (p = original; *p; p++)
3451     {
3452       if (!last_underscore && *p == '_')
3453         last_underscore = TRUE;
3454       else
3455         {
3456           last_underscore = FALSE;
3457           *q++ = *p;
3458         }
3459     }
3460   
3461   *q = '\0';
3462   
3463   return result;
3464 }
3465
3466 static GtkWidget *
3467 gtk_toolbar_internal_insert_element (GtkToolbar          *toolbar,
3468                                      GtkToolbarChildType  type,
3469                                      GtkWidget           *widget,
3470                                      const char          *text,
3471                                      const char          *tooltip_text,
3472                                      const char          *tooltip_private_text,
3473                                      GtkWidget           *icon,
3474                                      GtkSignalFunc        callback,
3475                                      gpointer             user_data,
3476                                      gint                 position,
3477                                      gboolean             use_stock)
3478 {
3479   GtkToolbarChild *child;
3480   GtkToolItem *item = NULL;
3481   
3482   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
3483   
3484   if (!gtk_toolbar_check_old_api (toolbar))
3485     return NULL;
3486   
3487   if (type == GTK_TOOLBAR_CHILD_WIDGET)
3488     g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
3489   else if (type != GTK_TOOLBAR_CHILD_RADIOBUTTON)
3490     g_return_val_if_fail (widget == NULL, NULL);
3491
3492   child = g_new (GtkToolbarChild, 1);
3493
3494   child->type = type;
3495   child->icon = NULL;
3496   child->label = NULL;
3497
3498   switch (type)
3499     {
3500     case GTK_TOOLBAR_CHILD_SPACE:
3501       item = gtk_separator_tool_item_new ();
3502       child->widget = NULL;
3503       break;
3504
3505     case GTK_TOOLBAR_CHILD_WIDGET:
3506       item = gtk_tool_item_new ();
3507       child->widget = widget;
3508       gtk_container_add (GTK_CONTAINER (item), child->widget);
3509       break;
3510
3511     case GTK_TOOLBAR_CHILD_BUTTON:
3512       item = gtk_tool_button_new (NULL, NULL);
3513       child->widget = _gtk_tool_button_get_button (GTK_TOOL_BUTTON (item));
3514       break;
3515       
3516     case GTK_TOOLBAR_CHILD_TOGGLEBUTTON:
3517       item = gtk_toggle_tool_button_new ();
3518       child->widget = _gtk_tool_button_get_button (GTK_TOOL_BUTTON (item));
3519       break;
3520
3521     case GTK_TOOLBAR_CHILD_RADIOBUTTON:
3522       item = gtk_radio_tool_button_new (widget
3523                                         ? gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget))
3524                                         : NULL);
3525       child->widget = _gtk_tool_button_get_button (GTK_TOOL_BUTTON (item));
3526       break;
3527     }
3528
3529   /*
3530    * When we are using the old API, consider all items "is_important". That
3531    * way BOTH_HORIZ will continue to show both icon and label in old API mode
3532    */
3533   gtk_tool_item_set_is_important (item, TRUE);
3534
3535   gtk_widget_show (GTK_WIDGET (item));
3536   
3537   if (type == GTK_TOOLBAR_CHILD_BUTTON ||
3538       type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
3539       type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
3540     {
3541       if (text)
3542         {
3543           if (use_stock)
3544             {
3545               GtkStockItem stock_item;
3546               gchar *label_text;
3547
3548               gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (item), text);
3549
3550               gtk_stock_lookup (text, &stock_item);
3551               label_text = _gtk_toolbar_elide_underscores (stock_item.label);
3552               child->label = GTK_WIDGET (gtk_label_new (label_text));
3553               g_free (label_text);
3554             }
3555           else
3556             {
3557               child->label = gtk_label_new (text);
3558             }
3559           gtk_tool_button_set_label_widget (GTK_TOOL_BUTTON (item), child->label);
3560           gtk_widget_show (child->label);
3561         }
3562
3563       if (icon)
3564         {
3565           child->icon = icon;
3566           gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (item), icon);
3567
3568           /* Applications depend on the toolbar showing the widget for them */
3569           gtk_widget_show (GTK_WIDGET (icon));
3570         }
3571
3572       /*
3573        * We need to connect to the button's clicked callback because some
3574        * programs may rely on that the widget in the callback is a GtkButton
3575        */
3576       if (callback)
3577         g_signal_connect (child->widget, "clicked",
3578                           callback, user_data);
3579     }
3580
3581   if ((type != GTK_TOOLBAR_CHILD_SPACE) && tooltip_text)
3582     gtk_tool_item_set_tooltip (item, toolbar->tooltips,
3583                                tooltip_text, tooltip_private_text);
3584   
3585   toolbar->children = g_list_insert (toolbar->children, child, position);
3586
3587   gtk_toolbar_insert_tool_item (toolbar, item, position, FALSE);
3588
3589   return child->widget;
3590 }
3591
3592 static void
3593 gtk_toolbar_finalize (GObject *object)
3594 {
3595   GList *list;
3596   GtkToolbar *toolbar = GTK_TOOLBAR (object);
3597   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3598   
3599   if (toolbar->tooltips)
3600     g_object_unref (toolbar->tooltips);
3601
3602   for (list = toolbar->children; list != NULL; list = list->next)
3603     g_free (list->data);
3604
3605   g_list_free (toolbar->children);
3606
3607   for (list = priv->content; list != NULL; list = list->next)
3608     g_free (list->data);
3609
3610   g_list_free (priv->content);
3611
3612   g_timer_destroy (priv->timer);
3613
3614   if (priv->idle_id)
3615     g_source_remove (priv->idle_id);
3616   
3617   G_OBJECT_CLASS (parent_class)->finalize (object);
3618 }