]> Pileus Git - ~andy/gtk/blob - gtk/gtktoolbar.c
Swap GTK_ARROW_LEFT and GTK_ARROW_RIGHT for GTK_TEXT_DIR_LTR. (#129159,
[~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   
1747   /* if focus is already somewhere inside the toolbar then return FALSE.
1748    * The only way focus can stay inside the toolbar is when the user presses
1749    * arrow keys or Ctrl TAB (both of which are handled by the
1750    * gtk_toolbar_move_focus() keybinding function.
1751    */
1752   if (GTK_CONTAINER (widget)->focus_child)
1753     return FALSE;
1754   
1755   children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
1756   
1757   for (list = children; list != NULL; list = list->next)
1758     {
1759       GtkWidget *child = list->data;
1760       
1761       if (GTK_WIDGET_MAPPED (child) && gtk_widget_child_focus (child, dir))
1762         return TRUE;
1763     }
1764   
1765   g_list_free (children);
1766   
1767   return FALSE;
1768 }
1769
1770 static void
1771 style_change_notify (GtkToolbar *toolbar)
1772 {
1773   if (!toolbar->style_set)
1774     {
1775       /* pretend it was set, then unset, thus reverting to new default */
1776       toolbar->style_set = TRUE; 
1777       gtk_toolbar_unset_style (toolbar);
1778     }
1779 }
1780
1781 static void
1782 icon_size_change_notify (GtkToolbar *toolbar)
1783
1784   if (!toolbar->icon_size_set)
1785     {
1786       /* pretend it was set, then unset, thus reverting to new default */
1787       toolbar->icon_size_set = TRUE; 
1788       gtk_toolbar_unset_icon_size (toolbar);
1789     }
1790 }
1791
1792 static GtkSettings *
1793 toolbar_get_settings (GtkToolbar *toolbar)
1794 {
1795   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1796   return priv->settings;
1797 }
1798
1799 static void
1800 gtk_toolbar_screen_changed (GtkWidget *widget,
1801                             GdkScreen *previous_screen)
1802 {
1803   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
1804   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
1805   GtkSettings *old_settings = toolbar_get_settings (toolbar);
1806   GtkSettings *settings;
1807   
1808   if (gtk_widget_has_screen (GTK_WIDGET (toolbar)))
1809     settings = gtk_widget_get_settings (GTK_WIDGET (toolbar));
1810   else
1811     settings = NULL;
1812   
1813   if (settings == old_settings)
1814     return;
1815   
1816   if (old_settings)
1817     {
1818       g_signal_handler_disconnect (old_settings, toolbar->style_set_connection);
1819       g_signal_handler_disconnect (old_settings, toolbar->icon_size_connection);
1820       
1821       g_object_unref (old_settings);
1822     }
1823   
1824   if (settings)
1825     {
1826       toolbar->style_set_connection =
1827         g_signal_connect_swapped (settings,
1828                                   "notify::gtk-toolbar-style",
1829                                   G_CALLBACK (style_change_notify),
1830                                   toolbar);
1831       toolbar->icon_size_connection =
1832         g_signal_connect_swapped (settings,
1833                                   "notify::gtk-toolbar-icon-size",
1834                                   G_CALLBACK (icon_size_change_notify),
1835                                   toolbar);
1836       
1837       g_object_ref (settings);
1838       priv->settings = settings;
1839     }
1840   else
1841     priv->settings = NULL;
1842   
1843   style_change_notify (toolbar);
1844   icon_size_change_notify (toolbar);
1845 }
1846
1847 static int
1848 find_drop_index (GtkToolbar *toolbar,
1849                  gint        x,
1850                  gint        y)
1851 {
1852   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1853   GList *interesting_content;
1854   GList *list;
1855   GtkOrientation orientation;
1856   GtkTextDirection direction;
1857   gint best_distance = G_MAXINT;
1858   gint distance;
1859   gint cursor;
1860   gint pos;
1861   ToolbarContent *best_content;
1862   GtkAllocation allocation;
1863   
1864   /* list items we care about wrt. drag and drop */
1865   interesting_content = NULL;
1866   for (list = priv->content; list != NULL; list = list->next)
1867     {
1868       ToolbarContent *content = list->data;
1869       
1870       if (toolbar_content_get_state (content) == NORMAL)
1871         interesting_content = g_list_prepend (interesting_content, content);
1872     }
1873   interesting_content = g_list_reverse (interesting_content);
1874   
1875   if (!interesting_content)
1876     return 0;
1877   
1878   orientation = toolbar->orientation;
1879   direction = gtk_widget_get_direction (GTK_WIDGET (toolbar));
1880   
1881   /* distance to first interesting item */
1882   best_content = interesting_content->data;
1883   toolbar_content_get_allocation (best_content, &allocation);
1884   
1885   if (orientation == GTK_ORIENTATION_HORIZONTAL)
1886     {
1887       cursor = x;
1888       
1889       if (direction == GTK_TEXT_DIR_LTR)
1890         pos = allocation.x;
1891       else
1892         pos = allocation.x + allocation.width;
1893     }
1894   else
1895     {
1896       cursor = y;
1897       pos = allocation.y;
1898     }
1899   
1900   best_content = NULL;
1901   best_distance = ABS (pos - cursor);
1902   
1903   /* distance to far end of each item */
1904   for (list = interesting_content; list != NULL; list = list->next)
1905     {
1906       ToolbarContent *content = list->data;
1907       
1908       toolbar_content_get_allocation (content, &allocation);
1909       
1910       if (orientation == GTK_ORIENTATION_HORIZONTAL)
1911         {
1912           if (direction == GTK_TEXT_DIR_LTR)
1913             pos = allocation.x + allocation.width;
1914           else
1915             pos = allocation.x;
1916         }
1917       else
1918         {
1919           pos = allocation.y + allocation.height;
1920         }
1921       
1922       distance = ABS (pos - cursor);
1923       
1924       if (distance < best_distance)
1925         {
1926           best_distance = distance;
1927           best_content = content;
1928         }
1929     }
1930   
1931   g_list_free (interesting_content);
1932   
1933   if (!best_content)
1934     return 0;
1935   else
1936     return g_list_index (priv->content, best_content) + 1;
1937 }
1938
1939 static void
1940 reset_all_placeholders (GtkToolbar *toolbar)
1941 {
1942   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1943   GList *list;
1944   
1945   for (list = priv->content; list != NULL; list = list->next)
1946     {
1947       ToolbarContent *content = list->data;
1948       if (toolbar_content_is_placeholder (content))
1949         toolbar_content_set_disappearing (content, TRUE);
1950     }
1951 }
1952
1953 static gint
1954 physical_to_logical (GtkToolbar *toolbar,
1955                      gint        physical)
1956 {
1957   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1958   GList *list;
1959   int logical;
1960   
1961   g_assert (physical >= 0);
1962   
1963   logical = 0;
1964   for (list = priv->content; list && physical > 0; list = list->next)
1965     {
1966       ToolbarContent *content = list->data;
1967       
1968       if (!toolbar_content_is_placeholder (content))
1969         logical++;
1970       physical--;
1971     }
1972   
1973   g_assert (physical == 0);
1974   
1975   return logical;
1976 }
1977
1978 static gint
1979 logical_to_physical (GtkToolbar *toolbar,
1980                      gint        logical)
1981 {
1982   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
1983   GList *list;
1984   gint physical;
1985   
1986   g_assert (logical >= 0);
1987   
1988   physical = 0;
1989   for (list = priv->content; list; list = list->next)
1990     {
1991       ToolbarContent *content = list->data;
1992       
1993       if (!toolbar_content_is_placeholder (content))
1994         {
1995           if (logical == 0)
1996             break;
1997           logical--;
1998         }
1999       
2000       physical++;
2001     }
2002   
2003   g_assert (logical == 0);
2004   
2005   return physical;
2006 }
2007
2008 /**
2009  * gtk_toolbar_set_drop_highlight_item:
2010  * @toolbar: a #GtkToolbar
2011  * @tool_item: a #GtkToolItem, or %NULL to turn of highlighting
2012  * @index: a position on @toolbar
2013  * 
2014  * Highlights @toolbar to give an idea of what it would look like
2015  * if @item was added to @toolbar at position indicated by @index. If @item
2016  * is %NULL, highlighting is turned off. In that case @index is ignored.
2017  *
2018  * The @tool_item passed to this function must not be part of any widget
2019  * hierarchy. When an item is set as drop highlight item it can not
2020  * added to any widget hierarchy or used as highlight item for another
2021  * toolbar.
2022  * 
2023  * Since: 2.4
2024  **/
2025 void
2026 gtk_toolbar_set_drop_highlight_item (GtkToolbar  *toolbar,
2027                                      GtkToolItem *tool_item,
2028                                      gint         index)
2029 {
2030   ToolbarContent *content;
2031   GtkToolbarPrivate *priv;
2032   gint n_items;
2033   GtkRequisition requisition;
2034   GtkRequisition old_requisition;
2035   gboolean restart_sliding;
2036   
2037   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2038   g_return_if_fail (tool_item == NULL || GTK_IS_TOOL_ITEM (tool_item));
2039   
2040   gtk_toolbar_check_new_api (toolbar);
2041   
2042   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2043   
2044   if (!tool_item)
2045     {
2046       if (priv->highlight_tool_item)
2047         {
2048           gtk_widget_unparent (GTK_WIDGET (priv->highlight_tool_item));
2049           g_object_unref (priv->highlight_tool_item);
2050           priv->highlight_tool_item = NULL;
2051         }
2052       
2053       reset_all_placeholders (toolbar);
2054       gtk_toolbar_begin_sliding (toolbar);
2055       return;
2056     }
2057   
2058   n_items = gtk_toolbar_get_n_items (toolbar);
2059   if (index < 0 || index > n_items)
2060     index = n_items;
2061   
2062   if (tool_item != priv->highlight_tool_item)
2063     {
2064       if (priv->highlight_tool_item)
2065         g_object_unref (priv->highlight_tool_item);
2066       
2067       g_object_ref (tool_item);
2068       gtk_object_sink (GTK_OBJECT (tool_item));
2069       
2070       priv->highlight_tool_item = tool_item;
2071       
2072       gtk_widget_set_parent (GTK_WIDGET (priv->highlight_tool_item),
2073                              GTK_WIDGET (toolbar));
2074     }
2075   
2076   index = logical_to_physical (toolbar, index);
2077   
2078   content = g_list_nth_data (priv->content, index);
2079   
2080   if (index > 0)
2081     {
2082       ToolbarContent *prev_content;
2083       
2084       prev_content = g_list_nth_data (priv->content, index - 1);
2085       
2086       if (prev_content && toolbar_content_is_placeholder (prev_content))
2087         content = prev_content;
2088     }
2089   
2090   if (!content || !toolbar_content_is_placeholder (content))
2091     {
2092       GtkWidget *placeholder;
2093       
2094       placeholder = GTK_WIDGET (gtk_separator_tool_item_new ());
2095
2096       content = toolbar_content_new_tool_item (toolbar,
2097                                                GTK_TOOL_ITEM (placeholder),
2098                                                TRUE, index);
2099       gtk_widget_show (placeholder);
2100     }
2101   
2102   g_assert (content);
2103   g_assert (toolbar_content_is_placeholder (content));
2104   
2105   gtk_widget_size_request (GTK_WIDGET (priv->highlight_tool_item),
2106                            &requisition);
2107
2108   
2109   restart_sliding = FALSE;
2110   toolbar_content_size_request (content, toolbar, &old_requisition);
2111   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2112     {
2113       requisition.height = -1;
2114       if (requisition.width != old_requisition.width)
2115         restart_sliding = TRUE;
2116     }
2117   else
2118     {
2119       requisition.width = -1;
2120       if (requisition.height != old_requisition.height)
2121         restart_sliding = TRUE;
2122     }
2123
2124   if (toolbar_content_disappearing (content))
2125     restart_sliding = TRUE;
2126   
2127   reset_all_placeholders (toolbar);
2128   toolbar_content_set_disappearing (content, FALSE);
2129   
2130   toolbar_content_set_size_request (content,
2131                                     requisition.width, requisition.height);
2132   
2133   if (restart_sliding)
2134     gtk_toolbar_begin_sliding (toolbar);
2135 }
2136
2137 static void
2138 gtk_toolbar_get_child_property (GtkContainer *container,
2139                                 GtkWidget    *child,
2140                                 guint         property_id,
2141                                 GValue       *value,
2142                                 GParamSpec   *pspec)
2143 {
2144   GtkToolItem *item = GTK_TOOL_ITEM (child);
2145   
2146   switch (property_id)
2147     {
2148     case CHILD_PROP_HOMOGENEOUS:
2149       g_value_set_boolean (value, gtk_tool_item_get_homogeneous (item));
2150       break;
2151       
2152     case CHILD_PROP_EXPAND:
2153       g_value_set_boolean (value, gtk_tool_item_get_expand (item));
2154       break;
2155       
2156     default:
2157       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2158       break;
2159     }
2160 }
2161
2162 static void
2163 gtk_toolbar_set_child_property (GtkContainer *container,
2164                                 GtkWidget    *child,
2165                                 guint         property_id,
2166                                 const GValue *value,
2167                                 GParamSpec   *pspec)
2168 {
2169   switch (property_id)
2170     {
2171     case CHILD_PROP_HOMOGENEOUS:
2172       gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2173       break;
2174       
2175     case CHILD_PROP_EXPAND:
2176       gtk_tool_item_set_expand (GTK_TOOL_ITEM (child), g_value_get_boolean (value));
2177       break;
2178       
2179     default:
2180       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2181       break;
2182     }
2183 }
2184
2185 static void
2186 gtk_toolbar_show_all (GtkWidget *widget)
2187 {
2188   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
2189   GList *list;
2190
2191   for (list = priv->content; list != NULL; list = list->next)
2192     {
2193       ToolbarContent *content = list->data;
2194       
2195       toolbar_content_show_all (content);
2196     }
2197   
2198   gtk_widget_show (widget);
2199 }
2200
2201 static void
2202 gtk_toolbar_hide_all (GtkWidget *widget)
2203 {
2204   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (widget);
2205   GList *list;
2206
2207   for (list = priv->content; list != NULL; list = list->next)
2208     {
2209       ToolbarContent *content = list->data;
2210       
2211       toolbar_content_hide_all (content);
2212     }
2213
2214   gtk_widget_hide (widget);
2215 }
2216
2217 static void
2218 gtk_toolbar_add (GtkContainer *container,
2219                  GtkWidget    *widget)
2220 {
2221   GtkToolbar *toolbar;
2222   
2223   g_return_if_fail (GTK_IS_TOOLBAR (container));
2224   g_return_if_fail (widget != NULL);
2225   
2226   toolbar = GTK_TOOLBAR (container);
2227   
2228   if (GTK_IS_TOOL_ITEM (widget))
2229     gtk_toolbar_insert (toolbar, GTK_TOOL_ITEM (widget), -1);
2230   else
2231     gtk_toolbar_append_widget (toolbar, widget, NULL, NULL);
2232 }
2233
2234 static void
2235 gtk_toolbar_remove (GtkContainer *container,
2236                     GtkWidget    *widget)
2237 {
2238   GtkToolbar *toolbar;
2239   GtkToolbarPrivate *priv;
2240   ToolbarContent *content_to_remove;
2241   GList *list;
2242   
2243   g_return_if_fail (GTK_IS_TOOLBAR (container));
2244   g_return_if_fail (GTK_IS_WIDGET (widget));
2245   
2246   toolbar = GTK_TOOLBAR (container);
2247   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2248   
2249   content_to_remove = NULL;
2250   for (list = priv->content; list != NULL; list = list->next)
2251     {
2252       ToolbarContent *content = list->data;
2253       GtkWidget *child;
2254       
2255       child = toolbar_content_get_widget (content);
2256       if (child && child == widget)
2257         {
2258           content_to_remove = content;
2259           break;
2260         }
2261     }
2262   
2263   g_return_if_fail (content_to_remove != NULL);
2264   
2265   toolbar_content_remove (content_to_remove, toolbar);
2266   toolbar_content_free (content_to_remove);
2267 }
2268
2269 static void
2270 gtk_toolbar_forall (GtkContainer *container,
2271                     gboolean      include_internals,
2272                     GtkCallback   callback,
2273                     gpointer      callback_data)
2274 {
2275   GtkToolbar *toolbar = GTK_TOOLBAR (container);
2276   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2277   GList *list;
2278   
2279   g_return_if_fail (callback != NULL);
2280   
2281   list = priv->content;
2282   while (list)
2283     {
2284       ToolbarContent *content = list->data;
2285       GList *next = list->next;
2286       
2287       if (include_internals || !toolbar_content_is_placeholder (content))
2288         {
2289           GtkWidget *child = toolbar_content_get_widget (content);
2290           
2291           if (child)
2292             (*callback) (child, callback_data);
2293         }
2294       
2295       list = next;
2296     }
2297   
2298   if (include_internals)
2299     (* callback) (priv->arrow_button, callback_data);
2300 }
2301
2302 static GType
2303 gtk_toolbar_child_type (GtkContainer *container)
2304 {
2305   return GTK_TYPE_TOOL_ITEM;
2306 }
2307
2308 static void
2309 gtk_toolbar_reconfigured (GtkToolbar *toolbar)
2310 {
2311   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2312   GList *list;
2313   
2314   list = priv->content;
2315   while (list)
2316     {
2317       ToolbarContent *content = list->data;
2318       GList *next = list->next;
2319       
2320       toolbar_content_toolbar_reconfigured (content, toolbar);
2321       
2322       list = next;
2323     }
2324 }
2325
2326 static void
2327 gtk_toolbar_orientation_changed (GtkToolbar    *toolbar,
2328                                  GtkOrientation orientation)
2329 {
2330   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2331   if (toolbar->orientation != orientation)
2332     {
2333       toolbar->orientation = orientation;
2334       
2335       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2336         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
2337       else
2338         gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
2339       
2340       gtk_toolbar_reconfigured (toolbar);
2341       
2342       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2343       g_object_notify (G_OBJECT (toolbar), "orientation");
2344     }
2345 }
2346
2347 static void
2348 gtk_toolbar_real_style_changed (GtkToolbar     *toolbar,
2349                                 GtkToolbarStyle style)
2350 {
2351   if (toolbar->style != style)
2352     {
2353       toolbar->style = style;
2354       
2355       gtk_toolbar_reconfigured (toolbar);
2356       
2357       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
2358       g_object_notify (G_OBJECT (toolbar), "toolbar_style");
2359     }
2360 }
2361
2362 static void
2363 menu_position_func (GtkMenu  *menu,
2364                     gint     *x,
2365                     gint     *y,
2366                     gboolean *push_in,
2367                     gpointer  user_data)
2368 {
2369   GtkToolbar *toolbar = GTK_TOOLBAR (user_data);
2370   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2371   GtkRequisition req;
2372   GtkRequisition menu_req;
2373   
2374   gdk_window_get_origin (GTK_BUTTON (priv->arrow_button)->event_window, x, y);
2375   gtk_widget_size_request (priv->arrow_button, &req);
2376   gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
2377   
2378   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
2379     {
2380       *y += priv->arrow_button->allocation.height;
2381       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2382         *x += priv->arrow_button->allocation.width - req.width;
2383       else 
2384         *x += req.width - menu_req.width;
2385     }
2386   else 
2387     {
2388       if (gtk_widget_get_direction (GTK_WIDGET (toolbar)) == GTK_TEXT_DIR_LTR) 
2389         *x += priv->arrow_button->allocation.width;
2390       else 
2391         *x -= menu_req.width;
2392       *y += priv->arrow_button->allocation.height - req.height;      
2393     }
2394   
2395   *push_in = TRUE;
2396 }
2397
2398 static void
2399 menu_deactivated (GtkWidget  *menu,
2400                   GtkToolbar *toolbar)
2401 {
2402   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2403   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->arrow_button), FALSE);
2404 }
2405
2406 static void
2407 menu_detached (GtkWidget  *toolbar,
2408                GtkMenu    *menu)
2409 {
2410   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2411   priv->menu = NULL;
2412 }
2413
2414 static void
2415 remove_item (GtkWidget *menu_item,
2416              gpointer   data)
2417 {
2418   gtk_container_remove (GTK_CONTAINER (menu_item->parent), menu_item);
2419 }
2420
2421 static void
2422 show_menu (GtkToolbar     *toolbar,
2423            GdkEventButton *event)
2424 {
2425   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2426   GList *list;
2427   
2428   if (priv->menu)
2429     {
2430       gtk_container_foreach (GTK_CONTAINER (priv->menu), remove_item, NULL);
2431       gtk_widget_destroy (GTK_WIDGET (priv->menu));
2432     }
2433
2434   priv->menu = GTK_MENU (gtk_menu_new ());
2435   gtk_menu_attach_to_widget (priv->menu,
2436                              GTK_WIDGET (toolbar),
2437                              menu_detached);
2438   g_signal_connect (priv->menu, "deactivate", G_CALLBACK (menu_deactivated), toolbar);
2439
2440   for (list = priv->content; list != NULL; list = list->next)
2441     {
2442       ToolbarContent *content = list->data;
2443       
2444       if (toolbar_content_get_state (content) == OVERFLOWN &&
2445           !toolbar_content_is_placeholder (content))
2446         {
2447           GtkWidget *menu_item = toolbar_content_retrieve_menu_item (content);
2448           
2449           if (menu_item)
2450             {
2451               g_assert (GTK_IS_MENU_ITEM (menu_item));
2452               gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), menu_item);
2453             }
2454         }
2455     }
2456
2457   gtk_widget_show_all (GTK_WIDGET (priv->menu));
2458
2459   gtk_menu_popup (priv->menu, NULL, NULL,
2460                   menu_position_func, toolbar,
2461                   event? event->button : 0,
2462                   event? event->time : gtk_get_current_event_time());
2463 }
2464
2465 static void
2466 gtk_toolbar_arrow_button_clicked (GtkWidget  *button,
2467                                   GtkToolbar *toolbar)
2468 {
2469   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);  
2470   
2471   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->arrow_button)) &&
2472       (!priv->menu || !GTK_WIDGET_VISIBLE (GTK_WIDGET (priv->menu))))
2473     {
2474       /* We only get here when the button is clicked with the keybaord,
2475        * because mouse button presses result in the menu being shown so
2476        * that priv->menu would be non-NULL and visible.
2477        */
2478       show_menu (toolbar, NULL);
2479       gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->menu), FALSE);
2480     }
2481 }
2482
2483 static gboolean
2484 gtk_toolbar_arrow_button_press (GtkWidget      *button,
2485                                 GdkEventButton *event,
2486                                 GtkToolbar     *toolbar)
2487 {
2488   show_menu (toolbar, event);
2489   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2490   
2491   return TRUE;
2492 }
2493
2494 static gboolean
2495 gtk_toolbar_button_press (GtkWidget      *toolbar,
2496                           GdkEventButton *event)
2497 {
2498   if (event->button == 3)
2499     {
2500       gboolean return_value;
2501       
2502       g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2503                      (int)event->x_root, (int)event->y_root, event->button,
2504                      &return_value);
2505       
2506       return return_value;
2507     }
2508   
2509   return FALSE;
2510 }
2511
2512 static gboolean
2513 gtk_toolbar_popup_menu (GtkWidget *toolbar)
2514 {
2515   gboolean return_value;
2516   /* This function is the handler for the "popup menu" keybinding,
2517    * ie., it is called when the user presses Shift F10
2518    */
2519   g_signal_emit (toolbar, toolbar_signals[POPUP_CONTEXT_MENU], 0,
2520                  -1, -1, -1, &return_value);
2521   
2522   return return_value;
2523 }
2524
2525 /**
2526  * gtk_toolbar_new:
2527  * 
2528  * Creates a new toolbar. 
2529  
2530  * Return Value: the newly-created toolbar.
2531  **/
2532 GtkWidget *
2533 gtk_toolbar_new (void)
2534 {
2535   GtkToolbar *toolbar;
2536   
2537   toolbar = g_object_new (GTK_TYPE_TOOLBAR, NULL);
2538   
2539   return GTK_WIDGET (toolbar);
2540 }
2541
2542 /**
2543  * gtk_toolbar_insert:
2544  * @toolbar: a #GtkToolbar
2545  * @item: a #GtkToolItem
2546  * @pos: the position of the new item
2547  *
2548  * Insert a #GtkToolItem into the toolbar at position @pos. If @pos is
2549  * 0 the item is prepended to the start of the toolbar. If @pos is
2550  * negative, the item is appended to the end of the toolbar.
2551  *
2552  * Since: 2.4
2553  **/
2554 void
2555 gtk_toolbar_insert (GtkToolbar  *toolbar,
2556                     GtkToolItem *item,
2557                     gint         pos)
2558 {
2559   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2560   g_return_if_fail (GTK_IS_TOOL_ITEM (item));
2561   
2562   if (!gtk_toolbar_check_new_api (toolbar))
2563     return;
2564   
2565   if (pos >= 0)
2566     pos = logical_to_physical (toolbar, pos);
2567
2568   toolbar_content_new_tool_item (toolbar, item, FALSE, pos);
2569 }
2570
2571 /**
2572  * gtk_toolbar_get_item_index:
2573  * @toolbar: a #GtkToolbar
2574  * @item: a #GtkToolItem that is a child of @toolbar
2575  * 
2576  * Returns the position of @item on the toolbar, starting from 0.
2577  * It is an error if @item is not a child of the toolbar.
2578  * 
2579  * Return value: the position of item on the toolbar.
2580  * 
2581  * Since: 2.4
2582  **/
2583 gint
2584 gtk_toolbar_get_item_index (GtkToolbar  *toolbar,
2585                             GtkToolItem *item)
2586 {
2587   GtkToolbarPrivate *priv;
2588   GList *list;
2589   int n;
2590   
2591   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2592   g_return_val_if_fail (GTK_IS_TOOL_ITEM (item), -1);
2593   g_return_val_if_fail (GTK_WIDGET (item)->parent == GTK_WIDGET (toolbar), -1);
2594   
2595   if (!gtk_toolbar_check_new_api (toolbar))
2596     return -1;
2597   
2598   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2599   
2600   n = 0;
2601   for (list = priv->content; list != NULL; list = list->next)
2602     {
2603       ToolbarContent *content = list->data;
2604       GtkWidget *widget;
2605       
2606       widget = toolbar_content_get_widget (content);
2607       
2608       if (item == GTK_TOOL_ITEM (widget))
2609         break;
2610       
2611       ++n;
2612     }
2613   
2614   return physical_to_logical (toolbar, n);
2615 }
2616
2617 /**
2618  * gtk_toolbar_set_orientation:
2619  * @toolbar: a #GtkToolbar.
2620  * @orientation: a new #GtkOrientation.
2621  * 
2622  * Sets whether a toolbar should appear horizontally or vertically.
2623  **/
2624 void
2625 gtk_toolbar_set_orientation (GtkToolbar     *toolbar,
2626                              GtkOrientation  orientation)
2627 {
2628   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2629   
2630   g_signal_emit (toolbar, toolbar_signals[ORIENTATION_CHANGED], 0, orientation);
2631 }
2632
2633 /**
2634  * gtk_toolbar_get_orientation:
2635  * @toolbar: a #GtkToolbar
2636  * 
2637  * Retrieves the current orientation of the toolbar. See
2638  * gtk_toolbar_set_orientation().
2639  *
2640  * Return value: the orientation
2641  **/
2642 GtkOrientation
2643 gtk_toolbar_get_orientation (GtkToolbar *toolbar)
2644 {
2645   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL);
2646   
2647   return toolbar->orientation;
2648 }
2649
2650 /**
2651  * gtk_toolbar_set_style:
2652  * @toolbar: a #GtkToolbar.
2653  * @style: the new style for @toolbar.
2654  * 
2655  * Alters the view of @toolbar to display either icons only, text only, or both.
2656  **/
2657 void
2658 gtk_toolbar_set_style (GtkToolbar      *toolbar,
2659                        GtkToolbarStyle  style)
2660 {
2661   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2662   
2663   toolbar->style_set = TRUE;  
2664   g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2665 }
2666
2667 /**
2668  * gtk_toolbar_get_style:
2669  * @toolbar: a #GtkToolbar
2670  *
2671  * Retrieves whether the toolbar has text, icons, or both . See
2672  * gtk_toolbar_set_style().
2673  
2674  * Return value: the current style of @toolbar
2675  **/
2676 GtkToolbarStyle
2677 gtk_toolbar_get_style (GtkToolbar *toolbar)
2678 {
2679   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE);
2680   
2681   return toolbar->style;
2682 }
2683
2684 /**
2685  * gtk_toolbar_unset_style:
2686  * @toolbar: a #GtkToolbar
2687  * 
2688  * Unsets a toolbar style set with gtk_toolbar_set_style(), so that
2689  * user preferences will be used to determine the toolbar style.
2690  **/
2691 void
2692 gtk_toolbar_unset_style (GtkToolbar *toolbar)
2693 {
2694   GtkToolbarStyle style;
2695   
2696   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2697   
2698   if (toolbar->style_set)
2699     {
2700       GtkSettings *settings = toolbar_get_settings (toolbar);
2701       
2702       if (settings)
2703         g_object_get (settings,
2704                       "gtk-toolbar-style", &style,
2705                       NULL);
2706       else
2707         style = DEFAULT_TOOLBAR_STYLE;
2708       
2709       if (style != toolbar->style)
2710         g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
2711       
2712       toolbar->style_set = FALSE;
2713     }
2714 }
2715
2716 /**
2717  * gtk_toolbar_set_tooltips:
2718  * @toolbar: a #GtkToolbar.
2719  * @enable: set to %FALSE to disable the tooltips, or %TRUE to enable them.
2720  * 
2721  * Sets if the tooltips of a toolbar should be active or not.
2722  **/
2723 void
2724 gtk_toolbar_set_tooltips (GtkToolbar *toolbar,
2725                           gboolean    enable)
2726 {
2727   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2728   
2729   if (enable)
2730     gtk_tooltips_enable (toolbar->tooltips);
2731   else
2732     gtk_tooltips_disable (toolbar->tooltips);
2733 }
2734
2735 /**
2736  * gtk_toolbar_get_tooltips:
2737  * @toolbar: a #GtkToolbar
2738  *
2739  * Retrieves whether tooltips are enabled. See
2740  * gtk_toolbar_set_tooltips().
2741  *
2742  * Return value: %TRUE if tooltips are enabled
2743  **/
2744 gboolean
2745 gtk_toolbar_get_tooltips (GtkToolbar *toolbar)
2746 {
2747   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2748   
2749   return toolbar->tooltips->enabled;
2750 }
2751
2752 /**
2753  * gtk_toolbar_get_n_items:
2754  * @toolbar: a #GtkToolbar
2755  * 
2756  * Returns the number of items on the toolbar.
2757  * 
2758  * Return value: the number of items on the toolbar
2759  * 
2760  * Since: 2.4
2761  **/
2762 gint
2763 gtk_toolbar_get_n_items (GtkToolbar *toolbar)
2764 {
2765   GtkToolbarPrivate *priv;
2766   
2767   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2768   
2769   if (!gtk_toolbar_check_new_api (toolbar))
2770     return -1;
2771   
2772   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2773   
2774   return physical_to_logical (toolbar, g_list_length (priv->content));
2775 }
2776
2777 /**
2778  * gtk_toolbar_get_nth_item:
2779  * @toolbar: a #GtkToolbar
2780  * @n: A position on the toolbar
2781  *
2782  * Returns the @n<!-- -->'s item on @toolbar, or %NULL if the
2783  * toolbar does not contain an @n<!-- -->'th item.
2784  * 
2785  * Return value: The @n<!-- -->'th #GtkToolItem on @toolbar, or %NULL if there
2786  * isn't an @n<!-- -->th item.
2787  * 
2788  * Since: 2.4
2789  **/
2790 GtkToolItem *
2791 gtk_toolbar_get_nth_item (GtkToolbar *toolbar,
2792                           gint        n)
2793 {
2794   GtkToolbarPrivate *priv;
2795   ToolbarContent *content;
2796   gint n_items;
2797   
2798   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
2799   
2800   if (!gtk_toolbar_check_new_api (toolbar))
2801     return NULL;
2802   
2803   n_items = gtk_toolbar_get_n_items (toolbar);
2804   
2805   if (n < 0 || n >= n_items)
2806     return NULL;
2807   
2808   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2809   
2810   content = g_list_nth_data (priv->content, logical_to_physical (toolbar, n));
2811   
2812   g_assert (content);
2813   g_assert (!toolbar_content_is_placeholder (content));
2814   
2815   return GTK_TOOL_ITEM (toolbar_content_get_widget (content));
2816 }
2817
2818 /**
2819  * gtk_toolbar_get_icon_size:
2820  * @toolbar: a #GtkToolbar
2821  *
2822  * Retrieves the icon size fo the toolbar. See gtk_toolbar_set_icon_size().
2823  *
2824  * Return value: the current icon size for the icons on the toolbar.
2825  **/
2826 GtkIconSize
2827 gtk_toolbar_get_icon_size (GtkToolbar *toolbar)
2828 {
2829   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_ICON_SIZE);
2830   
2831   return toolbar->icon_size;
2832 }
2833
2834 /**
2835  * gtk_toolbar_get_relief_style:
2836  * @toolbar: a #GtkToolbar
2837  * 
2838  * Returns the relief style of buttons on @toolbar. See
2839  * gtk_button_set_relief().
2840  * 
2841  * Return value: The relief style of buttons on @toolbar.
2842  * 
2843  * Since: 2.4
2844  **/
2845 GtkReliefStyle
2846 gtk_toolbar_get_relief_style (GtkToolbar *toolbar)
2847 {
2848   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_RELIEF_NONE);
2849   
2850   return get_button_relief (toolbar);
2851 }
2852
2853 /**
2854  * gtk_toolbar_set_show_arrow:
2855  * @toolbar: a #GtkToolbar
2856  * @show_arrow: Whether to show an overflow menu
2857  * 
2858  * Sets whether to show an overflow menu when
2859  * @toolbar doesn't have room for all items on it. If %TRUE,
2860  * items that there are not room are available through an
2861  * overflow menu.
2862  * 
2863  * Since: 2.4
2864  **/
2865 void
2866 gtk_toolbar_set_show_arrow (GtkToolbar *toolbar,
2867                             gboolean    show_arrow)
2868 {
2869   GtkToolbarPrivate *priv;
2870   
2871   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2872   
2873   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2874   show_arrow = show_arrow != FALSE;
2875   
2876   if (priv->show_arrow != show_arrow)
2877     {
2878       priv->show_arrow = show_arrow;
2879       
2880       if (!priv->show_arrow)
2881         gtk_widget_hide (priv->arrow_button);
2882       
2883       gtk_widget_queue_resize (GTK_WIDGET (toolbar));      
2884       g_object_notify (G_OBJECT (toolbar), "show_arrow");
2885     }
2886 }
2887
2888 /**
2889  * gtk_toolbar_get_show_arrow:
2890  * @toolbar: a #GtkToolbar
2891  * 
2892  * Returns whether the toolbar has an overflow menu.
2893  * See gtk_toolbar_set_show_arrow()
2894  * 
2895  * Return value: 
2896  * 
2897  * Since: 2.4
2898  **/
2899 gboolean
2900 gtk_toolbar_get_show_arrow (GtkToolbar *toolbar)
2901 {
2902   GtkToolbarPrivate *priv;
2903   
2904   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
2905   
2906   if (!gtk_toolbar_check_new_api (toolbar))
2907     return FALSE;
2908   
2909   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2910   
2911   return priv->show_arrow;
2912 }
2913
2914 /**
2915  * gtk_toolbar_get_drop_index:
2916  * @toolbar: a #GtkToolbar
2917  * @x: x coordinate of a point on the toolbar
2918  * @y: y coordinate of a point on the toolbar
2919  *
2920  * Returns the position corresponding to the indicated point on
2921  * @toolbar. This is useful when dragging items to the toolbar:
2922  * this function returns the position a new item should be
2923  * inserted.
2924  *
2925  * @x and @y are in @toolbar coordinates.
2926  * 
2927  * Return value: The position corresponding to the point (@x, @y) on the toolbar.
2928  * 
2929  * Since: 2.4
2930  **/
2931 gint
2932 gtk_toolbar_get_drop_index (GtkToolbar *toolbar,
2933                             gint        x,
2934                             gint        y)
2935 {
2936   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), -1);
2937   
2938   if (!gtk_toolbar_check_new_api (toolbar))
2939     return -1;
2940   
2941   return physical_to_logical (toolbar, find_drop_index (toolbar, x, y));
2942 }
2943
2944 static void
2945 gtk_toolbar_finalize (GObject *object)
2946 {
2947   GList *list;
2948   GtkToolbar *toolbar = GTK_TOOLBAR (object);
2949   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
2950   
2951   if (toolbar->tooltips)
2952     g_object_unref (toolbar->tooltips);
2953   
2954   for (list = priv->content; list != NULL; list = list->next)
2955     {
2956       ToolbarContent *content = list->data;
2957
2958       toolbar_content_free (content);
2959     }
2960   
2961   g_list_free (priv->content);
2962   g_list_free (toolbar->children);
2963   
2964   g_timer_destroy (priv->timer);
2965   
2966   if (priv->menu)
2967     gtk_widget_destroy (GTK_WIDGET (priv->menu));
2968   
2969   if (priv->idle_id)
2970     g_source_remove (priv->idle_id);
2971   
2972   G_OBJECT_CLASS (parent_class)->finalize (object);
2973 }
2974
2975 /*
2976  * Deprecated API
2977  */
2978
2979 /**
2980  * gtk_toolbar_set_icon_size:
2981  * @toolbar: A #GtkToolbar
2982  * @icon_size: The #GtkIconSize that stock icons in the toolbar shall have.
2983  *
2984  * This function sets the size of stock icons in the toolbar. You
2985  * can call it both before you add the icons and after they've been
2986  * added. The size you set will override user preferences for the default
2987  * icon size.
2988  **/
2989 void
2990 gtk_toolbar_set_icon_size (GtkToolbar  *toolbar,
2991                            GtkIconSize  icon_size)
2992 {
2993   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
2994   
2995   toolbar->icon_size_set = TRUE;
2996   
2997   if (toolbar->icon_size == icon_size)
2998     return;
2999   
3000   toolbar->icon_size = icon_size;
3001   
3002   gtk_toolbar_reconfigured (toolbar);
3003   
3004   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3005 }
3006
3007 /**
3008  * gtk_toolbar_unset_icon_size:
3009  * @toolbar: a #GtkToolbar
3010  * 
3011  * Unsets toolbar icon size set with gtk_toolbar_set_icon_size(), so that
3012  * user preferences will be used to determine the icon size.
3013  **/
3014 void
3015 gtk_toolbar_unset_icon_size (GtkToolbar *toolbar)
3016 {
3017   GtkIconSize size;
3018   
3019   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3020   
3021   if (toolbar->icon_size_set)
3022     {
3023       GtkSettings *settings = toolbar_get_settings (toolbar);
3024       
3025       if (settings)
3026         {
3027           g_object_get (settings,
3028                         "gtk-toolbar-icon-size", &size,
3029                         NULL);
3030         }
3031       else
3032         size = DEFAULT_ICON_SIZE;
3033       
3034       if (size != toolbar->icon_size)
3035         gtk_toolbar_set_icon_size (toolbar, size);
3036       
3037       toolbar->icon_size_set = FALSE;
3038     }
3039 }
3040
3041 /**
3042  * gtk_toolbar_append_item:
3043  * @toolbar: a #GtkToolbar.
3044  * @text: give your toolbar button a label.
3045  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3046  * @tooltip_private_text: use with #GtkTipsQuery.
3047  * @icon: a #GtkWidget that should be used as the button's icon.
3048  * @callback: the function to be executed when the button is pressed.
3049  * @user_data: a pointer to any data you wish to be passed to the callback.
3050  * 
3051  * Inserts a new item into the toolbar. You must specify the position
3052  * in the toolbar where it will be inserted.
3053  *
3054  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3055  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3056  *
3057  * Return value: the new toolbar item as a #GtkWidget.
3058  **/
3059 GtkWidget *
3060 gtk_toolbar_append_item (GtkToolbar    *toolbar,
3061                          const char    *text,
3062                          const char    *tooltip_text,
3063                          const char    *tooltip_private_text,
3064                          GtkWidget     *icon,
3065                          GtkSignalFunc  callback,
3066                          gpointer       user_data)
3067 {
3068   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3069                                      NULL, text,
3070                                      tooltip_text, tooltip_private_text,
3071                                      icon, callback, user_data,
3072                                      toolbar->num_children);
3073 }
3074
3075 /**
3076  * gtk_toolbar_prepend_item:
3077  * @toolbar: a #GtkToolbar.
3078  * @text: give your toolbar button a label.
3079  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3080  * @tooltip_private_text: use with #GtkTipsQuery.
3081  * @icon: a #GtkWidget that should be used as the button's icon.
3082  * @callback: the function to be executed when the button is pressed.
3083  * @user_data: a pointer to any data you wish to be passed to the callback.
3084  * 
3085  * Adds a new button to the beginning (top or left edges) of the given toolbar.
3086  *
3087  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3088  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3089  *
3090  * Return value: the new toolbar item as a #GtkWidget.
3091  **/
3092 GtkWidget *
3093 gtk_toolbar_prepend_item (GtkToolbar    *toolbar,
3094                           const char    *text,
3095                           const char    *tooltip_text,
3096                           const char    *tooltip_private_text,
3097                           GtkWidget     *icon,
3098                           GtkSignalFunc  callback,
3099                           gpointer       user_data)
3100 {
3101   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3102                                      NULL, text,
3103                                      tooltip_text, tooltip_private_text,
3104                                      icon, callback, user_data,
3105                                      0);
3106 }
3107
3108 /**
3109  * gtk_toolbar_insert_item:
3110  * @toolbar: a #GtkToolbar.
3111  * @text: give your toolbar button a label.
3112  * @tooltip_text: a string that appears when the user holds the mouse over this item.
3113  * @tooltip_private_text: use with #GtkTipsQuery.
3114  * @icon: a #GtkWidget that should be used as the button's icon.
3115  * @callback: the function to be executed when the button is pressed.
3116  * @user_data: a pointer to any data you wish to be passed to the callback.
3117  * @position: the number of widgets to insert this item after.
3118  * 
3119  * Inserts a new item into the toolbar. You must specify the position in the
3120  * toolbar where it will be inserted.
3121  *
3122  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3123  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3124  *
3125  * Return value: the new toolbar item as a #GtkWidget.
3126  **/
3127 GtkWidget *
3128 gtk_toolbar_insert_item (GtkToolbar    *toolbar,
3129                          const char    *text,
3130                          const char    *tooltip_text,
3131                          const char    *tooltip_private_text,
3132                          GtkWidget     *icon,
3133                          GtkSignalFunc  callback,
3134                          gpointer       user_data,
3135                          gint           position)
3136 {
3137   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3138                                      NULL, text,
3139                                      tooltip_text, tooltip_private_text,
3140                                      icon, callback, user_data,
3141                                      position);
3142 }
3143
3144 /**
3145  * gtk_toolbar_insert_stock:
3146  * @toolbar: A #GtkToolbar
3147  * @stock_id: The id of the stock item you want to insert
3148  * @tooltip_text: The text in the tooltip of the toolbar button
3149  * @tooltip_private_text: The private text of the tooltip
3150  * @callback: The callback called when the toolbar button is clicked.
3151  * @user_data: user data passed to callback
3152  * @position: The position the button shall be inserted at.
3153  *            -1 means at the end.
3154  *
3155  * Inserts a stock item at the specified position of the toolbar.  If
3156  * @stock_id is not a known stock item ID, it's inserted verbatim,
3157  * except that underscores used to mark mnemonics are removed.
3158  *
3159  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3160  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3161  *
3162  * Returns: the inserted widget
3163  */
3164 GtkWidget*
3165 gtk_toolbar_insert_stock (GtkToolbar      *toolbar,
3166                           const gchar     *stock_id,
3167                           const char      *tooltip_text,
3168                           const char      *tooltip_private_text,
3169                           GtkSignalFunc    callback,
3170                           gpointer         user_data,
3171                           gint             position)
3172 {
3173   return internal_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
3174                                   NULL, stock_id,
3175                                   tooltip_text, tooltip_private_text,
3176                                   NULL, callback, user_data,
3177                                   position, TRUE);
3178 }
3179
3180 /**
3181  * gtk_toolbar_append_space:
3182  * @toolbar: a #GtkToolbar.
3183  * 
3184  * Adds a new space to the end of the toolbar.
3185  **/
3186 void
3187 gtk_toolbar_append_space (GtkToolbar *toolbar)
3188 {
3189   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3190                               NULL, NULL,
3191                               NULL, NULL,
3192                               NULL, NULL, NULL,
3193                               toolbar->num_children);
3194 }
3195
3196 /**
3197  * gtk_toolbar_prepend_space:
3198  * @toolbar: a #GtkToolbar.
3199  * 
3200  * Adds a new space to the beginning of the toolbar.
3201  **/
3202 void
3203 gtk_toolbar_prepend_space (GtkToolbar *toolbar)
3204 {
3205   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3206                               NULL, NULL,
3207                               NULL, NULL,
3208                               NULL, NULL, NULL,
3209                               0);
3210 }
3211
3212 /**
3213  * gtk_toolbar_insert_space:
3214  * @toolbar: a #GtkToolbar
3215  * @position: the number of widgets after which a space should be inserted.
3216  * 
3217  * Inserts a new space in the toolbar at the specified position.
3218  **/
3219 void
3220 gtk_toolbar_insert_space (GtkToolbar *toolbar,
3221                           gint        position)
3222 {
3223   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
3224                               NULL, NULL,
3225                               NULL, NULL,
3226                               NULL, NULL, NULL,
3227                               position);
3228 }
3229
3230 /**
3231  * gtk_toolbar_remove_space:
3232  * @toolbar: a #GtkToolbar.
3233  * @position: the index of the space to remove.
3234  * 
3235  * Removes a space from the specified position.
3236  **/
3237 void
3238 gtk_toolbar_remove_space (GtkToolbar *toolbar,
3239                           gint        position)
3240 {
3241   GtkToolbarPrivate *priv;
3242   ToolbarContent *content;
3243   
3244   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
3245   
3246   if (!gtk_toolbar_check_old_api (toolbar))
3247     return;
3248   
3249   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3250   
3251   content = g_list_nth_data (priv->content, position);
3252   
3253   if (!content)
3254     {
3255       g_warning ("Toolbar position %d doesn't exist", position);
3256       return;
3257     }
3258   
3259   if (!toolbar_content_is_separator (content))
3260     {
3261       g_warning ("Toolbar position %d is not a space", position);
3262       return;
3263     }
3264   
3265   toolbar_content_remove (content, toolbar);
3266   toolbar_content_free (content);
3267 }
3268
3269 /**
3270  * gtk_toolbar_append_widget:
3271  * @toolbar: a #GtkToolbar.
3272  * @widget: a #GtkWidget to add to the toolbar. 
3273  * @tooltip_text: the element's tooltip.
3274  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3275  * 
3276  * Adds a widget to the end of the given toolbar.
3277  **/ 
3278 void
3279 gtk_toolbar_append_widget (GtkToolbar  *toolbar,
3280                            GtkWidget   *widget,
3281                            const gchar *tooltip_text,
3282                            const gchar *tooltip_private_text)
3283 {
3284   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3285                               widget, NULL,
3286                               tooltip_text, tooltip_private_text,
3287                               NULL, NULL, NULL,
3288                               toolbar->num_children);
3289 }
3290
3291 /**
3292  * gtk_toolbar_prepend_widget:
3293  * @toolbar: a #GtkToolbar.
3294  * @widget: a #GtkWidget to add to the toolbar. 
3295  * @tooltip_text: the element's tooltip.
3296  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3297  * 
3298  * Adds a widget to the beginning of the given toolbar.
3299  **/ 
3300 void
3301 gtk_toolbar_prepend_widget (GtkToolbar  *toolbar,
3302                             GtkWidget   *widget,
3303                             const gchar *tooltip_text,
3304                             const gchar *tooltip_private_text)
3305 {
3306   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3307                               widget, NULL,
3308                               tooltip_text, tooltip_private_text,
3309                               NULL, NULL, NULL,
3310                               0);
3311 }
3312
3313 /**
3314  * gtk_toolbar_insert_widget:
3315  * @toolbar: a #GtkToolbar.
3316  * @widget: a #GtkWidget to add to the toolbar. 
3317  * @tooltip_text: the element's tooltip.
3318  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3319  * @position: the number of widgets to insert this widget after.
3320  * 
3321  * Inserts a widget in the toolbar at the given position.
3322  **/ 
3323 void
3324 gtk_toolbar_insert_widget (GtkToolbar *toolbar,
3325                            GtkWidget  *widget,
3326                            const char *tooltip_text,
3327                            const char *tooltip_private_text,
3328                            gint        position)
3329 {
3330   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
3331                               widget, NULL,
3332                               tooltip_text, tooltip_private_text,
3333                               NULL, NULL, NULL,
3334                               position);
3335 }
3336
3337 /**
3338  * gtk_toolbar_append_element:
3339  * @toolbar: a #GtkToolbar.
3340  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3341  * @widget: a #GtkWidget, or %NULL.
3342  * @text: the element's label.
3343  * @tooltip_text: the element's tooltip.
3344  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3345  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3346  * @callback: the function to be executed when the button is pressed.
3347  * @user_data: any data you wish to pass to the callback.
3348  * 
3349  * Adds a new element to the end of a toolbar.
3350  * 
3351  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3352  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3353  * the radio group for the new element. In all other cases, @widget must
3354  * be %NULL.
3355  * 
3356  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3357  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3358  *
3359  * Return value: the new toolbar element as a #GtkWidget.
3360  **/
3361 GtkWidget*
3362 gtk_toolbar_append_element (GtkToolbar          *toolbar,
3363                             GtkToolbarChildType  type,
3364                             GtkWidget           *widget,
3365                             const char          *text,
3366                             const char          *tooltip_text,
3367                             const char          *tooltip_private_text,
3368                             GtkWidget           *icon,
3369                             GtkSignalFunc        callback,
3370                             gpointer             user_data)
3371 {
3372   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3373                                      tooltip_text, tooltip_private_text,
3374                                      icon, callback, user_data,
3375                                      toolbar->num_children);
3376 }
3377
3378 /**
3379  * gtk_toolbar_prepend_element:
3380  * @toolbar: a #GtkToolbar.
3381  * @type: a value of type #GtkToolbarChildType that determines what @widget will be.
3382  * @widget: a #GtkWidget, or %NULL
3383  * @text: the element's label.
3384  * @tooltip_text: the element's tooltip.
3385  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3386  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3387  * @callback: the function to be executed when the button is pressed.
3388  * @user_data: any data you wish to pass to the callback.
3389  *  
3390  * Adds a new element to the beginning of a toolbar.
3391  * 
3392  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3393  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3394  * the radio group for the new element. In all other cases, @widget must
3395  * be %NULL.
3396  * 
3397  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3398  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3399  *
3400  * Return value: the new toolbar element as a #GtkWidget.
3401  **/
3402 GtkWidget *
3403 gtk_toolbar_prepend_element (GtkToolbar          *toolbar,
3404                              GtkToolbarChildType  type,
3405                              GtkWidget           *widget,
3406                              const char          *text,
3407                              const char          *tooltip_text,
3408                              const char          *tooltip_private_text,
3409                              GtkWidget           *icon,
3410                              GtkSignalFunc        callback,
3411                              gpointer             user_data)
3412 {
3413   return gtk_toolbar_insert_element (toolbar, type, widget, text,
3414                                      tooltip_text, tooltip_private_text,
3415                                      icon, callback, user_data, 0);
3416 }
3417
3418 /**
3419  * gtk_toolbar_insert_element:
3420  * @toolbar: a #GtkToolbar.
3421  * @type: a value of type #GtkToolbarChildType that determines what @widget
3422  *   will be.
3423  * @widget: a #GtkWidget, or %NULL. 
3424  * @text: the element's label.
3425  * @tooltip_text: the element's tooltip.
3426  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
3427  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
3428  * @callback: the function to be executed when the button is pressed.
3429  * @user_data: any data you wish to pass to the callback.
3430  * @position: the number of widgets to insert this element after.
3431  *
3432  * Inserts a new element in the toolbar at the given position. 
3433  *
3434  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
3435  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
3436  * the radio group for the new element. In all other cases, @widget must
3437  * be %NULL.
3438  *
3439  * @callback must be a pointer to a function taking a #GtkWidget and a gpointer as
3440  * arguments. Use the GTK_SIGNAL_FUNC() to cast the function to #GtkSignalFunc.
3441  *
3442  * Return value: the new toolbar element as a #GtkWidget.
3443  **/
3444 GtkWidget *
3445 gtk_toolbar_insert_element (GtkToolbar          *toolbar,
3446                             GtkToolbarChildType  type,
3447                             GtkWidget           *widget,
3448                             const char          *text,
3449                             const char          *tooltip_text,
3450                             const char          *tooltip_private_text,
3451                             GtkWidget           *icon,
3452                             GtkSignalFunc        callback,
3453                             gpointer             user_data,
3454                             gint                 position)
3455 {
3456   return internal_insert_element (toolbar, type, widget, text,
3457                                   tooltip_text, tooltip_private_text,
3458                                   icon, callback, user_data, position, FALSE);
3459 }
3460
3461 static void
3462 set_child_packing_and_visibility(GtkToolbar      *toolbar,
3463                                  GtkToolbarChild *child)
3464 {
3465   GtkWidget *box;
3466   gboolean   expand;
3467
3468   box = gtk_bin_get_child (GTK_BIN (child->widget));
3469   
3470   g_return_if_fail (GTK_IS_BOX (box));
3471   
3472   if (child->label)
3473     {
3474       expand = (toolbar->style != GTK_TOOLBAR_BOTH);
3475       
3476       gtk_box_set_child_packing (GTK_BOX (box), child->label,
3477                                  expand, expand, 0, GTK_PACK_END);
3478       
3479       if (toolbar->style != GTK_TOOLBAR_ICONS)
3480         gtk_widget_show (child->label);
3481       else
3482         gtk_widget_hide (child->label);
3483     }
3484   
3485   if (child->icon)
3486     {
3487       expand = (toolbar->style != GTK_TOOLBAR_BOTH_HORIZ);
3488       
3489       gtk_box_set_child_packing (GTK_BOX (box), child->icon,
3490                                  expand, expand, 0, GTK_PACK_END);
3491       
3492       if (toolbar->style != GTK_TOOLBAR_TEXT)
3493         gtk_widget_show (child->icon);
3494       else
3495         gtk_widget_hide (child->icon);
3496     }
3497 }
3498
3499 static GtkWidget *
3500 internal_insert_element (GtkToolbar          *toolbar,
3501                          GtkToolbarChildType  type,
3502                          GtkWidget           *widget,
3503                          const char          *text,
3504                          const char          *tooltip_text,
3505                          const char          *tooltip_private_text,
3506                          GtkWidget           *icon,
3507                          GtkSignalFunc        callback,
3508                          gpointer             user_data,
3509                          gint                 position,
3510                          gboolean             use_stock)
3511 {
3512   GtkWidget *box;
3513   ToolbarContent *content;
3514   GtkToolbarPrivate *priv;
3515   char *free_me = NULL;
3516   gboolean is_button = FALSE;
3517
3518   GtkWidget *child_widget;
3519   GtkWidget *child_label;
3520   GtkWidget *child_icon;
3521
3522   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
3523   if (type == GTK_TOOLBAR_CHILD_WIDGET)
3524     g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
3525   else if (type != GTK_TOOLBAR_CHILD_RADIOBUTTON)
3526     g_return_val_if_fail (widget == NULL, NULL);
3527   
3528   if (!gtk_toolbar_check_old_api (toolbar))
3529     return NULL;
3530   
3531   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3532   
3533   child_widget = NULL;
3534   child_label = NULL;
3535   child_icon = NULL;
3536   
3537   switch (type)
3538     {
3539     case GTK_TOOLBAR_CHILD_SPACE:
3540       break;
3541       
3542     case GTK_TOOLBAR_CHILD_WIDGET:
3543       child_widget = widget;
3544       break;
3545       
3546     case GTK_TOOLBAR_CHILD_BUTTON:
3547     case GTK_TOOLBAR_CHILD_TOGGLEBUTTON:
3548     case GTK_TOOLBAR_CHILD_RADIOBUTTON:
3549       is_button = TRUE;
3550       if (type == GTK_TOOLBAR_CHILD_BUTTON)
3551         {
3552           child_widget = gtk_button_new ();
3553         }
3554       else if (type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
3555         {
3556           child_widget = gtk_toggle_button_new ();
3557           gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child_widget), FALSE);
3558         }
3559       else /* type == GTK_TOOLBAR_CHILD_RADIOBUTTON */
3560         {
3561           GSList *group = NULL;
3562
3563           if (widget)
3564             group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
3565           
3566           child_widget = gtk_radio_button_new (group);
3567           gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child_widget), FALSE);
3568         }
3569
3570       gtk_button_set_relief (GTK_BUTTON (child_widget), get_button_relief (toolbar));
3571       gtk_button_set_focus_on_click (GTK_BUTTON (child_widget), FALSE);
3572       
3573       if (callback)
3574         {
3575           g_signal_connect (child_widget, "clicked",
3576                             callback, user_data);
3577         }
3578       
3579       if (toolbar->style == GTK_TOOLBAR_BOTH_HORIZ)
3580         box = gtk_hbox_new (FALSE, 0);
3581       else
3582         box = gtk_vbox_new (FALSE, 0);
3583
3584       gtk_container_add (GTK_CONTAINER (child_widget), box);
3585       gtk_widget_show (box);
3586       
3587       if (text && use_stock)
3588         {
3589           GtkStockItem stock_item;
3590           if (gtk_stock_lookup (text, &stock_item))
3591             {
3592               if (!icon)
3593                 icon = gtk_image_new_from_stock (text, toolbar->icon_size);
3594           
3595               text = free_me = _gtk_toolbar_elide_underscores (stock_item.label);
3596             }
3597         }
3598       
3599       if (text)
3600         {
3601           child_label = gtk_label_new (text);
3602           
3603           gtk_container_add (GTK_CONTAINER (box), child_label);
3604         }
3605       
3606       if (icon)
3607         {
3608           child_icon = GTK_WIDGET (icon);
3609           gtk_container_add (GTK_CONTAINER (box), child_icon);
3610         }
3611       
3612       gtk_widget_show (child_widget);
3613       break;
3614       
3615     default:
3616       g_assert_not_reached ();
3617       break;
3618     }
3619   
3620   if ((type != GTK_TOOLBAR_CHILD_SPACE) && tooltip_text)
3621     {
3622       gtk_tooltips_set_tip (toolbar->tooltips, child_widget,
3623                             tooltip_text, tooltip_private_text);
3624     }
3625   
3626   content = toolbar_content_new_compatibility (toolbar, type, child_widget,
3627                                                child_icon, child_label, position);
3628   
3629   if (free_me)
3630     g_free (free_me);
3631   
3632   return child_widget;
3633 }
3634
3635 /*
3636  * ToolbarContent methods
3637  */
3638 struct _ToolbarContent
3639 {
3640   ContentType   type;
3641   ItemState     state;
3642   
3643   union
3644   {
3645     struct
3646     {
3647       GtkToolItem *     item;
3648       GtkAllocation     start_allocation;
3649       GtkAllocation     goal_allocation;
3650       guint             is_placeholder : 1;
3651       guint             disappearing : 1;
3652     } tool_item;
3653     
3654     struct
3655     {
3656       GtkToolbarChild   child;
3657       GtkAllocation     space_allocation;
3658       guint             space_visible : 1;
3659     } compatibility;
3660   } u;
3661 };
3662
3663 static ToolbarContent *
3664 toolbar_content_new_tool_item (GtkToolbar  *toolbar,
3665                                GtkToolItem *item,
3666                                gboolean     is_placeholder,
3667                                gint         pos)
3668 {
3669   ToolbarContent *content;
3670   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3671   
3672   content = g_new0 (ToolbarContent, 1);
3673   
3674   content->type = TOOL_ITEM;
3675   content->state = NOT_ALLOCATED;
3676   content->u.tool_item.item = item;
3677   content->u.tool_item.is_placeholder = is_placeholder;
3678   
3679   gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar));
3680
3681   priv->content = g_list_insert (priv->content, content, pos);
3682   
3683   if (!is_placeholder)
3684     {
3685       toolbar->num_children++;
3686
3687       gtk_toolbar_stop_sliding (toolbar);
3688     }
3689
3690   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3691   
3692   return content;
3693 }
3694
3695 static ToolbarContent *
3696 toolbar_content_new_compatibility (GtkToolbar          *toolbar,
3697                                    GtkToolbarChildType  type,
3698                                    GtkWidget            *widget,
3699                                    GtkWidget            *icon,
3700                                    GtkWidget            *label,
3701                                    gint                  pos)
3702 {
3703   ToolbarContent *content;
3704   GtkToolbarChild *child;
3705   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3706   
3707   content = g_new0 (ToolbarContent, 1);
3708
3709   child = &(content->u.compatibility.child);
3710   
3711   content->type = COMPATIBILITY;
3712   child->type = type;
3713   child->widget = widget;
3714   child->icon = icon;
3715   child->label = label;
3716   
3717   if (type != GTK_TOOLBAR_CHILD_SPACE)
3718     {
3719       gtk_widget_set_parent (child->widget, GTK_WIDGET (toolbar));
3720     }
3721   else
3722     {
3723       content->u.compatibility.space_visible = TRUE;
3724       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3725     }
3726  
3727   if (type == GTK_TOOLBAR_CHILD_BUTTON ||
3728       type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
3729       type == GTK_TOOLBAR_CHILD_RADIOBUTTON)
3730     {
3731       set_child_packing_and_visibility (toolbar, child);
3732     }
3733
3734   priv->content = g_list_insert (priv->content, content, pos);
3735   toolbar->children = g_list_insert (toolbar->children, child, pos);
3736   
3737   toolbar->num_children++;
3738   
3739   return content;
3740 }
3741
3742 static void
3743 toolbar_content_remove (ToolbarContent *content,
3744                         GtkToolbar     *toolbar)
3745 {
3746   GtkToolbarChild *child;
3747   GtkToolbarPrivate *priv;
3748
3749   priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3750   
3751   switch (content->type)
3752     {
3753     case TOOL_ITEM:
3754       gtk_widget_unparent (GTK_WIDGET (content->u.tool_item.item));
3755       break;
3756       
3757     case COMPATIBILITY:
3758       child = &(content->u.compatibility.child);
3759       
3760       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
3761         {
3762           g_object_ref (child->widget);
3763           gtk_widget_unparent (child->widget);
3764           gtk_widget_destroy (child->widget);
3765           g_object_unref (child->widget);
3766         }
3767       
3768       toolbar->children = g_list_remove (toolbar->children, child);
3769       break;
3770     }
3771
3772   priv->content = g_list_remove (priv->content, content);
3773
3774   if (!toolbar_content_is_placeholder (content))
3775     toolbar->num_children--;
3776
3777   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
3778 }
3779
3780 static void
3781 toolbar_content_free (ToolbarContent *content)
3782 {
3783   g_free (content);
3784 }
3785
3786 static gint
3787 calculate_max_homogeneous_pixels (GtkWidget *widget)
3788 {
3789   PangoContext *context;
3790   PangoFontMetrics *metrics;
3791   gint char_width;
3792   
3793   context = gtk_widget_get_pango_context (widget);
3794   metrics = pango_context_get_metrics (context,
3795                                        widget->style->font_desc,
3796                                        pango_context_get_language (context));
3797   char_width = pango_font_metrics_get_approximate_char_width (metrics);
3798   pango_font_metrics_unref (metrics);
3799   
3800   return PANGO_PIXELS (MAX_HOMOGENEOUS_N_CHARS * char_width);
3801 }
3802
3803 static void
3804 toolbar_content_expose (ToolbarContent *content,
3805                         GtkContainer   *container,
3806                         GdkEventExpose *expose)
3807 {
3808   GtkToolbar *toolbar = GTK_TOOLBAR (container);
3809   GtkToolbarChild *child;
3810   GtkWidget *widget = NULL; /* quiet gcc */
3811   
3812   switch (content->type)
3813     {
3814     case TOOL_ITEM:
3815       if (!content->u.tool_item.is_placeholder)
3816         widget = GTK_WIDGET (content->u.tool_item.item);
3817       break;
3818       
3819     case COMPATIBILITY:
3820       child = &(content->u.compatibility.child);
3821       
3822       if (child->type == GTK_TOOLBAR_CHILD_SPACE)
3823         {
3824           if (get_space_style (toolbar) == GTK_TOOLBAR_SPACE_LINE &&
3825               content->u.compatibility.space_visible)
3826             {
3827               _gtk_toolbar_paint_space_line (GTK_WIDGET (toolbar), toolbar,
3828                                              &expose->area,
3829                                              &content->u.compatibility.space_allocation);
3830             }
3831           return;
3832         }
3833       
3834       widget = child->widget;
3835       break;
3836     }
3837   
3838   if (widget)
3839     gtk_container_propagate_expose (container, widget, expose);
3840 }
3841
3842 static gboolean
3843 toolbar_content_visible (ToolbarContent *content,
3844                          GtkToolbar     *toolbar)
3845 {
3846   GtkToolItem *item;
3847   
3848   switch (content->type)
3849     {
3850     case TOOL_ITEM:
3851       item = content->u.tool_item.item;
3852       
3853       if (!GTK_WIDGET_VISIBLE (item))
3854         return FALSE;
3855       
3856       if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL &&
3857           gtk_tool_item_get_visible_horizontal (item))
3858         {
3859           return TRUE;
3860         }
3861       
3862       if ((toolbar->orientation == GTK_ORIENTATION_VERTICAL &&
3863            gtk_tool_item_get_visible_vertical (item)))
3864         {
3865           return TRUE;
3866         }
3867       
3868       return FALSE;
3869       break;
3870       
3871     case COMPATIBILITY:
3872       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
3873         return GTK_WIDGET_VISIBLE (content->u.compatibility.child.widget);
3874       else
3875         return TRUE;
3876       break;
3877     }
3878   
3879   g_assert_not_reached ();
3880   return FALSE;
3881 }
3882
3883 static void
3884 toolbar_content_size_request (ToolbarContent *content,
3885                               GtkToolbar     *toolbar,
3886                               GtkRequisition *requisition)
3887 {
3888   gint space_size;
3889   
3890   switch (content->type)
3891     {
3892     case TOOL_ITEM:
3893       gtk_widget_size_request (GTK_WIDGET (content->u.tool_item.item),
3894                                requisition);
3895       if (content->u.tool_item.is_placeholder &&
3896           content->u.tool_item.disappearing)
3897         {
3898           requisition->width = 0;
3899           requisition->height = 0;
3900         }
3901       break;
3902       
3903     case COMPATIBILITY:
3904       space_size = get_space_size (toolbar);
3905       
3906       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
3907         {
3908           gtk_widget_size_request (content->u.compatibility.child.widget,
3909                                    requisition);
3910         }
3911       else
3912         {
3913           if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
3914             {
3915               requisition->width = space_size;
3916               requisition->height = 0;
3917             }
3918           else
3919             {
3920               requisition->height = space_size;
3921               requisition->width = 0;
3922             }
3923         }
3924       
3925       break;
3926     }
3927 }
3928
3929 static gboolean
3930 toolbar_content_is_homogeneous (ToolbarContent *content,
3931                                 GtkToolbar     *toolbar)
3932 {
3933   gboolean result = FALSE;      /* quiet gcc */
3934   GtkRequisition requisition;
3935   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
3936   
3937   if (priv->max_homogeneous_pixels < 0)
3938     {
3939       priv->max_homogeneous_pixels =
3940         calculate_max_homogeneous_pixels (GTK_WIDGET (toolbar));
3941     }
3942   
3943   toolbar_content_size_request (content, toolbar, &requisition);
3944   
3945   if (requisition.width > priv->max_homogeneous_pixels)
3946     return FALSE;
3947   
3948   switch (content->type)
3949     {
3950     case TOOL_ITEM:
3951       result = gtk_tool_item_get_homogeneous (content->u.tool_item.item) &&
3952         !GTK_IS_SEPARATOR_TOOL_ITEM (content->u.tool_item.item);
3953       
3954       if (gtk_tool_item_get_is_important (content->u.tool_item.item) &&
3955           toolbar->style == GTK_TOOLBAR_BOTH_HORIZ &&
3956           toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
3957         {
3958           result = FALSE;
3959         }
3960       break;
3961       
3962     case COMPATIBILITY:
3963       if (content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_BUTTON ||
3964           content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
3965           content->u.compatibility.child.type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
3966         {
3967           result = TRUE;
3968         }
3969       else
3970         {
3971           result = FALSE;
3972         }
3973       break;
3974     }
3975   
3976   return result;
3977 }
3978
3979 static gboolean
3980 toolbar_content_is_placeholder (ToolbarContent *content)
3981 {
3982   if (content->type == TOOL_ITEM && content->u.tool_item.is_placeholder)
3983     return TRUE;
3984   
3985   return FALSE;
3986 }
3987
3988 static gboolean
3989 toolbar_content_disappearing (ToolbarContent *content)
3990 {
3991   if (content->type == TOOL_ITEM && content->u.tool_item.disappearing)
3992     return TRUE;
3993   
3994   return FALSE;
3995 }
3996
3997 static ItemState
3998 toolbar_content_get_state (ToolbarContent *content)
3999 {
4000   return content->state;
4001 }
4002
4003 static gboolean
4004 toolbar_content_child_visible (ToolbarContent *content)
4005 {
4006   switch (content->type)
4007     {
4008     case TOOL_ITEM:
4009       return GTK_WIDGET_CHILD_VISIBLE (content->u.tool_item.item);
4010       break;
4011       
4012     case COMPATIBILITY:
4013       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4014         {
4015           return GTK_WIDGET_CHILD_VISIBLE (content->u.compatibility.child.widget);
4016         }
4017       else
4018         {
4019           return content->u.compatibility.space_visible;
4020         }
4021       break;
4022     }
4023   
4024   return FALSE; /* quiet gcc */
4025 }
4026
4027 static void
4028 toolbar_content_get_goal_allocation (ToolbarContent *content,
4029                                      GtkAllocation  *allocation)
4030 {
4031   switch (content->type)
4032     {
4033     case TOOL_ITEM:
4034       *allocation = content->u.tool_item.goal_allocation;
4035       break;
4036       
4037     case COMPATIBILITY:
4038       /* Goal allocations are only relevant when we are
4039        * using the new API, so we should never get here
4040        */
4041       g_assert_not_reached ();
4042       break;
4043     }
4044 }
4045
4046 static void
4047 toolbar_content_get_allocation (ToolbarContent *content,
4048                                 GtkAllocation  *allocation)
4049 {
4050   GtkToolbarChild *child;
4051   
4052   switch (content->type)
4053     {
4054     case TOOL_ITEM:
4055       *allocation = GTK_WIDGET (content->u.tool_item.item)->allocation;
4056       break;
4057       
4058     case COMPATIBILITY:
4059       child = &(content->u.compatibility.child);
4060       
4061       if (child->type == GTK_TOOLBAR_CHILD_SPACE)
4062         *allocation = content->u.compatibility.space_allocation;
4063       else
4064         *allocation = child->widget->allocation;
4065       break;
4066     }
4067 }
4068
4069 static void
4070 toolbar_content_set_start_allocation (ToolbarContent *content,
4071                                       GtkAllocation  *allocation)
4072 {
4073   switch (content->type)
4074     {
4075     case TOOL_ITEM:
4076       content->u.tool_item.start_allocation = *allocation;
4077       break;
4078       
4079     case COMPATIBILITY:
4080       /* start_allocation is only relevant when using the new API */
4081       g_assert_not_reached ();
4082       break;
4083     }
4084 }
4085
4086 static gboolean
4087 toolbar_content_get_expand (ToolbarContent *content)
4088 {
4089   if (content->type == TOOL_ITEM &&
4090       gtk_tool_item_get_expand (content->u.tool_item.item))
4091     {
4092       return TRUE;
4093     }
4094   
4095   return FALSE;
4096 }
4097
4098 static void
4099 toolbar_content_set_goal_allocation (ToolbarContent *content,
4100                                      GtkAllocation  *allocation)
4101 {
4102   switch (content->type)
4103     {
4104     case TOOL_ITEM:
4105       content->u.tool_item.goal_allocation = *allocation;
4106       break;
4107       
4108     case COMPATIBILITY:
4109       /* Only relevant when using new API */
4110       g_assert_not_reached ();
4111       break;
4112     }
4113 }
4114
4115 static void
4116 toolbar_content_set_child_visible (ToolbarContent *content,
4117                                    GtkToolbar     *toolbar,
4118                                    gboolean        visible)
4119 {
4120   GtkToolbarChild *child;
4121   
4122   switch (content->type)
4123     {
4124     case TOOL_ITEM:
4125       gtk_widget_set_child_visible (GTK_WIDGET (content->u.tool_item.item),
4126                                     visible);
4127       break;
4128       
4129     case COMPATIBILITY:
4130       child = &(content->u.compatibility.child);
4131       
4132       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
4133         {
4134           gtk_widget_set_child_visible (child->widget, visible);
4135         }
4136       else
4137         {
4138           content->u.compatibility.space_visible = visible;
4139           gtk_widget_queue_draw (GTK_WIDGET (toolbar));
4140         }
4141       break;
4142     }
4143 }
4144
4145 static void
4146 toolbar_content_get_start_allocation (ToolbarContent *content,
4147                                       GtkAllocation  *start_allocation)
4148 {
4149   switch (content->type)
4150     {
4151     case TOOL_ITEM:
4152       *start_allocation = content->u.tool_item.start_allocation;
4153       break;
4154       
4155     case COMPATIBILITY:
4156       /* Only relevant for new API */
4157       g_assert_not_reached ();
4158       break;
4159     }
4160 }
4161
4162 static void
4163 toolbar_content_size_allocate (ToolbarContent *content,
4164                                GtkAllocation  *allocation)
4165 {
4166   switch (content->type)
4167     {
4168     case TOOL_ITEM:
4169       gtk_widget_size_allocate (GTK_WIDGET (content->u.tool_item.item),
4170                                 allocation);
4171       break;
4172       
4173     case COMPATIBILITY:
4174       if (content->u.compatibility.child.type != GTK_TOOLBAR_CHILD_SPACE)
4175         {
4176           gtk_widget_size_allocate (content->u.compatibility.child.widget,
4177                                     allocation);
4178         }
4179       else
4180         {
4181           content->u.compatibility.space_allocation = *allocation;
4182         }
4183       break;
4184     }
4185 }
4186
4187 static void
4188 toolbar_content_set_state (ToolbarContent *content,
4189                            ItemState       state)
4190 {
4191   content->state = state;
4192 }
4193
4194 static GtkWidget *
4195 toolbar_content_get_widget (ToolbarContent *content)
4196 {
4197   GtkToolbarChild *child;
4198   
4199   switch (content->type)
4200     {
4201     case TOOL_ITEM:
4202       return GTK_WIDGET (content->u.tool_item.item);
4203       break;
4204       
4205     case COMPATIBILITY:
4206       child = &(content->u.compatibility.child);
4207       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
4208         return child->widget;
4209       else
4210         return NULL;
4211       break;
4212     }
4213   
4214   return NULL;
4215 }
4216
4217 static void
4218 toolbar_content_set_disappearing (ToolbarContent *content,
4219                                   gboolean        disappearing)
4220 {
4221   switch (content->type)
4222     {
4223     case TOOL_ITEM:
4224       content->u.tool_item.disappearing = disappearing;
4225       break;
4226       
4227     case COMPATIBILITY:
4228       /* Only relevant for new API */
4229       g_assert_not_reached ();
4230       break;
4231     }
4232 }
4233
4234 static void
4235 toolbar_content_set_size_request (ToolbarContent *content,
4236                                   gint            width,
4237                                   gint            height)
4238 {
4239   switch (content->type)
4240     {
4241     case TOOL_ITEM:
4242       gtk_widget_set_size_request (GTK_WIDGET (content->u.tool_item.item),
4243                                    width, height);
4244       break;
4245       
4246     case COMPATIBILITY:
4247       /* Setting size requests only happens with sliding,
4248        * so not relevant here
4249        */
4250       g_assert_not_reached ();
4251       break;
4252     }
4253 }
4254
4255 static void
4256 toolbar_child_reconfigure (GtkToolbar      *toolbar,
4257                            GtkToolbarChild *child)
4258 {
4259   GtkWidget *box;
4260   GtkImage *image;
4261   GtkToolbarStyle style;
4262   GtkIconSize icon_size;
4263   GtkReliefStyle relief;
4264   gchar *stock_id;
4265   
4266   style = gtk_toolbar_get_style (toolbar);
4267   icon_size = gtk_toolbar_get_icon_size (toolbar);
4268   relief = gtk_toolbar_get_relief_style (toolbar);
4269   
4270   /* style */
4271   if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4272       child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4273       child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4274     {
4275       box = gtk_bin_get_child (GTK_BIN (child->widget));
4276       
4277       if (style == GTK_TOOLBAR_BOTH && GTK_IS_HBOX (box))
4278         {
4279           GtkWidget *vbox;
4280           
4281           vbox = gtk_vbox_new (FALSE, 0);
4282           
4283           if (child->label)
4284             gtk_widget_reparent (child->label, vbox);
4285           if (child->icon)
4286             gtk_widget_reparent (child->icon, vbox);
4287           
4288           gtk_widget_destroy (box);
4289           gtk_container_add (GTK_CONTAINER (child->widget), vbox);
4290           
4291           gtk_widget_show (vbox);
4292         }
4293       else if (style == GTK_TOOLBAR_BOTH_HORIZ && GTK_IS_VBOX (box))
4294         {
4295           GtkWidget *hbox;
4296           
4297           hbox = gtk_hbox_new (FALSE, 0);
4298           
4299           if (child->label)
4300             gtk_widget_reparent (child->label, hbox);
4301           if (child->icon)
4302             gtk_widget_reparent (child->icon, hbox);
4303           
4304           gtk_widget_destroy (box);
4305           gtk_container_add (GTK_CONTAINER (child->widget), hbox);
4306           
4307           gtk_widget_show (hbox);
4308         }
4309
4310       set_child_packing_and_visibility (toolbar, child);
4311     }
4312   
4313   /* icon size */
4314   
4315   if ((child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4316        child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
4317        child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON) &&
4318       GTK_IS_IMAGE (child->icon))
4319     {
4320       image = GTK_IMAGE (child->icon);
4321       if (gtk_image_get_storage_type (image) == GTK_IMAGE_STOCK)
4322         {
4323           gtk_image_get_stock (image, &stock_id, NULL);
4324           stock_id = g_strdup (stock_id);
4325           gtk_image_set_from_stock (image,
4326                                     stock_id,
4327                                     icon_size);
4328           g_free (stock_id);
4329         }
4330     }
4331   
4332   /* relief */
4333   if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
4334       child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
4335       child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
4336     {
4337       gtk_button_set_relief (GTK_BUTTON (child->widget), relief);
4338     }
4339 }
4340
4341 static void
4342 toolbar_content_toolbar_reconfigured (ToolbarContent *content,
4343                                       GtkToolbar     *toolbar)
4344 {
4345   switch (content->type)
4346     {
4347     case TOOL_ITEM:
4348       _gtk_tool_item_toolbar_reconfigured (content->u.tool_item.item);
4349       break;
4350       
4351     case COMPATIBILITY:
4352       toolbar_child_reconfigure (toolbar, &(content->u.compatibility.child));
4353       break;
4354     }
4355 }
4356
4357 static GtkWidget *
4358 toolbar_content_retrieve_menu_item (ToolbarContent *content)
4359 {
4360   if (content->type == TOOL_ITEM)
4361     return gtk_tool_item_retrieve_proxy_menu_item (content->u.tool_item.item);
4362   
4363   /* FIXME - we might actually be able to do something meaningful here */
4364   return NULL; 
4365 }
4366
4367 static gboolean
4368 toolbar_content_is_separator (ToolbarContent *content)
4369 {
4370   GtkToolbarChild *child;
4371   
4372   switch (content->type)
4373     {
4374     case TOOL_ITEM:
4375       return GTK_IS_SEPARATOR_TOOL_ITEM (content->u.tool_item.item);
4376       break;
4377       
4378     case COMPATIBILITY:
4379       child = &(content->u.compatibility.child);
4380       return (child->type == GTK_TOOLBAR_CHILD_SPACE);
4381       break;
4382     }
4383   
4384   return FALSE;
4385 }
4386
4387 static gboolean
4388 ignore_show_and_hide_all (ToolbarContent *content)
4389 {
4390   if (content->type == COMPATIBILITY)
4391     {
4392       GtkToolbarChildType type = content->u.compatibility.child.type;
4393       
4394       if (type == GTK_TOOLBAR_CHILD_BUTTON ||
4395           type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
4396           type == GTK_TOOLBAR_CHILD_RADIOBUTTON)
4397         {
4398           return TRUE;
4399         }
4400     }
4401   
4402   return FALSE;
4403 }
4404
4405 static void
4406 toolbar_content_show_all (ToolbarContent  *content)
4407 {
4408   GtkWidget *widget;
4409   
4410   if (ignore_show_and_hide_all (content))
4411     return;
4412
4413   widget = toolbar_content_get_widget (content);
4414   if (widget)
4415     gtk_widget_show_all (widget);
4416 }
4417
4418 static void
4419 toolbar_content_hide_all (ToolbarContent  *content)
4420 {
4421   GtkWidget *widget;
4422   
4423   if (ignore_show_and_hide_all (content))
4424     return;
4425
4426   widget = toolbar_content_get_widget (content);
4427   if (widget)
4428     gtk_widget_hide_all (widget);
4429 }
4430
4431 /*
4432  * Getters
4433  */
4434 static gint
4435 get_space_size (GtkToolbar *toolbar)
4436 {
4437   gint space_size = DEFAULT_SPACE_SIZE;
4438   
4439   if (toolbar)
4440     {
4441       gtk_widget_style_get (GTK_WIDGET (toolbar),
4442                             "space_size", &space_size,
4443                             NULL);
4444     }
4445   
4446   return space_size;
4447 }
4448
4449 static GtkToolbarSpaceStyle
4450 get_space_style (GtkToolbar *toolbar)
4451 {
4452   GtkToolbarSpaceStyle space_style = DEFAULT_SPACE_STYLE;
4453
4454   if (toolbar)
4455     {
4456       gtk_widget_style_get (GTK_WIDGET (toolbar),
4457                             "space_style", &space_style,
4458                             NULL);
4459     }
4460   
4461   return space_style;  
4462 }
4463
4464 static GtkReliefStyle
4465 get_button_relief (GtkToolbar *toolbar)
4466 {
4467   GtkReliefStyle button_relief = GTK_RELIEF_NORMAL;
4468   
4469   gtk_widget_ensure_style (GTK_WIDGET (toolbar));
4470   
4471   gtk_widget_style_get (GTK_WIDGET (toolbar),
4472                         "button_relief", &button_relief,
4473                         NULL);
4474   
4475   return button_relief;
4476 }
4477
4478 static gint
4479 get_internal_padding (GtkToolbar *toolbar)
4480 {
4481   gint ipadding = 0;
4482   
4483   gtk_widget_style_get (GTK_WIDGET (toolbar),
4484                         "internal_padding", &ipadding,
4485                         NULL);
4486   
4487   return ipadding;
4488 }
4489
4490 static GtkShadowType
4491 get_shadow_type (GtkToolbar *toolbar)
4492 {
4493   GtkShadowType shadow_type;
4494   
4495   gtk_widget_style_get (GTK_WIDGET (toolbar),
4496                         "shadow_type", &shadow_type,
4497                         NULL);
4498   
4499   return shadow_type;
4500 }
4501
4502 /*
4503  * API checks
4504  */
4505 #define mixed_api_warning \
4506     "mixing deprecated and non-deprecated GtkToolbar API is not allowed"
4507
4508 static gboolean
4509 gtk_toolbar_check_old_api (GtkToolbar *toolbar)
4510 {
4511   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4512   
4513   if (priv->api_mode == NEW_API)
4514     {
4515       g_warning (mixed_api_warning);
4516       return FALSE;
4517     }
4518   
4519   priv->api_mode = OLD_API;
4520   return TRUE;
4521 }
4522
4523 static gboolean
4524 gtk_toolbar_check_new_api (GtkToolbar *toolbar)
4525 {
4526   GtkToolbarPrivate *priv = GTK_TOOLBAR_GET_PRIVATE (toolbar);
4527   
4528   if (priv->api_mode == OLD_API)
4529     {
4530       g_warning (mixed_api_warning);
4531       return FALSE;
4532     }
4533   
4534   priv->api_mode = NEW_API;
4535   return TRUE;
4536 }
4537
4538 /* GTK+ internal methods */
4539
4540 gint
4541 _gtk_toolbar_get_default_space_size (void)
4542 {
4543   return DEFAULT_SPACE_SIZE;
4544 }
4545
4546 void
4547 _gtk_toolbar_paint_space_line (GtkWidget       *widget,
4548                                GtkToolbar      *toolbar,
4549                                GdkRectangle    *area,
4550                                GtkAllocation   *allocation)
4551 {
4552   const double start_fraction = (SPACE_LINE_START / SPACE_LINE_DIVISION);
4553   const double end_fraction = (SPACE_LINE_END / SPACE_LINE_DIVISION);
4554   
4555   gint space_size;
4556   GtkToolbarSpaceStyle space_style;
4557   GtkOrientation orientation;
4558
4559   g_return_if_fail (GTK_IS_WIDGET (widget));
4560   
4561   space_size = get_space_size (toolbar);
4562   space_style = get_space_style (toolbar);
4563   orientation = toolbar? toolbar->orientation : GTK_ORIENTATION_HORIZONTAL;
4564
4565   if (orientation == GTK_ORIENTATION_HORIZONTAL)
4566     {
4567       gtk_paint_vline (widget->style, widget->window,
4568                        GTK_WIDGET_STATE (widget), area, widget,
4569                        "toolbar",
4570                        allocation->y + allocation->height * start_fraction,
4571                        allocation->y + allocation->height * end_fraction,
4572                        allocation->x + (space_size - widget->style->xthickness) / 2);
4573     }
4574   else
4575     {
4576       gtk_paint_hline (widget->style, widget->window,
4577                        GTK_WIDGET_STATE (widget), area, widget,
4578                        "toolbar",
4579                        allocation->x + allocation->width * start_fraction,
4580                        allocation->x + allocation->width * end_fraction,
4581                        allocation->y + (space_size - widget->style->ythickness) / 2);
4582     }
4583 }
4584
4585 gchar *
4586 _gtk_toolbar_elide_underscores (const gchar *original)
4587 {
4588   gchar *q, *result;
4589   const gchar *p;
4590   gboolean last_underscore;
4591   
4592   q = result = g_malloc (strlen (original) + 1);
4593   last_underscore = FALSE;
4594   
4595   for (p = original; *p; p++)
4596     {
4597       if (!last_underscore && *p == '_')
4598         last_underscore = TRUE;
4599       else
4600         {
4601           last_underscore = FALSE;
4602           *q++ = *p;
4603         }
4604     }
4605   
4606   *q = '\0';
4607   
4608   return result;
4609 }