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