]> Pileus Git - ~andy/gtk/blob - gtk/gtktoolbar.c
Subtract off twice the border width from the width/height, not 1x the
[~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  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 #include <string.h>
29
30 #include "gtkbutton.h"
31 #include "gtktogglebutton.h"
32 #include "gtkradiobutton.h"
33 #include "gtklabel.h"
34 #include "gtkvbox.h"
35 #include "gtkhbox.h"
36 #include "gtktoolbar.h"
37 #include "gtkstock.h"
38 #include "gtkiconfactory.h"
39 #include "gtkimage.h"
40 #include "gtksettings.h"
41 #include "gtkintl.h"
42 #include "gtkmarshalers.h"
43
44
45 #define DEFAULT_IPADDING 0
46 #define DEFAULT_SPACE_SIZE  5
47 #define DEFAULT_SPACE_STYLE GTK_TOOLBAR_SPACE_LINE
48
49 #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_LARGE_TOOLBAR
50 #define DEFAULT_TOOLBAR_STYLE GTK_TOOLBAR_BOTH
51
52 #define SPACE_LINE_DIVISION 10
53 #define SPACE_LINE_START    3
54 #define SPACE_LINE_END      7
55
56 enum {
57   PROP_0,
58   PROP_ORIENTATION,
59   PROP_TOOLBAR_STYLE
60 };
61
62 enum {
63   ORIENTATION_CHANGED,
64   STYLE_CHANGED,
65   LAST_SIGNAL
66 };
67
68 typedef struct _GtkToolbarChildSpace GtkToolbarChildSpace;
69 struct _GtkToolbarChildSpace
70 {
71   GtkToolbarChild child;
72
73   gint alloc_x, alloc_y;
74 };
75
76 static void gtk_toolbar_class_init               (GtkToolbarClass *class);
77 static void gtk_toolbar_init                     (GtkToolbar      *toolbar);
78 static void gtk_toolbar_set_property             (GObject         *object,
79                                                   guint            prop_id,
80                                                   const GValue    *value,
81                                                   GParamSpec      *pspec);
82 static void gtk_toolbar_get_property             (GObject         *object,
83                                                   guint            prop_id,
84                                                   GValue          *value,
85                                                   GParamSpec      *pspec);
86 static void gtk_toolbar_destroy                  (GtkObject       *object);
87 static gint gtk_toolbar_expose                   (GtkWidget       *widget,
88                                                   GdkEventExpose  *event);
89 static void gtk_toolbar_size_request             (GtkWidget       *widget,
90                                                   GtkRequisition  *requisition);
91 static void gtk_toolbar_size_allocate            (GtkWidget       *widget,
92                                                   GtkAllocation   *allocation);
93 static void gtk_toolbar_style_set                (GtkWidget       *widget,
94                                                   GtkStyle        *prev_style);
95 static gboolean gtk_toolbar_focus                (GtkWidget       *widget,
96                                                   GtkDirectionType dir);
97 static void gtk_toolbar_screen_changed           (GtkWidget       *widget,
98                                                   GdkScreen       *previous_screen);
99 static void gtk_toolbar_show_all                 (GtkWidget       *widget);
100 static void gtk_toolbar_hide_all                 (GtkWidget       *widget);
101 static void gtk_toolbar_add                      (GtkContainer    *container,
102                                                   GtkWidget       *widget);
103 static void gtk_toolbar_remove                   (GtkContainer    *container,
104                                                   GtkWidget       *widget);
105 static void gtk_toolbar_forall                   (GtkContainer    *container,
106                                                   gboolean         include_internals,
107                                                   GtkCallback      callback,
108                                                   gpointer         callback_data);
109
110 static void gtk_real_toolbar_orientation_changed (GtkToolbar      *toolbar,
111                                                   GtkOrientation   orientation);
112 static void gtk_real_toolbar_style_changed       (GtkToolbar      *toolbar,
113                                                   GtkToolbarStyle  style);
114
115 static GtkWidget * gtk_toolbar_internal_insert_element (GtkToolbar          *toolbar,
116                                                         GtkToolbarChildType  type,
117                                                         GtkWidget           *widget,
118                                                         const char          *text,
119                                                         const char          *tooltip_text,
120                                                         const char          *tooltip_private_text,
121                                                         GtkWidget           *icon,
122                                                         GtkSignalFunc        callback,
123                                                         gpointer             user_data,
124                                                         gint                 position);
125
126 static GtkWidget * gtk_toolbar_internal_insert_item (GtkToolbar    *toolbar,
127                                                      const char    *text,
128                                                      const char    *tooltip_text,
129                                                      const char    *tooltip_private_text,
130                                                      GtkWidget     *icon,
131                                                      GtkSignalFunc  callback,
132                                                      gpointer       user_data,
133                                                      gint           position);
134
135 static void        gtk_toolbar_update_button_relief (GtkToolbar *toolbar);
136
137 static GtkReliefStyle       get_button_relief (GtkToolbar *toolbar);
138 static gint                 get_space_size    (GtkToolbar *toolbar);
139 static GtkToolbarSpaceStyle get_space_style   (GtkToolbar *toolbar);
140
141
142 static GtkContainerClass *parent_class;
143
144 static guint toolbar_signals[LAST_SIGNAL] = { 0 };
145
146
147 GType
148 gtk_toolbar_get_type (void)
149 {
150   static GType toolbar_type = 0;
151
152   if (!toolbar_type)
153     {
154       static const GTypeInfo toolbar_info =
155       {
156         sizeof (GtkToolbarClass),
157         NULL,           /* base_init */
158         NULL,           /* base_finalize */
159         (GClassInitFunc) gtk_toolbar_class_init,
160         NULL,           /* class_finalize */
161         NULL,           /* class_data */
162         sizeof (GtkToolbar),
163         0,              /* n_preallocs */
164         (GInstanceInitFunc) gtk_toolbar_init,
165       };
166
167       toolbar_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkToolbar",
168                                              &toolbar_info, 0);
169     }
170
171   return toolbar_type;
172 }
173
174 static void
175 gtk_toolbar_class_init (GtkToolbarClass *class)
176 {
177   GObjectClass   *gobject_class;
178   GtkObjectClass *object_class;
179   GtkWidgetClass *widget_class;
180   GtkContainerClass *container_class;
181
182   gobject_class = G_OBJECT_CLASS (class);
183   object_class = (GtkObjectClass *) class;
184   widget_class = (GtkWidgetClass *) class;
185   container_class = (GtkContainerClass *) class;
186
187   parent_class = g_type_class_peek_parent (class);
188
189   object_class->destroy = gtk_toolbar_destroy;
190   gobject_class->set_property = gtk_toolbar_set_property;
191   gobject_class->get_property = gtk_toolbar_get_property;
192
193   widget_class->expose_event = gtk_toolbar_expose;
194   widget_class->size_request = gtk_toolbar_size_request;
195   widget_class->size_allocate = gtk_toolbar_size_allocate;
196   widget_class->style_set = gtk_toolbar_style_set;
197   widget_class->show_all = gtk_toolbar_show_all;
198   widget_class->hide_all = gtk_toolbar_hide_all;
199   widget_class->focus = gtk_toolbar_focus;
200   widget_class->screen_changed = gtk_toolbar_screen_changed;
201   
202   container_class->add = gtk_toolbar_add;
203   container_class->remove = gtk_toolbar_remove;
204   container_class->forall = gtk_toolbar_forall;
205   
206   class->orientation_changed = gtk_real_toolbar_orientation_changed;
207   class->style_changed = gtk_real_toolbar_style_changed;
208
209   toolbar_signals[ORIENTATION_CHANGED] =
210     g_signal_new ("orientation_changed",
211                   G_OBJECT_CLASS_TYPE (gobject_class),
212                   G_SIGNAL_RUN_FIRST,
213                   G_STRUCT_OFFSET (GtkToolbarClass, orientation_changed),
214                   NULL, NULL,
215                   _gtk_marshal_VOID__ENUM,
216                   G_TYPE_NONE, 1,
217                   GTK_TYPE_ORIENTATION);
218   toolbar_signals[STYLE_CHANGED] =
219     g_signal_new ("style_changed",
220                   G_OBJECT_CLASS_TYPE (gobject_class),
221                   G_SIGNAL_RUN_FIRST,
222                   G_STRUCT_OFFSET (GtkToolbarClass, style_changed),
223                   NULL, NULL,
224                   _gtk_marshal_VOID__ENUM,
225                   G_TYPE_NONE, 1,
226                   GTK_TYPE_TOOLBAR_STYLE);
227   
228   g_object_class_install_property (gobject_class,
229                                    PROP_ORIENTATION,
230                                    g_param_spec_enum ("orientation",
231                                                       _("Orientation"),
232                                                       _("The orientation of the toolbar"),
233                                                       GTK_TYPE_ORIENTATION,
234                                                       GTK_ORIENTATION_HORIZONTAL,
235                                                       G_PARAM_READWRITE));
236  
237    g_object_class_install_property (gobject_class,
238                                     PROP_TOOLBAR_STYLE,
239                                     g_param_spec_enum ("toolbar_style",
240                                                       _("Toolbar Style"),
241                                                       _("How to draw the toolbar"),
242                                                       GTK_TYPE_TOOLBAR_STYLE,
243                                                       GTK_TOOLBAR_ICONS,
244                                                       G_PARAM_READWRITE));
245
246
247   gtk_widget_class_install_style_property (widget_class,
248                                            g_param_spec_int ("space_size",
249                                                              _("Spacer size"),
250                                                              _("Size of spacers"),
251                                                              0,
252                                                              G_MAXINT,
253                                                              DEFAULT_SPACE_SIZE,
254                                                              G_PARAM_READABLE));
255
256   gtk_widget_class_install_style_property (widget_class,
257                                            g_param_spec_int ("internal_padding",
258                                                              _("Internal padding"),
259                                                              _("Amount of border space between the toolbar shadow and the buttons"),
260                                                              0,
261                                                              G_MAXINT,
262                                                              DEFAULT_IPADDING,
263                                                              G_PARAM_READABLE));
264   
265   gtk_widget_class_install_style_property (widget_class,
266                                            g_param_spec_enum ("space_style",
267                                                              _("Space style"),
268                                                              _("Whether spacers are vertical lines or just blank"),
269                                                               GTK_TYPE_TOOLBAR_SPACE_STYLE,
270                                                               DEFAULT_SPACE_STYLE,
271                                                               
272                                                               G_PARAM_READABLE));
273
274   gtk_widget_class_install_style_property (widget_class,
275                                            g_param_spec_enum ("button_relief",
276                                                              _("Button relief"),
277                                                              _("Type of bevel around toolbar buttons"),
278                                                               GTK_TYPE_RELIEF_STYLE,
279                                                               GTK_RELIEF_NONE,
280                                                               G_PARAM_READABLE));
281
282   gtk_widget_class_install_style_property (widget_class,
283                                            g_param_spec_enum ("shadow_type",
284                                                               _("Shadow type"),
285                                                               _("Style of bevel around the toolbar"),
286                                                               GTK_TYPE_SHADOW_TYPE,
287                                                               GTK_SHADOW_OUT,
288                                                               G_PARAM_READABLE));
289
290   gtk_settings_install_property (g_param_spec_enum ("gtk-toolbar-style",
291                                                     _("Toolbar style"),
292                                                     _("Whether default toolbars have text only, text and icons, icons only, etc."),
293                                                     GTK_TYPE_TOOLBAR_STYLE,
294                                                     DEFAULT_TOOLBAR_STYLE,
295                                                     G_PARAM_READWRITE));
296
297   gtk_settings_install_property (g_param_spec_enum ("gtk-toolbar-icon-size",
298                                                     _("Toolbar icon size"),
299                                                     _("Size of icons in default toolbars"),
300                                                     GTK_TYPE_ICON_SIZE,
301                                                     DEFAULT_ICON_SIZE,
302                                                     G_PARAM_READWRITE));  
303 }
304
305 static void
306 style_change_notify (GtkToolbar *toolbar)
307 {
308   if (!toolbar->style_set)
309     {
310       /* pretend it was set, then unset, thus reverting to new default */
311       toolbar->style_set = TRUE; 
312       gtk_toolbar_unset_style (toolbar);
313     }
314 }
315
316 static void
317 icon_size_change_notify (GtkToolbar *toolbar)
318 {
319   if (!toolbar->icon_size_set)
320     {
321       /* pretend it was set, then unset, thus reverting to new default */
322       toolbar->icon_size_set = TRUE; 
323       gtk_toolbar_unset_icon_size (toolbar);
324     }
325 }
326
327 static GtkSettings *
328 toolbar_get_settings (GtkToolbar *toolbar)
329 {
330   return g_object_get_data (G_OBJECT (toolbar), "gtk-toolbar-settings");
331 }
332
333 static void
334 gtk_toolbar_screen_changed (GtkWidget *widget,
335                             GdkScreen *previous_screen)
336 {
337   GtkToolbar *toolbar = GTK_TOOLBAR (widget);
338   GtkSettings *old_settings = toolbar_get_settings (toolbar);
339   GtkSettings *settings;
340
341   if (gtk_widget_has_screen (GTK_WIDGET (toolbar)))
342     settings = gtk_widget_get_settings (GTK_WIDGET (toolbar));
343   else
344     settings = NULL;
345
346   if (settings == old_settings)
347     return;
348
349   if (old_settings)
350     {
351       g_signal_handler_disconnect (old_settings, toolbar->style_set_connection);
352       g_signal_handler_disconnect (old_settings, toolbar->icon_size_connection);
353
354       g_object_unref (old_settings);
355     }
356   
357   if (settings)
358     {
359       toolbar->style_set_connection =
360         g_signal_connect_swapped (settings,
361                                   "notify::gtk-toolbar-style",
362                                   G_CALLBACK (style_change_notify),
363                                   toolbar);
364       
365       toolbar->icon_size_connection =
366         g_signal_connect_swapped (settings,
367                                   "notify::gtk-toolbar-icon-size",
368                                    G_CALLBACK (icon_size_change_notify),
369                                    toolbar);
370
371
372       g_object_ref (settings);
373       g_object_set_data (G_OBJECT (toolbar), "gtk-toolbar-settings", settings);
374     }
375   else
376     g_object_set_data (G_OBJECT (toolbar), "gtk-toolbar-settings", NULL);
377
378   style_change_notify (toolbar);
379   icon_size_change_notify (toolbar);
380 }
381
382 static void
383 gtk_toolbar_init (GtkToolbar *toolbar)
384 {
385   GTK_WIDGET_SET_FLAGS (toolbar, GTK_NO_WINDOW);
386   GTK_WIDGET_UNSET_FLAGS (toolbar, GTK_CAN_FOCUS);
387
388   toolbar->num_children = 0;
389   toolbar->children     = NULL;
390   toolbar->orientation  = GTK_ORIENTATION_HORIZONTAL;
391   toolbar->icon_size    = DEFAULT_ICON_SIZE;
392   toolbar->style        = DEFAULT_TOOLBAR_STYLE;
393   toolbar->tooltips     = gtk_tooltips_new ();
394   g_object_ref (toolbar->tooltips);
395   gtk_object_sink (GTK_OBJECT (toolbar->tooltips));
396   
397   toolbar->button_maxw  = 0;
398   toolbar->button_maxh  = 0;
399
400   toolbar->style_set = FALSE;
401   toolbar->icon_size_set = FALSE;
402 }
403
404 static void
405 gtk_toolbar_set_property (GObject      *object,
406                           guint         prop_id,
407                           const GValue *value,
408                           GParamSpec   *pspec)
409 {
410   GtkToolbar *toolbar = GTK_TOOLBAR (object);
411   
412   switch (prop_id)
413     {
414     case PROP_ORIENTATION:
415       gtk_toolbar_set_orientation (toolbar, g_value_get_enum (value));
416       break;
417     case PROP_TOOLBAR_STYLE:
418       gtk_toolbar_set_style (toolbar, g_value_get_enum (value));
419       break;
420     }
421 }
422
423 static void
424 gtk_toolbar_get_property (GObject      *object,
425                           guint         prop_id,
426                           GValue       *value,
427                           GParamSpec   *pspec)
428 {
429   GtkToolbar *toolbar = GTK_TOOLBAR (object);
430
431   switch (prop_id)
432     {
433     case PROP_ORIENTATION:
434       g_value_set_enum (value, toolbar->orientation);
435       break;
436     case PROP_TOOLBAR_STYLE:
437       g_value_set_enum (value, toolbar->style);
438       break;
439     default:
440       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
441       break;
442     }
443 }
444
445 GtkWidget*
446 gtk_toolbar_new (void)
447 {
448   GtkToolbar *toolbar;
449
450   toolbar = g_object_new (GTK_TYPE_TOOLBAR, NULL);
451
452   return GTK_WIDGET (toolbar);
453 }
454
455 static void
456 gtk_toolbar_destroy (GtkObject *object)
457 {
458   GtkToolbar *toolbar;
459   GList *children;
460
461   g_return_if_fail (GTK_IS_TOOLBAR (object));
462
463   toolbar = GTK_TOOLBAR (object);
464
465   if (toolbar->tooltips)
466     {
467       g_object_unref (toolbar->tooltips);
468       toolbar->tooltips = NULL;
469     }
470
471   for (children = toolbar->children; children; children = children->next)
472     {
473       GtkToolbarChild *child;
474
475       child = children->data;
476
477       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
478         {
479           g_object_ref (child->widget);
480           gtk_widget_unparent (child->widget);
481           gtk_widget_destroy (child->widget);
482           g_object_unref (child->widget);
483         }
484
485       g_free (child);
486     }
487   g_list_free (toolbar->children);
488   toolbar->children = NULL;
489   
490   GTK_OBJECT_CLASS (parent_class)->destroy (object);
491 }
492
493 static void
494 gtk_toolbar_paint_space_line (GtkWidget       *widget,
495                               GdkRectangle    *area,
496                               GtkToolbarChild *child)
497 {
498   GtkToolbar *toolbar;
499   GtkToolbarChildSpace *child_space;
500   gint space_size;
501   
502   g_return_if_fail (GTK_IS_TOOLBAR (widget));
503   g_return_if_fail (child != NULL);
504   g_return_if_fail (child->type == GTK_TOOLBAR_CHILD_SPACE);
505
506   toolbar = GTK_TOOLBAR (widget);
507
508   child_space = (GtkToolbarChildSpace *) child;
509   space_size = get_space_size (toolbar);
510   
511   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
512     gtk_paint_vline (widget->style, widget->window,
513                      GTK_WIDGET_STATE (widget), area, widget,
514                      "toolbar",
515                      child_space->alloc_y + toolbar->button_maxh *
516                      SPACE_LINE_START / SPACE_LINE_DIVISION,
517                      child_space->alloc_y + toolbar->button_maxh *
518                      SPACE_LINE_END / SPACE_LINE_DIVISION,
519                      child_space->alloc_x +
520                      (space_size -
521                       widget->style->xthickness) / 2);
522   else
523     gtk_paint_hline (widget->style, widget->window,
524                      GTK_WIDGET_STATE (widget), area, widget,
525                      "toolbar",
526                      child_space->alloc_x + toolbar->button_maxw *
527                      SPACE_LINE_START / SPACE_LINE_DIVISION,
528                      child_space->alloc_x + toolbar->button_maxw *
529                      SPACE_LINE_END / SPACE_LINE_DIVISION,
530                      child_space->alloc_y +
531                      (space_size -
532                       widget->style->ythickness) / 2);
533 }
534
535 static gint
536 gtk_toolbar_expose (GtkWidget      *widget,
537                     GdkEventExpose *event)
538 {
539   GtkToolbar *toolbar;
540   GList *children;
541   GtkToolbarChild *child;
542   gint border_width;
543   
544   g_return_val_if_fail (GTK_IS_TOOLBAR (widget), FALSE);
545   g_return_val_if_fail (event != NULL, FALSE);
546
547   border_width = GTK_CONTAINER (widget)->border_width;
548   
549   if (GTK_WIDGET_DRAWABLE (widget))
550     {
551       GtkShadowType shadow_type;
552
553       toolbar = GTK_TOOLBAR (widget);
554
555       gtk_widget_style_get (widget, "shadow_type", &shadow_type, NULL);
556       
557       gtk_paint_box (widget->style,
558                      widget->window,
559                      GTK_WIDGET_STATE (widget),
560                      shadow_type,
561                      &event->area, widget, "toolbar",
562                      widget->allocation.x + border_width,
563                      widget->allocation.y + border_width,
564                      widget->allocation.width - 2 * border_width,
565                      widget->allocation.height - 2 * border_width);
566       
567       for (children = toolbar->children; children; children = children->next)
568         {
569           child = children->data;
570
571           if (child->type == GTK_TOOLBAR_CHILD_SPACE)
572             {
573               if (get_space_style (toolbar) == GTK_TOOLBAR_SPACE_LINE)
574                 gtk_toolbar_paint_space_line (widget, &event->area, child);
575             }
576           else
577             gtk_container_propagate_expose (GTK_CONTAINER (widget),
578                                             child->widget,
579                                             event);
580         }
581     }
582
583   return FALSE;
584 }
585
586 static void
587 gtk_toolbar_size_request (GtkWidget      *widget,
588                           GtkRequisition *requisition)
589 {
590   GtkToolbar *toolbar;
591   GList *children;
592   GtkToolbarChild *child;
593   gint nbuttons;
594   gint button_maxw, button_maxh;
595   gint widget_maxw, widget_maxh;
596   GtkRequisition child_requisition;
597   gint space_size;
598   gint ipadding;
599   
600   g_return_if_fail (GTK_IS_TOOLBAR (widget));
601   g_return_if_fail (requisition != NULL);
602
603   toolbar = GTK_TOOLBAR (widget);
604
605   requisition->width = GTK_CONTAINER (toolbar)->border_width * 2;
606   requisition->height = GTK_CONTAINER (toolbar)->border_width * 2;
607   nbuttons = 0;
608   button_maxw = 0;
609   button_maxh = 0;
610   widget_maxw = 0;
611   widget_maxh = 0;
612
613   space_size = get_space_size (toolbar);
614   
615   for (children = toolbar->children; children; children = children->next)
616     {
617       child = children->data;
618
619       switch (child->type)
620         {
621         case GTK_TOOLBAR_CHILD_SPACE:
622           if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
623             requisition->width += space_size;
624           else
625             requisition->height += space_size;
626
627           break;
628
629         case GTK_TOOLBAR_CHILD_BUTTON:
630         case GTK_TOOLBAR_CHILD_RADIOBUTTON:
631         case GTK_TOOLBAR_CHILD_TOGGLEBUTTON:
632           if (GTK_WIDGET_VISIBLE (child->widget))
633             {              
634               gtk_widget_size_request (child->widget, &child_requisition);
635
636               nbuttons++;
637               button_maxw = MAX (button_maxw, child_requisition.width);
638               button_maxh = MAX (button_maxh, child_requisition.height);
639             }
640
641           break;
642
643         case GTK_TOOLBAR_CHILD_WIDGET:
644           if (GTK_WIDGET_VISIBLE (child->widget))
645             {
646               gtk_widget_size_request (child->widget, &child_requisition);
647
648               widget_maxw = MAX (widget_maxw, child_requisition.width);
649               widget_maxh = MAX (widget_maxh, child_requisition.height);
650
651               if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
652                 requisition->width += child_requisition.width;
653               else
654                 requisition->height += child_requisition.height;
655             }
656
657           break;
658
659         default:
660           g_assert_not_reached ();
661         }
662     }
663
664   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
665     {
666       requisition->width += nbuttons * button_maxw;
667       requisition->height += MAX (button_maxh, widget_maxh);
668     }
669   else
670     {
671       requisition->width += MAX (button_maxw, widget_maxw);
672       requisition->height += nbuttons * button_maxh;
673     }
674
675   /* Extra spacing */
676   gtk_widget_style_get (widget, "internal_padding", &ipadding, NULL);
677   
678   requisition->width += 2 * ipadding;
679   requisition->height += 2 * ipadding;
680   
681   toolbar->button_maxw = button_maxw;
682   toolbar->button_maxh = button_maxh;
683 }
684
685 static void
686 gtk_toolbar_size_allocate (GtkWidget     *widget,
687                            GtkAllocation *allocation)
688 {
689   GtkToolbar *toolbar;
690   GList *children;
691   GtkToolbarChild *child;
692   GtkToolbarChildSpace *child_space;
693   GtkAllocation alloc;
694   GtkRequisition child_requisition;
695   gint x_border_width, y_border_width;
696   gint space_size;
697   gint ipadding;
698   GtkTextDirection direction;
699   gint ltr_x = 0;               /* Quiet GCC */
700   
701   g_return_if_fail (GTK_IS_TOOLBAR (widget));
702   g_return_if_fail (allocation != NULL);
703
704   toolbar = GTK_TOOLBAR (widget);
705   widget->allocation = *allocation;
706   
707   direction = gtk_widget_get_direction (widget);
708
709   x_border_width = GTK_CONTAINER (toolbar)->border_width;
710   y_border_width = GTK_CONTAINER (toolbar)->border_width;
711
712   gtk_widget_style_get (widget, "internal_padding", &ipadding, NULL);
713   
714   x_border_width += ipadding;
715   y_border_width += ipadding;
716   
717   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
718     ltr_x = allocation->x + x_border_width;
719   else
720     alloc.y = allocation->y + y_border_width;
721
722   space_size = get_space_size (toolbar);
723   
724   for (children = toolbar->children; children; children = children->next)
725     {
726       child = children->data;
727
728       switch (child->type)
729         {
730         case GTK_TOOLBAR_CHILD_SPACE:
731
732           child_space = (GtkToolbarChildSpace *) child;
733
734           if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
735             {
736               if (direction == GTK_TEXT_DIR_LTR)
737                 child_space->alloc_x = ltr_x;
738               else
739                 child_space->alloc_x = allocation->width - ltr_x - space_size;
740               child_space->alloc_y = allocation->y + (allocation->height - toolbar->button_maxh) / 2;
741               ltr_x += space_size;
742             }
743           else
744             {
745               child_space->alloc_x = allocation->x + (allocation->width - toolbar->button_maxw) / 2;
746               child_space->alloc_y = alloc.y;
747               alloc.y += space_size;
748             }
749
750           break;
751
752         case GTK_TOOLBAR_CHILD_BUTTON:
753         case GTK_TOOLBAR_CHILD_RADIOBUTTON:
754         case GTK_TOOLBAR_CHILD_TOGGLEBUTTON:
755           if (!GTK_WIDGET_VISIBLE (child->widget))
756             break;
757
758           alloc.width = toolbar->button_maxw;
759           alloc.height = toolbar->button_maxh;
760
761           if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) 
762             {
763               if (direction == GTK_TEXT_DIR_LTR)
764                 alloc.x = ltr_x;
765               else
766                 alloc.x = allocation->width - ltr_x - alloc.width;
767               alloc.y = allocation->y + (allocation->height - toolbar->button_maxh) / 2;
768             }
769           else
770             alloc.x = allocation->x + (allocation->width - toolbar->button_maxw) / 2;
771           
772           gtk_widget_size_allocate (child->widget, &alloc);
773
774           if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
775             ltr_x += toolbar->button_maxw;
776           else
777             alloc.y += toolbar->button_maxh;
778
779           break;
780
781         case GTK_TOOLBAR_CHILD_WIDGET:
782           if (!GTK_WIDGET_VISIBLE (child->widget))
783             break;
784
785           gtk_widget_get_child_requisition (child->widget, &child_requisition);
786           
787           alloc.width = child_requisition.width;
788           alloc.height = child_requisition.height;
789
790           if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) 
791             {
792               if (direction == GTK_TEXT_DIR_LTR)
793                 alloc.x = ltr_x;
794               else
795                 alloc.x = allocation->width - ltr_x - alloc.width;
796               alloc.y = allocation->y + (allocation->height - child_requisition.height) / 2;
797             }
798           else
799             alloc.x = allocation->x + (allocation->width - child_requisition.width) / 2;
800
801           gtk_widget_size_allocate (child->widget, &alloc);
802
803           if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
804             ltr_x += child_requisition.width;
805           else
806             alloc.y += child_requisition.height;
807
808           break;
809
810         default:
811           g_assert_not_reached ();
812         }
813     }
814 }
815
816 static void
817 gtk_toolbar_style_set (GtkWidget  *widget,
818                        GtkStyle   *prev_style)
819 {
820   if (prev_style)
821     gtk_toolbar_update_button_relief (GTK_TOOLBAR (widget));
822 }
823
824 static gboolean
825 gtk_toolbar_focus (GtkWidget       *widget,
826                    GtkDirectionType dir)
827 {
828   /* Focus can't go in toolbars */
829   
830   return FALSE;
831 }
832
833 static void
834 child_show_all (GtkWidget *widget)
835 {
836   /* Don't show our own children, since that would
837    * show labels we may intend to hide in icons-only mode
838    */
839   if (!g_object_get_data (G_OBJECT (widget),
840                           "gtk-toolbar-is-child"))
841     gtk_widget_show_all (widget);
842 }
843
844 static void
845 gtk_toolbar_show_all (GtkWidget *widget)
846 {
847   gtk_container_foreach (GTK_CONTAINER (widget),
848                          (GtkCallback) child_show_all,
849                          NULL);
850   gtk_widget_show (widget);
851 }
852
853 static void
854 child_hide_all (GtkWidget *widget)
855 {
856   /* Don't hide our own children, since that would also hide
857    * widgets that won't be shown again by gtk_toolbar_show_all().
858    */
859   if (!g_object_get_data (G_OBJECT (widget),
860                           "gtk-toolbar-is-child"))
861     gtk_widget_hide_all (widget);
862 }
863
864 static void
865 gtk_toolbar_hide_all (GtkWidget *widget)
866 {
867   gtk_container_foreach (GTK_CONTAINER (widget),
868                          (GtkCallback) child_hide_all,
869                          NULL);
870   gtk_widget_hide (widget);
871 }
872
873 static void
874 gtk_toolbar_add (GtkContainer *container,
875                  GtkWidget    *widget)
876 {
877   g_return_if_fail (GTK_IS_TOOLBAR (container));
878   g_return_if_fail (widget != NULL);
879
880   gtk_toolbar_append_widget (GTK_TOOLBAR (container), widget, NULL, NULL);
881 }
882
883 static void
884 gtk_toolbar_remove (GtkContainer *container,
885                     GtkWidget    *widget)
886 {
887   GtkToolbar *toolbar;
888   GList *children;
889   GtkToolbarChild *child;
890
891   g_return_if_fail (GTK_IS_TOOLBAR (container));
892   g_return_if_fail (widget != NULL);
893
894   toolbar = GTK_TOOLBAR (container);
895
896   for (children = toolbar->children; children; children = children->next)
897     {
898       child = children->data;
899
900       if ((child->type != GTK_TOOLBAR_CHILD_SPACE) && (child->widget == widget))
901         {
902           gboolean was_visible;
903
904           was_visible = GTK_WIDGET_VISIBLE (widget);
905           gtk_widget_unparent (widget);
906
907           toolbar->children = g_list_remove_link (toolbar->children, children);
908           g_free (child);
909           g_list_free (children);
910           toolbar->num_children--;
911
912           if (was_visible && GTK_WIDGET_VISIBLE (container))
913             gtk_widget_queue_resize (GTK_WIDGET (container));
914
915           break;
916         }
917     }
918 }
919
920 static void
921 gtk_toolbar_forall (GtkContainer *container,
922                     gboolean      include_internals,
923                     GtkCallback   callback,
924                     gpointer      callback_data)
925 {
926   GtkToolbar *toolbar;
927   GList *children;
928   GtkToolbarChild *child;
929
930   g_return_if_fail (GTK_IS_TOOLBAR (container));
931   g_return_if_fail (callback != NULL);
932
933   toolbar = GTK_TOOLBAR (container);
934
935   for (children = toolbar->children; children; children = children->next)
936     {
937       child = children->data;
938
939       if (child->type != GTK_TOOLBAR_CHILD_SPACE)
940         (*callback) (child->widget, callback_data);
941     }
942 }
943
944 GtkWidget *
945 gtk_toolbar_append_item (GtkToolbar    *toolbar,
946                          const char    *text,
947                          const char    *tooltip_text,
948                          const char    *tooltip_private_text,
949                          GtkWidget     *icon,
950                          GtkSignalFunc  callback,
951                          gpointer       user_data)
952 {
953   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
954                                      NULL, text,
955                                      tooltip_text, tooltip_private_text,
956                                      icon, callback, user_data,
957                                      toolbar->num_children);
958 }
959
960 GtkWidget *
961 gtk_toolbar_prepend_item (GtkToolbar    *toolbar,
962                           const char    *text,
963                           const char    *tooltip_text,
964                           const char    *tooltip_private_text,
965                           GtkWidget     *icon,
966                           GtkSignalFunc  callback,
967                           gpointer       user_data)
968 {
969   return gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
970                                      NULL, text,
971                                      tooltip_text, tooltip_private_text,
972                                      icon, callback, user_data,
973                                      0);
974 }
975
976 static GtkWidget *
977 gtk_toolbar_internal_insert_item (GtkToolbar    *toolbar,
978                                   const char    *text,
979                                   const char    *tooltip_text,
980                                   const char    *tooltip_private_text,
981                                   GtkWidget     *icon,
982                                   GtkSignalFunc  callback,
983                                   gpointer       user_data,
984                                   gint           position)
985 {
986   return gtk_toolbar_internal_insert_element (toolbar, GTK_TOOLBAR_CHILD_BUTTON,
987                                               NULL, text,
988                                               tooltip_text, tooltip_private_text,
989                                               icon, callback, user_data,
990                                               position);
991 }
992      
993 GtkWidget *
994 gtk_toolbar_insert_item (GtkToolbar    *toolbar,
995                          const char    *text,
996                          const char    *tooltip_text,
997                          const char    *tooltip_private_text,
998                          GtkWidget     *icon,
999                          GtkSignalFunc  callback,
1000                          gpointer       user_data,
1001                          gint           position)
1002 {
1003   return gtk_toolbar_internal_insert_item (toolbar, 
1004                                            text, tooltip_text, tooltip_private_text,
1005                                            icon, callback, user_data,
1006                                            position);
1007 }
1008
1009 /**
1010  * gtk_toolbar_set_icon_size:
1011  * @toolbar: A #GtkToolbar
1012  * @icon_size: The #GtkIconSize that stock icons in the toolbar shall have.
1013  *
1014  * This function sets the size of stock icons in the toolbar. You
1015  * can call it both before you add the icons and after they've been
1016  * added. The size you set will override user preferences for the default
1017  * icon size.
1018  **/
1019 void
1020 gtk_toolbar_set_icon_size (GtkToolbar  *toolbar,
1021                            GtkIconSize  icon_size)
1022 {
1023   GList *children;
1024   GtkToolbarChild *child;
1025   GtkImage *image;
1026   gchar *stock_id;
1027
1028   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
1029
1030   toolbar->icon_size_set = TRUE;
1031   
1032   if (toolbar->icon_size == icon_size)
1033     return;
1034   
1035   toolbar->icon_size = icon_size;
1036
1037   for (children = toolbar->children; children; children = children->next)
1038     {
1039       child = children->data;
1040       if ((child->type == GTK_TOOLBAR_CHILD_BUTTON ||
1041            child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON ||
1042            child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON) &&
1043           GTK_IS_IMAGE (child->icon))
1044         {
1045           image = GTK_IMAGE (child->icon);
1046           if (gtk_image_get_storage_type (image) == GTK_IMAGE_STOCK)
1047             {
1048               gtk_image_get_stock (image, &stock_id, NULL);
1049               stock_id = g_strdup (stock_id);
1050               gtk_image_set_from_stock (image,
1051                                         stock_id,
1052                                         icon_size);
1053               g_free (stock_id);
1054             }
1055         }
1056     }
1057   
1058   gtk_widget_queue_resize (GTK_WIDGET (toolbar));
1059 }
1060
1061 /**
1062  * gtk_toolbar_get_icon_size:
1063  * @toolbar: a #GtkToolbar
1064  *
1065  * Retrieves the icon size fo the toolbar. See gtk_toolbar_set_icon_size().
1066  *
1067  * Return value: the current icon size for the icons on the toolbar.
1068  **/
1069 GtkIconSize
1070 gtk_toolbar_get_icon_size (GtkToolbar *toolbar)
1071 {
1072   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_ICON_SIZE);
1073
1074   return toolbar->icon_size;
1075 }
1076
1077 /**
1078  * gtk_toolbar_unset_icon_size:
1079  * @toolbar: a #GtkToolbar
1080  * 
1081  * Unsets toolbar icon size set with gtk_toolbar_set_icon_size(), so that
1082  * user preferences will be used to determine the icon size.
1083  **/
1084 void
1085 gtk_toolbar_unset_icon_size (GtkToolbar  *toolbar)
1086 {
1087   GtkIconSize size;
1088
1089   if (toolbar->icon_size_set)
1090     {
1091       GtkSettings *settings = toolbar_get_settings (toolbar);
1092
1093       if (settings)
1094         g_object_get (settings,
1095                       "gtk-toolbar-icon-size", &size,
1096                       NULL);
1097       else
1098         size = DEFAULT_ICON_SIZE;
1099
1100       if (size != toolbar->icon_size)
1101         gtk_toolbar_set_icon_size (toolbar, size);
1102
1103       toolbar->icon_size_set = FALSE;
1104     }
1105 }
1106
1107 static gchar *
1108 elide_underscores (const gchar *original)
1109 {
1110   gchar *q, *result;
1111   const gchar *p;
1112   gboolean last_underscore;
1113
1114   q = result = g_malloc (strlen (original) + 1);
1115   last_underscore = FALSE;
1116   
1117   for (p = original; *p; p++)
1118     {
1119       if (!last_underscore && *p == '_')
1120         last_underscore = TRUE;
1121       else
1122         {
1123           last_underscore = FALSE;
1124           *q++ = *p;
1125         }
1126     }
1127   
1128   *q = '\0';
1129   
1130   return result;
1131 }
1132
1133 /**
1134  * gtk_toolbar_insert_stock:
1135  * @toolbar: A #GtkToolbar
1136  * @stock_id: The id of the stock item you want to insert
1137  * @tooltip_text: The text in the tooltip of the toolbar button
1138  * @tooltip_private_text: The private text of the tooltip
1139  * @callback: The callback called when the toolbar button is clicked.
1140  * @user_data: user data passed to callback
1141  * @position: The position the button shall be inserted at.
1142  *            -1 means at the end.
1143  *
1144  * Inserts a stock item at the specified position of the toolbar.  If
1145  * @stock_id is not a known stock item ID, it's inserted verbatim,
1146  * except that underscores used to mark mnemonics are removed.
1147  *
1148  * Returns: the inserted widget
1149  */
1150 GtkWidget*
1151 gtk_toolbar_insert_stock (GtkToolbar      *toolbar,
1152                           const gchar     *stock_id,
1153                           const char      *tooltip_text,
1154                           const char      *tooltip_private_text,
1155                           GtkSignalFunc    callback,
1156                           gpointer         user_data,
1157                           gint             position)
1158 {
1159   GtkStockItem item;
1160   GtkWidget *image = NULL;
1161   const gchar *label;
1162   gchar *label_no_mnemonic;
1163   GtkWidget *retval;
1164
1165   if (gtk_stock_lookup (stock_id, &item))
1166     {
1167       image = gtk_image_new_from_stock (stock_id, toolbar->icon_size);
1168       label = item.label;
1169     }
1170   else
1171     label = stock_id;
1172
1173   label_no_mnemonic = elide_underscores (label);
1174   
1175   retval =  gtk_toolbar_internal_insert_item (toolbar,
1176                                               label_no_mnemonic,
1177                                               tooltip_text,
1178                                               tooltip_private_text,
1179                                               image,
1180                                               callback,
1181                                               user_data,
1182                                               position);
1183
1184   g_free (label_no_mnemonic);
1185
1186   return retval;
1187 }
1188
1189
1190
1191 void
1192 gtk_toolbar_append_space (GtkToolbar *toolbar)
1193 {
1194   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
1195                               NULL, NULL,
1196                               NULL, NULL,
1197                               NULL, NULL, NULL,
1198                               toolbar->num_children);
1199 }
1200
1201 void
1202 gtk_toolbar_prepend_space (GtkToolbar *toolbar)
1203 {
1204   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
1205                               NULL, NULL,
1206                               NULL, NULL,
1207                               NULL, NULL, NULL,
1208                               0);
1209 }
1210
1211 void
1212 gtk_toolbar_insert_space (GtkToolbar *toolbar,
1213                           gint        position)
1214 {
1215   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_SPACE,
1216                               NULL, NULL,
1217                               NULL, NULL,
1218                               NULL, NULL, NULL,
1219                               position);
1220 }
1221
1222 /**
1223  * gtk_toolbar_remove_space:
1224  * @toolbar: a #GtkToolbar.
1225  * @position: the index of the space to remove.
1226  * 
1227  * Removes a space from the specified position.
1228  **/
1229 void
1230 gtk_toolbar_remove_space (GtkToolbar *toolbar,
1231                           gint        position)
1232 {
1233   GList *children;
1234   GtkToolbarChild *child;
1235   gint i;
1236   
1237   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
1238   
1239   i = 0;
1240   for (children = toolbar->children; children; children = children->next)
1241     {
1242       child = children->data;
1243
1244       if (i == position)
1245         {
1246           if (child->type == GTK_TOOLBAR_CHILD_SPACE)
1247             {
1248               toolbar->children = g_list_remove_link (toolbar->children, children);
1249               g_free (child);
1250               g_list_free (children);
1251               toolbar->num_children--;
1252               
1253               gtk_widget_queue_resize (GTK_WIDGET (toolbar));
1254             }
1255           else
1256             {
1257               g_warning ("Toolbar position %d is not a space", position);
1258             }
1259
1260           return;
1261         }
1262
1263       ++i;
1264     }
1265
1266   g_warning ("Toolbar position %d doesn't exist", position);
1267 }
1268
1269 /**
1270  * gtk_toolbar_append_widget:
1271  * @toolbar: a #GtkToolbar.
1272  * @widget: a #GtkWidget to add to the toolbar. 
1273  * @tooltip_text: the element's tooltip.
1274  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
1275  * 
1276  * Adds a widget to the end of the given toolbar.
1277  **/ 
1278 void
1279 gtk_toolbar_append_widget (GtkToolbar  *toolbar,
1280                            GtkWidget   *widget,
1281                            const gchar *tooltip_text,
1282                            const gchar *tooltip_private_text)
1283 {
1284   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
1285                               widget, NULL,
1286                               tooltip_text, tooltip_private_text,
1287                               NULL, NULL, NULL,
1288                               toolbar->num_children);
1289 }
1290
1291 /**
1292  * gtk_toolbar_prepend_widget:
1293  * @toolbar: a #GtkToolbar.
1294  * @widget: a #GtkWidget to add to the toolbar. 
1295  * @tooltip_text: the element's tooltip.
1296  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
1297  * 
1298  * Adds a widget to the beginning of the given toolbar.
1299  **/ 
1300 void
1301 gtk_toolbar_prepend_widget (GtkToolbar  *toolbar,
1302                             GtkWidget   *widget,
1303                             const gchar *tooltip_text,
1304                             const gchar *tooltip_private_text)
1305 {
1306   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
1307                               widget, NULL,
1308                               tooltip_text, tooltip_private_text,
1309                               NULL, NULL, NULL,
1310                               0);
1311 }
1312
1313 /**
1314  * gtk_toolbar_insert_widget:
1315  * @toolbar: a #GtkToolbar.
1316  * @widget: a #GtkWidget to add to the toolbar. 
1317  * @tooltip_text: the element's tooltip.
1318  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
1319  * @position: the number of widgets to insert this widget after.
1320  * 
1321  * Inserts a widget in the toolbar at the given position.
1322  **/ 
1323 void
1324 gtk_toolbar_insert_widget (GtkToolbar *toolbar,
1325                            GtkWidget  *widget,
1326                            const char *tooltip_text,
1327                            const char *tooltip_private_text,
1328                            gint        position)
1329 {
1330   gtk_toolbar_insert_element (toolbar, GTK_TOOLBAR_CHILD_WIDGET,
1331                               widget, NULL,
1332                               tooltip_text, tooltip_private_text,
1333                               NULL, NULL, NULL,
1334                               position);
1335 }
1336
1337 GtkWidget*
1338 gtk_toolbar_append_element (GtkToolbar          *toolbar,
1339                             GtkToolbarChildType  type,
1340                             GtkWidget           *widget,
1341                             const char          *text,
1342                             const char          *tooltip_text,
1343                             const char          *tooltip_private_text,
1344                             GtkWidget           *icon,
1345                             GtkSignalFunc        callback,
1346                             gpointer             user_data)
1347 {
1348   return gtk_toolbar_insert_element (toolbar, type, widget, text,
1349                                      tooltip_text, tooltip_private_text,
1350                                      icon, callback, user_data,
1351                                      toolbar->num_children);
1352 }
1353
1354 GtkWidget *
1355 gtk_toolbar_prepend_element (GtkToolbar          *toolbar,
1356                              GtkToolbarChildType  type,
1357                              GtkWidget           *widget,
1358                              const char          *text,
1359                              const char          *tooltip_text,
1360                              const char          *tooltip_private_text,
1361                              GtkWidget           *icon,
1362                              GtkSignalFunc        callback,
1363                              gpointer             user_data)
1364 {
1365   return gtk_toolbar_insert_element (toolbar, type, widget, text,
1366                                      tooltip_text, tooltip_private_text,
1367                                      icon, callback, user_data, 0);
1368 }
1369
1370 /**
1371  * gtk_toolbar_insert_element:
1372  * @toolbar: a #GtkToolbar.
1373  * @type: a value of type #GtkToolbarChildType that determines what @widget
1374  *   will be.
1375  * @widget: a #GtkWidget, or %NULL. 
1376  * @text: the element's label.
1377  * @tooltip_text: the element's tooltip.
1378  * @tooltip_private_text: used for context-sensitive help about this toolbar element.
1379  * @icon: a #GtkWidget that provides pictorial representation of the element's function.
1380  * @callback: the function to be executed when the button is pressed.
1381  * @user_data: any data you wish to pass to the callback.
1382  * @position: the number of widgets to insert this element after.
1383  *
1384  * Inserts a new element in the toolbar at the given position. 
1385  *
1386  * If @type == %GTK_TOOLBAR_CHILD_WIDGET, @widget is used as the new element.
1387  * If @type == %GTK_TOOLBAR_CHILD_RADIOBUTTON, @widget is used to determine
1388  * the radio group for the new element. In all other cases, @widget must
1389  * be %NULL.
1390  *
1391  * Return value: the new toolbar element as a #GtkWidget.
1392  **/
1393 GtkWidget *
1394 gtk_toolbar_insert_element (GtkToolbar          *toolbar,
1395                             GtkToolbarChildType  type,
1396                             GtkWidget           *widget,
1397                             const char          *text,
1398                             const char          *tooltip_text,
1399                             const char          *tooltip_private_text,
1400                             GtkWidget           *icon,
1401                             GtkSignalFunc        callback,
1402                             gpointer             user_data,
1403                             gint                 position)
1404 {
1405   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
1406   if (type == GTK_TOOLBAR_CHILD_WIDGET)
1407     {
1408       g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1409     }
1410   else if (type != GTK_TOOLBAR_CHILD_RADIOBUTTON)
1411     g_return_val_if_fail (widget == NULL, NULL);
1412   
1413   return gtk_toolbar_internal_insert_element (toolbar, type, widget, text,
1414                                               tooltip_text, tooltip_private_text,
1415                                               icon, callback, user_data,
1416                                               position);
1417 }
1418
1419 static void
1420 set_child_packing_and_visibility(GtkToolbar      *toolbar,
1421                                  GtkToolbarChild *child)
1422 {
1423   GtkWidget *box;
1424   gboolean   expand;
1425
1426   box = gtk_bin_get_child (GTK_BIN (child->widget));
1427
1428   g_return_if_fail (GTK_IS_BOX (box));
1429
1430   if (child->label)
1431     {
1432       expand = (toolbar->style != GTK_TOOLBAR_BOTH);
1433
1434       gtk_box_set_child_packing (GTK_BOX (box), child->label,
1435                                  expand, expand, 0, GTK_PACK_END);
1436
1437       if (toolbar->style != GTK_TOOLBAR_ICONS)
1438         gtk_widget_show (child->label);
1439       else
1440         gtk_widget_hide (child->label);
1441     }
1442
1443   if (child->icon)
1444     {
1445       expand = (toolbar->style != GTK_TOOLBAR_BOTH_HORIZ);
1446
1447       gtk_box_set_child_packing (GTK_BOX (box), child->icon,
1448                                  expand, expand, 0, GTK_PACK_END);
1449
1450       if (toolbar->style != GTK_TOOLBAR_TEXT)
1451         gtk_widget_show (child->icon);
1452       else
1453         gtk_widget_hide (child->icon);
1454     }
1455 }
1456
1457 static GtkWidget *
1458 gtk_toolbar_internal_insert_element (GtkToolbar          *toolbar,
1459                                      GtkToolbarChildType  type,
1460                                      GtkWidget           *widget,
1461                                      const char          *text,
1462                                      const char          *tooltip_text,
1463                                      const char          *tooltip_private_text,
1464                                      GtkWidget           *icon,
1465                                      GtkSignalFunc        callback,
1466                                      gpointer             user_data,
1467                                      gint                 position)
1468 {
1469   GtkToolbarChild *child;
1470   GtkWidget *box;
1471
1472   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), NULL);
1473   if (type == GTK_TOOLBAR_CHILD_WIDGET)
1474     {
1475       g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1476     }
1477   else if (type != GTK_TOOLBAR_CHILD_RADIOBUTTON)
1478     g_return_val_if_fail (widget == NULL, NULL);
1479
1480   if (type == GTK_TOOLBAR_CHILD_SPACE)
1481     child = (GtkToolbarChild *) g_new (GtkToolbarChildSpace, 1);
1482   else
1483     child = g_new (GtkToolbarChild, 1);
1484
1485   child->type = type;
1486   child->icon = NULL;
1487   child->label = NULL;
1488
1489   switch (type)
1490     {
1491     case GTK_TOOLBAR_CHILD_SPACE:
1492       child->widget = NULL;
1493       ((GtkToolbarChildSpace *) child)->alloc_x =
1494         ((GtkToolbarChildSpace *) child)->alloc_y = 0;
1495       break;
1496
1497     case GTK_TOOLBAR_CHILD_WIDGET:
1498       child->widget = widget;
1499       break;
1500
1501     case GTK_TOOLBAR_CHILD_BUTTON:
1502     case GTK_TOOLBAR_CHILD_TOGGLEBUTTON:
1503     case GTK_TOOLBAR_CHILD_RADIOBUTTON:
1504       if (type == GTK_TOOLBAR_CHILD_BUTTON)
1505         {
1506           child->widget = gtk_button_new ();
1507           gtk_button_set_relief (GTK_BUTTON (child->widget), get_button_relief (toolbar));
1508         }
1509       else if (type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
1510         {
1511           child->widget = gtk_toggle_button_new ();
1512           gtk_button_set_relief (GTK_BUTTON (child->widget), get_button_relief (toolbar));
1513           gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child->widget),
1514                                       FALSE);
1515         }
1516       else
1517         {
1518           child->widget = gtk_radio_button_new (widget
1519                                                 ? gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget))
1520                                                 : NULL);
1521           gtk_button_set_relief (GTK_BUTTON (child->widget), get_button_relief (toolbar));
1522           gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (child->widget), FALSE);
1523         }
1524
1525       GTK_WIDGET_UNSET_FLAGS (child->widget, GTK_CAN_FOCUS);
1526
1527       if (callback)
1528         g_signal_connect (child->widget, "clicked",
1529                           callback, user_data);
1530
1531       if (toolbar->style == GTK_TOOLBAR_BOTH_HORIZ)
1532           box = gtk_hbox_new (FALSE, 0);
1533       else
1534           box = gtk_vbox_new (FALSE, 0);
1535       gtk_container_add (GTK_CONTAINER (child->widget), box);
1536       gtk_widget_show (box);
1537
1538       if (text)
1539         {
1540           child->label = gtk_label_new (text);
1541           gtk_container_add (GTK_CONTAINER (box), child->label);
1542         }
1543
1544       if (icon)
1545         {
1546           child->icon = GTK_WIDGET (icon);
1547           gtk_container_add (GTK_CONTAINER (box), child->icon);
1548         }
1549
1550       set_child_packing_and_visibility (toolbar, child);
1551
1552       /* Mark child as ours */
1553       g_object_set_data (G_OBJECT (child->widget),
1554                          "gtk-toolbar-is-child",
1555                          GINT_TO_POINTER (TRUE));
1556
1557       gtk_widget_show (child->widget);
1558       break;
1559
1560     default:
1561       g_assert_not_reached ();
1562     }
1563
1564   if ((type != GTK_TOOLBAR_CHILD_SPACE) && tooltip_text)
1565     gtk_tooltips_set_tip (toolbar->tooltips, child->widget,
1566                           tooltip_text, tooltip_private_text);
1567
1568   toolbar->children = g_list_insert (toolbar->children, child, position);
1569   toolbar->num_children++;
1570
1571   if (type != GTK_TOOLBAR_CHILD_SPACE)
1572     gtk_widget_set_parent (child->widget, GTK_WIDGET (toolbar));
1573   else
1574     gtk_widget_queue_resize (GTK_WIDGET (toolbar));
1575
1576   return child->widget;
1577 }
1578
1579 void
1580 gtk_toolbar_set_orientation (GtkToolbar     *toolbar,
1581                              GtkOrientation  orientation)
1582 {
1583   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
1584
1585   g_signal_emit (toolbar, toolbar_signals[ORIENTATION_CHANGED], 0, orientation);
1586 }
1587
1588 /**
1589  * gtk_toolbar_get_orientation:
1590  * @toolbar: a #GtkToolbar
1591  * 
1592  * Retrieves the current orientation of the toolbar. See
1593  * gtk_toolbar_set_orientation().
1594  *
1595  * Return value: the orientation
1596  **/
1597 GtkOrientation
1598 gtk_toolbar_get_orientation (GtkToolbar *toolbar)
1599 {
1600   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL);
1601
1602   return toolbar->orientation;
1603 }
1604
1605 void
1606 gtk_toolbar_set_style (GtkToolbar      *toolbar,
1607                        GtkToolbarStyle  style)
1608 {
1609   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
1610
1611   toolbar->style_set = TRUE;
1612   g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
1613 }
1614
1615 /**
1616  * gtk_toolbar_get_style:
1617  * @toolbar: a #GtkToolbar
1618  *
1619  * Retrieves whether the toolbar has text, icons, or both . See
1620  * gtk_toolbar_set_style().
1621  
1622  * Return value: the current style of @toolbar
1623  **/
1624 GtkToolbarStyle
1625 gtk_toolbar_get_style (GtkToolbar *toolbar)
1626 {
1627   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE);
1628
1629   return toolbar->style;
1630 }
1631
1632 /**
1633  * gtk_toolbar_unset_style:
1634  * @toolbar: a #GtkToolbar
1635  * 
1636  * Unsets a toolbar style set with gtk_toolbar_set_style(), so that
1637  * user preferences will be used to determine the toolbar style.
1638  **/
1639 void
1640 gtk_toolbar_unset_style (GtkToolbar *toolbar)
1641 {
1642   GtkToolbarStyle style;
1643   
1644   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
1645
1646   if (toolbar->style_set)
1647     {
1648       GtkSettings *settings = toolbar_get_settings (toolbar);
1649
1650       if (settings)
1651         g_object_get (settings,
1652                       "gtk-toolbar-style", &style,
1653                       NULL);
1654       else
1655         style = DEFAULT_TOOLBAR_STYLE;
1656
1657       if (style != toolbar->style)
1658         g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style);
1659       
1660       toolbar->style_set = FALSE;
1661     }
1662 }
1663
1664 void
1665 gtk_toolbar_set_tooltips (GtkToolbar *toolbar,
1666                           gboolean    enable)
1667 {
1668   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
1669
1670   if (enable)
1671     gtk_tooltips_enable (toolbar->tooltips);
1672   else
1673     gtk_tooltips_disable (toolbar->tooltips);
1674 }
1675
1676 /**
1677  * gtk_toolbar_get_tooltips:
1678  * @toolbar: a #GtkToolbar
1679  *
1680  * Retrieves whether tooltips are enabled. See
1681  * gtk_toolbar_set_tooltips().
1682  *
1683  * Return value: %TRUE if tooltips are enabled
1684  **/
1685 gboolean
1686 gtk_toolbar_get_tooltips (GtkToolbar *toolbar)
1687 {
1688   g_return_val_if_fail (GTK_IS_TOOLBAR (toolbar), FALSE);
1689
1690   return toolbar->tooltips->enabled;
1691 }
1692
1693 static void
1694 gtk_toolbar_update_button_relief (GtkToolbar *toolbar)
1695 {
1696   GList *children;
1697   GtkToolbarChild *child;
1698   GtkReliefStyle relief;
1699   
1700   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
1701
1702   relief = get_button_relief (toolbar);
1703   
1704   for (children = toolbar->children; children; children = children->next)
1705     {
1706       child = children->data;
1707       if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
1708           child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
1709           child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
1710         gtk_button_set_relief (GTK_BUTTON (child->widget), relief);
1711     }
1712 }
1713
1714 static void
1715 gtk_real_toolbar_orientation_changed (GtkToolbar     *toolbar,
1716                                       GtkOrientation  orientation)
1717 {
1718   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
1719
1720   if (toolbar->orientation != orientation)
1721     {
1722       toolbar->orientation = orientation;
1723       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
1724       g_object_notify (G_OBJECT (toolbar), "orientation");
1725     }
1726 }
1727
1728 static void
1729 gtk_real_toolbar_style_changed (GtkToolbar      *toolbar,
1730                                 GtkToolbarStyle  style)
1731 {
1732   GList *children;
1733   GtkToolbarChild *child;
1734   GtkWidget* box;
1735   
1736   g_return_if_fail (GTK_IS_TOOLBAR (toolbar));
1737
1738   if (toolbar->style != style)
1739     {
1740       toolbar->style = style;
1741
1742       for (children = toolbar->children; children; children = children->next)
1743         {
1744           child = children->data;
1745
1746           if (child->type == GTK_TOOLBAR_CHILD_BUTTON ||
1747               child->type == GTK_TOOLBAR_CHILD_RADIOBUTTON ||
1748               child->type == GTK_TOOLBAR_CHILD_TOGGLEBUTTON)
1749             {
1750               box = gtk_bin_get_child (GTK_BIN (child->widget));
1751
1752               if (style == GTK_TOOLBAR_BOTH && GTK_IS_HBOX (box))
1753                 {
1754                   GtkWidget *vbox;
1755
1756                   vbox = gtk_vbox_new (FALSE, 0);
1757
1758                   if (child->label)
1759                     gtk_widget_reparent (child->label, vbox);
1760                   if (child->icon)
1761                     gtk_widget_reparent (child->icon, vbox);
1762
1763                   gtk_widget_destroy (box);
1764                   gtk_container_add (GTK_CONTAINER (child->widget), vbox);
1765
1766                   gtk_widget_show (vbox);
1767                 }
1768               else if (style == GTK_TOOLBAR_BOTH_HORIZ && GTK_IS_VBOX (box))
1769                 {
1770                   GtkWidget *hbox;
1771
1772                   hbox = gtk_hbox_new (FALSE, 0);
1773
1774                   if (child->label)
1775                     gtk_widget_reparent (child->label, hbox);
1776                   if (child->icon)
1777                     gtk_widget_reparent (child->icon, hbox);
1778
1779                   gtk_widget_destroy (box);
1780                   gtk_container_add (GTK_CONTAINER (child->widget), hbox);
1781
1782                   gtk_widget_show (hbox);
1783                 }
1784
1785               set_child_packing_and_visibility (toolbar, child);
1786             }
1787         }
1788
1789       gtk_widget_queue_resize (GTK_WIDGET (toolbar));
1790       g_object_notify (G_OBJECT (toolbar), "toolbar_style");
1791     }
1792 }
1793
1794
1795 static GtkReliefStyle
1796 get_button_relief (GtkToolbar *toolbar)
1797 {
1798   GtkReliefStyle button_relief = GTK_RELIEF_NORMAL;
1799
1800   gtk_widget_ensure_style (GTK_WIDGET (toolbar));
1801   gtk_widget_style_get (GTK_WIDGET (toolbar),
1802                         "button_relief", &button_relief,
1803                         NULL);
1804
1805   return button_relief;
1806 }
1807
1808 static gint
1809 get_space_size (GtkToolbar *toolbar)
1810 {
1811   gint space_size = DEFAULT_SPACE_SIZE;
1812
1813   gtk_widget_style_get (GTK_WIDGET (toolbar),
1814                         "space_size", &space_size,
1815                         NULL);
1816
1817   return space_size;
1818 }
1819
1820 static GtkToolbarSpaceStyle
1821 get_space_style (GtkToolbar *toolbar)
1822 {
1823   GtkToolbarSpaceStyle space_style = DEFAULT_SPACE_STYLE;
1824
1825   gtk_widget_style_get (GTK_WIDGET (toolbar),
1826                         "space_style", &space_style,
1827                         NULL);
1828
1829
1830   return space_style;  
1831 }