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