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