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