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