]> Pileus Git - ~andy/gtk/blob - gtk/gtktoolbar.c
Replace non-deprecated API using old tooltips API, deprecate old tooltips
[~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   if (container->focus_child &&
1926       gtk_widget_child_focus (container->focus_child, dir))
1927     {
1928       return;
1929     }
1930   
1931   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1932   
1933   for (list = children; list != NULL; list = list->next)
1934     {
1935       GtkWidget *child = list->data;
1936       
1937       if (try_focus && GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir))
1938         break;
1939       
1940       if (child == GTK_CONTAINER (toolbar)->focus_child)
1941         try_focus = TRUE;
1942     }
1943   
1944   g_list_free (children);
1945 }
1946
1947 /* The focus handler for the toolbar. It called when the user presses
1948  * TAB or otherwise tries to focus the toolbar.
1949  */
1950 static gboolean
1951 gtk_toolbar_focus (GtkWidget        *widget,
1952                    GtkDirectionType  dir)
1953 {
1954   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1955   GList *children, *list;
1956   gboolean result = FALSE;
1957
1958   /* if focus is already somewhere inside the toolbar then return FALSE.
1959    * The only way focus can stay inside the toolbar is when the user presses
1960    * arrow keys or Ctrl TAB (both of which are handled by the
1961    * gtk_toolbar_move_focus() keybinding function.
1962    */
1963   if (GTK_CONTAINER (widget)->focus_child)
1964     return FALSE;
1965
1966   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1967
1968   for (list = children; list != NULL; list = list->next)
1969     {
1970       GtkWidget *child = list->data;
1971       
1972       if (GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir))
1973         {
1974           result = TRUE;
1975           break;
1976         }
1977     }
1978
1979   g_list_free (children);
1980
1981   return result;
1982 }
1983
1984 static GtkSettings *
1985 toolbar_get_settings (GtkToolbar *toolbar)
1986 {
1987   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1988   return priv->settings;
1989 }
1990
1991 static void
1992 style_change_notify (GtkToolbar *toolbar)
1993 {
1994   if (!toolbar->style_set)
1995     {
1996       /* pretend it was set, then unset, thus reverting to new default */
1997       toolbar->style_set = TRUE;
1998       gtk_toolbar_unset_style (toolbar);
1999     }
2000 }
2001
2002 static void
2003 icon_size_change_notify (GtkToolbar *toolbar)
2004 {
2005   if (!toolbar->icon_size_set)
2006     {
2007       /* pretend it was set, then unset, thus reverting to new default */
2008       toolbar->icon_size_set = TRUE;
2009       gtk_toolbar_unset_icon_size (toolbar);
2010     }
2011 }
2012
2013 static void
2014 animation_change_notify (GtkToolbar *toolbar)
2015 {
2016   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2017   GtkSettings *settings = toolbar_get_settings (toolbar);
2018   gboolean animation;
2019
2020   if (settings)
2021     g_object_get (settings,
2022                   "gtk-enable-animations", &animation,
2023                   NULL);
2024   else
2025     animation = DEFAULT_ANIMATION_STATE;
2026
2027   priv->animation = animation;
2028 }
2029
2030 static void
2031 settings_change_notify (GtkSettings      *settings,
2032                         const GParamSpec *pspec,
2033                         GtkToolbar       *toolbar)
2034 {
2035   if (! strcmp (pspec->name, "gtk-toolbar-style"))
2036     style_change_notify (toolbar);
2037   else if (! strcmp (pspec->name, "gtk-toolbar-icon-size"))
2038     icon_size_change_notify (toolbar);
2039   else if (! strcmp (pspec->name, "gtk-enable-animations"))
2040     animation_change_notify (toolbar);
2041 }
2042
2043 static void
2044 gtk_toolbar_screen_changed (GtkWidget *widget,
2045                             GdkScreen *previous_screen)
2046 {
2047   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
2048   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
2049   GtkSettings *old_settings = toolbar_get_settings (toolbar);
2050   GtkSettings *settings;
2051   
2052   if (gtk_widget_has_screen (GTK_WIDGET (toolbar)))
2053     settings = gtk_widget_get_settings (GTK_WIDGET (toolbar));
2054   else
2055     settings = NULL;
2056   
2057   if (settings == old_settings)
2058     return;
2059   
2060   if (old_settings)
2061     {
2062       g_signal_handler_disconnect (old_settings, priv->settings_connection);
2063
2064       g_object_unref (old_settings);
2065     }
2066
2067   if (settings)
2068     {
2069       priv->settings_connection =
2070         g_signal_connect (settings, "notify",
2071                           G_CALLBACK (settings_change_notify),
2072                           toolbar);
2073
2074       priv->settings = g_object_ref (settings);
2075     }
2076   else
2077     priv->settings = NULL;
2078
2079   style_change_notify (toolbar);
2080   icon_size_change_notify (toolbar);
2081   animation_change_notify (toolbar);
2082 }
2083
2084 static int
2085 find_drop_index (GtkToolbar *toolbar,
2086                  gint        x,
2087                  gint        y)
2088 {
2089   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2090   GList *interesting_content;
2091   GList *list;
2092   GtkOrientation orientation;
2093   GtkTextDirection direction;
2094   gint best_distance = G_MAXINT;
2095   gint distance;
2096   gint cursor;
2097   gint pos;
2098   ToolbarContent *best_content;
2099   GtkAllocation allocation;
2100   
2101   /* list items we care about wrt. drag and drop */
2102   interesting_content = NULL;
2103   for (list = priv->content; list != NULL; list = list->next)
2104     {
2105       ToolbarContent *content = list->data;
2106       
2107       if (toolbar_content_get_state (content) == NORMAL)
2108         interesting_content = g_list_prepend (interesting_content, content);
2109     }
2110   interesting_content = g_list_reverse (interesting_content);
2111   
2112   if (!interesting_content)
2113     return 0;
2114   
2115   orientation = toolbar->orientation;
2116   direction = gtk_widget_get_direction (GTK_WIDGET (toolbar));
2117   
2118   /* distance to first interesting item */
2119   best_content = interesting_content->data;
2120   toolbar_content_get_allocation (best_content, &allocation);
2121   
2122   if (orientation == GTK_ORIENTATION_HORIZONTAL)
2123     {
2124       cursor = x;
2125       
2126       if (direction == GTK_TEXT_DIR_LTR)
2127         pos = allocation.x;
2128       else
2129         pos = allocation.x + allocation.width;
2130     }
2131   else
2132     {
2133       cursor = y;
2134       pos = allocation.y;
2135     }
2136   
2137   best_content = NULL;
2138   best_distance = ABS (pos - cursor);
2139   
2140   /* distance to far end of each item */
2141   for (list = interesting_content; list != NULL; list = list->next)
2142     {
2143       ToolbarContent *content = list->data;
2144       
2145       toolbar_content_get_allocation (content, &allocation);
2146       
2147       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2148         {
2149           if (direction == GTK_TEXT_DIR_LTR)
2150             pos = allocation.x + allocation.width;
2151           else
2152             pos = allocation.x;
2153         }
2154       else
2155         {
2156           pos = allocation.y + allocation.height;
2157         }
2158       
2159       distance = ABS (pos - cursor);
2160       
2161       if (distance < best_distance)
2162         {
2163           best_distance = distance;
2164           best_content = content;
2165         }
2166     }
2167   
2168   g_list_free (interesting_content);
2169   
2170   if (!best_content)
2171     return 0;
2172   else
2173     return g_list_index (priv->content, best_content) + 1;
2174 }
2175
2176 static void
2177 reset_all_placeholders (GtkToolbar *toolbar)
2178 {
2179   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2180   GList *list;
2181   
2182   for (list = priv->content; list != NULL; list = list->next)
2183     {
2184       ToolbarContent *content = list->data;
2185       if (toolbar_content_is_placeholder (content))
2186         toolbar_content_set_disappearing (content, TRUE);
2187     }
2188 }
2189
2190 static gint
2191 physical_to_logical (GtkToolbar *toolbar,
2192                      gint        physical)
2193 {
2194   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2195   GList *list;
2196   int logical;
2197   
2198   g_assert (physical >= 0);
2199   
2200   logical = 0;
2201   for (list = priv->content; list && physical > 0; list = list->next)
2202     {
2203       ToolbarContent *content = list->data;
2204       
2205       if (!toolbar_content_is_placeholder (content))
2206         logical++;
2207       physical--;
2208     }
2209   
2210   g_assert (physical == 0);
2211   
2212   return logical;
2213 }
2214
2215 static gint
2216 logical_to_physical (GtkToolbar *toolbar,
2217                      gint        logical)
2218 {
2219   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2220   GList *list;
2221   gint physical;
2222   
2223   g_assert (logical >= 0);
2224   
2225   physical = 0;
2226   for (list = priv->content; list; list = list->next)
2227     {
2228       ToolbarContent *content = list->data;
2229       
2230       if (!toolbar_content_is_placeholder (content))
2231         {
2232           if (logical == 0)
2233             break;
2234           logical--;
2235         }
2236       
2237       physical++;
2238     }
2239   
2240   g_assert (logical == 0);
2241   
2242   return physical;
2243 }
2244
2245 /**
2246  * gtk_toolbar_set_drop_highlight_item:
2247  * @toolbar: a #GtkToolbar
2248  * @tool_item: a #GtkToolItem, or %NULL to turn of highlighting
2249  * @index_: a position on @toolbar
2250  * 
2251  * Highlights @toolbar to give an idea of what it would look like
2252  * if @item was added to @toolbar at the position indicated by @index_. 
2253  * If @item is %NULL, highlighting is turned off. In that case @index_ 
2254  * is ignored.
2255  *
2256  * The @tool_item passed to this function must not be part of any widget
2257  * hierarchy. When an item is set as drop highlight item it can not
2258  * added to any widget hierarchy or used as highlight item for another
2259  * toolbar.
2260  * 
2261  * Since: 2.4
2262  **/
2263 void
2264 gtk_toolbar_set_drop_highlight_item (GtkToolbar  *toolbar,
2265                                      GtkToolItem *tool_item,
2266                                      gint         index_)
2267 {
2268   ToolbarContent *content;
2269   GtkToolbarPrivate *priv;
2270   gint n_items;
2271   GtkRequisition requisition;
2272   GtkRequisition old_requisition;
2273   gboolean restart_sliding;
2274   
2275   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2276   g_return_if_fail (tool_item == NULL || GTK_IS_TOOL_ITEM (tool_item));
2277   
2278   gtk_toolbar_check_new_api (toolbar);
2279   
2280   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2281   
2282   if (!tool_item)
2283     {
2284       if (priv->highlight_tool_item)
2285         {
2286           gtk_widget_unparent (GTK_WIDGET (priv->highlight_tool_item));
2287           g_object_unref (priv->highlight_tool_item);
2288           priv->highlight_tool_item = NULL;
2289         }
2290       
2291       reset_all_placeholders (toolbar);
2292       gtk_toolbar_begin_sliding (toolbar);
2293       return;
2294     }
2295   
2296   n_items = gtk_toolbar_get_n_items (toolbar);
2297   if (index_ < 0 || index_ > n_items)
2298     index_ = n_items;
2299   
2300   if (tool_item != priv->highlight_tool_item)
2301     {
2302       if (priv->highlight_tool_item)
2303         g_object_unref (priv->highlight_tool_item);
2304       
2305       g_object_ref_sink (tool_item);
2306       
2307       priv->highlight_tool_item = tool_item;
2308       
2309       gtk_widget_set_parent (GTK_WIDGET (priv->highlight_tool_item),
2310                              GTK_WIDGET (toolbar));
2311     }
2312   
2313   index_ = logical_to_physical (toolbar, index_);
2314   
2315   content = g_list_nth_data (priv->content, index_);
2316   
2317   if (index_ > 0)
2318     {
2319       ToolbarContent *prev_content;
2320       
2321       prev_content = g_list_nth_data (priv->content, index_ - 1);
2322       
2323       if (prev_content && toolbar_content_is_placeholder (prev_content))
2324         content = prev_content;
2325     }
2326   
2327   if (!content || !toolbar_content_is_placeholder (content))
2328     {
2329       GtkWidget *placeholder;
2330       
2331       placeholder = GTK_WIDGET (gtk_separator_tool_item_new ());
2332
2333       content = toolbar_content_new_tool_item (toolbar,
2334                                                GTK_TOOL_ITEM (placeholder),
2335                                                TRUE, index_);
2336       gtk_widget_show (placeholder);
2337     }
2338   
2339   g_assert (content);
2340   g_assert (toolbar_content_is_placeholder (content));
2341   
2342   gtk_widget_size_request (GTK_WIDGET (priv->highlight_tool_item),
2343                            &requisition);
2344
2345   toolbar_content_set_expand (content, gtk_tool_item_get_expand (tool_item));
2346   
2347   restart_sliding = FALSE;
2348   toolbar_content_size_request (content, toolbar, &old_requisition);
2349   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2350     {
2351       requisition.height = -1;
2352       if (requisition.width != old_requisition.width)
2353         restart_sliding = TRUE;
2354     }
2355   else
2356     {
2357       requisition.width = -1;
2358       if (requisition.height != old_requisition.height)
2359         restart_sliding = TRUE;
2360     }
2361
2362   if (toolbar_content_disappearing (content))
2363     restart_sliding = TRUE;
2364   
2365   reset_all_placeholders (toolbar);
2366   toolbar_content_set_disappearing (content, FALSE);
2367   
2368   toolbar_content_set_size_request (content,
2369                                     requisition.width, requisition.height);
2370   
2371   if (restart_sliding)
2372     gtk_toolbar_begin_sliding (toolbar);
2373 }
2374
2375 static void
2376 gtk_toolbar_get_child_property (GtkContainer *container,
2377                                 GtkWidget    *child,
2378                                 guint         property_id,
2379                                 GValue       *value,
2380                                 GParamSpec   *pspec)
2381 {
2382   GtkToolItem *item = GTK_TOOL_ITEM (child);
2383   
2384   switch (property_id)
2385     {
2386     case CHILD_PROP_HOMOGENEOUS:
2387       g_value_set_boolean (value, gtk_tool_item_get_homogeneous (item));
2388       break;
2389       
2390     case CHILD_PROP_EXPAND:
2391       g_value_set_boolean (value, gtk_tool_item_get_expand (item));
2392       break;
2393       
2394     default:
2395       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2396       break;
2397     }
2398 }
2399
2400 static void
2401 gtk_toolbar_set_child_property (GtkContainer *container,
2402                                 GtkWidget    *child,
2403                                 guint         property_id,
2404                                 const GValue *value,
2405                                 GParamSpec   *pspec)
2406 {
2407   switch (property_id)
2408     {
2409     case CHILD_PROP_HOMOGENEOUS:
2410       gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2411       break;
2412       
2413     case CHILD_PROP_EXPAND:
2414       gtk_tool_item_set_expand (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2415       break;
2416       
2417     default:
2418       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2419       break;
2420     }
2421 }
2422
2423 static void
2424 gtk_toolbar_show_all (GtkWidget *widget)
2425 {
2426   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
2427   GList *list;
2428
2429   for (list = priv->content; list != NULL; list = list->next)
2430     {
2431       ToolbarContent *content = list->data;
2432       
2433       toolbar_content_show_all (content);
2434     }
2435   
2436   gtk_widget_show (widget);
2437 }
2438
2439 static void
2440 gtk_toolbar_hide_all (GtkWidget *widget)
2441 {
2442   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
2443   GList *list;
2444
2445   for (list = priv->content; list != NULL; list = list->next)
2446     {
2447       ToolbarContent *content = list->data;
2448       
2449       toolbar_content_hide_all (content);
2450     }
2451
2452   gtk_widget_hide (widget);
2453 }
2454
2455 static void
2456 gtk_toolbar_add (GtkContainer *container,
2457                  GtkWidget    *widget)
2458 {
2459   GtkToolbar *toolbar;
2460   
2461   g_return_if_fail (GTK_IS_TOOLBAR (container));
2462   g_return_if_fail (widget != NULL);
2463   
2464   toolbar = GTK_TOOLBAR (container);
2465   
2466   if (GTK_IS_TOOL_ITEM (widget))
2467     gtk_toolbar_insert (toolbar, GTK_TOOL_ITEM (widget), -1);
2468   else
2469     gtk_toolbar_append_widget (toolbar, widget, NULL, NULL);
2470 }
2471
2472 static void
2473 gtk_toolbar_remove (GtkContainer *container,
2474                     GtkWidget    *widget)
2475 {
2476   GtkToolbar *toolbar;
2477   GtkToolbarPrivate *priv;
2478   ToolbarContent *content_to_remove;
2479   GList *list;
2480   
2481   g_return_if_fail (GTK_IS_TOOLBAR (container));
2482   g_return_if_fail (GTK_IS_WIDGET (widget));
2483   
2484   toolbar = GTK_TOOLBAR (container);
2485   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2486   
2487   content_to_remove = NULL;
2488   for (list = priv->content; list != NULL; list = list->next)
2489     {
2490       ToolbarContent *content = list->data;
2491       GtkWidget *child;
2492       
2493       child = toolbar_content_get_widget (content);
2494       if (child && child == widget)
2495         {
2496           content_to_remove = content;
2497           break;
2498         }
2499     }
2500   
2501   g_return_if_fail (content_to_remove != NULL);
2502   
2503   toolbar_content_remove (content_to_remove, toolbar);
2504   toolbar_content_free (content_to_remove);
2505 }
2506
2507 static void
2508 gtk_toolbar_forall (GtkContainer *container,
2509                     gboolean      include_internals,
2510                     GtkCallback   callback,
2511                     gpointer      callback_data)
2512 {
2513   GtkToolbar *toolbar = GTK_TOOLBAR (container);
2514   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2515   GList *list;
2516   
2517   g_return_if_fail (callback != NULL);
2518   
2519   list = priv->content;
2520   while (list)
2521     {
2522       ToolbarContent *content = list->data;
2523       GList *next = list->next;
2524       
2525       if (include_internals || !toolbar_content_is_placeholder (content))
2526         {
2527           GtkWidget *child = toolbar_content_get_widget (content);
2528           
2529           if (child)
2530             (*callback) (child, callback_data);
2531         }
2532       
2533       list = next;
2534     }
2535   
2536   if (include_internals)
2537     (* callback) (priv->arrow_button, callback_data);
2538 }
2539
2540 static GType
2541 gtk_toolbar_child_type (GtkContainer *container)
2542 {
2543   return GTK_TYPE_TOOL_ITEM;
2544 }
2545
2546 static void
2547 gtk_toolbar_reconfigured (GtkToolbar *toolbar)
2548 {
2549   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2550   GList *list;
2551   
2552   list = priv->content;
2553   while (list)
2554     {
2555       ToolbarContent *content = list->data;
2556       GList *next = list->next;
2557       
2558       toolbar_content_toolbar_reconfigured (content, toolbar);
2559       
2560       list = next;
2561     }
2562 }
2563
2564 static void
2565 gtk_toolbar_orientation_changed (GtkToolbar    *toolbar,
2566                                  GtkOrientation orientation)
2567 {
2568   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2569   if (toolbar->orientation != orientation)
2570     {
2571       toolbar->orientation = orientation;
2572       
2573       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2574         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
2575       else
2576         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
2577       
2578       gtk_toolbar_reconfigured (toolbar);
2579       
2580       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2581       g_object_notify (G_OBJECT (toolbar), "orientation");
2582     }
2583 }
2584
2585 static void
2586 gtk_toolbar_real_style_changed (GtkToolbar     *toolbar,
2587                                 GtkToolbarStyle style)
2588 {
2589   if (toolbar->style != style)
2590     {
2591       toolbar->style = style;
2592       
2593       gtk_toolbar_reconfigured (toolbar);
2594       
2595       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2596       g_object_notify (G_OBJECT (toolbar), "toolbar-style");
2597     }
2598 }
2599
2600 static void
2601 menu_position_func (GtkMenu  *menu,
2602                     gint     *x,
2603                     gint     *y,
2604                     gboolean *push_in,
2605                     gpointer  user_data)
2606 {
2607   GtkToolbar *toolbar = GTK_TOOLBAR (user_data);
2608   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2609   GtkRequisition req;
2610   GtkRequisition menu_req;
2611   GdkRectangle monitor;
2612   gint monitor_num;
2613   GdkScreen *screen;
2614   
2615   gtk_widget_size_request (priv->arrow_button, &req);
2616   gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
2617   
2618   screen = gtk_widget_get_screen (GTK_WIDGET (menu));
2619   monitor_num = gdk_screen_get_monitor_at_window (screen, priv->arrow_button->window);
2620   if (monitor_num < 0)
2621     monitor_num = 0;
2622   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
2623
2624   gdk_window_get_origin (GTK_BUTTON (priv->arrow_button)->event_window, x, y);
2625   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2626     {
2627       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2628         *x += priv->arrow_button->allocation.width - req.width;
2629       else 
2630         *x += req.width - menu_req.width;
2631
2632       if ((*y + priv->arrow_button->allocation.height + menu_req.height) <= monitor.y + monitor.height)
2633         *y += priv->arrow_button->allocation.height;
2634       else if ((*y - menu_req.height) >= monitor.y)
2635         *y -= menu_req.height;
2636       else if (monitor.y + monitor.height - (*y + priv->arrow_button->allocation.height) > *y)
2637         *y += priv->arrow_button->allocation.height;
2638       else
2639         *y -= menu_req.height;
2640     }
2641   else 
2642     {
2643       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2644         *x += priv->arrow_button->allocation.width;
2645       else 
2646         *x -= menu_req.width;
2647
2648       if (*y + menu_req.height > monitor.y + monitor.height &&
2649           *y + priv->arrow_button->allocation.height - monitor.y > monitor.y + monitor.height - *y)
2650         *y += priv->arrow_button->allocation.height - menu_req.height;
2651     }
2652
2653   *push_in = FALSE;
2654 }
2655
2656 static void
2657 show_menu (GtkToolbar     *toolbar,
2658            GdkEventButton *event)
2659 {
2660   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2661
2662   rebuild_menu (toolbar);
2663
2664   gtk_widget_show_all (GTK_WIDGET (priv->menu));
2665
2666   gtk_menu_popup (priv->menu, NULL, NULL,
2667                   menu_position_func, toolbar,
2668                   event? event->button : 0,
2669                   event? event->time : gtk_get_current_event_time());
2670 }
2671
2672 static void
2673 gtk_toolbar_arrow_button_clicked (GtkWidget  *button,
2674                                   GtkToolbar *toolbar)
2675 {
2676   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);  
2677   
2678   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->arrow_button)) &&
2679       (!priv->menu || !GTK_WIDGET_VISIBLE (priv->menu)))
2680     {
2681       /* We only get here when the button is clicked with the keyboard,
2682        * because mouse button presses result in the menu being shown so
2683        * that priv->menu would be non-NULL and visible.
2684        */
2685       show_menu (toolbar, NULL);
2686       gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2687     }
2688 }
2689
2690 static gboolean
2691 gtk_toolbar_arrow_button_press (GtkWidget      *button,
2692                                 GdkEventButton *event,
2693                                 GtkToolbar     *toolbar)
2694 {
2695   show_menu (toolbar, event);
2696   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2697   
2698   return TRUE;
2699 }
2700
2701 static gboolean
2702 gtk_toolbar_button_press (GtkWidget      *toolbar,
2703                           GdkEventButton *event)
2704 {
2705   if (event->button == 3)
2706     {
2707       gboolean return_value;
2708       
2709       g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2710                      (int)event->x_root, (int)event->y_root, event->button,
2711                      &return_value);
2712       
2713       return return_value;
2714     }
2715   
2716   return FALSE;
2717 }
2718
2719 static gboolean
2720 gtk_toolbar_popup_menu (GtkWidget *toolbar)
2721 {
2722   gboolean return_value;
2723   /* This function is the handler for the "popup menu" keybinding,
2724    * ie., it is called when the user presses Shift F10
2725    */
2726   g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2727                  -1, -1, -1, &return_value);
2728   
2729   return return_value;
2730 }
2731
2732 /**
2733  * gtk_toolbar_new:
2734  * 
2735  * Creates a new toolbar. 
2736  
2737  * Return Value: the newly-created toolbar.
2738  **/
2739 GtkWidget *
2740 gtk_toolbar_new (void)
2741 {
2742   GtkToolbar *toolbar;
2743   
2744   toolbar = g_object_new (GTK_TYPE_TOOLBAR, NULL);
2745   
2746   return GTK_WIDGET (toolbar);
2747 }
2748
2749 /**
2750  * gtk_toolbar_insert:
2751  * @toolbar: a #GtkToolbar
2752  * @item: a #GtkToolItem
2753  * @pos: the position of the new item
2754  *
2755  * Insert a #GtkToolItem into the toolbar at position @pos. If @pos is
2756  * 0 the item is prepended to the start of the toolbar. If @pos is
2757  * negative, the item is appended to the end of the toolbar.
2758  *
2759  * Since: 2.4
2760  **/
2761 void
2762 gtk_toolbar_insert (GtkToolbar  *toolbar,
2763                     GtkToolItem *item,
2764                     gint         pos)
2765 {
2766   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2767   g_return_if_fail (GTK_IS_TOOL_ITEM (item));
2768   
2769   if (!gtk_toolbar_check_new_api (toolbar))
2770     return;
2771   
2772   if (pos >= 0)
2773     pos = logical_to_physical (toolbar, pos);
2774
2775   toolbar_content_new_tool_item (toolbar, item, FALSE, pos);
2776 }
2777
2778 /**
2779  * gtk_toolbar_get_item_index:
2780  * @toolbar: a #GtkToolbar
2781  * @item: a #GtkToolItem that is a child of @toolbar
2782  * 
2783  * Returns the position of @item on the toolbar, starting from 0.
2784  * It is an error if @item is not a child of the toolbar.
2785  * 
2786  * Return value: the position of item on the toolbar.
2787  * 
2788  * Since: 2.4
2789  **/
2790 gint
2791 gtk_toolbar_get_item_index (GtkToolbar  *toolbar,
2792                             GtkToolItem *item)
2793 {
2794   GtkToolbarPrivate *priv;
2795   GList *list;
2796   int n;
2797   
2798   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2799   g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1);
2800   g_return_val_if_fail (GTK_WIDGET (item)->parent == GTK_WIDGET (toolbar), -1);
2801   
2802   if (!gtk_toolbar_check_new_api (toolbar))
2803     return -1;
2804   
2805   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2806   
2807   n = 0;
2808   for (list = priv->content; list != NULL; list = list->next)
2809     {
2810       ToolbarContent *content = list->data;
2811       GtkWidget *widget;
2812       
2813       widget = toolbar_content_get_widget (content);
2814       
2815       if (item == GTK_TOOL_ITEM (widget))
2816         break;
2817       
2818       ++n;
2819     }
2820   
2821   return physical_to_logical (toolbar, n);
2822 }
2823
2824 /**
2825  * gtk_toolbar_set_orientation:
2826  * @toolbar: a #GtkToolbar.
2827  * @orientation: a new #GtkOrientation.
2828  * 
2829  * Sets whether a toolbar should appear horizontally or vertically.
2830  **/
2831 void
2832 gtk_toolbar_set_orientation (GtkToolbar     *toolbar,
2833                              GtkOrientation  orientation)
2834 {
2835   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2836   
2837   g_signal_emit (toolbar, toolbar_signals[ORIENTATION_CHANGED], 0, orientation);
2838 }
2839
2840 /**
2841  * gtk_toolbar_get_orientation:
2842  * @toolbar: a #GtkToolbar
2843  * 
2844  * Retrieves the current orientation of the toolbar. See
2845  * gtk_toolbar_set_orientation().
2846  *
2847  * Return value: the orientation
2848  **/
2849 GtkOrientation
2850 gtk_toolbar_get_orientation (GtkToolbar *toolbar)
2851 {
2852   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL);
2853   
2854   return toolbar->orientation;
2855 }
2856
2857 /**
2858  * gtk_toolbar_set_style:
2859  * @toolbar: a #GtkToolbar.
2860  * @style: the new style for @toolbar.
2861  * 
2862  * Alters the view of @toolbar to display either icons only, text only, or both.
2863  **/
2864 void
2865 gtk_toolbar_set_style (GtkToolbar      *toolbar,
2866                        GtkToolbarStyle  style)
2867 {
2868   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2869   
2870   toolbar->style_set = TRUE;  
2871   g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2872 }
2873
2874 /**
2875  * gtk_toolbar_get_style:
2876  * @toolbar: a #GtkToolbar
2877  *
2878  * Retrieves whether the toolbar has text, icons, or both . See
2879  * gtk_toolbar_set_style().
2880  
2881  * Return value: the current style of @toolbar
2882  **/
2883 GtkToolbarStyle
2884 gtk_toolbar_get_style (GtkToolbar *toolbar)
2885 {
2886   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE);
2887   
2888   return toolbar->style;
2889 }
2890
2891 /**
2892  * gtk_toolbar_unset_style:
2893  * @toolbar: a #GtkToolbar
2894  * 
2895  * Unsets a toolbar style set with gtk_toolbar_set_style(), so that
2896  * user preferences will be used to determine the toolbar style.
2897  **/
2898 void
2899 gtk_toolbar_unset_style (GtkToolbar *toolbar)
2900 {
2901   GtkToolbarStyle style;
2902   
2903   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2904   
2905   if (toolbar->style_set)
2906     {
2907       GtkSettings *settings = toolbar_get_settings (toolbar);
2908       
2909       if (settings)
2910         g_object_get (settings,
2911                       "gtk-toolbar-style", &style,
2912                       NULL);
2913       else
2914         style = DEFAULT_TOOLBAR_STYLE;
2915       
2916       if (style != toolbar->style)
2917         g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2918       
2919       toolbar->style_set = FALSE;
2920     }
2921 }
2922
2923 /**
2924  * gtk_toolbar_set_tooltips:
2925  * @toolbar: a #GtkToolbar.
2926  * @enable: set to %FALSE to disable the tooltips, or %TRUE to enable them.
2927  * 
2928  * Sets if the tooltips of a toolbar should be active or not.
2929  **/
2930 void
2931 gtk_toolbar_set_tooltips (GtkToolbar *toolbar,
2932                           gboolean    enable)
2933 {
2934   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2935   
2936   if (enable)
2937     gtk_tooltips_enable (toolbar->tooltips);
2938   else
2939     gtk_tooltips_disable (toolbar->tooltips);
2940
2941   g_object_notify (G_OBJECT (toolbar), "tooltips");
2942 }
2943
2944 /**
2945  * gtk_toolbar_get_tooltips:
2946  * @toolbar: a #GtkToolbar
2947  *
2948  * Retrieves whether tooltips are enabled. See
2949  * gtk_toolbar_set_tooltips().
2950  *
2951  * Return value: %TRUE if tooltips are enabled
2952  **/
2953 gboolean
2954 gtk_toolbar_get_tooltips (GtkToolbar *toolbar)
2955 {
2956   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2957   
2958   return TRUE;
2959 }
2960
2961 /**
2962  * gtk_toolbar_get_n_items:
2963  * @toolbar: a #GtkToolbar
2964  * 
2965  * Returns the number of items on the toolbar.
2966  * 
2967  * Return value: the number of items on the toolbar
2968  * 
2969  * Since: 2.4
2970  **/
2971 gint
2972 gtk_toolbar_get_n_items (GtkToolbar *toolbar)
2973 {
2974   GtkToolbarPrivate *priv;
2975   
2976   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2977   
2978   if (!gtk_toolbar_check_new_api (toolbar))
2979     return -1;
2980   
2981   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2982   
2983   return physical_to_logical (toolbar, g_list_length (priv->content));
2984 }
2985
2986 /**
2987  * gtk_toolbar_get_nth_item:
2988  * @toolbar: a #GtkToolbar
2989  * @n: A position on the toolbar
2990  *
2991  * Returns the @n<!-- -->'th item on @toolbar, or %NULL if the
2992  * toolbar does not contain an @n<!-- -->'th item.
2993  * 
2994  * Return value: The @n<!-- -->'th #GtkToolItem on @toolbar, or %NULL if there
2995  * isn't an @n<!-- -->'th item.
2996  * 
2997  * Since: 2.4
2998  **/
2999 GtkToolItem *
3000 gtk_toolbar_get_nth_item (GtkToolbar *toolbar,
3001                           gint        n)
3002 {
3003   GtkToolbarPrivate *priv;
3004   ToolbarContent *content;
3005   gint n_items;
3006   
3007   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
3008   
3009   if (!gtk_toolbar_check_new_api (toolbar))
3010     return NULL;
3011   
3012   n_items = gtk_toolbar_get_n_items (toolbar);
3013   
3014   if (n < 0 || n >= n_items)
3015     return NULL;
3016   
3017   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3018   
3019   content = g_list_nth_data (priv->content, logical_to_physical (toolbar, n));
3020   
3021   g_assert (content);
3022   g_assert (!toolbar_content_is_placeholder (content));
3023   
3024   return GTK_TOOL_ITEM (toolbar_content_get_widget (content));
3025 }
3026
3027 /**
3028  * gtk_toolbar_get_icon_size:
3029  * @toolbar: a #GtkToolbar
3030  *
3031  * Retrieves the icon size for the toolbar. See gtk_toolbar_set_icon_size().
3032  *
3033  * Return value: the current icon size for the icons on the toolbar.
3034  **/
3035 GtkIconSize
3036 gtk_toolbar_get_icon_size (GtkToolbar *toolbar)
3037 {
3038   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_ICON_SIZE);
3039   
3040   return toolbar->icon_size;
3041 }
3042
3043 /**
3044  * gtk_toolbar_get_relief_style:
3045  * @toolbar: a #GtkToolbar
3046  * 
3047  * Returns the relief style of buttons on @toolbar. See
3048  * gtk_button_set_relief().
3049  * 
3050  * Return value: The relief style of buttons on @toolbar.
3051  * 
3052  * Since: 2.4
3053  **/
3054 GtkReliefStyle
3055 gtk_toolbar_get_relief_style (GtkToolbar *toolbar)
3056 {
3057   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_RELIEF_NONE);
3058   
3059   return get_button_relief (toolbar);
3060 }
3061
3062 /**
3063  * gtk_toolbar_set_show_arrow:
3064  * @toolbar: a #GtkToolbar
3065  * @show_arrow: Whether to show an overflow menu
3066  * 
3067  * Sets whether to show an overflow menu when
3068  * @toolbar doesn't have room for all items on it. If %TRUE,
3069  * items that there are not room are available through an
3070  * overflow menu.
3071  * 
3072  * Since: 2.4
3073  **/
3074 void
3075 gtk_toolbar_set_show_arrow (GtkToolbar *toolbar,
3076                             gboolean    show_arrow)
3077 {
3078   GtkToolbarPrivate *priv;
3079   
3080   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3081   
3082   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3083   show_arrow = show_arrow != FALSE;
3084   
3085   if (priv->show_arrow != show_arrow)
3086     {
3087       priv->show_arrow = show_arrow;
3088       
3089       if (!priv->show_arrow)
3090         gtk_widget_hide (priv->arrow_button);
3091       
3092       gtk_widget_queue_resize (GTK_WIDGET (toolbar));      
3093       g_object_notify (G_OBJECT (toolbar), "show-arrow");
3094     }
3095 }
3096
3097 /**
3098  * gtk_toolbar_get_show_arrow:
3099  * @toolbar: a #GtkToolbar
3100  * 
3101  * Returns whether the toolbar has an overflow menu.
3102  * See gtk_toolbar_set_show_arrow().
3103  * 
3104  * Return value: %TRUE if the toolbar has an overflow menu.
3105  * 
3106  * Since: 2.4
3107  **/
3108 gboolean
3109 gtk_toolbar_get_show_arrow (GtkToolbar *toolbar)
3110 {
3111   GtkToolbarPrivate *priv;
3112   
3113   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
3114   
3115   if (!gtk_toolbar_check_new_api (toolbar))
3116     return FALSE;
3117   
3118   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3119   
3120   return priv->show_arrow;
3121 }
3122
3123 /**
3124  * gtk_toolbar_get_drop_index:
3125  * @toolbar: a #GtkToolbar
3126  * @x: x coordinate of a point on the toolbar
3127  * @y: y coordinate of a point on the toolbar
3128  *
3129  * Returns the position corresponding to the indicated point on
3130  * @toolbar. This is useful when dragging items to the toolbar:
3131  * this function returns the position a new item should be
3132  * inserted.
3133  *
3134  * @x and @y are in @toolbar coordinates.
3135  * 
3136  * Return value: The position corresponding to the point (@x, @y) on the toolbar.
3137  * 
3138  * Since: 2.4
3139  **/
3140 gint
3141 gtk_toolbar_get_drop_index (GtkToolbar *toolbar,
3142                             gint        x,
3143                             gint        y)
3144 {
3145   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
3146   
3147   if (!gtk_toolbar_check_new_api (toolbar))
3148     return -1;
3149   
3150   return physical_to_logical (toolbar, find_drop_index (toolbar, x, y));
3151 }
3152
3153 static void
3154 gtk_toolbar_finalize (GObject *object)
3155 {
3156   GList *list;
3157   GtkToolbar *toolbar = GTK_TOOLBAR (object);
3158   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3159   
3160   if (toolbar->tooltips)
3161     g_object_unref (toolbar->tooltips);
3162   
3163   if (priv->arrow_button)
3164     gtk_widget_unparent (priv->arrow_button);
3165
3166   for (list = priv->content; list != NULL; list = list->next)
3167     {
3168       ToolbarContent *content = list->data;
3169
3170       toolbar_content_free (content);
3171     }
3172   
3173   g_list_free (priv->content);
3174   g_list_free (toolbar->children);
3175   
3176   g_timer_destroy (priv->timer);
3177   
3178   if (priv->menu)
3179     gtk_widget_destroy (GTK_WIDGET (priv->menu));
3180   
3181   if (priv->idle_id)
3182     g_source_remove (priv->idle_id);
3183
3184   G_OBJECT_CLASS (gtk_toolbar_parent_class)->finalize (object);
3185 }
3186
3187 /**
3188  * gtk_toolbar_set_icon_size:
3189  * @toolbar: A #GtkToolbar
3190  * @icon_size: The #GtkIconSize that stock icons in the toolbar shall have.
3191  *
3192  * This function sets the size of stock icons in the toolbar. You
3193  * can call it both before you add the icons and after they've been
3194  * added. The size you set will override user preferences for the default
3195  * icon size.
3196  * 
3197  * This should only be used for special-purpose toolbars, normal
3198  * application toolbars should respect the user preferences for the
3199  * size of icons.
3200  **/
3201 void
3202 gtk_toolbar_set_icon_size (GtkToolbar  *toolbar,
3203                            GtkIconSize  icon_size)
3204 {
3205   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3206   g_return_if_fail (icon_size != GTK_ICON_SIZE_INVALID);
3207   
3208   if (!toolbar->icon_size_set)
3209     {
3210       toolbar->icon_size_set = TRUE;  
3211       g_object_notify (G_OBJECT (toolbar), "icon-size-set");
3212     }
3213
3214   if (toolbar->icon_size == icon_size)
3215     return;
3216   
3217   toolbar->icon_size = icon_size;
3218   g_object_notify (G_OBJECT (toolbar), "icon-size");
3219   
3220   gtk_toolbar_reconfigured (toolbar);
3221   
3222   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3223 }
3224
3225 /**
3226  * gtk_toolbar_unset_icon_size:
3227  * @toolbar: a #GtkToolbar
3228  * 
3229  * Unsets toolbar icon size set with gtk_toolbar_set_icon_size(), so that
3230  * user preferences will be used to determine the icon size.
3231  **/
3232 void
3233 gtk_toolbar_unset_icon_size (GtkToolbar *toolbar)
3234 {
3235   GtkIconSize size;
3236   
3237   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3238   
3239   if (toolbar->icon_size_set)
3240     {
3241       GtkSettings *settings = toolbar_get_settings (toolbar);
3242       
3243       if (settings)
3244         {
3245           g_object_get (settings,
3246                         "gtk-toolbar-icon-size", &size,
3247                         NULL);
3248         }
3249       else
3250         size = DEFAULT_ICON_SIZE;
3251       
3252       if (size != toolbar->icon_size)
3253         {
3254           gtk_toolbar_set_icon_size (toolbar, size);
3255           g_object_notify (G_OBJECT (toolbar), "icon-size");      
3256         }
3257       
3258       toolbar->icon_size_set = FALSE;
3259       g_object_notify (G_OBJECT (toolbar), "icon-size-set");      
3260     }
3261 }
3262
3263 /*
3264  * Deprecated API
3265  */
3266
3267 /**
3268  * gtk_toolbar_append_item:
3269  * @toolbar: a #GtkToolbar.
3270  * @text: give your toolbar button a label.
3271  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3272  * @tooltip_private_text: use with #GtkTipsQuery.
3273  * @icon: a #GtkWidget that should be used as the button's icon.
3274  * @callback: the function to be executed when the button is pressed.
3275  * @user_data: a pointer to any data you wish to be passed to the callback.
3276  * 
3277  * Inserts a new item into the toolbar. You must specify the position
3278  * in the toolbar where it will be inserted.
3279  *
3280  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3281  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3282  *
3283  * Return value: the new toolbar item as a #GtkWidget.
3284  **/
3285 GtkWidget *
3286 gtk_toolbar_append_item (GtkToolbar    *toolbar,
3287                          const char    *text,
3288                          const char    *tooltip_text,
3289                          const char    *tooltip_private_text,
3290                          GtkWidget     *icon,
3291                          GtkSignalFunc  callback,
3292                          gpointer       user_data)
3293 {
3294   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3295                                      NULL, text,
3296                                      tooltip_text, tooltip_private_text,
3297                                      icon, callback, user_data,
3298                                      toolbar->num_children);
3299 }
3300
3301 /**
3302  * gtk_toolbar_prepend_item:
3303  * @toolbar: a #GtkToolbar.
3304  * @text: give your toolbar button a label.
3305  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3306  * @tooltip_private_text: use with #GtkTipsQuery.
3307  * @icon: a #GtkWidget that should be used as the button's icon.
3308  * @callback: the function to be executed when the button is pressed.
3309  * @user_data: a pointer to any data you wish to be passed to the callback.
3310  * 
3311  * Adds a new button to the beginning (top or left edges) of the given toolbar.
3312  *
3313  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3314  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3315  *
3316  * Return value: the new toolbar item as a #GtkWidget.
3317  **/
3318 GtkWidget *
3319 gtk_toolbar_prepend_item (GtkToolbar    *toolbar,
3320                           const char    *text,
3321                           const char    *tooltip_text,
3322                           const char    *tooltip_private_text,
3323                           GtkWidget     *icon,
3324                           GtkSignalFunc  callback,
3325                           gpointer       user_data)
3326 {
3327   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3328                                      NULL, text,
3329                                      tooltip_text, tooltip_private_text,
3330                                      icon, callback, user_data,
3331                                      0);
3332 }
3333
3334 /**
3335  * gtk_toolbar_insert_item:
3336  * @toolbar: a #GtkToolbar.
3337  * @text: give your toolbar button a label.
3338  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3339  * @tooltip_private_text: use with #GtkTipsQuery.
3340  * @icon: a #GtkWidget that should be used as the button's icon.
3341  * @callback: the function to be executed when the button is pressed.
3342  * @user_data: a pointer to any data you wish to be passed to the callback.
3343  * @position: the number of widgets to insert this item after.
3344  * 
3345  * Inserts a new item into the toolbar. You must specify the position in the
3346  * toolbar where it will be inserted.
3347  *
3348  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3349  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3350  *
3351  * Return value: the new toolbar item as a #GtkWidget.
3352  **/
3353 GtkWidget *
3354 gtk_toolbar_insert_item (GtkToolbar    *toolbar,
3355                          const char    *text,
3356                          const char    *tooltip_text,
3357                          const char    *tooltip_private_text,
3358                          GtkWidget     *icon,
3359                          GtkSignalFunc  callback,
3360                          gpointer       user_data,
3361                          gint           position)
3362 {
3363   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3364                                      NULL, text,
3365                                      tooltip_text, tooltip_private_text,
3366                                      icon, callback, user_data,
3367                                      position);
3368 }
3369
3370 /**
3371  * gtk_toolbar_insert_stock:
3372  * @toolbar: A #GtkToolbar
3373  * @stock_id: The id of the stock item you want to insert
3374  * @tooltip_text: The text in the tooltip of the toolbar button
3375  * @tooltip_private_text: The private text of the tooltip
3376  * @callback: The callback called when the toolbar button is clicked.
3377  * @user_data: user data passed to callback
3378  * @position: The position the button shall be inserted at.
3379  *            -1 means at the end.
3380  *
3381  * Inserts a stock item at the specified position of the toolbar.  If
3382  * @stock_id is not a known stock item ID, it's inserted verbatim,
3383  * except that underscores used to mark mnemonics are removed.
3384  *
3385  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3386  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3387  *
3388  * Returns: the inserted widget
3389  */
3390 GtkWidget*
3391 gtk_toolbar_insert_stock (GtkToolbar      *toolbar,
3392                           const gchar     *stock_id,
3393                           const char      *tooltip_text,
3394                           const char      *tooltip_private_text,
3395                           GtkSignalFunc    callback,
3396                           gpointer         user_data,
3397                           gint             position)
3398 {
3399   return internal_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3400                                   NULL, stock_id,
3401                                   tooltip_text, tooltip_private_text,
3402                                   NULL, callback, user_data,
3403                                   position, TRUE);
3404 }
3405
3406 /**
3407  * gtk_toolbar_append_space:
3408  * @toolbar: a #GtkToolbar.
3409  * 
3410  * Adds a new space to the end of the toolbar.
3411  **/
3412 void
3413 gtk_toolbar_append_space (GtkToolbar *toolbar)
3414 {
3415   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3416                               NULL, NULL,
3417                               NULL, NULL,
3418                               NULL, NULL, NULL,
3419                               toolbar->num_children);
3420 }
3421
3422 /**
3423  * gtk_toolbar_prepend_space:
3424  * @toolbar: a #GtkToolbar.
3425  * 
3426  * Adds a new space to the beginning of the toolbar.
3427  **/
3428 void
3429 gtk_toolbar_prepend_space (GtkToolbar *toolbar)
3430 {
3431   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3432                               NULL, NULL,
3433                               NULL, NULL,
3434                               NULL, NULL, NULL,
3435                               0);
3436 }
3437
3438 /**
3439  * gtk_toolbar_insert_space:
3440  * @toolbar: a #GtkToolbar
3441  * @position: the number of widgets after which a space should be inserted.
3442  * 
3443  * Inserts a new space in the toolbar at the specified position.
3444  **/
3445 void
3446 gtk_toolbar_insert_space (GtkToolbar *toolbar,
3447                           gint        position)
3448 {
3449   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3450                               NULL, NULL,
3451                               NULL, NULL,
3452                               NULL, NULL, NULL,
3453                               position);
3454 }
3455
3456 /**
3457  * gtk_toolbar_remove_space:
3458  * @toolbar: a #GtkToolbar.
3459  * @position: the index of the space to remove.
3460  * 
3461  * Removes a space from the specified position.
3462  **/
3463 void
3464 gtk_toolbar_remove_space (GtkToolbar *toolbar,
3465                           gint        position)
3466 {
3467   GtkToolbarPrivate *priv;
3468   ToolbarContent *content;
3469   
3470   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3471   
3472   if (!gtk_toolbar_check_old_api (toolbar))
3473     return;
3474   
3475   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3476   
3477   content = g_list_nth_data (priv->content, position);
3478   
3479   if (!content)
3480     {
3481       g_warning ("Toolbar position %d doesn't exist", position);
3482       return;
3483     }
3484   
3485   if (!toolbar_content_is_separator (content))
3486     {
3487       g_warning ("Toolbar position %d is not a space", position);
3488       return;
3489     }
3490   
3491   toolbar_content_remove (content, toolbar);
3492   toolbar_content_free (content);
3493 }
3494
3495 /**
3496  * gtk_toolbar_append_widget:
3497  * @toolbar: a #GtkToolbar.
3498  * @widget: a #GtkWidget to add to the toolbar. 
3499  * @tooltip_text: the element's tooltip.
3500  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3501  * 
3502  * Adds a widget to the end of the given toolbar.
3503  **/ 
3504 void
3505 gtk_toolbar_append_widget (GtkToolbar  *toolbar,
3506                            GtkWidget   *widget,
3507                            const gchar *tooltip_text,
3508                            const gchar *tooltip_private_text)
3509 {
3510   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3511                               widget, NULL,
3512                               tooltip_text, tooltip_private_text,
3513                               NULL, NULL, NULL,
3514                               toolbar->num_children);
3515 }
3516
3517 /**
3518  * gtk_toolbar_prepend_widget:
3519  * @toolbar: a #GtkToolbar.
3520  * @widget: a #GtkWidget to add to the toolbar. 
3521  * @tooltip_text: the element's tooltip.
3522  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3523  * 
3524  * Adds a widget to the beginning of the given toolbar.
3525  **/ 
3526 void
3527 gtk_toolbar_prepend_widget (GtkToolbar  *toolbar,
3528                             GtkWidget   *widget,
3529                             const gchar *tooltip_text,
3530                             const gchar *tooltip_private_text)
3531 {
3532   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3533                               widget, NULL,
3534                               tooltip_text, tooltip_private_text,
3535                               NULL, NULL, NULL,
3536                               0);
3537 }
3538
3539 /**
3540  * gtk_toolbar_insert_widget:
3541  * @toolbar: a #GtkToolbar.
3542  * @widget: a #GtkWidget to add to the toolbar. 
3543  * @tooltip_text: the element's tooltip.
3544  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3545  * @position: the number of widgets to insert this widget after.
3546  * 
3547  * Inserts a widget in the toolbar at the given position.
3548  **/ 
3549 void
3550 gtk_toolbar_insert_widget (GtkToolbar *toolbar,
3551                            GtkWidget  *widget,
3552                            const char *tooltip_text,
3553                            const char *tooltip_private_text,
3554                            gint        position)
3555 {
3556   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3557                               widget, NULL,
3558                               tooltip_text, tooltip_private_text,
3559                               NULL, NULL, NULL,
3560                               position);
3561 }
3562
3563 /**
3564  * gtk_toolbar_append_element:
3565  * @toolbar: a #GtkToolbar.
3566  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3567  * @widget: a #GtkWidget, or %NULL.
3568  * @text: the element's label.
3569  * @tooltip_text: the element's tooltip.
3570  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3571  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3572  * @callback: the function to be executed when the button is pressed.
3573  * @user_data: any data you wish to pass to the callback.
3574  * 
3575  * Adds a new element to the end of a toolbar.
3576  * 
3577  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3578  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3579  * the radio group for the new element. In all other cases, @widget must
3580  * be %NULL.
3581  * 
3582  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3583  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3584  *
3585  * Return value: the new toolbar element as a #GtkWidget.
3586  **/
3587 GtkWidget*
3588 gtk_toolbar_append_element (GtkToolbar          *toolbar,
3589                             GtkToolbarChildType  type,
3590                             GtkWidget           *widget,
3591                             const char          *text,
3592                             const char          *tooltip_text,
3593                             const char          *tooltip_private_text,
3594                             GtkWidget           *icon,
3595                             GtkSignalFunc        callback,
3596                             gpointer             user_data)
3597 {
3598   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3599                                      tooltip_text, tooltip_private_text,
3600                                      icon, callback, user_data,
3601                                      toolbar->num_children);
3602 }
3603
3604 /**
3605  * gtk_toolbar_prepend_element:
3606  * @toolbar: a #GtkToolbar.
3607  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3608  * @widget: a #GtkWidget, or %NULL
3609  * @text: the element's label.
3610  * @tooltip_text: the element's tooltip.
3611  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3612  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3613  * @callback: the function to be executed when the button is pressed.
3614  * @user_data: any data you wish to pass to the callback.
3615  *  
3616  * Adds a new element to the beginning of a toolbar.
3617  * 
3618  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3619  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3620  * the radio group for the new element. In all other cases, @widget must
3621  * be %NULL.
3622  * 
3623  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3624  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3625  *
3626  * Return value: the new toolbar element as a #GtkWidget.
3627  **/
3628 GtkWidget *
3629 gtk_toolbar_prepend_element (GtkToolbar          *toolbar,
3630                              GtkToolbarChildType  type,
3631                              GtkWidget           *widget,
3632                              const char          *text,
3633                              const char          *tooltip_text,
3634                              const char          *tooltip_private_text,
3635                              GtkWidget           *icon,
3636                              GtkSignalFunc        callback,
3637                              gpointer             user_data)
3638 {
3639   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3640                                      tooltip_text, tooltip_private_text,
3641                                      icon, callback, user_data, 0);
3642 }
3643
3644 /**
3645  * gtk_toolbar_insert_element:
3646  * @toolbar: a #GtkToolbar.
3647  * @type: a value of type #GtkToolbarChildType that determines what @widget
3648  *   will be.
3649  * @widget: a #GtkWidget, or %NULL. 
3650  * @text: the element's label.
3651  * @tooltip_text: the element's tooltip.
3652  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3653  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3654  * @callback: the function to be executed when the button is pressed.
3655  * @user_data: any data you wish to pass to the callback.
3656  * @position: the number of widgets to insert this element after.
3657  *
3658  * Inserts a new element in the toolbar at the given position. 
3659  *
3660  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3661  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3662  * the radio group for the new element. In all other cases, @widget must
3663  * be %NULL.
3664  *
3665  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3666  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3667  *
3668  * Return value: the new toolbar element as a #GtkWidget.
3669  **/
3670 GtkWidget *
3671 gtk_toolbar_insert_element (GtkToolbar          *toolbar,
3672                             GtkToolbarChildType  type,
3673                             GtkWidget           *widget,
3674                             const char          *text,
3675                             const char          *tooltip_text,
3676                             const char          *tooltip_private_text,
3677                             GtkWidget           *icon,
3678                             GtkSignalFunc        callback,
3679                             gpointer             user_data,
3680                             gint                 position)
3681 {
3682   return internal_insert_element (toolbar, type, widget, text,
3683                                   tooltip_text, tooltip_private_text,
3684                                   icon, callback, user_data, position, FALSE);
3685 }
3686
3687 static void
3688 set_child_packing_and_visibility(GtkToolbar      *toolbar,
3689                                  GtkToolbarChild *child)
3690 {
3691   GtkWidget *box;
3692   gboolean   expand;
3693
3694   box = gtk_bin_get_child (GTK_BIN (child->widget));
3695   
3696   g_return_if_fail (GTK_IS_BOX (box));
3697   
3698   if (child->label)
3699     {
3700       expand = (toolbar->style != GTK_TOOLBAR_BOTH);
3701       
3702       gtk_box_set_child_packing (GTK_BOX (box), child->label,
3703                                  expand, expand, 0, GTK_PACK_END);
3704       
3705       if (toolbar->style != GTK_TOOLBAR_ICONS)
3706         gtk_widget_show (child->label);
3707       else
3708         gtk_widget_hide (child->label);
3709     }
3710   
3711   if (child->icon)
3712     {
3713       expand = (toolbar->style != GTK_TOOLBAR_BOTH_HORIZ);
3714       
3715       gtk_box_set_child_packing (GTK_BOX (box), child->icon,
3716                                  expand, expand, 0, GTK_PACK_END);
3717       
3718       if (toolbar->style != GTK_TOOLBAR_TEXT)
3719         gtk_widget_show (child->icon);
3720       else
3721         gtk_widget_hide (child->icon);
3722     }
3723 }
3724
3725 static GtkWidget *
3726 internal_insert_element (GtkToolbar          *toolbar,
3727                          GtkToolbarChildType  type,
3728                          GtkWidget           *widget,
3729                          const char          *text,
3730                          const char          *tooltip_text,
3731                          const char          *tooltip_private_text,
3732                          GtkWidget           *icon,
3733                          GtkSignalFunc        callback,
3734                          gpointer             user_data,
3735                          gint                 position,
3736                          gboolean             use_stock)
3737 {
3738   GtkWidget *box;
3739   ToolbarContent *content;
3740   char *free_me = NULL;
3741
3742   GtkWidget *child_widget;
3743   GtkWidget *child_label;
3744   GtkWidget *child_icon;
3745
3746   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
3747   if (type == GTK_TOOLBAR_CHILD_WIDGET)
3748     g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
3749   else if (type != GTK_TOOLBAR_CHILD_RADIOBUTTON)
3750     g_return_val_if_fail (widget == NULL, NULL);
3751   if (GTK_IS_TOOL_ITEM (widget))
3752     g_warning (MIXED_API_WARNING);
3753   
3754   if (!gtk_toolbar_check_old_api (toolbar))
3755     return NULL;
3756   
3757   child_widget = NULL;
3758   child_label = NULL;
3759   child_icon = NULL;
3760   
3761   switch (type)
3762     {
3763     case GTK_TOOLBAR_CHILD_SPACE:
3764       break;
3765       
3766     case GTK_TOOLBAR_CHILD_WIDGET:
3767       child_widget = widget;
3768       break;
3769       
3770     case GTK_TOOLBAR_CHILD_BUTTON:
3771     case GTK_TOOLBAR_CHILD_TOGGLEBUTTON:
3772     case GTK_TOOLBAR_CHILD_RADIOBUTTON:
3773       if (type == GTK_TOOLBAR_CHILD_BUTTON)
3774         {
3775           child_widget = gtk_button_new ();
3776         }
3777       else if (type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
3778         {
3779           child_widget = gtk_toggle_button_new ();
3780           gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child_widget), FALSE);
3781         }
3782       else /* type == GTK_TOOLBAR_CHILD_RADIOBUTTON */
3783         {
3784           GSList *group = NULL;
3785
3786           if (widget)
3787             group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
3788           
3789           child_widget = gtk_radio_button_new (group);
3790           gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child_widget), FALSE);
3791         }
3792
3793       gtk_button_set_relief (GTK_BUTTON (child_widget), get_button_relief (toolbar));
3794       gtk_button_set_focus_on_click (GTK_BUTTON (child_widget), FALSE);
3795       
3796       if (callback)
3797         {
3798           g_signal_connect (child_widget, "clicked",
3799                             callback, user_data);
3800         }
3801       
3802       if (toolbar->style == GTK_TOOLBAR_BOTH_HORIZ)
3803         box = gtk_hbox_new (FALSE, 0);
3804       else
3805         box = gtk_vbox_new (FALSE, 0);
3806
3807       gtk_container_add (GTK_CONTAINER (child_widget), box);
3808       gtk_widget_show (box);
3809       
3810       if (text && use_stock)
3811         {
3812           GtkStockItem stock_item;
3813           if (gtk_stock_lookup (text, &stock_item))
3814             {
3815               if (!icon)
3816                 icon = gtk_image_new_from_stock (text, toolbar->icon_size);
3817           
3818               text = free_me = _gtk_toolbar_elide_underscores (stock_item.label);
3819             }
3820         }
3821       
3822       if (text)
3823         {
3824           child_label = gtk_label_new (text);
3825           
3826           gtk_container_add (GTK_CONTAINER (box), child_label);
3827         }
3828       
3829       if (icon)
3830         {
3831           child_icon = GTK_WIDGET (icon);
3832           gtk_container_add (GTK_CONTAINER (box), child_icon);
3833         }
3834       
3835       gtk_widget_show (child_widget);
3836       break;
3837       
3838     default:
3839       g_assert_not_reached ();
3840       break;
3841     }
3842   
3843   if ((type != GTK_TOOLBAR_CHILD_SPACE) && tooltip_text)
3844     {
3845       gtk_tooltips_set_tip (toolbar->tooltips, child_widget,
3846                             tooltip_text, tooltip_private_text);
3847     }
3848   
3849   content = toolbar_content_new_compatibility (toolbar, type, child_widget,
3850                                                child_icon, child_label, position);
3851   
3852   g_free (free_me);
3853   
3854   return child_widget;
3855 }
3856
3857 /*
3858  * ToolbarContent methods
3859  */
3860 typedef enum {
3861   UNKNOWN,
3862   YES,
3863   NO,
3864 } TriState;
3865
3866 struct _ToolbarContent
3867 {
3868   ContentType   type;
3869   ItemState     state;
3870   
3871   union
3872   {
3873     struct
3874     {
3875       GtkToolItem *     item;
3876       GtkAllocation     start_allocation;
3877       GtkAllocation     goal_allocation;
3878       guint             is_placeholder : 1;
3879       guint             disappearing : 1;
3880       TriState          has_menu : 2;
3881     } tool_item;
3882     
3883     struct
3884     {
3885       GtkToolbarChild   child;
3886       GtkAllocation     space_allocation;
3887       guint             space_visible : 1;
3888     } compatibility;
3889   } u;
3890 };
3891
3892 static ToolbarContent *
3893 toolbar_content_new_tool_item (GtkToolbar  *toolbar,
3894                                GtkToolItem *item,
3895                                gboolean     is_placeholder,
3896                                gint         pos)
3897 {
3898   ToolbarContent *content;
3899   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3900   
3901   content = g_new0 (ToolbarContent, 1);
3902   
3903   content->type = TOOL_ITEM;
3904   content->state = NOT_ALLOCATED;
3905   content->u.tool_item.item = item;
3906   content->u.tool_item.is_placeholder = is_placeholder;
3907   
3908   gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar));
3909
3910   priv->content = g_list_insert (priv->content, content, pos);
3911   
3912   if (!is_placeholder)
3913     {
3914       toolbar->num_children++;
3915
3916       gtk_toolbar_stop_sliding (toolbar);
3917     }
3918
3919   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3920   priv->need_rebuild = TRUE;
3921   
3922   return content;
3923 }
3924
3925 static ToolbarContent *
3926 toolbar_content_new_compatibility (GtkToolbar          *toolbar,
3927                                    GtkToolbarChildType  type,
3928                                    GtkWidget            *widget,
3929                                    GtkWidget            *icon,
3930                                    GtkWidget            *label,
3931                                    gint                  pos)
3932 {
3933   ToolbarContent *content;
3934   GtkToolbarChild *child;
3935   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3936   
3937   content = g_new0 (ToolbarContent, 1);
3938
3939   child = &(content->u.compatibility.child);
3940   
3941   content->type = COMPATIBILITY;
3942   child->type = type;
3943   child->widget = widget;
3944   child->icon = icon;
3945   child->label = label;
3946   
3947   if (type != GTK_TOOLBAR_CHILD_SPACE)
3948     {
3949       gtk_widget_set_parent (child->widget, GTK_WIDGET (toolbar));
3950     }
3951   else
3952     {
3953       content->u.compatibility.space_visible = TRUE;
3954       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3955     }
3956  
3957   if (type == GTK_TOOLBAR_CHILD_BUTTON ||
3958       type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
3959       type == GTK_TOOLBAR_CHILD_RADIOBUTTON)
3960     {
3961       set_child_packing_and_visibility (toolbar, child);
3962     }
3963
3964   priv->content = g_list_insert (priv->content, content, pos);
3965   toolbar->children = g_list_insert (toolbar->children, child, pos);
3966   priv->need_rebuild = TRUE;
3967   
3968   toolbar->num_children++;
3969   
3970   return content;
3971 }
3972
3973 static void
3974 toolbar_content_remove (ToolbarContent *content,
3975                         GtkToolbar     *toolbar)
3976 {
3977   GtkToolbarChild *child;
3978   GtkToolbarPrivate *priv;
3979
3980   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3981   
3982   switch (content->type)
3983     {
3984     case TOOL_ITEM:
3985       gtk_widget_unparent (GTK_WIDGET (content->u.tool_item.item));
3986       break;
3987       
3988     case COMPATIBILITY:
3989       child = &(content->u.compatibility.child);
3990       
3991       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
3992         {
3993           g_object_ref (child->widget);
3994           gtk_widget_unparent (child->widget);
3995           gtk_widget_destroy (child->widget);
3996           g_object_unref (child->widget);
3997         }
3998       
3999       toolbar->children = g_list_remove (toolbar->children, child);
4000       break;
4001     }
4002
4003   priv->content = g_list_remove (priv->content, content);
4004
4005   if (!toolbar_content_is_placeholder (content))
4006     toolbar->num_children--;
4007
4008   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
4009   priv->need_rebuild = TRUE;
4010 }
4011
4012 static void
4013 toolbar_content_free (ToolbarContent *content)
4014 {
4015   g_free (content);
4016 }
4017
4018 static gint
4019 calculate_max_homogeneous_pixels (GtkWidget *widget)
4020 {
4021   PangoContext *context;
4022   PangoFontMetrics *metrics;
4023   gint char_width;
4024   
4025   context = gtk_widget_get_pango_context (widget);
4026   metrics = pango_context_get_metrics (context,
4027                                        widget->style->font_desc,
4028                                        pango_context_get_language (context));
4029   char_width = pango_font_metrics_get_approximate_char_width (metrics);
4030   pango_font_metrics_unref (metrics);
4031   
4032   return PANGO_PIXELS (MAX_HOMOGENEOUS_N_CHARS * char_width);
4033 }
4034
4035 static void
4036 toolbar_content_expose (ToolbarContent *content,
4037                         GtkContainer   *container,
4038                         GdkEventExpose *expose)
4039 {
4040   GtkToolbar *toolbar = GTK_TOOLBAR (container);
4041   GtkToolbarChild *child;
4042   GtkWidget *widget = NULL; /* quiet gcc */
4043   
4044   switch (content->type)
4045     {
4046     case TOOL_ITEM:
4047       if (!content->u.tool_item.is_placeholder)
4048         widget = GTK_WIDGET (content->u.tool_item.item);
4049       break;
4050       
4051     case COMPATIBILITY:
4052       child = &(content->u.compatibility.child);
4053       
4054       if (child->type == GTK_TOOLBAR_CHILD_SPACE)
4055         {
4056           if (content->u.compatibility.space_visible &&
4057               get_space_style (toolbar) == GTK_TOOLBAR_SPACE_LINE)
4058              _gtk_toolbar_paint_space_line (GTK_WIDGET (toolbar), toolbar,
4059                                             &expose->area,
4060                                             &content->u.compatibility.space_allocation);
4061           return;
4062         }
4063       
4064       widget = child->widget;
4065       break;
4066     }
4067   
4068   if (widget)
4069     gtk_container_propagate_expose (container, widget, expose);
4070 }
4071
4072 static gboolean
4073 toolbar_content_visible (ToolbarContent *content,
4074                          GtkToolbar     *toolbar)
4075 {
4076   GtkToolItem *item;
4077   
4078   switch (content->type)
4079     {
4080     case TOOL_ITEM:
4081       item = content->u.tool_item.item;
4082       
4083       if (!GTK_WIDGET_VISIBLE (item))
4084         return FALSE;
4085       
4086       if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL &&
4087           gtk_tool_item_get_visible_horizontal (item))
4088         return TRUE;
4089       
4090       if ((toolbar->orientation == GTK_ORIENTATION_VERTICAL &&
4091            gtk_tool_item_get_visible_vertical (item)))
4092         return TRUE;
4093       
4094       return FALSE;
4095       break;
4096       
4097     case COMPATIBILITY:
4098       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4099         return GTK_WIDGET_VISIBLE (content->u.compatibility.child.widget);
4100       else
4101         return TRUE;
4102       break;
4103     }
4104   
4105   g_assert_not_reached ();
4106   return FALSE;
4107 }
4108
4109 static void
4110 toolbar_content_size_request (ToolbarContent *content,
4111                               GtkToolbar     *toolbar,
4112                               GtkRequisition *requisition)
4113 {
4114   gint space_size;
4115   
4116   switch (content->type)
4117     {
4118     case TOOL_ITEM:
4119       gtk_widget_size_request (GTK_WIDGET (content->u.tool_item.item),
4120                                requisition);
4121       if (content->u.tool_item.is_placeholder &&
4122           content->u.tool_item.disappearing)
4123         {
4124           requisition->width = 0;
4125           requisition->height = 0;
4126         }
4127       break;
4128       
4129     case COMPATIBILITY:
4130       space_size = get_space_size (toolbar);
4131       
4132       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4133         {
4134           gtk_widget_size_request (content->u.compatibility.child.widget,
4135                                    requisition);
4136         }
4137       else
4138         {
4139           if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
4140             {
4141               requisition->width = space_size;
4142               requisition->height = 0;
4143             }
4144           else
4145             {
4146               requisition->height = space_size;
4147               requisition->width = 0;
4148             }
4149         }
4150       
4151       break;
4152     }
4153 }
4154
4155 static gboolean
4156 toolbar_content_is_homogeneous (ToolbarContent *content,
4157                                 GtkToolbar     *toolbar)
4158 {
4159   gboolean result = FALSE;      /* quiet gcc */
4160   GtkRequisition requisition;
4161   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4162   
4163   if (priv->max_homogeneous_pixels < 0)
4164     {
4165       priv->max_homogeneous_pixels =
4166         calculate_max_homogeneous_pixels (GTK_WIDGET (toolbar));
4167     }
4168   
4169   toolbar_content_size_request (content, toolbar, &requisition);
4170   
4171   if (requisition.width > priv->max_homogeneous_pixels)
4172     return FALSE;
4173   
4174   switch (content->type)
4175     {
4176     case TOOL_ITEM:
4177       result = gtk_tool_item_get_homogeneous (content->u.tool_item.item) &&
4178         !GTK_IS_SEPARATOR_TOOL_ITEM (content->u.tool_item.item);
4179       
4180       if (gtk_tool_item_get_is_important (content->u.tool_item.item) &&
4181           toolbar->style == GTK_TOOLBAR_BOTH_HORIZ &&
4182           toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
4183         {
4184           result = FALSE;
4185         }
4186       break;
4187       
4188     case COMPATIBILITY:
4189       if (content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_BUTTON ||
4190           content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4191           content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4192         {
4193           result = TRUE;
4194         }
4195       else
4196         {
4197           result = FALSE;
4198         }
4199       break;
4200     }
4201   
4202   return result;
4203 }
4204
4205 static gboolean
4206 toolbar_content_is_placeholder (ToolbarContent *content)
4207 {
4208   if (content->type == TOOL_ITEM && content->u.tool_item.is_placeholder)
4209     return TRUE;
4210   
4211   return FALSE;
4212 }
4213
4214 static gboolean
4215 toolbar_content_disappearing (ToolbarContent *content)
4216 {
4217   if (content->type == TOOL_ITEM && content->u.tool_item.disappearing)
4218     return TRUE;
4219   
4220   return FALSE;
4221 }
4222
4223 static ItemState
4224 toolbar_content_get_state (ToolbarContent *content)
4225 {
4226   return content->state;
4227 }
4228
4229 static gboolean
4230 toolbar_content_child_visible (ToolbarContent *content)
4231 {
4232   switch (content->type)
4233     {
4234     case TOOL_ITEM:
4235       return GTK_WIDGET_CHILD_VISIBLE (content->u.tool_item.item);
4236       break;
4237       
4238     case COMPATIBILITY:
4239       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4240         {
4241           return GTK_WIDGET_CHILD_VISIBLE (content->u.compatibility.child.widget);
4242         }
4243       else
4244         {
4245           return content->u.compatibility.space_visible;
4246         }
4247       break;
4248     }
4249   
4250   return FALSE; /* quiet gcc */
4251 }
4252
4253 static void
4254 toolbar_content_get_goal_allocation (ToolbarContent *content,
4255                                      GtkAllocation  *allocation)
4256 {
4257   switch (content->type)
4258     {
4259     case TOOL_ITEM:
4260       *allocation = content->u.tool_item.goal_allocation;
4261       break;
4262       
4263     case COMPATIBILITY:
4264       /* Goal allocations are only relevant when we are
4265        * using the new API, so we should never get here
4266        */
4267       g_assert_not_reached ();
4268       break;
4269     }
4270 }
4271
4272 static void
4273 toolbar_content_get_allocation (ToolbarContent *content,
4274                                 GtkAllocation  *allocation)
4275 {
4276   GtkToolbarChild *child;
4277   
4278   switch (content->type)
4279     {
4280     case TOOL_ITEM:
4281       *allocation = GTK_WIDGET (content->u.tool_item.item)->allocation;
4282       break;
4283       
4284     case COMPATIBILITY:
4285       child = &(content->u.compatibility.child);
4286       
4287       if (child->type == GTK_TOOLBAR_CHILD_SPACE)
4288         *allocation = content->u.compatibility.space_allocation;
4289       else
4290         *allocation = child->widget->allocation;
4291       break;
4292     }
4293 }
4294
4295 static void
4296 toolbar_content_set_start_allocation (ToolbarContent *content,
4297                                       GtkAllocation  *allocation)
4298 {
4299   switch (content->type)
4300     {
4301     case TOOL_ITEM:
4302       content->u.tool_item.start_allocation = *allocation;
4303       break;
4304       
4305     case COMPATIBILITY:
4306       /* start_allocation is only relevant when using the new API */
4307       g_assert_not_reached ();
4308       break;
4309     }
4310 }
4311
4312 static gboolean
4313 toolbar_content_get_expand (ToolbarContent *content)
4314 {
4315   if (content->type == TOOL_ITEM &&
4316       gtk_tool_item_get_expand (content->u.tool_item.item) &&
4317       !content->u.tool_item.disappearing)
4318     {
4319       return TRUE;
4320     }
4321   
4322   return FALSE;
4323 }
4324
4325 static void
4326 toolbar_content_set_goal_allocation (ToolbarContent *content,
4327                                      GtkAllocation  *allocation)
4328 {
4329   switch (content->type)
4330     {
4331     case TOOL_ITEM:
4332       content->u.tool_item.goal_allocation = *allocation;
4333       break;
4334       
4335     case COMPATIBILITY:
4336       /* Only relevant when using new API */
4337       g_assert_not_reached ();
4338       break;
4339     }
4340 }
4341
4342 static void
4343 toolbar_content_set_child_visible (ToolbarContent *content,
4344                                    GtkToolbar     *toolbar,
4345                                    gboolean        visible)
4346 {
4347   GtkToolbarChild *child;
4348   
4349   switch (content->type)
4350     {
4351     case TOOL_ITEM:
4352       gtk_widget_set_child_visible (GTK_WIDGET (content->u.tool_item.item),
4353                                     visible);
4354       break;
4355       
4356     case COMPATIBILITY:
4357       child = &(content->u.compatibility.child);
4358       
4359       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
4360         {
4361           gtk_widget_set_child_visible (child->widget, visible);
4362         }
4363       else
4364         {
4365           if (content->u.compatibility.space_visible != visible)
4366             {
4367               content->u.compatibility.space_visible = visible;
4368               gtk_widget_queue_draw (GTK_WIDGET (toolbar));
4369             }
4370         }
4371       break;
4372     }
4373 }
4374
4375 static void
4376 toolbar_content_get_start_allocation (ToolbarContent *content,
4377                                       GtkAllocation  *start_allocation)
4378 {
4379   switch (content->type)
4380     {
4381     case TOOL_ITEM:
4382       *start_allocation = content->u.tool_item.start_allocation;
4383       break;
4384       
4385     case COMPATIBILITY:
4386       /* Only relevant for new API */
4387       g_assert_not_reached ();
4388       break;
4389     }
4390 }
4391
4392 static void
4393 toolbar_content_size_allocate (ToolbarContent *content,
4394                                GtkAllocation  *allocation)
4395 {
4396   switch (content->type)
4397     {
4398     case TOOL_ITEM:
4399       gtk_widget_size_allocate (GTK_WIDGET (content->u.tool_item.item),
4400                                 allocation);
4401       break;
4402       
4403     case COMPATIBILITY:
4404       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4405         {
4406           gtk_widget_size_allocate (content->u.compatibility.child.widget,
4407                                     allocation);
4408         }
4409       else
4410         {
4411           content->u.compatibility.space_allocation = *allocation;
4412         }
4413       break;
4414     }
4415 }
4416
4417 static void
4418 toolbar_content_set_state (ToolbarContent *content,
4419                            ItemState       state)
4420 {
4421   content->state = state;
4422 }
4423
4424 static GtkWidget *
4425 toolbar_content_get_widget (ToolbarContent *content)
4426 {
4427   GtkToolbarChild *child;
4428   
4429   switch (content->type)
4430     {
4431     case TOOL_ITEM:
4432       return GTK_WIDGET (content->u.tool_item.item);
4433       break;
4434       
4435     case COMPATIBILITY:
4436       child = &(content->u.compatibility.child);
4437       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
4438         return child->widget;
4439       else
4440         return NULL;
4441       break;
4442     }
4443   
4444   return NULL;
4445 }
4446
4447 static void
4448 toolbar_content_set_disappearing (ToolbarContent *content,
4449                                   gboolean        disappearing)
4450 {
4451   switch (content->type)
4452     {
4453     case TOOL_ITEM:
4454       content->u.tool_item.disappearing = disappearing;
4455       break;
4456       
4457     case COMPATIBILITY:
4458       /* Only relevant for new API */
4459       g_assert_not_reached ();
4460       break;
4461     }
4462 }
4463
4464 static void
4465 toolbar_content_set_size_request (ToolbarContent *content,
4466                                   gint            width,
4467                                   gint            height)
4468 {
4469   switch (content->type)
4470     {
4471     case TOOL_ITEM:
4472       gtk_widget_set_size_request (GTK_WIDGET (content->u.tool_item.item),
4473                                    width, height);
4474       break;
4475       
4476     case COMPATIBILITY:
4477       /* Setting size requests only happens with sliding,
4478        * so not relevant here
4479        */
4480       g_assert_not_reached ();
4481       break;
4482     }
4483 }
4484
4485 static void
4486 toolbar_child_reconfigure (GtkToolbar      *toolbar,
4487                            GtkToolbarChild *child)
4488 {
4489   GtkWidget *box;
4490   GtkImage *image;
4491   GtkToolbarStyle style;
4492   GtkIconSize icon_size;
4493   GtkReliefStyle relief;
4494   gchar *stock_id;
4495   
4496   style = gtk_toolbar_get_style (toolbar);
4497   icon_size = gtk_toolbar_get_icon_size (toolbar);
4498   relief = gtk_toolbar_get_relief_style (toolbar);
4499   
4500   /* style */
4501   if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4502       child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4503       child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4504     {
4505       box = gtk_bin_get_child (GTK_BIN (child->widget));
4506       
4507       if (style == GTK_TOOLBAR_BOTH && GTK_IS_HBOX (box))
4508         {
4509           GtkWidget *vbox;
4510           
4511           vbox = gtk_vbox_new (FALSE, 0);
4512           
4513           if (child->label)
4514             gtk_widget_reparent (child->label, vbox);
4515           if (child->icon)
4516             gtk_widget_reparent (child->icon, vbox);
4517           
4518           gtk_widget_destroy (box);
4519           gtk_container_add (GTK_CONTAINER (child->widget), vbox);
4520           
4521           gtk_widget_show (vbox);
4522         }
4523       else if (style == GTK_TOOLBAR_BOTH_HORIZ && GTK_IS_VBOX (box))
4524         {
4525           GtkWidget *hbox;
4526           
4527           hbox = gtk_hbox_new (FALSE, 0);
4528           
4529           if (child->label)
4530             gtk_widget_reparent (child->label, hbox);
4531           if (child->icon)
4532             gtk_widget_reparent (child->icon, hbox);
4533           
4534           gtk_widget_destroy (box);
4535           gtk_container_add (GTK_CONTAINER (child->widget), hbox);
4536           
4537           gtk_widget_show (hbox);
4538         }
4539
4540       set_child_packing_and_visibility (toolbar, child);
4541     }
4542   
4543   /* icon size */
4544   
4545   if ((child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4546        child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
4547        child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON) &&
4548       GTK_IS_IMAGE (child->icon))
4549     {
4550       image = GTK_IMAGE (child->icon);
4551       if (gtk_image_get_storage_type (image) == GTK_IMAGE_STOCK)
4552         {
4553           gtk_image_get_stock (image, &stock_id, NULL);
4554           stock_id = g_strdup (stock_id);
4555           gtk_image_set_from_stock (image,
4556                                     stock_id,
4557                                     icon_size);
4558           g_free (stock_id);
4559         }
4560     }
4561   
4562   /* relief */
4563   if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4564       child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4565       child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4566     {
4567       gtk_button_set_relief (GTK_BUTTON (child->widget), relief);
4568     }
4569 }
4570
4571 static void
4572 toolbar_content_toolbar_reconfigured (ToolbarContent *content,
4573                                       GtkToolbar     *toolbar)
4574 {
4575   switch (content->type)
4576     {
4577     case TOOL_ITEM:
4578       _gtk_tool_item_toolbar_reconfigured (content->u.tool_item.item);
4579       break;
4580       
4581     case COMPATIBILITY:
4582       toolbar_child_reconfigure (toolbar, &(content->u.compatibility.child));
4583       break;
4584     }
4585 }
4586
4587 static GtkWidget *
4588 toolbar_content_retrieve_menu_item (ToolbarContent *content)
4589 {
4590   if (content->type == TOOL_ITEM)
4591     return gtk_tool_item_retrieve_proxy_menu_item (content->u.tool_item.item);
4592   
4593   /* FIXME - we might actually be able to do something meaningful here */
4594   return NULL; 
4595 }
4596
4597 static gboolean
4598 toolbar_content_has_proxy_menu_item (ToolbarContent *content)
4599 {
4600   if (content->type == TOOL_ITEM)
4601     {
4602       GtkWidget *menu_item;
4603
4604       if (content->u.tool_item.has_menu == YES)
4605         return TRUE;
4606       else if (content->u.tool_item.has_menu == NO)
4607         return FALSE;
4608
4609       menu_item = toolbar_content_retrieve_menu_item (content);
4610
4611       content->u.tool_item.has_menu = menu_item? YES : NO;
4612       
4613       return menu_item != NULL;
4614     }
4615   else
4616     {
4617       return FALSE;
4618     }
4619 }
4620
4621 static void
4622 toolbar_content_set_unknown_menu_status (ToolbarContent *content)
4623 {
4624   if (content->type == TOOL_ITEM)
4625     content->u.tool_item.has_menu = UNKNOWN;
4626 }
4627
4628 static gboolean
4629 toolbar_content_is_separator (ToolbarContent *content)
4630 {
4631   GtkToolbarChild *child;
4632   
4633   switch (content->type)
4634     {
4635     case TOOL_ITEM:
4636       return GTK_IS_SEPARATOR_TOOL_ITEM (content->u.tool_item.item);
4637       break;
4638       
4639     case COMPATIBILITY:
4640       child = &(content->u.compatibility.child);
4641       return (child->type == GTK_TOOLBAR_CHILD_SPACE);
4642       break;
4643     }
4644   
4645   return FALSE;
4646 }
4647
4648 static void
4649 toolbar_content_set_expand (ToolbarContent *content,
4650                             gboolean        expand)
4651 {
4652   if (content->type == TOOL_ITEM)
4653     gtk_tool_item_set_expand (content->u.tool_item.item, expand);
4654 }
4655
4656 static gboolean
4657 ignore_show_and_hide_all (ToolbarContent *content)
4658 {
4659   if (content->type == COMPATIBILITY)
4660     {
4661       GtkToolbarChildType type = content->u.compatibility.child.type;
4662       
4663       if (type == GTK_TOOLBAR_CHILD_BUTTON ||
4664           type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
4665           type == GTK_TOOLBAR_CHILD_RADIOBUTTON)
4666         {
4667           return TRUE;
4668         }
4669     }
4670   
4671   return FALSE;
4672 }
4673
4674 static void
4675 toolbar_content_show_all (ToolbarContent  *content)
4676 {
4677   GtkWidget *widget;
4678   
4679   if (ignore_show_and_hide_all (content))
4680     return;
4681
4682   widget = toolbar_content_get_widget (content);
4683   if (widget)
4684     gtk_widget_show_all (widget);
4685 }
4686
4687 static void
4688 toolbar_content_hide_all (ToolbarContent  *content)
4689 {
4690   GtkWidget *widget;
4691   
4692   if (ignore_show_and_hide_all (content))
4693     return;
4694
4695   widget = toolbar_content_get_widget (content);
4696   if (widget)
4697     gtk_widget_hide_all (widget);
4698 }
4699
4700 /*
4701  * Getters
4702  */
4703 static gint
4704 get_space_size (GtkToolbar *toolbar)
4705 {
4706   gint space_size = DEFAULT_SPACE_SIZE;
4707   
4708   if (toolbar)
4709     {
4710       gtk_widget_style_get (GTK_WIDGET (toolbar),
4711                             "space-size", &space_size,
4712                             NULL);
4713     }
4714   
4715   return space_size;
4716 }
4717
4718 static GtkToolbarSpaceStyle
4719 get_space_style (GtkToolbar *toolbar)
4720 {
4721   GtkToolbarSpaceStyle space_style = DEFAULT_SPACE_STYLE;
4722
4723   if (toolbar)
4724     {
4725       gtk_widget_style_get (GTK_WIDGET (toolbar),
4726                             "space-style", &space_style,
4727                             NULL);
4728     }
4729   
4730   return space_style;  
4731 }
4732
4733 static GtkReliefStyle
4734 get_button_relief (GtkToolbar *toolbar)
4735 {
4736   GtkReliefStyle button_relief = GTK_RELIEF_NORMAL;
4737   
4738   gtk_widget_ensure_style (GTK_WIDGET (toolbar));
4739   
4740   gtk_widget_style_get (GTK_WIDGET (toolbar),
4741                         "button-relief", &button_relief,
4742                         NULL);
4743   
4744   return button_relief;
4745 }
4746
4747 static gint
4748 get_internal_padding (GtkToolbar *toolbar)
4749 {
4750   gint ipadding = 0;
4751   
4752   gtk_widget_style_get (GTK_WIDGET (toolbar),
4753                         "internal-padding", &ipadding,
4754                         NULL);
4755   
4756   return ipadding;
4757 }
4758
4759 static gint
4760 get_max_child_expand (GtkToolbar *toolbar)
4761 {
4762   gint mexpand = G_MAXINT;
4763
4764   gtk_widget_style_get (GTK_WIDGET (toolbar),
4765                         "max-child-expand", &mexpand,
4766                         NULL);
4767   return mexpand;
4768 }
4769
4770 static GtkShadowType
4771 get_shadow_type (GtkToolbar *toolbar)
4772 {
4773   GtkShadowType shadow_type;
4774   
4775   gtk_widget_style_get (GTK_WIDGET (toolbar),
4776                         "shadow-type", &shadow_type,
4777                         NULL);
4778   
4779   return shadow_type;
4780 }
4781
4782 /*
4783  * API checks
4784  */
4785 static gboolean
4786 gtk_toolbar_check_old_api (GtkToolbar *toolbar)
4787 {
4788   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4789   
4790   if (priv->api_mode == NEW_API)
4791     {
4792       g_warning (MIXED_API_WARNING);
4793       return FALSE;
4794     }
4795   
4796   priv->api_mode = OLD_API;
4797   return TRUE;
4798 }
4799
4800 static gboolean
4801 gtk_toolbar_check_new_api (GtkToolbar *toolbar)
4802 {
4803   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4804   
4805   if (priv->api_mode == OLD_API)
4806     {
4807       g_warning (MIXED_API_WARNING);
4808       return FALSE;
4809     }
4810   
4811   priv->api_mode = NEW_API;
4812   return TRUE;
4813 }
4814
4815 /* GTK+ internal methods */
4816
4817 gint
4818 _gtk_toolbar_get_default_space_size (void)
4819 {
4820   return DEFAULT_SPACE_SIZE;
4821 }
4822
4823 void
4824 _gtk_toolbar_paint_space_line (GtkWidget       *widget,
4825                                GtkToolbar      *toolbar,
4826                                GdkRectangle    *area,
4827                                GtkAllocation   *allocation)
4828 {
4829   const double start_fraction = (SPACE_LINE_START / SPACE_LINE_DIVISION);
4830   const double end_fraction = (SPACE_LINE_END / SPACE_LINE_DIVISION);
4831   
4832   GtkOrientation orientation;
4833
4834   g_return_if_fail (GTK_IS_WIDGET (widget));
4835   
4836   orientation = toolbar? toolbar->orientation : GTK_ORIENTATION_HORIZONTAL;
4837
4838   if (orientation == GTK_ORIENTATION_HORIZONTAL)
4839     {
4840       gboolean wide_separators;
4841       gint     separator_width;
4842
4843       gtk_widget_style_get (widget,
4844                             "wide-separators", &wide_separators,
4845                             "separator-width", &separator_width,
4846                             NULL);
4847
4848       if (wide_separators)
4849         gtk_paint_box (widget->style, widget->window,
4850                        GTK_WIDGET_STATE (widget), GTK_SHADOW_ETCHED_OUT,
4851                        area, widget, "vseparator",
4852                        allocation->x + (allocation->width - separator_width) / 2,
4853                        allocation->y + allocation->height * start_fraction,
4854                        separator_width,
4855                        allocation->height * (end_fraction - start_fraction));
4856       else
4857         gtk_paint_vline (widget->style, widget->window,
4858                          GTK_WIDGET_STATE (widget), area, widget,
4859                          "toolbar",
4860                          allocation->y + allocation->height * start_fraction,
4861                          allocation->y + allocation->height * end_fraction,
4862                          allocation->x + (allocation->width - widget->style->xthickness) / 2);
4863     }
4864   else
4865     {
4866       gboolean wide_separators;
4867       gint     separator_height;
4868
4869       gtk_widget_style_get (widget,
4870                             "wide-separators",  &wide_separators,
4871                             "separator-height", &separator_height,
4872                             NULL);
4873
4874       if (wide_separators)
4875         gtk_paint_box (widget->style, widget->window,
4876                        GTK_WIDGET_STATE (widget), GTK_SHADOW_ETCHED_OUT,
4877                        area, widget, "hseparator",
4878                        allocation->x + allocation->width * start_fraction,
4879                        allocation->y + (allocation->height - separator_height) / 2,
4880                        allocation->width * (end_fraction - start_fraction),
4881                        separator_height);
4882       else
4883         gtk_paint_hline (widget->style, widget->window,
4884                          GTK_WIDGET_STATE (widget), area, widget,
4885                          "toolbar",
4886                          allocation->x + allocation->width * start_fraction,
4887                          allocation->x + allocation->width * end_fraction,
4888                          allocation->y + (allocation->height - widget->style->ythickness) / 2);
4889     }
4890 }
4891
4892 gchar *
4893 _gtk_toolbar_elide_underscores (const gchar *original)
4894 {
4895   gchar *q, *result;
4896   const gchar *p, *end;
4897   gsize len;
4898   gboolean last_underscore;
4899   
4900   if (!original)
4901     return NULL;
4902
4903   len = strlen (original);
4904   q = result = g_malloc (len + 1);
4905   last_underscore = FALSE;
4906   
4907   end = original + len;
4908   for (p = original; p < end; p++)
4909     {
4910       if (!last_underscore && *p == '_')
4911         last_underscore = TRUE;
4912       else
4913         {
4914           last_underscore = FALSE;
4915           if (original + 2 <= p && p + 1 <= end && 
4916               p[-2] == '(' && p[-1] == '_' && p[0] != '_' && p[1] == ')')
4917             {
4918               q--;
4919               *q = '\0';
4920               p++;
4921             }
4922           else
4923             *q++ = *p;
4924         }
4925     }
4926
4927   if (last_underscore)
4928     *q++ = '_';
4929   
4930   *q = '\0';
4931   
4932   return result;
4933 }
4934
4935 void
4936 _gtk_toolbar_rebuild_menu (GtkToolbar *toolbar)
4937 {
4938   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4939   GList *list;
4940
4941   priv->need_rebuild = TRUE;
4942
4943   for (list = priv->content; list != NULL; list = list->next)
4944     {
4945       ToolbarContent *content = list->data;
4946
4947       toolbar_content_set_unknown_menu_status (content);
4948     }
4949   
4950   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
4951 }
4952
4953 #define __GTK_TOOLBAR_C__
4954 #include "gtkaliasdef.c"