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