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