]> Pileus Git - ~andy/gtk/blob - gtk/gtktoolbar.c
Base the decision to map/unmap items on whether they are actually
[~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@gnome.org>
6  * Copyright (C) 2002 James Henstridge <james@daa.com.au>
7  * Copyright (C) 2003, 2004 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 #include "gtkhbox.h"
51 #include "gtkvbox.h"
52 #include "gtkimage.h"
53
54 typedef struct _ToolbarContent ToolbarContent;
55
56 #define DEFAULT_IPADDING 0
57
58 /* note: keep in sync with DEFAULT_SPACE_SIZE and DEFAULT_SPACE_STYLE in gtkseparatortoolitem.c */
59 #define DEFAULT_SPACE_SIZE  4
60 #define DEFAULT_SPACE_STYLE GTK_TOOLBAR_SPACE_LINE
61 #define SPACE_LINE_DIVISION 10.0
62 #define SPACE_LINE_START    3.0
63 #define SPACE_LINE_END      7.0
64
65 #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_LARGE_TOOLBAR
66 #define DEFAULT_TOOLBAR_STYLE GTK_TOOLBAR_BOTH
67
68 #define MAX_HOMOGENEOUS_N_CHARS 13 /* Items that are wider than this do not participate
69                                     * in the homogeneous game. In units of
70                                     * pango_font_get_estimated_char_width().
71                                     */
72 #define SLIDE_SPEED 800    /* How fast the items slide, in pixels per second */
73
74 /* Properties */
75 enum {
76   PROP_0,
77   PROP_ORIENTATION,
78   PROP_TOOLBAR_STYLE,
79   PROP_SHOW_ARROW
80 };
81
82 /* Child properties */
83 enum {
84   CHILD_PROP_0,
85   CHILD_PROP_EXPAND,
86   CHILD_PROP_HOMOGENEOUS
87 };
88
89 /* Signals */
90 enum {
91   ORIENTATION_CHANGED,
92   STYLE_CHANGED,
93   POPUP_CONTEXT_MENU,
94   MOVE_FOCUS,
95   FOCUS_HOME_OR_END,
96   LAST_SIGNAL
97 };
98
99 /* API mode */
100 typedef enum {
101   DONT_KNOW,
102   OLD_API,
103   NEW_API
104 } ApiMode;
105
106 typedef enum {
107   TOOL_ITEM,
108   COMPATIBILITY
109 } ContentType;
110
111 typedef enum {
112   NOT_ALLOCATED,
113   NORMAL,
114   HIDDEN,
115   OVERFLOWN,
116 } ItemState;
117
118 struct _GtkToolbarPrivate
119 {
120   GList *       content;
121   
122   GtkWidget *   arrow;
123   GtkWidget *   arrow_button;
124   
125   GtkMenu *     menu;
126   
127   GdkWindow *   event_window;
128   ApiMode       api_mode;
129   GtkSettings * settings;
130   int           idle_id;
131   GtkToolItem * highlight_tool_item;
132   gint          max_homogeneous_pixels;
133   
134   GTimer *      timer;
135   
136   guint         show_arrow : 1;
137   guint         need_sync : 1;
138   guint         is_sliding : 1;
139 };
140
141 static void            gtk_toolbar_init                 (GtkToolbar          *toolbar);
142 static void            gtk_toolbar_class_init           (GtkToolbarClass     *klass);
143 static void            gtk_toolbar_set_property         (GObject             *object,
144                                                          guint                prop_id,
145                                                          const GValue        *value,
146                                                          GParamSpec          *pspec);
147 static void            gtk_toolbar_get_property         (GObject             *object,
148                                                          guint                prop_id,
149                                                          GValue              *value,
150                                                          GParamSpec          *pspec);
151 static gint            gtk_toolbar_expose               (GtkWidget           *widget,
152                                                          GdkEventExpose      *event);
153 static void            gtk_toolbar_realize              (GtkWidget           *widget);
154 static void            gtk_toolbar_unrealize            (GtkWidget           *widget);
155 static void            gtk_toolbar_size_request         (GtkWidget           *widget,
156                                                          GtkRequisition      *requisition);
157 static void            gtk_toolbar_size_allocate        (GtkWidget           *widget,
158                                                          GtkAllocation       *allocation);
159 static void            gtk_toolbar_style_set            (GtkWidget           *widget,
160                                                          GtkStyle            *prev_style);
161 static void            gtk_toolbar_direction_changed    (GtkWidget           *widget,
162                                                          GtkTextDirection     previous_direction);
163 static gboolean        gtk_toolbar_focus                (GtkWidget           *widget,
164                                                          GtkDirectionType     dir);
165 static void            gtk_toolbar_screen_changed       (GtkWidget           *widget,
166                                                          GdkScreen           *previous_screen);
167 static void            gtk_toolbar_map                  (GtkWidget           *widget);
168 static void            gtk_toolbar_unmap                (GtkWidget           *widget);
169 static void            gtk_toolbar_set_child_property   (GtkContainer        *container,
170                                                          GtkWidget           *child,
171                                                          guint                property_id,
172                                                          const GValue        *value,
173                                                          GParamSpec          *pspec);
174 static void            gtk_toolbar_get_child_property   (GtkContainer        *container,
175                                                          GtkWidget           *child,
176                                                          guint                property_id,
177                                                          GValue              *value,
178                                                          GParamSpec          *pspec);
179 static void            gtk_toolbar_finalize             (GObject             *object);
180 static void            gtk_toolbar_show_all             (GtkWidget           *widget);
181 static void            gtk_toolbar_hide_all             (GtkWidget           *widget);
182 static void            gtk_toolbar_add                  (GtkContainer        *container,
183                                                          GtkWidget           *widget);
184 static void            gtk_toolbar_remove               (GtkContainer        *container,
185                                                          GtkWidget           *widget);
186 static void            gtk_toolbar_forall               (GtkContainer        *container,
187                                                          gboolean             include_internals,
188                                                          GtkCallback          callback,
189                                                          gpointer             callback_data);
190 static GType           gtk_toolbar_child_type           (GtkContainer        *container);
191 static void            gtk_toolbar_orientation_changed  (GtkToolbar          *toolbar,
192                                                          GtkOrientation       orientation);
193 static void            gtk_toolbar_real_style_changed   (GtkToolbar          *toolbar,
194                                                          GtkToolbarStyle      style);
195 static gboolean        gtk_toolbar_move_focus           (GtkToolbar          *toolbar,
196                                                          GtkDirectionType     dir);
197 static gboolean        gtk_toolbar_focus_home_or_end    (GtkToolbar          *toolbar,
198                                                          gboolean             focus_home);
199 static gboolean        gtk_toolbar_button_press         (GtkWidget           *toolbar,
200                                                          GdkEventButton      *event);
201 static gboolean        gtk_toolbar_arrow_button_press   (GtkWidget           *button,
202                                                          GdkEventButton      *event,
203                                                          GtkToolbar          *toolbar);
204 static void            gtk_toolbar_arrow_button_clicked (GtkWidget           *button,
205                                                          GtkToolbar          *toolbar);
206 static void            gtk_toolbar_update_button_relief (GtkToolbar          *toolbar);
207 static gboolean        gtk_toolbar_popup_menu           (GtkWidget           *toolbar);
208 static GtkWidget *     internal_insert_element          (GtkToolbar          *toolbar,
209                                                          GtkToolbarChildType  type,
210                                                          GtkWidget           *widget,
211                                                          const char          *text,
212                                                          const char          *tooltip_text,
213                                                          const char          *tooltip_private_text,
214                                                          GtkWidget           *icon,
215                                                          GtkSignalFunc        callback,
216                                                          gpointer             user_data,
217                                                          gint                 position,
218                                                          gboolean             use_stock);
219 static void            gtk_toolbar_reconfigured         (GtkToolbar          *toolbar);
220 static gboolean        gtk_toolbar_check_new_api        (GtkToolbar          *toolbar);
221 static gboolean        gtk_toolbar_check_old_api        (GtkToolbar          *toolbar);
222
223 static GtkReliefStyle       get_button_relief    (GtkToolbar *toolbar);
224 static gint                 get_internal_padding (GtkToolbar *toolbar);
225 static GtkShadowType        get_shadow_type      (GtkToolbar *toolbar);
226 static gint                 get_space_size       (GtkToolbar *toolbar);
227 static GtkToolbarSpaceStyle get_space_style      (GtkToolbar *toolbar);
228
229 /* methods on ToolbarContent 'class' */
230 static ToolbarContent *toolbar_content_new_tool_item        (GtkToolbar          *toolbar,
231                                                              GtkToolItem         *item,
232                                                              gboolean             is_placeholder,
233                                                              gint                 pos);
234 static ToolbarContent *toolbar_content_new_compatibility    (GtkToolbar          *toolbar,
235                                                              GtkToolbarChildType  type,
236                                                              GtkWidget           *widget,
237                                                              GtkWidget           *icon,
238                                                              GtkWidget           *label,
239                                                              gint                 pos);
240 static void            toolbar_content_remove               (ToolbarContent      *content,
241                                                              GtkToolbar          *toolbar);
242 static void            toolbar_content_free                 (ToolbarContent      *content);
243 static void            toolbar_content_expose               (ToolbarContent      *content,
244                                                              GtkContainer        *container,
245                                                              GdkEventExpose      *expose);
246 static gboolean        toolbar_content_visible              (ToolbarContent      *content,
247                                                              GtkToolbar          *toolbar);
248 static void            toolbar_content_size_request         (ToolbarContent      *content,
249                                                              GtkToolbar          *toolbar,
250                                                              GtkRequisition      *requisition);
251 static gboolean        toolbar_content_is_homogeneous       (ToolbarContent      *content,
252                                                              GtkToolbar          *toolbar);
253 static gboolean        toolbar_content_is_placeholder       (ToolbarContent      *content);
254 static gboolean        toolbar_content_disappearing         (ToolbarContent      *content);
255 static ItemState       toolbar_content_get_state            (ToolbarContent      *content);
256 static gboolean        toolbar_content_child_visible        (ToolbarContent      *content);
257 static void            toolbar_content_get_goal_allocation  (ToolbarContent      *content,
258                                                              GtkAllocation       *allocation);
259 static void            toolbar_content_get_allocation       (ToolbarContent      *content,
260                                                              GtkAllocation       *allocation);
261 static void            toolbar_content_set_start_allocation (ToolbarContent      *content,
262                                                              GtkAllocation       *new_start_allocation);
263 static void            toolbar_content_get_start_allocation (ToolbarContent      *content,
264                                                              GtkAllocation       *start_allocation);
265 static gboolean        toolbar_content_get_expand           (ToolbarContent      *content);
266 static void            toolbar_content_set_goal_allocation  (ToolbarContent      *content,
267                                                              GtkAllocation       *allocation);
268 static void            toolbar_content_set_child_visible    (ToolbarContent      *content,
269                                                              GtkToolbar          *toolbar,
270                                                              gboolean             visible);
271 static void            toolbar_content_size_allocate        (ToolbarContent      *content,
272                                                              GtkAllocation       *allocation);
273 static void            toolbar_content_set_state            (ToolbarContent      *content,
274                                                              ItemState            new_state);
275 static GtkWidget *     toolbar_content_get_widget           (ToolbarContent      *content);
276 static void            toolbar_content_set_disappearing     (ToolbarContent      *content,
277                                                              gboolean             disappearing);
278 static void            toolbar_content_set_size_request     (ToolbarContent      *content,
279                                                              gint                 width,
280                                                              gint                 height);
281 static void            toolbar_content_toolbar_reconfigured (ToolbarContent      *content,
282                                                              GtkToolbar          *toolbar);
283 static GtkWidget *     toolbar_content_retrieve_menu_item   (ToolbarContent      *content);
284 static gboolean        toolbar_content_is_separator         (ToolbarContent      *content);
285 static void            toolbar_content_show_all             (ToolbarContent      *content);
286 static void            toolbar_content_hide_all             (ToolbarContent      *content);
287
288
289 #define GTK_TOOLBAR_GET_PRIVATE(o)  \
290   (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_TOOLBAR, GtkToolbarPrivate))
291
292 static GtkContainerClass *      parent_class = NULL;
293 static guint                    toolbar_signals [LAST_SIGNAL] = { 0 };
294
295 GType
296 gtk_toolbar_get_type (void)
297 {
298   static GtkType type = 0;
299   
300   if (!type)
301     {
302       static const GTypeInfo type_info =
303         {
304           sizeof (GtkToolbarClass),
305           (GBaseInitFunc) NULL,
306           (GBaseFinalizeFunc) NULL,
307           (GClassInitFunc) gtk_toolbar_class_init,
308           (GClassFinalizeFunc) NULL,
309           NULL,
310           sizeof (GtkToolbar),
311           0, /* n_preallocs */
312           (GInstanceInitFunc) gtk_toolbar_init,
313         };
314       
315       type = g_type_register_static (GTK_TYPE_CONTAINER,
316                                      "GtkToolbar",
317                                      &type_info, 0);
318     }
319   
320   return type;
321 }
322
323 static void
324 add_arrow_bindings (GtkBindingSet   *binding_set,
325                     guint            keysym,
326                     GtkDirectionType dir)
327 {
328   guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
329   
330   gtk_binding_entry_add_signal (binding_set, keysym, 0,
331                                 "move_focus", 1,
332                                 GTK_TYPE_DIRECTION_TYPE, dir);
333   gtk_binding_entry_add_signal (binding_set, keypad_keysym, 0,
334                                 "move_focus", 1,
335                                 GTK_TYPE_DIRECTION_TYPE, dir);
336 }
337
338 static void
339 add_ctrl_tab_bindings (GtkBindingSet    *binding_set,
340                        GdkModifierType   modifiers,
341                        GtkDirectionType  direction)
342 {
343   gtk_binding_entry_add_signal (binding_set,
344                                 GDK_Tab, GDK_CONTROL_MASK | modifiers,
345                                 "move_focus", 1,
346                                 GTK_TYPE_DIRECTION_TYPE, direction);
347   gtk_binding_entry_add_signal (binding_set,
348                                 GDK_KP_Tab, GDK_CONTROL_MASK | modifiers,
349                                 "move_focus", 1,
350                                 GTK_TYPE_DIRECTION_TYPE, direction);
351 }
352
353 static void
354 gtk_toolbar_class_init (GtkToolbarClass *klass)
355 {
356   GObjectClass *gobject_class;
357   GtkWidgetClass *widget_class;
358   GtkContainerClass *container_class;
359   GtkBindingSet *binding_set;
360   
361   parent_class = g_type_class_peek_parent (klass);
362   
363   gobject_class = (GObjectClass *)klass;
364   widget_class = (GtkWidgetClass *)klass;
365   container_class = (GtkContainerClass *)klass;
366   
367   gobject_class->set_property = gtk_toolbar_set_property;
368   gobject_class->get_property = gtk_toolbar_get_property;
369   gobject_class->finalize = gtk_toolbar_finalize;
370   
371   widget_class->button_press_event = gtk_toolbar_button_press;
372   widget_class->expose_event = gtk_toolbar_expose;
373   widget_class->size_request = gtk_toolbar_size_request;
374   widget_class->size_allocate = gtk_toolbar_size_allocate;
375   widget_class->style_set = gtk_toolbar_style_set;
376   widget_class->direction_changed = gtk_toolbar_direction_changed;
377   widget_class->focus = gtk_toolbar_focus;
378   widget_class->screen_changed = gtk_toolbar_screen_changed;
379   widget_class->realize = gtk_toolbar_realize;
380   widget_class->unrealize = gtk_toolbar_unrealize;
381   widget_class->map = gtk_toolbar_map;
382   widget_class->unmap = gtk_toolbar_unmap;
383   widget_class->popup_menu = gtk_toolbar_popup_menu;
384   widget_class->show_all = gtk_toolbar_show_all;
385   widget_class->hide_all = gtk_toolbar_hide_all;
386   
387   container_class->add    = gtk_toolbar_add;
388   container_class->remove = gtk_toolbar_remove;
389   container_class->forall = gtk_toolbar_forall;
390   container_class->child_type = gtk_toolbar_child_type;
391   container_class->get_child_property = gtk_toolbar_get_child_property;
392   container_class->set_child_property = gtk_toolbar_set_child_property;
393   
394   klass->orientation_changed = gtk_toolbar_orientation_changed;
395   klass->style_changed = gtk_toolbar_real_style_changed;
396   
397   /**
398    * GtkToolbar::orientation-changed:
399    * @toolbar: the object which emitted the signal
400    * @orientation: the new #GtkOrientation of the toolbar
401    *
402    * Emitted when the orientation of the toolbar changes.
403    */
404   toolbar_signals[ORIENTATION_CHANGED] =
405     g_signal_new ("orientation-changed",
406                   G_OBJECT_CLASS_TYPE (klass),
407                   G_SIGNAL_RUN_FIRST,
408                   G_STRUCT_OFFSET (GtkToolbarClass, orientation_changed),
409                   NULL, NULL,
410                   g_cclosure_marshal_VOID__ENUM,
411                   G_TYPE_NONE, 1,
412                   GTK_TYPE_ORIENTATION);
413   /**
414    * GtkToolbar::style-changed:
415    * @toolbar: The #GtkToolbar which emitted the signal
416    * @style: the new #GtkToolbarStyle of the toolbar
417    *
418    * Emitted when the style of the toolbar changes. 
419    */
420   toolbar_signals[STYLE_CHANGED] =
421     g_signal_new ("style-changed",
422                   G_OBJECT_CLASS_TYPE (klass),
423                   G_SIGNAL_RUN_FIRST,
424                   G_STRUCT_OFFSET (GtkToolbarClass, style_changed),
425                   NULL, NULL,
426                   g_cclosure_marshal_VOID__ENUM,
427                   G_TYPE_NONE, 1,
428                   GTK_TYPE_TOOLBAR_STYLE);
429   /**
430    * GtkToolbar::popup-context-menu:
431    * @toolbar: the #GtkToolbar which emitted the signal
432    * @x: the x coordinate of the point where the menu should appear
433    * @y: the y coordinate of the point where the menu should appear
434    * @button: the mouse button the user pressed, or -1
435    *
436    * Emitted when the user right-clicks the toolbar or uses the
437    * keybinding to display a popup menu.
438    *
439    * Application developers should handle this signal if they want
440    * to display a context menu on the toolbar. The context-menu should
441    * appear at the coordinates given by @x and @y. The mouse button
442    * number is given by the @button parameter. If the menu was popped
443    * up using the keybaord, @button is -1.
444    *
445    * Return value: return %TRUE if the signal was handled, %FALSE if not
446    */
447   toolbar_signals[POPUP_CONTEXT_MENU] =
448     g_signal_new ("popup_context_menu",
449                   G_OBJECT_CLASS_TYPE (klass),
450                   G_SIGNAL_RUN_LAST,
451                   G_STRUCT_OFFSET (GtkToolbarClass, popup_context_menu),
452                   _gtk_boolean_handled_accumulator, NULL,
453                   _gtk_marshal_BOOLEAN__INT_INT_INT,
454                   G_TYPE_BOOLEAN, 3,
455                   G_TYPE_INT, G_TYPE_INT,
456                   G_TYPE_INT);
457   /**
458    * GtkToolbar::move-focus:
459    * @toolbar: the #GtkToolbar which emitted the signal
460    * @dir: a #GtkDirection
461    *
462    * A keybinding signal used internally by GTK+. This signal can't
463    * be used in application code.
464    *
465    * Return value: %TRUE if the signal was handled, %FALSE if not
466    */
467   toolbar_signals[MOVE_FOCUS] =
468     _gtk_binding_signal_new ("move_focus",
469                              G_TYPE_FROM_CLASS (klass),
470                              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
471                              G_CALLBACK (gtk_toolbar_move_focus),
472                              NULL, NULL,
473                              _gtk_marshal_BOOLEAN__ENUM,
474                              G_TYPE_BOOLEAN, 1,
475                              GTK_TYPE_DIRECTION_TYPE);
476   /**
477    * GtkToolbar::focus-home-or-end:
478    * @toolbar: the #GtkToolbar which emitted the signal
479    * @focus_home: %TRUE if the first item should be focused
480    *
481    * A keybinding signal used internally by GTK+. This signal can't
482    * be used in application code
483    *
484    * Return value: %TRUE if the signal was handled, %FALSE if not
485    */
486   toolbar_signals[FOCUS_HOME_OR_END] =
487     _gtk_binding_signal_new ("focus_home_or_end",
488                              G_OBJECT_CLASS_TYPE (klass),
489                              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
490                              G_CALLBACK (gtk_toolbar_focus_home_or_end),
491                              NULL, NULL,
492                              _gtk_marshal_BOOLEAN__BOOLEAN,
493                              G_TYPE_BOOLEAN, 1,
494                              G_TYPE_BOOLEAN);
495   
496   /* properties */
497   g_object_class_install_property (gobject_class,
498                                    PROP_ORIENTATION,
499                                    g_param_spec_enum ("orientation",
500                                                       P_("Orientation"),
501                                                       P_("The orientation of the toolbar"),
502                                                       GTK_TYPE_ORIENTATION,
503                                                       GTK_ORIENTATION_HORIZONTAL,
504                                                       G_PARAM_READWRITE));
505   
506   g_object_class_install_property (gobject_class,
507                                    PROP_TOOLBAR_STYLE,
508                                    g_param_spec_enum ("toolbar_style",
509                                                       P_("Toolbar Style"),
510                                                       P_("How to draw the toolbar"),
511                                                       GTK_TYPE_TOOLBAR_STYLE,
512                                                       GTK_TOOLBAR_ICONS,
513                                                       G_PARAM_READWRITE));
514   g_object_class_install_property (gobject_class,
515                                    PROP_SHOW_ARROW,
516                                    g_param_spec_boolean ("show_arrow",
517                                                          P_("Show Arrow"),
518                                                          P_("If an arrow should be shown if the toolbar doesn't fit"),
519                                                          TRUE,
520                                                          G_PARAM_READWRITE));
521   
522   /* child properties */
523   gtk_container_class_install_child_property (container_class,
524                                               CHILD_PROP_EXPAND,
525                                               g_param_spec_boolean ("expand", 
526                                                                     P_("Expand"), 
527                                                                     P_("Whether the item should receive extra space when the toolbar grows"),
528                                                                     TRUE,
529                                                                     G_PARAM_READWRITE));
530   
531   gtk_container_class_install_child_property (container_class,
532                                               CHILD_PROP_HOMOGENEOUS,
533                                               g_param_spec_boolean ("homogeneous", 
534                                                                     P_("Homogeneous"), 
535                                                                     P_("Whether the item should be the same size as other homogeneous items"),
536                                                                     TRUE,
537                                                                     G_PARAM_READWRITE));
538   
539   /* style properties */
540   gtk_widget_class_install_style_property (widget_class,
541                                            g_param_spec_int ("space_size",
542                                                              P_("Spacer size"),
543                                                              P_("Size of spacers"),
544                                                              0,
545                                                              G_MAXINT,
546                                                              DEFAULT_SPACE_SIZE,
547                                                              G_PARAM_READABLE));
548   
549   gtk_widget_class_install_style_property (widget_class,
550                                            g_param_spec_int ("internal_padding",
551                                                              P_("Internal padding"),
552                                                              P_("Amount of border space between the toolbar shadow and the buttons"),
553                                                              0,
554                                                              G_MAXINT,
555                                                              DEFAULT_IPADDING,
556                                                              G_PARAM_READABLE));
557   
558   gtk_widget_class_install_style_property (widget_class,
559                                            g_param_spec_enum ("space_style",
560                                                               P_("Space style"),
561                                                               P_("Whether spacers are vertical lines or just blank"),
562                                                               GTK_TYPE_TOOLBAR_SPACE_STYLE,
563                                                               DEFAULT_SPACE_STYLE,
564                                                               G_PARAM_READABLE));
565   
566   gtk_widget_class_install_style_property (widget_class,
567                                            g_param_spec_enum ("button_relief",
568                                                               P_("Button relief"),
569                                                               P_("Type of bevel around toolbar buttons"),
570                                                               GTK_TYPE_RELIEF_STYLE,
571                                                               GTK_RELIEF_NONE,
572                                                               G_PARAM_READABLE));
573   gtk_widget_class_install_style_property (widget_class,
574                                            g_param_spec_enum ("shadow_type",
575                                                               P_("Shadow type"),
576                                                               P_("Style of bevel around the toolbar"),
577                                                               GTK_TYPE_SHADOW_TYPE,
578                                                               GTK_SHADOW_OUT,
579                                                               G_PARAM_READABLE));
580   
581   gtk_settings_install_property (g_param_spec_enum ("gtk-toolbar-style",
582                                                     P_("Toolbar style"),
583                                                     P_("Whether default toolbars have text only, text and icons, icons only, etc."),
584                                                     GTK_TYPE_TOOLBAR_STYLE,
585                                                     DEFAULT_TOOLBAR_STYLE,
586                                                     G_PARAM_READWRITE));
587   
588   gtk_settings_install_property (g_param_spec_enum ("gtk-toolbar-icon-size",
589                                                     P_("Toolbar icon size"),
590                                                     P_("Size of icons in default toolbars"),
591                                                     GTK_TYPE_ICON_SIZE,
592                                                     DEFAULT_ICON_SIZE,
593                                                     G_PARAM_READWRITE));  
594   
595   binding_set = gtk_binding_set_by_class (klass);
596   
597   add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
598   add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
599   add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
600   add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
601   
602   gtk_binding_entry_add_signal (binding_set, GDK_KP_Home, 0,
603                                 "focus_home_or_end", 1,
604                                 G_TYPE_BOOLEAN, TRUE);
605   gtk_binding_entry_add_signal (binding_set, GDK_Home, 0,
606                                 "focus_home_or_end", 1,
607                                 G_TYPE_BOOLEAN, TRUE);
608   gtk_binding_entry_add_signal (binding_set, GDK_KP_End, 0,
609                                 "focus_home_or_end", 1,
610                                 G_TYPE_BOOLEAN, FALSE);
611   gtk_binding_entry_add_signal (binding_set, GDK_End, 0,
612                                 "focus_home_or_end", 1,
613                                 G_TYPE_BOOLEAN, FALSE);
614   
615   add_ctrl_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
616   add_ctrl_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
617   
618   g_type_class_add_private (gobject_class, sizeof (GtkToolbarPrivate));  
619 }
620
621 static void
622 gtk_toolbar_init (GtkToolbar *toolbar)
623 {
624   GtkToolbarPrivate *priv;
625   
626   GTK_WIDGET_UNSET_FLAGS (toolbar, GTK_CAN_FOCUS);
627   GTK_WIDGET_SET_FLAGS (toolbar, GTK_NO_WINDOW);
628   
629   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
630   
631   toolbar->orientation = GTK_ORIENTATION_HORIZONTAL;
632   toolbar->style = DEFAULT_TOOLBAR_STYLE;
633   toolbar->icon_size = DEFAULT_ICON_SIZE;
634   toolbar->tooltips = gtk_tooltips_new ();
635   g_object_ref (toolbar->tooltips);
636   gtk_object_sink (GTK_OBJECT (toolbar->tooltips));
637   
638   priv->arrow_button = gtk_toggle_button_new ();
639   g_signal_connect (priv->arrow_button, "button_press_event",
640                     G_CALLBACK (gtk_toolbar_arrow_button_press), toolbar);
641   g_signal_connect (priv->arrow_button, "clicked",
642                     G_CALLBACK (gtk_toolbar_arrow_button_clicked), toolbar);
643   gtk_button_set_relief (GTK_BUTTON (priv->arrow_button),
644                          get_button_relief (toolbar));
645   
646   priv->api_mode = DONT_KNOW;
647   
648   gtk_button_set_focus_on_click (GTK_BUTTON (priv->arrow_button), FALSE);
649   
650   priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
651   gtk_widget_set_name (priv->arrow, "gtk-toolbar-arrow");
652   gtk_widget_show (priv->arrow);
653   gtk_container_add (GTK_CONTAINER (priv->arrow_button), priv->arrow);
654   
655   gtk_widget_set_parent (priv->arrow_button, GTK_WIDGET (toolbar));
656   
657   /* which child position a drop will occur at */
658   priv->menu = NULL;
659   priv->show_arrow = TRUE;
660   priv->settings = NULL;
661   
662   priv->max_homogeneous_pixels = -1;
663   
664   priv->timer = g_timer_new ();
665 }
666
667 static void
668 gtk_toolbar_set_property (GObject      *object,
669                           guint         prop_id,
670                           const GValue *value,
671                           GParamSpec   *pspec)
672 {
673   GtkToolbar *toolbar = GTK_TOOLBAR (object);
674   
675   switch (prop_id)
676     {
677     case PROP_ORIENTATION:
678       gtk_toolbar_set_orientation (toolbar, g_value_get_enum (value));
679       break;
680     case PROP_TOOLBAR_STYLE:
681       gtk_toolbar_set_style (toolbar, g_value_get_enum (value));
682       break;
683     case PROP_SHOW_ARROW:
684       gtk_toolbar_set_show_arrow (toolbar, g_value_get_boolean (value));
685       break;
686     default:
687       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
688       break;
689     }
690 }
691
692 static void
693 gtk_toolbar_get_property (GObject    *object,
694                           guint       prop_id,
695                           GValue     *value,
696                           GParamSpec *pspec)
697 {
698   GtkToolbar *toolbar = GTK_TOOLBAR (object);
699   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
700   
701   switch (prop_id)
702     {
703     case PROP_ORIENTATION:
704       g_value_set_enum (value, toolbar->orientation);
705       break;
706     case PROP_TOOLBAR_STYLE:
707       g_value_set_enum (value, toolbar->style);
708       break;
709     case PROP_SHOW_ARROW:
710       g_value_set_boolean (value, priv->show_arrow);
711       break;
712     default:
713       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
714       break;
715     }
716 }
717
718 static void
719 gtk_toolbar_map (GtkWidget *widget)
720 {
721   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
722   
723   GTK_WIDGET_CLASS (parent_class)->map (widget);
724   
725   if (priv->event_window)
726     gdk_window_show_unraised (priv->event_window);
727 }
728
729 static void
730 gtk_toolbar_unmap (GtkWidget *widget)
731 {
732   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
733   
734   if (priv->event_window)
735     gdk_window_hide (priv->event_window);
736   
737   GTK_WIDGET_CLASS (parent_class)->unmap (widget);
738 }
739
740 static void
741 gtk_toolbar_realize (GtkWidget *widget)
742 {
743   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
744   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
745   
746   GdkWindowAttr attributes;
747   gint attributes_mask;
748   gint border_width;
749   
750   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
751   
752   border_width = GTK_CONTAINER (widget)->border_width;
753   
754   attributes.wclass = GDK_INPUT_ONLY;
755   attributes.window_type = GDK_WINDOW_CHILD;
756   attributes.x = widget->allocation.x + border_width;
757   attributes.y = widget->allocation.y + border_width;
758   attributes.width = widget->allocation.width - border_width * 2;
759   attributes.height = widget->allocation.height - border_width * 2;
760   attributes.event_mask = gtk_widget_get_events (widget);
761   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
762                             GDK_BUTTON_RELEASE_MASK |
763                             GDK_ENTER_NOTIFY_MASK |
764                             GDK_LEAVE_NOTIFY_MASK);
765   
766   attributes_mask = GDK_WA_X | GDK_WA_Y;
767   
768   widget->window = gtk_widget_get_parent_window (widget);
769   g_object_ref (widget->window);
770   widget->style = gtk_style_attach (widget->style, widget->window);
771   
772   priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
773                                        &attributes, attributes_mask);
774   gdk_window_set_user_data (priv->event_window, toolbar);
775 }
776
777 static void
778 gtk_toolbar_unrealize (GtkWidget *widget)
779 {
780   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
781   
782   if (priv->event_window)
783     {
784       gdk_window_set_user_data (priv->event_window, NULL);
785       gdk_window_destroy (priv->event_window);
786       priv->event_window = NULL;
787     }
788   
789   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
790     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
791 }
792
793 static gint
794 gtk_toolbar_expose (GtkWidget      *widget,
795                     GdkEventExpose *event)
796 {
797   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
798   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
799   
800   GList *list;
801   gint border_width;
802   
803   border_width = GTK_CONTAINER (widget)->border_width;
804   
805   if (GTK_WIDGET_DRAWABLE (widget))
806     {
807       gtk_paint_box (widget->style,
808                      widget->window,
809                      GTK_WIDGET_STATE (widget),
810                      get_shadow_type (toolbar),
811                      &event->area, widget, "toolbar",
812                      border_width + widget->allocation.x,
813                      border_width + widget->allocation.y,
814                      widget->allocation.width - 2 * border_width,
815                      widget->allocation.height - 2 * border_width);
816     }
817   
818   for (list = priv->content; list != NULL; list = list->next)
819     {
820       ToolbarContent *content = list->data;
821       
822       toolbar_content_expose (content, GTK_CONTAINER (widget), event);
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_front_size;
846   gint ipadding;
847   GtkRequisition arrow_requisition;
848   
849   max_homogeneous_child_width = 0;
850   max_homogeneous_child_height = 0;
851   max_child_width = 0;
852   max_child_height = 0;
853   for (list = priv->content; list != NULL; list = list->next)
854     {
855       GtkRequisition requisition;
856       ToolbarContent *content = list->data;
857       
858       if (!toolbar_content_visible (content, toolbar))
859         continue;
860       
861       toolbar_content_size_request (content, toolbar, &requisition);
862
863       max_child_width = MAX (max_child_width, requisition.width);
864       max_child_height = MAX (max_child_height, requisition.height);
865       
866       if (toolbar_content_is_homogeneous (content, toolbar))
867         {
868           max_homogeneous_child_width = MAX (max_homogeneous_child_width, requisition.width);
869           max_homogeneous_child_height = MAX (max_homogeneous_child_height, requisition.height);
870         }
871     }
872   
873   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
874     homogeneous_size = max_homogeneous_child_width;
875   else
876     homogeneous_size = max_homogeneous_child_height;
877   
878   pack_front_size = 0;
879   for (list = priv->content; list != NULL; list = list->next)
880     {
881       ToolbarContent *content = list->data;
882       guint size;
883       
884       if (!toolbar_content_visible (content, toolbar))
885         continue;
886
887       if (toolbar_content_is_homogeneous (content, toolbar))
888         {
889           size = homogeneous_size;
890         }
891       else
892         {
893           GtkRequisition requisition;
894           
895           toolbar_content_size_request (content, toolbar, &requisition);
896           
897           if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
898             size = requisition.width;
899           else
900             size = requisition.height;
901         }
902
903       pack_front_size += size;
904     }
905   
906   if (priv->show_arrow && priv->api_mode == NEW_API)
907     {
908       gtk_widget_size_request (priv->arrow_button, &arrow_requisition);
909       
910       if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
911         long_req = arrow_requisition.width;
912       else
913         long_req = arrow_requisition.height;
914       
915       /* There is no point requesting space for the arrow if that would take
916        * up more space than all the items combined
917        */
918       long_req = MIN (long_req, pack_front_size);
919     }
920   else
921     {
922       arrow_requisition.height = 0;
923       arrow_requisition.width = 0;
924       
925       long_req = pack_front_size;
926     }
927   
928   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
929     {
930       requisition->width = long_req;
931       requisition->height = MAX (max_child_height, arrow_requisition.height);
932     }
933   else
934     {
935       requisition->height = long_req;
936       requisition->width = MAX (max_child_width, arrow_requisition.width);
937     }
938   
939   /* Extra spacing */
940   ipadding = get_internal_padding (toolbar);
941   
942   requisition->width += 2 * (ipadding + GTK_CONTAINER (toolbar)->border_width);
943   requisition->height += 2 * (ipadding + GTK_CONTAINER (toolbar)->border_width);
944   
945   if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
946     {
947       requisition->width += 2 * widget->style->xthickness;
948       requisition->height += 2 * widget->style->ythickness;
949     }
950   
951   toolbar->button_maxw = max_homogeneous_child_width;
952   toolbar->button_maxh = max_homogeneous_child_height;
953 }
954
955 static gint
956 position (gint from, gint to, gdouble elapsed)
957 {
958   if (to > from)
959     return MIN (from + SLIDE_SPEED * elapsed, to);
960   else
961     return MAX (from - SLIDE_SPEED * elapsed, to);
962 }
963
964 static void
965 compute_intermediate_allocation (GtkToolbar          *toolbar,
966                                  const GtkAllocation *start,
967                                  const GtkAllocation *goal,
968                                  GtkAllocation       *intermediate)
969 {
970   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
971   gdouble elapsed = g_timer_elapsed (priv->timer, NULL);
972   
973   intermediate->x = position (start->x, goal->x, elapsed);
974   intermediate->y = position (start->y, goal->y, elapsed);
975   intermediate->width =
976     position (start->x + start->width, goal->x + goal->width, elapsed) - intermediate->x;
977   intermediate->height =
978     position (start->y + start->height, goal->y + goal->height, elapsed) - intermediate->y;
979 }
980
981 static void
982 fixup_allocation_for_rtl (gint           total_size,
983                           GtkAllocation *allocation)
984 {
985   allocation->x += (total_size - (2 * allocation->x + allocation->width));
986 }
987
988 static void
989 fixup_allocation_for_vertical (GtkAllocation *allocation)
990 {
991   gint tmp;
992   
993   tmp = allocation->x;
994   allocation->x = allocation->y;
995   allocation->y = tmp;
996   
997   tmp = allocation->width;
998   allocation->width = allocation->height;
999   allocation->height = tmp;
1000 }
1001
1002 static gint
1003 get_item_size (GtkToolbar     *toolbar,
1004                ToolbarContent *content)
1005 {
1006   GtkRequisition requisition;
1007   
1008   toolbar_content_size_request (content, toolbar, &requisition);
1009   
1010   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
1011     {
1012       if (toolbar_content_is_homogeneous (content, toolbar))
1013         return toolbar->button_maxw;
1014       else
1015         return requisition.width;
1016     }
1017   else
1018     {
1019       if (toolbar_content_is_homogeneous (content, toolbar))
1020         return toolbar->button_maxh;
1021       else
1022         return requisition.height;
1023     }
1024 }
1025
1026 static gboolean
1027 slide_idle_handler (gpointer data)
1028 {
1029   GtkToolbar *toolbar = data;
1030   GtkToolbarPrivate *priv;
1031   GList *list;
1032   
1033   GDK_THREADS_ENTER ();
1034   
1035   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1036   
1037   if (priv->need_sync)
1038     {
1039       gdk_flush ();
1040       priv->need_sync = FALSE;
1041     }
1042   
1043   for (list = priv->content; list != NULL; list = list->next)
1044     {
1045       ToolbarContent *content = list->data;
1046       ItemState state;
1047       GtkAllocation goal_allocation;
1048       GtkAllocation allocation;
1049       gboolean cont;
1050       gboolean disappearing_placeholder;
1051
1052       state = toolbar_content_get_state (content);
1053       toolbar_content_get_goal_allocation (content, &goal_allocation);
1054       toolbar_content_get_allocation (content, &allocation);
1055       
1056       cont = FALSE;
1057       
1058       if (state == NOT_ALLOCATED)
1059         {
1060           /* an unallocated item means that size allocate has to
1061            * called at least once more
1062            */
1063           cont = TRUE;
1064         }
1065
1066       disappearing_placeholder =
1067         toolbar_content_is_placeholder (content) &&
1068         toolbar_content_disappearing (content);
1069       
1070       /* An invisible item with a goal allocation of
1071        * 0 is already at its goal.
1072        */
1073       if ((state == NORMAL || state == OVERFLOWN) &&
1074           ((goal_allocation.width != 0 &&
1075             goal_allocation.height != 0) ||
1076            toolbar_content_child_visible (content)))
1077         {
1078           if ((goal_allocation.x != allocation.x ||
1079                goal_allocation.y != allocation.y ||
1080                goal_allocation.width != allocation.width ||
1081                goal_allocation.height != allocation.height))
1082             {
1083               /* An item is simply not in its right position yet. Note
1084                * that OVERFLOWN items still get an allocation in
1085                * gtk_toolbar_size_allocate(). This way you can see
1086                * them slide in when you drag out of the toolbar
1087                */
1088               cont = TRUE;
1089             }
1090         }
1091
1092       if (disappearing_placeholder && toolbar_content_child_visible (content))
1093         cont = TRUE;
1094
1095       if (cont)
1096         {
1097           gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1098           
1099           GDK_THREADS_LEAVE ();
1100           return TRUE;
1101         }
1102     }
1103   
1104   priv->is_sliding = FALSE;
1105   priv->idle_id = 0;
1106
1107   GDK_THREADS_LEAVE();
1108   return FALSE;
1109 }
1110
1111 static gboolean
1112 rect_within (GtkAllocation *a1, GtkAllocation *a2)
1113 {
1114   return (a1->x >= a2->x                         &&
1115           a1->x + a1->width <= a2->x + a2->width &&
1116           a1->y >= a2->y                         &&
1117           a1->y + a1->height <= a2->y + a2->height);
1118 }
1119
1120 static void
1121 gtk_toolbar_begin_sliding (GtkToolbar *toolbar)
1122 {
1123   GtkWidget *widget = GTK_WIDGET (toolbar);
1124   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1125   GList *list;
1126   gint cur_x;
1127   gint cur_y;
1128   gint border_width;
1129   gboolean rtl;
1130   gboolean vertical;
1131   
1132   /* Start the sliding. This function copies the allocation of every
1133    * item into content->start_allocation. For items that haven't
1134    * been allocated yet, we calculate their position and save that
1135    * in start_allocatino along with zero width and zero height.
1136    */
1137   priv->is_sliding = TRUE;
1138   
1139   if (!priv->idle_id)
1140     priv->idle_id = g_idle_add (slide_idle_handler, toolbar);
1141   
1142   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1143   vertical = (toolbar->orientation == GTK_ORIENTATION_VERTICAL);
1144   border_width = get_internal_padding (toolbar) + GTK_CONTAINER (toolbar)->border_width;
1145   
1146   if (rtl)
1147     {
1148       cur_x = widget->allocation.width - border_width - widget->style->xthickness;
1149       cur_y = widget->allocation.height - border_width - widget->style->ythickness;
1150     }
1151   else
1152     {
1153       cur_x = border_width + widget->style->xthickness;
1154       cur_y = border_width + widget->style->ythickness;
1155     }
1156   
1157   cur_x += widget->allocation.x;
1158   cur_y += widget->allocation.y;
1159   
1160   for (list = priv->content; list != NULL; list = list->next)
1161     {
1162       ToolbarContent *content = list->data;
1163       GtkAllocation new_start_allocation;
1164       ItemState state;
1165       GtkAllocation item_allocation;
1166       
1167       state = toolbar_content_get_state (content);
1168       toolbar_content_get_allocation (content, &item_allocation);
1169       
1170       if ((state == NORMAL &&
1171            rect_within (&item_allocation, &(widget->allocation))) ||
1172           state == OVERFLOWN)
1173         {
1174           new_start_allocation = item_allocation;
1175         }
1176       else
1177         {
1178           new_start_allocation.x = cur_x;
1179           new_start_allocation.y = cur_y;
1180           
1181           if (vertical)
1182             {
1183               new_start_allocation.width = widget->allocation.width -
1184                 2 * border_width - 2 * widget->style->xthickness;
1185               new_start_allocation.height = 0;
1186             }
1187           else
1188             {
1189               new_start_allocation.width = 0;
1190               new_start_allocation.height = widget->allocation.height -
1191                 2 * border_width - 2 * widget->style->ythickness;
1192             }
1193         }
1194       
1195       if (vertical)
1196         cur_y = new_start_allocation.y + new_start_allocation.height;
1197       else if (rtl)
1198         cur_x = new_start_allocation.x;
1199       else
1200         cur_x = new_start_allocation.x + new_start_allocation.width;
1201       
1202       toolbar_content_set_start_allocation (content, &new_start_allocation);
1203     }
1204
1205   /* This resize will run before the first idle handler. This
1206    * will make sure that items get the right goal allocatiuon
1207    * so that the idle handler will not immediately return
1208    * FALSE
1209    */
1210   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1211   g_timer_reset (priv->timer);
1212 }
1213
1214 static void
1215 gtk_toolbar_stop_sliding (GtkToolbar *toolbar)
1216 {
1217   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1218   
1219   if (priv->is_sliding)
1220     {
1221       GList *list;
1222       
1223       priv->is_sliding = FALSE;
1224       
1225       if (priv->idle_id)
1226         {
1227           g_source_remove (priv->idle_id);
1228           priv->idle_id = 0;
1229         }
1230       
1231       list = priv->content;
1232       while (list)
1233         {
1234           ToolbarContent *content = list->data;
1235           list = list->next;
1236
1237           if (toolbar_content_is_placeholder (content))
1238             {
1239               toolbar_content_remove (content, toolbar);
1240               toolbar_content_free (content);
1241             }
1242         }
1243       
1244       gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1245     }
1246 }
1247
1248 static void
1249 gtk_toolbar_size_allocate (GtkWidget     *widget,
1250                            GtkAllocation *allocation)
1251 {
1252   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1253   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1254   GtkAllocation *allocations;
1255   ItemState *new_states;
1256   GtkAllocation arrow_allocation;
1257   gint arrow_size;
1258   gint size, pos, short_size;
1259   GList *list;
1260   gint i;
1261   gboolean need_arrow;
1262   gint n_expand_items;
1263   gint border_width;
1264   gint available_size;
1265   gint n_items;
1266   gint needed_size;
1267   GtkRequisition arrow_requisition;
1268   gboolean overflowing;
1269   gboolean size_changed;
1270   gdouble elapsed;
1271   GtkAllocation item_area;
1272   
1273   size_changed = FALSE;
1274   if (widget->allocation.x != allocation->x             ||
1275       widget->allocation.y != allocation->y             ||
1276       widget->allocation.width != allocation->width     ||
1277       widget->allocation.height != allocation->height)
1278     {
1279       size_changed = TRUE;
1280     }
1281   
1282   if (size_changed)
1283     gtk_toolbar_stop_sliding (toolbar);
1284   
1285   widget->allocation = *allocation;
1286   
1287   border_width = GTK_CONTAINER (toolbar)->border_width;
1288   
1289   if (GTK_WIDGET_REALIZED (widget))
1290     {
1291       gdk_window_move_resize (priv->event_window,
1292                               allocation->x + border_width,
1293                               allocation->y + border_width,
1294                               allocation->width - border_width * 2,
1295                               allocation->height - border_width * 2);
1296     }
1297   
1298   border_width += get_internal_padding (toolbar);
1299   
1300   gtk_widget_get_child_requisition (GTK_WIDGET (priv->arrow_button),
1301                                     &arrow_requisition);
1302   
1303   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
1304     {
1305       available_size = size = allocation->width - 2 * border_width;
1306       short_size = allocation->height - 2 * border_width;
1307       arrow_size = arrow_requisition.width;
1308       
1309       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1310         {
1311           available_size -= 2 * widget->style->xthickness;
1312           short_size -= 2 * widget->style->ythickness;
1313         }
1314     }
1315   else
1316     {
1317       available_size = size = allocation->height - 2 * border_width;
1318       short_size = allocation->width - 2 * border_width;
1319       arrow_size = arrow_requisition.height;
1320       
1321       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1322         {
1323           available_size -= 2 * widget->style->ythickness;
1324           short_size -= 2 * widget->style->xthickness;
1325         }
1326     }
1327   
1328   n_items = g_list_length (priv->content);
1329   allocations = g_new0 (GtkAllocation, n_items);
1330   new_states = g_new0 (ItemState, n_items);
1331   
1332   needed_size = 0;
1333   for (list = priv->content; list != NULL; list = list->next)
1334     {
1335       ToolbarContent *content = list->data;
1336       
1337       if (toolbar_content_visible (content, toolbar))
1338         needed_size += get_item_size (toolbar, content);
1339     }
1340   
1341   need_arrow = (needed_size > available_size) && priv->show_arrow && priv->api_mode == NEW_API;
1342   
1343   if (need_arrow)
1344     size = available_size - arrow_size;
1345   else
1346     size = available_size;
1347   
1348   /* calculate widths of items */
1349   overflowing = FALSE;
1350   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1351     {
1352       ToolbarContent *content = list->data;
1353       gint item_size;
1354       
1355       if (!toolbar_content_visible (content, toolbar))
1356         {
1357           new_states[i] = HIDDEN;
1358           continue;
1359         }
1360       
1361       item_size = get_item_size (toolbar, content);
1362       if (item_size <= size && !overflowing)
1363         {
1364           size -= item_size;
1365           allocations[i].width = item_size;
1366           new_states[i] = NORMAL;
1367         }
1368       else
1369         {
1370           overflowing = TRUE;
1371           new_states[i] = OVERFLOWN;
1372           allocations[i].width = item_size;
1373         }
1374     }
1375   
1376   /* calculate width of arrow */  
1377   if (need_arrow)
1378     {
1379       arrow_allocation.width = arrow_size;
1380       arrow_allocation.height = short_size;
1381     }
1382   
1383   /* expand expandable items */
1384   
1385   /* We don't expand when there is an overflow menu, because that leads to
1386    * weird jumps when items get moved to the overflow menu and the expanding
1387    * items suddenly get a lot of extra space
1388    */
1389   if (!overflowing)
1390     {
1391       n_expand_items = 0;
1392       for (i = 0, list = priv->content; list != NULL; list = list->next, ++i)
1393         {
1394           ToolbarContent *content = list->data;
1395           
1396           if (toolbar_content_get_expand (content) && new_states[i] == NORMAL)
1397             n_expand_items++;
1398         }
1399       
1400       for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1401         {
1402           ToolbarContent *content = list->data;
1403           
1404           if (toolbar_content_get_expand (content) && new_states[i] == NORMAL)
1405             {
1406               gint extra = size / n_expand_items;
1407               if (size % n_expand_items != 0)
1408                 extra++;
1409               
1410               allocations[i].width += extra;
1411               size -= extra;
1412               n_expand_items--;
1413             }
1414         }
1415       
1416       g_assert (n_expand_items == 0);
1417     }
1418   
1419   /* position items */
1420   pos = border_width;
1421   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1422     {
1423       /* both NORMAL and OVERFLOWN items get a position. This ensures
1424        * that sliding will work for OVERFLOWN items too
1425        */
1426       if (new_states[i] == NORMAL ||
1427           new_states[i] == OVERFLOWN)
1428         {
1429           allocations[i].x = pos;
1430           allocations[i].y = border_width;
1431           allocations[i].height = short_size;
1432           
1433           pos += allocations[i].width;
1434         }
1435     }
1436   
1437   /* position arrow */
1438   if (need_arrow)
1439     {
1440       arrow_allocation.x = available_size - border_width - arrow_allocation.width;
1441       arrow_allocation.y = border_width;
1442     }
1443   
1444   item_area.x = 0;
1445   item_area.y = 0;
1446   item_area.width = available_size - (need_arrow? arrow_size : 0);
1447   item_area.height = short_size;
1448
1449   /* fix up allocations in the vertical or RTL cases */
1450   if (toolbar->orientation == GTK_ORIENTATION_VERTICAL)
1451     {
1452       for (i = 0; i < n_items; ++i)
1453         fixup_allocation_for_vertical (&(allocations[i]));
1454       
1455       if (need_arrow)
1456         fixup_allocation_for_vertical (&arrow_allocation);
1457
1458       fixup_allocation_for_vertical (&item_area);
1459     }
1460   else if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1461     {
1462       for (i = 0; i < n_items; ++i)
1463         fixup_allocation_for_rtl (available_size, &(allocations[i]));
1464       
1465       if (need_arrow)
1466         fixup_allocation_for_rtl (available_size, &arrow_allocation);
1467
1468       fixup_allocation_for_rtl (allocation->width, &item_area);
1469     }
1470   
1471   /* translate the items by allocation->(x,y) */
1472   for (i = 0; i < n_items; ++i)
1473     {
1474       allocations[i].x += allocation->x;
1475       allocations[i].y += allocation->y;
1476       
1477       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1478         {
1479           allocations[i].x += widget->style->xthickness;
1480           allocations[i].y += widget->style->ythickness;
1481         }
1482     }
1483   
1484   if (need_arrow)
1485     {
1486       arrow_allocation.x += allocation->x;
1487       arrow_allocation.y += allocation->y;
1488       
1489       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1490         {
1491           arrow_allocation.x += widget->style->xthickness;
1492           arrow_allocation.y += widget->style->ythickness;
1493         }
1494     }
1495
1496   item_area.x += allocation->x;
1497   item_area.y += allocation->y;
1498   if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1499     {
1500       item_area.x += widget->style->xthickness;
1501       item_area.y += widget->style->ythickness;
1502     }
1503
1504   /* did anything change? */
1505   for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1506     {
1507       ToolbarContent *content = list->data;
1508       
1509       if (toolbar_content_get_state (content) == NORMAL &&
1510           new_states[i] != NORMAL)
1511         {
1512           /* an item disappeared, begin sliding */
1513           if (!size_changed)
1514             gtk_toolbar_begin_sliding (toolbar);
1515         }
1516     }
1517   
1518   /* finally allocate the items */
1519   if (priv->is_sliding)
1520     {
1521       for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1522         {
1523           ToolbarContent *content = list->data;
1524           
1525           toolbar_content_set_goal_allocation (content, &(allocations[i]));
1526         }
1527     }
1528
1529   elapsed = g_timer_elapsed (priv->timer, NULL);
1530   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1531     {
1532       ToolbarContent *content = list->data;
1533
1534       if (new_states[i] == OVERFLOWN ||
1535           new_states[i] == NORMAL)
1536         {
1537           GtkAllocation alloc;
1538           GtkAllocation start_allocation;
1539           GtkAllocation goal_allocation;
1540
1541           if (priv->is_sliding)
1542             {
1543               toolbar_content_get_start_allocation (content, &start_allocation);
1544               toolbar_content_get_goal_allocation (content, &goal_allocation);
1545               
1546               compute_intermediate_allocation (toolbar,
1547                                                &start_allocation,
1548                                                &goal_allocation,
1549                                                &alloc);
1550
1551               priv->need_sync = TRUE;
1552             }
1553           else
1554             {
1555               alloc = allocations[i];
1556             }
1557
1558           if (alloc.width == 0 || alloc.height == 0)
1559             {
1560               toolbar_content_set_child_visible (content, toolbar, FALSE);
1561             }
1562           else
1563             {
1564               if (!rect_within (&alloc, &item_area))
1565                 {
1566                   toolbar_content_set_child_visible (content, toolbar, FALSE);
1567                   toolbar_content_size_allocate (content, &alloc);
1568                 }
1569               else
1570                 {
1571                   toolbar_content_set_child_visible (content, toolbar, TRUE);
1572                   toolbar_content_size_allocate (content, &alloc);
1573                 }
1574             }
1575         }
1576       else
1577         {
1578           toolbar_content_set_child_visible (content, toolbar, FALSE);
1579         }
1580           
1581       toolbar_content_set_state (content, new_states[i]);
1582     }
1583   
1584   if (need_arrow)
1585     {
1586       gtk_widget_size_allocate (GTK_WIDGET (priv->arrow_button),
1587                                 &arrow_allocation);
1588       gtk_widget_show (GTK_WIDGET (priv->arrow_button));
1589     }
1590   else
1591     {
1592       gtk_widget_hide (GTK_WIDGET (priv->arrow_button));
1593     }
1594   
1595   g_free (allocations);
1596   g_free (new_states);
1597 }
1598
1599 static void
1600 gtk_toolbar_update_button_relief (GtkToolbar *toolbar)
1601 {
1602   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1603   
1604   gtk_toolbar_reconfigured (toolbar);
1605   
1606   gtk_button_set_relief (GTK_BUTTON (priv->arrow_button), get_button_relief (toolbar));
1607 }
1608
1609 static void
1610 gtk_toolbar_style_set (GtkWidget *widget,
1611                        GtkStyle  *prev_style)
1612 {
1613   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
1614   
1615   priv->max_homogeneous_pixels = -1;
1616   
1617   if (GTK_WIDGET_REALIZED (widget))
1618     gtk_style_set_background (widget->style, widget->window, widget->state);
1619   
1620   if (prev_style)
1621     gtk_toolbar_update_button_relief (GTK_TOOLBAR (widget));
1622 }
1623
1624 static void 
1625 gtk_toolbar_direction_changed (GtkWidget        *widget,
1626                                GtkTextDirection  previous_dir)
1627 {
1628   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1629   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1630   
1631   if (toolbar->orientation == GTK_ORIENTATION_VERTICAL)
1632     {
1633       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1634         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
1635       else 
1636         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_LEFT, GTK_SHADOW_NONE);
1637     }
1638   
1639   GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
1640 }
1641
1642 static GList *
1643 gtk_toolbar_list_children_in_focus_order (GtkToolbar       *toolbar,
1644                                           GtkDirectionType  dir)
1645 {
1646   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1647   GList *result = NULL;
1648   GList *list;
1649   gboolean rtl;
1650   
1651   /* generate list of children in reverse logical order */
1652   
1653   for (list = priv->content; list != NULL; list = list->next)
1654     {
1655       ToolbarContent *content = list->data;
1656       GtkWidget *widget;
1657       
1658       widget = toolbar_content_get_widget (content);
1659       
1660       if (widget)
1661         result = g_list_prepend (result, widget);
1662     }
1663   
1664   result = g_list_prepend (result, priv->arrow_button);
1665   
1666   rtl = (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL);
1667   
1668   /* move in logical order when
1669    *
1670    *    - dir is TAB_FORWARD
1671    *
1672    *    - in RTL mode and moving left or up
1673    *
1674    *    - in LTR mode and moving right or down
1675    */
1676   if (dir == GTK_DIR_TAB_FORWARD                                        ||
1677       (rtl  && (dir == GTK_DIR_UP   || dir == GTK_DIR_LEFT))            ||
1678       (!rtl && (dir == GTK_DIR_DOWN || dir == GTK_DIR_RIGHT)))
1679     {
1680       result = g_list_reverse (result);
1681     }
1682   
1683   return result;
1684 }
1685
1686 static gboolean
1687 gtk_toolbar_focus_home_or_end (GtkToolbar *toolbar,
1688                                gboolean    focus_home)
1689 {
1690   GList *children, *list;
1691   GtkDirectionType dir = focus_home? GTK_DIR_RIGHT : GTK_DIR_LEFT;
1692   
1693   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1694   
1695   if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1696     {
1697       children = g_list_reverse (children);
1698       
1699       dir = (dir == GTK_DIR_RIGHT)? GTK_DIR_LEFT : GTK_DIR_RIGHT;
1700     }
1701   
1702   for (list = children; list != NULL; list = list->next)
1703     {
1704       GtkWidget *child = list->data;
1705       
1706       if (GTK_CONTAINER (toolbar)->focus_child == child)
1707         break;
1708       
1709       if (GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir))
1710         break;
1711     }
1712   
1713   g_list_free (children);
1714   
1715   return TRUE;
1716 }   
1717
1718 /* Keybinding handler. This function is called when the user presses
1719  * Ctrl TAB or an arrow key.
1720  */
1721 static gboolean
1722 gtk_toolbar_move_focus (GtkToolbar       *toolbar,
1723                         GtkDirectionType  dir)
1724 {
1725   GList *list;
1726   gboolean try_focus = FALSE;
1727   GList *children;
1728   GtkContainer *container = GTK_CONTAINER (toolbar);
1729   
1730   if (container->focus_child &&
1731       gtk_widget_child_focus (container->focus_child, dir))
1732     {
1733       return TRUE;
1734     }
1735   
1736   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1737   
1738   for (list = children; list != NULL; list = list->next)
1739     {
1740       GtkWidget *child = list->data;
1741       
1742       if (try_focus && GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir))
1743         break;
1744       
1745       if (child == GTK_CONTAINER (toolbar)->focus_child)
1746         try_focus = TRUE;
1747     }
1748   
1749   g_list_free (children);
1750   
1751   return FALSE;
1752 }
1753
1754 /* The focus handler for the toolbar. It called when the user presses
1755  * TAB or otherwise tries to focus the toolbar.
1756  */
1757 static gboolean
1758 gtk_toolbar_focus (GtkWidget        *widget,
1759                    GtkDirectionType  dir)
1760 {
1761   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1762   GList *children, *list;
1763   
1764   /* if focus is already somewhere inside the toolbar then return FALSE.
1765    * The only way focus can stay inside the toolbar is when the user presses
1766    * arrow keys or Ctrl TAB (both of which are handled by the
1767    * gtk_toolbar_move_focus() keybinding function.
1768    */
1769   if (GTK_CONTAINER (widget)->focus_child)
1770     return FALSE;
1771   
1772   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1773   
1774   for (list = children; list != NULL; list = list->next)
1775     {
1776       GtkWidget *child = list->data;
1777       
1778       if (GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir))
1779         return TRUE;
1780     }
1781   
1782   g_list_free (children);
1783   
1784   return FALSE;
1785 }
1786
1787 static void
1788 style_change_notify (GtkToolbar *toolbar)
1789 {
1790   if (!toolbar->style_set)
1791     {
1792       /* pretend it was set, then unset, thus reverting to new default */
1793       toolbar->style_set = TRUE; 
1794       gtk_toolbar_unset_style (toolbar);
1795     }
1796 }
1797
1798 static void
1799 icon_size_change_notify (GtkToolbar *toolbar)
1800
1801   if (!toolbar->icon_size_set)
1802     {
1803       /* pretend it was set, then unset, thus reverting to new default */
1804       toolbar->icon_size_set = TRUE; 
1805       gtk_toolbar_unset_icon_size (toolbar);
1806     }
1807 }
1808
1809 static GtkSettings *
1810 toolbar_get_settings (GtkToolbar *toolbar)
1811 {
1812   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1813   return priv->settings;
1814 }
1815
1816 static void
1817 gtk_toolbar_screen_changed (GtkWidget *widget,
1818                             GdkScreen *previous_screen)
1819 {
1820   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
1821   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1822   GtkSettings *old_settings = toolbar_get_settings (toolbar);
1823   GtkSettings *settings;
1824   
1825   if (gtk_widget_has_screen (GTK_WIDGET (toolbar)))
1826     settings = gtk_widget_get_settings (GTK_WIDGET (toolbar));
1827   else
1828     settings = NULL;
1829   
1830   if (settings == old_settings)
1831     return;
1832   
1833   if (old_settings)
1834     {
1835       g_signal_handler_disconnect (old_settings, toolbar->style_set_connection);
1836       g_signal_handler_disconnect (old_settings, toolbar->icon_size_connection);
1837       
1838       g_object_unref (old_settings);
1839     }
1840   
1841   if (settings)
1842     {
1843       toolbar->style_set_connection =
1844         g_signal_connect_swapped (settings,
1845                                   "notify::gtk-toolbar-style",
1846                                   G_CALLBACK (style_change_notify),
1847                                   toolbar);
1848       toolbar->icon_size_connection =
1849         g_signal_connect_swapped (settings,
1850                                   "notify::gtk-toolbar-icon-size",
1851                                   G_CALLBACK (icon_size_change_notify),
1852                                   toolbar);
1853       
1854       g_object_ref (settings);
1855       priv->settings = settings;
1856     }
1857   else
1858     priv->settings = NULL;
1859   
1860   style_change_notify (toolbar);
1861   icon_size_change_notify (toolbar);
1862 }
1863
1864 static int
1865 find_drop_index (GtkToolbar *toolbar,
1866                  gint        x,
1867                  gint        y)
1868 {
1869   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1870   GList *interesting_content;
1871   GList *list;
1872   GtkOrientation orientation;
1873   GtkTextDirection direction;
1874   gint best_distance = G_MAXINT;
1875   gint distance;
1876   gint cursor;
1877   gint pos;
1878   ToolbarContent *best_content;
1879   GtkAllocation allocation;
1880   
1881   /* list items we care about wrt. drag and drop */
1882   interesting_content = NULL;
1883   for (list = priv->content; list != NULL; list = list->next)
1884     {
1885       ToolbarContent *content = list->data;
1886       
1887       if (toolbar_content_get_state (content) == NORMAL)
1888         interesting_content = g_list_prepend (interesting_content, content);
1889     }
1890   interesting_content = g_list_reverse (interesting_content);
1891   
1892   if (!interesting_content)
1893     return 0;
1894   
1895   orientation = toolbar->orientation;
1896   direction = gtk_widget_get_direction (GTK_WIDGET (toolbar));
1897   
1898   /* distance to first interesting item */
1899   best_content = interesting_content->data;
1900   toolbar_content_get_allocation (best_content, &allocation);
1901   
1902   if (orientation == GTK_ORIENTATION_HORIZONTAL)
1903     {
1904       cursor = x;
1905       
1906       if (direction == GTK_TEXT_DIR_LTR)
1907         pos = allocation.x;
1908       else
1909         pos = allocation.x + allocation.width;
1910     }
1911   else
1912     {
1913       cursor = y;
1914       pos = allocation.y;
1915     }
1916   
1917   best_content = NULL;
1918   best_distance = ABS (pos - cursor);
1919   
1920   /* distance to far end of each item */
1921   for (list = interesting_content; list != NULL; list = list->next)
1922     {
1923       ToolbarContent *content = list->data;
1924       
1925       toolbar_content_get_allocation (content, &allocation);
1926       
1927       if (orientation == GTK_ORIENTATION_HORIZONTAL)
1928         {
1929           if (direction == GTK_TEXT_DIR_LTR)
1930             pos = allocation.x + allocation.width;
1931           else
1932             pos = allocation.x;
1933         }
1934       else
1935         {
1936           pos = allocation.y + allocation.height;
1937         }
1938       
1939       distance = ABS (pos - cursor);
1940       
1941       if (distance < best_distance)
1942         {
1943           best_distance = distance;
1944           best_content = content;
1945         }
1946     }
1947   
1948   g_list_free (interesting_content);
1949   
1950   if (!best_content)
1951     return 0;
1952   else
1953     return g_list_index (priv->content, best_content) + 1;
1954 }
1955
1956 static void
1957 reset_all_placeholders (GtkToolbar *toolbar)
1958 {
1959   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1960   GList *list;
1961   
1962   for (list = priv->content; list != NULL; list = list->next)
1963     {
1964       ToolbarContent *content = list->data;
1965       if (toolbar_content_is_placeholder (content))
1966         toolbar_content_set_disappearing (content, TRUE);
1967     }
1968 }
1969
1970 static gint
1971 physical_to_logical (GtkToolbar *toolbar,
1972                      gint        physical)
1973 {
1974   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1975   GList *list;
1976   int logical;
1977   
1978   g_assert (physical >= 0);
1979   
1980   logical = 0;
1981   for (list = priv->content; list && physical > 0; list = list->next)
1982     {
1983       ToolbarContent *content = list->data;
1984       
1985       if (!toolbar_content_is_placeholder (content))
1986         logical++;
1987       physical--;
1988     }
1989   
1990   g_assert (physical == 0);
1991   
1992   return logical;
1993 }
1994
1995 static gint
1996 logical_to_physical (GtkToolbar *toolbar,
1997                      gint        logical)
1998 {
1999   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2000   GList *list;
2001   gint physical;
2002   
2003   g_assert (logical >= 0);
2004   
2005   physical = 0;
2006   for (list = priv->content; list; list = list->next)
2007     {
2008       ToolbarContent *content = list->data;
2009       
2010       if (!toolbar_content_is_placeholder (content))
2011         {
2012           if (logical == 0)
2013             break;
2014           logical--;
2015         }
2016       
2017       physical++;
2018     }
2019   
2020   g_assert (logical == 0);
2021   
2022   return physical;
2023 }
2024
2025 /**
2026  * gtk_toolbar_set_drop_highlight_item:
2027  * @toolbar: a #GtkToolbar
2028  * @tool_item: a #GtkToolItem, or %NULL to turn of highlighting
2029  * @index: a position on @toolbar
2030  * 
2031  * Highlights @toolbar to give an idea of what it would look like
2032  * if @item was added to @toolbar at position indicated by @index. If @item
2033  * is %NULL, highlighting is turned off. In that case @index is ignored.
2034  *
2035  * The @tool_item passed to this function must not be part of any widget
2036  * hierarchy. When an item is set as drop highlight item it can not
2037  * added to any widget hierarchy or used as highlight item for another
2038  * toolbar.
2039  * 
2040  * Since: 2.4
2041  **/
2042 void
2043 gtk_toolbar_set_drop_highlight_item (GtkToolbar  *toolbar,
2044                                      GtkToolItem *tool_item,
2045                                      gint         index)
2046 {
2047   ToolbarContent *content;
2048   GtkToolbarPrivate *priv;
2049   gint n_items;
2050   GtkRequisition requisition;
2051   
2052   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2053   g_return_if_fail (tool_item == NULL || GTK_IS_TOOL_ITEM (tool_item));
2054   
2055   gtk_toolbar_check_new_api (toolbar);
2056   
2057   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2058   
2059   if (!tool_item)
2060     {
2061       if (priv->highlight_tool_item)
2062         {
2063           gtk_widget_unparent (GTK_WIDGET (priv->highlight_tool_item));
2064           g_object_unref (priv->highlight_tool_item);
2065           priv->highlight_tool_item = NULL;
2066         }
2067       
2068       reset_all_placeholders (toolbar);
2069       gtk_toolbar_begin_sliding (toolbar);
2070       return;
2071     }
2072   
2073   if (tool_item != priv->highlight_tool_item)
2074     {
2075       if (priv->highlight_tool_item)
2076         g_object_unref (priv->highlight_tool_item);
2077       
2078       g_object_ref (tool_item);
2079       gtk_object_sink (GTK_OBJECT (tool_item));
2080       
2081       priv->highlight_tool_item = tool_item;
2082       
2083       gtk_widget_set_parent (GTK_WIDGET (priv->highlight_tool_item),
2084                              GTK_WIDGET (toolbar));
2085     }
2086   
2087   n_items = gtk_toolbar_get_n_items (toolbar);
2088   if (index < 0 || index > n_items)
2089     index = n_items;
2090   
2091   index = logical_to_physical (toolbar, index);
2092   
2093   content = g_list_nth_data (priv->content, index);
2094   
2095   if (index > 0)
2096     {
2097       ToolbarContent *prev_content;
2098       
2099       prev_content = g_list_nth_data (priv->content, index - 1);
2100       
2101       if (prev_content && toolbar_content_is_placeholder (prev_content))
2102         content = prev_content;
2103     }
2104   
2105   if (!content || !toolbar_content_is_placeholder (content))
2106     {
2107       GtkWidget *placeholder;
2108       
2109       placeholder = GTK_WIDGET (gtk_separator_tool_item_new ());
2110
2111       content = toolbar_content_new_tool_item (toolbar,
2112                                                GTK_TOOL_ITEM (placeholder),
2113                                                TRUE, index);
2114       gtk_widget_show (placeholder);
2115     }
2116   
2117   g_assert (content);
2118   g_assert (toolbar_content_is_placeholder (content));
2119   
2120   reset_all_placeholders (toolbar);
2121   
2122   toolbar_content_set_disappearing (content, FALSE);
2123   
2124   gtk_widget_size_request (GTK_WIDGET (priv->highlight_tool_item),
2125                            &requisition);
2126   
2127   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2128     requisition.height = -1;
2129   else
2130     requisition.width = -1;
2131   
2132   toolbar_content_set_size_request (content,
2133                                     requisition.width, requisition.height);
2134   
2135   gtk_toolbar_begin_sliding (toolbar);
2136 }
2137
2138 static void
2139 gtk_toolbar_get_child_property (GtkContainer *container,
2140                                 GtkWidget    *child,
2141                                 guint         property_id,
2142                                 GValue       *value,
2143                                 GParamSpec   *pspec)
2144 {
2145   GtkToolItem *item = GTK_TOOL_ITEM (child);
2146   
2147   switch (property_id)
2148     {
2149     case CHILD_PROP_HOMOGENEOUS:
2150       g_value_set_boolean (value, gtk_tool_item_get_homogeneous (item));
2151       break;
2152       
2153     case CHILD_PROP_EXPAND:
2154       g_value_set_boolean (value, gtk_tool_item_get_expand (item));
2155       break;
2156       
2157     default:
2158       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2159       break;
2160     }
2161 }
2162
2163 static void
2164 gtk_toolbar_set_child_property (GtkContainer *container,
2165                                 GtkWidget    *child,
2166                                 guint         property_id,
2167                                 const GValue *value,
2168                                 GParamSpec   *pspec)
2169 {
2170   switch (property_id)
2171     {
2172     case CHILD_PROP_HOMOGENEOUS:
2173       gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2174       break;
2175       
2176     case CHILD_PROP_EXPAND:
2177       gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2178       break;
2179       
2180     default:
2181       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2182       break;
2183     }
2184 }
2185
2186 static void
2187 gtk_toolbar_show_all (GtkWidget *widget)
2188 {
2189   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
2190   GList *list;
2191
2192   for (list = priv->content; list != NULL; list = list->next)
2193     {
2194       ToolbarContent *content = list->data;
2195       
2196       toolbar_content_show_all (content);
2197     }
2198   
2199   gtk_widget_show (widget);
2200 }
2201
2202 static void
2203 gtk_toolbar_hide_all (GtkWidget *widget)
2204 {
2205   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
2206   GList *list;
2207
2208   for (list = priv->content; list != NULL; list = list->next)
2209     {
2210       ToolbarContent *content = list->data;
2211       
2212       toolbar_content_hide_all (content);
2213     }
2214
2215   gtk_widget_hide (widget);
2216 }
2217
2218 static void
2219 gtk_toolbar_add (GtkContainer *container,
2220                  GtkWidget    *widget)
2221 {
2222   GtkToolbar *toolbar;
2223   
2224   g_return_if_fail (GTK_IS_TOOLBAR (container));
2225   g_return_if_fail (widget != NULL);
2226   
2227   toolbar = GTK_TOOLBAR (container);
2228   
2229   if (GTK_IS_TOOL_ITEM (widget))
2230     gtk_toolbar_insert (toolbar, GTK_TOOL_ITEM (widget), -1);
2231   else
2232     gtk_toolbar_append_widget (toolbar, widget, NULL, NULL);
2233 }
2234
2235 static void
2236 gtk_toolbar_remove (GtkContainer *container,
2237                     GtkWidget    *widget)
2238 {
2239   GtkToolbar *toolbar;
2240   GtkToolbarPrivate *priv;
2241   ToolbarContent *content_to_remove;
2242   GList *list;
2243   
2244   g_return_if_fail (GTK_IS_TOOLBAR (container));
2245   g_return_if_fail (GTK_IS_WIDGET (widget));
2246   
2247   toolbar = GTK_TOOLBAR (container);
2248   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2249   
2250   content_to_remove = NULL;
2251   for (list = priv->content; list != NULL; list = list->next)
2252     {
2253       ToolbarContent *content = list->data;
2254       GtkWidget *child;
2255       
2256       child = toolbar_content_get_widget (content);
2257       if (child && child == widget)
2258         {
2259           content_to_remove = content;
2260           break;
2261         }
2262     }
2263   
2264   g_return_if_fail (content_to_remove != NULL);
2265   
2266   toolbar_content_remove (content_to_remove, toolbar);
2267   toolbar_content_free (content_to_remove);
2268 }
2269
2270 static void
2271 gtk_toolbar_forall (GtkContainer *container,
2272                     gboolean      include_internals,
2273                     GtkCallback   callback,
2274                     gpointer      callback_data)
2275 {
2276   GtkToolbar *toolbar = GTK_TOOLBAR (container);
2277   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2278   GList *list;
2279   
2280   g_return_if_fail (callback != NULL);
2281   
2282   list = priv->content;
2283   while (list)
2284     {
2285       ToolbarContent *content = list->data;
2286       GList *next = list->next;
2287       
2288       if (include_internals || !toolbar_content_is_placeholder (content))
2289         {
2290           GtkWidget *child = toolbar_content_get_widget (content);
2291           
2292           if (child)
2293             (*callback) (child, callback_data);
2294         }
2295       
2296       list = next;
2297     }
2298   
2299   if (include_internals)
2300     (* callback) (priv->arrow_button, callback_data);
2301 }
2302
2303 static GType
2304 gtk_toolbar_child_type (GtkContainer *container)
2305 {
2306   return GTK_TYPE_TOOL_ITEM;
2307 }
2308
2309 static void
2310 gtk_toolbar_reconfigured (GtkToolbar *toolbar)
2311 {
2312   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2313   GList *list;
2314   
2315   list = priv->content;
2316   while (list)
2317     {
2318       ToolbarContent *content = list->data;
2319       GList *next = list->next;
2320       
2321       toolbar_content_toolbar_reconfigured (content, toolbar);
2322       
2323       list = next;
2324     }
2325 }
2326
2327 static void
2328 gtk_toolbar_orientation_changed (GtkToolbar    *toolbar,
2329                                  GtkOrientation orientation)
2330 {
2331   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2332   if (toolbar->orientation != orientation)
2333     {
2334       toolbar->orientation = orientation;
2335       
2336       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2337         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
2338       else if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR)
2339         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
2340       else 
2341         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_LEFT, GTK_SHADOW_NONE);
2342       
2343       gtk_toolbar_reconfigured (toolbar);
2344       
2345       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2346       g_object_notify (G_OBJECT (toolbar), "orientation");
2347     }
2348 }
2349
2350 static void
2351 gtk_toolbar_real_style_changed (GtkToolbar     *toolbar,
2352                                 GtkToolbarStyle style)
2353 {
2354   if (toolbar->style != style)
2355     {
2356       toolbar->style = style;
2357       
2358       gtk_toolbar_reconfigured (toolbar);
2359       
2360       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2361       g_object_notify (G_OBJECT (toolbar), "toolbar_style");
2362     }
2363 }
2364
2365 static void
2366 menu_position_func (GtkMenu  *menu,
2367                     gint     *x,
2368                     gint     *y,
2369                     gboolean *push_in,
2370                     gpointer  user_data)
2371 {
2372   GtkToolbar *toolbar = GTK_TOOLBAR (user_data);
2373   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2374   GtkRequisition req;
2375   GtkRequisition menu_req;
2376   
2377   gdk_window_get_origin (GTK_BUTTON (priv->arrow_button)->event_window, x, y);
2378   gtk_widget_size_request (priv->arrow_button, &req);
2379   gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
2380   
2381   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2382     {
2383       *y += priv->arrow_button->allocation.height;
2384       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2385         *x += priv->arrow_button->allocation.width - req.width;
2386       else 
2387         *x += req.width - menu_req.width;
2388     }
2389   else 
2390     {
2391       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2392         *x += priv->arrow_button->allocation.width;
2393       else 
2394         *x -= menu_req.width;
2395       *y += priv->arrow_button->allocation.height - req.height;      
2396     }
2397   
2398   *push_in = TRUE;
2399 }
2400
2401 static void
2402 menu_deactivated (GtkWidget  *menu,
2403                   GtkToolbar *toolbar)
2404 {
2405   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2406   
2407   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->arrow_button), FALSE);
2408 }
2409
2410 static void
2411 remove_item (GtkWidget *menu_item,
2412              gpointer   data)
2413 {
2414   gtk_container_remove (GTK_CONTAINER (menu_item->parent), menu_item);
2415 }
2416
2417 static void
2418 show_menu (GtkToolbar     *toolbar,
2419            GdkEventButton *event)
2420 {
2421   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2422   GList *list;
2423   
2424   if (priv->menu)
2425     {
2426       gtk_container_foreach (GTK_CONTAINER (priv->menu), remove_item, NULL);
2427       gtk_widget_destroy (GTK_WIDGET (priv->menu));
2428     }
2429   
2430   priv->menu = GTK_MENU (gtk_menu_new ());
2431   g_signal_connect (priv->menu, "deactivate", G_CALLBACK (menu_deactivated), toolbar);
2432   
2433   for (list = priv->content; list != NULL; list = list->next)
2434     {
2435       ToolbarContent *content = list->data;
2436       
2437       if (toolbar_content_get_state (content) == OVERFLOWN &&
2438           !toolbar_content_is_placeholder (content))
2439         {
2440           GtkWidget *menu_item = toolbar_content_retrieve_menu_item (content);
2441           
2442           if (menu_item)
2443             {
2444               g_assert (GTK_IS_MENU_ITEM (menu_item));
2445               gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menu_item);
2446             }
2447         }
2448     }
2449   
2450   gtk_widget_show_all (GTK_WIDGET (priv->menu));
2451   
2452   gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2453                   menu_position_func, toolbar,
2454                   event? event->button : 0, event? event->time : gtk_get_current_event_time());
2455 }
2456
2457 static void
2458 gtk_toolbar_arrow_button_clicked (GtkWidget  *button,
2459                                   GtkToolbar *toolbar)
2460 {
2461   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);  
2462   
2463   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->arrow_button)) &&
2464       (!priv->menu || !GTK_WIDGET_VISIBLE (GTK_WIDGET (priv->menu))))
2465     {
2466       /* We only get here when the button is clicked with the keybaord,
2467        * because mouse button presses result in the menu being shown so
2468        * that priv->menu would be non-NULL and visible.
2469        */
2470       show_menu (toolbar, NULL);
2471       gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2472     }
2473 }
2474
2475 static gboolean
2476 gtk_toolbar_arrow_button_press (GtkWidget      *button,
2477                                 GdkEventButton *event,
2478                                 GtkToolbar     *toolbar)
2479 {
2480   show_menu (toolbar, event);
2481   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2482   
2483   return TRUE;
2484 }
2485
2486 static gboolean
2487 gtk_toolbar_button_press (GtkWidget      *toolbar,
2488                           GdkEventButton *event)
2489 {
2490   if (event->button == 3)
2491     {
2492       gboolean return_value;
2493       
2494       g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2495                      (int)event->x_root, (int)event->y_root, event->button,
2496                      &return_value);
2497       
2498       return return_value;
2499     }
2500   
2501   return FALSE;
2502 }
2503
2504 static gboolean
2505 gtk_toolbar_popup_menu (GtkWidget *toolbar)
2506 {
2507   gboolean return_value;
2508   /* This function is the handler for the "popup menu" keybinding,
2509    * ie., it is called when the user presses Shift F10
2510    */
2511   g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2512                  -1, -1, -1, &return_value);
2513   
2514   return return_value;
2515 }
2516
2517 /**
2518  * gtk_toolbar_new:
2519  * 
2520  * Creates a new toolbar. 
2521  
2522  * Return Value: the newly-created toolbar.
2523  **/
2524 GtkWidget *
2525 gtk_toolbar_new (void)
2526 {
2527   GtkToolbar *toolbar;
2528   
2529   toolbar = g_object_new (GTK_TYPE_TOOLBAR, NULL);
2530   
2531   return GTK_WIDGET (toolbar);
2532 }
2533
2534 /**
2535  * gtk_toolbar_insert:
2536  * @toolbar: a #GtkToolbar
2537  * @item: a #GtkToolItem
2538  * @pos: the position of the new item
2539  *
2540  * Insert a #GtkToolItem into the toolbar at position @pos. If @pos is
2541  * 0 the item is prepended to the start of the toolbar. If @pos is
2542  * negative, the item is appended to the end of the toolbar.
2543  *
2544  * Since: 2.4
2545  **/
2546 void
2547 gtk_toolbar_insert (GtkToolbar  *toolbar,
2548                     GtkToolItem *item,
2549                     gint         pos)
2550 {
2551   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2552   g_return_if_fail (GTK_IS_TOOL_ITEM (item));
2553   
2554   if (!gtk_toolbar_check_new_api (toolbar))
2555     return;
2556   
2557   if (pos >= 0)
2558     pos = logical_to_physical (toolbar, pos);
2559
2560   toolbar_content_new_tool_item (toolbar, item, FALSE, pos);
2561 }
2562
2563 /**
2564  * gtk_toolbar_get_item_index:
2565  * @toolbar: a #GtkToolbar
2566  * @item: a #GtkToolItem that is a child of @toolbar
2567  * 
2568  * Returns the position of @item on the toolbar, starting from 0.
2569  * It is an error if @item is not a child of the toolbar.
2570  * 
2571  * Return value: the position of item on the toolbar.
2572  * 
2573  * Since: 2.4
2574  **/
2575 gint
2576 gtk_toolbar_get_item_index (GtkToolbar  *toolbar,
2577                             GtkToolItem *item)
2578 {
2579   GtkToolbarPrivate *priv;
2580   GList *list;
2581   int n;
2582   
2583   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2584   g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1);
2585   g_return_val_if_fail (GTK_WIDGET (item)->parent == GTK_WIDGET (toolbar), -1);
2586   
2587   if (!gtk_toolbar_check_new_api (toolbar))
2588     return -1;
2589   
2590   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2591   
2592   n = 0;
2593   for (list = priv->content; list != NULL; list = list->next)
2594     {
2595       ToolbarContent *content = list->data;
2596       GtkWidget *widget;
2597       
2598       widget = toolbar_content_get_widget (content);
2599       
2600       if (item == GTK_TOOL_ITEM (widget))
2601         break;
2602       
2603       ++n;
2604     }
2605   
2606   return physical_to_logical (toolbar, n);
2607 }
2608
2609 /**
2610  * gtk_toolbar_set_orientation:
2611  * @toolbar: a #GtkToolbar.
2612  * @orientation: a new #GtkOrientation.
2613  * 
2614  * Sets whether a toolbar should appear horizontally or vertically.
2615  **/
2616 void
2617 gtk_toolbar_set_orientation (GtkToolbar     *toolbar,
2618                              GtkOrientation  orientation)
2619 {
2620   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2621   
2622   g_signal_emit (toolbar, toolbar_signals[ORIENTATION_CHANGED], 0, orientation);
2623 }
2624
2625 /**
2626  * gtk_toolbar_get_orientation:
2627  * @toolbar: a #GtkToolbar
2628  * 
2629  * Retrieves the current orientation of the toolbar. See
2630  * gtk_toolbar_set_orientation().
2631  *
2632  * Return value: the orientation
2633  **/
2634 GtkOrientation
2635 gtk_toolbar_get_orientation (GtkToolbar *toolbar)
2636 {
2637   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL);
2638   
2639   return toolbar->orientation;
2640 }
2641
2642 /**
2643  * gtk_toolbar_set_style:
2644  * @toolbar: a #GtkToolbar.
2645  * @style: the new style for @toolbar.
2646  * 
2647  * Alters the view of @toolbar to display either icons only, text only, or both.
2648  **/
2649 void
2650 gtk_toolbar_set_style (GtkToolbar      *toolbar,
2651                        GtkToolbarStyle  style)
2652 {
2653   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2654   
2655   toolbar->style_set = TRUE;  
2656   g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2657 }
2658
2659 /**
2660  * gtk_toolbar_get_style:
2661  * @toolbar: a #GtkToolbar
2662  *
2663  * Retrieves whether the toolbar has text, icons, or both . See
2664  * gtk_toolbar_set_style().
2665  
2666  * Return value: the current style of @toolbar
2667  **/
2668 GtkToolbarStyle
2669 gtk_toolbar_get_style (GtkToolbar *toolbar)
2670 {
2671   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE);
2672   
2673   return toolbar->style;
2674 }
2675
2676 /**
2677  * gtk_toolbar_unset_style:
2678  * @toolbar: a #GtkToolbar
2679  * 
2680  * Unsets a toolbar style set with gtk_toolbar_set_style(), so that
2681  * user preferences will be used to determine the toolbar style.
2682  **/
2683 void
2684 gtk_toolbar_unset_style (GtkToolbar *toolbar)
2685 {
2686   GtkToolbarStyle style;
2687   
2688   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2689   
2690   if (toolbar->style_set)
2691     {
2692       GtkSettings *settings = toolbar_get_settings (toolbar);
2693       
2694       if (settings)
2695         g_object_get (settings,
2696                       "gtk-toolbar-style", &style,
2697                       NULL);
2698       else
2699         style = DEFAULT_TOOLBAR_STYLE;
2700       
2701       if (style != toolbar->style)
2702         g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2703       
2704       toolbar->style_set = FALSE;
2705     }
2706 }
2707
2708 /**
2709  * gtk_toolbar_set_tooltips:
2710  * @toolbar: a #GtkToolbar.
2711  * @enable: set to %FALSE to disable the tooltips, or %TRUE to enable them.
2712  * 
2713  * Sets if the tooltips of a toolbar should be active or not.
2714  **/
2715 void
2716 gtk_toolbar_set_tooltips (GtkToolbar *toolbar,
2717                           gboolean    enable)
2718 {
2719   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2720   
2721   if (enable)
2722     gtk_tooltips_enable (toolbar->tooltips);
2723   else
2724     gtk_tooltips_disable (toolbar->tooltips);
2725 }
2726
2727 /**
2728  * gtk_toolbar_get_tooltips:
2729  * @toolbar: a #GtkToolbar
2730  *
2731  * Retrieves whether tooltips are enabled. See
2732  * gtk_toolbar_set_tooltips().
2733  *
2734  * Return value: %TRUE if tooltips are enabled
2735  **/
2736 gboolean
2737 gtk_toolbar_get_tooltips (GtkToolbar *toolbar)
2738 {
2739   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2740   
2741   return toolbar->tooltips->enabled;
2742 }
2743
2744 /**
2745  * gtk_toolbar_get_n_items:
2746  * @toolbar: a #GtkToolbar
2747  * 
2748  * Returns the number of items on the toolbar.
2749  * 
2750  * Return value: the number of items on the toolbar
2751  * 
2752  * Since: 2.4
2753  **/
2754 gint
2755 gtk_toolbar_get_n_items (GtkToolbar *toolbar)
2756 {
2757   GtkToolbarPrivate *priv;
2758   
2759   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2760   
2761   if (!gtk_toolbar_check_new_api (toolbar))
2762     return -1;
2763   
2764   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2765   
2766   return physical_to_logical (toolbar, g_list_length (priv->content));
2767 }
2768
2769 /**
2770  * gtk_toolbar_get_nth_item:
2771  * @toolbar: a #GtkToolbar
2772  * @n: A position on the toolbar
2773  *
2774  * Returns the @n<!-- -->'s item on @toolbar, or %NULL if the
2775  * toolbar does not contain an @n<!-- -->'th item.
2776  * 
2777  * Return value: The @n<!-- -->'th #GtkToolItem on @toolbar, or %NULL if there
2778  * isn't an @n<!-- -->th item.
2779  * 
2780  * Since: 2.4
2781  **/
2782 GtkToolItem *
2783 gtk_toolbar_get_nth_item (GtkToolbar *toolbar,
2784                           gint        n)
2785 {
2786   GtkToolbarPrivate *priv;
2787   ToolbarContent *content;
2788   gint n_items;
2789   
2790   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
2791   
2792   if (!gtk_toolbar_check_new_api (toolbar))
2793     return NULL;
2794   
2795   n_items = gtk_toolbar_get_n_items (toolbar);
2796   
2797   if (n < 0 || n >= n_items)
2798     return NULL;
2799   
2800   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2801   
2802   content = g_list_nth_data (priv->content, logical_to_physical (toolbar, n));
2803   
2804   g_assert (content);
2805   g_assert (!toolbar_content_is_placeholder (content));
2806   
2807   return GTK_TOOL_ITEM (toolbar_content_get_widget (content));
2808 }
2809
2810 /**
2811  * gtk_toolbar_get_icon_size:
2812  * @toolbar: a #GtkToolbar
2813  *
2814  * Retrieves the icon size fo the toolbar. See gtk_toolbar_set_icon_size().
2815  *
2816  * Return value: the current icon size for the icons on the toolbar.
2817  **/
2818 GtkIconSize
2819 gtk_toolbar_get_icon_size (GtkToolbar *toolbar)
2820 {
2821   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_ICON_SIZE);
2822   
2823   return toolbar->icon_size;
2824 }
2825
2826 /**
2827  * gtk_toolbar_get_relief_style:
2828  * @toolbar: a #GtkToolbar
2829  * 
2830  * Returns the relief style of buttons on @toolbar. See
2831  * gtk_button_set_relief_style().
2832  * 
2833  * Return value: The relief style of buttons on @toolbar.
2834  * 
2835  * Since: 2.4
2836  **/
2837 GtkReliefStyle
2838 gtk_toolbar_get_relief_style (GtkToolbar *toolbar)
2839 {
2840   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_RELIEF_NONE);
2841   
2842   return get_button_relief (toolbar);
2843 }
2844
2845 /**
2846  * gtk_toolbar_set_show_arrow:
2847  * @toolbar: a #GtkToolbar
2848  * @show_arrow: Whether to show an overflow menu
2849  * 
2850  * Sets whether to show an overflow menu when
2851  * @toolbar doesn't have room for all items on it. If %TRUE,
2852  * items that there are not room are available through an
2853  * overflow menu.
2854  * 
2855  * Since: 2.4
2856  **/
2857 void
2858 gtk_toolbar_set_show_arrow (GtkToolbar *toolbar,
2859                             gboolean    show_arrow)
2860 {
2861   GtkToolbarPrivate *priv;
2862   
2863   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2864   
2865   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2866   show_arrow = show_arrow != FALSE;
2867   
2868   if (priv->show_arrow != show_arrow)
2869     {
2870       priv->show_arrow = show_arrow;
2871       
2872       if (!priv->show_arrow)
2873         gtk_widget_hide (priv->arrow_button);
2874       
2875       gtk_widget_queue_resize (GTK_WIDGET (toolbar));      
2876       g_object_notify (G_OBJECT (toolbar), "show_arrow");
2877     }
2878 }
2879
2880 /**
2881  * gtk_toolbar_get_show_arrow:
2882  * @toolbar: a #GtkToolbar
2883  * 
2884  * Returns whether the toolbar has an overflow menu.
2885  * See gtk_toolbar_set_show_arrow()
2886  * 
2887  * Return value: 
2888  * 
2889  * Since: 2.4
2890  **/
2891 gboolean
2892 gtk_toolbar_get_show_arrow (GtkToolbar *toolbar)
2893 {
2894   GtkToolbarPrivate *priv;
2895   
2896   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2897   
2898   if (!gtk_toolbar_check_new_api (toolbar))
2899     return FALSE;
2900   
2901   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2902   
2903   return priv->show_arrow;
2904 }
2905
2906 /**
2907  * gtk_toolbar_get_drop_index:
2908  * @toolbar: a #GtkToolbar
2909  * @x: x coordinate of a point on the toolbar
2910  * @y: y coordinate of a point on the toolbar
2911  *
2912  * Returns the position corresponding to the indicated point on
2913  * @toolbar. This is useful when dragging items to the toolbar:
2914  * this function returns the position a new item should be
2915  * inserted.
2916  *
2917  * @x and @y are in @toolbar coordinates.
2918  * 
2919  * Return value: The position corresponding to the point (@x, @y) on the toolbar.
2920  * 
2921  * Since: 2.4
2922  **/
2923 gint
2924 gtk_toolbar_get_drop_index (GtkToolbar *toolbar,
2925                             gint        x,
2926                             gint        y)
2927 {
2928   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2929   
2930   if (!gtk_toolbar_check_new_api (toolbar))
2931     return -1;
2932   
2933   return physical_to_logical (toolbar, find_drop_index (toolbar, x, y));
2934 }
2935
2936 static void
2937 gtk_toolbar_finalize (GObject *object)
2938 {
2939   GList *list;
2940   GtkToolbar *toolbar = GTK_TOOLBAR (object);
2941   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2942   
2943   if (toolbar->tooltips)
2944     g_object_unref (toolbar->tooltips);
2945   
2946   for (list = priv->content; list != NULL; list = list->next)
2947     {
2948       ToolbarContent *content = list->data;
2949
2950       toolbar_content_free (content);
2951     }
2952   
2953   g_list_free (priv->content);
2954   g_list_free (toolbar->children);
2955   
2956   g_timer_destroy (priv->timer);
2957   
2958   if (priv->menu)
2959     gtk_widget_destroy (GTK_WIDGET (priv->menu));
2960   
2961   if (priv->idle_id)
2962     g_source_remove (priv->idle_id);
2963   
2964   G_OBJECT_CLASS (parent_class)->finalize (object);
2965 }
2966
2967 gchar *
2968 _gtk_toolbar_elide_underscores (const gchar *original)
2969 {
2970   gchar *q, *result;
2971   const gchar *p;
2972   gboolean last_underscore;
2973   
2974   q = result = g_malloc (strlen (original) + 1);
2975   last_underscore = FALSE;
2976   
2977   for (p = original; *p; p++)
2978     {
2979       if (!last_underscore && *p == '_')
2980         last_underscore = TRUE;
2981       else
2982         {
2983           last_underscore = FALSE;
2984           *q++ = *p;
2985         }
2986     }
2987   
2988   *q = '\0';
2989   
2990   return result;
2991 }
2992
2993 /*
2994  * Deprecated API
2995  */
2996
2997 /**
2998  * gtk_toolbar_set_icon_size:
2999  * @toolbar: A #GtkToolbar
3000  * @icon_size: The #GtkIconSize that stock icons in the toolbar shall have.
3001  *
3002  * This function sets the size of stock icons in the toolbar. You
3003  * can call it both before you add the icons and after they've been
3004  * added. The size you set will override user preferences for the default
3005  * icon size.
3006  **/
3007 void
3008 gtk_toolbar_set_icon_size (GtkToolbar  *toolbar,
3009                            GtkIconSize  icon_size)
3010 {
3011   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3012   
3013   toolbar->icon_size_set = TRUE;
3014   
3015   if (toolbar->icon_size == icon_size)
3016     return;
3017   
3018   toolbar->icon_size = icon_size;
3019   
3020   gtk_toolbar_reconfigured (toolbar);
3021   
3022   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3023 }
3024
3025 /**
3026  * gtk_toolbar_unset_icon_size:
3027  * @toolbar: a #GtkToolbar
3028  * 
3029  * Unsets toolbar icon size set with gtk_toolbar_set_icon_size(), so that
3030  * user preferences will be used to determine the icon size.
3031  **/
3032 void
3033 gtk_toolbar_unset_icon_size (GtkToolbar *toolbar)
3034 {
3035   GtkIconSize size;
3036   
3037   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3038   
3039   if (toolbar->icon_size_set)
3040     {
3041       GtkSettings *settings = toolbar_get_settings (toolbar);
3042       
3043       if (settings)
3044         {
3045           g_object_get (settings,
3046                         "gtk-toolbar-icon-size", &size,
3047                         NULL);
3048         }
3049       else
3050         size = DEFAULT_ICON_SIZE;
3051       
3052       if (size != toolbar->icon_size)
3053         gtk_toolbar_set_icon_size (toolbar, size);
3054       
3055       toolbar->icon_size_set = FALSE;
3056     }
3057 }
3058
3059 /**
3060  * gtk_toolbar_append_item:
3061  * @toolbar: a #GtkToolbar.
3062  * @text: give your toolbar button a label.
3063  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3064  * @tooltip_private_text: use with #GtkTipsQuery.
3065  * @icon: a #GtkWidget that should be used as the button's icon.
3066  * @callback: the function to be executed when the button is pressed.
3067  * @user_data: a pointer to any data you wish to be passed to the callback.
3068  * 
3069  * Inserts a new item into the toolbar. You must specify the position
3070  * in the toolbar where it will be inserted.
3071  *
3072  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3073  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3074  *
3075  * Return value: the new toolbar item as a #GtkWidget.
3076  **/
3077 GtkWidget *
3078 gtk_toolbar_append_item (GtkToolbar    *toolbar,
3079                          const char    *text,
3080                          const char    *tooltip_text,
3081                          const char    *tooltip_private_text,
3082                          GtkWidget     *icon,
3083                          GtkSignalFunc  callback,
3084                          gpointer       user_data)
3085 {
3086   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3087                                      NULL, text,
3088                                      tooltip_text, tooltip_private_text,
3089                                      icon, callback, user_data,
3090                                      toolbar->num_children);
3091 }
3092
3093 /**
3094  * gtk_toolbar_prepend_item:
3095  * @toolbar: a #GtkToolbar.
3096  * @text: give your toolbar button a label.
3097  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3098  * @tooltip_private_text: use with #GtkTipsQuery.
3099  * @icon: a #GtkWidget that should be used as the button's icon.
3100  * @callback: the function to be executed when the button is pressed.
3101  * @user_data: a pointer to any data you wish to be passed to the callback.
3102  * 
3103  * Adds a new button to the beginning (top or left edges) of the given toolbar.
3104  *
3105  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3106  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3107  *
3108  * Return value: the new toolbar item as a #GtkWidget.
3109  **/
3110 GtkWidget *
3111 gtk_toolbar_prepend_item (GtkToolbar    *toolbar,
3112                           const char    *text,
3113                           const char    *tooltip_text,
3114                           const char    *tooltip_private_text,
3115                           GtkWidget     *icon,
3116                           GtkSignalFunc  callback,
3117                           gpointer       user_data)
3118 {
3119   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3120                                      NULL, text,
3121                                      tooltip_text, tooltip_private_text,
3122                                      icon, callback, user_data,
3123                                      0);
3124 }
3125
3126 /**
3127  * gtk_toolbar_insert_item:
3128  * @toolbar: a #GtkToolbar.
3129  * @text: give your toolbar button a label.
3130  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3131  * @tooltip_private_text: use with #GtkTipsQuery.
3132  * @icon: a #GtkWidget that should be used as the button's icon.
3133  * @callback: the function to be executed when the button is pressed.
3134  * @user_data: a pointer to any data you wish to be passed to the callback.
3135  * @position: the number of widgets to insert this item after.
3136  * 
3137  * Inserts a new item into the toolbar. You must specify the position in the
3138  * toolbar where it will be inserted.
3139  *
3140  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3141  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3142  *
3143  * Return value: the new toolbar item as a #GtkWidget.
3144  **/
3145 GtkWidget *
3146 gtk_toolbar_insert_item (GtkToolbar    *toolbar,
3147                          const char    *text,
3148                          const char    *tooltip_text,
3149                          const char    *tooltip_private_text,
3150                          GtkWidget     *icon,
3151                          GtkSignalFunc  callback,
3152                          gpointer       user_data,
3153                          gint           position)
3154 {
3155   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3156                                      NULL, text,
3157                                      tooltip_text, tooltip_private_text,
3158                                      icon, callback, user_data,
3159                                      position);
3160 }
3161
3162 /**
3163  * gtk_toolbar_insert_stock:
3164  * @toolbar: A #GtkToolbar
3165  * @stock_id: The id of the stock item you want to insert
3166  * @tooltip_text: The text in the tooltip of the toolbar button
3167  * @tooltip_private_text: The private text of the tooltip
3168  * @callback: The callback called when the toolbar button is clicked.
3169  * @user_data: user data passed to callback
3170  * @position: The position the button shall be inserted at.
3171  *            -1 means at the end.
3172  *
3173  * Inserts a stock item at the specified position of the toolbar.  If
3174  * @stock_id is not a known stock item ID, it's inserted verbatim,
3175  * except that underscores used to mark mnemonics are removed.
3176  *
3177  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3178  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3179  *
3180  * Returns: the inserted widget
3181  */
3182 GtkWidget*
3183 gtk_toolbar_insert_stock (GtkToolbar      *toolbar,
3184                           const gchar     *stock_id,
3185                           const char      *tooltip_text,
3186                           const char      *tooltip_private_text,
3187                           GtkSignalFunc    callback,
3188                           gpointer         user_data,
3189                           gint             position)
3190 {
3191   return internal_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3192                                   NULL, stock_id,
3193                                   tooltip_text, tooltip_private_text,
3194                                   NULL, callback, user_data,
3195                                   position, TRUE);
3196 }
3197
3198 /**
3199  * gtk_toolbar_append_space:
3200  * @toolbar: a #GtkToolbar.
3201  * 
3202  * Adds a new space to the end of the toolbar.
3203  **/
3204 void
3205 gtk_toolbar_append_space (GtkToolbar *toolbar)
3206 {
3207   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3208                               NULL, NULL,
3209                               NULL, NULL,
3210                               NULL, NULL, NULL,
3211                               toolbar->num_children);
3212 }
3213
3214 /**
3215  * gtk_toolbar_prepend_space:
3216  * @toolbar: a #GtkToolbar.
3217  * 
3218  * Adds a new space to the beginning of the toolbar.
3219  **/
3220 void
3221 gtk_toolbar_prepend_space (GtkToolbar *toolbar)
3222 {
3223   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3224                               NULL, NULL,
3225                               NULL, NULL,
3226                               NULL, NULL, NULL,
3227                               0);
3228 }
3229
3230 /**
3231  * gtk_toolbar_insert_space:
3232  * @toolbar: a #GtkToolbar
3233  * @position: the number of widgets after which a space should be inserted.
3234  * 
3235  * Inserts a new space in the toolbar at the specified position.
3236  **/
3237 void
3238 gtk_toolbar_insert_space (GtkToolbar *toolbar,
3239                           gint        position)
3240 {
3241   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3242                               NULL, NULL,
3243                               NULL, NULL,
3244                               NULL, NULL, NULL,
3245                               position);
3246 }
3247
3248 /**
3249  * gtk_toolbar_remove_space:
3250  * @toolbar: a #GtkToolbar.
3251  * @position: the index of the space to remove.
3252  * 
3253  * Removes a space from the specified position.
3254  **/
3255 void
3256 gtk_toolbar_remove_space (GtkToolbar *toolbar,
3257                           gint        position)
3258 {
3259   GtkToolbarPrivate *priv;
3260   ToolbarContent *content;
3261   
3262   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3263   
3264   if (!gtk_toolbar_check_old_api (toolbar))
3265     return;
3266   
3267   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3268   
3269   content = g_list_nth_data (priv->content, position);
3270   
3271   if (!content)
3272     {
3273       g_warning ("Toolbar position %d doesn't exist", position);
3274       return;
3275     }
3276   
3277   if (!toolbar_content_is_separator (content))
3278     {
3279       g_warning ("Toolbar position %d is not a space", position);
3280       return;
3281     }
3282   
3283   toolbar_content_remove (content, toolbar);
3284   toolbar_content_free (content);
3285 }
3286
3287 /**
3288  * gtk_toolbar_append_widget:
3289  * @toolbar: a #GtkToolbar.
3290  * @widget: a #GtkWidget to add to the toolbar. 
3291  * @tooltip_text: the element's tooltip.
3292  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3293  * 
3294  * Adds a widget to the end of the given toolbar.
3295  **/ 
3296 void
3297 gtk_toolbar_append_widget (GtkToolbar  *toolbar,
3298                            GtkWidget   *widget,
3299                            const gchar *tooltip_text,
3300                            const gchar *tooltip_private_text)
3301 {
3302   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3303                               widget, NULL,
3304                               tooltip_text, tooltip_private_text,
3305                               NULL, NULL, NULL,
3306                               toolbar->num_children);
3307 }
3308
3309 /**
3310  * gtk_toolbar_prepend_widget:
3311  * @toolbar: a #GtkToolbar.
3312  * @widget: a #GtkWidget to add to the toolbar. 
3313  * @tooltip_text: the element's tooltip.
3314  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3315  * 
3316  * Adds a widget to the beginning of the given toolbar.
3317  **/ 
3318 void
3319 gtk_toolbar_prepend_widget (GtkToolbar  *toolbar,
3320                             GtkWidget   *widget,
3321                             const gchar *tooltip_text,
3322                             const gchar *tooltip_private_text)
3323 {
3324   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3325                               widget, NULL,
3326                               tooltip_text, tooltip_private_text,
3327                               NULL, NULL, NULL,
3328                               0);
3329 }
3330
3331 /**
3332  * gtk_toolbar_insert_widget:
3333  * @toolbar: a #GtkToolbar.
3334  * @widget: a #GtkWidget to add to the toolbar. 
3335  * @tooltip_text: the element's tooltip.
3336  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3337  * @position: the number of widgets to insert this widget after.
3338  * 
3339  * Inserts a widget in the toolbar at the given position.
3340  **/ 
3341 void
3342 gtk_toolbar_insert_widget (GtkToolbar *toolbar,
3343                            GtkWidget  *widget,
3344                            const char *tooltip_text,
3345                            const char *tooltip_private_text,
3346                            gint        position)
3347 {
3348   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3349                               widget, NULL,
3350                               tooltip_text, tooltip_private_text,
3351                               NULL, NULL, NULL,
3352                               position);
3353 }
3354
3355 /**
3356  * gtk_toolbar_append_element:
3357  * @toolbar: a #GtkToolbar.
3358  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3359  * @widget: a #GtkWidget, or %NULL.
3360  * @text: the element's label.
3361  * @tooltip_text: the element's tooltip.
3362  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3363  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3364  * @callback: the function to be executed when the button is pressed.
3365  * @user_data: any data you wish to pass to the callback.
3366  * 
3367  * Adds a new element to the end of a toolbar.
3368  * 
3369  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3370  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3371  * the radio group for the new element. In all other cases, @widget must
3372  * be %NULL.
3373  * 
3374  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3375  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3376  *
3377  * Return value: the new toolbar element as a #GtkWidget.
3378  **/
3379 GtkWidget*
3380 gtk_toolbar_append_element (GtkToolbar          *toolbar,
3381                             GtkToolbarChildType  type,
3382                             GtkWidget           *widget,
3383                             const char          *text,
3384                             const char          *tooltip_text,
3385                             const char          *tooltip_private_text,
3386                             GtkWidget           *icon,
3387                             GtkSignalFunc        callback,
3388                             gpointer             user_data)
3389 {
3390   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3391                                      tooltip_text, tooltip_private_text,
3392                                      icon, callback, user_data,
3393                                      toolbar->num_children);
3394 }
3395
3396 /**
3397  * gtk_toolbar_prepend_element:
3398  * @toolbar: a #GtkToolbar.
3399  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3400  * @widget: a #GtkWidget, or %NULL
3401  * @text: the element's label.
3402  * @tooltip_text: the element's tooltip.
3403  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3404  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3405  * @callback: the function to be executed when the button is pressed.
3406  * @user_data: any data you wish to pass to the callback.
3407  *  
3408  * Adds a new element to the beginning of a toolbar.
3409  * 
3410  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3411  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3412  * the radio group for the new element. In all other cases, @widget must
3413  * be %NULL.
3414  * 
3415  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3416  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3417  *
3418  * Return value: the new toolbar element as a #GtkWidget.
3419  **/
3420 GtkWidget *
3421 gtk_toolbar_prepend_element (GtkToolbar          *toolbar,
3422                              GtkToolbarChildType  type,
3423                              GtkWidget           *widget,
3424                              const char          *text,
3425                              const char          *tooltip_text,
3426                              const char          *tooltip_private_text,
3427                              GtkWidget           *icon,
3428                              GtkSignalFunc        callback,
3429                              gpointer             user_data)
3430 {
3431   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3432                                      tooltip_text, tooltip_private_text,
3433                                      icon, callback, user_data, 0);
3434 }
3435
3436 /**
3437  * gtk_toolbar_insert_element:
3438  * @toolbar: a #GtkToolbar.
3439  * @type: a value of type #GtkToolbarChildType that determines what @widget
3440  *   will be.
3441  * @widget: a #GtkWidget, or %NULL. 
3442  * @text: the element's label.
3443  * @tooltip_text: the element's tooltip.
3444  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3445  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3446  * @callback: the function to be executed when the button is pressed.
3447  * @user_data: any data you wish to pass to the callback.
3448  * @position: the number of widgets to insert this element after.
3449  *
3450  * Inserts a new element in the toolbar at the given position. 
3451  *
3452  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3453  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3454  * the radio group for the new element. In all other cases, @widget must
3455  * be %NULL.
3456  *
3457  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3458  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3459  *
3460  * Return value: the new toolbar element as a #GtkWidget.
3461  **/
3462 GtkWidget *
3463 gtk_toolbar_insert_element (GtkToolbar          *toolbar,
3464                             GtkToolbarChildType  type,
3465                             GtkWidget           *widget,
3466                             const char          *text,
3467                             const char          *tooltip_text,
3468                             const char          *tooltip_private_text,
3469                             GtkWidget           *icon,
3470                             GtkSignalFunc        callback,
3471                             gpointer             user_data,
3472                             gint                 position)
3473 {
3474   return internal_insert_element (toolbar, type, widget, text,
3475                                   tooltip_text, tooltip_private_text,
3476                                   icon, callback, user_data, position, FALSE);
3477 }
3478
3479 static void
3480 set_child_packing_and_visibility(GtkToolbar      *toolbar,
3481                                  GtkToolbarChild *child)
3482 {
3483   GtkWidget *box;
3484   gboolean   expand;
3485
3486   box = gtk_bin_get_child (GTK_BIN (child->widget));
3487   
3488   g_return_if_fail (GTK_IS_BOX (box));
3489   
3490   if (child->label)
3491     {
3492       expand = (toolbar->style != GTK_TOOLBAR_BOTH);
3493       
3494       gtk_box_set_child_packing (GTK_BOX (box), child->label,
3495                                  expand, expand, 0, GTK_PACK_END);
3496       
3497       if (toolbar->style != GTK_TOOLBAR_ICONS)
3498         gtk_widget_show (child->label);
3499       else
3500         gtk_widget_hide (child->label);
3501     }
3502   
3503   if (child->icon)
3504     {
3505       expand = (toolbar->style != GTK_TOOLBAR_BOTH_HORIZ);
3506       
3507       gtk_box_set_child_packing (GTK_BOX (box), child->icon,
3508                                  expand, expand, 0, GTK_PACK_END);
3509       
3510       if (toolbar->style != GTK_TOOLBAR_TEXT)
3511         gtk_widget_show (child->icon);
3512       else
3513         gtk_widget_hide (child->icon);
3514     }
3515 }
3516
3517 static GtkWidget *
3518 internal_insert_element (GtkToolbar          *toolbar,
3519                          GtkToolbarChildType  type,
3520                          GtkWidget           *widget,
3521                          const char          *text,
3522                          const char          *tooltip_text,
3523                          const char          *tooltip_private_text,
3524                          GtkWidget           *icon,
3525                          GtkSignalFunc        callback,
3526                          gpointer             user_data,
3527                          gint                 position,
3528                          gboolean             use_stock)
3529 {
3530   GtkWidget *box;
3531   ToolbarContent *content;
3532   GtkToolbarPrivate *priv;
3533   char *free_me = NULL;
3534   gboolean is_button = FALSE;
3535
3536   GtkWidget *child_widget;
3537   GtkWidget *child_label;
3538   GtkWidget *child_icon;
3539
3540   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
3541   if (type == GTK_TOOLBAR_CHILD_WIDGET)
3542     g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
3543   else if (type != GTK_TOOLBAR_CHILD_RADIOBUTTON)
3544     g_return_val_if_fail (widget == NULL, NULL);
3545   
3546   if (!gtk_toolbar_check_old_api (toolbar))
3547     return NULL;
3548   
3549   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3550   
3551   child_widget = NULL;
3552   child_label = NULL;
3553   child_icon = NULL;
3554   
3555   switch (type)
3556     {
3557     case GTK_TOOLBAR_CHILD_SPACE:
3558       break;
3559       
3560     case GTK_TOOLBAR_CHILD_WIDGET:
3561       child_widget = widget;
3562       break;
3563       
3564     case GTK_TOOLBAR_CHILD_BUTTON:
3565     case GTK_TOOLBAR_CHILD_TOGGLEBUTTON:
3566     case GTK_TOOLBAR_CHILD_RADIOBUTTON:
3567       is_button = TRUE;
3568       if (type == GTK_TOOLBAR_CHILD_BUTTON)
3569         {
3570           child_widget = gtk_button_new ();
3571         }
3572       else if (type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
3573         {
3574           child_widget = gtk_toggle_button_new ();
3575           gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child_widget), FALSE);
3576         }
3577       else /* type == GTK_TOOLBAR_CHILD_RADIOBUTTON */
3578         {
3579           GSList *group = NULL;
3580
3581           if (widget)
3582             group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
3583           
3584           child_widget = gtk_radio_button_new (group);
3585           gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child_widget), FALSE);
3586         }
3587
3588       gtk_button_set_relief (GTK_BUTTON (child_widget), get_button_relief (toolbar));
3589       gtk_button_set_focus_on_click (GTK_BUTTON (child_widget), FALSE);
3590       
3591       if (callback)
3592         {
3593           g_signal_connect (child_widget, "clicked",
3594                             callback, user_data);
3595         }
3596       
3597       if (toolbar->style == GTK_TOOLBAR_BOTH_HORIZ)
3598         box = gtk_hbox_new (FALSE, 0);
3599       else
3600         box = gtk_vbox_new (FALSE, 0);
3601
3602       gtk_container_add (GTK_CONTAINER (child_widget), box);
3603       gtk_widget_show (box);
3604       
3605       if (text && use_stock)
3606         {
3607           GtkStockItem stock_item;
3608           gtk_stock_lookup (text, &stock_item);
3609           
3610           if (!icon)
3611             icon = gtk_image_new_from_stock (text, toolbar->icon_size);
3612           
3613           text = free_me = _gtk_toolbar_elide_underscores (stock_item.label);
3614         }
3615       
3616       if (text)
3617         {
3618           child_label = gtk_label_new (text);
3619           
3620           gtk_container_add (GTK_CONTAINER (box), child_label);
3621         }
3622       
3623       if (icon)
3624         {
3625           child_icon = GTK_WIDGET (icon);
3626           gtk_container_add (GTK_CONTAINER (box), child_icon);
3627         }
3628       
3629       gtk_widget_show (child_widget);
3630       break;
3631       
3632     default:
3633       g_assert_not_reached ();
3634       break;
3635     }
3636   
3637   if ((type != GTK_TOOLBAR_CHILD_SPACE) && tooltip_text)
3638     {
3639       gtk_tooltips_set_tip (toolbar->tooltips, child_widget,
3640                             tooltip_text, tooltip_private_text);
3641     }
3642   
3643   content = toolbar_content_new_compatibility (toolbar, type, child_widget,
3644                                                child_icon, child_label, position);
3645   
3646   if (free_me)
3647     g_free (free_me);
3648   
3649   return child_widget;
3650 }
3651
3652 /*
3653  * ToolbarContent methods
3654  */
3655 struct _ToolbarContent
3656 {
3657   ContentType   type;
3658   ItemState     state;
3659   
3660   union
3661   {
3662     struct
3663     {
3664       GtkToolItem *     item;
3665       GtkAllocation     start_allocation;
3666       GtkAllocation     goal_allocation;
3667       guint             is_placeholder : 1;
3668       guint             disappearing : 1;
3669     } tool_item;
3670     
3671     struct
3672     {
3673       GtkToolbarChild   child;
3674       GtkAllocation     space_allocation;
3675       guint             space_visible : 1;
3676     } compatibility;
3677   } u;
3678 };
3679
3680 static ToolbarContent *
3681 toolbar_content_new_tool_item (GtkToolbar  *toolbar,
3682                                GtkToolItem *item,
3683                                gboolean     is_placeholder,
3684                                gint         pos)
3685 {
3686   ToolbarContent *content;
3687   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3688   
3689   content = g_new0 (ToolbarContent, 1);
3690   
3691   content->type = TOOL_ITEM;
3692   content->state = NOT_ALLOCATED;
3693   content->u.tool_item.item = item;
3694   content->u.tool_item.is_placeholder = is_placeholder;
3695   
3696   gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar));
3697
3698   priv->content = g_list_insert (priv->content, content, pos);
3699   
3700   if (!is_placeholder)
3701     {
3702       toolbar->num_children++;
3703
3704       gtk_toolbar_stop_sliding (toolbar);
3705     }
3706
3707   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3708   
3709   return content;
3710 }
3711
3712 static ToolbarContent *
3713 toolbar_content_new_compatibility (GtkToolbar          *toolbar,
3714                                    GtkToolbarChildType  type,
3715                                    GtkWidget            *widget,
3716                                    GtkWidget            *icon,
3717                                    GtkWidget            *label,
3718                                    gint                  pos)
3719 {
3720   ToolbarContent *content;
3721   GtkToolbarChild *child;
3722   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3723   
3724   content = g_new0 (ToolbarContent, 1);
3725
3726   child = &(content->u.compatibility.child);
3727   
3728   content->type = COMPATIBILITY;
3729   child->type = type;
3730   child->widget = widget;
3731   child->icon = icon;
3732   child->label = label;
3733   
3734   if (type != GTK_TOOLBAR_CHILD_SPACE)
3735     {
3736       gtk_widget_set_parent (child->widget, GTK_WIDGET (toolbar));
3737     }
3738   else
3739     {
3740       content->u.compatibility.space_visible = TRUE;
3741       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3742     }
3743  
3744   if (type == GTK_TOOLBAR_CHILD_BUTTON ||
3745       type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
3746       type == GTK_TOOLBAR_CHILD_RADIOBUTTON)
3747     {
3748       set_child_packing_and_visibility (toolbar, child);
3749     }
3750
3751   priv->content = g_list_insert (priv->content, content, pos);
3752   toolbar->children = g_list_insert (toolbar->children, child, pos);
3753   
3754   toolbar->num_children++;
3755   
3756   return content;
3757 }
3758
3759 static void
3760 toolbar_content_remove (ToolbarContent *content,
3761                         GtkToolbar     *toolbar)
3762 {
3763   GtkToolbarChild *child;
3764   GtkToolbarPrivate *priv;
3765
3766   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3767   
3768   switch (content->type)
3769     {
3770     case TOOL_ITEM:
3771       gtk_widget_unparent (GTK_WIDGET (content->u.tool_item.item));
3772       break;
3773       
3774     case COMPATIBILITY:
3775       child = &(content->u.compatibility.child);
3776       
3777       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
3778         {
3779           g_object_ref (child->widget);
3780           gtk_widget_unparent (child->widget);
3781           gtk_widget_destroy (child->widget);
3782           g_object_unref (child->widget);
3783         }
3784       
3785       toolbar->children = g_list_remove (toolbar->children, child);
3786       break;
3787     }
3788
3789   priv->content = g_list_remove (priv->content, content);
3790
3791   if (!toolbar_content_is_placeholder (content))
3792     toolbar->num_children--;
3793
3794   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3795 }
3796
3797 static void
3798 toolbar_content_free (ToolbarContent *content)
3799 {
3800   g_free (content);
3801 }
3802
3803 static gint
3804 calculate_max_homogeneous_pixels (GtkWidget *widget)
3805 {
3806   PangoContext *context;
3807   PangoFontMetrics *metrics;
3808   gint char_width;
3809   
3810   context = gtk_widget_get_pango_context (widget);
3811   metrics = pango_context_get_metrics (context,
3812                                        widget->style->font_desc,
3813                                        pango_context_get_language (context));
3814   char_width = pango_font_metrics_get_approximate_char_width (metrics);
3815   pango_font_metrics_unref (metrics);
3816   
3817   return PANGO_PIXELS (MAX_HOMOGENEOUS_N_CHARS * char_width);
3818 }
3819
3820 gint
3821 _gtk_toolbar_get_default_space_size (void)
3822 {
3823   return DEFAULT_SPACE_SIZE;
3824 }
3825
3826 void
3827 _gtk_toolbar_paint_space_line (GtkWidget       *widget,
3828                                GtkToolbar      *toolbar,
3829                                GdkRectangle    *area,
3830                                GtkAllocation   *allocation)
3831 {
3832   const double start_fraction = (SPACE_LINE_START / SPACE_LINE_DIVISION);
3833   const double end_fraction = (SPACE_LINE_END / SPACE_LINE_DIVISION);
3834   
3835   gint space_size;
3836   GtkToolbarSpaceStyle space_style;
3837   GtkOrientation orientation;
3838
3839   g_return_if_fail (GTK_IS_WIDGET (widget));
3840   
3841   space_size = get_space_size (toolbar);
3842   space_style = get_space_style (toolbar);
3843   orientation = toolbar? toolbar->orientation : GTK_ORIENTATION_HORIZONTAL;
3844
3845   if (orientation == GTK_ORIENTATION_HORIZONTAL)
3846     {
3847       gtk_paint_vline (widget->style, widget->window,
3848                        GTK_WIDGET_STATE (widget), area, widget,
3849                        "toolbar",
3850                        allocation->y + allocation->height * start_fraction,
3851                        allocation->y + allocation->height * end_fraction,
3852                        allocation->x + (space_size - widget->style->xthickness) / 2);
3853     }
3854   else
3855     {
3856       gtk_paint_hline (widget->style, widget->window,
3857                        GTK_WIDGET_STATE (widget), area, widget,
3858                        "toolbar",
3859                        allocation->x + allocation->width * start_fraction,
3860                        allocation->x + allocation->width * end_fraction,
3861                        allocation->y + (space_size - widget->style->ythickness) / 2);
3862     }
3863 }
3864
3865 static void
3866 toolbar_content_expose (ToolbarContent *content,
3867                         GtkContainer   *container,
3868                         GdkEventExpose *expose)
3869 {
3870   GtkToolbar *toolbar = GTK_TOOLBAR (container);
3871   GtkToolbarChild *child;
3872   GtkWidget *widget = NULL; /* quiet gcc */
3873   
3874   switch (content->type)
3875     {
3876     case TOOL_ITEM:
3877       if (!content->u.tool_item.is_placeholder)
3878         widget = GTK_WIDGET (content->u.tool_item.item);
3879       break;
3880       
3881     case COMPATIBILITY:
3882       child = &(content->u.compatibility.child);
3883       
3884       if (child->type == GTK_TOOLBAR_CHILD_SPACE)
3885         {
3886           if (get_space_style (toolbar) == GTK_TOOLBAR_SPACE_LINE &&
3887               content->u.compatibility.space_visible)
3888             {
3889               _gtk_toolbar_paint_space_line (GTK_WIDGET (toolbar), toolbar,
3890                                              &expose->area,
3891                                              &content->u.compatibility.space_allocation);
3892             }
3893           return;
3894         }
3895       
3896       widget = child->widget;
3897       break;
3898     }
3899   
3900   if (widget)
3901     gtk_container_propagate_expose (container, widget, expose);
3902 }
3903
3904 static gboolean
3905 toolbar_content_visible (ToolbarContent *content,
3906                          GtkToolbar     *toolbar)
3907 {
3908   GtkToolItem *item;
3909   
3910   switch (content->type)
3911     {
3912     case TOOL_ITEM:
3913       item = content->u.tool_item.item;
3914       
3915       if (!GTK_WIDGET_VISIBLE (item))
3916         return FALSE;
3917       
3918       if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL &&
3919           gtk_tool_item_get_visible_horizontal (item))
3920         {
3921           return TRUE;
3922         }
3923       
3924       if ((toolbar->orientation == GTK_ORIENTATION_VERTICAL &&
3925            gtk_tool_item_get_visible_vertical (item)))
3926         {
3927           return TRUE;
3928         }
3929       
3930       return FALSE;
3931       break;
3932       
3933     case COMPATIBILITY:
3934       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
3935         return GTK_WIDGET_VISIBLE (content->u.compatibility.child.widget);
3936       else
3937         return TRUE;
3938       break;
3939     }
3940   
3941   g_assert_not_reached ();
3942   return FALSE;
3943 }
3944
3945 static void
3946 toolbar_content_size_request (ToolbarContent *content,
3947                               GtkToolbar     *toolbar,
3948                               GtkRequisition *requisition)
3949 {
3950   gint space_size;
3951   
3952   switch (content->type)
3953     {
3954     case TOOL_ITEM:
3955       gtk_widget_size_request (GTK_WIDGET (content->u.tool_item.item),
3956                                requisition);
3957       if (content->u.tool_item.is_placeholder &&
3958           content->u.tool_item.disappearing)
3959         {
3960           requisition->width = 0;
3961           requisition->height = 0;
3962         }
3963       break;
3964       
3965     case COMPATIBILITY:
3966       space_size = get_space_size (toolbar);
3967       
3968       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
3969         {
3970           gtk_widget_size_request (content->u.compatibility.child.widget,
3971                                    requisition);
3972         }
3973       else
3974         {
3975           if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
3976             {
3977               requisition->width = space_size;
3978               requisition->height = 0;
3979             }
3980           else
3981             {
3982               requisition->height = space_size;
3983               requisition->width = 0;
3984             }
3985         }
3986       
3987       break;
3988     }
3989 }
3990
3991 static gboolean
3992 toolbar_content_is_homogeneous (ToolbarContent *content,
3993                                 GtkToolbar     *toolbar)
3994 {
3995   gboolean result = FALSE;      /* quiet gcc */
3996   GtkRequisition requisition;
3997   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3998   
3999   if (priv->max_homogeneous_pixels < 0)
4000     {
4001       priv->max_homogeneous_pixels =
4002         calculate_max_homogeneous_pixels (GTK_WIDGET (toolbar));
4003     }
4004   
4005   toolbar_content_size_request (content, toolbar, &requisition);
4006   
4007   if (requisition.width > priv->max_homogeneous_pixels)
4008     return FALSE;
4009   
4010   switch (content->type)
4011     {
4012     case TOOL_ITEM:
4013       result = gtk_tool_item_get_homogeneous (content->u.tool_item.item) &&
4014         !GTK_IS_SEPARATOR_TOOL_ITEM (content->u.tool_item.item);
4015       
4016       if (gtk_tool_item_get_is_important (content->u.tool_item.item) &&
4017           toolbar->style == GTK_TOOLBAR_BOTH_HORIZ &&
4018           toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
4019         {
4020           result = FALSE;
4021         }
4022       break;
4023       
4024     case COMPATIBILITY:
4025       if (content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_BUTTON ||
4026           content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4027           content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4028         {
4029           result = TRUE;
4030         }
4031       else
4032         {
4033           result = FALSE;
4034         }
4035       break;
4036     }
4037   
4038   return result;
4039 }
4040
4041 static gboolean
4042 toolbar_content_is_placeholder (ToolbarContent *content)
4043 {
4044   if (content->type == TOOL_ITEM && content->u.tool_item.is_placeholder)
4045     return TRUE;
4046   
4047   return FALSE;
4048 }
4049
4050 static gboolean
4051 toolbar_content_disappearing (ToolbarContent *content)
4052 {
4053   if (content->type == TOOL_ITEM && content->u.tool_item.disappearing)
4054     return TRUE;
4055   
4056   return FALSE;
4057 }
4058
4059 static ItemState
4060 toolbar_content_get_state (ToolbarContent *content)
4061 {
4062   return content->state;
4063 }
4064
4065 static gboolean
4066 toolbar_content_child_visible (ToolbarContent *content)
4067 {
4068   switch (content->type)
4069     {
4070     case TOOL_ITEM:
4071       return GTK_WIDGET_CHILD_VISIBLE (content->u.tool_item.item);
4072       break;
4073       
4074     case COMPATIBILITY:
4075       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4076         {
4077           return GTK_WIDGET_CHILD_VISIBLE (content->u.compatibility.child.widget);
4078         }
4079       else
4080         {
4081           return content->u.compatibility.space_visible;
4082         }
4083       break;
4084     }
4085   
4086   return FALSE; /* quiet gcc */
4087 }
4088
4089 static void
4090 toolbar_content_get_goal_allocation (ToolbarContent *content,
4091                                      GtkAllocation  *allocation)
4092 {
4093   switch (content->type)
4094     {
4095     case TOOL_ITEM:
4096       *allocation = content->u.tool_item.goal_allocation;
4097       break;
4098       
4099     case COMPATIBILITY:
4100       /* Goal allocations are only relevant when we are
4101        * using the new API, so we should never get here
4102        */
4103       g_assert_not_reached ();
4104       break;
4105     }
4106 }
4107
4108 static void
4109 toolbar_content_get_allocation (ToolbarContent *content,
4110                                 GtkAllocation  *allocation)
4111 {
4112   GtkToolbarChild *child;
4113   
4114   switch (content->type)
4115     {
4116     case TOOL_ITEM:
4117       *allocation = GTK_WIDGET (content->u.tool_item.item)->allocation;
4118       break;
4119       
4120     case COMPATIBILITY:
4121       child = &(content->u.compatibility.child);
4122       
4123       if (child->type == GTK_TOOLBAR_CHILD_SPACE)
4124         *allocation = content->u.compatibility.space_allocation;
4125       else
4126         *allocation = child->widget->allocation;
4127       break;
4128     }
4129 }
4130
4131 static void
4132 toolbar_content_set_start_allocation (ToolbarContent *content,
4133                                       GtkAllocation  *allocation)
4134 {
4135   switch (content->type)
4136     {
4137     case TOOL_ITEM:
4138       content->u.tool_item.start_allocation = *allocation;
4139       break;
4140       
4141     case COMPATIBILITY:
4142       /* start_allocation is only relevant when using the new API */
4143       g_assert_not_reached ();
4144       break;
4145     }
4146 }
4147
4148 static gboolean
4149 toolbar_content_get_expand (ToolbarContent *content)
4150 {
4151   if (content->type == TOOL_ITEM &&
4152       gtk_tool_item_get_expand (content->u.tool_item.item))
4153     {
4154       return TRUE;
4155     }
4156   
4157   return FALSE;
4158 }
4159
4160 static void
4161 toolbar_content_set_goal_allocation (ToolbarContent *content,
4162                                      GtkAllocation  *allocation)
4163 {
4164   switch (content->type)
4165     {
4166     case TOOL_ITEM:
4167       content->u.tool_item.goal_allocation = *allocation;
4168       break;
4169       
4170     case COMPATIBILITY:
4171       /* Only relevant when using new API */
4172       g_assert_not_reached ();
4173       break;
4174     }
4175 }
4176
4177 static void
4178 toolbar_content_set_child_visible (ToolbarContent *content,
4179                                    GtkToolbar     *toolbar,
4180                                    gboolean        visible)
4181 {
4182   GtkToolbarChild *child;
4183   
4184   switch (content->type)
4185     {
4186     case TOOL_ITEM:
4187       gtk_widget_set_child_visible (GTK_WIDGET (content->u.tool_item.item),
4188                                     visible);
4189       break;
4190       
4191     case COMPATIBILITY:
4192       child = &(content->u.compatibility.child);
4193       
4194       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
4195         {
4196           gtk_widget_set_child_visible (child->widget, visible);
4197         }
4198       else
4199         {
4200           content->u.compatibility.space_visible = visible;
4201           gtk_widget_queue_draw (GTK_WIDGET (toolbar));
4202         }
4203       break;
4204     }
4205 }
4206
4207 static void
4208 toolbar_content_get_start_allocation (ToolbarContent *content,
4209                                       GtkAllocation  *start_allocation)
4210 {
4211   switch (content->type)
4212     {
4213     case TOOL_ITEM:
4214       *start_allocation = content->u.tool_item.start_allocation;
4215       break;
4216       
4217     case COMPATIBILITY:
4218       /* Only relevant for new API */
4219       g_assert_not_reached ();
4220       break;
4221     }
4222 }
4223
4224 static void
4225 toolbar_content_size_allocate (ToolbarContent *content,
4226                                GtkAllocation  *allocation)
4227 {
4228   switch (content->type)
4229     {
4230     case TOOL_ITEM:
4231       gtk_widget_size_allocate (GTK_WIDGET (content->u.tool_item.item),
4232                                 allocation);
4233       break;
4234       
4235     case COMPATIBILITY:
4236       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4237         {
4238           gtk_widget_size_allocate (content->u.compatibility.child.widget,
4239                                     allocation);
4240         }
4241       else
4242         {
4243           content->u.compatibility.space_allocation = *allocation;
4244         }
4245       break;
4246     }
4247 }
4248
4249 static void
4250 toolbar_content_set_state (ToolbarContent *content,
4251                            ItemState       state)
4252 {
4253   content->state = state;
4254 }
4255
4256 static GtkWidget *
4257 toolbar_content_get_widget (ToolbarContent *content)
4258 {
4259   GtkToolbarChild *child;
4260   
4261   switch (content->type)
4262     {
4263     case TOOL_ITEM:
4264       return GTK_WIDGET (content->u.tool_item.item);
4265       break;
4266       
4267     case COMPATIBILITY:
4268       child = &(content->u.compatibility.child);
4269       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
4270         return child->widget;
4271       else
4272         return NULL;
4273       break;
4274     }
4275   
4276   return NULL;
4277 }
4278
4279 static void
4280 toolbar_content_set_disappearing (ToolbarContent *content,
4281                                   gboolean        disappearing)
4282 {
4283   switch (content->type)
4284     {
4285     case TOOL_ITEM:
4286       content->u.tool_item.disappearing = disappearing;
4287       break;
4288       
4289     case COMPATIBILITY:
4290       /* Only relevant for new API */
4291       g_assert_not_reached ();
4292       break;
4293     }
4294 }
4295
4296 static void
4297 toolbar_content_set_size_request (ToolbarContent *content,
4298                                   gint            width,
4299                                   gint            height)
4300 {
4301   switch (content->type)
4302     {
4303     case TOOL_ITEM:
4304       gtk_widget_set_size_request (GTK_WIDGET (content->u.tool_item.item),
4305                                    width, height);
4306       break;
4307       
4308     case COMPATIBILITY:
4309       /* Setting size requests only happens with sliding,
4310        * so not relevant here
4311        */
4312       g_assert_not_reached ();
4313       break;
4314     }
4315 }
4316
4317 static void
4318 toolbar_child_reconfigure (GtkToolbar      *toolbar,
4319                            GtkToolbarChild *child)
4320 {
4321   GtkWidget *box;
4322   GtkImage *image;
4323   GtkToolbarStyle style;
4324   GtkIconSize icon_size;
4325   GtkReliefStyle relief;
4326   gchar *stock_id;
4327   
4328   style = gtk_toolbar_get_style (toolbar);
4329   icon_size = gtk_toolbar_get_icon_size (toolbar);
4330   relief = gtk_toolbar_get_relief_style (toolbar);
4331   
4332   /* style */
4333   if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4334       child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4335       child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4336     {
4337       box = gtk_bin_get_child (GTK_BIN (child->widget));
4338       
4339       if (style == GTK_TOOLBAR_BOTH && GTK_IS_HBOX (box))
4340         {
4341           GtkWidget *vbox;
4342           
4343           vbox = gtk_vbox_new (FALSE, 0);
4344           
4345           if (child->label)
4346             gtk_widget_reparent (child->label, vbox);
4347           if (child->icon)
4348             gtk_widget_reparent (child->icon, vbox);
4349           
4350           gtk_widget_destroy (box);
4351           gtk_container_add (GTK_CONTAINER (child->widget), vbox);
4352           
4353           gtk_widget_show (vbox);
4354         }
4355       else if (style == GTK_TOOLBAR_BOTH_HORIZ && GTK_IS_VBOX (box))
4356         {
4357           GtkWidget *hbox;
4358           
4359           hbox = gtk_hbox_new (FALSE, 0);
4360           
4361           if (child->label)
4362             gtk_widget_reparent (child->label, hbox);
4363           if (child->icon)
4364             gtk_widget_reparent (child->icon, hbox);
4365           
4366           gtk_widget_destroy (box);
4367           gtk_container_add (GTK_CONTAINER (child->widget), hbox);
4368           
4369           gtk_widget_show (hbox);
4370         }
4371
4372       set_child_packing_and_visibility (toolbar, child);
4373     }
4374   
4375   /* icon size */
4376   
4377   if ((child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4378        child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
4379        child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON) &&
4380       GTK_IS_IMAGE (child->icon))
4381     {
4382       image = GTK_IMAGE (child->icon);
4383       if (gtk_image_get_storage_type (image) == GTK_IMAGE_STOCK)
4384         {
4385           gtk_image_get_stock (image, &stock_id, NULL);
4386           stock_id = g_strdup (stock_id);
4387           gtk_image_set_from_stock (image,
4388                                     stock_id,
4389                                     icon_size);
4390           g_free (stock_id);
4391         }
4392     }
4393   
4394   /* relief */
4395   if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4396       child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4397       child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4398     {
4399       gtk_button_set_relief (GTK_BUTTON (child->widget), relief);
4400     }
4401 }
4402
4403 static void
4404 toolbar_content_toolbar_reconfigured (ToolbarContent *content,
4405                                       GtkToolbar     *toolbar)
4406 {
4407   switch (content->type)
4408     {
4409     case TOOL_ITEM:
4410       _gtk_tool_item_toolbar_reconfigured (content->u.tool_item.item);
4411       break;
4412       
4413     case COMPATIBILITY:
4414       toolbar_child_reconfigure (toolbar, &(content->u.compatibility.child));
4415       break;
4416     }
4417 }
4418
4419 static GtkWidget *
4420 toolbar_content_retrieve_menu_item (ToolbarContent *content)
4421 {
4422   if (content->type == TOOL_ITEM)
4423     return gtk_tool_item_retrieve_proxy_menu_item (content->u.tool_item.item);
4424   
4425   /* FIXME - we might actually be able to do something meaningful here */
4426   return NULL; 
4427 }
4428
4429 static gboolean
4430 toolbar_content_is_separator (ToolbarContent *content)
4431 {
4432   GtkToolbarChild *child;
4433   
4434   switch (content->type)
4435     {
4436     case TOOL_ITEM:
4437       return GTK_IS_SEPARATOR_TOOL_ITEM (content->u.tool_item.item);
4438       break;
4439       
4440     case COMPATIBILITY:
4441       child = &(content->u.compatibility.child);
4442       return (child->type == GTK_TOOLBAR_CHILD_SPACE);
4443       break;
4444     }
4445   
4446   return FALSE;
4447 }
4448
4449 static gboolean
4450 ignore_show_and_hide_all (ToolbarContent *content)
4451 {
4452   if (content->type == COMPATIBILITY)
4453     {
4454       GtkToolbarChildType type = content->u.compatibility.child.type;
4455       
4456       if (type == GTK_TOOLBAR_CHILD_BUTTON ||
4457           type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
4458           type == GTK_TOOLBAR_CHILD_RADIOBUTTON)
4459         {
4460           return TRUE;
4461         }
4462     }
4463   
4464   return FALSE;
4465 }
4466
4467 static void
4468 toolbar_content_show_all (ToolbarContent  *content)
4469 {
4470   GtkWidget *widget;
4471   
4472   if (ignore_show_and_hide_all (content))
4473     return;
4474
4475   widget = toolbar_content_get_widget (content);
4476   if (widget)
4477     gtk_widget_show_all (widget);
4478 }
4479
4480 static void
4481 toolbar_content_hide_all (ToolbarContent  *content)
4482 {
4483   GtkWidget *widget;
4484   
4485   if (ignore_show_and_hide_all (content))
4486     return;
4487
4488   widget = toolbar_content_get_widget (content);
4489   if (widget)
4490     gtk_widget_hide_all (widget);
4491 }
4492
4493 /*
4494  * Getters
4495  */
4496 static gint
4497 get_space_size (GtkToolbar *toolbar)
4498 {
4499   gint space_size = DEFAULT_SPACE_SIZE;
4500   
4501   if (toolbar)
4502     {
4503       gtk_widget_style_get (GTK_WIDGET (toolbar),
4504                             "space_size", &space_size,
4505                             NULL);
4506     }
4507   
4508   return space_size;
4509 }
4510
4511 static GtkToolbarSpaceStyle
4512 get_space_style (GtkToolbar *toolbar)
4513 {
4514   GtkToolbarSpaceStyle space_style = DEFAULT_SPACE_STYLE;
4515
4516   if (toolbar)
4517     {
4518       gtk_widget_style_get (GTK_WIDGET (toolbar),
4519                             "space_style", &space_style,
4520                             NULL);
4521     }
4522   
4523   return space_style;  
4524 }
4525
4526 static GtkReliefStyle
4527 get_button_relief (GtkToolbar *toolbar)
4528 {
4529   GtkReliefStyle button_relief = GTK_RELIEF_NORMAL;
4530   
4531   gtk_widget_ensure_style (GTK_WIDGET (toolbar));
4532   
4533   gtk_widget_style_get (GTK_WIDGET (toolbar),
4534                         "button_relief", &button_relief,
4535                         NULL);
4536   
4537   return button_relief;
4538 }
4539
4540 static gint
4541 get_internal_padding (GtkToolbar *toolbar)
4542 {
4543   gint ipadding = 0;
4544   
4545   gtk_widget_style_get (GTK_WIDGET (toolbar),
4546                         "internal_padding", &ipadding,
4547                         NULL);
4548   
4549   return ipadding;
4550 }
4551
4552 static GtkShadowType
4553 get_shadow_type (GtkToolbar *toolbar)
4554 {
4555   GtkShadowType shadow_type;
4556   
4557   gtk_widget_style_get (GTK_WIDGET (toolbar),
4558                         "shadow_type", &shadow_type,
4559                         NULL);
4560   
4561   return shadow_type;
4562 }
4563
4564 /*
4565  * API checks
4566  */
4567 static gboolean
4568 gtk_toolbar_check_old_api (GtkToolbar *toolbar)
4569 {
4570   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4571   
4572   if (priv->api_mode == NEW_API)
4573     {
4574       g_warning ("mixing deprecated and non-deprecated GtkToolbar API is not allowed");
4575       return FALSE;
4576     }
4577   
4578   priv->api_mode = OLD_API;
4579   return TRUE;
4580 }
4581
4582 static gboolean
4583 gtk_toolbar_check_new_api (GtkToolbar *toolbar)
4584 {
4585   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4586   
4587   if (priv->api_mode == OLD_API)
4588     {
4589       g_warning ("mixing deprecated and non-deprecated GtkToolbar API is not allowed");
4590       return FALSE;
4591     }
4592   
4593   priv->api_mode = NEW_API;
4594   return TRUE;
4595 }