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