]> Pileus Git - ~andy/gtk/blob - gtk/gtktoolbutton.c
Only set the accesible label if it is non-empty
[~andy/gtk] / gtk / gtktoolbutton.c
1 /* gtktoolbutton.c
2  *
3  * Copyright (C) 2002 Anders Carlsson <andersca@gnome.org>
4  * Copyright (C) 2002 James Henstridge <james@daa.com.au>
5  * Copyright (C) 2003 Soeren Sandmann <sandmann@daimi.au.dk>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "config.h"
24 #include "gtktoolbutton.h"
25 #include "gtkbutton.h"
26 #include "gtkhbox.h"
27 #include "gtkiconfactory.h"
28 #include "gtkimage.h"
29 #include "gtkimagemenuitem.h"
30 #include "gtklabel.h"
31 #include "gtkstock.h"
32 #include "gtkvbox.h"
33 #include "gtkintl.h"
34 #include "gtktoolbar.h"
35 #include "gtkactivatable.h"
36 #include "gtkprivate.h"
37 #include "gtkalias.h"
38
39 #include <string.h>
40
41 #define MENU_ID "gtk-tool-button-menu-id"
42
43 enum {
44   CLICKED,
45   LAST_SIGNAL
46 };
47
48 enum {
49   PROP_0,
50   PROP_LABEL,
51   PROP_USE_UNDERLINE,
52   PROP_LABEL_WIDGET,
53   PROP_STOCK_ID,
54   PROP_ICON_NAME,
55   PROP_ICON_WIDGET
56 };
57
58 static void gtk_tool_button_init          (GtkToolButton      *button,
59                                            GtkToolButtonClass *klass);
60 static void gtk_tool_button_class_init    (GtkToolButtonClass *klass);
61 static void gtk_tool_button_set_property  (GObject            *object,
62                                            guint               prop_id,
63                                            const GValue       *value,
64                                            GParamSpec         *pspec);
65 static void gtk_tool_button_get_property  (GObject            *object,
66                                            guint               prop_id,
67                                            GValue             *value,
68                                            GParamSpec         *pspec);
69 static void gtk_tool_button_property_notify (GObject          *object,
70                                              GParamSpec       *pspec);
71 static void gtk_tool_button_finalize      (GObject            *object);
72
73 static void gtk_tool_button_toolbar_reconfigured (GtkToolItem *tool_item);
74 static gboolean   gtk_tool_button_create_menu_proxy (GtkToolItem     *item);
75 static void       button_clicked                    (GtkWidget       *widget,
76                                                      GtkToolButton   *button);
77 static void gtk_tool_button_style_set      (GtkWidget          *widget,
78                                             GtkStyle           *prev_style);
79
80 static void gtk_tool_button_construct_contents (GtkToolItem *tool_item);
81
82 static void gtk_tool_button_activatable_interface_init (GtkActivatableIface  *iface);
83 static void gtk_tool_button_update                     (GtkActivatable       *activatable,
84                                                         GtkAction            *action,
85                                                         const gchar          *property_name);
86 static void gtk_tool_button_sync_action_properties     (GtkActivatable       *activatable,
87                                                         GtkAction            *action);
88
89
90 struct _GtkToolButtonPrivate
91 {
92   GtkWidget *button;
93
94   gchar *stock_id;
95   gchar *icon_name;
96   gchar *label_text;
97   GtkWidget *label_widget;
98   GtkWidget *icon_widget;
99   
100   guint use_underline : 1;
101   guint contents_invalid : 1;
102 };
103
104 static GObjectClass        *parent_class = NULL;
105 static GtkActivatableIface *parent_activatable_iface;
106 static guint                toolbutton_signals[LAST_SIGNAL] = { 0 };
107
108 #define GTK_TOOL_BUTTON_GET_PRIVATE(obj)(G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_TOOL_BUTTON, GtkToolButtonPrivate))
109
110 GType
111 gtk_tool_button_get_type (void)
112 {
113   static GType type = 0;
114   
115   if (!type)
116     {
117       static const GInterfaceInfo activatable_info =
118       {
119         (GInterfaceInitFunc) gtk_tool_button_activatable_interface_init,
120         (GInterfaceFinalizeFunc) NULL,
121         NULL
122       };
123
124       type = g_type_register_static_simple (GTK_TYPE_TOOL_ITEM,
125                                             I_("GtkToolButton"),
126                                             sizeof (GtkToolButtonClass),
127                                             (GClassInitFunc) gtk_tool_button_class_init,
128                                             sizeof (GtkToolButton),
129                                             (GInstanceInitFunc) gtk_tool_button_init,
130                                             0);
131
132       g_type_add_interface_static (type, GTK_TYPE_ACTIVATABLE,
133                                    &activatable_info);
134     }
135   return type;
136 }
137
138 static void
139 gtk_tool_button_class_init (GtkToolButtonClass *klass)
140 {
141   GObjectClass *object_class;
142   GtkWidgetClass *widget_class;
143   GtkToolItemClass *tool_item_class;
144   
145   parent_class = g_type_class_peek_parent (klass);
146   
147   object_class = (GObjectClass *)klass;
148   widget_class = (GtkWidgetClass *)klass;
149   tool_item_class = (GtkToolItemClass *)klass;
150   
151   object_class->set_property = gtk_tool_button_set_property;
152   object_class->get_property = gtk_tool_button_get_property;
153   object_class->notify = gtk_tool_button_property_notify;
154   object_class->finalize = gtk_tool_button_finalize;
155
156   widget_class->style_set = gtk_tool_button_style_set;
157
158   tool_item_class->create_menu_proxy = gtk_tool_button_create_menu_proxy;
159   tool_item_class->toolbar_reconfigured = gtk_tool_button_toolbar_reconfigured;
160   
161   klass->button_type = GTK_TYPE_BUTTON;
162
163   /* Properties are interpreted like this:
164    *
165    *          - if the tool button has an icon_widget, then that widget
166    *            will be used as the icon. Otherwise, if the tool button
167    *            has a stock id, the corresponding stock icon will be
168    *            used. Otherwise, if the tool button has an icon name,
169    *            the corresponding icon from the theme will be used.
170    *            Otherwise, the tool button will not have an icon.
171    *
172    *          - if the tool button has a label_widget then that widget
173    *            will be used as the label. Otherwise, if the tool button
174    *            has a label text, that text will be used as label. Otherwise,
175    *            if the toolbutton has a stock id, the corresponding text
176    *            will be used as label. Otherwise, if the tool button has
177    *            an icon name, the corresponding icon name from the theme will
178    *            be used. Otherwise, the toolbutton will have an empty label.
179    *
180    *          - The use_underline property only has an effect when the label
181    *            on the toolbutton comes from the label property (ie. not from
182    *            label_widget or from stock_id).
183    *
184    *            In that case, if use_underline is set,
185    *
186    *                    - underscores are removed from the label text before
187    *                      the label is shown on the toolbutton unless the
188    *                      underscore is followed by another underscore
189    *
190    *                    - an underscore indicates that the next character when
191    *                      used in the overflow menu should be used as a
192    *                      mnemonic.
193    *
194    *            In short: use_underline = TRUE means that the label text has
195    *            the form "_Open" and the toolbar should take appropriate
196    *            action.
197    */
198
199   g_object_class_install_property (object_class,
200                                    PROP_LABEL,
201                                    g_param_spec_string ("label",
202                                                         P_("Label"),
203                                                         P_("Text to show in the item."),
204                                                         NULL,
205                                                         GTK_PARAM_READWRITE));
206   g_object_class_install_property (object_class,
207                                    PROP_USE_UNDERLINE,
208                                    g_param_spec_boolean ("use-underline",
209                                                          P_("Use underline"),
210                                                          P_("If set, an underline in the label property indicates that the next character should be used for the mnemonic accelerator key in the overflow menu"),
211                                                          FALSE,
212                                                          GTK_PARAM_READWRITE));
213   g_object_class_install_property (object_class,
214                                    PROP_LABEL_WIDGET,
215                                    g_param_spec_object ("label-widget",
216                                                         P_("Label widget"),
217                                                         P_("Widget to use as the item label"),
218                                                         GTK_TYPE_WIDGET,
219                                                         GTK_PARAM_READWRITE));
220   g_object_class_install_property (object_class,
221                                    PROP_STOCK_ID,
222                                    g_param_spec_string ("stock-id",
223                                                         P_("Stock Id"),
224                                                         P_("The stock icon displayed on the item"),
225                                                         NULL,
226                                                         GTK_PARAM_READWRITE));
227
228   /**
229    * GtkToolButton:icon-name:
230    * 
231    * The name of the themed icon displayed on the item.
232    * This property only has an effect if not overridden by "label", 
233    * "icon_widget" or "stock_id" properties.
234    *
235    * Since: 2.8 
236    */
237   g_object_class_install_property (object_class,
238                                    PROP_ICON_NAME,
239                                    g_param_spec_string ("icon-name",
240                                                         P_("Icon name"),
241                                                         P_("The name of the themed icon displayed on the item"),
242                                                         NULL,
243                                                         GTK_PARAM_READWRITE));
244   g_object_class_install_property (object_class,
245                                    PROP_ICON_WIDGET,
246                                    g_param_spec_object ("icon-widget",
247                                                         P_("Icon widget"),
248                                                         P_("Icon widget to display in the item"),
249                                                         GTK_TYPE_WIDGET,
250                                                         GTK_PARAM_READWRITE));
251
252   /**
253    * GtkButton:icon-spacing:
254    * 
255    * Spacing in pixels between the icon and label.
256    * 
257    * Since: 2.10
258    */
259   gtk_widget_class_install_style_property (widget_class,
260                                            g_param_spec_int ("icon-spacing",
261                                                              P_("Icon spacing"),
262                                                              P_("Spacing in pixels between the icon and label"),
263                                                              0,
264                                                              G_MAXINT,
265                                                              0,
266                                                              GTK_PARAM_READWRITE));
267
268 /**
269  * GtkToolButton::clicked:
270  * @toolbutton: the object that emitted the signal
271  *
272  * This signal is emitted when the tool button is clicked with the mouse
273  * or activated with the keyboard.
274  **/
275   toolbutton_signals[CLICKED] =
276     g_signal_new (I_("clicked"),
277                   G_OBJECT_CLASS_TYPE (klass),
278                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
279                   G_STRUCT_OFFSET (GtkToolButtonClass, clicked),
280                   NULL, NULL,
281                   g_cclosure_marshal_VOID__VOID,
282                   G_TYPE_NONE, 0);
283   
284   g_type_class_add_private (object_class, sizeof (GtkToolButtonPrivate));
285 }
286
287 static void
288 gtk_tool_button_init (GtkToolButton      *button,
289                       GtkToolButtonClass *klass)
290 {
291   GtkToolItem *toolitem = GTK_TOOL_ITEM (button);
292   
293   button->priv = GTK_TOOL_BUTTON_GET_PRIVATE (button);
294
295   button->priv->contents_invalid = TRUE;
296
297   gtk_tool_item_set_homogeneous (toolitem, TRUE);
298
299   /* create button */
300   button->priv->button = g_object_new (klass->button_type, NULL);
301   gtk_button_set_focus_on_click (GTK_BUTTON (button->priv->button), FALSE);
302   g_signal_connect_object (button->priv->button, "clicked",
303                            G_CALLBACK (button_clicked), button, 0);
304
305   gtk_container_add (GTK_CONTAINER (button), button->priv->button);
306   gtk_widget_show (button->priv->button);
307 }
308
309 static void
310 gtk_tool_button_construct_contents (GtkToolItem *tool_item)
311 {
312   GtkToolButton *button = GTK_TOOL_BUTTON (tool_item);
313   GtkWidget *label = NULL;
314   GtkWidget *icon = NULL;
315   GtkToolbarStyle style;
316   gboolean need_label = FALSE;
317   gboolean need_icon = FALSE;
318   GtkIconSize icon_size;
319   GtkWidget *box = NULL;
320   guint icon_spacing;
321
322   button->priv->contents_invalid = FALSE;
323
324   gtk_widget_style_get (GTK_WIDGET (tool_item), 
325                         "icon-spacing", &icon_spacing,
326                         NULL);
327
328   if (button->priv->icon_widget && button->priv->icon_widget->parent)
329     {
330       gtk_container_remove (GTK_CONTAINER (button->priv->icon_widget->parent),
331                             button->priv->icon_widget);
332     }
333
334   if (button->priv->label_widget && button->priv->label_widget->parent)
335     {
336       gtk_container_remove (GTK_CONTAINER (button->priv->label_widget->parent),
337                             button->priv->label_widget);
338     }
339
340   if (GTK_BIN (button->priv->button)->child)
341     {
342       /* Note: we are not destroying the label_widget or icon_widget
343        * here because they were removed from their containers above
344        */
345       gtk_widget_destroy (GTK_BIN (button->priv->button)->child);
346     }
347
348   style = gtk_tool_item_get_toolbar_style (GTK_TOOL_ITEM (button));
349   
350   if (style != GTK_TOOLBAR_TEXT)
351     need_icon = TRUE;
352
353   if (style != GTK_TOOLBAR_ICONS && style != GTK_TOOLBAR_BOTH_HORIZ)
354     need_label = TRUE;
355
356   if (style == GTK_TOOLBAR_BOTH_HORIZ &&
357       (gtk_tool_item_get_is_important (GTK_TOOL_ITEM (button)) ||
358        gtk_tool_item_get_orientation (GTK_TOOL_ITEM (button)) == GTK_ORIENTATION_VERTICAL))
359     {
360       need_label = TRUE;
361     }
362   
363   if (style == GTK_TOOLBAR_ICONS && button->priv->icon_widget == NULL &&
364       button->priv->stock_id == NULL && button->priv->icon_name == NULL)
365     {
366       need_label = TRUE;
367       need_icon = FALSE;
368       style = GTK_TOOLBAR_TEXT;
369     }
370
371   if (style == GTK_TOOLBAR_TEXT && button->priv->label_widget == NULL &&
372       button->priv->stock_id == NULL && button->priv->label_text == NULL)
373     {
374       need_label = FALSE;
375       need_icon = TRUE;
376       style = GTK_TOOLBAR_ICONS;
377     }
378
379   if (need_label)
380     {
381       if (button->priv->label_widget)
382         {
383           label = button->priv->label_widget;
384         }
385       else
386         {
387           GtkStockItem stock_item;
388           gboolean elide;
389           gchar *label_text;
390
391           if (button->priv->label_text)
392             {
393               label_text = button->priv->label_text;
394               elide = button->priv->use_underline;
395             }
396           else if (button->priv->stock_id && gtk_stock_lookup (button->priv->stock_id, &stock_item))
397             {
398               label_text = stock_item.label;
399               elide = TRUE;
400             }
401           else
402             {
403               label_text = "";
404               elide = FALSE;
405             }
406
407           if (elide)
408             label_text = _gtk_toolbar_elide_underscores (label_text);
409           else
410             label_text = g_strdup (label_text);
411
412           label = gtk_label_new (label_text);
413
414           g_free (label_text);
415           
416           gtk_widget_show (label);
417         }
418     }
419
420   icon_size = gtk_tool_item_get_icon_size (GTK_TOOL_ITEM (button));
421   if (need_icon)
422     {
423       if (button->priv->icon_widget)
424         {
425           icon = button->priv->icon_widget;
426           
427           if (GTK_IS_IMAGE (icon))
428             {
429               g_object_set (button->priv->icon_widget,
430                             "icon-size", icon_size,
431                             NULL);
432             }
433         }
434       else if (button->priv->stock_id && 
435                gtk_icon_factory_lookup_default (button->priv->stock_id))
436         {
437           icon = gtk_image_new_from_stock (button->priv->stock_id, icon_size);
438           gtk_widget_show (icon);
439         }
440       else if (button->priv->icon_name)
441         {
442           icon = gtk_image_new_from_icon_name (button->priv->icon_name, icon_size);
443           gtk_widget_show (icon);
444         }
445     }
446
447   switch (style)
448     {
449     case GTK_TOOLBAR_ICONS:
450       if (icon)
451         gtk_container_add (GTK_CONTAINER (button->priv->button), icon);
452       break;
453
454     case GTK_TOOLBAR_BOTH:
455       box = gtk_vbox_new (FALSE, icon_spacing);
456       if (icon)
457         gtk_box_pack_start (GTK_BOX (box), icon, TRUE, TRUE, 0);
458       gtk_box_pack_end (GTK_BOX (box), label, FALSE, TRUE, 0);
459       gtk_container_add (GTK_CONTAINER (button->priv->button), box);
460       break;
461
462     case GTK_TOOLBAR_BOTH_HORIZ:
463       box = gtk_hbox_new (FALSE, icon_spacing);
464       if (icon)
465         gtk_box_pack_start (GTK_BOX (box), icon, label? FALSE : TRUE, TRUE, 0);
466       if (label)
467         gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
468       gtk_container_add (GTK_CONTAINER (button->priv->button), box);
469       break;
470
471     case GTK_TOOLBAR_TEXT:
472       gtk_container_add (GTK_CONTAINER (button->priv->button), label);
473       break;
474     }
475
476   if (box)
477     gtk_widget_show (box);
478
479   gtk_button_set_relief (GTK_BUTTON (button->priv->button),
480                          gtk_tool_item_get_relief_style (GTK_TOOL_ITEM (button)));
481
482   gtk_tool_item_rebuild_menu (tool_item);
483   
484   gtk_widget_queue_resize (GTK_WIDGET (button));
485 }
486
487 static void
488 gtk_tool_button_set_property (GObject         *object,
489                               guint            prop_id,
490                               const GValue    *value,
491                               GParamSpec      *pspec)
492 {
493   GtkToolButton *button = GTK_TOOL_BUTTON (object);
494   
495   switch (prop_id)
496     {
497     case PROP_LABEL:
498       gtk_tool_button_set_label (button, g_value_get_string (value));
499       break;
500     case PROP_USE_UNDERLINE:
501       gtk_tool_button_set_use_underline (button, g_value_get_boolean (value));
502       break;
503     case PROP_LABEL_WIDGET:
504       gtk_tool_button_set_label_widget (button, g_value_get_object (value));
505       break;
506     case PROP_STOCK_ID:
507       gtk_tool_button_set_stock_id (button, g_value_get_string (value));
508       break;
509     case PROP_ICON_NAME:
510       gtk_tool_button_set_icon_name (button, g_value_get_string (value));
511       break;
512     case PROP_ICON_WIDGET:
513       gtk_tool_button_set_icon_widget (button, g_value_get_object (value));
514       break;
515     default:
516       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
517       break;
518     }
519 }
520
521 static void
522 gtk_tool_button_property_notify (GObject          *object,
523                                  GParamSpec       *pspec)
524 {
525   GtkToolButton *button = GTK_TOOL_BUTTON (object);
526
527   if (button->priv->contents_invalid ||
528       strcmp ("is-important", pspec->name) == 0)
529     gtk_tool_button_construct_contents (GTK_TOOL_ITEM (object));
530
531   if (parent_class->notify)
532     parent_class->notify (object, pspec);
533 }
534
535 static void
536 gtk_tool_button_get_property (GObject         *object,
537                               guint            prop_id,
538                               GValue          *value,
539                               GParamSpec      *pspec)
540 {
541   GtkToolButton *button = GTK_TOOL_BUTTON (object);
542
543   switch (prop_id)
544     {
545     case PROP_LABEL:
546       g_value_set_string (value, gtk_tool_button_get_label (button));
547       break;
548     case PROP_LABEL_WIDGET:
549       g_value_set_object (value, gtk_tool_button_get_label_widget (button));
550       break;
551     case PROP_USE_UNDERLINE:
552       g_value_set_boolean (value, gtk_tool_button_get_use_underline (button));
553       break;
554     case PROP_STOCK_ID:
555       g_value_set_string (value, button->priv->stock_id);
556       break;
557     case PROP_ICON_NAME:
558       g_value_set_string (value, button->priv->icon_name);
559       break;
560     case PROP_ICON_WIDGET:
561       g_value_set_object (value, button->priv->icon_widget);
562       break;
563     default:
564       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
565       break;
566     }
567 }
568
569 static void
570 gtk_tool_button_finalize (GObject *object)
571 {
572   GtkToolButton *button = GTK_TOOL_BUTTON (object);
573
574   g_free (button->priv->stock_id);
575   g_free (button->priv->icon_name);
576   g_free (button->priv->label_text);
577
578   if (button->priv->label_widget)
579     g_object_unref (button->priv->label_widget);
580
581   if (button->priv->icon_widget)
582     g_object_unref (button->priv->icon_widget);
583   
584   parent_class->finalize (object);
585 }
586
587 static GtkWidget *
588 clone_image_menu_size (GtkImage *image, GtkSettings *settings)
589 {
590   GtkImageType storage_type = gtk_image_get_storage_type (image);
591
592   if (storage_type == GTK_IMAGE_STOCK)
593     {
594       gchar *stock_id;
595       gtk_image_get_stock (image, &stock_id, NULL);
596       return gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
597     }
598   else if (storage_type == GTK_IMAGE_ICON_SET)
599     {
600       GtkIconSet *icon_set;
601       gtk_image_get_icon_set (image, &icon_set, NULL);
602       return gtk_image_new_from_icon_set (icon_set, GTK_ICON_SIZE_MENU);
603     }
604   else if (storage_type == GTK_IMAGE_GICON)
605     {
606       GIcon *icon;
607       gtk_image_get_gicon (image, &icon, NULL);
608       return gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU);
609     }
610   else if (storage_type == GTK_IMAGE_PIXBUF)
611     {
612       gint width, height;
613       
614       if (settings &&
615           gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
616                                              &width, &height))
617         {
618           GdkPixbuf *src_pixbuf, *dest_pixbuf;
619           GtkWidget *cloned_image;
620
621           src_pixbuf = gtk_image_get_pixbuf (image);
622           dest_pixbuf = gdk_pixbuf_scale_simple (src_pixbuf, width, height,
623                                                  GDK_INTERP_BILINEAR);
624
625           cloned_image = gtk_image_new_from_pixbuf (dest_pixbuf);
626           g_object_unref (dest_pixbuf);
627
628           return cloned_image;
629         }
630     }
631
632   return NULL;
633 }
634       
635 static gboolean
636 gtk_tool_button_create_menu_proxy (GtkToolItem *item)
637 {
638   GtkToolButton *button = GTK_TOOL_BUTTON (item);
639   GtkWidget *menu_item;
640   GtkWidget *menu_image = NULL;
641   GtkStockItem stock_item;
642   gboolean use_mnemonic = TRUE;
643   const char *label;
644
645   if (_gtk_tool_item_create_menu_proxy (item))
646     return TRUE;
647  
648   if (GTK_IS_LABEL (button->priv->label_widget))
649     {
650       label = gtk_label_get_label (GTK_LABEL (button->priv->label_widget));
651       use_mnemonic = gtk_label_get_use_underline (GTK_LABEL (button->priv->label_widget));
652     }
653   else if (button->priv->label_text)
654     {
655       label = button->priv->label_text;
656       use_mnemonic = button->priv->use_underline;
657     }
658   else if (button->priv->stock_id && gtk_stock_lookup (button->priv->stock_id, &stock_item))
659     {
660       label = stock_item.label;
661     }
662   else
663     {
664       label = "";
665     }
666   
667   if (use_mnemonic)
668     menu_item = gtk_image_menu_item_new_with_mnemonic (label);
669   else
670     menu_item = gtk_image_menu_item_new_with_label (label);
671
672   if (GTK_IS_IMAGE (button->priv->icon_widget))
673     {
674       menu_image = clone_image_menu_size (GTK_IMAGE (button->priv->icon_widget),
675                                           gtk_widget_get_settings (GTK_WIDGET (button)));
676     }
677   else if (button->priv->stock_id)
678     {
679       menu_image = gtk_image_new_from_stock (button->priv->stock_id, GTK_ICON_SIZE_MENU);
680     }
681
682   if (menu_image)
683     gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), menu_image);
684
685   g_signal_connect_closure_by_id (menu_item,
686                                   g_signal_lookup ("activate", G_OBJECT_TYPE (menu_item)), 0,
687                                   g_cclosure_new_object_swap (G_CALLBACK (gtk_button_clicked),
688                                                               G_OBJECT (GTK_TOOL_BUTTON (button)->priv->button)),
689                                   FALSE);
690
691   gtk_tool_item_set_proxy_menu_item (GTK_TOOL_ITEM (button), MENU_ID, menu_item);
692   
693   return TRUE;
694 }
695
696 static void
697 button_clicked (GtkWidget     *widget,
698                 GtkToolButton *button)
699 {
700   GtkAction *action;
701
702   action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (button));
703   
704   if (action)
705     gtk_action_activate (action);
706
707   g_signal_emit_by_name (button, "clicked");
708 }
709
710 static void
711 gtk_tool_button_toolbar_reconfigured (GtkToolItem *tool_item)
712 {
713   gtk_tool_button_construct_contents (tool_item);
714 }
715
716 static void 
717 gtk_tool_button_update_icon_spacing (GtkToolButton *button)
718 {
719   GtkWidget *box;
720   guint spacing;
721
722   box = GTK_BIN (button->priv->button)->child;
723   if (GTK_IS_BOX (box))
724     {
725       gtk_widget_style_get (GTK_WIDGET (button), 
726                             "icon-spacing", &spacing,
727                             NULL);
728       gtk_box_set_spacing (GTK_BOX (box), spacing);      
729     }
730 }
731
732 static void
733 gtk_tool_button_style_set (GtkWidget *widget,
734                            GtkStyle  *prev_style)
735 {
736   gtk_tool_button_update_icon_spacing (GTK_TOOL_BUTTON (widget));
737 }
738
739 static void 
740 gtk_tool_button_activatable_interface_init (GtkActivatableIface  *iface)
741 {
742   parent_activatable_iface = g_type_interface_peek_parent (iface);
743   iface->update = gtk_tool_button_update;
744   iface->sync_action_properties = gtk_tool_button_sync_action_properties;
745 }
746
747 static void
748 gtk_tool_button_update (GtkActivatable *activatable,
749                         GtkAction      *action,
750                         const gchar    *property_name)
751 {
752   GtkToolButton *button;
753   GtkWidget *image;
754
755   parent_activatable_iface->update (activatable, action, property_name);
756
757   if (!gtk_activatable_get_use_action_appearance (activatable))
758     return;
759
760   button = GTK_TOOL_BUTTON (activatable);
761   
762   if (strcmp (property_name, "short-label") == 0)
763     gtk_tool_button_set_label (button, gtk_action_get_short_label (action));
764   else if (strcmp (property_name, "stock-id") == 0)
765     gtk_tool_button_set_stock_id (button, gtk_action_get_stock_id (action));
766   else if (strcmp (property_name, "gicon") == 0)
767     {
768       const gchar *stock_id = gtk_action_get_stock_id (action);
769       GIcon *icon = gtk_action_get_gicon (action);
770       GtkIconSize icon_size = GTK_ICON_SIZE_BUTTON;
771
772       if ((stock_id && gtk_icon_factory_lookup_default (stock_id)) || !icon)
773         image = NULL;
774       else 
775         {   
776           image = gtk_tool_button_get_icon_widget (button);
777           icon_size = gtk_tool_item_get_icon_size (GTK_TOOL_ITEM (button));
778
779           if (!image)
780             image = gtk_image_new ();
781         }
782
783       gtk_tool_button_set_icon_widget (button, image);
784       gtk_image_set_from_gicon (GTK_IMAGE (image), icon, icon_size);
785
786     }
787   else if (strcmp (property_name, "icon-name") == 0)
788     gtk_tool_button_set_icon_name (button, gtk_action_get_icon_name (action));
789 }
790
791 static void
792 gtk_tool_button_sync_action_properties (GtkActivatable *activatable,
793                                         GtkAction      *action)
794 {
795   GtkToolButton *button;
796   GIcon         *icon;
797   const gchar   *stock_id;
798
799   parent_activatable_iface->sync_action_properties (activatable, action);
800
801   if (!action)
802     return;
803
804   if (!gtk_activatable_get_use_action_appearance (activatable))
805     return;
806
807   button = GTK_TOOL_BUTTON (activatable);
808   stock_id = gtk_action_get_stock_id (action);
809
810   gtk_tool_button_set_label (button, gtk_action_get_short_label (action));
811   gtk_tool_button_set_use_underline (button, TRUE);
812   gtk_tool_button_set_stock_id (button, stock_id);
813   gtk_tool_button_set_icon_name (button, gtk_action_get_icon_name (action));
814
815   if (stock_id && gtk_icon_factory_lookup_default (stock_id))
816       gtk_tool_button_set_icon_widget (button, NULL);
817   else if ((icon = gtk_action_get_gicon (action)) != NULL)
818     {
819       GtkIconSize icon_size = gtk_tool_item_get_icon_size (GTK_TOOL_ITEM (button));
820       GtkWidget  *image = gtk_tool_button_get_icon_widget (button);
821       
822       if (!image)
823         {
824           image = gtk_image_new ();
825           gtk_widget_show (image);
826           gtk_tool_button_set_icon_widget (button, image);
827         }
828
829       gtk_image_set_from_gicon (GTK_IMAGE (image), icon, icon_size);
830     }
831   else if (gtk_action_get_icon_name (action))
832     gtk_tool_button_set_icon_name (button, gtk_action_get_icon_name (action));
833   else
834     gtk_tool_button_set_label (button, gtk_action_get_short_label (action));
835 }
836
837 /**
838  * gtk_tool_button_new_from_stock:
839  * @stock_id: the name of the stock item 
840  *
841  * Creates a new #GtkToolButton containing the image and text from a
842  * stock item. Some stock ids have preprocessor macros like #GTK_STOCK_OK
843  * and #GTK_STOCK_APPLY.
844  *
845  * It is an error if @stock_id is not a name of a stock item.
846  * 
847  * Return value: A new #GtkToolButton
848  * 
849  * Since: 2.4
850  **/
851 GtkToolItem *
852 gtk_tool_button_new_from_stock (const gchar *stock_id)
853 {
854   GtkToolButton *button;
855
856   g_return_val_if_fail (stock_id != NULL, NULL);
857     
858   button = g_object_new (GTK_TYPE_TOOL_BUTTON,
859                          "stock-id", stock_id,
860                          NULL);
861
862   return GTK_TOOL_ITEM (button);
863 }
864
865 /**
866  * gtk_tool_button_new:
867  * @label: a string that will be used as label, or %NULL
868  * @icon_widget: a widget that will be used as icon widget, or %NULL
869  * 
870  * Creates a new %GtkToolButton using @icon_widget as icon and @label as
871  * label.
872  * 
873  * Return value: A new #GtkToolButton
874  * 
875  * Since: 2.4
876  **/
877 GtkToolItem *
878 gtk_tool_button_new (GtkWidget   *icon_widget,
879                      const gchar *label)
880 {
881   GtkToolButton *button;
882
883   button = g_object_new (GTK_TYPE_TOOL_BUTTON,
884                          "label", label,
885                          "icon-widget", icon_widget,
886                          NULL);
887
888   return GTK_TOOL_ITEM (button);  
889 }
890
891 /**
892  * gtk_tool_button_set_label:
893  * @button: a #GtkToolButton
894  * @label: a string that will be used as label, or %NULL.
895  * 
896  * Sets @label as the label used for the tool button. The "label" property
897  * only has an effect if not overridden by a non-%NULL "label_widget" property.
898  * If both the "label_widget" and "label" properties are %NULL, the label
899  * is determined by the "stock_id" property. If the "stock_id" property is also
900  * %NULL, @button will not have a label.
901  * 
902  * Since: 2.4
903  **/
904 void
905 gtk_tool_button_set_label (GtkToolButton *button,
906                            const gchar   *label)
907 {
908   gchar *old_label;
909   gchar *elided_label;
910   AtkObject *accessible;
911   
912   g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
913
914   old_label = button->priv->label_text;
915
916   button->priv->label_text = g_strdup (label);
917   button->priv->contents_invalid = TRUE;     
918
919   if (label)
920     {
921       elided_label = _gtk_toolbar_elide_underscores (label);
922       accessible = gtk_widget_get_accessible (GTK_WIDGET (button->priv->button));
923       atk_object_set_name (accessible, elided_label);
924       g_free (elided_label);
925     }
926
927   g_free (old_label);
928  
929   g_object_notify (G_OBJECT (button), "label");
930 }
931
932 /**
933  * gtk_tool_button_get_label:
934  * @button: a #GtkToolButton
935  * 
936  * Returns the label used by the tool button, or %NULL if the tool button
937  * doesn't have a label. or uses a the label from a stock item. The returned
938  * string is owned by GTK+, and must not be modified or freed.
939  * 
940  * Return value: The label, or %NULL
941  * 
942  * Since: 2.4
943  **/
944 G_CONST_RETURN gchar *
945 gtk_tool_button_get_label (GtkToolButton *button)
946 {
947   g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL);
948
949   return button->priv->label_text;
950 }
951
952 /**
953  * gtk_tool_button_set_use_underline:
954  * @button: a #GtkToolButton
955  * @use_underline: whether the button label has the form "_Open"
956  *
957  * If set, an underline in the label property indicates that the next character
958  * should be used for the mnemonic accelerator key in the overflow menu. For
959  * example, if the label property is "_Open" and @use_underline is %TRUE,
960  * the label on the tool button will be "Open" and the item on the overflow
961  * menu will have an underlined 'O'.
962  * 
963  * Labels shown on tool buttons never have mnemonics on them; this property
964  * only affects the menu item on the overflow menu.
965  * 
966  * Since: 2.4
967  **/
968 void
969 gtk_tool_button_set_use_underline (GtkToolButton *button,
970                                    gboolean       use_underline)
971 {
972   g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
973
974   use_underline = use_underline != FALSE;
975
976   if (use_underline != button->priv->use_underline)
977     {
978       button->priv->use_underline = use_underline;
979       button->priv->contents_invalid = TRUE;
980
981       g_object_notify (G_OBJECT (button), "use-underline");
982     }
983 }
984
985 /**
986  * gtk_tool_button_get_use_underline:
987  * @button: a #GtkToolButton
988  * 
989  * Returns whether underscores in the label property are used as mnemonics
990  * on menu items on the overflow menu. See gtk_tool_button_set_use_underline().
991  * 
992  * Return value: %TRUE if underscores in the label property are used as
993  * mnemonics on menu items on the overflow menu.
994  * 
995  * Since: 2.4
996  **/
997 gboolean
998 gtk_tool_button_get_use_underline (GtkToolButton *button)
999 {
1000   g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), FALSE);
1001
1002   return button->priv->use_underline;
1003 }
1004
1005 /**
1006  * gtk_tool_button_set_stock_id:
1007  * @button: a #GtkToolButton
1008  * @stock_id: a name of a stock item, or %NULL
1009  * 
1010  * Sets the name of the stock item. See gtk_tool_button_new_from_stock().
1011  * The stock_id property only has an effect if not
1012  * overridden by non-%NULL "label" and "icon_widget" properties.
1013  * 
1014  * Since: 2.4
1015  **/
1016 void
1017 gtk_tool_button_set_stock_id (GtkToolButton *button,
1018                               const gchar   *stock_id)
1019 {
1020   gchar *old_stock_id;
1021   
1022   g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
1023
1024   old_stock_id = button->priv->stock_id;
1025
1026   button->priv->stock_id = g_strdup (stock_id);
1027   button->priv->contents_invalid = TRUE;
1028
1029   g_free (old_stock_id);
1030   
1031   g_object_notify (G_OBJECT (button), "stock-id");
1032 }
1033
1034 /**
1035  * gtk_tool_button_get_stock_id:
1036  * @button: a #GtkToolButton
1037  * 
1038  * Returns the name of the stock item. See gtk_tool_button_set_stock_id().
1039  * The returned string is owned by GTK+ and must not be freed or modifed.
1040  * 
1041  * Return value: the name of the stock item for @button.
1042  * 
1043  * Since: 2.4
1044  **/
1045 G_CONST_RETURN gchar *
1046 gtk_tool_button_get_stock_id (GtkToolButton *button)
1047 {
1048   g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL);
1049
1050   return button->priv->stock_id;
1051 }
1052
1053 /**
1054  * gtk_tool_button_set_icon_name
1055  * @button: a #GtkToolButton
1056  * @icon_name: the name of the themed icon
1057  * 
1058  * Sets the icon for the tool button from a named themed icon.
1059  * See the docs for #GtkIconTheme for more details.
1060  * The "icon_name" property only has an effect if not
1061  * overridden by non-%NULL "label", "icon_widget" and "stock_id"
1062  * properties.
1063  * 
1064  * Since: 2.8
1065  **/
1066 void
1067 gtk_tool_button_set_icon_name (GtkToolButton *button,
1068                                const gchar   *icon_name)
1069 {
1070   gchar *old_icon_name;
1071
1072   g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
1073
1074   old_icon_name = button->priv->icon_name;
1075
1076   button->priv->icon_name = g_strdup (icon_name);
1077   button->priv->contents_invalid = TRUE; 
1078
1079   g_free (old_icon_name);
1080
1081   g_object_notify (G_OBJECT (button), "icon-name");
1082 }
1083
1084 /**
1085  * gtk_tool_button_get_icon_name
1086  * @button: a #GtkToolButton
1087  * 
1088  * Returns the name of the themed icon for the tool button,
1089  * see gtk_tool_button_set_icon_name().
1090  *
1091  * Returns: the icon name or %NULL if the tool button has
1092  * no themed icon
1093  * 
1094  * Since: 2.8
1095  **/
1096 G_CONST_RETURN gchar*
1097 gtk_tool_button_get_icon_name (GtkToolButton *button)
1098 {
1099   g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL);
1100
1101   return button->priv->icon_name;
1102 }
1103
1104 /**
1105  * gtk_tool_button_set_icon_widget:
1106  * @button: a #GtkToolButton
1107  * @icon_widget: the widget used as icon, or %NULL
1108  * 
1109  * Sets @icon as the widget used as icon on @button. If @icon_widget is
1110  * %NULL the icon is determined by the "stock_id" property. If the
1111  * "stock_id" property is also %NULL, @button will not have an icon.
1112  * 
1113  * Since: 2.4
1114  **/
1115 void
1116 gtk_tool_button_set_icon_widget (GtkToolButton *button,
1117                                  GtkWidget     *icon_widget)
1118 {
1119   g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
1120   g_return_if_fail (icon_widget == NULL || GTK_IS_WIDGET (icon_widget));
1121
1122   if (icon_widget != button->priv->icon_widget)
1123     {
1124       if (button->priv->icon_widget)
1125         {
1126           if (button->priv->icon_widget->parent)
1127             gtk_container_remove (GTK_CONTAINER (button->priv->icon_widget->parent),
1128                                     button->priv->icon_widget);
1129
1130           g_object_unref (button->priv->icon_widget);
1131         }
1132       
1133       if (icon_widget)
1134         g_object_ref_sink (icon_widget);
1135
1136       button->priv->icon_widget = icon_widget;
1137       button->priv->contents_invalid = TRUE;
1138       
1139       g_object_notify (G_OBJECT (button), "icon-widget");
1140     }
1141 }
1142
1143 /**
1144  * gtk_tool_button_set_label_widget:
1145  * @button: a #GtkToolButton
1146  * @label_widget: the widget used as label, or %NULL
1147  * 
1148  * Sets @label_widget as the widget that will be used as the label
1149  * for @button. If @label_widget is %NULL the "label" property is used
1150  * as label. If "label" is also %NULL, the label in the stock item
1151  * determined by the "stock_id" property is used as label. If
1152  * "stock_id" is also %NULL, @button does not have a label.
1153  * 
1154  * Since: 2.4
1155  **/
1156 void
1157 gtk_tool_button_set_label_widget (GtkToolButton *button,
1158                                   GtkWidget     *label_widget)
1159 {
1160   g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
1161   g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget));
1162
1163   if (label_widget != button->priv->label_widget)
1164     {
1165       if (button->priv->label_widget)
1166         {
1167           if (button->priv->label_widget->parent)
1168             gtk_container_remove (GTK_CONTAINER (button->priv->label_widget->parent),
1169                                   button->priv->label_widget);
1170           
1171           g_object_unref (button->priv->label_widget);
1172         }
1173       
1174       if (label_widget)
1175         g_object_ref_sink (label_widget);
1176
1177       button->priv->label_widget = label_widget;
1178       button->priv->contents_invalid = TRUE;
1179       
1180       g_object_notify (G_OBJECT (button), "label-widget");
1181     }
1182 }
1183
1184 /**
1185  * gtk_tool_button_get_label_widget:
1186  * @button: a #GtkToolButton
1187  * 
1188  * Returns the widget used as label on @button. See
1189  * gtk_tool_button_set_label_widget().
1190  * 
1191  * Return value: The widget used as label on @button, or %NULL.
1192  * 
1193  * Since: 2.4
1194  **/
1195 GtkWidget *
1196 gtk_tool_button_get_label_widget (GtkToolButton *button)
1197 {
1198   g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL);
1199
1200   return button->priv->label_widget;
1201 }
1202
1203 /**
1204  * gtk_tool_button_get_icon_widget:
1205  * @button: a #GtkToolButton
1206  * 
1207  * Return the widget used as icon widget on @button. See
1208  * gtk_tool_button_set_icon_widget().
1209  * 
1210  * Return value: The widget used as icon on @button, or %NULL.
1211  * 
1212  * Since: 2.4
1213  **/
1214 GtkWidget *
1215 gtk_tool_button_get_icon_widget (GtkToolButton *button)
1216 {
1217   g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL);
1218
1219   return button->priv->icon_widget;
1220 }
1221
1222 GtkWidget *
1223 _gtk_tool_button_get_button (GtkToolButton *button)
1224 {
1225   g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL);
1226
1227   return button->priv->button;
1228 }
1229
1230
1231 #define __GTK_TOOL_BUTTON_C__
1232 #include "gtkaliasdef.c"