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