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