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