]> Pileus Git - ~andy/gtk/blob - gtk/gtktoolbar.c
Add a tooltips property.
[~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   
2542   gdk_window_get_origin (GTK_BUTTON (priv->arrow_button)->event_window, x, y);
2543   gtk_widget_size_request (priv->arrow_button, &req);
2544   gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
2545   
2546   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2547     {
2548       *y += priv->arrow_button->allocation.height;
2549       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2550         *x += priv->arrow_button->allocation.width - req.width;
2551       else 
2552         *x += req.width - menu_req.width;
2553     }
2554   else 
2555     {
2556       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2557         *x += priv->arrow_button->allocation.width;
2558       else 
2559         *x -= menu_req.width;
2560       *y += priv->arrow_button->allocation.height - req.height;      
2561     }
2562   
2563   *push_in = TRUE;
2564 }
2565
2566 static void
2567 show_menu (GtkToolbar     *toolbar,
2568            GdkEventButton *event)
2569 {
2570   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2571
2572   rebuild_menu (toolbar);
2573
2574   gtk_widget_show_all (GTK_WIDGET (priv->menu));
2575
2576   gtk_menu_popup (priv->menu, NULL, NULL,
2577                   menu_position_func, toolbar,
2578                   event? event->button : 0,
2579                   event? event->time : gtk_get_current_event_time());
2580 }
2581
2582 static void
2583 gtk_toolbar_arrow_button_clicked (GtkWidget  *button,
2584                                   GtkToolbar *toolbar)
2585 {
2586   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);  
2587   
2588   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->arrow_button)) &&
2589       (!priv->menu || !GTK_WIDGET_VISIBLE (priv->menu)))
2590     {
2591       /* We only get here when the button is clicked with the keyboard,
2592        * because mouse button presses result in the menu being shown so
2593        * that priv->menu would be non-NULL and visible.
2594        */
2595       show_menu (toolbar, NULL);
2596       gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2597     }
2598 }
2599
2600 static gboolean
2601 gtk_toolbar_arrow_button_press (GtkWidget      *button,
2602                                 GdkEventButton *event,
2603                                 GtkToolbar     *toolbar)
2604 {
2605   show_menu (toolbar, event);
2606   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2607   
2608   return TRUE;
2609 }
2610
2611 static gboolean
2612 gtk_toolbar_button_press (GtkWidget      *toolbar,
2613                           GdkEventButton *event)
2614 {
2615   if (event->button == 3)
2616     {
2617       gboolean return_value;
2618       
2619       g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2620                      (int)event->x_root, (int)event->y_root, event->button,
2621                      &return_value);
2622       
2623       return return_value;
2624     }
2625   
2626   return FALSE;
2627 }
2628
2629 static gboolean
2630 gtk_toolbar_popup_menu (GtkWidget *toolbar)
2631 {
2632   gboolean return_value;
2633   /* This function is the handler for the "popup menu" keybinding,
2634    * ie., it is called when the user presses Shift F10
2635    */
2636   g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2637                  -1, -1, -1, &return_value);
2638   
2639   return return_value;
2640 }
2641
2642 /**
2643  * gtk_toolbar_new:
2644  * 
2645  * Creates a new toolbar. 
2646  
2647  * Return Value: the newly-created toolbar.
2648  **/
2649 GtkWidget *
2650 gtk_toolbar_new (void)
2651 {
2652   GtkToolbar *toolbar;
2653   
2654   toolbar = g_object_new (GTK_TYPE_TOOLBAR, NULL);
2655   
2656   return GTK_WIDGET (toolbar);
2657 }
2658
2659 /**
2660  * gtk_toolbar_insert:
2661  * @toolbar: a #GtkToolbar
2662  * @item: a #GtkToolItem
2663  * @pos: the position of the new item
2664  *
2665  * Insert a #GtkToolItem into the toolbar at position @pos. If @pos is
2666  * 0 the item is prepended to the start of the toolbar. If @pos is
2667  * negative, the item is appended to the end of the toolbar.
2668  *
2669  * Since: 2.4
2670  **/
2671 void
2672 gtk_toolbar_insert (GtkToolbar  *toolbar,
2673                     GtkToolItem *item,
2674                     gint         pos)
2675 {
2676   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2677   g_return_if_fail (GTK_IS_TOOL_ITEM (item));
2678   
2679   if (!gtk_toolbar_check_new_api (toolbar))
2680     return;
2681   
2682   if (pos >= 0)
2683     pos = logical_to_physical (toolbar, pos);
2684
2685   toolbar_content_new_tool_item (toolbar, item, FALSE, pos);
2686 }
2687
2688 /**
2689  * gtk_toolbar_get_item_index:
2690  * @toolbar: a #GtkToolbar
2691  * @item: a #GtkToolItem that is a child of @toolbar
2692  * 
2693  * Returns the position of @item on the toolbar, starting from 0.
2694  * It is an error if @item is not a child of the toolbar.
2695  * 
2696  * Return value: the position of item on the toolbar.
2697  * 
2698  * Since: 2.4
2699  **/
2700 gint
2701 gtk_toolbar_get_item_index (GtkToolbar  *toolbar,
2702                             GtkToolItem *item)
2703 {
2704   GtkToolbarPrivate *priv;
2705   GList *list;
2706   int n;
2707   
2708   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2709   g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1);
2710   g_return_val_if_fail (GTK_WIDGET (item)->parent == GTK_WIDGET (toolbar), -1);
2711   
2712   if (!gtk_toolbar_check_new_api (toolbar))
2713     return -1;
2714   
2715   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2716   
2717   n = 0;
2718   for (list = priv->content; list != NULL; list = list->next)
2719     {
2720       ToolbarContent *content = list->data;
2721       GtkWidget *widget;
2722       
2723       widget = toolbar_content_get_widget (content);
2724       
2725       if (item == GTK_TOOL_ITEM (widget))
2726         break;
2727       
2728       ++n;
2729     }
2730   
2731   return physical_to_logical (toolbar, n);
2732 }
2733
2734 /**
2735  * gtk_toolbar_set_orientation:
2736  * @toolbar: a #GtkToolbar.
2737  * @orientation: a new #GtkOrientation.
2738  * 
2739  * Sets whether a toolbar should appear horizontally or vertically.
2740  **/
2741 void
2742 gtk_toolbar_set_orientation (GtkToolbar     *toolbar,
2743                              GtkOrientation  orientation)
2744 {
2745   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2746   
2747   g_signal_emit (toolbar, toolbar_signals[ORIENTATION_CHANGED], 0, orientation);
2748 }
2749
2750 /**
2751  * gtk_toolbar_get_orientation:
2752  * @toolbar: a #GtkToolbar
2753  * 
2754  * Retrieves the current orientation of the toolbar. See
2755  * gtk_toolbar_set_orientation().
2756  *
2757  * Return value: the orientation
2758  **/
2759 GtkOrientation
2760 gtk_toolbar_get_orientation (GtkToolbar *toolbar)
2761 {
2762   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL);
2763   
2764   return toolbar->orientation;
2765 }
2766
2767 /**
2768  * gtk_toolbar_set_style:
2769  * @toolbar: a #GtkToolbar.
2770  * @style: the new style for @toolbar.
2771  * 
2772  * Alters the view of @toolbar to display either icons only, text only, or both.
2773  **/
2774 void
2775 gtk_toolbar_set_style (GtkToolbar      *toolbar,
2776                        GtkToolbarStyle  style)
2777 {
2778   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2779   
2780   toolbar->style_set = TRUE;  
2781   g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2782 }
2783
2784 /**
2785  * gtk_toolbar_get_style:
2786  * @toolbar: a #GtkToolbar
2787  *
2788  * Retrieves whether the toolbar has text, icons, or both . See
2789  * gtk_toolbar_set_style().
2790  
2791  * Return value: the current style of @toolbar
2792  **/
2793 GtkToolbarStyle
2794 gtk_toolbar_get_style (GtkToolbar *toolbar)
2795 {
2796   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE);
2797   
2798   return toolbar->style;
2799 }
2800
2801 /**
2802  * gtk_toolbar_unset_style:
2803  * @toolbar: a #GtkToolbar
2804  * 
2805  * Unsets a toolbar style set with gtk_toolbar_set_style(), so that
2806  * user preferences will be used to determine the toolbar style.
2807  **/
2808 void
2809 gtk_toolbar_unset_style (GtkToolbar *toolbar)
2810 {
2811   GtkToolbarStyle style;
2812   
2813   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2814   
2815   if (toolbar->style_set)
2816     {
2817       GtkSettings *settings = toolbar_get_settings (toolbar);
2818       
2819       if (settings)
2820         g_object_get (settings,
2821                       "gtk-toolbar-style", &style,
2822                       NULL);
2823       else
2824         style = DEFAULT_TOOLBAR_STYLE;
2825       
2826       if (style != toolbar->style)
2827         g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2828       
2829       toolbar->style_set = FALSE;
2830     }
2831 }
2832
2833 /**
2834  * gtk_toolbar_set_tooltips:
2835  * @toolbar: a #GtkToolbar.
2836  * @enable: set to %FALSE to disable the tooltips, or %TRUE to enable them.
2837  * 
2838  * Sets if the tooltips of a toolbar should be active or not.
2839  **/
2840 void
2841 gtk_toolbar_set_tooltips (GtkToolbar *toolbar,
2842                           gboolean    enable)
2843 {
2844   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2845   
2846   if (enable)
2847     gtk_tooltips_enable (toolbar->tooltips);
2848   else
2849     gtk_tooltips_disable (toolbar->tooltips);
2850
2851   g_object_notify (G_OBJECT (toolbar), "tooltips");
2852 }
2853
2854 /**
2855  * gtk_toolbar_get_tooltips:
2856  * @toolbar: a #GtkToolbar
2857  *
2858  * Retrieves whether tooltips are enabled. See
2859  * gtk_toolbar_set_tooltips().
2860  *
2861  * Return value: %TRUE if tooltips are enabled
2862  **/
2863 gboolean
2864 gtk_toolbar_get_tooltips (GtkToolbar *toolbar)
2865 {
2866   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2867   
2868   return toolbar->tooltips->enabled;
2869 }
2870
2871 /**
2872  * gtk_toolbar_get_n_items:
2873  * @toolbar: a #GtkToolbar
2874  * 
2875  * Returns the number of items on the toolbar.
2876  * 
2877  * Return value: the number of items on the toolbar
2878  * 
2879  * Since: 2.4
2880  **/
2881 gint
2882 gtk_toolbar_get_n_items (GtkToolbar *toolbar)
2883 {
2884   GtkToolbarPrivate *priv;
2885   
2886   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2887   
2888   if (!gtk_toolbar_check_new_api (toolbar))
2889     return -1;
2890   
2891   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2892   
2893   return physical_to_logical (toolbar, g_list_length (priv->content));
2894 }
2895
2896 /**
2897  * gtk_toolbar_get_nth_item:
2898  * @toolbar: a #GtkToolbar
2899  * @n: A position on the toolbar
2900  *
2901  * Returns the @n<!-- -->'s item on @toolbar, or %NULL if the
2902  * toolbar does not contain an @n<!-- -->'th item.
2903  * 
2904  * Return value: The @n<!-- -->'th #GtkToolItem on @toolbar, or %NULL if there
2905  * isn't an @n<!-- -->th item.
2906  * 
2907  * Since: 2.4
2908  **/
2909 GtkToolItem *
2910 gtk_toolbar_get_nth_item (GtkToolbar *toolbar,
2911                           gint        n)
2912 {
2913   GtkToolbarPrivate *priv;
2914   ToolbarContent *content;
2915   gint n_items;
2916   
2917   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
2918   
2919   if (!gtk_toolbar_check_new_api (toolbar))
2920     return NULL;
2921   
2922   n_items = gtk_toolbar_get_n_items (toolbar);
2923   
2924   if (n < 0 || n >= n_items)
2925     return NULL;
2926   
2927   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2928   
2929   content = g_list_nth_data (priv->content, logical_to_physical (toolbar, n));
2930   
2931   g_assert (content);
2932   g_assert (!toolbar_content_is_placeholder (content));
2933   
2934   return GTK_TOOL_ITEM (toolbar_content_get_widget (content));
2935 }
2936
2937 /**
2938  * gtk_toolbar_get_icon_size:
2939  * @toolbar: a #GtkToolbar
2940  *
2941  * Retrieves the icon size fo the toolbar. See gtk_toolbar_set_icon_size().
2942  *
2943  * Return value: the current icon size for the icons on the toolbar.
2944  **/
2945 GtkIconSize
2946 gtk_toolbar_get_icon_size (GtkToolbar *toolbar)
2947 {
2948   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_ICON_SIZE);
2949   
2950   return toolbar->icon_size;
2951 }
2952
2953 /**
2954  * gtk_toolbar_get_relief_style:
2955  * @toolbar: a #GtkToolbar
2956  * 
2957  * Returns the relief style of buttons on @toolbar. See
2958  * gtk_button_set_relief().
2959  * 
2960  * Return value: The relief style of buttons on @toolbar.
2961  * 
2962  * Since: 2.4
2963  **/
2964 GtkReliefStyle
2965 gtk_toolbar_get_relief_style (GtkToolbar *toolbar)
2966 {
2967   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_RELIEF_NONE);
2968   
2969   return get_button_relief (toolbar);
2970 }
2971
2972 /**
2973  * gtk_toolbar_set_show_arrow:
2974  * @toolbar: a #GtkToolbar
2975  * @show_arrow: Whether to show an overflow menu
2976  * 
2977  * Sets whether to show an overflow menu when
2978  * @toolbar doesn't have room for all items on it. If %TRUE,
2979  * items that there are not room are available through an
2980  * overflow menu.
2981  * 
2982  * Since: 2.4
2983  **/
2984 void
2985 gtk_toolbar_set_show_arrow (GtkToolbar *toolbar,
2986                             gboolean    show_arrow)
2987 {
2988   GtkToolbarPrivate *priv;
2989   
2990   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2991   
2992   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2993   show_arrow = show_arrow != FALSE;
2994   
2995   if (priv->show_arrow != show_arrow)
2996     {
2997       priv->show_arrow = show_arrow;
2998       
2999       if (!priv->show_arrow)
3000         gtk_widget_hide (priv->arrow_button);
3001       
3002       gtk_widget_queue_resize (GTK_WIDGET (toolbar));      
3003       g_object_notify (G_OBJECT (toolbar), "show-arrow");
3004     }
3005 }
3006
3007 /**
3008  * gtk_toolbar_get_show_arrow:
3009  * @toolbar: a #GtkToolbar
3010  * 
3011  * Returns whether the toolbar has an overflow menu.
3012  * See gtk_toolbar_set_show_arrow()
3013  * 
3014  * Return value: 
3015  * 
3016  * Since: 2.4
3017  **/
3018 gboolean
3019 gtk_toolbar_get_show_arrow (GtkToolbar *toolbar)
3020 {
3021   GtkToolbarPrivate *priv;
3022   
3023   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
3024   
3025   if (!gtk_toolbar_check_new_api (toolbar))
3026     return FALSE;
3027   
3028   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3029   
3030   return priv->show_arrow;
3031 }
3032
3033 /**
3034  * gtk_toolbar_get_drop_index:
3035  * @toolbar: a #GtkToolbar
3036  * @x: x coordinate of a point on the toolbar
3037  * @y: y coordinate of a point on the toolbar
3038  *
3039  * Returns the position corresponding to the indicated point on
3040  * @toolbar. This is useful when dragging items to the toolbar:
3041  * this function returns the position a new item should be
3042  * inserted.
3043  *
3044  * @x and @y are in @toolbar coordinates.
3045  * 
3046  * Return value: The position corresponding to the point (@x, @y) on the toolbar.
3047  * 
3048  * Since: 2.4
3049  **/
3050 gint
3051 gtk_toolbar_get_drop_index (GtkToolbar *toolbar,
3052                             gint        x,
3053                             gint        y)
3054 {
3055   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
3056   
3057   if (!gtk_toolbar_check_new_api (toolbar))
3058     return -1;
3059   
3060   return physical_to_logical (toolbar, find_drop_index (toolbar, x, y));
3061 }
3062
3063 static void
3064 gtk_toolbar_finalize (GObject *object)
3065 {
3066   GList *list;
3067   GtkToolbar *toolbar = GTK_TOOLBAR (object);
3068   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3069   
3070   if (toolbar->tooltips)
3071     g_object_unref (toolbar->tooltips);
3072   
3073   if (priv->arrow_button)
3074     gtk_widget_unparent (priv->arrow_button);
3075
3076   for (list = priv->content; list != NULL; list = list->next)
3077     {
3078       ToolbarContent *content = list->data;
3079
3080       toolbar_content_free (content);
3081     }
3082   
3083   g_list_free (priv->content);
3084   g_list_free (toolbar->children);
3085   
3086   g_timer_destroy (priv->timer);
3087   
3088   if (priv->menu)
3089     gtk_widget_destroy (GTK_WIDGET (priv->menu));
3090   
3091   if (priv->idle_id)
3092     g_source_remove (priv->idle_id);
3093
3094   G_OBJECT_CLASS (parent_class)->finalize (object);
3095 }
3096
3097 /*
3098  * Deprecated API
3099  */
3100
3101 /**
3102  * gtk_toolbar_set_icon_size:
3103  * @toolbar: A #GtkToolbar
3104  * @icon_size: The #GtkIconSize that stock icons in the toolbar shall have.
3105  *
3106  * This function sets the size of stock icons in the toolbar. You
3107  * can call it both before you add the icons and after they've been
3108  * added. The size you set will override user preferences for the default
3109  * icon size.
3110  * 
3111  * Deprecated: Applications should respect the user preferences for
3112  *   the size of icons in toolbars.
3113  **/
3114 void
3115 gtk_toolbar_set_icon_size (GtkToolbar  *toolbar,
3116                            GtkIconSize  icon_size)
3117 {
3118   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3119   
3120   toolbar->icon_size_set = TRUE;
3121   
3122   if (toolbar->icon_size == icon_size)
3123     return;
3124   
3125   toolbar->icon_size = icon_size;
3126   
3127   gtk_toolbar_reconfigured (toolbar);
3128   
3129   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3130 }
3131
3132 /**
3133  * gtk_toolbar_unset_icon_size:
3134  * @toolbar: a #GtkToolbar
3135  * 
3136  * Unsets toolbar icon size set with gtk_toolbar_set_icon_size(), so that
3137  * user preferences will be used to determine the icon size.
3138  **/
3139 void
3140 gtk_toolbar_unset_icon_size (GtkToolbar *toolbar)
3141 {
3142   GtkIconSize size;
3143   
3144   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3145   
3146   if (toolbar->icon_size_set)
3147     {
3148       GtkSettings *settings = toolbar_get_settings (toolbar);
3149       
3150       if (settings)
3151         {
3152           g_object_get (settings,
3153                         "gtk-toolbar-icon-size", &size,
3154                         NULL);
3155         }
3156       else
3157         size = DEFAULT_ICON_SIZE;
3158       
3159       if (size != toolbar->icon_size)
3160         gtk_toolbar_set_icon_size (toolbar, size);
3161       
3162       toolbar->icon_size_set = FALSE;
3163     }
3164 }
3165
3166 /**
3167  * gtk_toolbar_append_item:
3168  * @toolbar: a #GtkToolbar.
3169  * @text: give your toolbar button a label.
3170  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3171  * @tooltip_private_text: use with #GtkTipsQuery.
3172  * @icon: a #GtkWidget that should be used as the button's icon.
3173  * @callback: the function to be executed when the button is pressed.
3174  * @user_data: a pointer to any data you wish to be passed to the callback.
3175  * 
3176  * Inserts a new item into the toolbar. You must specify the position
3177  * in the toolbar where it will be inserted.
3178  *
3179  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3180  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3181  *
3182  * Return value: the new toolbar item as a #GtkWidget.
3183  **/
3184 GtkWidget *
3185 gtk_toolbar_append_item (GtkToolbar    *toolbar,
3186                          const char    *text,
3187                          const char    *tooltip_text,
3188                          const char    *tooltip_private_text,
3189                          GtkWidget     *icon,
3190                          GtkSignalFunc  callback,
3191                          gpointer       user_data)
3192 {
3193   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3194                                      NULL, text,
3195                                      tooltip_text, tooltip_private_text,
3196                                      icon, callback, user_data,
3197                                      toolbar->num_children);
3198 }
3199
3200 /**
3201  * gtk_toolbar_prepend_item:
3202  * @toolbar: a #GtkToolbar.
3203  * @text: give your toolbar button a label.
3204  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3205  * @tooltip_private_text: use with #GtkTipsQuery.
3206  * @icon: a #GtkWidget that should be used as the button's icon.
3207  * @callback: the function to be executed when the button is pressed.
3208  * @user_data: a pointer to any data you wish to be passed to the callback.
3209  * 
3210  * Adds a new button to the beginning (top or left edges) of the given toolbar.
3211  *
3212  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3213  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3214  *
3215  * Return value: the new toolbar item as a #GtkWidget.
3216  **/
3217 GtkWidget *
3218 gtk_toolbar_prepend_item (GtkToolbar    *toolbar,
3219                           const char    *text,
3220                           const char    *tooltip_text,
3221                           const char    *tooltip_private_text,
3222                           GtkWidget     *icon,
3223                           GtkSignalFunc  callback,
3224                           gpointer       user_data)
3225 {
3226   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3227                                      NULL, text,
3228                                      tooltip_text, tooltip_private_text,
3229                                      icon, callback, user_data,
3230                                      0);
3231 }
3232
3233 /**
3234  * gtk_toolbar_insert_item:
3235  * @toolbar: a #GtkToolbar.
3236  * @text: give your toolbar button a label.
3237  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3238  * @tooltip_private_text: use with #GtkTipsQuery.
3239  * @icon: a #GtkWidget that should be used as the button's icon.
3240  * @callback: the function to be executed when the button is pressed.
3241  * @user_data: a pointer to any data you wish to be passed to the callback.
3242  * @position: the number of widgets to insert this item after.
3243  * 
3244  * Inserts a new item into the toolbar. You must specify the position in the
3245  * toolbar where it will be inserted.
3246  *
3247  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3248  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3249  *
3250  * Return value: the new toolbar item as a #GtkWidget.
3251  **/
3252 GtkWidget *
3253 gtk_toolbar_insert_item (GtkToolbar    *toolbar,
3254                          const char    *text,
3255                          const char    *tooltip_text,
3256                          const char    *tooltip_private_text,
3257                          GtkWidget     *icon,
3258                          GtkSignalFunc  callback,
3259                          gpointer       user_data,
3260                          gint           position)
3261 {
3262   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3263                                      NULL, text,
3264                                      tooltip_text, tooltip_private_text,
3265                                      icon, callback, user_data,
3266                                      position);
3267 }
3268
3269 /**
3270  * gtk_toolbar_insert_stock:
3271  * @toolbar: A #GtkToolbar
3272  * @stock_id: The id of the stock item you want to insert
3273  * @tooltip_text: The text in the tooltip of the toolbar button
3274  * @tooltip_private_text: The private text of the tooltip
3275  * @callback: The callback called when the toolbar button is clicked.
3276  * @user_data: user data passed to callback
3277  * @position: The position the button shall be inserted at.
3278  *            -1 means at the end.
3279  *
3280  * Inserts a stock item at the specified position of the toolbar.  If
3281  * @stock_id is not a known stock item ID, it's inserted verbatim,
3282  * except that underscores used to mark mnemonics are removed.
3283  *
3284  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3285  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3286  *
3287  * Returns: the inserted widget
3288  */
3289 GtkWidget*
3290 gtk_toolbar_insert_stock (GtkToolbar      *toolbar,
3291                           const gchar     *stock_id,
3292                           const char      *tooltip_text,
3293                           const char      *tooltip_private_text,
3294                           GtkSignalFunc    callback,
3295                           gpointer         user_data,
3296                           gint             position)
3297 {
3298   return internal_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3299                                   NULL, stock_id,
3300                                   tooltip_text, tooltip_private_text,
3301                                   NULL, callback, user_data,
3302                                   position, TRUE);
3303 }
3304
3305 /**
3306  * gtk_toolbar_append_space:
3307  * @toolbar: a #GtkToolbar.
3308  * 
3309  * Adds a new space to the end of the toolbar.
3310  **/
3311 void
3312 gtk_toolbar_append_space (GtkToolbar *toolbar)
3313 {
3314   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3315                               NULL, NULL,
3316                               NULL, NULL,
3317                               NULL, NULL, NULL,
3318                               toolbar->num_children);
3319 }
3320
3321 /**
3322  * gtk_toolbar_prepend_space:
3323  * @toolbar: a #GtkToolbar.
3324  * 
3325  * Adds a new space to the beginning of the toolbar.
3326  **/
3327 void
3328 gtk_toolbar_prepend_space (GtkToolbar *toolbar)
3329 {
3330   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3331                               NULL, NULL,
3332                               NULL, NULL,
3333                               NULL, NULL, NULL,
3334                               0);
3335 }
3336
3337 /**
3338  * gtk_toolbar_insert_space:
3339  * @toolbar: a #GtkToolbar
3340  * @position: the number of widgets after which a space should be inserted.
3341  * 
3342  * Inserts a new space in the toolbar at the specified position.
3343  **/
3344 void
3345 gtk_toolbar_insert_space (GtkToolbar *toolbar,
3346                           gint        position)
3347 {
3348   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3349                               NULL, NULL,
3350                               NULL, NULL,
3351                               NULL, NULL, NULL,
3352                               position);
3353 }
3354
3355 /**
3356  * gtk_toolbar_remove_space:
3357  * @toolbar: a #GtkToolbar.
3358  * @position: the index of the space to remove.
3359  * 
3360  * Removes a space from the specified position.
3361  **/
3362 void
3363 gtk_toolbar_remove_space (GtkToolbar *toolbar,
3364                           gint        position)
3365 {
3366   GtkToolbarPrivate *priv;
3367   ToolbarContent *content;
3368   
3369   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3370   
3371   if (!gtk_toolbar_check_old_api (toolbar))
3372     return;
3373   
3374   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3375   
3376   content = g_list_nth_data (priv->content, position);
3377   
3378   if (!content)
3379     {
3380       g_warning ("Toolbar position %d doesn't exist", position);
3381       return;
3382     }
3383   
3384   if (!toolbar_content_is_separator (content))
3385     {
3386       g_warning ("Toolbar position %d is not a space", position);
3387       return;
3388     }
3389   
3390   toolbar_content_remove (content, toolbar);
3391   toolbar_content_free (content);
3392 }
3393
3394 /**
3395  * gtk_toolbar_append_widget:
3396  * @toolbar: a #GtkToolbar.
3397  * @widget: a #GtkWidget to add to the toolbar. 
3398  * @tooltip_text: the element's tooltip.
3399  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3400  * 
3401  * Adds a widget to the end of the given toolbar.
3402  **/ 
3403 void
3404 gtk_toolbar_append_widget (GtkToolbar  *toolbar,
3405                            GtkWidget   *widget,
3406                            const gchar *tooltip_text,
3407                            const gchar *tooltip_private_text)
3408 {
3409   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3410                               widget, NULL,
3411                               tooltip_text, tooltip_private_text,
3412                               NULL, NULL, NULL,
3413                               toolbar->num_children);
3414 }
3415
3416 /**
3417  * gtk_toolbar_prepend_widget:
3418  * @toolbar: a #GtkToolbar.
3419  * @widget: a #GtkWidget to add to the toolbar. 
3420  * @tooltip_text: the element's tooltip.
3421  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3422  * 
3423  * Adds a widget to the beginning of the given toolbar.
3424  **/ 
3425 void
3426 gtk_toolbar_prepend_widget (GtkToolbar  *toolbar,
3427                             GtkWidget   *widget,
3428                             const gchar *tooltip_text,
3429                             const gchar *tooltip_private_text)
3430 {
3431   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3432                               widget, NULL,
3433                               tooltip_text, tooltip_private_text,
3434                               NULL, NULL, NULL,
3435                               0);
3436 }
3437
3438 /**
3439  * gtk_toolbar_insert_widget:
3440  * @toolbar: a #GtkToolbar.
3441  * @widget: a #GtkWidget to add to the toolbar. 
3442  * @tooltip_text: the element's tooltip.
3443  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3444  * @position: the number of widgets to insert this widget after.
3445  * 
3446  * Inserts a widget in the toolbar at the given position.
3447  **/ 
3448 void
3449 gtk_toolbar_insert_widget (GtkToolbar *toolbar,
3450                            GtkWidget  *widget,
3451                            const char *tooltip_text,
3452                            const char *tooltip_private_text,
3453                            gint        position)
3454 {
3455   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3456                               widget, NULL,
3457                               tooltip_text, tooltip_private_text,
3458                               NULL, NULL, NULL,
3459                               position);
3460 }
3461
3462 /**
3463  * gtk_toolbar_append_element:
3464  * @toolbar: a #GtkToolbar.
3465  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3466  * @widget: a #GtkWidget, or %NULL.
3467  * @text: the element's label.
3468  * @tooltip_text: the element's tooltip.
3469  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3470  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3471  * @callback: the function to be executed when the button is pressed.
3472  * @user_data: any data you wish to pass to the callback.
3473  * 
3474  * Adds a new element to the end of a toolbar.
3475  * 
3476  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3477  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3478  * the radio group for the new element. In all other cases, @widget must
3479  * be %NULL.
3480  * 
3481  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3482  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3483  *
3484  * Return value: the new toolbar element as a #GtkWidget.
3485  **/
3486 GtkWidget*
3487 gtk_toolbar_append_element (GtkToolbar          *toolbar,
3488                             GtkToolbarChildType  type,
3489                             GtkWidget           *widget,
3490                             const char          *text,
3491                             const char          *tooltip_text,
3492                             const char          *tooltip_private_text,
3493                             GtkWidget           *icon,
3494                             GtkSignalFunc        callback,
3495                             gpointer             user_data)
3496 {
3497   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3498                                      tooltip_text, tooltip_private_text,
3499                                      icon, callback, user_data,
3500                                      toolbar->num_children);
3501 }
3502
3503 /**
3504  * gtk_toolbar_prepend_element:
3505  * @toolbar: a #GtkToolbar.
3506  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3507  * @widget: a #GtkWidget, or %NULL
3508  * @text: the element's label.
3509  * @tooltip_text: the element's tooltip.
3510  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3511  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3512  * @callback: the function to be executed when the button is pressed.
3513  * @user_data: any data you wish to pass to the callback.
3514  *  
3515  * Adds a new element to the beginning of a toolbar.
3516  * 
3517  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3518  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3519  * the radio group for the new element. In all other cases, @widget must
3520  * be %NULL.
3521  * 
3522  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3523  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3524  *
3525  * Return value: the new toolbar element as a #GtkWidget.
3526  **/
3527 GtkWidget *
3528 gtk_toolbar_prepend_element (GtkToolbar          *toolbar,
3529                              GtkToolbarChildType  type,
3530                              GtkWidget           *widget,
3531                              const char          *text,
3532                              const char          *tooltip_text,
3533                              const char          *tooltip_private_text,
3534                              GtkWidget           *icon,
3535                              GtkSignalFunc        callback,
3536                              gpointer             user_data)
3537 {
3538   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3539                                      tooltip_text, tooltip_private_text,
3540                                      icon, callback, user_data, 0);
3541 }
3542
3543 /**
3544  * gtk_toolbar_insert_element:
3545  * @toolbar: a #GtkToolbar.
3546  * @type: a value of type #GtkToolbarChildType that determines what @widget
3547  *   will be.
3548  * @widget: a #GtkWidget, or %NULL. 
3549  * @text: the element's label.
3550  * @tooltip_text: the element's tooltip.
3551  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3552  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3553  * @callback: the function to be executed when the button is pressed.
3554  * @user_data: any data you wish to pass to the callback.
3555  * @position: the number of widgets to insert this element after.
3556  *
3557  * Inserts a new element in the toolbar at the given position. 
3558  *
3559  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3560  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3561  * the radio group for the new element. In all other cases, @widget must
3562  * be %NULL.
3563  *
3564  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3565  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3566  *
3567  * Return value: the new toolbar element as a #GtkWidget.
3568  **/
3569 GtkWidget *
3570 gtk_toolbar_insert_element (GtkToolbar          *toolbar,
3571                             GtkToolbarChildType  type,
3572                             GtkWidget           *widget,
3573                             const char          *text,
3574                             const char          *tooltip_text,
3575                             const char          *tooltip_private_text,
3576                             GtkWidget           *icon,
3577                             GtkSignalFunc        callback,
3578                             gpointer             user_data,
3579                             gint                 position)
3580 {
3581   return internal_insert_element (toolbar, type, widget, text,
3582                                   tooltip_text, tooltip_private_text,
3583                                   icon, callback, user_data, position, FALSE);
3584 }
3585
3586 static void
3587 set_child_packing_and_visibility(GtkToolbar      *toolbar,
3588                                  GtkToolbarChild *child)
3589 {
3590   GtkWidget *box;
3591   gboolean   expand;
3592
3593   box = gtk_bin_get_child (GTK_BIN (child->widget));
3594   
3595   g_return_if_fail (GTK_IS_BOX (box));
3596   
3597   if (child->label)
3598     {
3599       expand = (toolbar->style != GTK_TOOLBAR_BOTH);
3600       
3601       gtk_box_set_child_packing (GTK_BOX (box), child->label,
3602                                  expand, expand, 0, GTK_PACK_END);
3603       
3604       if (toolbar->style != GTK_TOOLBAR_ICONS)
3605         gtk_widget_show (child->label);
3606       else
3607         gtk_widget_hide (child->label);
3608     }
3609   
3610   if (child->icon)
3611     {
3612       expand = (toolbar->style != GTK_TOOLBAR_BOTH_HORIZ);
3613       
3614       gtk_box_set_child_packing (GTK_BOX (box), child->icon,
3615                                  expand, expand, 0, GTK_PACK_END);
3616       
3617       if (toolbar->style != GTK_TOOLBAR_TEXT)
3618         gtk_widget_show (child->icon);
3619       else
3620         gtk_widget_hide (child->icon);
3621     }
3622 }
3623
3624 static GtkWidget *
3625 internal_insert_element (GtkToolbar          *toolbar,
3626                          GtkToolbarChildType  type,
3627                          GtkWidget           *widget,
3628                          const char          *text,
3629                          const char          *tooltip_text,
3630                          const char          *tooltip_private_text,
3631                          GtkWidget           *icon,
3632                          GtkSignalFunc        callback,
3633                          gpointer             user_data,
3634                          gint                 position,
3635                          gboolean             use_stock)
3636 {
3637   GtkWidget *box;
3638   ToolbarContent *content;
3639   GtkToolbarPrivate *priv;
3640   char *free_me = NULL;
3641   gboolean is_button = FALSE;
3642
3643   GtkWidget *child_widget;
3644   GtkWidget *child_label;
3645   GtkWidget *child_icon;
3646
3647   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
3648   if (type == GTK_TOOLBAR_CHILD_WIDGET)
3649     g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
3650   else if (type != GTK_TOOLBAR_CHILD_RADIOBUTTON)
3651     g_return_val_if_fail (widget == NULL, NULL);
3652   if (GTK_IS_TOOL_ITEM (widget))
3653     g_warning (MIXED_API_WARNING);
3654   
3655   if (!gtk_toolbar_check_old_api (toolbar))
3656     return NULL;
3657   
3658   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3659   
3660   child_widget = NULL;
3661   child_label = NULL;
3662   child_icon = NULL;
3663   
3664   switch (type)
3665     {
3666     case GTK_TOOLBAR_CHILD_SPACE:
3667       break;
3668       
3669     case GTK_TOOLBAR_CHILD_WIDGET:
3670       child_widget = widget;
3671       break;
3672       
3673     case GTK_TOOLBAR_CHILD_BUTTON:
3674     case GTK_TOOLBAR_CHILD_TOGGLEBUTTON:
3675     case GTK_TOOLBAR_CHILD_RADIOBUTTON:
3676       is_button = TRUE;
3677       if (type == GTK_TOOLBAR_CHILD_BUTTON)
3678         {
3679           child_widget = gtk_button_new ();
3680         }
3681       else if (type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
3682         {
3683           child_widget = gtk_toggle_button_new ();
3684           gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child_widget), FALSE);
3685         }
3686       else /* type == GTK_TOOLBAR_CHILD_RADIOBUTTON */
3687         {
3688           GSList *group = NULL;
3689
3690           if (widget)
3691             group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
3692           
3693           child_widget = gtk_radio_button_new (group);
3694           gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child_widget), FALSE);
3695         }
3696
3697       gtk_button_set_relief (GTK_BUTTON (child_widget), get_button_relief (toolbar));
3698       gtk_button_set_focus_on_click (GTK_BUTTON (child_widget), FALSE);
3699       
3700       if (callback)
3701         {
3702           g_signal_connect (child_widget, "clicked",
3703                             callback, user_data);
3704         }
3705       
3706       if (toolbar->style == GTK_TOOLBAR_BOTH_HORIZ)
3707         box = gtk_hbox_new (FALSE, 0);
3708       else
3709         box = gtk_vbox_new (FALSE, 0);
3710
3711       gtk_container_add (GTK_CONTAINER (child_widget), box);
3712       gtk_widget_show (box);
3713       
3714       if (text && use_stock)
3715         {
3716           GtkStockItem stock_item;
3717           if (gtk_stock_lookup (text, &stock_item))
3718             {
3719               if (!icon)
3720                 icon = gtk_image_new_from_stock (text, toolbar->icon_size);
3721           
3722               text = free_me = _gtk_toolbar_elide_underscores (stock_item.label);
3723             }
3724         }
3725       
3726       if (text)
3727         {
3728           child_label = gtk_label_new (text);
3729           
3730           gtk_container_add (GTK_CONTAINER (box), child_label);
3731         }
3732       
3733       if (icon)
3734         {
3735           child_icon = GTK_WIDGET (icon);
3736           gtk_container_add (GTK_CONTAINER (box), child_icon);
3737         }
3738       
3739       gtk_widget_show (child_widget);
3740       break;
3741       
3742     default:
3743       g_assert_not_reached ();
3744       break;
3745     }
3746   
3747   if ((type != GTK_TOOLBAR_CHILD_SPACE) && tooltip_text)
3748     {
3749       gtk_tooltips_set_tip (toolbar->tooltips, child_widget,
3750                             tooltip_text, tooltip_private_text);
3751     }
3752   
3753   content = toolbar_content_new_compatibility (toolbar, type, child_widget,
3754                                                child_icon, child_label, position);
3755   
3756   if (free_me)
3757     g_free (free_me);
3758   
3759   return child_widget;
3760 }
3761
3762 /*
3763  * ToolbarContent methods
3764  */
3765 typedef enum {
3766   UNKNOWN,
3767   YES,
3768   NO,
3769 } TriState;
3770
3771 struct _ToolbarContent
3772 {
3773   ContentType   type;
3774   ItemState     state;
3775   
3776   union
3777   {
3778     struct
3779     {
3780       GtkToolItem *     item;
3781       GtkAllocation     start_allocation;
3782       GtkAllocation     goal_allocation;
3783       guint             is_placeholder : 1;
3784       guint             disappearing : 1;
3785       TriState          has_menu : 2;
3786     } tool_item;
3787     
3788     struct
3789     {
3790       GtkToolbarChild   child;
3791       GtkAllocation     space_allocation;
3792       guint             space_visible : 1;
3793     } compatibility;
3794   } u;
3795 };
3796
3797 static ToolbarContent *
3798 toolbar_content_new_tool_item (GtkToolbar  *toolbar,
3799                                GtkToolItem *item,
3800                                gboolean     is_placeholder,
3801                                gint         pos)
3802 {
3803   ToolbarContent *content;
3804   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3805   
3806   content = g_new0 (ToolbarContent, 1);
3807   
3808   content->type = TOOL_ITEM;
3809   content->state = NOT_ALLOCATED;
3810   content->u.tool_item.item = item;
3811   content->u.tool_item.is_placeholder = is_placeholder;
3812   
3813   gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar));
3814
3815   priv->content = g_list_insert (priv->content, content, pos);
3816   
3817   if (!is_placeholder)
3818     {
3819       toolbar->num_children++;
3820
3821       gtk_toolbar_stop_sliding (toolbar);
3822     }
3823
3824   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3825   priv->need_rebuild = TRUE;
3826   
3827   return content;
3828 }
3829
3830 static ToolbarContent *
3831 toolbar_content_new_compatibility (GtkToolbar          *toolbar,
3832                                    GtkToolbarChildType  type,
3833                                    GtkWidget            *widget,
3834                                    GtkWidget            *icon,
3835                                    GtkWidget            *label,
3836                                    gint                  pos)
3837 {
3838   ToolbarContent *content;
3839   GtkToolbarChild *child;
3840   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3841   
3842   content = g_new0 (ToolbarContent, 1);
3843
3844   child = &(content->u.compatibility.child);
3845   
3846   content->type = COMPATIBILITY;
3847   child->type = type;
3848   child->widget = widget;
3849   child->icon = icon;
3850   child->label = label;
3851   
3852   if (type != GTK_TOOLBAR_CHILD_SPACE)
3853     {
3854       gtk_widget_set_parent (child->widget, GTK_WIDGET (toolbar));
3855     }
3856   else
3857     {
3858       content->u.compatibility.space_visible = TRUE;
3859       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3860     }
3861  
3862   if (type == GTK_TOOLBAR_CHILD_BUTTON ||
3863       type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
3864       type == GTK_TOOLBAR_CHILD_RADIOBUTTON)
3865     {
3866       set_child_packing_and_visibility (toolbar, child);
3867     }
3868
3869   priv->content = g_list_insert (priv->content, content, pos);
3870   toolbar->children = g_list_insert (toolbar->children, child, pos);
3871   priv->need_rebuild = TRUE;
3872   
3873   toolbar->num_children++;
3874   
3875   return content;
3876 }
3877
3878 static void
3879 toolbar_content_remove (ToolbarContent *content,
3880                         GtkToolbar     *toolbar)
3881 {
3882   GtkToolbarChild *child;
3883   GtkToolbarPrivate *priv;
3884
3885   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3886   
3887   switch (content->type)
3888     {
3889     case TOOL_ITEM:
3890       gtk_widget_unparent (GTK_WIDGET (content->u.tool_item.item));
3891       break;
3892       
3893     case COMPATIBILITY:
3894       child = &(content->u.compatibility.child);
3895       
3896       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
3897         {
3898           g_object_ref (child->widget);
3899           gtk_widget_unparent (child->widget);
3900           gtk_widget_destroy (child->widget);
3901           g_object_unref (child->widget);
3902         }
3903       
3904       toolbar->children = g_list_remove (toolbar->children, child);
3905       break;
3906     }
3907
3908   priv->content = g_list_remove (priv->content, content);
3909
3910   if (!toolbar_content_is_placeholder (content))
3911     toolbar->num_children--;
3912
3913   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3914   priv->need_rebuild = TRUE;
3915 }
3916
3917 static void
3918 toolbar_content_free (ToolbarContent *content)
3919 {
3920   g_free (content);
3921 }
3922
3923 static gint
3924 calculate_max_homogeneous_pixels (GtkWidget *widget)
3925 {
3926   PangoContext *context;
3927   PangoFontMetrics *metrics;
3928   gint char_width;
3929   
3930   context = gtk_widget_get_pango_context (widget);
3931   metrics = pango_context_get_metrics (context,
3932                                        widget->style->font_desc,
3933                                        pango_context_get_language (context));
3934   char_width = pango_font_metrics_get_approximate_char_width (metrics);
3935   pango_font_metrics_unref (metrics);
3936   
3937   return PANGO_PIXELS (MAX_HOMOGENEOUS_N_CHARS * char_width);
3938 }
3939
3940 static void
3941 toolbar_content_expose (ToolbarContent *content,
3942                         GtkContainer   *container,
3943                         GdkEventExpose *expose)
3944 {
3945   GtkToolbar *toolbar = GTK_TOOLBAR (container);
3946   GtkToolbarChild *child;
3947   GtkWidget *widget = NULL; /* quiet gcc */
3948   
3949   switch (content->type)
3950     {
3951     case TOOL_ITEM:
3952       if (!content->u.tool_item.is_placeholder)
3953         widget = GTK_WIDGET (content->u.tool_item.item);
3954       break;
3955       
3956     case COMPATIBILITY:
3957       child = &(content->u.compatibility.child);
3958       
3959       if (child->type == GTK_TOOLBAR_CHILD_SPACE)
3960         {
3961           if (get_space_style (toolbar) == GTK_TOOLBAR_SPACE_LINE &&
3962               content->u.compatibility.space_visible)
3963             {
3964               _gtk_toolbar_paint_space_line (GTK_WIDGET (toolbar), toolbar,
3965                                              &expose->area,
3966                                              &content->u.compatibility.space_allocation);
3967             }
3968           return;
3969         }
3970       
3971       widget = child->widget;
3972       break;
3973     }
3974   
3975   if (widget)
3976     gtk_container_propagate_expose (container, widget, expose);
3977 }
3978
3979 static gboolean
3980 toolbar_content_visible (ToolbarContent *content,
3981                          GtkToolbar     *toolbar)
3982 {
3983   GtkToolItem *item;
3984   
3985   switch (content->type)
3986     {
3987     case TOOL_ITEM:
3988       item = content->u.tool_item.item;
3989       
3990       if (!GTK_WIDGET_VISIBLE (item))
3991         return FALSE;
3992       
3993       if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL &&
3994           gtk_tool_item_get_visible_horizontal (item))
3995         {
3996           return TRUE;
3997         }
3998       
3999       if ((toolbar->orientation == GTK_ORIENTATION_VERTICAL &&
4000            gtk_tool_item_get_visible_vertical (item)))
4001         {
4002           return TRUE;
4003         }
4004       
4005       return FALSE;
4006       break;
4007       
4008     case COMPATIBILITY:
4009       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4010         return GTK_WIDGET_VISIBLE (content->u.compatibility.child.widget);
4011       else
4012         return TRUE;
4013       break;
4014     }
4015   
4016   g_assert_not_reached ();
4017   return FALSE;
4018 }
4019
4020 static void
4021 toolbar_content_size_request (ToolbarContent *content,
4022                               GtkToolbar     *toolbar,
4023                               GtkRequisition *requisition)
4024 {
4025   gint space_size;
4026   
4027   switch (content->type)
4028     {
4029     case TOOL_ITEM:
4030       gtk_widget_size_request (GTK_WIDGET (content->u.tool_item.item),
4031                                requisition);
4032       if (content->u.tool_item.is_placeholder &&
4033           content->u.tool_item.disappearing)
4034         {
4035           requisition->width = 0;
4036           requisition->height = 0;
4037         }
4038       break;
4039       
4040     case COMPATIBILITY:
4041       space_size = get_space_size (toolbar);
4042       
4043       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4044         {
4045           gtk_widget_size_request (content->u.compatibility.child.widget,
4046                                    requisition);
4047         }
4048       else
4049         {
4050           if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
4051             {
4052               requisition->width = space_size;
4053               requisition->height = 0;
4054             }
4055           else
4056             {
4057               requisition->height = space_size;
4058               requisition->width = 0;
4059             }
4060         }
4061       
4062       break;
4063     }
4064 }
4065
4066 static gboolean
4067 toolbar_content_is_homogeneous (ToolbarContent *content,
4068                                 GtkToolbar     *toolbar)
4069 {
4070   gboolean result = FALSE;      /* quiet gcc */
4071   GtkRequisition requisition;
4072   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4073   
4074   if (priv->max_homogeneous_pixels < 0)
4075     {
4076       priv->max_homogeneous_pixels =
4077         calculate_max_homogeneous_pixels (GTK_WIDGET (toolbar));
4078     }
4079   
4080   toolbar_content_size_request (content, toolbar, &requisition);
4081   
4082   if (requisition.width > priv->max_homogeneous_pixels)
4083     return FALSE;
4084   
4085   switch (content->type)
4086     {
4087     case TOOL_ITEM:
4088       result = gtk_tool_item_get_homogeneous (content->u.tool_item.item) &&
4089         !GTK_IS_SEPARATOR_TOOL_ITEM (content->u.tool_item.item);
4090       
4091       if (gtk_tool_item_get_is_important (content->u.tool_item.item) &&
4092           toolbar->style == GTK_TOOLBAR_BOTH_HORIZ &&
4093           toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
4094         {
4095           result = FALSE;
4096         }
4097       break;
4098       
4099     case COMPATIBILITY:
4100       if (content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_BUTTON ||
4101           content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4102           content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4103         {
4104           result = TRUE;
4105         }
4106       else
4107         {
4108           result = FALSE;
4109         }
4110       break;
4111     }
4112   
4113   return result;
4114 }
4115
4116 static gboolean
4117 toolbar_content_is_placeholder (ToolbarContent *content)
4118 {
4119   if (content->type == TOOL_ITEM && content->u.tool_item.is_placeholder)
4120     return TRUE;
4121   
4122   return FALSE;
4123 }
4124
4125 static gboolean
4126 toolbar_content_disappearing (ToolbarContent *content)
4127 {
4128   if (content->type == TOOL_ITEM && content->u.tool_item.disappearing)
4129     return TRUE;
4130   
4131   return FALSE;
4132 }
4133
4134 static ItemState
4135 toolbar_content_get_state (ToolbarContent *content)
4136 {
4137   return content->state;
4138 }
4139
4140 static gboolean
4141 toolbar_content_child_visible (ToolbarContent *content)
4142 {
4143   switch (content->type)
4144     {
4145     case TOOL_ITEM:
4146       return GTK_WIDGET_CHILD_VISIBLE (content->u.tool_item.item);
4147       break;
4148       
4149     case COMPATIBILITY:
4150       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4151         {
4152           return GTK_WIDGET_CHILD_VISIBLE (content->u.compatibility.child.widget);
4153         }
4154       else
4155         {
4156           return content->u.compatibility.space_visible;
4157         }
4158       break;
4159     }
4160   
4161   return FALSE; /* quiet gcc */
4162 }
4163
4164 static void
4165 toolbar_content_get_goal_allocation (ToolbarContent *content,
4166                                      GtkAllocation  *allocation)
4167 {
4168   switch (content->type)
4169     {
4170     case TOOL_ITEM:
4171       *allocation = content->u.tool_item.goal_allocation;
4172       break;
4173       
4174     case COMPATIBILITY:
4175       /* Goal allocations are only relevant when we are
4176        * using the new API, so we should never get here
4177        */
4178       g_assert_not_reached ();
4179       break;
4180     }
4181 }
4182
4183 static void
4184 toolbar_content_get_allocation (ToolbarContent *content,
4185                                 GtkAllocation  *allocation)
4186 {
4187   GtkToolbarChild *child;
4188   
4189   switch (content->type)
4190     {
4191     case TOOL_ITEM:
4192       *allocation = GTK_WIDGET (content->u.tool_item.item)->allocation;
4193       break;
4194       
4195     case COMPATIBILITY:
4196       child = &(content->u.compatibility.child);
4197       
4198       if (child->type == GTK_TOOLBAR_CHILD_SPACE)
4199         *allocation = content->u.compatibility.space_allocation;
4200       else
4201         *allocation = child->widget->allocation;
4202       break;
4203     }
4204 }
4205
4206 static void
4207 toolbar_content_set_start_allocation (ToolbarContent *content,
4208                                       GtkAllocation  *allocation)
4209 {
4210   switch (content->type)
4211     {
4212     case TOOL_ITEM:
4213       content->u.tool_item.start_allocation = *allocation;
4214       break;
4215       
4216     case COMPATIBILITY:
4217       /* start_allocation is only relevant when using the new API */
4218       g_assert_not_reached ();
4219       break;
4220     }
4221 }
4222
4223 static gboolean
4224 toolbar_content_get_expand (ToolbarContent *content)
4225 {
4226   if (content->type == TOOL_ITEM &&
4227       gtk_tool_item_get_expand (content->u.tool_item.item) &&
4228       !content->u.tool_item.disappearing)
4229     {
4230       return TRUE;
4231     }
4232   
4233   return FALSE;
4234 }
4235
4236 static void
4237 toolbar_content_set_goal_allocation (ToolbarContent *content,
4238                                      GtkAllocation  *allocation)
4239 {
4240   switch (content->type)
4241     {
4242     case TOOL_ITEM:
4243       content->u.tool_item.goal_allocation = *allocation;
4244       break;
4245       
4246     case COMPATIBILITY:
4247       /* Only relevant when using new API */
4248       g_assert_not_reached ();
4249       break;
4250     }
4251 }
4252
4253 static void
4254 toolbar_content_set_child_visible (ToolbarContent *content,
4255                                    GtkToolbar     *toolbar,
4256                                    gboolean        visible)
4257 {
4258   GtkToolbarChild *child;
4259   
4260   switch (content->type)
4261     {
4262     case TOOL_ITEM:
4263       gtk_widget_set_child_visible (GTK_WIDGET (content->u.tool_item.item),
4264                                     visible);
4265       break;
4266       
4267     case COMPATIBILITY:
4268       child = &(content->u.compatibility.child);
4269       
4270       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
4271         {
4272           gtk_widget_set_child_visible (child->widget, visible);
4273         }
4274       else
4275         {
4276           if (content->u.compatibility.space_visible != visible)
4277             {
4278               content->u.compatibility.space_visible = visible;
4279               gtk_widget_queue_draw (GTK_WIDGET (toolbar));
4280             }
4281         }
4282       break;
4283     }
4284 }
4285
4286 static void
4287 toolbar_content_get_start_allocation (ToolbarContent *content,
4288                                       GtkAllocation  *start_allocation)
4289 {
4290   switch (content->type)
4291     {
4292     case TOOL_ITEM:
4293       *start_allocation = content->u.tool_item.start_allocation;
4294       break;
4295       
4296     case COMPATIBILITY:
4297       /* Only relevant for new API */
4298       g_assert_not_reached ();
4299       break;
4300     }
4301 }
4302
4303 static void
4304 toolbar_content_size_allocate (ToolbarContent *content,
4305                                GtkAllocation  *allocation)
4306 {
4307   switch (content->type)
4308     {
4309     case TOOL_ITEM:
4310       gtk_widget_size_allocate (GTK_WIDGET (content->u.tool_item.item),
4311                                 allocation);
4312       break;
4313       
4314     case COMPATIBILITY:
4315       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4316         {
4317           gtk_widget_size_allocate (content->u.compatibility.child.widget,
4318                                     allocation);
4319         }
4320       else
4321         {
4322           content->u.compatibility.space_allocation = *allocation;
4323         }
4324       break;
4325     }
4326 }
4327
4328 static void
4329 toolbar_content_set_state (ToolbarContent *content,
4330                            ItemState       state)
4331 {
4332   content->state = state;
4333 }
4334
4335 static GtkWidget *
4336 toolbar_content_get_widget (ToolbarContent *content)
4337 {
4338   GtkToolbarChild *child;
4339   
4340   switch (content->type)
4341     {
4342     case TOOL_ITEM:
4343       return GTK_WIDGET (content->u.tool_item.item);
4344       break;
4345       
4346     case COMPATIBILITY:
4347       child = &(content->u.compatibility.child);
4348       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
4349         return child->widget;
4350       else
4351         return NULL;
4352       break;
4353     }
4354   
4355   return NULL;
4356 }
4357
4358 static void
4359 toolbar_content_set_disappearing (ToolbarContent *content,
4360                                   gboolean        disappearing)
4361 {
4362   switch (content->type)
4363     {
4364     case TOOL_ITEM:
4365       content->u.tool_item.disappearing = disappearing;
4366       break;
4367       
4368     case COMPATIBILITY:
4369       /* Only relevant for new API */
4370       g_assert_not_reached ();
4371       break;
4372     }
4373 }
4374
4375 static void
4376 toolbar_content_set_size_request (ToolbarContent *content,
4377                                   gint            width,
4378                                   gint            height)
4379 {
4380   switch (content->type)
4381     {
4382     case TOOL_ITEM:
4383       gtk_widget_set_size_request (GTK_WIDGET (content->u.tool_item.item),
4384                                    width, height);
4385       break;
4386       
4387     case COMPATIBILITY:
4388       /* Setting size requests only happens with sliding,
4389        * so not relevant here
4390        */
4391       g_assert_not_reached ();
4392       break;
4393     }
4394 }
4395
4396 static void
4397 toolbar_child_reconfigure (GtkToolbar      *toolbar,
4398                            GtkToolbarChild *child)
4399 {
4400   GtkWidget *box;
4401   GtkImage *image;
4402   GtkToolbarStyle style;
4403   GtkIconSize icon_size;
4404   GtkReliefStyle relief;
4405   gchar *stock_id;
4406   
4407   style = gtk_toolbar_get_style (toolbar);
4408   icon_size = gtk_toolbar_get_icon_size (toolbar);
4409   relief = gtk_toolbar_get_relief_style (toolbar);
4410   
4411   /* style */
4412   if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4413       child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4414       child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4415     {
4416       box = gtk_bin_get_child (GTK_BIN (child->widget));
4417       
4418       if (style == GTK_TOOLBAR_BOTH && GTK_IS_HBOX (box))
4419         {
4420           GtkWidget *vbox;
4421           
4422           vbox = gtk_vbox_new (FALSE, 0);
4423           
4424           if (child->label)
4425             gtk_widget_reparent (child->label, vbox);
4426           if (child->icon)
4427             gtk_widget_reparent (child->icon, vbox);
4428           
4429           gtk_widget_destroy (box);
4430           gtk_container_add (GTK_CONTAINER (child->widget), vbox);
4431           
4432           gtk_widget_show (vbox);
4433         }
4434       else if (style == GTK_TOOLBAR_BOTH_HORIZ && GTK_IS_VBOX (box))
4435         {
4436           GtkWidget *hbox;
4437           
4438           hbox = gtk_hbox_new (FALSE, 0);
4439           
4440           if (child->label)
4441             gtk_widget_reparent (child->label, hbox);
4442           if (child->icon)
4443             gtk_widget_reparent (child->icon, hbox);
4444           
4445           gtk_widget_destroy (box);
4446           gtk_container_add (GTK_CONTAINER (child->widget), hbox);
4447           
4448           gtk_widget_show (hbox);
4449         }
4450
4451       set_child_packing_and_visibility (toolbar, child);
4452     }
4453   
4454   /* icon size */
4455   
4456   if ((child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4457        child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
4458        child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON) &&
4459       GTK_IS_IMAGE (child->icon))
4460     {
4461       image = GTK_IMAGE (child->icon);
4462       if (gtk_image_get_storage_type (image) == GTK_IMAGE_STOCK)
4463         {
4464           gtk_image_get_stock (image, &stock_id, NULL);
4465           stock_id = g_strdup (stock_id);
4466           gtk_image_set_from_stock (image,
4467                                     stock_id,
4468                                     icon_size);
4469           g_free (stock_id);
4470         }
4471     }
4472   
4473   /* relief */
4474   if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4475       child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4476       child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4477     {
4478       gtk_button_set_relief (GTK_BUTTON (child->widget), relief);
4479     }
4480 }
4481
4482 static void
4483 toolbar_content_toolbar_reconfigured (ToolbarContent *content,
4484                                       GtkToolbar     *toolbar)
4485 {
4486   switch (content->type)
4487     {
4488     case TOOL_ITEM:
4489       _gtk_tool_item_toolbar_reconfigured (content->u.tool_item.item);
4490       break;
4491       
4492     case COMPATIBILITY:
4493       toolbar_child_reconfigure (toolbar, &(content->u.compatibility.child));
4494       break;
4495     }
4496 }
4497
4498 static GtkWidget *
4499 toolbar_content_retrieve_menu_item (ToolbarContent *content)
4500 {
4501   if (content->type == TOOL_ITEM)
4502     return gtk_tool_item_retrieve_proxy_menu_item (content->u.tool_item.item);
4503   
4504   /* FIXME - we might actually be able to do something meaningful here */
4505   return NULL; 
4506 }
4507
4508 static gboolean
4509 toolbar_content_has_proxy_menu_item (ToolbarContent *content)
4510 {
4511   if (content->type == TOOL_ITEM)
4512     {
4513       GtkWidget *menu_item;
4514
4515       if (content->u.tool_item.has_menu == YES)
4516         return TRUE;
4517       else if (content->u.tool_item.has_menu == NO)
4518         return FALSE;
4519
4520       menu_item = toolbar_content_retrieve_menu_item (content);
4521
4522       content->u.tool_item.has_menu = menu_item? YES : NO;
4523       
4524       return menu_item != NULL;
4525     }
4526   else
4527     {
4528       return FALSE;
4529     }
4530 }
4531
4532 static void
4533 toolbar_content_set_unknown_menu_status (ToolbarContent *content)
4534 {
4535   if (content->type == TOOL_ITEM)
4536     content->u.tool_item.has_menu = UNKNOWN;
4537 }
4538
4539 static gboolean
4540 toolbar_content_is_separator (ToolbarContent *content)
4541 {
4542   GtkToolbarChild *child;
4543   
4544   switch (content->type)
4545     {
4546     case TOOL_ITEM:
4547       return GTK_IS_SEPARATOR_TOOL_ITEM (content->u.tool_item.item);
4548       break;
4549       
4550     case COMPATIBILITY:
4551       child = &(content->u.compatibility.child);
4552       return (child->type == GTK_TOOLBAR_CHILD_SPACE);
4553       break;
4554     }
4555   
4556   return FALSE;
4557 }
4558
4559 static void
4560 toolbar_content_set_expand (ToolbarContent *content,
4561                             gboolean        expand)
4562 {
4563   if (content->type == TOOL_ITEM)
4564     gtk_tool_item_set_expand (content->u.tool_item.item, expand);
4565 }
4566
4567 static gboolean
4568 ignore_show_and_hide_all (ToolbarContent *content)
4569 {
4570   if (content->type == COMPATIBILITY)
4571     {
4572       GtkToolbarChildType type = content->u.compatibility.child.type;
4573       
4574       if (type == GTK_TOOLBAR_CHILD_BUTTON ||
4575           type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
4576           type == GTK_TOOLBAR_CHILD_RADIOBUTTON)
4577         {
4578           return TRUE;
4579         }
4580     }
4581   
4582   return FALSE;
4583 }
4584
4585 static void
4586 toolbar_content_show_all (ToolbarContent  *content)
4587 {
4588   GtkWidget *widget;
4589   
4590   if (ignore_show_and_hide_all (content))
4591     return;
4592
4593   widget = toolbar_content_get_widget (content);
4594   if (widget)
4595     gtk_widget_show_all (widget);
4596 }
4597
4598 static void
4599 toolbar_content_hide_all (ToolbarContent  *content)
4600 {
4601   GtkWidget *widget;
4602   
4603   if (ignore_show_and_hide_all (content))
4604     return;
4605
4606   widget = toolbar_content_get_widget (content);
4607   if (widget)
4608     gtk_widget_hide_all (widget);
4609 }
4610
4611 /*
4612  * Getters
4613  */
4614 static gint
4615 get_space_size (GtkToolbar *toolbar)
4616 {
4617   gint space_size = DEFAULT_SPACE_SIZE;
4618   
4619   if (toolbar)
4620     {
4621       gtk_widget_style_get (GTK_WIDGET (toolbar),
4622                             "space-size", &space_size,
4623                             NULL);
4624     }
4625   
4626   return space_size;
4627 }
4628
4629 static GtkToolbarSpaceStyle
4630 get_space_style (GtkToolbar *toolbar)
4631 {
4632   GtkToolbarSpaceStyle space_style = DEFAULT_SPACE_STYLE;
4633
4634   if (toolbar)
4635     {
4636       gtk_widget_style_get (GTK_WIDGET (toolbar),
4637                             "space-style", &space_style,
4638                             NULL);
4639     }
4640   
4641   return space_style;  
4642 }
4643
4644 static GtkReliefStyle
4645 get_button_relief (GtkToolbar *toolbar)
4646 {
4647   GtkReliefStyle button_relief = GTK_RELIEF_NORMAL;
4648   
4649   gtk_widget_ensure_style (GTK_WIDGET (toolbar));
4650   
4651   gtk_widget_style_get (GTK_WIDGET (toolbar),
4652                         "button-relief", &button_relief,
4653                         NULL);
4654   
4655   return button_relief;
4656 }
4657
4658 static gint
4659 get_internal_padding (GtkToolbar *toolbar)
4660 {
4661   gint ipadding = 0;
4662   
4663   gtk_widget_style_get (GTK_WIDGET (toolbar),
4664                         "internal-padding", &ipadding,
4665                         NULL);
4666   
4667   return ipadding;
4668 }
4669
4670 static GtkShadowType
4671 get_shadow_type (GtkToolbar *toolbar)
4672 {
4673   GtkShadowType shadow_type;
4674   
4675   gtk_widget_style_get (GTK_WIDGET (toolbar),
4676                         "shadow-type", &shadow_type,
4677                         NULL);
4678   
4679   return shadow_type;
4680 }
4681
4682 /*
4683  * API checks
4684  */
4685 static gboolean
4686 gtk_toolbar_check_old_api (GtkToolbar *toolbar)
4687 {
4688   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4689   
4690   if (priv->api_mode == NEW_API)
4691     {
4692       g_warning (MIXED_API_WARNING);
4693       return FALSE;
4694     }
4695   
4696   priv->api_mode = OLD_API;
4697   return TRUE;
4698 }
4699
4700 static gboolean
4701 gtk_toolbar_check_new_api (GtkToolbar *toolbar)
4702 {
4703   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4704   
4705   if (priv->api_mode == OLD_API)
4706     {
4707       g_warning (MIXED_API_WARNING);
4708       return FALSE;
4709     }
4710   
4711   priv->api_mode = NEW_API;
4712   return TRUE;
4713 }
4714
4715 /* GTK+ internal methods */
4716
4717 gint
4718 _gtk_toolbar_get_default_space_size (void)
4719 {
4720   return DEFAULT_SPACE_SIZE;
4721 }
4722
4723 void
4724 _gtk_toolbar_paint_space_line (GtkWidget       *widget,
4725                                GtkToolbar      *toolbar,
4726                                GdkRectangle    *area,
4727                                GtkAllocation   *allocation)
4728 {
4729   const double start_fraction = (SPACE_LINE_START / SPACE_LINE_DIVISION);
4730   const double end_fraction = (SPACE_LINE_END / SPACE_LINE_DIVISION);
4731   
4732   GtkToolbarSpaceStyle space_style;
4733   GtkOrientation orientation;
4734
4735   g_return_if_fail (GTK_IS_WIDGET (widget));
4736   
4737   space_style = toolbar? get_space_style (toolbar) : DEFAULT_SPACE_STYLE;
4738   orientation = toolbar? toolbar->orientation : GTK_ORIENTATION_HORIZONTAL;
4739
4740   if (orientation == GTK_ORIENTATION_HORIZONTAL)
4741     {
4742       gtk_paint_vline (widget->style, widget->window,
4743                        GTK_WIDGET_STATE (widget), area, widget,
4744                        "toolbar",
4745                        allocation->y + allocation->height * start_fraction,
4746                        allocation->y + allocation->height * end_fraction,
4747                        allocation->x + (allocation->width - widget->style->xthickness) / 2);
4748     }
4749   else
4750     {
4751       gtk_paint_hline (widget->style, widget->window,
4752                        GTK_WIDGET_STATE (widget), area, widget,
4753                        "toolbar",
4754                        allocation->x + allocation->width * start_fraction,
4755                        allocation->x + allocation->width * end_fraction,
4756                        allocation->y + (allocation->height - widget->style->ythickness) / 2);
4757     }
4758 }
4759
4760 gchar *
4761 _gtk_toolbar_elide_underscores (const gchar *original)
4762 {
4763   gchar *q, *result;
4764   const gchar *p;
4765   gboolean last_underscore;
4766   
4767   q = result = g_malloc (strlen (original) + 1);
4768   last_underscore = FALSE;
4769   
4770   for (p = original; *p; p++)
4771     {
4772       if (!last_underscore && *p == '_')
4773         last_underscore = TRUE;
4774       else
4775         {
4776           last_underscore = FALSE;
4777           *q++ = *p;
4778         }
4779     }
4780   
4781   *q = '\0';
4782   
4783   return result;
4784 }
4785
4786 void
4787 _gtk_toolbar_rebuild_menu (GtkToolbar *toolbar)
4788 {
4789   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4790   GList *list;
4791
4792   priv->need_rebuild = TRUE;
4793
4794   for (list = priv->content; list != NULL; list = list->next)
4795     {
4796       ToolbarContent *content = list->data;
4797
4798       toolbar_content_set_unknown_menu_status (content);
4799     }
4800   
4801   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
4802 }
4803
4804 #define __GTK_TOOLBAR_C__
4805 #include "gtkaliasdef.c"