]> Pileus Git - ~andy/gtk/blob - gtk/gtktoolbar.c
Set a small size request and make the window resizable, to test
[~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
62 #define SPACE_LINE_START    3
63 #define SPACE_LINE_END      7
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       
1055       state = toolbar_content_get_state (content);
1056       toolbar_content_get_goal_allocation (content, &goal_allocation);
1057       toolbar_content_get_allocation (content, &allocation);
1058       
1059       if ((state == NOT_ALLOCATED) ||
1060           (state == NORMAL &&
1061            toolbar_content_child_visible (content) &&
1062            ((goal_allocation.x != allocation.x ||
1063              goal_allocation.y != allocation.y ||
1064              goal_allocation.width != allocation.width ||
1065              goal_allocation.height != allocation.height))) ||
1066           (toolbar_content_is_placeholder (content) &&
1067            toolbar_content_disappearing (content) &&
1068            toolbar_content_child_visible (content)))
1069         {
1070           gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1071           
1072           GDK_THREADS_LEAVE ();
1073           return TRUE;
1074         }
1075     }
1076   
1077   priv->is_sliding = FALSE;
1078   priv->idle_id = 0;
1079   
1080   GDK_THREADS_LEAVE();
1081   return FALSE;
1082 }
1083
1084 static gboolean
1085 rect_within (GtkAllocation *a1, GtkAllocation *a2)
1086 {
1087   return (a1->x >= a2->x                         &&
1088           a1->x + a1->width <= a2->x + a2->width &&
1089           a1->y >= a2->y                         &&
1090           a1->y + a1->height <= a2->y + a2->height);
1091 }
1092
1093 static void
1094 gtk_toolbar_begin_sliding (GtkToolbar *toolbar)
1095 {
1096   GtkWidget *widget = GTK_WIDGET (toolbar);
1097   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1098   GList *list;
1099   gint cur_x;
1100   gint cur_y;
1101   gint border_width;
1102   gboolean rtl;
1103   gboolean vertical;
1104   
1105   /* Start the sliding. This function copies the allocation of every
1106    * item into content->start_allocation. For items that haven't
1107    * been allocated yet, we calculate their position and save that
1108    * in start_allocatino along with zero width and zero height.
1109    */
1110   priv->is_sliding = TRUE;
1111   
1112   if (!priv->idle_id)
1113     priv->idle_id = g_idle_add (slide_idle_handler, toolbar);
1114   
1115   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1116   vertical = (toolbar->orientation == GTK_ORIENTATION_VERTICAL);
1117   border_width = get_internal_padding (toolbar) + GTK_CONTAINER (toolbar)->border_width;
1118   
1119   if (rtl)
1120     {
1121       cur_x = widget->allocation.width - border_width - widget->style->xthickness;
1122       cur_y = widget->allocation.height - border_width - widget->style->ythickness;
1123     }
1124   else
1125     {
1126       cur_x = border_width + widget->style->xthickness;
1127       cur_y = border_width + widget->style->ythickness;
1128     }
1129   
1130   cur_x += widget->allocation.x;
1131   cur_y += widget->allocation.y;
1132   
1133   for (list = priv->content; list != NULL; list = list->next)
1134     {
1135       ToolbarContent *content = list->data;
1136       GtkAllocation new_start_allocation;
1137       ItemState state;
1138       GtkAllocation item_allocation;
1139       
1140       state = toolbar_content_get_state (content);
1141       toolbar_content_get_allocation (content, &item_allocation);
1142       
1143       if (state == NORMAL &&
1144           rect_within (&item_allocation, &(widget->allocation)))
1145         {
1146           new_start_allocation = item_allocation;
1147         }
1148       else
1149         {
1150           new_start_allocation.x = cur_x;
1151           new_start_allocation.y = cur_y;
1152           
1153           if (vertical)
1154             {
1155               new_start_allocation.width = widget->allocation.width -
1156                 2 * border_width - 2 * widget->style->xthickness;
1157               new_start_allocation.height = 0;
1158             }
1159           else
1160             {
1161               new_start_allocation.width = 0;
1162               new_start_allocation.height = widget->allocation.height -
1163                 2 * border_width - 2 * widget->style->ythickness;
1164             }
1165         }
1166       
1167       if (vertical)
1168         cur_y = new_start_allocation.y + new_start_allocation.height;
1169       else if (rtl)
1170         cur_x = new_start_allocation.x;
1171       else
1172         cur_x = new_start_allocation.x + new_start_allocation.width;
1173       
1174       toolbar_content_set_start_allocation (content, &new_start_allocation);
1175     }
1176   
1177   g_timer_reset (priv->timer);
1178 }
1179
1180 static void
1181 gtk_toolbar_stop_sliding (GtkToolbar *toolbar)
1182 {
1183   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1184   
1185   if (priv->is_sliding)
1186     {
1187       GList *list;
1188       
1189       priv->is_sliding = FALSE;
1190       
1191       if (priv->idle_id)
1192         {
1193           g_source_remove (priv->idle_id);
1194           priv->idle_id = 0;
1195         }
1196       
1197       list = priv->content;
1198       while (list)
1199         {
1200           ToolbarContent *content = list->data;
1201           list = list->next;
1202           
1203           if (toolbar_content_is_placeholder (content))
1204             {
1205               toolbar_content_remove (content, toolbar);
1206               toolbar_content_free (content);
1207             }
1208         }
1209       
1210       gtk_widget_queue_resize_no_redraw (GTK_WIDGET (toolbar));
1211     }
1212 }
1213
1214 static void
1215 gtk_toolbar_size_allocate (GtkWidget     *widget,
1216                            GtkAllocation *allocation)
1217 {
1218   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1219   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1220   GtkAllocation *allocations;
1221   ItemState *new_states;
1222   GtkAllocation arrow_allocation;
1223   gint arrow_size;
1224   gint size, pos, short_size;
1225   GList *list;
1226   gint i;
1227   gboolean need_arrow;
1228   gint n_expand_items;
1229   gint border_width;
1230   gint available_size;
1231   gint n_items;
1232   gint needed_size;
1233   GtkRequisition arrow_requisition;
1234   gboolean overflowing;
1235   gboolean size_changed;
1236   gdouble elapsed;
1237
1238   size_changed = FALSE;
1239   if (widget->allocation.x != allocation->x             ||
1240       widget->allocation.y != allocation->y             ||
1241       widget->allocation.width != allocation->width     ||
1242       widget->allocation.height != allocation->height)
1243     {
1244       size_changed = TRUE;
1245     }
1246   
1247   if (size_changed)
1248     gtk_toolbar_stop_sliding (toolbar);
1249   
1250   widget->allocation = *allocation;
1251   
1252   border_width = GTK_CONTAINER (toolbar)->border_width;
1253   
1254   if (GTK_WIDGET_REALIZED (widget))
1255     {
1256       gdk_window_move_resize (priv->event_window,
1257                               allocation->x + border_width,
1258                               allocation->y + border_width,
1259                               allocation->width - border_width * 2,
1260                               allocation->height - border_width * 2);
1261     }
1262   
1263   border_width += get_internal_padding (toolbar);
1264   
1265   gtk_widget_get_child_requisition (GTK_WIDGET (priv->arrow_button),
1266                                     &arrow_requisition);
1267   
1268   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
1269     {
1270       available_size = size = allocation->width - 2 * border_width;
1271       short_size = allocation->height - 2 * border_width;
1272       arrow_size = arrow_requisition.width;
1273       
1274       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1275         {
1276           available_size -= 2 * widget->style->xthickness;
1277           short_size -= 2 * widget->style->ythickness;
1278         }
1279     }
1280   else
1281     {
1282       available_size = size = allocation->height - 2 * border_width;
1283       short_size = allocation->width - 2 * border_width;
1284       arrow_size = arrow_requisition.height;
1285       
1286       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1287         {
1288           available_size -= 2 * widget->style->ythickness;
1289           short_size -= 2 * widget->style->xthickness;
1290         }
1291     }
1292   
1293   n_items = g_list_length (priv->content);
1294   allocations = g_new0 (GtkAllocation, n_items);
1295   new_states = g_new0 (ItemState, n_items);
1296   
1297   needed_size = 0;
1298   for (list = priv->content; list != NULL; list = list->next)
1299     {
1300       ToolbarContent *content = list->data;
1301       
1302       if (toolbar_content_visible (content, toolbar))
1303         needed_size += get_item_size (toolbar, content);
1304     }
1305   
1306   need_arrow = (needed_size > available_size) && priv->show_arrow && priv->api_mode == NEW_API;
1307   
1308   if (need_arrow)
1309     size = available_size - arrow_size;
1310   else
1311     size = available_size;
1312   
1313   /* calculate widths of items */
1314   overflowing = FALSE;
1315   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1316     {
1317       ToolbarContent *content = list->data;
1318       gint item_size;
1319       
1320       if (!toolbar_content_visible (content, toolbar))
1321         {
1322           new_states[i] = HIDDEN;
1323           continue;
1324         }
1325       
1326       item_size = get_item_size (toolbar, content);
1327       if (item_size <= size && !overflowing)
1328         {
1329           size -= item_size;
1330           allocations[i].width = item_size;
1331           new_states[i] = NORMAL;
1332         }
1333       else
1334         {
1335           overflowing = TRUE;
1336           new_states[i] = OVERFLOWN;
1337         }
1338     }
1339   
1340   /* calculate width of arrow */  
1341   if (need_arrow)
1342     {
1343       arrow_allocation.width = arrow_size;
1344       arrow_allocation.height = short_size;
1345     }
1346   
1347   /* expand expandable items */
1348   
1349   /* We don't expand when there is an overflow menu, because that leads to
1350    * weird jumps when items get moved to the overflow menu and the expanding
1351    * items suddenly get a lot of extra space
1352    */
1353   if (!overflowing)
1354     {
1355       n_expand_items = 0;
1356       for (i = 0, list = priv->content; list != NULL; list = list->next, ++i)
1357         {
1358           ToolbarContent *content = list->data;
1359           
1360           if (toolbar_content_get_expand (content) && new_states[i] == NORMAL)
1361             n_expand_items++;
1362         }
1363       
1364       for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1365         {
1366           ToolbarContent *content = list->data;
1367           
1368           if (toolbar_content_get_expand (content) && new_states[i] == NORMAL)
1369             {
1370               gint extra = size / n_expand_items;
1371               if (size % n_expand_items != 0)
1372                 extra++;
1373               
1374               allocations[i].width += extra;
1375               size -= extra;
1376               n_expand_items--;
1377             }
1378         }
1379       
1380       g_assert (n_expand_items == 0);
1381     }
1382   
1383   /* position items */
1384   pos = border_width;
1385   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1386     {
1387       if (new_states[i] == NORMAL)
1388         {
1389           allocations[i].x = pos;
1390           allocations[i].y = border_width;
1391           allocations[i].height = short_size;
1392           
1393           pos += allocations[i].width;
1394         }
1395     }
1396   
1397   /* position arrow */
1398   if (need_arrow)
1399     {
1400       arrow_allocation.x = available_size - border_width - arrow_allocation.width;
1401       arrow_allocation.y = border_width;
1402     }
1403   
1404   /* fix up allocations in the vertical or RTL cases */
1405   if (toolbar->orientation == GTK_ORIENTATION_VERTICAL)
1406     {
1407       for (i = 0; i < n_items; ++i)
1408         fixup_allocation_for_vertical (&(allocations[i]));
1409       
1410       if (need_arrow)
1411         fixup_allocation_for_vertical (&arrow_allocation);
1412     }
1413   else if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1414     {
1415       for (i = 0; i < n_items; ++i)
1416         fixup_allocation_for_rtl (available_size, &(allocations[i]));
1417       
1418       if (need_arrow)
1419         fixup_allocation_for_rtl (available_size, &arrow_allocation);
1420     }
1421   
1422   /* translate the items by allocation->(x,y) */
1423   for (i = 0; i < n_items; ++i)
1424     {
1425       allocations[i].x += allocation->x;
1426       allocations[i].y += allocation->y;
1427       
1428       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1429         {
1430           allocations[i].x += widget->style->xthickness;
1431           allocations[i].y += widget->style->ythickness;
1432         }
1433     }
1434   
1435   if (need_arrow)
1436     {
1437       arrow_allocation.x += allocation->x;
1438       arrow_allocation.y += allocation->y;
1439       
1440       if (get_shadow_type (toolbar) != GTK_SHADOW_NONE)
1441         {
1442           arrow_allocation.x += widget->style->xthickness;
1443           arrow_allocation.y += widget->style->ythickness;
1444         }
1445     }
1446   
1447   /* did anything change? */
1448   for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1449     {
1450       ToolbarContent *content = list->data;
1451       
1452       if (toolbar_content_get_state (content) == NORMAL &&
1453           new_states[i] != NORMAL)
1454         {
1455           /* an item disappeared, begin sliding */
1456           if (!size_changed)
1457             gtk_toolbar_begin_sliding (toolbar);
1458         }
1459     }
1460   
1461   /* finally allocate the items */
1462   if (priv->is_sliding)
1463     {
1464       for (list = priv->content, i = 0; list != NULL; list = list->next, i++)
1465         {
1466           ToolbarContent *content = list->data;
1467           
1468           toolbar_content_set_goal_allocation (content, &(allocations[i]));
1469         }
1470     }
1471
1472   elapsed = g_timer_elapsed (priv->timer, NULL);
1473   for (list = priv->content, i = 0; list != NULL; list = list->next, ++i)
1474     {
1475       ToolbarContent *content = list->data;
1476
1477       if (new_states[i] != NORMAL)
1478         {
1479           toolbar_content_set_child_visible (content, toolbar, FALSE);
1480         }
1481       else
1482         {
1483           GtkAllocation alloc;
1484           GtkAllocation start_allocation;
1485           GtkAllocation goal_allocation;
1486
1487           if (priv->is_sliding)
1488             {
1489               toolbar_content_get_start_allocation (content, &start_allocation);
1490               toolbar_content_get_goal_allocation (content, &goal_allocation);
1491               
1492               compute_intermediate_allocation (toolbar,
1493                                                &start_allocation,
1494                                                &goal_allocation,
1495                                                &alloc);
1496               
1497               priv->need_sync = TRUE;
1498             }
1499           else
1500             {
1501               alloc = allocations[i];
1502             }
1503           
1504           if (alloc.width == 0 || alloc.height == 0)
1505             {
1506               toolbar_content_set_child_visible (content, toolbar, FALSE);
1507             }
1508           else
1509             {
1510               toolbar_content_set_child_visible (content, toolbar, TRUE);
1511               toolbar_content_size_allocate (content, &alloc);
1512             }
1513         }
1514       
1515       toolbar_content_set_state (content, new_states[i]);
1516     }
1517   
1518   if (need_arrow)
1519     {
1520       gtk_widget_size_allocate (GTK_WIDGET (priv->arrow_button),
1521                                 &arrow_allocation);
1522       gtk_widget_show (GTK_WIDGET (priv->arrow_button));
1523     }
1524   else
1525     {
1526       gtk_widget_hide (GTK_WIDGET (priv->arrow_button));
1527     }
1528   
1529   g_free (allocations);
1530   g_free (new_states);
1531 }
1532
1533 static void
1534 gtk_toolbar_update_button_relief (GtkToolbar *toolbar)
1535 {
1536   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1537   
1538   gtk_toolbar_reconfigured (toolbar);
1539   
1540   gtk_button_set_relief (GTK_BUTTON (priv->arrow_button), get_button_relief (toolbar));
1541 }
1542
1543 static void
1544 gtk_toolbar_style_set (GtkWidget *widget,
1545                        GtkStyle  *prev_style)
1546 {
1547   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
1548   
1549   priv->max_homogeneous_pixels = -1;
1550   
1551   if (GTK_WIDGET_REALIZED (widget))
1552     gtk_style_set_background (widget->style, widget->window, widget->state);
1553   
1554   if (prev_style)
1555     gtk_toolbar_update_button_relief (GTK_TOOLBAR (widget));
1556 }
1557
1558 static void 
1559 gtk_toolbar_direction_changed (GtkWidget        *widget,
1560                                GtkTextDirection  previous_dir)
1561 {
1562   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1563   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1564   
1565   if (toolbar->orientation == GTK_ORIENTATION_VERTICAL)
1566     {
1567       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1568         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
1569       else 
1570         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_LEFT, GTK_SHADOW_NONE);
1571     }
1572   
1573   GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
1574 }
1575
1576 static GList *
1577 gtk_toolbar_list_children_in_focus_order (GtkToolbar       *toolbar,
1578                                           GtkDirectionType  dir)
1579 {
1580   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1581   GList *result = NULL;
1582   GList *list;
1583   gboolean rtl;
1584   
1585   /* generate list of children in reverse logical order */
1586   
1587   for (list = priv->content; list != NULL; list = list->next)
1588     {
1589       ToolbarContent *content = list->data;
1590       GtkWidget *widget;
1591       
1592       widget = toolbar_content_get_widget (content);
1593       
1594       if (widget)
1595         result = g_list_prepend (result, widget);
1596     }
1597   
1598   result = g_list_prepend (result, priv->arrow_button);
1599   
1600   rtl = (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL);
1601   
1602   /* move in logical order when
1603    *
1604    *    - dir is TAB_FORWARD
1605    *
1606    *    - in RTL mode and moving left or up
1607    *
1608    *    - in LTR mode and moving right or down
1609    */
1610   if (dir == GTK_DIR_TAB_FORWARD                                        ||
1611       (rtl  && (dir == GTK_DIR_UP   || dir == GTK_DIR_LEFT))            ||
1612       (!rtl && (dir == GTK_DIR_DOWN || dir == GTK_DIR_RIGHT)))
1613     {
1614       result = g_list_reverse (result);
1615     }
1616   
1617   return result;
1618 }
1619
1620 static gboolean
1621 gtk_toolbar_focus_home_or_end (GtkToolbar *toolbar,
1622                                gboolean    focus_home)
1623 {
1624   GList *children, *list;
1625   GtkDirectionType dir = focus_home? GTK_DIR_RIGHT : GTK_DIR_LEFT;
1626   
1627   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1628   
1629   if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_RTL)
1630     {
1631       children = g_list_reverse (children);
1632       
1633       dir = (dir == GTK_DIR_RIGHT)? GTK_DIR_LEFT : GTK_DIR_RIGHT;
1634     }
1635   
1636   for (list = children; list != NULL; list = list->next)
1637     {
1638       GtkWidget *child = list->data;
1639       
1640       if (GTK_CONTAINER (toolbar)->focus_child == child)
1641         break;
1642       
1643       if (GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir))
1644         break;
1645     }
1646   
1647   g_list_free (children);
1648   
1649   return TRUE;
1650 }   
1651
1652 /* Keybinding handler. This function is called when the user presses
1653  * Ctrl TAB or an arrow key.
1654  */
1655 static gboolean
1656 gtk_toolbar_move_focus (GtkToolbar       *toolbar,
1657                         GtkDirectionType  dir)
1658 {
1659   GList *list;
1660   gboolean try_focus = FALSE;
1661   GList *children;
1662   GtkContainer *container = GTK_CONTAINER (toolbar);
1663   
1664   if (container->focus_child &&
1665       gtk_widget_child_focus (container->focus_child, dir))
1666     {
1667       return TRUE;
1668     }
1669   
1670   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1671   
1672   for (list = children; list != NULL; list = list->next)
1673     {
1674       GtkWidget *child = list->data;
1675       
1676       if (try_focus && GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir))
1677         break;
1678       
1679       if (child == GTK_CONTAINER (toolbar)->focus_child)
1680         try_focus = TRUE;
1681     }
1682   
1683   g_list_free (children);
1684   
1685   return FALSE;
1686 }
1687
1688 /* The focus handler for the toolbar. It called when the user presses
1689  * TAB or otherwise tries to focus the toolbar.
1690  */
1691 static gboolean
1692 gtk_toolbar_focus (GtkWidget        *widget,
1693                    GtkDirectionType  dir)
1694 {
1695   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1696   GList *children, *list;
1697   
1698   /* if focus is already somewhere inside the toolbar then return FALSE.
1699    * The only way focus can stay inside the toolbar is when the user presses
1700    * arrow keys or Ctrl TAB (both of which are handled by the
1701    * gtk_toolbar_move_focus() keybinding function.
1702    */
1703   if (GTK_CONTAINER (widget)->focus_child)
1704     return FALSE;
1705   
1706   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1707   
1708   for (list = children; list != NULL; list = list->next)
1709     {
1710       GtkWidget *child = list->data;
1711       
1712       if (GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir))
1713         return TRUE;
1714     }
1715   
1716   g_list_free (children);
1717   
1718   return FALSE;
1719 }
1720
1721 static void
1722 style_change_notify (GtkToolbar *toolbar)
1723 {
1724   if (!toolbar->style_set)
1725     {
1726       /* pretend it was set, then unset, thus reverting to new default */
1727       toolbar->style_set = TRUE; 
1728       gtk_toolbar_unset_style (toolbar);
1729     }
1730 }
1731
1732 static void
1733 icon_size_change_notify (GtkToolbar *toolbar)
1734
1735   if (!toolbar->icon_size_set)
1736     {
1737       /* pretend it was set, then unset, thus reverting to new default */
1738       toolbar->icon_size_set = TRUE; 
1739       gtk_toolbar_unset_icon_size (toolbar);
1740     }
1741 }
1742
1743 static GtkSettings *
1744 toolbar_get_settings (GtkToolbar *toolbar)
1745 {
1746   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1747   return priv->settings;
1748 }
1749
1750 static void
1751 gtk_toolbar_screen_changed (GtkWidget *widget,
1752                             GdkScreen *previous_screen)
1753 {
1754   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
1755   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1756   GtkSettings *old_settings = toolbar_get_settings (toolbar);
1757   GtkSettings *settings;
1758   
1759   if (gtk_widget_has_screen (GTK_WIDGET (toolbar)))
1760     settings = gtk_widget_get_settings (GTK_WIDGET (toolbar));
1761   else
1762     settings = NULL;
1763   
1764   if (settings == old_settings)
1765     return;
1766   
1767   if (old_settings)
1768     {
1769       g_signal_handler_disconnect (old_settings, toolbar->style_set_connection);
1770       g_signal_handler_disconnect (old_settings, toolbar->icon_size_connection);
1771       
1772       g_object_unref (old_settings);
1773     }
1774   
1775   if (settings)
1776     {
1777       toolbar->style_set_connection =
1778         g_signal_connect_swapped (settings,
1779                                   "notify::gtk-toolbar-style",
1780                                   G_CALLBACK (style_change_notify),
1781                                   toolbar);
1782       toolbar->icon_size_connection =
1783         g_signal_connect_swapped (settings,
1784                                   "notify::gtk-toolbar-icon-size",
1785                                   G_CALLBACK (icon_size_change_notify),
1786                                   toolbar);
1787       
1788       g_object_ref (settings);
1789       priv->settings = settings;
1790     }
1791   else
1792     priv->settings = NULL;
1793   
1794   style_change_notify (toolbar);
1795   icon_size_change_notify (toolbar);
1796 }
1797
1798 static int
1799 find_drop_index (GtkToolbar *toolbar,
1800                  gint        x,
1801                  gint        y)
1802 {
1803   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1804   GList *interesting_content;
1805   GList *list;
1806   GtkOrientation orientation;
1807   GtkTextDirection direction;
1808   gint best_distance = G_MAXINT;
1809   gint distance;
1810   gint cursor;
1811   gint pos;
1812   ToolbarContent *best_content;
1813   GtkAllocation allocation;
1814   
1815   /* list items we care about wrt. drag and drop */
1816   interesting_content = NULL;
1817   for (list = priv->content; list != NULL; list = list->next)
1818     {
1819       ToolbarContent *content = list->data;
1820       
1821       if (toolbar_content_get_state (content) == NORMAL)
1822         interesting_content = g_list_prepend (interesting_content, content);
1823     }
1824   interesting_content = g_list_reverse (interesting_content);
1825   
1826   if (!interesting_content)
1827     return 0;
1828   
1829   orientation = toolbar->orientation;
1830   direction = gtk_widget_get_direction (GTK_WIDGET (toolbar));
1831   
1832   /* distance to first interesting item */
1833   best_content = interesting_content->data;
1834   toolbar_content_get_allocation (best_content, &allocation);
1835   
1836   if (orientation == GTK_ORIENTATION_HORIZONTAL)
1837     {
1838       cursor = x;
1839       
1840       if (direction == GTK_TEXT_DIR_LTR)
1841         pos = allocation.x;
1842       else
1843         pos = allocation.x + allocation.width;
1844     }
1845   else
1846     {
1847       cursor = y;
1848       pos = allocation.y;
1849     }
1850   
1851   best_content = NULL;
1852   best_distance = ABS (pos - cursor);
1853   
1854   /* distance to far end of each item */
1855   for (list = interesting_content; list != NULL; list = list->next)
1856     {
1857       ToolbarContent *content = list->data;
1858       
1859       toolbar_content_get_allocation (content, &allocation);
1860       
1861       if (orientation == GTK_ORIENTATION_HORIZONTAL)
1862         {
1863           if (direction == GTK_TEXT_DIR_LTR)
1864             pos = allocation.x + allocation.width;
1865           else
1866             pos = allocation.x;
1867         }
1868       else
1869         {
1870           pos = allocation.y + allocation.height;
1871         }
1872       
1873       distance = ABS (pos - cursor);
1874       
1875       if (distance < best_distance)
1876         {
1877           best_distance = distance;
1878           best_content = content;
1879         }
1880     }
1881   
1882   g_list_free (interesting_content);
1883   
1884   if (!best_content)
1885     return 0;
1886   else
1887     return g_list_index (priv->content, best_content) + 1;
1888 }
1889
1890 static void
1891 reset_all_placeholders (GtkToolbar *toolbar)
1892 {
1893   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1894   GList *list;
1895   
1896   for (list = priv->content; list != NULL; list = list->next)
1897     {
1898       ToolbarContent *content = list->data;
1899       if (toolbar_content_is_placeholder (content))
1900         toolbar_content_set_disappearing (content, TRUE);
1901     }
1902 }
1903
1904 static gint
1905 physical_to_logical (GtkToolbar *toolbar,
1906                      gint        physical)
1907 {
1908   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1909   GList *list;
1910   int logical;
1911   
1912   g_assert (physical >= 0);
1913   
1914   logical = 0;
1915   for (list = priv->content; list && physical > 0; list = list->next)
1916     {
1917       ToolbarContent *content = list->data;
1918       
1919       if (!toolbar_content_is_placeholder (content))
1920         logical++;
1921       physical--;
1922     }
1923   
1924   g_assert (physical == 0);
1925   
1926   return logical;
1927 }
1928
1929 static gint
1930 logical_to_physical (GtkToolbar *toolbar,
1931                      gint        logical)
1932 {
1933   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1934   GList *list;
1935   gint physical;
1936   
1937   g_assert (logical >= 0);
1938   
1939   physical = 0;
1940   for (list = priv->content; list; list = list->next)
1941     {
1942       ToolbarContent *content = list->data;
1943       
1944       if (!toolbar_content_is_placeholder (content))
1945         {
1946           if (logical == 0)
1947             break;
1948           logical--;
1949         }
1950       
1951       physical++;
1952     }
1953   
1954   g_assert (logical == 0);
1955   
1956   return physical;
1957 }
1958
1959 /**
1960  * gtk_toolbar_set_drop_highlight_item:
1961  * @toolbar: a #GtkToolbar
1962  * @item: a #GtkToolItem, or %NULL to turn of highlighting
1963  * @index: a position on @toolbar
1964  * 
1965  * Highlights @toolbar to give an idea of what it would look like
1966  * if @item was added to @toolbar at position indicated by @index. If @item
1967  * is %NULL, highlighting is turned off. In that case @index is ignored.
1968  *
1969  * The @tool_item passed to this function must not be part of any widget
1970  * hierarchy. When an item is set as drop highlight item it can not
1971  * added to any widget hierarchy or used as highlight item for another
1972  * toolbar.
1973  * 
1974  * Since: 2.4
1975  **/
1976 void
1977 gtk_toolbar_set_drop_highlight_item (GtkToolbar  *toolbar,
1978                                      GtkToolItem *tool_item,
1979                                      gint         index)
1980 {
1981   ToolbarContent *content;
1982   GtkToolbarPrivate *priv;
1983   gint n_items;
1984   GtkRequisition requisition;
1985   
1986   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
1987   g_return_if_fail (tool_item == NULL || GTK_IS_TOOL_ITEM (tool_item));
1988   
1989   gtk_toolbar_check_new_api (toolbar);
1990   
1991   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1992   
1993   if (!tool_item)
1994     {
1995       if (priv->highlight_tool_item)
1996         {
1997           gtk_widget_unparent (GTK_WIDGET (priv->highlight_tool_item));
1998           g_object_unref (priv->highlight_tool_item);
1999           priv->highlight_tool_item = NULL;
2000         }
2001       
2002       reset_all_placeholders (toolbar);
2003       gtk_toolbar_begin_sliding (toolbar);
2004       return;
2005     }
2006   
2007   if (tool_item != priv->highlight_tool_item)
2008     {
2009       if (priv->highlight_tool_item)
2010         g_object_unref (priv->highlight_tool_item);
2011       
2012       g_object_ref (tool_item);
2013       gtk_object_sink (GTK_OBJECT (tool_item));
2014       
2015       priv->highlight_tool_item = tool_item;
2016       
2017       gtk_widget_set_parent (GTK_WIDGET (priv->highlight_tool_item),
2018                              GTK_WIDGET (toolbar));
2019     }
2020   
2021   n_items = gtk_toolbar_get_n_items (toolbar);
2022   if (index < 0 || index > n_items)
2023     index = n_items;
2024   
2025   index = logical_to_physical (toolbar, index);
2026   
2027   content = g_list_nth_data (priv->content, index);
2028   
2029   if (index > 0)
2030     {
2031       ToolbarContent *prev_content;
2032       
2033       prev_content = g_list_nth_data (priv->content, index - 1);
2034       
2035       if (prev_content && toolbar_content_is_placeholder (prev_content))
2036         content = prev_content;
2037     }
2038   
2039   if (!content || !toolbar_content_is_placeholder (content))
2040     {
2041       GtkWidget *placeholder;
2042       
2043       placeholder = GTK_WIDGET (gtk_separator_tool_item_new ());
2044
2045       content = toolbar_content_new_tool_item (toolbar,
2046                                                GTK_TOOL_ITEM (placeholder),
2047                                                TRUE, index);
2048       gtk_widget_show (placeholder);
2049     }
2050   
2051   g_assert (content);
2052   g_assert (toolbar_content_is_placeholder (content));
2053   
2054   reset_all_placeholders (toolbar);
2055   
2056   toolbar_content_set_disappearing (content, FALSE);
2057   
2058   gtk_widget_size_request (GTK_WIDGET (priv->highlight_tool_item),
2059                            &requisition);
2060   
2061   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2062     requisition.height = -1;
2063   else
2064     requisition.width = -1;
2065   
2066   toolbar_content_set_size_request (content,
2067                                     requisition.width, requisition.height);
2068   
2069   gtk_toolbar_begin_sliding (toolbar);
2070 }
2071
2072 static void
2073 gtk_toolbar_get_child_property (GtkContainer *container,
2074                                 GtkWidget    *child,
2075                                 guint         property_id,
2076                                 GValue       *value,
2077                                 GParamSpec   *pspec)
2078 {
2079   GtkToolItem *item = GTK_TOOL_ITEM (child);
2080   
2081   switch (property_id)
2082     {
2083     case CHILD_PROP_HOMOGENEOUS:
2084       g_value_set_boolean (value, gtk_tool_item_get_homogeneous (item));
2085       break;
2086       
2087     case CHILD_PROP_EXPAND:
2088       g_value_set_boolean (value, gtk_tool_item_get_expand (item));
2089       break;
2090       
2091     default:
2092       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2093       break;
2094     }
2095 }
2096
2097 static void
2098 gtk_toolbar_set_child_property (GtkContainer *container,
2099                                 GtkWidget    *child,
2100                                 guint         property_id,
2101                                 const GValue *value,
2102                                 GParamSpec   *pspec)
2103 {
2104   switch (property_id)
2105     {
2106     case CHILD_PROP_HOMOGENEOUS:
2107       gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2108       break;
2109       
2110     case CHILD_PROP_EXPAND:
2111       gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2112       break;
2113       
2114     default:
2115       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2116       break;
2117     }
2118 }
2119
2120 static void
2121 gtk_toolbar_show_all (GtkWidget *widget)
2122 {
2123   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
2124   GList *list;
2125
2126   for (list = priv->content; list != NULL; list = list->next)
2127     {
2128       ToolbarContent *content = list->data;
2129       
2130       toolbar_content_show_all (content);
2131     }
2132   
2133   gtk_widget_show (widget);
2134 }
2135
2136 static void
2137 gtk_toolbar_hide_all (GtkWidget *widget)
2138 {
2139   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
2140   GList *list;
2141
2142   for (list = priv->content; list != NULL; list = list->next)
2143     {
2144       ToolbarContent *content = list->data;
2145       
2146       toolbar_content_hide_all (content);
2147     }
2148
2149   gtk_widget_hide (widget);
2150 }
2151
2152 static void
2153 gtk_toolbar_add (GtkContainer *container,
2154                  GtkWidget    *widget)
2155 {
2156   GtkToolbar *toolbar;
2157   
2158   g_return_if_fail (GTK_IS_TOOLBAR (container));
2159   g_return_if_fail (widget != NULL);
2160   
2161   toolbar = GTK_TOOLBAR (container);
2162   
2163   if (GTK_IS_TOOL_ITEM (widget))
2164     gtk_toolbar_insert (toolbar, GTK_TOOL_ITEM (widget), -1);
2165   else
2166     gtk_toolbar_append_widget (toolbar, widget, NULL, NULL);
2167 }
2168
2169 static void
2170 gtk_toolbar_remove (GtkContainer *container,
2171                     GtkWidget    *widget)
2172 {
2173   GtkToolbar *toolbar;
2174   GtkToolbarPrivate *priv;
2175   ToolbarContent *content_to_remove;
2176   GList *list;
2177   
2178   g_return_if_fail (GTK_IS_TOOLBAR (container));
2179   g_return_if_fail (GTK_IS_WIDGET (widget));
2180   
2181   toolbar = GTK_TOOLBAR (container);
2182   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2183   
2184   content_to_remove = NULL;
2185   for (list = priv->content; list != NULL; list = list->next)
2186     {
2187       ToolbarContent *content = list->data;
2188       GtkWidget *child;
2189       
2190       child = toolbar_content_get_widget (content);
2191       if (child && child == widget)
2192         {
2193           content_to_remove = content;
2194           break;
2195         }
2196     }
2197   
2198   g_return_if_fail (content_to_remove != NULL);
2199   
2200   toolbar_content_remove (content_to_remove, toolbar);
2201   toolbar_content_free (content_to_remove);
2202 }
2203
2204 static void
2205 gtk_toolbar_forall (GtkContainer *container,
2206                     gboolean      include_internals,
2207                     GtkCallback   callback,
2208                     gpointer      callback_data)
2209 {
2210   GtkToolbar *toolbar = GTK_TOOLBAR (container);
2211   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2212   GList *list;
2213   
2214   g_return_if_fail (callback != NULL);
2215   
2216   list = priv->content;
2217   while (list)
2218     {
2219       ToolbarContent *content = list->data;
2220       GList *next = list->next;
2221       
2222       if (include_internals || !toolbar_content_is_placeholder (content))
2223         {
2224           GtkWidget *child = toolbar_content_get_widget (content);
2225           
2226           if (child)
2227             (*callback) (child, callback_data);
2228         }
2229       
2230       list = next;
2231     }
2232   
2233   if (include_internals)
2234     (* callback) (priv->arrow_button, callback_data);
2235 }
2236
2237 static GType
2238 gtk_toolbar_child_type (GtkContainer *container)
2239 {
2240   return GTK_TYPE_TOOL_ITEM;
2241 }
2242
2243 static void
2244 gtk_toolbar_reconfigured (GtkToolbar *toolbar)
2245 {
2246   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2247   GList *list;
2248   
2249   list = priv->content;
2250   while (list)
2251     {
2252       ToolbarContent *content = list->data;
2253       GList *next = list->next;
2254       
2255       toolbar_content_toolbar_reconfigured (content, toolbar);
2256       
2257       list = next;
2258     }
2259 }
2260
2261 static void
2262 gtk_toolbar_orientation_changed (GtkToolbar    *toolbar,
2263                                  GtkOrientation orientation)
2264 {
2265   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2266   if (toolbar->orientation != orientation)
2267     {
2268       toolbar->orientation = orientation;
2269       
2270       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2271         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
2272       else if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR)
2273         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
2274       else 
2275         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_LEFT, GTK_SHADOW_NONE);
2276       
2277       gtk_toolbar_reconfigured (toolbar);
2278       
2279       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2280       g_object_notify (G_OBJECT (toolbar), "orientation");
2281     }
2282 }
2283
2284 static void
2285 gtk_toolbar_real_style_changed (GtkToolbar     *toolbar,
2286                                 GtkToolbarStyle style)
2287 {
2288   if (toolbar->style != style)
2289     {
2290       toolbar->style = style;
2291       
2292       gtk_toolbar_reconfigured (toolbar);
2293       
2294       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2295       g_object_notify (G_OBJECT (toolbar), "toolbar_style");
2296     }
2297 }
2298
2299 static void
2300 menu_position_func (GtkMenu  *menu,
2301                     gint     *x,
2302                     gint     *y,
2303                     gboolean *push_in,
2304                     gpointer  user_data)
2305 {
2306   GtkToolbar *toolbar = GTK_TOOLBAR (user_data);
2307   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2308   GtkRequisition req;
2309   GtkRequisition menu_req;
2310   
2311   gdk_window_get_origin (GTK_BUTTON (priv->arrow_button)->event_window, x, y);
2312   gtk_widget_size_request (priv->arrow_button, &req);
2313   gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
2314   
2315   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2316     {
2317       *y += priv->arrow_button->allocation.height;
2318       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2319         *x += priv->arrow_button->allocation.width - req.width;
2320       else 
2321         *x += req.width - menu_req.width;
2322     }
2323   else 
2324     {
2325       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2326         *x += priv->arrow_button->allocation.width;
2327       else 
2328         *x -= menu_req.width;
2329       *y += priv->arrow_button->allocation.height - req.height;      
2330     }
2331   
2332   *push_in = TRUE;
2333 }
2334
2335 static void
2336 menu_deactivated (GtkWidget  *menu,
2337                   GtkToolbar *toolbar)
2338 {
2339   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2340   
2341   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->arrow_button), FALSE);
2342 }
2343
2344 static void
2345 remove_item (GtkWidget *menu_item,
2346              gpointer   data)
2347 {
2348   gtk_container_remove (GTK_CONTAINER (menu_item->parent), menu_item);
2349 }
2350
2351 static void
2352 show_menu (GtkToolbar     *toolbar,
2353            GdkEventButton *event)
2354 {
2355   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2356   GList *list;
2357   
2358   if (priv->menu)
2359     {
2360       gtk_container_foreach (GTK_CONTAINER (priv->menu), remove_item, NULL);
2361       gtk_widget_destroy (GTK_WIDGET (priv->menu));
2362     }
2363   
2364   priv->menu = GTK_MENU (gtk_menu_new ());
2365   g_signal_connect (priv->menu, "deactivate", G_CALLBACK (menu_deactivated), toolbar);
2366   
2367   for (list = priv->content; list != NULL; list = list->next)
2368     {
2369       ToolbarContent *content = list->data;
2370       
2371       if (toolbar_content_get_state (content) == OVERFLOWN)
2372         {
2373           GtkWidget *menu_item = toolbar_content_retrieve_menu_item (content);
2374           
2375           if (menu_item)
2376             {
2377               g_assert (GTK_IS_MENU_ITEM (menu_item));
2378               gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menu_item);
2379             }
2380         }
2381     }
2382   
2383   gtk_widget_show_all (GTK_WIDGET (priv->menu));
2384   
2385   gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
2386                   menu_position_func, toolbar,
2387                   event? event->button : 0, event? event->time : gtk_get_current_event_time());
2388 }
2389
2390 static void
2391 gtk_toolbar_arrow_button_clicked (GtkWidget  *button,
2392                                   GtkToolbar *toolbar)
2393 {
2394   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);  
2395   
2396   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->arrow_button)) &&
2397       (!priv->menu || !GTK_WIDGET_VISIBLE (GTK_WIDGET (priv->menu))))
2398     {
2399       /* We only get here when the button is clicked with the keybaord,
2400        * because mouse button presses result in the menu being shown so
2401        * that priv->menu would be non-NULL and visible.
2402        */
2403       show_menu (toolbar, NULL);
2404       gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2405     }
2406 }
2407
2408 static gboolean
2409 gtk_toolbar_arrow_button_press (GtkWidget      *button,
2410                                 GdkEventButton *event,
2411                                 GtkToolbar     *toolbar)
2412 {
2413   show_menu (toolbar, event);
2414   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2415   
2416   return TRUE;
2417 }
2418
2419 static gboolean
2420 gtk_toolbar_button_press (GtkWidget      *toolbar,
2421                           GdkEventButton *event)
2422 {
2423   if (event->button == 3)
2424     {
2425       gboolean return_value;
2426       
2427       g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2428                      (int)event->x_root, (int)event->y_root, event->button,
2429                      &return_value);
2430       
2431       return return_value;
2432     }
2433   
2434   return FALSE;
2435 }
2436
2437 static gboolean
2438 gtk_toolbar_popup_menu (GtkWidget *toolbar)
2439 {
2440   gboolean return_value;
2441   /* This function is the handler for the "popup menu" keybinding,
2442    * ie., it is called when the user presses Shift F10
2443    */
2444   g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2445                  -1, -1, -1, &return_value);
2446   
2447   return return_value;
2448 }
2449
2450 /**
2451  * gtk_toolbar_new:
2452  * 
2453  * Creates a new toolbar. 
2454  
2455  * Return Value: the newly-created toolbar.
2456  **/
2457 GtkWidget *
2458 gtk_toolbar_new (void)
2459 {
2460   GtkToolbar *toolbar;
2461   
2462   toolbar = g_object_new (GTK_TYPE_TOOLBAR, NULL);
2463   
2464   return GTK_WIDGET (toolbar);
2465 }
2466
2467 /**
2468  * gtk_toolbar_insert:
2469  * @toolbar: a #GtkToolbar
2470  * @item: a #GtkToolItem
2471  * @pos: the position of the new item
2472  *
2473  * Insert a #GtkToolItem into the toolbar at position @pos. If @pos is
2474  * 0 the item is prepended to the start of the toolbar. If @pos is
2475  * negative, the item is appended to the end of the toolbar.
2476  *
2477  * Since: 2.4
2478  **/
2479 void
2480 gtk_toolbar_insert (GtkToolbar  *toolbar,
2481                     GtkToolItem *item,
2482                     gint         pos)
2483 {
2484   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2485   g_return_if_fail (GTK_IS_TOOL_ITEM (item));
2486   
2487   if (!gtk_toolbar_check_new_api (toolbar))
2488     return;
2489   
2490   if (pos >= 0)
2491     pos = logical_to_physical (toolbar, pos);
2492
2493   toolbar_content_new_tool_item (toolbar, item, FALSE, pos);
2494 }
2495
2496 /**
2497  * gtk_toolbar_get_item_index:
2498  * @toolbar: a #GtkToolbar
2499  * @item: a #GtkToolItem that is a child of @toolbar
2500  * 
2501  * Returns the position of @item on the toolbar, starting from 0.
2502  * It is an error if @item is not a child of the toolbar.
2503  * 
2504  * Return value: the position of item on the toolbar.
2505  * 
2506  * Since: 2.4
2507  **/
2508 gint
2509 gtk_toolbar_get_item_index (GtkToolbar  *toolbar,
2510                             GtkToolItem *item)
2511 {
2512   GtkToolbarPrivate *priv;
2513   GList *list;
2514   int n;
2515   
2516   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2517   g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1);
2518   g_return_val_if_fail (GTK_WIDGET (item)->parent == GTK_WIDGET (toolbar), -1);
2519   
2520   if (!gtk_toolbar_check_new_api (toolbar))
2521     return -1;
2522   
2523   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2524   
2525   n = 0;
2526   for (list = priv->content; list != NULL; list = list->next)
2527     {
2528       ToolbarContent *content = list->data;
2529       GtkWidget *widget;
2530       
2531       widget = toolbar_content_get_widget (content);
2532       
2533       if (item == GTK_TOOL_ITEM (widget))
2534         break;
2535       
2536       ++n;
2537     }
2538   
2539   return physical_to_logical (toolbar, n);
2540 }
2541
2542 /**
2543  * gtk_toolbar_set_orientation:
2544  * @toolbar: a #GtkToolbar.
2545  * @orientation: a new #GtkOrientation.
2546  * 
2547  * Sets whether a toolbar should appear horizontally or vertically.
2548  **/
2549 void
2550 gtk_toolbar_set_orientation (GtkToolbar     *toolbar,
2551                              GtkOrientation  orientation)
2552 {
2553   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2554   
2555   g_signal_emit (toolbar, toolbar_signals[ORIENTATION_CHANGED], 0, orientation);
2556 }
2557
2558 /**
2559  * gtk_toolbar_get_orientation:
2560  * @toolbar: a #GtkToolbar
2561  * 
2562  * Retrieves the current orientation of the toolbar. See
2563  * gtk_toolbar_set_orientation().
2564  *
2565  * Return value: the orientation
2566  **/
2567 GtkOrientation
2568 gtk_toolbar_get_orientation (GtkToolbar *toolbar)
2569 {
2570   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL);
2571   
2572   return toolbar->orientation;
2573 }
2574
2575 /**
2576  * gtk_toolbar_set_style:
2577  * @toolbar: a #GtkToolbar.
2578  * @style: the new style for @toolbar.
2579  * 
2580  * Alters the view of @toolbar to display either icons only, text only, or both.
2581  **/
2582 void
2583 gtk_toolbar_set_style (GtkToolbar      *toolbar,
2584                        GtkToolbarStyle  style)
2585 {
2586   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2587   
2588   toolbar->style_set = TRUE;  
2589   g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2590 }
2591
2592 /**
2593  * gtk_toolbar_get_style:
2594  * @toolbar: a #GtkToolbar
2595  *
2596  * Retrieves whether the toolbar has text, icons, or both . See
2597  * gtk_toolbar_set_style().
2598  
2599  * Return value: the current style of @toolbar
2600  **/
2601 GtkToolbarStyle
2602 gtk_toolbar_get_style (GtkToolbar *toolbar)
2603 {
2604   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE);
2605   
2606   return toolbar->style;
2607 }
2608
2609 /**
2610  * gtk_toolbar_unset_style:
2611  * @toolbar: a #GtkToolbar
2612  * 
2613  * Unsets a toolbar style set with gtk_toolbar_set_style(), so that
2614  * user preferences will be used to determine the toolbar style.
2615  **/
2616 void
2617 gtk_toolbar_unset_style (GtkToolbar *toolbar)
2618 {
2619   GtkToolbarStyle style;
2620   
2621   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2622   
2623   if (toolbar->style_set)
2624     {
2625       GtkSettings *settings = toolbar_get_settings (toolbar);
2626       
2627       if (settings)
2628         g_object_get (settings,
2629                       "gtk-toolbar-style", &style,
2630                       NULL);
2631       else
2632         style = DEFAULT_TOOLBAR_STYLE;
2633       
2634       if (style != toolbar->style)
2635         g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2636       
2637       toolbar->style_set = FALSE;
2638     }
2639 }
2640
2641 /**
2642  * gtk_toolbar_set_tooltips:
2643  * @toolbar: a #GtkToolbar.
2644  * @enable: set to %FALSE to disable the tooltips, or %TRUE to enable them.
2645  * 
2646  * Sets if the tooltips of a toolbar should be active or not.
2647  **/
2648 void
2649 gtk_toolbar_set_tooltips (GtkToolbar *toolbar,
2650                           gboolean    enable)
2651 {
2652   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2653   
2654   if (enable)
2655     gtk_tooltips_enable (toolbar->tooltips);
2656   else
2657     gtk_tooltips_disable (toolbar->tooltips);
2658 }
2659
2660 /**
2661  * gtk_toolbar_get_tooltips:
2662  * @toolbar: a #GtkToolbar
2663  *
2664  * Retrieves whether tooltips are enabled. See
2665  * gtk_toolbar_set_tooltips().
2666  *
2667  * Return value: %TRUE if tooltips are enabled
2668  **/
2669 gboolean
2670 gtk_toolbar_get_tooltips (GtkToolbar *toolbar)
2671 {
2672   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2673   
2674   return toolbar->tooltips->enabled;
2675 }
2676
2677 /**
2678  * gtk_toolbar_get_n_items:
2679  * @toolbar: a #GtkToolbar
2680  * 
2681  * Returns the number of items on the toolbar.
2682  * 
2683  * Return value: the number of items on the toolbar
2684  * 
2685  * Since: 2.4
2686  **/
2687 gint
2688 gtk_toolbar_get_n_items (GtkToolbar *toolbar)
2689 {
2690   GtkToolbarPrivate *priv;
2691   
2692   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2693   
2694   if (!gtk_toolbar_check_new_api (toolbar))
2695     return -1;
2696   
2697   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2698   
2699   return physical_to_logical (toolbar, g_list_length (priv->content));
2700 }
2701
2702 /**
2703  * gtk_toolbar_get_nth_item:
2704  * @toolbar: a #GtkToolbar
2705  * @n: A position on the toolbar
2706  *
2707  * Returns the @n<!-- -->'s item on @toolbar, or %NULL if the
2708  * toolbar does not contain an @n<!-- -->'th item.
2709  * 
2710  * Return value: The @n<!-- -->'th #GtkToolItem on @toolbar, or %NULL if there
2711  * isn't an @n<!-- -->th item.
2712  * 
2713  * Since: 2.4
2714  **/
2715 GtkToolItem *
2716 gtk_toolbar_get_nth_item (GtkToolbar *toolbar,
2717                           gint        n)
2718 {
2719   GtkToolbarPrivate *priv;
2720   ToolbarContent *content;
2721   gint n_items;
2722   
2723   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
2724   
2725   if (!gtk_toolbar_check_new_api (toolbar))
2726     return NULL;
2727   
2728   n_items = gtk_toolbar_get_n_items (toolbar);
2729   
2730   if (n < 0 || n >= n_items)
2731     return NULL;
2732   
2733   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2734   
2735   content = g_list_nth_data (priv->content, logical_to_physical (toolbar, n));
2736   
2737   g_assert (content);
2738   g_assert (!toolbar_content_is_placeholder (content));
2739   
2740   return GTK_TOOL_ITEM (toolbar_content_get_widget (content));
2741 }
2742
2743 /**
2744  * gtk_toolbar_get_icon_size:
2745  * @toolbar: a #GtkToolbar
2746  *
2747  * Retrieves the icon size fo the toolbar. See gtk_toolbar_set_icon_size().
2748  *
2749  * Return value: the current icon size for the icons on the toolbar.
2750  **/
2751 GtkIconSize
2752 gtk_toolbar_get_icon_size (GtkToolbar *toolbar)
2753 {
2754   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_ICON_SIZE);
2755   
2756   return toolbar->icon_size;
2757 }
2758
2759 /**
2760  * gtk_toolbar_get_relief_style:
2761  * @toolbar: a #GtkToolbar
2762  * 
2763  * Returns the relief style of buttons on @toolbar. See
2764  * gtk_button_set_relief_style().
2765  * 
2766  * Return value: The relief style of buttons on @toolbar.
2767  * 
2768  * Since: 2.4
2769  **/
2770 GtkReliefStyle
2771 gtk_toolbar_get_relief_style (GtkToolbar *toolbar)
2772 {
2773   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_RELIEF_NONE);
2774   
2775   return get_button_relief (toolbar);
2776 }
2777
2778 /**
2779  * gtk_toolbar_set_show_arrow:
2780  * @toolbar: a #GtkToolbar
2781  * @show_arrow: Whether to show an overflow menu
2782  * 
2783  * Sets whether to show an overflow menu when
2784  * @toolbar doesn't have room for all items on it. If %TRUE,
2785  * items that there are not room are available through an
2786  * overflow menu.
2787  * 
2788  * Since: 2.4
2789  **/
2790 void
2791 gtk_toolbar_set_show_arrow (GtkToolbar *toolbar,
2792                             gboolean    show_arrow)
2793 {
2794   GtkToolbarPrivate *priv;
2795   
2796   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2797   
2798   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2799   show_arrow = show_arrow != FALSE;
2800   
2801   if (priv->show_arrow != show_arrow)
2802     {
2803       priv->show_arrow = show_arrow;
2804       
2805       if (!priv->show_arrow)
2806         gtk_widget_hide (priv->arrow_button);
2807       
2808       gtk_widget_queue_resize (GTK_WIDGET (toolbar));      
2809       g_object_notify (G_OBJECT (toolbar), "show_arrow");
2810     }
2811 }
2812
2813 /**
2814  * gtk_toolbar_get_show_arrow:
2815  * @toolbar: a #GtkToolbar
2816  * 
2817  * Returns whether the toolbar has an overflow menu.
2818  * See gtk_toolbar_set_show_arrow()
2819  * 
2820  * Return value: 
2821  * 
2822  * Since: 2.4
2823  **/
2824 gboolean
2825 gtk_toolbar_get_show_arrow (GtkToolbar *toolbar)
2826 {
2827   GtkToolbarPrivate *priv;
2828   
2829   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2830   
2831   if (!gtk_toolbar_check_new_api (toolbar))
2832     return FALSE;
2833   
2834   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2835   
2836   return priv->show_arrow;
2837 }
2838
2839 /**
2840  * gtk_toolbar_get_drop_index:
2841  * @toolbar: a #GtkToolbar
2842  * @x: x coordinate of a point on the toolbar
2843  * @y: y coordinate of a point on the toolbar
2844  *
2845  * Returns the position corresponding to the indicated point on
2846  * @toolbar. This is useful when dragging items to the toolbar:
2847  * this function returns the position a new item should be
2848  * inserted.
2849  *
2850  * @x and @y are in @toolbar coordinates.
2851  * 
2852  * Return value: The position corresponding to the point (@x, @y) on the toolbar.
2853  * 
2854  * Since: 2.4
2855  **/
2856 gint
2857 gtk_toolbar_get_drop_index (GtkToolbar *toolbar,
2858                             gint        x,
2859                             gint        y)
2860 {
2861   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2862   
2863   if (!gtk_toolbar_check_new_api (toolbar))
2864     return -1;
2865   
2866   return physical_to_logical (toolbar, find_drop_index (toolbar, x, y));
2867 }
2868
2869 static void
2870 gtk_toolbar_finalize (GObject *object)
2871 {
2872   GList *list;
2873   GtkToolbar *toolbar = GTK_TOOLBAR (object);
2874   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2875   
2876   if (toolbar->tooltips)
2877     g_object_unref (toolbar->tooltips);
2878   
2879   for (list = priv->content; list != NULL; list = list->next)
2880     {
2881       ToolbarContent *content = list->data;
2882
2883       toolbar_content_free (content);
2884     }
2885   
2886   g_list_free (priv->content);
2887   g_list_free (toolbar->children);
2888   
2889   g_timer_destroy (priv->timer);
2890   
2891   if (priv->menu)
2892     gtk_widget_destroy (GTK_WIDGET (priv->menu));
2893   
2894   if (priv->idle_id)
2895     g_source_remove (priv->idle_id);
2896   
2897   G_OBJECT_CLASS (parent_class)->finalize (object);
2898 }
2899
2900 gchar *
2901 _gtk_toolbar_elide_underscores (const gchar *original)
2902 {
2903   gchar *q, *result;
2904   const gchar *p;
2905   gboolean last_underscore;
2906   
2907   q = result = g_malloc (strlen (original) + 1);
2908   last_underscore = FALSE;
2909   
2910   for (p = original; *p; p++)
2911     {
2912       if (!last_underscore && *p == '_')
2913         last_underscore = TRUE;
2914       else
2915         {
2916           last_underscore = FALSE;
2917           *q++ = *p;
2918         }
2919     }
2920   
2921   *q = '\0';
2922   
2923   return result;
2924 }
2925
2926 /*
2927  * Deprecated API
2928  */
2929
2930 /**
2931  * gtk_toolbar_set_icon_size:
2932  * @toolbar: A #GtkToolbar
2933  * @icon_size: The #GtkIconSize that stock icons in the toolbar shall have.
2934  *
2935  * This function sets the size of stock icons in the toolbar. You
2936  * can call it both before you add the icons and after they've been
2937  * added. The size you set will override user preferences for the default
2938  * icon size.
2939  **/
2940 void
2941 gtk_toolbar_set_icon_size (GtkToolbar  *toolbar,
2942                            GtkIconSize  icon_size)
2943 {
2944   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2945   
2946   toolbar->icon_size_set = TRUE;
2947   
2948   if (toolbar->icon_size == icon_size)
2949     return;
2950   
2951   toolbar->icon_size = icon_size;
2952   
2953   gtk_toolbar_reconfigured (toolbar);
2954   
2955   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2956 }
2957
2958 /**
2959  * gtk_toolbar_unset_icon_size:
2960  * @toolbar: a #GtkToolbar
2961  * 
2962  * Unsets toolbar icon size set with gtk_toolbar_set_icon_size(), so that
2963  * user preferences will be used to determine the icon size.
2964  **/
2965 void
2966 gtk_toolbar_unset_icon_size (GtkToolbar *toolbar)
2967 {
2968   GtkIconSize size;
2969   
2970   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2971   
2972   if (toolbar->icon_size_set)
2973     {
2974       GtkSettings *settings = toolbar_get_settings (toolbar);
2975       
2976       if (settings)
2977         {
2978           g_object_get (settings,
2979                         "gtk-toolbar-icon-size", &size,
2980                         NULL);
2981         }
2982       else
2983         size = DEFAULT_ICON_SIZE;
2984       
2985       if (size != toolbar->icon_size)
2986         gtk_toolbar_set_icon_size (toolbar, size);
2987       
2988       toolbar->icon_size_set = FALSE;
2989     }
2990 }
2991
2992 /**
2993  * gtk_toolbar_append_item:
2994  * @toolbar: a #GtkToolbar.
2995  * @text: give your toolbar button a label.
2996  * @tooltip_text: a string that appears when the user holds the mouse over this item.
2997  * @tooltip_private_text: use with #GtkTipsQuery.
2998  * @icon: a #GtkWidget that should be used as the button's icon.
2999  * @callback: the function to be executed when the button is pressed.
3000  * @user_data: a pointer to any data you wish to be passed to the callback.
3001  * 
3002  * Inserts a new item into the toolbar. You must specify the position
3003  * in the toolbar where it will be inserted.
3004  *
3005  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3006  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3007  *
3008  * Return value: the new toolbar item as a #GtkWidget.
3009  **/
3010 GtkWidget *
3011 gtk_toolbar_append_item (GtkToolbar    *toolbar,
3012                          const char    *text,
3013                          const char    *tooltip_text,
3014                          const char    *tooltip_private_text,
3015                          GtkWidget     *icon,
3016                          GtkSignalFunc  callback,
3017                          gpointer       user_data)
3018 {
3019   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3020                                      NULL, text,
3021                                      tooltip_text, tooltip_private_text,
3022                                      icon, callback, user_data,
3023                                      toolbar->num_children);
3024 }
3025
3026 /**
3027  * gtk_toolbar_prepend_item:
3028  * @toolbar: a #GtkToolbar.
3029  * @text: give your toolbar button a label.
3030  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3031  * @tooltip_private_text: use with #GtkTipsQuery.
3032  * @icon: a #GtkWidget that should be used as the button's icon.
3033  * @callback: the function to be executed when the button is pressed.
3034  * @user_data: a pointer to any data you wish to be passed to the callback.
3035  * 
3036  * Adds a new button to the beginning (top or left edges) of the given toolbar.
3037  *
3038  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3039  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3040  *
3041  * Return value: the new toolbar item as a #GtkWidget.
3042  **/
3043 GtkWidget *
3044 gtk_toolbar_prepend_item (GtkToolbar    *toolbar,
3045                           const char    *text,
3046                           const char    *tooltip_text,
3047                           const char    *tooltip_private_text,
3048                           GtkWidget     *icon,
3049                           GtkSignalFunc  callback,
3050                           gpointer       user_data)
3051 {
3052   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3053                                      NULL, text,
3054                                      tooltip_text, tooltip_private_text,
3055                                      icon, callback, user_data,
3056                                      0);
3057 }
3058
3059 /**
3060  * gtk_toolbar_insert_item:
3061  * @toolbar: a #GtkToolbar.
3062  * @text: give your toolbar button a label.
3063  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3064  * @tooltip_private_text: use with #GtkTipsQuery.
3065  * @icon: a #GtkWidget that should be used as the button's icon.
3066  * @callback: the function to be executed when the button is pressed.
3067  * @user_data: a pointer to any data you wish to be passed to the callback.
3068  * @position: the number of widgets to insert this item after.
3069  * 
3070  * Inserts a new item into the toolbar. You must specify the position in the
3071  * toolbar where it will be inserted.
3072  *
3073  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3074  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3075  *
3076  * Return value: the new toolbar item as a #GtkWidget.
3077  **/
3078 GtkWidget *
3079 gtk_toolbar_insert_item (GtkToolbar    *toolbar,
3080                          const char    *text,
3081                          const char    *tooltip_text,
3082                          const char    *tooltip_private_text,
3083                          GtkWidget     *icon,
3084                          GtkSignalFunc  callback,
3085                          gpointer       user_data,
3086                          gint           position)
3087 {
3088   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3089                                      NULL, text,
3090                                      tooltip_text, tooltip_private_text,
3091                                      icon, callback, user_data,
3092                                      position);
3093 }
3094
3095 /**
3096  * gtk_toolbar_insert_stock:
3097  * @toolbar: A #GtkToolbar
3098  * @stock_id: The id of the stock item you want to insert
3099  * @tooltip_text: The text in the tooltip of the toolbar button
3100  * @tooltip_private_text: The private text of the tooltip
3101  * @callback: The callback called when the toolbar button is clicked.
3102  * @user_data: user data passed to callback
3103  * @position: The position the button shall be inserted at.
3104  *            -1 means at the end.
3105  *
3106  * Inserts a stock item at the specified position of the toolbar.  If
3107  * @stock_id is not a known stock item ID, it's inserted verbatim,
3108  * except that underscores used to mark mnemonics are removed.
3109  *
3110  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3111  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3112  *
3113  * Returns: the inserted widget
3114  */
3115 GtkWidget*
3116 gtk_toolbar_insert_stock (GtkToolbar      *toolbar,
3117                           const gchar     *stock_id,
3118                           const char      *tooltip_text,
3119                           const char      *tooltip_private_text,
3120                           GtkSignalFunc    callback,
3121                           gpointer         user_data,
3122                           gint             position)
3123 {
3124   return internal_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3125                                   NULL, stock_id,
3126                                   tooltip_text, tooltip_private_text,
3127                                   NULL, callback, user_data,
3128                                   position, TRUE);
3129 }
3130
3131 /**
3132  * gtk_toolbar_append_space:
3133  * @toolbar: a #GtkToolbar.
3134  * 
3135  * Adds a new space to the end of the toolbar.
3136  **/
3137 void
3138 gtk_toolbar_append_space (GtkToolbar *toolbar)
3139 {
3140   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3141                               NULL, NULL,
3142                               NULL, NULL,
3143                               NULL, NULL, NULL,
3144                               toolbar->num_children);
3145 }
3146
3147 /**
3148  * gtk_toolbar_prepend_space:
3149  * @toolbar: a #GtkToolbar.
3150  * 
3151  * Adds a new space to the beginning of the toolbar.
3152  **/
3153 void
3154 gtk_toolbar_prepend_space (GtkToolbar *toolbar)
3155 {
3156   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3157                               NULL, NULL,
3158                               NULL, NULL,
3159                               NULL, NULL, NULL,
3160                               0);
3161 }
3162
3163 /**
3164  * gtk_toolbar_insert_space:
3165  * @toolbar: a #GtkToolbar
3166  * @position: the number of widgets after which a space should be inserted.
3167  * 
3168  * Inserts a new space in the toolbar at the specified position.
3169  **/
3170 void
3171 gtk_toolbar_insert_space (GtkToolbar *toolbar,
3172                           gint        position)
3173 {
3174   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3175                               NULL, NULL,
3176                               NULL, NULL,
3177                               NULL, NULL, NULL,
3178                               position);
3179 }
3180
3181 /**
3182  * gtk_toolbar_remove_space:
3183  * @toolbar: a #GtkToolbar.
3184  * @position: the index of the space to remove.
3185  * 
3186  * Removes a space from the specified position.
3187  **/
3188 void
3189 gtk_toolbar_remove_space (GtkToolbar *toolbar,
3190                           gint        position)
3191 {
3192   GtkToolbarPrivate *priv;
3193   ToolbarContent *content;
3194   
3195   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3196   
3197   if (!gtk_toolbar_check_old_api (toolbar))
3198     return;
3199   
3200   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3201   
3202   content = g_list_nth_data (priv->content, position);
3203   
3204   if (!content)
3205     {
3206       g_warning ("Toolbar position %d doesn't exist", position);
3207       return;
3208     }
3209   
3210   if (!toolbar_content_is_separator (content))
3211     {
3212       g_warning ("Toolbar position %d is not a space", position);
3213       return;
3214     }
3215   
3216   toolbar_content_remove (content, toolbar);
3217   toolbar_content_free (content);
3218 }
3219
3220 /**
3221  * gtk_toolbar_append_widget:
3222  * @toolbar: a #GtkToolbar.
3223  * @widget: a #GtkWidget to add to the toolbar. 
3224  * @tooltip_text: the element's tooltip.
3225  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3226  * 
3227  * Adds a widget to the end of the given toolbar.
3228  **/ 
3229 void
3230 gtk_toolbar_append_widget (GtkToolbar  *toolbar,
3231                            GtkWidget   *widget,
3232                            const gchar *tooltip_text,
3233                            const gchar *tooltip_private_text)
3234 {
3235   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3236                               widget, NULL,
3237                               tooltip_text, tooltip_private_text,
3238                               NULL, NULL, NULL,
3239                               toolbar->num_children);
3240 }
3241
3242 /**
3243  * gtk_toolbar_prepend_widget:
3244  * @toolbar: a #GtkToolbar.
3245  * @widget: a #GtkWidget to add to the toolbar. 
3246  * @tooltip_text: the element's tooltip.
3247  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3248  * 
3249  * Adds a widget to the beginning of the given toolbar.
3250  **/ 
3251 void
3252 gtk_toolbar_prepend_widget (GtkToolbar  *toolbar,
3253                             GtkWidget   *widget,
3254                             const gchar *tooltip_text,
3255                             const gchar *tooltip_private_text)
3256 {
3257   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3258                               widget, NULL,
3259                               tooltip_text, tooltip_private_text,
3260                               NULL, NULL, NULL,
3261                               0);
3262 }
3263
3264 /**
3265  * gtk_toolbar_insert_widget:
3266  * @toolbar: a #GtkToolbar.
3267  * @widget: a #GtkWidget to add to the toolbar. 
3268  * @tooltip_text: the element's tooltip.
3269  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3270  * @position: the number of widgets to insert this widget after.
3271  * 
3272  * Inserts a widget in the toolbar at the given position.
3273  **/ 
3274 void
3275 gtk_toolbar_insert_widget (GtkToolbar *toolbar,
3276                            GtkWidget  *widget,
3277                            const char *tooltip_text,
3278                            const char *tooltip_private_text,
3279                            gint        position)
3280 {
3281   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3282                               widget, NULL,
3283                               tooltip_text, tooltip_private_text,
3284                               NULL, NULL, NULL,
3285                               position);
3286 }
3287
3288 /**
3289  * gtk_toolbar_append_element:
3290  * @toolbar: a #GtkToolbar.
3291  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3292  * @widget: a #GtkWidget, or %NULL.
3293  * @text: the element's label.
3294  * @tooltip_text: the element's tooltip.
3295  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3296  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3297  * @callback: the function to be executed when the button is pressed.
3298  * @user_data: any data you wish to pass to the callback.
3299  * 
3300  * Adds a new element to the end of a toolbar.
3301  * 
3302  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3303  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3304  * the radio group for the new element. In all other cases, @widget must
3305  * be %NULL.
3306  * 
3307  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3308  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3309  *
3310  * Return value: the new toolbar element as a #GtkWidget.
3311  **/
3312 GtkWidget*
3313 gtk_toolbar_append_element (GtkToolbar          *toolbar,
3314                             GtkToolbarChildType  type,
3315                             GtkWidget           *widget,
3316                             const char          *text,
3317                             const char          *tooltip_text,
3318                             const char          *tooltip_private_text,
3319                             GtkWidget           *icon,
3320                             GtkSignalFunc        callback,
3321                             gpointer             user_data)
3322 {
3323   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3324                                      tooltip_text, tooltip_private_text,
3325                                      icon, callback, user_data,
3326                                      toolbar->num_children);
3327 }
3328
3329 /**
3330  * gtk_toolbar_prepend_element:
3331  * @toolbar: a #GtkToolbar.
3332  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3333  * @widget: a #GtkWidget, or %NULL
3334  * @text: the element's label.
3335  * @tooltip_text: the element's tooltip.
3336  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3337  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3338  * @callback: the function to be executed when the button is pressed.
3339  * @user_data: any data you wish to pass to the callback.
3340  *  
3341  * Adds a new element to the beginning of a toolbar.
3342  * 
3343  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3344  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3345  * the radio group for the new element. In all other cases, @widget must
3346  * be %NULL.
3347  * 
3348  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3349  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3350  *
3351  * Return value: the new toolbar element as a #GtkWidget.
3352  **/
3353 GtkWidget *
3354 gtk_toolbar_prepend_element (GtkToolbar          *toolbar,
3355                              GtkToolbarChildType  type,
3356                              GtkWidget           *widget,
3357                              const char          *text,
3358                              const char          *tooltip_text,
3359                              const char          *tooltip_private_text,
3360                              GtkWidget           *icon,
3361                              GtkSignalFunc        callback,
3362                              gpointer             user_data)
3363 {
3364   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3365                                      tooltip_text, tooltip_private_text,
3366                                      icon, callback, user_data, 0);
3367 }
3368
3369 /**
3370  * gtk_toolbar_insert_element:
3371  * @toolbar: a #GtkToolbar.
3372  * @type: a value of type #GtkToolbarChildType that determines what @widget
3373  *   will be.
3374  * @widget: a #GtkWidget, or %NULL. 
3375  * @text: the element's label.
3376  * @tooltip_text: the element's tooltip.
3377  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3378  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3379  * @callback: the function to be executed when the button is pressed.
3380  * @user_data: any data you wish to pass to the callback.
3381  * @position: the number of widgets to insert this element after.
3382  *
3383  * Inserts a new element in the toolbar at the given position. 
3384  *
3385  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3386  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3387  * the radio group for the new element. In all other cases, @widget must
3388  * be %NULL.
3389  *
3390  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3391  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3392  *
3393  * Return value: the new toolbar element as a #GtkWidget.
3394  **/
3395 GtkWidget *
3396 gtk_toolbar_insert_element (GtkToolbar          *toolbar,
3397                             GtkToolbarChildType  type,
3398                             GtkWidget           *widget,
3399                             const char          *text,
3400                             const char          *tooltip_text,
3401                             const char          *tooltip_private_text,
3402                             GtkWidget           *icon,
3403                             GtkSignalFunc        callback,
3404                             gpointer             user_data,
3405                             gint                 position)
3406 {
3407   return internal_insert_element (toolbar, type, widget, text,
3408                                   tooltip_text, tooltip_private_text,
3409                                   icon, callback, user_data, position, FALSE);
3410 }
3411
3412 static void
3413 set_child_packing_and_visibility(GtkToolbar      *toolbar,
3414                                  GtkToolbarChild *child)
3415 {
3416   GtkWidget *box;
3417   gboolean   expand;
3418
3419   box = gtk_bin_get_child (GTK_BIN (child->widget));
3420   
3421   g_return_if_fail (GTK_IS_BOX (box));
3422   
3423   if (child->label)
3424     {
3425       expand = (toolbar->style != GTK_TOOLBAR_BOTH);
3426       
3427       gtk_box_set_child_packing (GTK_BOX (box), child->label,
3428                                  expand, expand, 0, GTK_PACK_END);
3429       
3430       if (toolbar->style != GTK_TOOLBAR_ICONS)
3431         gtk_widget_show (child->label);
3432       else
3433         gtk_widget_hide (child->label);
3434     }
3435   
3436   if (child->icon)
3437     {
3438       expand = (toolbar->style != GTK_TOOLBAR_BOTH_HORIZ);
3439       
3440       gtk_box_set_child_packing (GTK_BOX (box), child->icon,
3441                                  expand, expand, 0, GTK_PACK_END);
3442       
3443       if (toolbar->style != GTK_TOOLBAR_TEXT)
3444         gtk_widget_show (child->icon);
3445       else
3446         gtk_widget_hide (child->icon);
3447     }
3448 }
3449
3450 static GtkWidget *
3451 internal_insert_element (GtkToolbar          *toolbar,
3452                          GtkToolbarChildType  type,
3453                          GtkWidget           *widget,
3454                          const char          *text,
3455                          const char          *tooltip_text,
3456                          const char          *tooltip_private_text,
3457                          GtkWidget           *icon,
3458                          GtkSignalFunc        callback,
3459                          gpointer             user_data,
3460                          gint                 position,
3461                          gboolean             use_stock)
3462 {
3463   GtkWidget *box;
3464   ToolbarContent *content;
3465   GtkToolbarPrivate *priv;
3466   char *free_me = NULL;
3467   gboolean is_button = FALSE;
3468
3469   GtkWidget *child_widget;
3470   GtkWidget *child_label;
3471   GtkWidget *child_icon;
3472
3473   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
3474   if (type == GTK_TOOLBAR_CHILD_WIDGET)
3475     g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
3476   else if (type != GTK_TOOLBAR_CHILD_RADIOBUTTON)
3477     g_return_val_if_fail (widget == NULL, NULL);
3478   
3479   if (!gtk_toolbar_check_old_api (toolbar))
3480     return NULL;
3481   
3482   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3483   
3484   child_widget = NULL;
3485   child_label = NULL;
3486   child_icon = NULL;
3487   
3488   switch (type)
3489     {
3490     case GTK_TOOLBAR_CHILD_SPACE:
3491       break;
3492       
3493     case GTK_TOOLBAR_CHILD_WIDGET:
3494       child_widget = widget;
3495       break;
3496       
3497     case GTK_TOOLBAR_CHILD_BUTTON:
3498     case GTK_TOOLBAR_CHILD_TOGGLEBUTTON:
3499     case GTK_TOOLBAR_CHILD_RADIOBUTTON:
3500       is_button = TRUE;
3501       if (type == GTK_TOOLBAR_CHILD_BUTTON)
3502         {
3503           child_widget = gtk_button_new ();
3504         }
3505       else if (type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
3506         {
3507           child_widget = gtk_toggle_button_new ();
3508           gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child_widget), FALSE);
3509         }
3510       else /* type == GTK_TOOLBAR_CHILD_RADIOBUTTON */
3511         {
3512           GSList *group = NULL;
3513
3514           if (widget)
3515             group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
3516           
3517           child_widget = gtk_radio_button_new (group);
3518           gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child_widget), FALSE);
3519         }
3520
3521       gtk_button_set_relief (GTK_BUTTON (child_widget), get_button_relief (toolbar));
3522       gtk_button_set_focus_on_click (GTK_BUTTON (child_widget), FALSE);
3523       
3524       if (callback)
3525         {
3526           g_signal_connect (child_widget, "clicked",
3527                             callback, user_data);
3528         }
3529       
3530       if (toolbar->style == GTK_TOOLBAR_BOTH_HORIZ)
3531         box = gtk_hbox_new (FALSE, 0);
3532       else
3533         box = gtk_vbox_new (FALSE, 0);
3534
3535       gtk_container_add (GTK_CONTAINER (child_widget), box);
3536       gtk_widget_show (box);
3537       
3538       if (text && use_stock)
3539         {
3540           GtkStockItem stock_item;
3541           gtk_stock_lookup (text, &stock_item);
3542           
3543           if (!icon)
3544             icon = gtk_image_new_from_stock (text, toolbar->icon_size);
3545           
3546           text = free_me = _gtk_toolbar_elide_underscores (stock_item.label);
3547         }
3548       
3549       if (text)
3550         {
3551           child_label = gtk_label_new (text);
3552           
3553           gtk_container_add (GTK_CONTAINER (box), child_label);
3554         }
3555       
3556       if (icon)
3557         {
3558           child_icon = GTK_WIDGET (icon);
3559           gtk_container_add (GTK_CONTAINER (box), child_icon);
3560         }
3561       
3562       gtk_widget_show (child_widget);
3563       break;
3564       
3565     default:
3566       g_assert_not_reached ();
3567       break;
3568     }
3569   
3570   if ((type != GTK_TOOLBAR_CHILD_SPACE) && tooltip_text)
3571     {
3572       gtk_tooltips_set_tip (toolbar->tooltips, child_widget,
3573                             tooltip_text, tooltip_private_text);
3574     }
3575   
3576   content = toolbar_content_new_compatibility (toolbar, type, child_widget,
3577                                                child_icon, child_label, position);
3578   
3579   if (free_me)
3580     g_free (free_me);
3581   
3582   return child_widget;
3583 }
3584
3585 /*
3586  * ToolbarContent methods
3587  */
3588 struct _ToolbarContent
3589 {
3590   ContentType   type;
3591   ItemState     state;
3592   
3593   union
3594   {
3595     struct
3596     {
3597       GtkToolItem *     item;
3598       GtkAllocation     start_allocation;
3599       GtkAllocation     goal_allocation;
3600       guint             is_placeholder : 1;
3601       guint             disappearing : 1;
3602     } tool_item;
3603     
3604     struct
3605     {
3606       GtkToolbarChild   child;
3607       GtkAllocation     space_allocation;
3608       guint             space_visible : 1;
3609     } compatibility;
3610   } u;
3611 };
3612
3613 static ToolbarContent *
3614 toolbar_content_new_tool_item (GtkToolbar  *toolbar,
3615                                GtkToolItem *item,
3616                                gboolean     is_placeholder,
3617                                gint         pos)
3618 {
3619   ToolbarContent *content;
3620   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3621   
3622   content = g_new0 (ToolbarContent, 1);
3623   
3624   content->type = TOOL_ITEM;
3625   content->state = NOT_ALLOCATED;
3626   content->u.tool_item.item = item;
3627   content->u.tool_item.is_placeholder = is_placeholder;
3628   
3629   gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar));
3630
3631   priv->content = g_list_insert (priv->content, content, pos);
3632   
3633   if (!is_placeholder)
3634     toolbar->num_children++;
3635   
3636   return content;
3637 }
3638
3639 static ToolbarContent *
3640 toolbar_content_new_compatibility (GtkToolbar          *toolbar,
3641                                    GtkToolbarChildType  type,
3642                                    GtkWidget            *widget,
3643                                    GtkWidget            *icon,
3644                                    GtkWidget            *label,
3645                                    gint                  pos)
3646 {
3647   ToolbarContent *content;
3648   GtkToolbarChild *child;
3649   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3650   
3651   content = g_new0 (ToolbarContent, 1);
3652
3653   child = &(content->u.compatibility.child);
3654   
3655   content->type = COMPATIBILITY;
3656   child->type = type;
3657   child->widget = widget;
3658   child->icon = icon;
3659   child->label = label;
3660   
3661   if (type != GTK_TOOLBAR_CHILD_SPACE)
3662     {
3663       gtk_widget_set_parent (child->widget, GTK_WIDGET (toolbar));
3664     }
3665   else
3666     {
3667       content->u.compatibility.space_visible = TRUE;
3668       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3669     }
3670  
3671   if (type == GTK_TOOLBAR_CHILD_BUTTON ||
3672       type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
3673       type == GTK_TOOLBAR_CHILD_RADIOBUTTON)
3674     {
3675       set_child_packing_and_visibility (toolbar, child);
3676     }
3677
3678   priv->content = g_list_insert (priv->content, content, pos);
3679   toolbar->children = g_list_insert (toolbar->children, child, pos);
3680   
3681   toolbar->num_children++;
3682   
3683   return content;
3684 }
3685
3686 static void
3687 toolbar_content_remove (ToolbarContent *content,
3688                         GtkToolbar     *toolbar)
3689 {
3690   GtkToolbarChild *child;
3691   GtkToolbarPrivate *priv;
3692
3693   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3694   
3695   switch (content->type)
3696     {
3697     case TOOL_ITEM:
3698       gtk_widget_unparent (GTK_WIDGET (content->u.tool_item.item));
3699       break;
3700       
3701     case COMPATIBILITY:
3702       child = &(content->u.compatibility.child);
3703       
3704       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
3705         {
3706           g_object_ref (child->widget);
3707           gtk_widget_unparent (child->widget);
3708           gtk_widget_destroy (child->widget);
3709           g_object_unref (child->widget);
3710         }
3711       
3712       toolbar->children = g_list_remove (toolbar->children, child);
3713       break;
3714     }
3715
3716   priv->content = g_list_remove (priv->content, content);
3717
3718   if (!toolbar_content_is_placeholder (content))
3719     toolbar->num_children--;
3720
3721   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3722 }
3723
3724 static void
3725 toolbar_content_free (ToolbarContent *content)
3726 {
3727   g_free (content);
3728 }
3729
3730 static gint
3731 calculate_max_homogeneous_pixels (GtkWidget *widget)
3732 {
3733   PangoContext *context;
3734   PangoFontMetrics *metrics;
3735   gint char_width;
3736   
3737   context = gtk_widget_get_pango_context (widget);
3738   metrics = pango_context_get_metrics (context,
3739                                        widget->style->font_desc,
3740                                        pango_context_get_language (context));
3741   char_width = pango_font_metrics_get_approximate_char_width (metrics);
3742   pango_font_metrics_unref (metrics);
3743   
3744   return PANGO_PIXELS (MAX_HOMOGENEOUS_N_CHARS * char_width);
3745 }
3746
3747 static void
3748 gtk_toolbar_paint_space_line (GtkWidget       *widget,
3749                               GdkRectangle    *area,
3750                               ToolbarContent  *content)
3751 {
3752   GtkToolbar *toolbar;
3753   gint space_size;
3754   GtkAllocation *allocation = &(content->u.compatibility.space_allocation);
3755   double end_fraction = (SPACE_LINE_END / SPACE_LINE_DIVISION);
3756   double start_fraction = (SPACE_LINE_START / SPACE_LINE_DIVISION);
3757   
3758   g_return_if_fail (GTK_IS_TOOLBAR (widget));
3759   
3760   toolbar = GTK_TOOLBAR (widget);
3761   
3762   space_size = get_space_size (toolbar);
3763   
3764   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
3765     {
3766       gtk_paint_vline (widget->style, widget->window,
3767                        GTK_WIDGET_STATE (widget), area, widget,
3768                        "toolbar",
3769                        allocation->y + allocation->height * start_fraction,
3770                        allocation->y + allocation->height * end_fraction,
3771                        allocation->x + (space_size - widget->style->xthickness) / 2);
3772     }
3773   else
3774     {
3775       gtk_paint_hline (widget->style, widget->window,
3776                        GTK_WIDGET_STATE (widget), area, widget,
3777                        "toolbar",
3778                        allocation->x + allocation->width * start_fraction,
3779                        allocation->x + allocation->width * end_fraction,
3780                        allocation->y + (space_size - widget->style->ythickness) / 2);
3781     }
3782 }
3783
3784 static void
3785 toolbar_content_expose (ToolbarContent *content,
3786                         GtkContainer   *container,
3787                         GdkEventExpose *expose)
3788 {
3789   GtkToolbar *toolbar = GTK_TOOLBAR (container);
3790   GtkToolbarChild *child;
3791   GtkWidget *widget = NULL; /* quiet gcc */
3792   
3793   switch (content->type)
3794     {
3795     case TOOL_ITEM:
3796       if (!content->u.tool_item.is_placeholder)
3797         widget = GTK_WIDGET (content->u.tool_item.item);
3798       break;
3799       
3800     case COMPATIBILITY:
3801       child = &(content->u.compatibility.child);
3802       
3803       if (child->type == GTK_TOOLBAR_CHILD_SPACE)
3804         {
3805           if (get_space_style (toolbar) == GTK_TOOLBAR_SPACE_LINE &&
3806               content->u.compatibility.space_visible)
3807             {
3808               gtk_toolbar_paint_space_line (GTK_WIDGET (toolbar), &expose->area, content);
3809             }
3810           return;
3811         }
3812       
3813       widget = child->widget;
3814       break;
3815     }
3816   
3817   if (widget)
3818     gtk_container_propagate_expose (container, widget, expose);
3819 }
3820
3821 static gboolean
3822 toolbar_content_visible (ToolbarContent *content,
3823                          GtkToolbar     *toolbar)
3824 {
3825   GtkToolItem *item;
3826   
3827   switch (content->type)
3828     {
3829     case TOOL_ITEM:
3830       item = content->u.tool_item.item;
3831       
3832       if (!GTK_WIDGET_VISIBLE (item))
3833         return FALSE;
3834       
3835       if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL &&
3836           gtk_tool_item_get_visible_horizontal (item))
3837         {
3838           return TRUE;
3839         }
3840       
3841       if ((toolbar->orientation == GTK_ORIENTATION_VERTICAL &&
3842            gtk_tool_item_get_visible_vertical (item)))
3843         {
3844           return TRUE;
3845         }
3846       
3847       return FALSE;
3848       break;
3849       
3850     case COMPATIBILITY:
3851       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
3852         return GTK_WIDGET_VISIBLE (content->u.compatibility.child.widget);
3853       else
3854         return TRUE;
3855       break;
3856     }
3857   
3858   g_assert_not_reached ();
3859   return FALSE;
3860 }
3861
3862 static void
3863 toolbar_content_size_request (ToolbarContent *content,
3864                               GtkToolbar     *toolbar,
3865                               GtkRequisition *requisition)
3866 {
3867   gint space_size;
3868   
3869   switch (content->type)
3870     {
3871     case TOOL_ITEM:
3872       gtk_widget_size_request (GTK_WIDGET (content->u.tool_item.item),
3873                                requisition);
3874       break;
3875       
3876     case COMPATIBILITY:
3877       space_size = get_space_size (toolbar);
3878       
3879       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
3880         {
3881           gtk_widget_size_request (content->u.compatibility.child.widget,
3882                                    requisition);
3883         }
3884       else
3885         {
3886           if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
3887             {
3888               requisition->width = space_size;
3889               requisition->height = 0;
3890             }
3891           else
3892             {
3893               requisition->height = space_size;
3894               requisition->width = 0;
3895             }
3896         }
3897       
3898       break;
3899     }
3900 }
3901
3902 static gboolean
3903 toolbar_content_is_homogeneous (ToolbarContent *content,
3904                                 GtkToolbar     *toolbar)
3905 {
3906   gboolean result = FALSE;      /* quiet gcc */
3907   GtkRequisition requisition;
3908   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3909   
3910   if (priv->max_homogeneous_pixels < 0)
3911     {
3912       priv->max_homogeneous_pixels =
3913         calculate_max_homogeneous_pixels (GTK_WIDGET (toolbar));
3914     }
3915   
3916   toolbar_content_size_request (content, toolbar, &requisition);
3917   
3918   if (requisition.width > priv->max_homogeneous_pixels)
3919     return FALSE;
3920   
3921   switch (content->type)
3922     {
3923     case TOOL_ITEM:
3924       result = gtk_tool_item_get_homogeneous (content->u.tool_item.item) &&
3925         !GTK_IS_SEPARATOR_TOOL_ITEM (content->u.tool_item.item);
3926       
3927       if (gtk_tool_item_get_is_important (content->u.tool_item.item) &&
3928           toolbar->style == GTK_TOOLBAR_BOTH_HORIZ &&
3929           toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
3930         {
3931           result = FALSE;
3932         }
3933       break;
3934       
3935     case COMPATIBILITY:
3936       if (content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_BUTTON ||
3937           content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
3938           content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
3939         {
3940           result = TRUE;
3941         }
3942       else
3943         {
3944           result = FALSE;
3945         }
3946       break;
3947     }
3948   
3949   return result;
3950 }
3951
3952 static gboolean
3953 toolbar_content_is_placeholder (ToolbarContent *content)
3954 {
3955   if (content->type == TOOL_ITEM && content->u.tool_item.is_placeholder)
3956     return TRUE;
3957   
3958   return FALSE;
3959 }
3960
3961 static gboolean
3962 toolbar_content_disappearing (ToolbarContent *content)
3963 {
3964   if (content->type == TOOL_ITEM && content->u.tool_item.disappearing)
3965     return TRUE;
3966   
3967   return FALSE;
3968 }
3969
3970 static ItemState
3971 toolbar_content_get_state (ToolbarContent *content)
3972 {
3973   return content->state;
3974 }
3975
3976 static gboolean
3977 toolbar_content_child_visible (ToolbarContent *content)
3978 {
3979   switch (content->type)
3980     {
3981     case TOOL_ITEM:
3982       return GTK_WIDGET_CHILD_VISIBLE (content->u.tool_item.item);
3983       break;
3984       
3985     case COMPATIBILITY:
3986       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
3987         {
3988           return GTK_WIDGET_CHILD_VISIBLE (content->u.compatibility.child.widget);
3989         }
3990       else
3991         {
3992           return content->u.compatibility.space_visible;
3993         }
3994       break;
3995     }
3996   
3997   return FALSE; /* quiet gcc */
3998 }
3999
4000 static void
4001 toolbar_content_get_goal_allocation (ToolbarContent *content,
4002                                      GtkAllocation  *allocation)
4003 {
4004   switch (content->type)
4005     {
4006     case TOOL_ITEM:
4007       *allocation = content->u.tool_item.goal_allocation;
4008       break;
4009       
4010     case COMPATIBILITY:
4011       /* Goal allocations are only relevant when we are
4012        * using the new API, so we should never get here
4013        */
4014       g_assert_not_reached ();
4015       break;
4016     }
4017 }
4018
4019 static void
4020 toolbar_content_get_allocation (ToolbarContent *content,
4021                                 GtkAllocation  *allocation)
4022 {
4023   GtkToolbarChild *child;
4024   
4025   switch (content->type)
4026     {
4027     case TOOL_ITEM:
4028       *allocation = GTK_WIDGET (content->u.tool_item.item)->allocation;
4029       break;
4030       
4031     case COMPATIBILITY:
4032       child = &(content->u.compatibility.child);
4033       
4034       if (child->type == GTK_TOOLBAR_CHILD_SPACE)
4035         *allocation = content->u.compatibility.space_allocation;
4036       else
4037         *allocation = child->widget->allocation;
4038       break;
4039     }
4040 }
4041
4042 static void
4043 toolbar_content_set_start_allocation (ToolbarContent *content,
4044                                       GtkAllocation  *allocation)
4045 {
4046   switch (content->type)
4047     {
4048     case TOOL_ITEM:
4049       content->u.tool_item.start_allocation = *allocation;
4050       break;
4051       
4052     case COMPATIBILITY:
4053       /* start_allocation is only relevant when using the new API */
4054       g_assert_not_reached ();
4055       break;
4056     }
4057 }
4058
4059 static gboolean
4060 toolbar_content_get_expand (ToolbarContent *content)
4061 {
4062   if (content->type == TOOL_ITEM &&
4063       gtk_tool_item_get_expand (content->u.tool_item.item))
4064     {
4065       return TRUE;
4066     }
4067   
4068   return FALSE;
4069 }
4070
4071 static void
4072 toolbar_content_set_goal_allocation (ToolbarContent *content,
4073                                      GtkAllocation  *allocation)
4074 {
4075   switch (content->type)
4076     {
4077     case TOOL_ITEM:
4078       content->u.tool_item.goal_allocation = *allocation;
4079       break;
4080       
4081     case COMPATIBILITY:
4082       /* Only relevant when using new API */
4083       g_assert_not_reached ();
4084       break;
4085     }
4086 }
4087
4088 static void
4089 toolbar_content_set_child_visible (ToolbarContent *content,
4090                                    GtkToolbar     *toolbar,
4091                                    gboolean        visible)
4092 {
4093   GtkToolbarChild *child;
4094   
4095   switch (content->type)
4096     {
4097     case TOOL_ITEM:
4098       gtk_widget_set_child_visible (GTK_WIDGET (content->u.tool_item.item),
4099                                     visible);
4100       break;
4101       
4102     case COMPATIBILITY:
4103       child = &(content->u.compatibility.child);
4104       
4105       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
4106         {
4107           gtk_widget_set_child_visible (child->widget, visible);
4108         }
4109       else
4110         {
4111           content->u.compatibility.space_visible = visible;
4112           gtk_widget_queue_draw (GTK_WIDGET (toolbar));
4113         }
4114       break;
4115     }
4116 }
4117
4118 static void
4119 toolbar_content_get_start_allocation (ToolbarContent *content,
4120                                       GtkAllocation  *start_allocation)
4121 {
4122   switch (content->type)
4123     {
4124     case TOOL_ITEM:
4125       *start_allocation = content->u.tool_item.start_allocation;
4126       break;
4127       
4128     case COMPATIBILITY:
4129       /* Only relevant for new API */
4130       g_assert_not_reached ();
4131       break;
4132     }
4133 }
4134
4135 static void
4136 toolbar_content_size_allocate (ToolbarContent *content,
4137                                GtkAllocation  *allocation)
4138 {
4139   switch (content->type)
4140     {
4141     case TOOL_ITEM:
4142       gtk_widget_size_allocate (GTK_WIDGET (content->u.tool_item.item),
4143                                 allocation);
4144       break;
4145       
4146     case COMPATIBILITY:
4147       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4148         {
4149           gtk_widget_size_allocate (content->u.compatibility.child.widget,
4150                                     allocation);
4151         }
4152       else
4153         {
4154           content->u.compatibility.space_allocation = *allocation;
4155         }
4156       break;
4157     }
4158 }
4159
4160 static void
4161 toolbar_content_set_state (ToolbarContent *content,
4162                            ItemState       state)
4163 {
4164   content->state = state;
4165 }
4166
4167 static GtkWidget *
4168 toolbar_content_get_widget (ToolbarContent *content)
4169 {
4170   GtkToolbarChild *child;
4171   
4172   switch (content->type)
4173     {
4174     case TOOL_ITEM:
4175       return GTK_WIDGET (content->u.tool_item.item);
4176       break;
4177       
4178     case COMPATIBILITY:
4179       child = &(content->u.compatibility.child);
4180       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
4181         return child->widget;
4182       else
4183         return NULL;
4184       break;
4185     }
4186   
4187   return NULL;
4188 }
4189
4190 static void
4191 toolbar_content_set_disappearing (ToolbarContent *content,
4192                                   gboolean        disappearing)
4193 {
4194   switch (content->type)
4195     {
4196     case TOOL_ITEM:
4197       content->u.tool_item.disappearing = disappearing;
4198       break;
4199       
4200     case COMPATIBILITY:
4201       /* Only relevant for new API */
4202       g_assert_not_reached ();
4203       break;
4204     }
4205 }
4206
4207 static void
4208 toolbar_content_set_size_request (ToolbarContent *content,
4209                                   gint            width,
4210                                   gint            height)
4211 {
4212   switch (content->type)
4213     {
4214     case TOOL_ITEM:
4215       gtk_widget_set_size_request (GTK_WIDGET (content->u.tool_item.item),
4216                                    width, height);
4217       break;
4218       
4219     case COMPATIBILITY:
4220       /* Setting size requests only happens with sliding,
4221        * so not relevant here
4222        */
4223       g_assert_not_reached ();
4224       break;
4225     }
4226 }
4227
4228 static void
4229 toolbar_child_reconfigure (GtkToolbar      *toolbar,
4230                            GtkToolbarChild *child)
4231 {
4232   GtkWidget *box;
4233   GtkImage *image;
4234   GtkToolbarStyle style;
4235   GtkIconSize icon_size;
4236   GtkReliefStyle relief;
4237   gchar *stock_id;
4238   
4239   style = gtk_toolbar_get_style (toolbar);
4240   icon_size = gtk_toolbar_get_icon_size (toolbar);
4241   relief = gtk_toolbar_get_relief_style (toolbar);
4242   
4243   /* style */
4244   if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4245       child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4246       child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4247     {
4248       box = gtk_bin_get_child (GTK_BIN (child->widget));
4249       
4250       if (style == GTK_TOOLBAR_BOTH && GTK_IS_HBOX (box))
4251         {
4252           GtkWidget *vbox;
4253           
4254           vbox = gtk_vbox_new (FALSE, 0);
4255           
4256           if (child->label)
4257             gtk_widget_reparent (child->label, vbox);
4258           if (child->icon)
4259             gtk_widget_reparent (child->icon, vbox);
4260           
4261           gtk_widget_destroy (box);
4262           gtk_container_add (GTK_CONTAINER (child->widget), vbox);
4263           
4264           gtk_widget_show (vbox);
4265         }
4266       else if (style == GTK_TOOLBAR_BOTH_HORIZ && GTK_IS_VBOX (box))
4267         {
4268           GtkWidget *hbox;
4269           
4270           hbox = gtk_hbox_new (FALSE, 0);
4271           
4272           if (child->label)
4273             gtk_widget_reparent (child->label, hbox);
4274           if (child->icon)
4275             gtk_widget_reparent (child->icon, hbox);
4276           
4277           gtk_widget_destroy (box);
4278           gtk_container_add (GTK_CONTAINER (child->widget), hbox);
4279           
4280           gtk_widget_show (hbox);
4281         }
4282
4283       set_child_packing_and_visibility (toolbar, child);
4284     }
4285   
4286   /* icon size */
4287   
4288   if ((child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4289        child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
4290        child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON) &&
4291       GTK_IS_IMAGE (child->icon))
4292     {
4293       image = GTK_IMAGE (child->icon);
4294       if (gtk_image_get_storage_type (image) == GTK_IMAGE_STOCK)
4295         {
4296           gtk_image_get_stock (image, &stock_id, NULL);
4297           stock_id = g_strdup (stock_id);
4298           gtk_image_set_from_stock (image,
4299                                     stock_id,
4300                                     icon_size);
4301           g_free (stock_id);
4302         }
4303     }
4304   
4305   /* relief */
4306   if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4307       child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4308       child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4309     {
4310       gtk_button_set_relief (GTK_BUTTON (child->widget), relief);
4311     }
4312 }
4313
4314 static void
4315 toolbar_content_toolbar_reconfigured (ToolbarContent *content,
4316                                       GtkToolbar     *toolbar)
4317 {
4318   switch (content->type)
4319     {
4320     case TOOL_ITEM:
4321       _gtk_tool_item_toolbar_reconfigured (content->u.tool_item.item);
4322       break;
4323       
4324     case COMPATIBILITY:
4325       toolbar_child_reconfigure (toolbar, &(content->u.compatibility.child));
4326       break;
4327     }
4328 }
4329
4330 static GtkWidget *
4331 toolbar_content_retrieve_menu_item (ToolbarContent *content)
4332 {
4333   if (content->type == TOOL_ITEM)
4334     return gtk_tool_item_retrieve_proxy_menu_item (content->u.tool_item.item);
4335   
4336   /* FIXME - we might actually be able to do something meaningful here */
4337   return NULL; 
4338 }
4339
4340 static gboolean
4341 toolbar_content_is_separator (ToolbarContent *content)
4342 {
4343   GtkToolbarChild *child;
4344   
4345   switch (content->type)
4346     {
4347     case TOOL_ITEM:
4348       return GTK_IS_SEPARATOR_TOOL_ITEM (content->u.tool_item.item);
4349       break;
4350       
4351     case COMPATIBILITY:
4352       child = &(content->u.compatibility.child);
4353       return (child->type == GTK_TOOLBAR_CHILD_SPACE);
4354       break;
4355     }
4356   
4357   return FALSE;
4358 }
4359
4360 static gboolean
4361 ignore_show_and_hide_all (ToolbarContent *content)
4362 {
4363   if (content->type == COMPATIBILITY)
4364     {
4365       GtkToolbarChildType type = content->u.compatibility.child.type;
4366       
4367       if (type == GTK_TOOLBAR_CHILD_BUTTON ||
4368           type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
4369           type == GTK_TOOLBAR_CHILD_RADIOBUTTON)
4370         {
4371           return TRUE;
4372         }
4373     }
4374   
4375   return FALSE;
4376 }
4377
4378 static void
4379 toolbar_content_show_all (ToolbarContent  *content)
4380 {
4381   GtkWidget *widget;
4382   
4383   if (ignore_show_and_hide_all (content))
4384     return;
4385
4386   widget = toolbar_content_get_widget (content);
4387   if (widget)
4388     gtk_widget_show_all (widget);
4389 }
4390
4391 static void
4392 toolbar_content_hide_all (ToolbarContent  *content)
4393 {
4394   GtkWidget *widget;
4395   
4396   if (ignore_show_and_hide_all (content))
4397     return;
4398
4399   widget = toolbar_content_get_widget (content);
4400   if (widget)
4401     gtk_widget_hide_all (widget);
4402 }
4403
4404 /*
4405  * Getters
4406  */
4407 static gint
4408 get_space_size (GtkToolbar *toolbar)
4409 {
4410   gint space_size = DEFAULT_SPACE_SIZE;
4411   
4412   gtk_widget_style_get (GTK_WIDGET (toolbar),
4413                         "space_size", &space_size,
4414                         NULL);
4415   
4416   return space_size;
4417 }
4418
4419 static GtkToolbarSpaceStyle
4420 get_space_style (GtkToolbar *toolbar)
4421 {
4422   GtkToolbarSpaceStyle space_style = DEFAULT_SPACE_STYLE;
4423   
4424   gtk_widget_style_get (GTK_WIDGET (toolbar),
4425                         "space_style", &space_style,
4426                         NULL);
4427   
4428   
4429   return space_style;  
4430 }
4431
4432 static GtkReliefStyle
4433 get_button_relief (GtkToolbar *toolbar)
4434 {
4435   GtkReliefStyle button_relief = GTK_RELIEF_NORMAL;
4436   
4437   gtk_widget_ensure_style (GTK_WIDGET (toolbar));
4438   
4439   gtk_widget_style_get (GTK_WIDGET (toolbar),
4440                         "button_relief", &button_relief,
4441                         NULL);
4442   
4443   return button_relief;
4444 }
4445
4446 static gint
4447 get_internal_padding (GtkToolbar *toolbar)
4448 {
4449   gint ipadding = 0;
4450   
4451   gtk_widget_style_get (GTK_WIDGET (toolbar),
4452                         "internal_padding", &ipadding,
4453                         NULL);
4454   
4455   return ipadding;
4456 }
4457
4458 static GtkShadowType
4459 get_shadow_type (GtkToolbar *toolbar)
4460 {
4461   GtkShadowType shadow_type;
4462   
4463   gtk_widget_style_get (GTK_WIDGET (toolbar),
4464                         "shadow_type", &shadow_type,
4465                         NULL);
4466   
4467   return shadow_type;
4468 }
4469
4470 /*
4471  * API checks
4472  */
4473 static gboolean
4474 gtk_toolbar_check_old_api (GtkToolbar *toolbar)
4475 {
4476   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4477   
4478   if (priv->api_mode == NEW_API)
4479     {
4480       g_warning ("mixing deprecated and non-deprecated GtkToolbar API is not allowed");
4481       return FALSE;
4482     }
4483   
4484   priv->api_mode = OLD_API;
4485   return TRUE;
4486 }
4487
4488 static gboolean
4489 gtk_toolbar_check_new_api (GtkToolbar *toolbar)
4490 {
4491   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4492   
4493   if (priv->api_mode == OLD_API)
4494     {
4495       g_warning ("mixing deprecated and non-deprecated GtkToolbar API is not allowed");
4496       return FALSE;
4497     }
4498   
4499   priv->api_mode = NEW_API;
4500   return TRUE;
4501 }