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