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