]> Pileus Git - ~andy/gtk/blob - gtk/gtktoolbar.c
Remove deprecated GtkToolbar code
[~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 #include "gtkalias.h"
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   gint border_width;
750   
751   gtk_widget_set_realized (widget, TRUE);
752   
753   border_width = GTK_CONTAINER (widget)->border_width;
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   gint border_width;
802   
803   border_width = GTK_CONTAINER (widget)->border_width;
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   GtkRequisition arrow_requisition;
848   
849   max_homogeneous_child_width = 0;
850   max_homogeneous_child_height = 0;
851   max_child_width = 0;
852   max_child_height = 0;
853   for (list = priv->content; list != NULL; list = list->next)
854     {
855       GtkRequisition requisition;
856       ToolbarContent *content = list->data;
857       
858       if (!toolbar_content_visible (content, toolbar))
859         continue;
860       
861       toolbar_content_size_request (content, toolbar, &requisition);
862
863       max_child_width = MAX (max_child_width, requisition.width);
864       max_child_height = MAX (max_child_height, requisition.height);
865       
866       if (toolbar_content_is_homogeneous (content, toolbar))
867         {
868           max_homogeneous_child_width = MAX (max_homogeneous_child_width, requisition.width);
869           max_homogeneous_child_height = MAX (max_homogeneous_child_height, requisition.height);
870         }
871     }
872   
873   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
874     homogeneous_size = max_homogeneous_child_width;
875   else
876     homogeneous_size = max_homogeneous_child_height;
877   
878   pack_front_size = 0;
879   for (list = priv->content; list != NULL; list = list->next)
880     {
881       ToolbarContent *content = list->data;
882       guint size;
883       
884       if (!toolbar_content_visible (content, toolbar))
885         continue;
886
887       if (toolbar_content_is_homogeneous (content, toolbar))
888         {
889           size = homogeneous_size;
890         }
891       else
892         {
893           GtkRequisition requisition;
894           
895           toolbar_content_size_request (content, toolbar, &requisition);
896           
897           if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
898             size = requisition.width;
899           else
900             size = requisition.height;
901         }
902
903       pack_front_size += size;
904     }
905   
906   if (priv->show_arrow)
907     {
908       gtk_widget_size_request (priv->arrow_button, &arrow_requisition);
909       
910       if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
911         long_req = arrow_requisition.width;
912       else
913         long_req = arrow_requisition.height;
914       
915       /* There is no point requesting space for the arrow if that would take
916        * up more space than all the items combined
917        */
918       long_req = MIN (long_req, pack_front_size);
919     }
920   else
921     {
922       arrow_requisition.height = 0;
923       arrow_requisition.width = 0;
924       
925       long_req = pack_front_size;
926     }
927   
928   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
929     {
930       requisition->width = long_req;
931       requisition->height = MAX (max_child_height, arrow_requisition.height);
932     }
933   else
934     {
935       requisition->height = long_req;
936       requisition->width = MAX (max_child_width, arrow_requisition.width);
937     }
938   
939   /* Extra spacing */
940   ipadding = get_internal_padding (toolbar);
941   
942   requisition->width += 2 * (ipadding + GTK_CONTAINER (toolbar)->border_width);
943   requisition->height += 2 * (ipadding + GTK_CONTAINER (toolbar)->border_width);
944   
945   if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
946     {
947       requisition->width += 2 * widget->style->xthickness;
948       requisition->height += 2 * widget->style->ythickness;
949     }
950   
951   toolbar->button_maxw = max_homogeneous_child_width;
952   toolbar->button_maxh = max_homogeneous_child_height;
953 }
954
955 static gint
956 position (GtkToolbar *toolbar,
957           gint        from,
958           gint        to,
959           gdouble     elapsed)
960 {
961   gint n_pixels;
962
963   if (! GTK_TOOLBAR_GET_PRIVATE (toolbar)->animation)
964     return to;
965
966   if (elapsed <= ACCEL_THRESHOLD)
967     {
968       n_pixels = SLIDE_SPEED * elapsed;
969     }
970   else
971     {
972       /* The formula is a second degree polynomial in
973        * @elapsed that has the line SLIDE_SPEED * @elapsed
974        * as tangent for @elapsed == ACCEL_THRESHOLD.
975        * This makes @n_pixels a smooth function of elapsed time.
976        */
977       n_pixels = (SLIDE_SPEED / ACCEL_THRESHOLD) * elapsed * elapsed -
978         SLIDE_SPEED * elapsed + SLIDE_SPEED * ACCEL_THRESHOLD;
979     }
980
981   if (to > from)
982     return MIN (from + n_pixels, to);
983   else
984     return MAX (from - n_pixels, to);
985 }
986
987 static void
988 compute_intermediate_allocation (GtkToolbar          *toolbar,
989                                  const GtkAllocation *start,
990                                  const GtkAllocation *goal,
991                                  GtkAllocation       *intermediate)
992 {
993   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
994   gdouble elapsed = g_timer_elapsed (priv->timer, NULL);
995
996   intermediate->x      = position (toolbar, start->x, goal->x, elapsed);
997   intermediate->y      = position (toolbar, start->y, goal->y, elapsed);
998   intermediate->width  = position (toolbar, start->x + start->width,
999                                    goal->x + goal->width,
1000                                    elapsed) - intermediate->x;
1001   intermediate->height = position (toolbar, start->y + start->height,
1002                                    goal->y + goal->height,
1003                                    elapsed) - intermediate->y;
1004 }
1005
1006 static void
1007 fixup_allocation_for_rtl (gint           total_size,
1008                           GtkAllocation *allocation)
1009 {
1010   allocation->x += (total_size - (2 * allocation->x + allocation->width));
1011 }
1012
1013 static void
1014 fixup_allocation_for_vertical (GtkAllocation *allocation)
1015 {
1016   gint tmp;
1017   
1018   tmp = allocation->x;
1019   allocation->x = allocation->y;
1020   allocation->y = tmp;
1021   
1022   tmp = allocation->width;
1023   allocation->width = allocation->height;
1024   allocation->height = tmp;
1025 }
1026
1027 static gint
1028 get_item_size (GtkToolbar     *toolbar,
1029                ToolbarContent *content)
1030 {
1031   GtkRequisition requisition;
1032   
1033   toolbar_content_size_request (content, toolbar, &requisition);
1034   
1035   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
1036     {
1037       if (toolbar_content_is_homogeneous (content, toolbar))
1038         return toolbar->button_maxw;
1039       else
1040         return requisition.width;
1041     }
1042   else
1043     {
1044       if (toolbar_content_is_homogeneous (content, toolbar))
1045         return toolbar->button_maxh;
1046       else
1047         return requisition.height;
1048     }
1049 }
1050
1051 static gboolean
1052 slide_idle_handler (gpointer data)
1053 {
1054   GtkToolbar *toolbar = data;
1055   GtkToolbarPrivate *priv;
1056   GList *list;
1057   
1058   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1059   
1060   if (priv->need_sync)
1061     {
1062       gdk_flush ();
1063       priv->need_sync = FALSE;
1064     }
1065   
1066   for (list = priv->content; list != NULL; list = list->next)
1067     {
1068       ToolbarContent *content = list->data;
1069       ItemState state;
1070       GtkAllocation goal_allocation;
1071       GtkAllocation allocation;
1072       gboolean cont;
1073
1074       state = toolbar_content_get_state (content);
1075       toolbar_content_get_goal_allocation (content, &goal_allocation);
1076       toolbar_content_get_allocation (content, &allocation);
1077       
1078       cont = FALSE;
1079       
1080       if (state == NOT_ALLOCATED)
1081         {
1082           /* an unallocated item means that size allocate has to
1083            * called at least once more
1084            */
1085           cont = TRUE;
1086         }
1087
1088       /* An invisible item with a goal allocation of
1089        * 0 is already at its goal.
1090        */
1091       if ((state == NORMAL || state == OVERFLOWN) &&
1092           ((goal_allocation.width != 0 &&
1093             goal_allocation.height != 0) ||
1094            toolbar_content_child_visible (content)))
1095         {
1096           if ((goal_allocation.x != allocation.x ||
1097                goal_allocation.y != allocation.y ||
1098                goal_allocation.width != allocation.width ||
1099                goal_allocation.height != allocation.height))
1100             {
1101               /* An item is not in its right position yet. Note
1102                * that OVERFLOWN items do get an allocation in
1103                * gtk_toolbar_size_allocate(). This way you can see
1104                * them slide back in when you drag an item off the
1105                * toolbar.
1106                */
1107               cont = TRUE;
1108             }
1109         }
1110
1111       if (toolbar_content_is_placeholder (content) &&
1112           toolbar_content_disappearing (content) &&
1113           toolbar_content_child_visible (content))
1114         {
1115           /* A disappearing placeholder is still visible.
1116            */
1117              
1118           cont = TRUE;
1119         }
1120       
1121       if (cont)
1122         {
1123           gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1124           
1125           return TRUE;
1126         }
1127     }
1128   
1129   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1130
1131   priv->is_sliding = FALSE;
1132   priv->idle_id = 0;
1133
1134   return FALSE;
1135 }
1136
1137 static gboolean
1138 rect_within (GtkAllocation *a1,
1139              GtkAllocation *a2)
1140 {
1141   return (a1->x >= a2->x                         &&
1142           a1->x + a1->width <= a2->x + a2->width &&
1143           a1->y >= a2->y                         &&
1144           a1->y + a1->height <= a2->y + a2->height);
1145 }
1146
1147 static void
1148 gtk_toolbar_begin_sliding (GtkToolbar *toolbar)
1149 {
1150   GtkWidget *widget = GTK_WIDGET (toolbar);
1151   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1152   GList *list;
1153   gint cur_x;
1154   gint cur_y;
1155   gint border_width;
1156   gboolean rtl;
1157   gboolean vertical;
1158   
1159   /* Start the sliding. This function copies the allocation of every
1160    * item into content->start_allocation. For items that haven't
1161    * been allocated yet, we calculate their position and save that
1162    * in start_allocatino along with zero width and zero height.
1163    *
1164    * FIXME: It would be nice if we could share this code with
1165    * the equivalent in gtk_widget_size_allocate().
1166    */
1167   priv->is_sliding = TRUE;
1168   
1169   if (!priv->idle_id)
1170     priv->idle_id = gdk_threads_add_idle (slide_idle_handler, toolbar);
1171   
1172   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1173   vertical = (toolbar->orientation == GTK_ORIENTATION_VERTICAL);
1174   border_width = get_internal_padding (toolbar) + GTK_CONTAINER (toolbar)->border_width;
1175   
1176   if (rtl)
1177     {
1178       cur_x = widget->allocation.width - border_width - widget->style->xthickness;
1179       cur_y = widget->allocation.height - border_width - widget->style->ythickness;
1180     }
1181   else
1182     {
1183       cur_x = border_width + widget->style->xthickness;
1184       cur_y = border_width + widget->style->ythickness;
1185     }
1186   
1187   cur_x += widget->allocation.x;
1188   cur_y += widget->allocation.y;
1189   
1190   for (list = priv->content; list != NULL; list = list->next)
1191     {
1192       ToolbarContent *content = list->data;
1193       GtkAllocation new_start_allocation;
1194       GtkAllocation item_allocation;
1195       ItemState state;
1196       
1197       state = toolbar_content_get_state (content);
1198       toolbar_content_get_allocation (content, &item_allocation);
1199       
1200       if ((state == NORMAL &&
1201            rect_within (&item_allocation, &(widget->allocation))) ||
1202           state == OVERFLOWN)
1203         {
1204           new_start_allocation = item_allocation;
1205         }
1206       else
1207         {
1208           new_start_allocation.x = cur_x;
1209           new_start_allocation.y = cur_y;
1210           
1211           if (vertical)
1212             {
1213               new_start_allocation.width = widget->allocation.width -
1214                 2 * border_width - 2 * widget->style->xthickness;
1215               new_start_allocation.height = 0;
1216             }
1217           else
1218             {
1219               new_start_allocation.width = 0;
1220               new_start_allocation.height = widget->allocation.height -
1221                 2 * border_width - 2 * widget->style->ythickness;
1222             }
1223         }
1224       
1225       if (vertical)
1226         cur_y = new_start_allocation.y + new_start_allocation.height;
1227       else if (rtl)
1228         cur_x = new_start_allocation.x;
1229       else
1230         cur_x = new_start_allocation.x + new_start_allocation.width;
1231       
1232       toolbar_content_set_start_allocation (content, &new_start_allocation);
1233     }
1234
1235   /* This resize will run before the first idle handler. This
1236    * will make sure that items get the right goal allocation
1237    * so that the idle handler will not immediately return
1238    * FALSE
1239    */
1240   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1241   g_timer_reset (priv->timer);
1242 }
1243
1244 static void
1245 gtk_toolbar_stop_sliding (GtkToolbar *toolbar)
1246 {
1247   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1248   
1249   if (priv->is_sliding)
1250     {
1251       GList *list;
1252       
1253       priv->is_sliding = FALSE;
1254       
1255       if (priv->idle_id)
1256         {
1257           g_source_remove (priv->idle_id);
1258           priv->idle_id = 0;
1259         }
1260       
1261       list = priv->content;
1262       while (list)
1263         {
1264           ToolbarContent *content = list->data;
1265           list = list->next;
1266
1267           if (toolbar_content_is_placeholder (content))
1268             {
1269               toolbar_content_remove (content, toolbar);
1270               toolbar_content_free (content);
1271             }
1272         }
1273       
1274       gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1275     }
1276 }
1277
1278 static void
1279 remove_item (GtkWidget *menu_item,
1280              gpointer   data)
1281 {
1282   gtk_container_remove (GTK_CONTAINER (menu_item->parent), menu_item);
1283 }
1284
1285 static void
1286 menu_deactivated (GtkWidget  *menu,
1287                   GtkToolbar *toolbar)
1288 {
1289   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1290   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->arrow_button), FALSE);
1291 }
1292
1293 static void
1294 menu_detached (GtkWidget  *toolbar,
1295                GtkMenu    *menu)
1296 {
1297   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1298   priv->menu = NULL;
1299 }
1300
1301 static void
1302 rebuild_menu (GtkToolbar *toolbar)
1303 {
1304   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1305   GList *list, *children;
1306   
1307   if (!priv->menu)
1308     {
1309       priv->menu = GTK_MENU (gtk_menu_new());
1310       gtk_menu_attach_to_widget (priv->menu,
1311                                  GTK_WIDGET (toolbar),
1312                                  menu_detached);
1313
1314       g_signal_connect (priv->menu, "deactivate",
1315                         G_CALLBACK (menu_deactivated), toolbar);
1316     }
1317
1318   gtk_container_foreach (GTK_CONTAINER (priv->menu), remove_item, NULL);
1319   
1320   for (list = priv->content; list != NULL; list = list->next)
1321     {
1322       ToolbarContent *content = list->data;
1323       
1324       if (toolbar_content_get_state (content) == OVERFLOWN &&
1325           !toolbar_content_is_placeholder (content))
1326         {
1327           GtkWidget *menu_item = toolbar_content_retrieve_menu_item (content);
1328           
1329           if (menu_item)
1330             {
1331               g_assert (GTK_IS_MENU_ITEM (menu_item));
1332               gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menu_item);
1333             }
1334         }
1335     }
1336
1337   /* Remove leading and trailing separator items */
1338   children = gtk_container_get_children (GTK_CONTAINER (priv->menu));
1339   
1340   list = children;
1341   while (list && GTK_IS_SEPARATOR_MENU_ITEM (list->data))
1342     {
1343       GtkWidget *child = list->data;
1344       
1345       gtk_container_remove (GTK_CONTAINER (priv->menu), child);
1346       list = list->next;
1347     }
1348   g_list_free (children);
1349
1350   /* Regenerate the list of children so we don't try to remove items twice */
1351   children = gtk_container_get_children (GTK_CONTAINER (priv->menu));
1352
1353   list = g_list_last (children);
1354   while (list && GTK_IS_SEPARATOR_MENU_ITEM (list->data))
1355     {
1356       GtkWidget *child = list->data;
1357
1358       gtk_container_remove (GTK_CONTAINER (priv->menu), child);
1359       list = list->prev;
1360     }
1361   g_list_free (children);
1362
1363   priv->need_rebuild = FALSE;
1364 }
1365
1366 static void
1367 gtk_toolbar_size_allocate (GtkWidget     *widget,
1368                            GtkAllocation *allocation)
1369 {
1370   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1371   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1372   GtkAllocation *allocations;
1373   ItemState *new_states;
1374   GtkAllocation arrow_allocation;
1375   gint arrow_size;
1376   gint size, pos, short_size;
1377   GList *list;
1378   gint i;
1379   gboolean need_arrow;
1380   gint n_expand_items;
1381   gint border_width;
1382   gint available_size;
1383   gint n_items;
1384   gint needed_size;
1385   GtkRequisition arrow_requisition;
1386   gboolean overflowing;
1387   gboolean size_changed;
1388   gdouble elapsed;
1389   GtkAllocation item_area;
1390   GtkShadowType shadow_type;
1391   
1392   size_changed = FALSE;
1393   if (widget->allocation.x != allocation->x             ||
1394       widget->allocation.y != allocation->y             ||
1395       widget->allocation.width != allocation->width     ||
1396       widget->allocation.height != allocation->height)
1397     {
1398       size_changed = TRUE;
1399     }
1400   
1401   if (size_changed)
1402     gtk_toolbar_stop_sliding (toolbar);
1403   
1404   widget->allocation = *allocation;
1405   
1406   border_width = GTK_CONTAINER (toolbar)->border_width;
1407   
1408   if (gtk_widget_get_realized (widget))
1409     {
1410       gdk_window_move_resize (priv->event_window,
1411                               allocation->x + border_width,
1412                               allocation->y + border_width,
1413                               allocation->width - border_width * 2,
1414                               allocation->height - border_width * 2);
1415     }
1416   
1417   border_width += get_internal_padding (toolbar);
1418   
1419   gtk_widget_get_child_requisition (GTK_WIDGET (priv->arrow_button),
1420                                     &arrow_requisition);
1421   
1422   shadow_type = get_shadow_type (toolbar);
1423
1424   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
1425     {
1426       available_size = size = allocation->width - 2 * border_width;
1427       short_size = allocation->height - 2 * border_width;
1428       arrow_size = arrow_requisition.width;
1429       
1430       if (shadow_type != GTK_SHADOW_NONE)
1431         {
1432           available_size -= 2 * widget->style->xthickness;
1433           short_size -= 2 * widget->style->ythickness;
1434         }
1435     }
1436   else
1437     {
1438       available_size = size = allocation->height - 2 * border_width;
1439       short_size = allocation->width - 2 * border_width;
1440       arrow_size = arrow_requisition.height;
1441       
1442       if (shadow_type != GTK_SHADOW_NONE)
1443         {
1444           available_size -= 2 * widget->style->ythickness;
1445           short_size -= 2 * widget->style->xthickness;
1446         }
1447     }
1448   
1449   n_items = g_list_length (priv->content);
1450   allocations = g_new0 (GtkAllocation, n_items);
1451   new_states = g_new0 (ItemState, n_items);
1452   
1453   needed_size = 0;
1454   need_arrow = FALSE;
1455   for (list = priv->content; list != NULL; list = list->next)
1456     {
1457       ToolbarContent *content = list->data;
1458       
1459       if (toolbar_content_visible (content, toolbar))
1460         {
1461           needed_size += get_item_size (toolbar, content);
1462
1463           /* Do we need an arrow?
1464            *
1465            * Assume we don't, and see if any non-separator item with a
1466            * proxy menu item is then going to overflow.
1467            */
1468           if (needed_size > available_size                      &&
1469               !need_arrow                                       &&
1470               priv->show_arrow                                  &&
1471               toolbar_content_has_proxy_menu_item (content)     &&
1472               !toolbar_content_is_separator (content))
1473             {
1474               need_arrow = TRUE;
1475             }
1476         }
1477     }
1478   
1479   if (need_arrow)
1480     size = available_size - arrow_size;
1481   else
1482     size = available_size;
1483   
1484   /* calculate widths and states of items */
1485   overflowing = FALSE;
1486   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1487     {
1488       ToolbarContent *content = list->data;
1489       gint item_size;
1490       
1491       if (!toolbar_content_visible (content, toolbar))
1492         {
1493           new_states[i] = HIDDEN;
1494           continue;
1495         }
1496       
1497       item_size = get_item_size (toolbar, content);
1498       if (item_size <= size && !overflowing)
1499         {
1500           size -= item_size;
1501           allocations[i].width = item_size;
1502           new_states[i] = NORMAL;
1503         }
1504       else
1505         {
1506           overflowing = TRUE;
1507           new_states[i] = OVERFLOWN;
1508           allocations[i].width = item_size;
1509         }
1510     }
1511   
1512   /* calculate width of arrow */  
1513   if (need_arrow)
1514     {
1515       arrow_allocation.width = arrow_size;
1516       arrow_allocation.height = MAX (short_size, 1);
1517     }
1518   
1519   /* expand expandable items */
1520   
1521   /* We don't expand when there is an overflow menu, because that leads to
1522    * weird jumps when items get moved to the overflow menu and the expanding
1523    * items suddenly get a lot of extra space
1524    */
1525   if (!overflowing)
1526     {
1527       gint max_child_expand;
1528       n_expand_items = 0;
1529       
1530       for (i = 0, list = priv->content; list != NULL; list = list->next, ++i)
1531         {
1532           ToolbarContent *content = list->data;
1533           
1534           if (toolbar_content_get_expand (content) && new_states[i] == NORMAL)
1535             n_expand_items++;
1536         }
1537       
1538       max_child_expand = get_max_child_expand (toolbar);
1539       for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1540         {
1541           ToolbarContent *content = list->data;
1542           
1543           if (toolbar_content_get_expand (content) && new_states[i] == NORMAL)
1544             {
1545               gint extra = size / n_expand_items;
1546               if (size % n_expand_items != 0)
1547                 extra++;
1548
1549               if (extra > max_child_expand)
1550                 extra = max_child_expand;
1551
1552               allocations[i].width += extra;
1553               size -= extra;
1554               n_expand_items--;
1555             }
1556         }
1557       
1558       g_assert (n_expand_items == 0);
1559     }
1560   
1561   /* position items */
1562   pos = border_width;
1563   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1564     {
1565       /* both NORMAL and OVERFLOWN items get a position. This ensures
1566        * that sliding will work for OVERFLOWN items too
1567        */
1568       if (new_states[i] == NORMAL ||
1569           new_states[i] == OVERFLOWN)
1570         {
1571           allocations[i].x = pos;
1572           allocations[i].y = border_width;
1573           allocations[i].height = short_size;
1574           
1575           pos += allocations[i].width;
1576         }
1577     }
1578   
1579   /* position arrow */
1580   if (need_arrow)
1581     {
1582       arrow_allocation.x = available_size - border_width - arrow_allocation.width;
1583       arrow_allocation.y = border_width;
1584     }
1585   
1586   item_area.x = border_width;
1587   item_area.y = border_width;
1588   item_area.width = available_size - (need_arrow? arrow_size : 0);
1589   item_area.height = short_size;
1590
1591   /* fix up allocations in the vertical or RTL cases */
1592   if (toolbar->orientation == GTK_ORIENTATION_VERTICAL)
1593     {
1594       for (i = 0; i < n_items; ++i)
1595         fixup_allocation_for_vertical (&(allocations[i]));
1596       
1597       if (need_arrow)
1598         fixup_allocation_for_vertical (&arrow_allocation);
1599
1600       fixup_allocation_for_vertical (&item_area);
1601     }
1602   else if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1603     {
1604       for (i = 0; i < n_items; ++i)
1605         fixup_allocation_for_rtl (available_size, &(allocations[i]));
1606       
1607       if (need_arrow)
1608         fixup_allocation_for_rtl (available_size, &arrow_allocation);
1609
1610       fixup_allocation_for_rtl (available_size, &item_area);
1611     }
1612   
1613   /* translate the items by allocation->(x,y) */
1614   for (i = 0; i < n_items; ++i)
1615     {
1616       allocations[i].x += allocation->x;
1617       allocations[i].y += allocation->y;
1618       
1619       if (shadow_type != GTK_SHADOW_NONE)
1620         {
1621           allocations[i].x += widget->style->xthickness;
1622           allocations[i].y += widget->style->ythickness;
1623         }
1624     }
1625   
1626   if (need_arrow)
1627     {
1628       arrow_allocation.x += allocation->x;
1629       arrow_allocation.y += allocation->y;
1630       
1631       if (shadow_type != GTK_SHADOW_NONE)
1632         {
1633           arrow_allocation.x += widget->style->xthickness;
1634           arrow_allocation.y += widget->style->ythickness;
1635         }
1636     }
1637
1638   item_area.x += allocation->x;
1639   item_area.y += allocation->y;
1640   if (shadow_type != GTK_SHADOW_NONE)
1641     {
1642       item_area.x += widget->style->xthickness;
1643       item_area.y += widget->style->ythickness;
1644     }
1645
1646   /* did anything change? */
1647   for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1648     {
1649       ToolbarContent *content = list->data;
1650       
1651       if (toolbar_content_get_state (content) == NORMAL &&
1652           new_states[i] != NORMAL)
1653         {
1654           /* an item disappeared and we didn't change size, so begin sliding */
1655           if (!size_changed)
1656             gtk_toolbar_begin_sliding (toolbar);
1657         }
1658     }
1659   
1660   /* finally allocate the items */
1661   if (priv->is_sliding)
1662     {
1663       for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1664         {
1665           ToolbarContent *content = list->data;
1666           
1667           toolbar_content_set_goal_allocation (content, &(allocations[i]));
1668         }
1669     }
1670
1671   elapsed = g_timer_elapsed (priv->timer, NULL);
1672   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1673     {
1674       ToolbarContent *content = list->data;
1675
1676       if (new_states[i] == OVERFLOWN ||
1677           new_states[i] == NORMAL)
1678         {
1679           GtkAllocation alloc;
1680           GtkAllocation start_allocation = { 0, };
1681           GtkAllocation goal_allocation;
1682
1683           if (priv->is_sliding)
1684             {
1685               toolbar_content_get_start_allocation (content, &start_allocation);
1686               toolbar_content_get_goal_allocation (content, &goal_allocation);
1687               
1688               compute_intermediate_allocation (toolbar,
1689                                                &start_allocation,
1690                                                &goal_allocation,
1691                                                &alloc);
1692
1693               priv->need_sync = TRUE;
1694             }
1695           else
1696             {
1697               alloc = allocations[i];
1698             }
1699
1700           if (alloc.width <= 0 || alloc.height <= 0)
1701             {
1702               toolbar_content_set_child_visible (content, toolbar, FALSE);
1703             }
1704           else
1705             {
1706               if (!rect_within (&alloc, &item_area))
1707                 {
1708                   toolbar_content_set_child_visible (content, toolbar, FALSE);
1709                   toolbar_content_size_allocate (content, &alloc);
1710                 }
1711               else
1712                 {
1713                   toolbar_content_set_child_visible (content, toolbar, TRUE);
1714                   toolbar_content_size_allocate (content, &alloc);
1715                 }
1716             }
1717         }
1718       else
1719         {
1720           toolbar_content_set_child_visible (content, toolbar, FALSE);
1721         }
1722           
1723       toolbar_content_set_state (content, new_states[i]);
1724     }
1725   
1726   if (priv->menu && priv->need_rebuild)
1727     rebuild_menu (toolbar);
1728   
1729   if (need_arrow)
1730     {
1731       gtk_widget_size_allocate (GTK_WIDGET (priv->arrow_button),
1732                                 &arrow_allocation);
1733       gtk_widget_show (GTK_WIDGET (priv->arrow_button));
1734     }
1735   else
1736     {
1737       gtk_widget_hide (GTK_WIDGET (priv->arrow_button));
1738
1739       if (priv->menu && gtk_widget_get_visible (GTK_WIDGET (priv->menu)))
1740         gtk_menu_shell_deactivate (GTK_MENU_SHELL (priv->menu));
1741     }
1742
1743   g_free (allocations);
1744   g_free (new_states);
1745 }
1746
1747 static void
1748 gtk_toolbar_update_button_relief (GtkToolbar *toolbar)
1749 {
1750   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1751   GtkReliefStyle relief;
1752
1753   relief = get_button_relief (toolbar);
1754
1755   if (relief != gtk_button_get_relief (GTK_BUTTON (priv->arrow_button)))
1756     {
1757       gtk_toolbar_reconfigured (toolbar);
1758   
1759       gtk_button_set_relief (GTK_BUTTON (priv->arrow_button), relief);
1760     }
1761 }
1762
1763 static void
1764 gtk_toolbar_style_set (GtkWidget *widget,
1765                        GtkStyle  *prev_style)
1766 {
1767   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
1768   
1769   priv->max_homogeneous_pixels = -1;
1770
1771   if (gtk_widget_get_realized (widget))
1772     gtk_style_set_background (widget->style, widget->window, widget->state);
1773   
1774   if (prev_style)
1775     gtk_toolbar_update_button_relief (GTK_TOOLBAR (widget));
1776 }
1777
1778 static GList *
1779 gtk_toolbar_list_children_in_focus_order (GtkToolbar       *toolbar,
1780                                           GtkDirectionType  dir)
1781 {
1782   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1783   GList *result = NULL;
1784   GList *list;
1785   gboolean rtl;
1786   
1787   /* generate list of children in reverse logical order */
1788   
1789   for (list = priv->content; list != NULL; list = list->next)
1790     {
1791       ToolbarContent *content = list->data;
1792       GtkWidget *widget;
1793       
1794       widget = toolbar_content_get_widget (content);
1795       
1796       if (widget)
1797         result = g_list_prepend (result, widget);
1798     }
1799   
1800   result = g_list_prepend (result, priv->arrow_button);
1801   
1802   rtl = (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL);
1803   
1804   /* move in logical order when
1805    *
1806    *    - dir is TAB_FORWARD
1807    *
1808    *    - in RTL mode and moving left or up
1809    *
1810    *    - in LTR mode and moving right or down
1811    */
1812   if (dir == GTK_DIR_TAB_FORWARD                                        ||
1813       (rtl  && (dir == GTK_DIR_UP   || dir == GTK_DIR_LEFT))            ||
1814       (!rtl && (dir == GTK_DIR_DOWN || dir == GTK_DIR_RIGHT)))
1815     {
1816       result = g_list_reverse (result);
1817     }
1818   
1819   return result;
1820 }
1821
1822 static gboolean
1823 gtk_toolbar_focus_home_or_end (GtkToolbar *toolbar,
1824                                gboolean    focus_home)
1825 {
1826   GList *children, *list;
1827   GtkDirectionType dir = focus_home? GTK_DIR_RIGHT : GTK_DIR_LEFT;
1828   
1829   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1830   
1831   if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1832     {
1833       children = g_list_reverse (children);
1834       
1835       dir = (dir == GTK_DIR_RIGHT)? GTK_DIR_LEFT : GTK_DIR_RIGHT;
1836     }
1837   
1838   for (list = children; list != NULL; list = list->next)
1839     {
1840       GtkWidget *child = list->data;
1841       
1842       if (GTK_CONTAINER (toolbar)->focus_child == child)
1843         break;
1844       
1845       if (gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
1846         break;
1847     }
1848   
1849   g_list_free (children);
1850   
1851   return TRUE;
1852 }   
1853
1854 /* Keybinding handler. This function is called when the user presses
1855  * Ctrl TAB or an arrow key.
1856  */
1857 static void
1858 gtk_toolbar_move_focus (GtkWidget        *widget,
1859                         GtkDirectionType  dir)
1860 {
1861   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1862   GtkContainer *container = GTK_CONTAINER (toolbar);
1863   GList *list;
1864   gboolean try_focus = FALSE;
1865   GList *children;
1866
1867   if (container->focus_child &&
1868       gtk_widget_child_focus (container->focus_child, dir))
1869     {
1870       return;
1871     }
1872   
1873   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1874   
1875   for (list = children; list != NULL; list = list->next)
1876     {
1877       GtkWidget *child = list->data;
1878       
1879       if (try_focus && gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
1880         break;
1881       
1882       if (child == GTK_CONTAINER (toolbar)->focus_child)
1883         try_focus = TRUE;
1884     }
1885   
1886   g_list_free (children);
1887 }
1888
1889 /* The focus handler for the toolbar. It called when the user presses
1890  * TAB or otherwise tries to focus the toolbar.
1891  */
1892 static gboolean
1893 gtk_toolbar_focus (GtkWidget        *widget,
1894                    GtkDirectionType  dir)
1895 {
1896   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1897   GList *children, *list;
1898   gboolean result = FALSE;
1899
1900   /* if focus is already somewhere inside the toolbar then return FALSE.
1901    * The only way focus can stay inside the toolbar is when the user presses
1902    * arrow keys or Ctrl TAB (both of which are handled by the
1903    * gtk_toolbar_move_focus() keybinding function.
1904    */
1905   if (GTK_CONTAINER (widget)->focus_child)
1906     return FALSE;
1907
1908   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1909
1910   for (list = children; list != NULL; list = list->next)
1911     {
1912       GtkWidget *child = list->data;
1913       
1914       if (gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
1915         {
1916           result = TRUE;
1917           break;
1918         }
1919     }
1920
1921   g_list_free (children);
1922
1923   return result;
1924 }
1925
1926 static GtkSettings *
1927 toolbar_get_settings (GtkToolbar *toolbar)
1928 {
1929   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1930   return priv->settings;
1931 }
1932
1933 static void
1934 style_change_notify (GtkToolbar *toolbar)
1935 {
1936   if (!toolbar->style_set)
1937     {
1938       /* pretend it was set, then unset, thus reverting to new default */
1939       toolbar->style_set = TRUE;
1940       gtk_toolbar_unset_style (toolbar);
1941     }
1942 }
1943
1944 static void
1945 icon_size_change_notify (GtkToolbar *toolbar)
1946 {
1947   if (!toolbar->icon_size_set)
1948     {
1949       /* pretend it was set, then unset, thus reverting to new default */
1950       toolbar->icon_size_set = TRUE;
1951       gtk_toolbar_unset_icon_size (toolbar);
1952     }
1953 }
1954
1955 static void
1956 animation_change_notify (GtkToolbar *toolbar)
1957 {
1958   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1959   GtkSettings *settings = toolbar_get_settings (toolbar);
1960   gboolean animation;
1961
1962   if (settings)
1963     g_object_get (settings,
1964                   "gtk-enable-animations", &animation,
1965                   NULL);
1966   else
1967     animation = DEFAULT_ANIMATION_STATE;
1968
1969   priv->animation = animation;
1970 }
1971
1972 static void
1973 settings_change_notify (GtkSettings      *settings,
1974                         const GParamSpec *pspec,
1975                         GtkToolbar       *toolbar)
1976 {
1977   if (! strcmp (pspec->name, "gtk-toolbar-style"))
1978     style_change_notify (toolbar);
1979   else if (! strcmp (pspec->name, "gtk-toolbar-icon-size"))
1980     icon_size_change_notify (toolbar);
1981   else if (! strcmp (pspec->name, "gtk-enable-animations"))
1982     animation_change_notify (toolbar);
1983 }
1984
1985 static void
1986 gtk_toolbar_screen_changed (GtkWidget *widget,
1987                             GdkScreen *previous_screen)
1988 {
1989   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
1990   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1991   GtkSettings *old_settings = toolbar_get_settings (toolbar);
1992   GtkSettings *settings;
1993   
1994   if (gtk_widget_has_screen (GTK_WIDGET (toolbar)))
1995     settings = gtk_widget_get_settings (GTK_WIDGET (toolbar));
1996   else
1997     settings = NULL;
1998   
1999   if (settings == old_settings)
2000     return;
2001   
2002   if (old_settings)
2003     {
2004       g_signal_handler_disconnect (old_settings, priv->settings_connection);
2005
2006       g_object_unref (old_settings);
2007     }
2008
2009   if (settings)
2010     {
2011       priv->settings_connection =
2012         g_signal_connect (settings, "notify",
2013                           G_CALLBACK (settings_change_notify),
2014                           toolbar);
2015
2016       priv->settings = g_object_ref (settings);
2017     }
2018   else
2019     priv->settings = NULL;
2020
2021   style_change_notify (toolbar);
2022   icon_size_change_notify (toolbar);
2023   animation_change_notify (toolbar);
2024 }
2025
2026 static int
2027 find_drop_index (GtkToolbar *toolbar,
2028                  gint        x,
2029                  gint        y)
2030 {
2031   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2032   GList *interesting_content;
2033   GList *list;
2034   GtkOrientation orientation;
2035   GtkTextDirection direction;
2036   gint best_distance = G_MAXINT;
2037   gint distance;
2038   gint cursor;
2039   gint pos;
2040   ToolbarContent *best_content;
2041   GtkAllocation allocation;
2042   
2043   /* list items we care about wrt. drag and drop */
2044   interesting_content = NULL;
2045   for (list = priv->content; list != NULL; list = list->next)
2046     {
2047       ToolbarContent *content = list->data;
2048       
2049       if (toolbar_content_get_state (content) == NORMAL)
2050         interesting_content = g_list_prepend (interesting_content, content);
2051     }
2052   interesting_content = g_list_reverse (interesting_content);
2053   
2054   if (!interesting_content)
2055     return 0;
2056   
2057   orientation = toolbar->orientation;
2058   direction = gtk_widget_get_direction (GTK_WIDGET (toolbar));
2059   
2060   /* distance to first interesting item */
2061   best_content = interesting_content->data;
2062   toolbar_content_get_allocation (best_content, &allocation);
2063   
2064   if (orientation == GTK_ORIENTATION_HORIZONTAL)
2065     {
2066       cursor = x;
2067       
2068       if (direction == GTK_TEXT_DIR_LTR)
2069         pos = allocation.x;
2070       else
2071         pos = allocation.x + allocation.width;
2072     }
2073   else
2074     {
2075       cursor = y;
2076       pos = allocation.y;
2077     }
2078   
2079   best_content = NULL;
2080   best_distance = ABS (pos - cursor);
2081   
2082   /* distance to far end of each item */
2083   for (list = interesting_content; list != NULL; list = list->next)
2084     {
2085       ToolbarContent *content = list->data;
2086       
2087       toolbar_content_get_allocation (content, &allocation);
2088       
2089       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2090         {
2091           if (direction == GTK_TEXT_DIR_LTR)
2092             pos = allocation.x + allocation.width;
2093           else
2094             pos = allocation.x;
2095         }
2096       else
2097         {
2098           pos = allocation.y + allocation.height;
2099         }
2100       
2101       distance = ABS (pos - cursor);
2102       
2103       if (distance < best_distance)
2104         {
2105           best_distance = distance;
2106           best_content = content;
2107         }
2108     }
2109   
2110   g_list_free (interesting_content);
2111   
2112   if (!best_content)
2113     return 0;
2114   else
2115     return g_list_index (priv->content, best_content) + 1;
2116 }
2117
2118 static void
2119 reset_all_placeholders (GtkToolbar *toolbar)
2120 {
2121   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2122   GList *list;
2123   
2124   for (list = priv->content; list != NULL; list = list->next)
2125     {
2126       ToolbarContent *content = list->data;
2127       if (toolbar_content_is_placeholder (content))
2128         toolbar_content_set_disappearing (content, TRUE);
2129     }
2130 }
2131
2132 static gint
2133 physical_to_logical (GtkToolbar *toolbar,
2134                      gint        physical)
2135 {
2136   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2137   GList *list;
2138   int logical;
2139   
2140   g_assert (physical >= 0);
2141   
2142   logical = 0;
2143   for (list = priv->content; list && physical > 0; list = list->next)
2144     {
2145       ToolbarContent *content = list->data;
2146       
2147       if (!toolbar_content_is_placeholder (content))
2148         logical++;
2149       physical--;
2150     }
2151   
2152   g_assert (physical == 0);
2153   
2154   return logical;
2155 }
2156
2157 static gint
2158 logical_to_physical (GtkToolbar *toolbar,
2159                      gint        logical)
2160 {
2161   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2162   GList *list;
2163   gint physical;
2164   
2165   g_assert (logical >= 0);
2166   
2167   physical = 0;
2168   for (list = priv->content; list; list = list->next)
2169     {
2170       ToolbarContent *content = list->data;
2171       
2172       if (!toolbar_content_is_placeholder (content))
2173         {
2174           if (logical == 0)
2175             break;
2176           logical--;
2177         }
2178       
2179       physical++;
2180     }
2181   
2182   g_assert (logical == 0);
2183   
2184   return physical;
2185 }
2186
2187 /**
2188  * gtk_toolbar_set_drop_highlight_item:
2189  * @toolbar: a #GtkToolbar
2190  * @tool_item: (allow-none): a #GtkToolItem, or %NULL to turn of highlighting
2191  * @index_: a position on @toolbar
2192  *
2193  * Highlights @toolbar to give an idea of what it would look like
2194  * if @item was added to @toolbar at the position indicated by @index_.
2195  * If @item is %NULL, highlighting is turned off. In that case @index_ 
2196  * is ignored.
2197  *
2198  * The @tool_item passed to this function must not be part of any widget
2199  * hierarchy. When an item is set as drop highlight item it can not
2200  * added to any widget hierarchy or used as highlight item for another
2201  * toolbar.
2202  * 
2203  * Since: 2.4
2204  **/
2205 void
2206 gtk_toolbar_set_drop_highlight_item (GtkToolbar  *toolbar,
2207                                      GtkToolItem *tool_item,
2208                                      gint         index_)
2209 {
2210   ToolbarContent *content;
2211   GtkToolbarPrivate *priv;
2212   gint n_items;
2213   GtkRequisition requisition;
2214   GtkRequisition old_requisition;
2215   gboolean restart_sliding;
2216   
2217   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2218   g_return_if_fail (tool_item == NULL || GTK_IS_TOOL_ITEM (tool_item));
2219   
2220   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2221   
2222   if (!tool_item)
2223     {
2224       if (priv->highlight_tool_item)
2225         {
2226           gtk_widget_unparent (GTK_WIDGET (priv->highlight_tool_item));
2227           g_object_unref (priv->highlight_tool_item);
2228           priv->highlight_tool_item = NULL;
2229         }
2230       
2231       reset_all_placeholders (toolbar);
2232       gtk_toolbar_begin_sliding (toolbar);
2233       return;
2234     }
2235   
2236   n_items = gtk_toolbar_get_n_items (toolbar);
2237   if (index_ < 0 || index_ > n_items)
2238     index_ = n_items;
2239   
2240   if (tool_item != priv->highlight_tool_item)
2241     {
2242       if (priv->highlight_tool_item)
2243         g_object_unref (priv->highlight_tool_item);
2244       
2245       g_object_ref_sink (tool_item);
2246       
2247       priv->highlight_tool_item = tool_item;
2248       
2249       gtk_widget_set_parent (GTK_WIDGET (priv->highlight_tool_item),
2250                              GTK_WIDGET (toolbar));
2251     }
2252   
2253   index_ = logical_to_physical (toolbar, index_);
2254   
2255   content = g_list_nth_data (priv->content, index_);
2256   
2257   if (index_ > 0)
2258     {
2259       ToolbarContent *prev_content;
2260       
2261       prev_content = g_list_nth_data (priv->content, index_ - 1);
2262       
2263       if (prev_content && toolbar_content_is_placeholder (prev_content))
2264         content = prev_content;
2265     }
2266   
2267   if (!content || !toolbar_content_is_placeholder (content))
2268     {
2269       GtkWidget *placeholder;
2270       
2271       placeholder = GTK_WIDGET (gtk_separator_tool_item_new ());
2272
2273       content = toolbar_content_new_tool_item (toolbar,
2274                                                GTK_TOOL_ITEM (placeholder),
2275                                                TRUE, index_);
2276       gtk_widget_show (placeholder);
2277     }
2278   
2279   g_assert (content);
2280   g_assert (toolbar_content_is_placeholder (content));
2281   
2282   gtk_widget_size_request (GTK_WIDGET (priv->highlight_tool_item),
2283                            &requisition);
2284
2285   toolbar_content_set_expand (content, gtk_tool_item_get_expand (tool_item));
2286   
2287   restart_sliding = FALSE;
2288   toolbar_content_size_request (content, toolbar, &old_requisition);
2289   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2290     {
2291       requisition.height = -1;
2292       if (requisition.width != old_requisition.width)
2293         restart_sliding = TRUE;
2294     }
2295   else
2296     {
2297       requisition.width = -1;
2298       if (requisition.height != old_requisition.height)
2299         restart_sliding = TRUE;
2300     }
2301
2302   if (toolbar_content_disappearing (content))
2303     restart_sliding = TRUE;
2304   
2305   reset_all_placeholders (toolbar);
2306   toolbar_content_set_disappearing (content, FALSE);
2307   
2308   toolbar_content_set_size_request (content,
2309                                     requisition.width, requisition.height);
2310   
2311   if (restart_sliding)
2312     gtk_toolbar_begin_sliding (toolbar);
2313 }
2314
2315 static void
2316 gtk_toolbar_get_child_property (GtkContainer *container,
2317                                 GtkWidget    *child,
2318                                 guint         property_id,
2319                                 GValue       *value,
2320                                 GParamSpec   *pspec)
2321 {
2322   GtkToolItem *item = GTK_TOOL_ITEM (child);
2323   
2324   switch (property_id)
2325     {
2326     case CHILD_PROP_HOMOGENEOUS:
2327       g_value_set_boolean (value, gtk_tool_item_get_homogeneous (item));
2328       break;
2329       
2330     case CHILD_PROP_EXPAND:
2331       g_value_set_boolean (value, gtk_tool_item_get_expand (item));
2332       break;
2333       
2334     default:
2335       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2336       break;
2337     }
2338 }
2339
2340 static void
2341 gtk_toolbar_set_child_property (GtkContainer *container,
2342                                 GtkWidget    *child,
2343                                 guint         property_id,
2344                                 const GValue *value,
2345                                 GParamSpec   *pspec)
2346 {
2347   switch (property_id)
2348     {
2349     case CHILD_PROP_HOMOGENEOUS:
2350       gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2351       break;
2352       
2353     case CHILD_PROP_EXPAND:
2354       gtk_tool_item_set_expand (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2355       break;
2356       
2357     default:
2358       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2359       break;
2360     }
2361 }
2362
2363 static void
2364 gtk_toolbar_show_all (GtkWidget *widget)
2365 {
2366   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
2367   GList *list;
2368
2369   for (list = priv->content; list != NULL; list = list->next)
2370     {
2371       ToolbarContent *content = list->data;
2372       
2373       toolbar_content_show_all (content);
2374     }
2375   
2376   gtk_widget_show (widget);
2377 }
2378
2379 static void
2380 gtk_toolbar_hide_all (GtkWidget *widget)
2381 {
2382   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
2383   GList *list;
2384
2385   for (list = priv->content; list != NULL; list = list->next)
2386     {
2387       ToolbarContent *content = list->data;
2388       
2389       toolbar_content_hide_all (content);
2390     }
2391
2392   gtk_widget_hide (widget);
2393 }
2394
2395 static void
2396 gtk_toolbar_add (GtkContainer *container,
2397                  GtkWidget    *widget)
2398 {
2399   GtkToolbar *toolbar = GTK_TOOLBAR (container);
2400
2401   gtk_toolbar_insert (toolbar, GTK_TOOL_ITEM (widget), -1);
2402 }
2403
2404 static void
2405 gtk_toolbar_remove (GtkContainer *container,
2406                     GtkWidget    *widget)
2407 {
2408   GtkToolbar *toolbar = GTK_TOOLBAR (container);
2409   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2410   ToolbarContent *content_to_remove;
2411   GList *list;
2412
2413   content_to_remove = NULL;
2414   for (list = priv->content; list != NULL; list = list->next)
2415     {
2416       ToolbarContent *content = list->data;
2417       GtkWidget *child;
2418       
2419       child = toolbar_content_get_widget (content);
2420       if (child && child == widget)
2421         {
2422           content_to_remove = content;
2423           break;
2424         }
2425     }
2426   
2427   g_return_if_fail (content_to_remove != NULL);
2428   
2429   toolbar_content_remove (content_to_remove, toolbar);
2430   toolbar_content_free (content_to_remove);
2431 }
2432
2433 static void
2434 gtk_toolbar_forall (GtkContainer *container,
2435                     gboolean      include_internals,
2436                     GtkCallback   callback,
2437                     gpointer      callback_data)
2438 {
2439   GtkToolbar *toolbar = GTK_TOOLBAR (container);
2440   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2441   GList *list;
2442   
2443   g_return_if_fail (callback != NULL);
2444   
2445   list = priv->content;
2446   while (list)
2447     {
2448       ToolbarContent *content = list->data;
2449       GList *next = list->next;
2450       
2451       if (include_internals || !toolbar_content_is_placeholder (content))
2452         {
2453           GtkWidget *child = toolbar_content_get_widget (content);
2454           
2455           if (child)
2456             callback (child, callback_data);
2457         }
2458       
2459       list = next;
2460     }
2461   
2462   if (include_internals)
2463     callback (priv->arrow_button, callback_data);
2464 }
2465
2466 static GType
2467 gtk_toolbar_child_type (GtkContainer *container)
2468 {
2469   return GTK_TYPE_TOOL_ITEM;
2470 }
2471
2472 static void
2473 gtk_toolbar_reconfigured (GtkToolbar *toolbar)
2474 {
2475   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2476   GList *list;
2477   
2478   list = priv->content;
2479   while (list)
2480     {
2481       ToolbarContent *content = list->data;
2482       GList *next = list->next;
2483       
2484       toolbar_content_toolbar_reconfigured (content, toolbar);
2485       
2486       list = next;
2487     }
2488 }
2489
2490 static void
2491 gtk_toolbar_orientation_changed (GtkToolbar    *toolbar,
2492                                  GtkOrientation orientation)
2493 {
2494   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2495   if (toolbar->orientation != orientation)
2496     {
2497       toolbar->orientation = orientation;
2498       
2499       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2500         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
2501       else
2502         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
2503       
2504       gtk_toolbar_reconfigured (toolbar);
2505       
2506       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2507       g_object_notify (G_OBJECT (toolbar), "orientation");
2508     }
2509 }
2510
2511 static void
2512 gtk_toolbar_real_style_changed (GtkToolbar     *toolbar,
2513                                 GtkToolbarStyle style)
2514 {
2515   if (toolbar->style != style)
2516     {
2517       toolbar->style = style;
2518       
2519       gtk_toolbar_reconfigured (toolbar);
2520       
2521       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2522       g_object_notify (G_OBJECT (toolbar), "toolbar-style");
2523     }
2524 }
2525
2526 static void
2527 menu_position_func (GtkMenu  *menu,
2528                     gint     *x,
2529                     gint     *y,
2530                     gboolean *push_in,
2531                     gpointer  user_data)
2532 {
2533   GtkToolbar *toolbar = GTK_TOOLBAR (user_data);
2534   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2535   GtkRequisition req;
2536   GtkRequisition menu_req;
2537   GdkRectangle monitor;
2538   gint monitor_num;
2539   GdkScreen *screen;
2540   
2541   gtk_widget_size_request (priv->arrow_button, &req);
2542   gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
2543   
2544   screen = gtk_widget_get_screen (GTK_WIDGET (menu));
2545   monitor_num = gdk_screen_get_monitor_at_window (screen, priv->arrow_button->window);
2546   if (monitor_num < 0)
2547     monitor_num = 0;
2548   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
2549
2550   gdk_window_get_origin (GTK_BUTTON (priv->arrow_button)->event_window, x, y);
2551   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2552     {
2553       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2554         *x += priv->arrow_button->allocation.width - req.width;
2555       else 
2556         *x += req.width - menu_req.width;
2557
2558       if ((*y + priv->arrow_button->allocation.height + menu_req.height) <= monitor.y + monitor.height)
2559         *y += priv->arrow_button->allocation.height;
2560       else if ((*y - menu_req.height) >= monitor.y)
2561         *y -= menu_req.height;
2562       else if (monitor.y + monitor.height - (*y + priv->arrow_button->allocation.height) > *y)
2563         *y += priv->arrow_button->allocation.height;
2564       else
2565         *y -= menu_req.height;
2566     }
2567   else 
2568     {
2569       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2570         *x += priv->arrow_button->allocation.width;
2571       else 
2572         *x -= menu_req.width;
2573
2574       if (*y + menu_req.height > monitor.y + monitor.height &&
2575           *y + priv->arrow_button->allocation.height - monitor.y > monitor.y + monitor.height - *y)
2576         *y += priv->arrow_button->allocation.height - menu_req.height;
2577     }
2578
2579   *push_in = FALSE;
2580 }
2581
2582 static void
2583 show_menu (GtkToolbar     *toolbar,
2584            GdkEventButton *event)
2585 {
2586   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2587
2588   rebuild_menu (toolbar);
2589
2590   gtk_widget_show_all (GTK_WIDGET (priv->menu));
2591
2592   gtk_menu_popup (priv->menu, NULL, NULL,
2593                   menu_position_func, toolbar,
2594                   event? event->button : 0,
2595                   event? event->time : gtk_get_current_event_time());
2596 }
2597
2598 static void
2599 gtk_toolbar_arrow_button_clicked (GtkWidget  *button,
2600                                   GtkToolbar *toolbar)
2601 {
2602   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);  
2603   
2604   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->arrow_button)) &&
2605       (!priv->menu || !gtk_widget_get_visible (GTK_WIDGET (priv->menu))))
2606     {
2607       /* We only get here when the button is clicked with the keyboard,
2608        * because mouse button presses result in the menu being shown so
2609        * that priv->menu would be non-NULL and visible.
2610        */
2611       show_menu (toolbar, NULL);
2612       gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2613     }
2614 }
2615
2616 static gboolean
2617 gtk_toolbar_arrow_button_press (GtkWidget      *button,
2618                                 GdkEventButton *event,
2619                                 GtkToolbar     *toolbar)
2620 {
2621   show_menu (toolbar, event);
2622   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2623   
2624   return TRUE;
2625 }
2626
2627 static gboolean
2628 gtk_toolbar_button_press (GtkWidget      *toolbar,
2629                           GdkEventButton *event)
2630 {
2631   if (event->button == 3)
2632     {
2633       gboolean return_value;
2634       
2635       g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2636                      (int)event->x_root, (int)event->y_root, event->button,
2637                      &return_value);
2638       
2639       return return_value;
2640     }
2641   
2642   return FALSE;
2643 }
2644
2645 static gboolean
2646 gtk_toolbar_popup_menu (GtkWidget *toolbar)
2647 {
2648   gboolean return_value;
2649   /* This function is the handler for the "popup menu" keybinding,
2650    * ie., it is called when the user presses Shift F10
2651    */
2652   g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2653                  -1, -1, -1, &return_value);
2654   
2655   return return_value;
2656 }
2657
2658 /**
2659  * gtk_toolbar_new:
2660  * 
2661  * Creates a new toolbar. 
2662  
2663  * Return Value: the newly-created toolbar.
2664  **/
2665 GtkWidget *
2666 gtk_toolbar_new (void)
2667 {
2668   GtkToolbar *toolbar;
2669   
2670   toolbar = g_object_new (GTK_TYPE_TOOLBAR, NULL);
2671   
2672   return GTK_WIDGET (toolbar);
2673 }
2674
2675 /**
2676  * gtk_toolbar_insert:
2677  * @toolbar: a #GtkToolbar
2678  * @item: a #GtkToolItem
2679  * @pos: the position of the new item
2680  *
2681  * Insert a #GtkToolItem into the toolbar at position @pos. If @pos is
2682  * 0 the item is prepended to the start of the toolbar. If @pos is
2683  * negative, the item is appended to the end of the toolbar.
2684  *
2685  * Since: 2.4
2686  **/
2687 void
2688 gtk_toolbar_insert (GtkToolbar  *toolbar,
2689                     GtkToolItem *item,
2690                     gint         pos)
2691 {
2692   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2693   g_return_if_fail (GTK_IS_TOOL_ITEM (item));
2694   
2695   if (pos >= 0)
2696     pos = logical_to_physical (toolbar, pos);
2697
2698   toolbar_content_new_tool_item (toolbar, item, FALSE, pos);
2699 }
2700
2701 /**
2702  * gtk_toolbar_get_item_index:
2703  * @toolbar: a #GtkToolbar
2704  * @item: a #GtkToolItem that is a child of @toolbar
2705  * 
2706  * Returns the position of @item on the toolbar, starting from 0.
2707  * It is an error if @item is not a child of the toolbar.
2708  * 
2709  * Return value: the position of item on the toolbar.
2710  * 
2711  * Since: 2.4
2712  **/
2713 gint
2714 gtk_toolbar_get_item_index (GtkToolbar  *toolbar,
2715                             GtkToolItem *item)
2716 {
2717   GtkToolbarPrivate *priv;
2718   GList *list;
2719   int n;
2720   
2721   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2722   g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1);
2723   g_return_val_if_fail (GTK_WIDGET (item)->parent == GTK_WIDGET (toolbar), -1);
2724   
2725   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2726   
2727   n = 0;
2728   for (list = priv->content; list != NULL; list = list->next)
2729     {
2730       ToolbarContent *content = list->data;
2731       GtkWidget *widget;
2732       
2733       widget = toolbar_content_get_widget (content);
2734       
2735       if (item == GTK_TOOL_ITEM (widget))
2736         break;
2737       
2738       ++n;
2739     }
2740   
2741   return physical_to_logical (toolbar, n);
2742 }
2743
2744 /**
2745  * gtk_toolbar_set_style:
2746  * @toolbar: a #GtkToolbar.
2747  * @style: the new style for @toolbar.
2748  * 
2749  * Alters the view of @toolbar to display either icons only, text only, or both.
2750  **/
2751 void
2752 gtk_toolbar_set_style (GtkToolbar      *toolbar,
2753                        GtkToolbarStyle  style)
2754 {
2755   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2756   
2757   toolbar->style_set = TRUE;  
2758   g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2759 }
2760
2761 /**
2762  * gtk_toolbar_get_style:
2763  * @toolbar: a #GtkToolbar
2764  *
2765  * Retrieves whether the toolbar has text, icons, or both . See
2766  * gtk_toolbar_set_style().
2767  
2768  * Return value: the current style of @toolbar
2769  **/
2770 GtkToolbarStyle
2771 gtk_toolbar_get_style (GtkToolbar *toolbar)
2772 {
2773   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE);
2774   
2775   return toolbar->style;
2776 }
2777
2778 /**
2779  * gtk_toolbar_unset_style:
2780  * @toolbar: a #GtkToolbar
2781  * 
2782  * Unsets a toolbar style set with gtk_toolbar_set_style(), so that
2783  * user preferences will be used to determine the toolbar style.
2784  **/
2785 void
2786 gtk_toolbar_unset_style (GtkToolbar *toolbar)
2787 {
2788   GtkToolbarStyle style;
2789   
2790   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2791   
2792   if (toolbar->style_set)
2793     {
2794       GtkSettings *settings = toolbar_get_settings (toolbar);
2795       
2796       if (settings)
2797         g_object_get (settings,
2798                       "gtk-toolbar-style", &style,
2799                       NULL);
2800       else
2801         style = DEFAULT_TOOLBAR_STYLE;
2802       
2803       if (style != toolbar->style)
2804         g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2805       
2806       toolbar->style_set = FALSE;
2807     }
2808 }
2809
2810 /**
2811  * gtk_toolbar_get_n_items:
2812  * @toolbar: a #GtkToolbar
2813  * 
2814  * Returns the number of items on the toolbar.
2815  * 
2816  * Return value: the number of items on the toolbar
2817  * 
2818  * Since: 2.4
2819  **/
2820 gint
2821 gtk_toolbar_get_n_items (GtkToolbar *toolbar)
2822 {
2823   GtkToolbarPrivate *priv;
2824   
2825   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2826   
2827   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2828   
2829   return physical_to_logical (toolbar, g_list_length (priv->content));
2830 }
2831
2832 /**
2833  * gtk_toolbar_get_nth_item:
2834  * @toolbar: a #GtkToolbar
2835  * @n: A position on the toolbar
2836  *
2837  * Returns the @n<!-- -->'th item on @toolbar, or %NULL if the
2838  * toolbar does not contain an @n<!-- -->'th item.
2839  * 
2840  * Return value: The @n<!-- -->'th #GtkToolItem on @toolbar, or %NULL if there
2841  * isn't an @n<!-- -->'th item.
2842  * 
2843  * Since: 2.4
2844  **/
2845 GtkToolItem *
2846 gtk_toolbar_get_nth_item (GtkToolbar *toolbar,
2847                           gint        n)
2848 {
2849   GtkToolbarPrivate *priv;
2850   ToolbarContent *content;
2851   gint n_items;
2852   
2853   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
2854   
2855   n_items = gtk_toolbar_get_n_items (toolbar);
2856   
2857   if (n < 0 || n >= n_items)
2858     return NULL;
2859   
2860   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2861   
2862   content = g_list_nth_data (priv->content, logical_to_physical (toolbar, n));
2863   
2864   g_assert (content);
2865   g_assert (!toolbar_content_is_placeholder (content));
2866   
2867   return GTK_TOOL_ITEM (toolbar_content_get_widget (content));
2868 }
2869
2870 /**
2871  * gtk_toolbar_get_icon_size:
2872  * @toolbar: a #GtkToolbar
2873  *
2874  * Retrieves the icon size for the toolbar. See gtk_toolbar_set_icon_size().
2875  *
2876  * Return value: (type int): the current icon size for the icons on
2877  * the toolbar.
2878  **/
2879 GtkIconSize
2880 gtk_toolbar_get_icon_size (GtkToolbar *toolbar)
2881 {
2882   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_ICON_SIZE);
2883   
2884   return toolbar->icon_size;
2885 }
2886
2887 /**
2888  * gtk_toolbar_get_relief_style:
2889  * @toolbar: a #GtkToolbar
2890  * 
2891  * Returns the relief style of buttons on @toolbar. See
2892  * gtk_button_set_relief().
2893  * 
2894  * Return value: The relief style of buttons on @toolbar.
2895  * 
2896  * Since: 2.4
2897  **/
2898 GtkReliefStyle
2899 gtk_toolbar_get_relief_style (GtkToolbar *toolbar)
2900 {
2901   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_RELIEF_NONE);
2902   
2903   return get_button_relief (toolbar);
2904 }
2905
2906 /**
2907  * gtk_toolbar_set_show_arrow:
2908  * @toolbar: a #GtkToolbar
2909  * @show_arrow: Whether to show an overflow menu
2910  * 
2911  * Sets whether to show an overflow menu when
2912  * @toolbar doesn't have room for all items on it. If %TRUE,
2913  * items that there are not room are available through an
2914  * overflow menu.
2915  * 
2916  * Since: 2.4
2917  **/
2918 void
2919 gtk_toolbar_set_show_arrow (GtkToolbar *toolbar,
2920                             gboolean    show_arrow)
2921 {
2922   GtkToolbarPrivate *priv;
2923   
2924   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2925   
2926   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2927   show_arrow = show_arrow != FALSE;
2928   
2929   if (priv->show_arrow != show_arrow)
2930     {
2931       priv->show_arrow = show_arrow;
2932       
2933       if (!priv->show_arrow)
2934         gtk_widget_hide (priv->arrow_button);
2935       
2936       gtk_widget_queue_resize (GTK_WIDGET (toolbar));      
2937       g_object_notify (G_OBJECT (toolbar), "show-arrow");
2938     }
2939 }
2940
2941 /**
2942  * gtk_toolbar_get_show_arrow:
2943  * @toolbar: a #GtkToolbar
2944  * 
2945  * Returns whether the toolbar has an overflow menu.
2946  * See gtk_toolbar_set_show_arrow().
2947  * 
2948  * Return value: %TRUE if the toolbar has an overflow menu.
2949  * 
2950  * Since: 2.4
2951  **/
2952 gboolean
2953 gtk_toolbar_get_show_arrow (GtkToolbar *toolbar)
2954 {
2955   GtkToolbarPrivate *priv;
2956   
2957   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2958   
2959   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2960   
2961   return priv->show_arrow;
2962 }
2963
2964 /**
2965  * gtk_toolbar_get_drop_index:
2966  * @toolbar: a #GtkToolbar
2967  * @x: x coordinate of a point on the toolbar
2968  * @y: y coordinate of a point on the toolbar
2969  *
2970  * Returns the position corresponding to the indicated point on
2971  * @toolbar. This is useful when dragging items to the toolbar:
2972  * this function returns the position a new item should be
2973  * inserted.
2974  *
2975  * @x and @y are in @toolbar coordinates.
2976  * 
2977  * Return value: The position corresponding to the point (@x, @y) on the toolbar.
2978  * 
2979  * Since: 2.4
2980  **/
2981 gint
2982 gtk_toolbar_get_drop_index (GtkToolbar *toolbar,
2983                             gint        x,
2984                             gint        y)
2985 {
2986   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2987   
2988   return physical_to_logical (toolbar, find_drop_index (toolbar, x, y));
2989 }
2990
2991 static void
2992 gtk_toolbar_finalize (GObject *object)
2993 {
2994   GList *list;
2995   GtkToolbar *toolbar = GTK_TOOLBAR (object);
2996   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2997   
2998   if (priv->arrow_button)
2999     gtk_widget_unparent (priv->arrow_button);
3000
3001   for (list = priv->content; list != NULL; list = list->next)
3002     {
3003       ToolbarContent *content = list->data;
3004
3005       toolbar_content_free (content);
3006     }
3007   
3008   g_list_free (priv->content);
3009   g_list_free (toolbar->children);
3010   
3011   g_timer_destroy (priv->timer);
3012   
3013   if (priv->menu)
3014     gtk_widget_destroy (GTK_WIDGET (priv->menu));
3015   
3016   if (priv->idle_id)
3017     g_source_remove (priv->idle_id);
3018
3019   G_OBJECT_CLASS (gtk_toolbar_parent_class)->finalize (object);
3020 }
3021
3022 /**
3023  * gtk_toolbar_set_icon_size:
3024  * @toolbar: A #GtkToolbar
3025  * @icon_size: (type int): The #GtkIconSize that stock icons in the
3026  *     toolbar shall have.
3027  *
3028  * This function sets the size of stock icons in the toolbar. You
3029  * can call it both before you add the icons and after they've been
3030  * added. The size you set will override user preferences for the default
3031  * icon size.
3032  * 
3033  * This should only be used for special-purpose toolbars, normal
3034  * application toolbars should respect the user preferences for the
3035  * size of icons.
3036  **/
3037 void
3038 gtk_toolbar_set_icon_size (GtkToolbar  *toolbar,
3039                            GtkIconSize  icon_size)
3040 {
3041   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3042   g_return_if_fail (icon_size != GTK_ICON_SIZE_INVALID);
3043   
3044   if (!toolbar->icon_size_set)
3045     {
3046       toolbar->icon_size_set = TRUE;  
3047       g_object_notify (G_OBJECT (toolbar), "icon-size-set");
3048     }
3049
3050   if (toolbar->icon_size == icon_size)
3051     return;
3052   
3053   toolbar->icon_size = icon_size;
3054   g_object_notify (G_OBJECT (toolbar), "icon-size");
3055   
3056   gtk_toolbar_reconfigured (toolbar);
3057   
3058   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3059 }
3060
3061 /**
3062  * gtk_toolbar_unset_icon_size:
3063  * @toolbar: a #GtkToolbar
3064  * 
3065  * Unsets toolbar icon size set with gtk_toolbar_set_icon_size(), so that
3066  * user preferences will be used to determine the icon size.
3067  **/
3068 void
3069 gtk_toolbar_unset_icon_size (GtkToolbar *toolbar)
3070 {
3071   GtkIconSize size;
3072   
3073   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3074   
3075   if (toolbar->icon_size_set)
3076     {
3077       GtkSettings *settings = toolbar_get_settings (toolbar);
3078       
3079       if (settings)
3080         {
3081           g_object_get (settings,
3082                         "gtk-toolbar-icon-size", &size,
3083                         NULL);
3084         }
3085       else
3086         size = DEFAULT_ICON_SIZE;
3087       
3088       if (size != toolbar->icon_size)
3089         {
3090           gtk_toolbar_set_icon_size (toolbar, size);
3091           g_object_notify (G_OBJECT (toolbar), "icon-size");      
3092         }
3093       
3094       toolbar->icon_size_set = FALSE;
3095       g_object_notify (G_OBJECT (toolbar), "icon-size-set");      
3096     }
3097 }
3098
3099 /*
3100  * ToolbarContent methods
3101  */
3102 typedef enum {
3103   UNKNOWN,
3104   YES,
3105   NO
3106 } TriState;
3107
3108 struct _ToolbarContent
3109 {
3110   ItemState      state;
3111
3112   GtkToolItem   *item;
3113   GtkAllocation  start_allocation;
3114   GtkAllocation  goal_allocation;
3115   guint          is_placeholder : 1;
3116   guint          disappearing : 1;
3117   guint          has_menu : 2;
3118 };
3119
3120 static ToolbarContent *
3121 toolbar_content_new_tool_item (GtkToolbar  *toolbar,
3122                                GtkToolItem *item,
3123                                gboolean     is_placeholder,
3124                                gint         pos)
3125 {
3126   ToolbarContent *content;
3127   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3128   
3129   content = g_slice_new0 (ToolbarContent);
3130   
3131   content->state = NOT_ALLOCATED;
3132   content->item = item;
3133   content->is_placeholder = is_placeholder;
3134   
3135   gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar));
3136
3137   priv->content = g_list_insert (priv->content, content, pos);
3138   
3139   if (!is_placeholder)
3140     {
3141       toolbar->num_children++;
3142
3143       gtk_toolbar_stop_sliding (toolbar);
3144     }
3145
3146   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3147   priv->need_rebuild = TRUE;
3148   
3149   return content;
3150 }
3151
3152 static void
3153 toolbar_content_remove (ToolbarContent *content,
3154                         GtkToolbar     *toolbar)
3155 {
3156   GtkToolbarPrivate *priv;
3157
3158   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3159
3160   gtk_widget_unparent (GTK_WIDGET (content->item));
3161
3162   priv->content = g_list_remove (priv->content, content);
3163
3164   if (!toolbar_content_is_placeholder (content))
3165     toolbar->num_children--;
3166
3167   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3168   priv->need_rebuild = TRUE;
3169 }
3170
3171 static void
3172 toolbar_content_free (ToolbarContent *content)
3173 {
3174   g_slice_free (ToolbarContent, content);
3175 }
3176
3177 static gint
3178 calculate_max_homogeneous_pixels (GtkWidget *widget)
3179 {
3180   PangoContext *context;
3181   PangoFontMetrics *metrics;
3182   gint char_width;
3183   
3184   context = gtk_widget_get_pango_context (widget);
3185   metrics = pango_context_get_metrics (context,
3186                                        widget->style->font_desc,
3187                                        pango_context_get_language (context));
3188   char_width = pango_font_metrics_get_approximate_char_width (metrics);
3189   pango_font_metrics_unref (metrics);
3190   
3191   return PANGO_PIXELS (MAX_HOMOGENEOUS_N_CHARS * char_width);
3192 }
3193
3194 static void
3195 toolbar_content_expose (ToolbarContent *content,
3196                         GtkContainer   *container,
3197                         GdkEventExpose *expose)
3198 {
3199   GtkWidget *widget;
3200
3201   if (!content->is_placeholder)
3202     widget = GTK_WIDGET (content->item);
3203
3204   if (widget)
3205     gtk_container_propagate_expose (container, widget, expose);
3206 }
3207
3208 static gboolean
3209 toolbar_content_visible (ToolbarContent *content,
3210                          GtkToolbar     *toolbar)
3211 {
3212   GtkToolItem *item;
3213
3214   item = content->item;
3215
3216   if (!gtk_widget_get_visible (GTK_WIDGET (item)))
3217     return FALSE;
3218
3219   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL &&
3220       gtk_tool_item_get_visible_horizontal (item))
3221     return TRUE;
3222
3223   if (toolbar->orientation == GTK_ORIENTATION_VERTICAL &&
3224       gtk_tool_item_get_visible_vertical (item))
3225     return TRUE;
3226       
3227   return FALSE;
3228 }
3229
3230 static void
3231 toolbar_content_size_request (ToolbarContent *content,
3232                               GtkToolbar     *toolbar,
3233                               GtkRequisition *requisition)
3234 {
3235   gtk_widget_size_request (GTK_WIDGET (content->item),
3236                            requisition);
3237   if (content->is_placeholder &&
3238       content->disappearing)
3239     {
3240       requisition->width = 0;
3241       requisition->height = 0;
3242     }
3243 }
3244
3245 static gboolean
3246 toolbar_content_is_homogeneous (ToolbarContent *content,
3247                                 GtkToolbar     *toolbar)
3248 {
3249   GtkRequisition requisition;
3250   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3251   gboolean result;
3252   
3253   if (priv->max_homogeneous_pixels < 0)
3254     {
3255       priv->max_homogeneous_pixels =
3256         calculate_max_homogeneous_pixels (GTK_WIDGET (toolbar));
3257     }
3258   
3259   toolbar_content_size_request (content, toolbar, &requisition);
3260   
3261   if (requisition.width > priv->max_homogeneous_pixels)
3262     return FALSE;
3263
3264   result = gtk_tool_item_get_homogeneous (content->item) &&
3265            !GTK_IS_SEPARATOR_TOOL_ITEM (content->item);
3266
3267   if (gtk_tool_item_get_is_important (content->item) &&
3268       toolbar->style == GTK_TOOLBAR_BOTH_HORIZ &&
3269       toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
3270     {
3271       result = FALSE;
3272     }
3273
3274   return result;
3275 }
3276
3277 static gboolean
3278 toolbar_content_is_placeholder (ToolbarContent *content)
3279 {
3280   if (content->is_placeholder)
3281     return TRUE;
3282   
3283   return FALSE;
3284 }
3285
3286 static gboolean
3287 toolbar_content_disappearing (ToolbarContent *content)
3288 {
3289   if (content->disappearing)
3290     return TRUE;
3291   
3292   return FALSE;
3293 }
3294
3295 static ItemState
3296 toolbar_content_get_state (ToolbarContent *content)
3297 {
3298   return content->state;
3299 }
3300
3301 static gboolean
3302 toolbar_content_child_visible (ToolbarContent *content)
3303 {
3304   return GTK_WIDGET_CHILD_VISIBLE (content->item);
3305 }
3306
3307 static void
3308 toolbar_content_get_goal_allocation (ToolbarContent *content,
3309                                      GtkAllocation  *allocation)
3310 {
3311   *allocation = content->goal_allocation;
3312 }
3313
3314 static void
3315 toolbar_content_get_allocation (ToolbarContent *content,
3316                                 GtkAllocation  *allocation)
3317 {
3318   gtk_widget_get_allocation (GTK_WIDGET (content->item), allocation);
3319 }
3320
3321 static void
3322 toolbar_content_set_start_allocation (ToolbarContent *content,
3323                                       GtkAllocation  *allocation)
3324 {
3325   content->start_allocation = *allocation;
3326 }
3327
3328 static gboolean
3329 toolbar_content_get_expand (ToolbarContent *content)
3330 {
3331   if (!content->disappearing &&
3332       gtk_tool_item_get_expand (content->item))
3333     return TRUE;
3334
3335   return FALSE;
3336 }
3337
3338 static void
3339 toolbar_content_set_goal_allocation (ToolbarContent *content,
3340                                      GtkAllocation  *allocation)
3341 {
3342   content->goal_allocation = *allocation;
3343 }
3344
3345 static void
3346 toolbar_content_set_child_visible (ToolbarContent *content,
3347                                    GtkToolbar     *toolbar,
3348                                    gboolean        visible)
3349 {
3350   gtk_widget_set_child_visible (GTK_WIDGET (content->item),
3351                                 visible);
3352 }
3353
3354 static void
3355 toolbar_content_get_start_allocation (ToolbarContent *content,
3356                                       GtkAllocation  *start_allocation)
3357 {
3358   *start_allocation = content->start_allocation;
3359 }
3360
3361 static void
3362 toolbar_content_size_allocate (ToolbarContent *content,
3363                                GtkAllocation  *allocation)
3364 {
3365   gtk_widget_size_allocate (GTK_WIDGET (content->item),
3366                             allocation);
3367 }
3368
3369 static void
3370 toolbar_content_set_state (ToolbarContent *content,
3371                            ItemState       state)
3372 {
3373   content->state = state;
3374 }
3375
3376 static GtkWidget *
3377 toolbar_content_get_widget (ToolbarContent *content)
3378 {
3379   return GTK_WIDGET (content->item);
3380 }
3381
3382
3383 static void
3384 toolbar_content_set_disappearing (ToolbarContent *content,
3385                                   gboolean        disappearing)
3386 {
3387   content->disappearing = disappearing;
3388 }
3389
3390 static void
3391 toolbar_content_set_size_request (ToolbarContent *content,
3392                                   gint            width,
3393                                   gint            height)
3394 {
3395   gtk_widget_set_size_request (GTK_WIDGET (content->item),
3396                                width, height);
3397 }
3398
3399 static void
3400 toolbar_content_toolbar_reconfigured (ToolbarContent *content,
3401                                       GtkToolbar     *toolbar)
3402 {
3403   gtk_tool_item_toolbar_reconfigured (content->item);
3404 }
3405
3406 static GtkWidget *
3407 toolbar_content_retrieve_menu_item (ToolbarContent *content)
3408 {
3409   return gtk_tool_item_retrieve_proxy_menu_item (content->item);
3410 }
3411
3412 static gboolean
3413 toolbar_content_has_proxy_menu_item (ToolbarContent *content)
3414 {
3415   GtkWidget *menu_item;
3416
3417   if (content->has_menu == YES)
3418     return TRUE;
3419   else if (content->has_menu == NO)
3420     return FALSE;
3421
3422   menu_item = toolbar_content_retrieve_menu_item (content);
3423
3424   content->has_menu = menu_item? YES : NO;
3425
3426   return menu_item != NULL;
3427 }
3428
3429 static void
3430 toolbar_content_set_unknown_menu_status (ToolbarContent *content)
3431 {
3432   content->has_menu = UNKNOWN;
3433 }
3434
3435 static gboolean
3436 toolbar_content_is_separator (ToolbarContent *content)
3437 {
3438   return GTK_IS_SEPARATOR_TOOL_ITEM (content->item);
3439 }
3440
3441 static void
3442 toolbar_content_set_expand (ToolbarContent *content,
3443                             gboolean        expand)
3444 {
3445   gtk_tool_item_set_expand (content->item, expand);
3446 }
3447
3448 static void
3449 toolbar_content_show_all (ToolbarContent  *content)
3450 {
3451   GtkWidget *widget;
3452   
3453   widget = toolbar_content_get_widget (content);
3454   if (widget)
3455     gtk_widget_show_all (widget);
3456 }
3457
3458 static void
3459 toolbar_content_hide_all (ToolbarContent  *content)
3460 {
3461   GtkWidget *widget;
3462   
3463   widget = toolbar_content_get_widget (content);
3464   if (widget)
3465     gtk_widget_hide_all (widget);
3466 }
3467
3468 /*
3469  * Getters
3470  */
3471 static GtkReliefStyle
3472 get_button_relief (GtkToolbar *toolbar)
3473 {
3474   GtkReliefStyle button_relief = GTK_RELIEF_NORMAL;
3475   
3476   gtk_widget_ensure_style (GTK_WIDGET (toolbar));
3477   
3478   gtk_widget_style_get (GTK_WIDGET (toolbar),
3479                         "button-relief", &button_relief,
3480                         NULL);
3481   
3482   return button_relief;
3483 }
3484
3485 static gint
3486 get_internal_padding (GtkToolbar *toolbar)
3487 {
3488   gint ipadding = 0;
3489   
3490   gtk_widget_style_get (GTK_WIDGET (toolbar),
3491                         "internal-padding", &ipadding,
3492                         NULL);
3493   
3494   return ipadding;
3495 }
3496
3497 static gint
3498 get_max_child_expand (GtkToolbar *toolbar)
3499 {
3500   gint mexpand = G_MAXINT;
3501
3502   gtk_widget_style_get (GTK_WIDGET (toolbar),
3503                         "max-child-expand", &mexpand,
3504                         NULL);
3505   return mexpand;
3506 }
3507
3508 static GtkShadowType
3509 get_shadow_type (GtkToolbar *toolbar)
3510 {
3511   GtkShadowType shadow_type;
3512   
3513   gtk_widget_style_get (GTK_WIDGET (toolbar),
3514                         "shadow-type", &shadow_type,
3515                         NULL);
3516   
3517   return shadow_type;
3518 }
3519
3520 /* GTK+ internal methods */
3521
3522 gint
3523 _gtk_toolbar_get_default_space_size (void)
3524 {
3525   return DEFAULT_SPACE_SIZE;
3526 }
3527
3528 void
3529 _gtk_toolbar_paint_space_line (GtkWidget           *widget,
3530                                GtkToolbar          *toolbar,
3531                                const GdkRectangle  *area,
3532                                const GtkAllocation *allocation)
3533 {
3534   const double start_fraction = (SPACE_LINE_START / SPACE_LINE_DIVISION);
3535   const double end_fraction = (SPACE_LINE_END / SPACE_LINE_DIVISION);
3536   
3537   GtkOrientation orientation;
3538
3539   g_return_if_fail (GTK_IS_WIDGET (widget));
3540   
3541   orientation = toolbar? toolbar->orientation : GTK_ORIENTATION_HORIZONTAL;
3542
3543   if (orientation == GTK_ORIENTATION_HORIZONTAL)
3544     {
3545       gboolean wide_separators;
3546       gint     separator_width;
3547
3548       gtk_widget_style_get (widget,
3549                             "wide-separators", &wide_separators,
3550                             "separator-width", &separator_width,
3551                             NULL);
3552
3553       if (wide_separators)
3554         gtk_paint_box (widget->style, widget->window,
3555                        gtk_widget_get_state (widget), GTK_SHADOW_ETCHED_OUT,
3556                        area, widget, "vseparator",
3557                        allocation->x + (allocation->width - separator_width) / 2,
3558                        allocation->y + allocation->height * start_fraction,
3559                        separator_width,
3560                        allocation->height * (end_fraction - start_fraction));
3561       else
3562         gtk_paint_vline (widget->style, widget->window,
3563                          gtk_widget_get_state (widget), area, widget,
3564                          "toolbar",
3565                          allocation->y + allocation->height * start_fraction,
3566                          allocation->y + allocation->height * end_fraction,
3567                          allocation->x + (allocation->width - widget->style->xthickness) / 2);
3568     }
3569   else
3570     {
3571       gboolean wide_separators;
3572       gint     separator_height;
3573
3574       gtk_widget_style_get (widget,
3575                             "wide-separators",  &wide_separators,
3576                             "separator-height", &separator_height,
3577                             NULL);
3578
3579       if (wide_separators)
3580         gtk_paint_box (widget->style, widget->window,
3581                        gtk_widget_get_state (widget), GTK_SHADOW_ETCHED_OUT,
3582                        area, widget, "hseparator",
3583                        allocation->x + allocation->width * start_fraction,
3584                        allocation->y + (allocation->height - separator_height) / 2,
3585                        allocation->width * (end_fraction - start_fraction),
3586                        separator_height);
3587       else
3588         gtk_paint_hline (widget->style, widget->window,
3589                          gtk_widget_get_state (widget), area, widget,
3590                          "toolbar",
3591                          allocation->x + allocation->width * start_fraction,
3592                          allocation->x + allocation->width * end_fraction,
3593                          allocation->y + (allocation->height - widget->style->ythickness) / 2);
3594     }
3595 }
3596
3597 gchar *
3598 _gtk_toolbar_elide_underscores (const gchar *original)
3599 {
3600   gchar *q, *result;
3601   const gchar *p, *end;
3602   gsize len;
3603   gboolean last_underscore;
3604   
3605   if (!original)
3606     return NULL;
3607
3608   len = strlen (original);
3609   q = result = g_malloc (len + 1);
3610   last_underscore = FALSE;
3611   
3612   end = original + len;
3613   for (p = original; p < end; p++)
3614     {
3615       if (!last_underscore && *p == '_')
3616         last_underscore = TRUE;
3617       else
3618         {
3619           last_underscore = FALSE;
3620           if (original + 2 <= p && p + 1 <= end && 
3621               p[-2] == '(' && p[-1] == '_' && p[0] != '_' && p[1] == ')')
3622             {
3623               q--;
3624               *q = '\0';
3625               p++;
3626             }
3627           else
3628             *q++ = *p;
3629         }
3630     }
3631
3632   if (last_underscore)
3633     *q++ = '_';
3634   
3635   *q = '\0';
3636   
3637   return result;
3638 }
3639
3640 static GtkIconSize
3641 toolbar_get_icon_size (GtkToolShell *shell)
3642 {
3643   return GTK_TOOLBAR (shell)->icon_size;
3644 }
3645
3646 static GtkOrientation
3647 toolbar_get_orientation (GtkToolShell *shell)
3648 {
3649   return GTK_TOOLBAR (shell)->orientation;
3650 }
3651
3652 static GtkToolbarStyle
3653 toolbar_get_style (GtkToolShell *shell)
3654 {
3655   return GTK_TOOLBAR (shell)->style;
3656 }
3657
3658 static GtkReliefStyle
3659 toolbar_get_relief_style (GtkToolShell *shell)
3660 {
3661   return get_button_relief (GTK_TOOLBAR (shell));
3662 }
3663
3664 static void
3665 toolbar_rebuild_menu (GtkToolShell *shell)
3666 {
3667   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (shell);
3668   GList *list;
3669
3670   priv->need_rebuild = TRUE;
3671
3672   for (list = priv->content; list != NULL; list = list->next)
3673     {
3674       ToolbarContent *content = list->data;
3675
3676       toolbar_content_set_unknown_menu_status (content);
3677     }
3678   
3679   gtk_widget_queue_resize (GTK_WIDGET (shell));
3680 }
3681
3682 #define __GTK_TOOLBAR_C__
3683 #include "gtkaliasdef.c"