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