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