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