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