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