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