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