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