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