]> Pileus Git - ~andy/gtk/blob - gtk/gtkbutton.c
: Mark param spec strings as static.
[~andy/gtk] / gtk / gtkbutton.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2001.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <config.h>
28 #include <string.h>
29 #include "gtkalignment.h"
30 #include "gtkbutton.h"
31 #include "gtklabel.h"
32 #include "gtkmain.h"
33 #include "gtkmarshalers.h"
34 #include "gtkimage.h"
35 #include "gtkhbox.h"
36 #include "gtkstock.h"
37 #include "gtkiconfactory.h"
38 #include "gtkintl.h"
39 #include "gtkalias.h"
40
41 #define CHILD_SPACING     1
42
43 static const GtkBorder default_default_border = { 1, 1, 1, 1 };
44 static const GtkBorder default_default_outside_border = { 0, 0, 0, 0 };
45
46 /* Time out before giving up on getting a key release when animating
47  * the close button.
48  */
49 #define ACTIVATE_TIMEOUT 250
50
51 enum {
52   PRESSED,
53   RELEASED,
54   CLICKED,
55   ENTER,
56   LEAVE,
57   ACTIVATE,
58   LAST_SIGNAL
59 };
60
61 enum {
62   PROP_0,
63   PROP_LABEL,
64   PROP_IMAGE,
65   PROP_RELIEF,
66   PROP_USE_UNDERLINE,
67   PROP_USE_STOCK,
68   PROP_FOCUS_ON_CLICK,
69   PROP_XALIGN,
70   PROP_YALIGN,
71 };
72
73 #define GTK_BUTTON_GET_PRIVATE(o)       (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_BUTTON, GtkButtonPrivate))
74 typedef struct _GtkButtonPrivate GtkButtonPrivate;
75
76 struct _GtkButtonPrivate
77 {
78   gfloat       xalign;
79   gfloat       yalign;
80   GtkWidget   *image;
81   guint        align_set : 1;
82   guint        image_is_stock : 1;
83 };
84
85 static void gtk_button_class_init     (GtkButtonClass   *klass);
86 static void gtk_button_init           (GtkButton        *button);
87 static void gtk_button_destroy        (GtkObject        *object);
88 static void gtk_button_set_property   (GObject         *object,
89                                        guint            prop_id,
90                                        const GValue    *value,
91                                        GParamSpec      *pspec);
92 static void gtk_button_get_property   (GObject         *object,
93                                        guint            prop_id,
94                                        GValue          *value,
95                                        GParamSpec      *pspec);
96 static void gtk_button_screen_changed (GtkWidget        *widget,
97                                        GdkScreen        *previous_screen);
98 static void gtk_button_realize        (GtkWidget        *widget);
99 static void gtk_button_unrealize      (GtkWidget        *widget);
100 static void gtk_button_map            (GtkWidget        *widget);
101 static void gtk_button_unmap          (GtkWidget        *widget);
102 static void gtk_button_size_request   (GtkWidget        *widget,
103                                        GtkRequisition   *requisition);
104 static void gtk_button_size_allocate  (GtkWidget        *widget,
105                                        GtkAllocation    *allocation);
106 static gint gtk_button_expose         (GtkWidget        *widget,
107                                        GdkEventExpose   *event);
108 static gint gtk_button_button_press   (GtkWidget        *widget,
109                                        GdkEventButton   *event);
110 static gint gtk_button_button_release (GtkWidget        *widget,
111                                        GdkEventButton   *event);
112 static gint gtk_button_key_release    (GtkWidget        *widget,
113                                        GdkEventKey      *event);
114 static gint gtk_button_enter_notify   (GtkWidget        *widget,
115                                        GdkEventCrossing *event);
116 static gint gtk_button_leave_notify   (GtkWidget        *widget,
117                                        GdkEventCrossing *event);
118 static void gtk_real_button_pressed   (GtkButton        *button);
119 static void gtk_real_button_released  (GtkButton        *button);
120 static void gtk_real_button_activate  (GtkButton         *button);
121 static void gtk_button_update_state   (GtkButton        *button);
122 static void gtk_button_add            (GtkContainer   *container,
123                                        GtkWidget      *widget);
124 static GType gtk_button_child_type    (GtkContainer     *container);
125 static void gtk_button_finish_activate (GtkButton *button,
126                                         gboolean   do_it);
127
128 static GObject* gtk_button_constructor (GType                  type,
129                                         guint                  n_construct_properties,
130                                         GObjectConstructParam *construct_params);
131 static void gtk_button_construct_child (GtkButton             *button);
132 static void gtk_button_state_changed   (GtkWidget             *widget,
133                                         GtkStateType           previous_state);
134 static void gtk_button_grab_notify     (GtkWidget             *widget,
135                                         gboolean               was_grabbed);
136
137
138
139 static GtkBinClass *parent_class = NULL;
140 static guint button_signals[LAST_SIGNAL] = { 0 };
141
142
143 GType
144 gtk_button_get_type (void)
145 {
146   static GType button_type = 0;
147
148   if (!button_type)
149     {
150       static const GTypeInfo button_info =
151       {
152         sizeof (GtkButtonClass),
153         NULL,           /* base_init */
154         NULL,           /* base_finalize */
155         (GClassInitFunc) gtk_button_class_init,
156         NULL,           /* class_finalize */
157         NULL,           /* class_data */
158         sizeof (GtkButton),
159         16,             /* n_preallocs */
160         (GInstanceInitFunc) gtk_button_init,
161       };
162
163       button_type = g_type_register_static (GTK_TYPE_BIN, "GtkButton",
164                                             &button_info, 0);
165     }
166
167   return button_type;
168 }
169
170 static void
171 gtk_button_class_init (GtkButtonClass *klass)
172 {
173   GObjectClass *gobject_class;
174   GtkObjectClass *object_class;
175   GtkWidgetClass *widget_class;
176   GtkContainerClass *container_class;
177
178   gobject_class = G_OBJECT_CLASS (klass);
179   object_class = (GtkObjectClass*) klass;
180   widget_class = (GtkWidgetClass*) klass;
181   container_class = (GtkContainerClass*) klass;
182   
183   parent_class = g_type_class_peek_parent (klass);
184
185   gobject_class->constructor = gtk_button_constructor;
186   gobject_class->set_property = gtk_button_set_property;
187   gobject_class->get_property = gtk_button_get_property;
188
189   object_class->destroy = gtk_button_destroy;
190
191   widget_class->screen_changed = gtk_button_screen_changed;
192   widget_class->realize = gtk_button_realize;
193   widget_class->unrealize = gtk_button_unrealize;
194   widget_class->map = gtk_button_map;
195   widget_class->unmap = gtk_button_unmap;
196   widget_class->size_request = gtk_button_size_request;
197   widget_class->size_allocate = gtk_button_size_allocate;
198   widget_class->expose_event = gtk_button_expose;
199   widget_class->button_press_event = gtk_button_button_press;
200   widget_class->button_release_event = gtk_button_button_release;
201   widget_class->key_release_event = gtk_button_key_release;
202   widget_class->enter_notify_event = gtk_button_enter_notify;
203   widget_class->leave_notify_event = gtk_button_leave_notify;
204   widget_class->state_changed = gtk_button_state_changed;
205   widget_class->grab_notify = gtk_button_grab_notify;
206
207   container_class->child_type = gtk_button_child_type;
208   container_class->add = gtk_button_add;
209
210   klass->pressed = gtk_real_button_pressed;
211   klass->released = gtk_real_button_released;
212   klass->clicked = NULL;
213   klass->enter = gtk_button_update_state;
214   klass->leave = gtk_button_update_state;
215   klass->activate = gtk_real_button_activate;
216
217 #define STATIC_STRINGS G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
218
219   g_object_class_install_property (gobject_class,
220                                    PROP_LABEL,
221                                    g_param_spec_string ("label",
222                                                         P_("Label"),
223                                                         P_("Text of the label widget inside the button, if the button contains a label widget"),
224                                                         NULL,
225                                                         G_PARAM_READWRITE | STATIC_STRINGS | G_PARAM_CONSTRUCT));
226   
227   g_object_class_install_property (gobject_class,
228                                    PROP_USE_UNDERLINE,
229                                    g_param_spec_boolean ("use-underline",
230                                                          P_("Use underline"),
231                                                          P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
232                                                         FALSE,
233                                                         G_PARAM_READWRITE | STATIC_STRINGS | G_PARAM_CONSTRUCT));
234   
235   g_object_class_install_property (gobject_class,
236                                    PROP_USE_STOCK,
237                                    g_param_spec_boolean ("use-stock",
238                                                          P_("Use stock"),
239                                                          P_("If set, the label is used to pick a stock item instead of being displayed"),
240                                                         FALSE,
241                                                         G_PARAM_READWRITE | STATIC_STRINGS | G_PARAM_CONSTRUCT));
242   
243   g_object_class_install_property (gobject_class,
244                                    PROP_FOCUS_ON_CLICK,
245                                    g_param_spec_boolean ("focus-on-click",
246                                                          P_("Focus on click"),
247                                                          P_("Whether the button grabs focus when it is clicked with the mouse"),
248                                                          TRUE,
249                                                          G_PARAM_READWRITE | STATIC_STRINGS));
250   
251   g_object_class_install_property (gobject_class,
252                                    PROP_RELIEF,
253                                    g_param_spec_enum ("relief",
254                                                       P_("Border relief"),
255                                                       P_("The border relief style"),
256                                                       GTK_TYPE_RELIEF_STYLE,
257                                                       GTK_RELIEF_NORMAL,
258                                                       G_PARAM_READWRITE | STATIC_STRINGS));
259   
260   /**
261    * GtkButton:xalign:
262    *
263    * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
264    * can be used to control it's horizontal alignment. 0.0 is left aligned, 
265    * 1.0 is right aligned.
266    * 
267    * Since: 2.4
268    */
269   g_object_class_install_property (gobject_class,
270                                    PROP_XALIGN,
271                                    g_param_spec_float("xalign",
272                                                       P_("Horizontal alignment for child"),
273                                                       P_("Horizontal position of child in available space. 0.0 is left aligned, 1.0 is right aligned"),
274                                                       0.0,
275                                                       1.0,
276                                                       0.5,
277                                                       G_PARAM_READWRITE | STATIC_STRINGS));
278
279   /**
280    * GtkButton:yalign:
281    *
282    * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
283    * can be used to control it's vertical alignment. 0.0 is top aligned, 
284    * 1.0 is bottom aligned.
285    * 
286    * Since: 2.4
287    */
288   g_object_class_install_property (gobject_class,
289                                    PROP_YALIGN,
290                                    g_param_spec_float("yalign",
291                                                       P_("Vertical alignment for child"),
292                                                       P_("Vertical position of child in available space. 0.0 is top aligned, 1.0 is bottom aligned"),
293                                                       0.0,
294                                                       1.0,
295                                                       0.5,
296                                                       G_PARAM_READWRITE | STATIC_STRINGS));
297
298   /**
299    * GtkButton::image:
300    * 
301    * The child widget to appear next to the button text.
302    * 
303    * Since: 2.6
304    */
305   g_object_class_install_property (gobject_class,
306                                    PROP_IMAGE,
307                                    g_param_spec_object ("image",
308                                                         P_("Image widget"),
309                                                         P_("Child widget to appear next to the button text"),
310                                                         GTK_TYPE_WIDGET,
311                                                         G_PARAM_READWRITE | STATIC_STRINGS));
312
313   button_signals[PRESSED] =
314     g_signal_new ("pressed",
315                   G_OBJECT_CLASS_TYPE (object_class),
316                   G_SIGNAL_RUN_FIRST,
317                   G_STRUCT_OFFSET (GtkButtonClass, pressed),
318                   NULL, NULL,
319                   _gtk_marshal_VOID__VOID,
320                   G_TYPE_NONE, 0);
321   button_signals[RELEASED] =
322     g_signal_new ("released",
323                   G_OBJECT_CLASS_TYPE (object_class),
324                   G_SIGNAL_RUN_FIRST,
325                   G_STRUCT_OFFSET (GtkButtonClass, released),
326                   NULL, NULL,
327                   _gtk_marshal_VOID__VOID,
328                   G_TYPE_NONE, 0);
329   button_signals[CLICKED] =
330     g_signal_new ("clicked",
331                   G_OBJECT_CLASS_TYPE (object_class),
332                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
333                   G_STRUCT_OFFSET (GtkButtonClass, clicked),
334                   NULL, NULL,
335                   _gtk_marshal_VOID__VOID,
336                   G_TYPE_NONE, 0);
337   button_signals[ENTER] =
338     g_signal_new ("enter",
339                   G_OBJECT_CLASS_TYPE (object_class),
340                   G_SIGNAL_RUN_FIRST,
341                   G_STRUCT_OFFSET (GtkButtonClass, enter),
342                   NULL, NULL,
343                   _gtk_marshal_VOID__VOID,
344                   G_TYPE_NONE, 0);
345   button_signals[LEAVE] =
346     g_signal_new ("leave",
347                   G_OBJECT_CLASS_TYPE (object_class),
348                   G_SIGNAL_RUN_FIRST,
349                   G_STRUCT_OFFSET (GtkButtonClass, leave),
350                   NULL, NULL,
351                   _gtk_marshal_VOID__VOID,
352                   G_TYPE_NONE, 0);
353
354   /**
355    * GtkButton::activate:
356    * @widget: the object which received the signal.
357    *
358    * The "activate" signal on GtkButton is an action signal and
359    * emitting it causes the button to animate press then release. 
360    * Applications should never connect to this signal, but use the
361    * "clicked" signal.
362    */
363   button_signals[ACTIVATE] =
364     g_signal_new ("activate",
365                   G_OBJECT_CLASS_TYPE (object_class),
366                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
367                   G_STRUCT_OFFSET (GtkButtonClass, activate),
368                   NULL, NULL,
369                   _gtk_marshal_VOID__VOID,
370                   G_TYPE_NONE, 0);
371   widget_class->activate_signal = button_signals[ACTIVATE];
372
373   gtk_widget_class_install_style_property (widget_class,
374                                            g_param_spec_boxed ("default-border",
375                                                                P_("Default Spacing"),
376                                                                P_("Extra space to add for CAN_DEFAULT buttons"),
377                                                                GTK_TYPE_BORDER,
378                                                                G_PARAM_READABLE | STATIC_STRINGS));
379
380   gtk_widget_class_install_style_property (widget_class,
381                                            g_param_spec_boxed ("default-outside-border",
382                                                                P_("Default Outside Spacing"),
383                                                                P_("Extra space to add for CAN_DEFAULT buttons that is always drawn outside the border"),
384                                                                GTK_TYPE_BORDER,
385                                                                G_PARAM_READABLE | STATIC_STRINGS));
386   gtk_widget_class_install_style_property (widget_class,
387                                            g_param_spec_int ("child-displacement-x",
388                                                              P_("Child X Displacement"),
389                                                              P_("How far in the x direction to move the child when the button is depressed"),
390                                                              G_MININT,
391                                                              G_MAXINT,
392                                                              0,
393                                                              G_PARAM_READABLE | STATIC_STRINGS));
394   gtk_widget_class_install_style_property (widget_class,
395                                            g_param_spec_int ("child-displacement-y",
396                                                              P_("Child Y Displacement"),
397                                                              P_("How far in the y direction to move the child when the button is depressed"),
398                                                              G_MININT,
399                                                              G_MAXINT,
400                                                              0,
401                                                              G_PARAM_READABLE | STATIC_STRINGS));
402
403   /**
404    * GtkButton:displace-focus:
405    *
406    * Whether the child_displacement_x/child_displacement_y properties should also 
407    * affect the focus rectangle.
408    *
409    * Since: 2.6
410    */
411   gtk_widget_class_install_style_property (widget_class,
412                                            g_param_spec_boolean ("displace-focus",
413                                                                  P_("Displace focus"),
414                                                                  P_("Whether the child_displacement_x/_y properties should also affect the focus rectangle"),
415                                                        FALSE,
416                                                        G_PARAM_READABLE | STATIC_STRINGS));
417
418   gtk_settings_install_property (g_param_spec_boolean ("gtk-button-images",
419                                                        P_("Show button images"),
420                                                        P_("Whether stock icons should be shown in buttons"),
421                                                        TRUE,
422                                                        G_PARAM_READWRITE | STATIC_STRINGS));
423   
424   g_type_class_add_private (gobject_class, sizeof (GtkButtonPrivate));  
425 }
426
427 static void
428 gtk_button_init (GtkButton *button)
429 {
430   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
431
432   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_FOCUS | GTK_RECEIVES_DEFAULT);
433   GTK_WIDGET_SET_FLAGS (button, GTK_NO_WINDOW);
434
435   button->label_text = NULL;
436   
437   button->constructed = FALSE;
438   button->in_button = FALSE;
439   button->button_down = FALSE;
440   button->relief = GTK_RELIEF_NORMAL;
441   button->use_stock = FALSE;
442   button->use_underline = FALSE;
443   button->depressed = FALSE;
444   button->depress_on_activate = TRUE;
445   button->focus_on_click = TRUE;
446
447   priv->xalign = 0.5;
448   priv->yalign = 0.5;
449   priv->align_set = 0;
450   priv->image_is_stock = TRUE;
451 }
452
453 static void
454 gtk_button_destroy (GtkObject *object)
455 {
456   GtkButton *button = GTK_BUTTON (object);
457   
458   if (button->label_text)
459     {
460       g_free (button->label_text);
461       button->label_text = NULL;
462     }
463   
464   (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
465 }
466
467 static GObject*
468 gtk_button_constructor (GType                  type,
469                         guint                  n_construct_properties,
470                         GObjectConstructParam *construct_params)
471 {
472   GObject *object;
473   GtkButton *button;
474
475   object = (* G_OBJECT_CLASS (parent_class)->constructor) (type,
476                                                            n_construct_properties,
477                                                            construct_params);
478
479   button = GTK_BUTTON (object);
480   button->constructed = TRUE;
481
482   if (button->label_text != NULL)
483     gtk_button_construct_child (button);
484   
485   return object;
486 }
487
488
489 static GType
490 gtk_button_child_type  (GtkContainer     *container)
491 {
492   if (!GTK_BIN (container)->child)
493     return GTK_TYPE_WIDGET;
494   else
495     return G_TYPE_NONE;
496 }
497
498 static void
499 maybe_set_alignment (GtkButton *button,
500                      GtkWidget *widget)
501 {
502   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
503
504   if (GTK_IS_MISC (widget))
505     {
506       GtkMisc *misc = GTK_MISC (widget);
507       
508       if (priv->align_set)
509         gtk_misc_set_alignment (misc, priv->xalign, priv->yalign);
510     }
511   else if (GTK_IS_ALIGNMENT (widget))
512     {
513       GtkAlignment *alignment = GTK_ALIGNMENT (widget);
514
515       if (priv->align_set)
516         gtk_alignment_set (alignment, priv->xalign, priv->yalign, 
517                            alignment->xscale, alignment->yscale);
518     }
519 }
520
521 static void
522 gtk_button_add (GtkContainer *container,
523                 GtkWidget    *widget)
524 {
525   maybe_set_alignment (GTK_BUTTON (container), widget);
526
527   GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
528 }
529
530 static void
531 gtk_button_set_property (GObject         *object,
532                          guint            prop_id,
533                          const GValue    *value,
534                          GParamSpec      *pspec)
535 {
536   GtkButton *button = GTK_BUTTON (object);
537   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
538
539   switch (prop_id)
540     {
541     case PROP_LABEL:
542       gtk_button_set_label (button, g_value_get_string (value));
543       break;
544     case PROP_IMAGE:
545       gtk_button_set_image (button, (GtkWidget *) g_value_get_object (value));
546       break;
547     case PROP_RELIEF:
548       gtk_button_set_relief (button, g_value_get_enum (value));
549       break;
550     case PROP_USE_UNDERLINE:
551       gtk_button_set_use_underline (button, g_value_get_boolean (value));
552       break;
553     case PROP_USE_STOCK:
554       gtk_button_set_use_stock (button, g_value_get_boolean (value));
555       break;
556     case PROP_FOCUS_ON_CLICK:
557       gtk_button_set_focus_on_click (button, g_value_get_boolean (value));
558       break;
559     case PROP_XALIGN:
560       gtk_button_set_alignment (button, g_value_get_float (value), priv->yalign);
561       break;
562     case PROP_YALIGN:
563       gtk_button_set_alignment (button, priv->xalign, g_value_get_float (value));
564       break;
565     default:
566       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
567       break;
568     }
569 }
570
571 static void
572 gtk_button_get_property (GObject         *object,
573                          guint            prop_id,
574                          GValue          *value,
575                          GParamSpec      *pspec)
576 {
577   GtkButton *button = GTK_BUTTON (object);
578   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
579
580   switch (prop_id)
581     {
582     case PROP_LABEL:
583       g_value_set_string (value, button->label_text);
584       break;
585     case PROP_IMAGE:
586       g_value_set_object (value, (GObject *)priv->image);
587       break;
588     case PROP_RELIEF:
589       g_value_set_enum (value, gtk_button_get_relief (button));
590       break;
591     case PROP_USE_UNDERLINE:
592       g_value_set_boolean (value, button->use_underline);
593       break;
594     case PROP_USE_STOCK:
595       g_value_set_boolean (value, button->use_stock);
596       break;
597     case PROP_FOCUS_ON_CLICK:
598       g_value_set_boolean (value, button->focus_on_click);
599       break;
600     case PROP_XALIGN:
601       g_value_set_float (value, priv->xalign);
602       break;
603     case PROP_YALIGN:
604       g_value_set_float (value, priv->yalign);
605       break;
606     default:
607       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
608       break;
609     }
610 }
611
612 GtkWidget*
613 gtk_button_new (void)
614 {
615   return g_object_new (GTK_TYPE_BUTTON, NULL);
616 }
617
618 static gboolean
619 show_image (GtkButton *button)
620 {
621   GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (button));  
622   gboolean show;
623
624   g_object_get (settings, "gtk-button-images", &show, NULL);
625
626   return show;
627 }
628
629 static void
630 gtk_button_construct_child (GtkButton *button)
631 {
632   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
633   GtkStockItem item;
634   GtkWidget *label;
635   GtkWidget *hbox;
636   GtkWidget *align;
637   GtkWidget *image = NULL;
638   gchar *label_text = NULL;
639   
640   if (!button->constructed)
641     return;
642   
643   if (button->label_text == NULL)
644     return;
645
646   if (GTK_BIN (button)->child)
647     {
648       if (priv->image && !priv->image_is_stock)
649         image = g_object_ref (priv->image);
650
651       gtk_container_remove (GTK_CONTAINER (button),
652                             GTK_BIN (button)->child);
653   
654       priv->image = NULL;
655     }
656   
657   if (button->use_stock &&
658       gtk_stock_lookup (button->label_text, &item))
659     {
660       if (!image)
661         image = g_object_ref (gtk_image_new_from_stock (button->label_text, GTK_ICON_SIZE_BUTTON));
662
663       label_text = item.label;
664     }
665   else
666     label_text = button->label_text;
667
668   if (image)
669     {
670       label = gtk_label_new_with_mnemonic (label_text);
671       gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
672       
673       priv->image = image;
674
675       g_object_set (priv->image, 
676                     "visible", show_image (button),
677                     "no_show_all", TRUE,
678                     NULL);
679       hbox = gtk_hbox_new (FALSE, 2);
680
681       if (priv->align_set)
682         align = gtk_alignment_new (priv->xalign, priv->yalign, 0.0, 0.0);
683       else
684         align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
685         
686       gtk_box_pack_start (GTK_BOX (hbox), priv->image, FALSE, FALSE, 0);
687       gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
688       
689       gtk_container_add (GTK_CONTAINER (button), align);
690       gtk_container_add (GTK_CONTAINER (align), hbox);
691       gtk_widget_show_all (align);
692
693       g_object_unref (image);
694
695       return;
696     }
697   
698  if (button->use_underline)
699     {
700       label = gtk_label_new_with_mnemonic (button->label_text);
701       gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
702     }
703   else
704     label = gtk_label_new (button->label_text);
705   
706   if (priv->align_set)
707     gtk_misc_set_alignment (GTK_MISC (label), priv->xalign, priv->yalign);
708
709   gtk_widget_show (label);
710   gtk_container_add (GTK_CONTAINER (button), label);
711 }
712
713
714 GtkWidget*
715 gtk_button_new_with_label (const gchar *label)
716 {
717   return g_object_new (GTK_TYPE_BUTTON, "label", label, NULL);
718 }
719
720 /**
721  * gtk_button_new_from_stock:
722  * @stock_id: the name of the stock item 
723  *
724  * Creates a new #GtkButton containing the image and text from a stock item.
725  * Some stock ids have preprocessor macros like #GTK_STOCK_OK and
726  * #GTK_STOCK_APPLY.
727  *
728  * If @stock_id is unknown, then it will be treated as a mnemonic
729  * label (as for gtk_button_new_with_mnemonic()).
730  *
731  * Returns: a new #GtkButton
732  **/
733 GtkWidget*
734 gtk_button_new_from_stock (const gchar *stock_id)
735 {
736   return g_object_new (GTK_TYPE_BUTTON,
737                        "label", stock_id,
738                        "use_stock", TRUE,
739                        "use_underline", TRUE,
740                        NULL);
741 }
742
743 /**
744  * gtk_button_new_with_mnemonic:
745  * @label: The text of the button, with an underscore in front of the
746  *         mnemonic character
747  * @returns: a new #GtkButton
748  *
749  * Creates a new #GtkButton containing a label.
750  * If characters in @label are preceded by an underscore, they are underlined.
751  * If you need a literal underscore character in a label, use '__' (two 
752  * underscores). The first underlined character represents a keyboard 
753  * accelerator called a mnemonic.
754  * Pressing Alt and that key activates the button.
755  **/
756 GtkWidget*
757 gtk_button_new_with_mnemonic (const gchar *label)
758 {
759   return g_object_new (GTK_TYPE_BUTTON, "label", label, "use_underline", TRUE,  NULL);
760 }
761
762 void
763 gtk_button_pressed (GtkButton *button)
764 {
765   g_return_if_fail (GTK_IS_BUTTON (button));
766
767   
768   g_signal_emit (button, button_signals[PRESSED], 0);
769 }
770
771 void
772 gtk_button_released (GtkButton *button)
773 {
774   g_return_if_fail (GTK_IS_BUTTON (button));
775
776   g_signal_emit (button, button_signals[RELEASED], 0);
777 }
778
779 void
780 gtk_button_clicked (GtkButton *button)
781 {
782   g_return_if_fail (GTK_IS_BUTTON (button));
783
784   g_signal_emit (button, button_signals[CLICKED], 0);
785 }
786
787 void
788 gtk_button_enter (GtkButton *button)
789 {
790   g_return_if_fail (GTK_IS_BUTTON (button));
791
792   g_signal_emit (button, button_signals[ENTER], 0);
793 }
794
795 void
796 gtk_button_leave (GtkButton *button)
797 {
798   g_return_if_fail (GTK_IS_BUTTON (button));
799
800   g_signal_emit (button, button_signals[LEAVE], 0);
801 }
802
803 void
804 gtk_button_set_relief (GtkButton *button,
805                        GtkReliefStyle newrelief)
806 {
807   g_return_if_fail (GTK_IS_BUTTON (button));
808
809   if (newrelief != button->relief) 
810     {
811        button->relief = newrelief;
812        g_object_notify (G_OBJECT (button), "relief");
813        gtk_widget_queue_draw (GTK_WIDGET (button));
814     }
815 }
816
817 GtkReliefStyle
818 gtk_button_get_relief (GtkButton *button)
819 {
820   g_return_val_if_fail (GTK_IS_BUTTON (button), GTK_RELIEF_NORMAL);
821
822   return button->relief;
823 }
824
825 static void
826 gtk_button_realize (GtkWidget *widget)
827 {
828   GtkButton *button;
829   GdkWindowAttr attributes;
830   gint attributes_mask;
831   gint border_width;
832
833   button = GTK_BUTTON (widget);
834   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
835
836   border_width = GTK_CONTAINER (widget)->border_width;
837
838   attributes.window_type = GDK_WINDOW_CHILD;
839   attributes.x = widget->allocation.x + border_width;
840   attributes.y = widget->allocation.y + border_width;
841   attributes.width = widget->allocation.width - border_width * 2;
842   attributes.height = widget->allocation.height - border_width * 2;
843   attributes.wclass = GDK_INPUT_ONLY;
844   attributes.event_mask = gtk_widget_get_events (widget);
845   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
846                             GDK_BUTTON_RELEASE_MASK |
847                             GDK_ENTER_NOTIFY_MASK |
848                             GDK_LEAVE_NOTIFY_MASK);
849
850   attributes_mask = GDK_WA_X | GDK_WA_Y;
851
852   widget->window = gtk_widget_get_parent_window (widget);
853   g_object_ref (widget->window);
854   
855   button->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
856                                          &attributes, attributes_mask);
857   gdk_window_set_user_data (button->event_window, button);
858
859   widget->style = gtk_style_attach (widget->style, widget->window);
860 }
861
862 static void
863 gtk_button_unrealize (GtkWidget *widget)
864 {
865   GtkButton *button = GTK_BUTTON (widget);
866
867   if (button->activate_timeout)
868     gtk_button_finish_activate (button, FALSE);
869
870   if (button->event_window)
871     {
872       gdk_window_set_user_data (button->event_window, NULL);
873       gdk_window_destroy (button->event_window);
874       button->event_window = NULL;
875     }
876   
877   GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
878 }
879
880 static void
881 gtk_button_map (GtkWidget *widget)
882 {
883   GtkButton *button = GTK_BUTTON (widget);
884   
885   GTK_WIDGET_CLASS (parent_class)->map (widget);
886
887   if (button->event_window)
888     gdk_window_show (button->event_window);
889 }
890
891 static void
892 gtk_button_unmap (GtkWidget *widget)
893 {
894   GtkButton *button = GTK_BUTTON (widget);
895     
896   if (button->event_window)
897     gdk_window_hide (button->event_window);
898
899   GTK_WIDGET_CLASS (parent_class)->unmap (widget);
900 }
901
902 static void
903 gtk_button_get_props (GtkButton *button,
904                       GtkBorder *default_border,
905                       GtkBorder *default_outside_border,
906                       gboolean  *interior_focus)
907 {
908   GtkWidget *widget =  GTK_WIDGET (button);
909   GtkBorder *tmp_border;
910
911   if (default_border)
912     {
913       gtk_widget_style_get (widget, "default_border", &tmp_border, NULL);
914
915       if (tmp_border)
916         {
917           *default_border = *tmp_border;
918           g_free (tmp_border);
919         }
920       else
921         *default_border = default_default_border;
922     }
923
924   if (default_outside_border)
925     {
926       gtk_widget_style_get (widget, "default_outside_border", &tmp_border, NULL);
927
928       if (tmp_border)
929         {
930           *default_outside_border = *tmp_border;
931           g_free (tmp_border);
932         }
933       else
934         *default_outside_border = default_default_outside_border;
935     }
936
937   if (interior_focus)
938     gtk_widget_style_get (widget, "interior_focus", interior_focus, NULL);
939 }
940         
941 static void
942 gtk_button_size_request (GtkWidget      *widget,
943                          GtkRequisition *requisition)
944 {
945   GtkButton *button = GTK_BUTTON (widget);
946   GtkBorder default_border;
947   gint focus_width;
948   gint focus_pad;
949
950   gtk_button_get_props (button, &default_border, NULL, NULL);
951   gtk_widget_style_get (GTK_WIDGET (widget),
952                         "focus-line-width", &focus_width,
953                         "focus-padding", &focus_pad,
954                         NULL);
955  
956   requisition->width = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
957                         GTK_WIDGET (widget)->style->xthickness) * 2;
958   requisition->height = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
959                          GTK_WIDGET (widget)->style->ythickness) * 2;
960
961   if (GTK_WIDGET_CAN_DEFAULT (widget))
962     {
963       requisition->width += default_border.left + default_border.right;
964       requisition->height += default_border.top + default_border.bottom;
965     }
966
967   if (GTK_BIN (button)->child && GTK_WIDGET_VISIBLE (GTK_BIN (button)->child))
968     {
969       GtkRequisition child_requisition;
970
971       gtk_widget_size_request (GTK_BIN (button)->child, &child_requisition);
972
973       requisition->width += child_requisition.width;
974       requisition->height += child_requisition.height;
975     }
976   
977   requisition->width += 2 * (focus_width + focus_pad);
978   requisition->height += 2 * (focus_width + focus_pad);
979 }
980
981 static void
982 gtk_button_size_allocate (GtkWidget     *widget,
983                           GtkAllocation *allocation)
984 {
985   GtkButton *button = GTK_BUTTON (widget);
986   GtkAllocation child_allocation;
987
988   gint border_width = GTK_CONTAINER (widget)->border_width;
989   gint xthickness = GTK_WIDGET (widget)->style->xthickness;
990   gint ythickness = GTK_WIDGET (widget)->style->ythickness;
991   GtkBorder default_border;
992   gint focus_width;
993   gint focus_pad;
994
995   gtk_button_get_props (button, &default_border, NULL, NULL);
996   gtk_widget_style_get (GTK_WIDGET (widget),
997                         "focus-line-width", &focus_width,
998                         "focus-padding", &focus_pad,
999                         NULL);
1000  
1001                             
1002   widget->allocation = *allocation;
1003
1004   if (GTK_WIDGET_REALIZED (widget))
1005     gdk_window_move_resize (button->event_window,
1006                             widget->allocation.x + border_width,
1007                             widget->allocation.y + border_width,
1008                             widget->allocation.width - border_width * 2,
1009                             widget->allocation.height - border_width * 2);
1010
1011   if (GTK_BIN (button)->child && GTK_WIDGET_VISIBLE (GTK_BIN (button)->child))
1012     {
1013       child_allocation.x = widget->allocation.x + border_width + CHILD_SPACING + xthickness;
1014       child_allocation.y = widget->allocation.y + border_width + CHILD_SPACING + ythickness;
1015       
1016       child_allocation.width = MAX (1, widget->allocation.width - (CHILD_SPACING + xthickness) * 2 -
1017                                     border_width * 2);
1018       child_allocation.height = MAX (1, widget->allocation.height - (CHILD_SPACING + ythickness) * 2 -
1019                                      border_width * 2);
1020
1021       if (GTK_WIDGET_CAN_DEFAULT (button))
1022         {
1023           child_allocation.x += default_border.left;
1024           child_allocation.y += default_border.top;
1025           child_allocation.width =  MAX (1, child_allocation.width - default_border.left - default_border.right);
1026           child_allocation.height = MAX (1, child_allocation.height - default_border.top - default_border.bottom);
1027         }
1028
1029       if (GTK_WIDGET_CAN_FOCUS (button))
1030         {
1031           child_allocation.x += focus_width + focus_pad;
1032           child_allocation.y += focus_width + focus_pad;
1033           child_allocation.width =  MAX (1, child_allocation.width - (focus_width + focus_pad) * 2);
1034           child_allocation.height = MAX (1, child_allocation.height - (focus_width + focus_pad) * 2);
1035         }
1036
1037       if (button->depressed)
1038         {
1039           gint child_displacement_x;
1040           gint child_displacement_y;
1041           
1042           gtk_widget_style_get (widget,
1043                                 "child_displacement_x", &child_displacement_x, 
1044                                 "child_displacement_y", &child_displacement_y,
1045                                 NULL);
1046           child_allocation.x += child_displacement_x;
1047           child_allocation.y += child_displacement_y;
1048         }
1049
1050       gtk_widget_size_allocate (GTK_BIN (button)->child, &child_allocation);
1051     }
1052 }
1053
1054 void
1055 _gtk_button_paint (GtkButton    *button,
1056                    GdkRectangle *area,
1057                    GtkStateType  state_type,
1058                    GtkShadowType shadow_type,
1059                    const gchar  *main_detail,
1060                    const gchar  *default_detail)
1061 {
1062   GtkWidget *widget;
1063   gint width, height;
1064   gint x, y;
1065   gint border_width;
1066   GtkBorder default_border;
1067   GtkBorder default_outside_border;
1068   gboolean interior_focus;
1069   gint focus_width;
1070   gint focus_pad;
1071    
1072   if (GTK_WIDGET_DRAWABLE (button))
1073     {
1074       widget = GTK_WIDGET (button);
1075       border_width = GTK_CONTAINER (widget)->border_width;
1076
1077       gtk_button_get_props (button, &default_border, &default_outside_border, &interior_focus);
1078       gtk_widget_style_get (GTK_WIDGET (widget),
1079                             "focus-line-width", &focus_width,
1080                             "focus-padding", &focus_pad,
1081                             NULL); 
1082         
1083       x = widget->allocation.x + border_width;
1084       y = widget->allocation.y + border_width;
1085       width = widget->allocation.width - border_width * 2;
1086       height = widget->allocation.height - border_width * 2;
1087
1088       if (GTK_WIDGET_HAS_DEFAULT (widget) &&
1089           GTK_BUTTON (widget)->relief == GTK_RELIEF_NORMAL)
1090         {
1091           gtk_paint_box (widget->style, widget->window,
1092                          GTK_STATE_NORMAL, GTK_SHADOW_IN,
1093                          area, widget, "buttondefault",
1094                          x, y, width, height);
1095
1096           x += default_border.left;
1097           y += default_border.top;
1098           width -= default_border.left + default_border.right;
1099           height -= default_border.top + default_border.bottom;
1100         }
1101       else if (GTK_WIDGET_CAN_DEFAULT (widget))
1102         {
1103           x += default_outside_border.left;
1104           y += default_outside_border.top;
1105           width -= default_outside_border.left + default_outside_border.right;
1106           height -= default_outside_border.top + default_outside_border.bottom;
1107         }
1108        
1109       if (!interior_focus && GTK_WIDGET_HAS_FOCUS (widget))
1110         {
1111           x += focus_width + focus_pad;
1112           y += focus_width + focus_pad;
1113           width -= 2 * (focus_width + focus_pad);
1114           height -= 2 * (focus_width + focus_pad);
1115         }
1116
1117       if (button->relief != GTK_RELIEF_NONE || button->depressed ||
1118           GTK_WIDGET_STATE(widget) == GTK_STATE_PRELIGHT)
1119         gtk_paint_box (widget->style, widget->window,
1120                        state_type,
1121                        shadow_type, area, widget, "button",
1122                        x, y, width, height);
1123        
1124       if (GTK_WIDGET_HAS_FOCUS (widget))
1125         {
1126           gint child_displacement_x;
1127           gint child_displacement_y;
1128           gboolean displace_focus;
1129           
1130           gtk_widget_style_get (GTK_WIDGET (widget),
1131                                 "child_displacement_y", &child_displacement_y,
1132                                 "child_displacement_x", &child_displacement_x,
1133                                 "displace_focus", &displace_focus,
1134                                 NULL);
1135
1136           if (interior_focus)
1137             {
1138               x += widget->style->xthickness + focus_pad;
1139               y += widget->style->ythickness + focus_pad;
1140               width -= 2 * (widget->style->xthickness + focus_pad);
1141               height -=  2 * (widget->style->ythickness + focus_pad);
1142             }
1143           else
1144             {
1145               x -= focus_width + focus_pad;
1146               y -= focus_width + focus_pad;
1147               width += 2 * (focus_width + focus_pad);
1148               height += 2 * (focus_width + focus_pad);
1149             }
1150
1151           if (button->depressed && displace_focus)
1152             {
1153               x += child_displacement_x;
1154               y += child_displacement_y;
1155             }
1156
1157           gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
1158                            area, widget, "button",
1159                            x, y, width, height);
1160         }
1161     }
1162 }
1163
1164 static gboolean
1165 gtk_button_expose (GtkWidget      *widget,
1166                    GdkEventExpose *event)
1167 {
1168   if (GTK_WIDGET_DRAWABLE (widget))
1169     {
1170       GtkButton *button = GTK_BUTTON (widget);
1171       
1172       _gtk_button_paint (button, &event->area,
1173                          GTK_WIDGET_STATE (widget),
1174                          button->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
1175                          "button", "buttondefault");
1176       
1177       (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
1178     }
1179   
1180   return FALSE;
1181 }
1182
1183 static gboolean
1184 gtk_button_button_press (GtkWidget      *widget,
1185                          GdkEventButton *event)
1186 {
1187   GtkButton *button;
1188
1189   if (event->type == GDK_BUTTON_PRESS)
1190     {
1191       button = GTK_BUTTON (widget);
1192
1193       if (button->focus_on_click && !GTK_WIDGET_HAS_FOCUS (widget))
1194         gtk_widget_grab_focus (widget);
1195
1196       if (event->button == 1)
1197         gtk_button_pressed (button);
1198     }
1199
1200   return TRUE;
1201 }
1202
1203 static gboolean
1204 gtk_button_button_release (GtkWidget      *widget,
1205                            GdkEventButton *event)
1206 {
1207   GtkButton *button;
1208
1209   if (event->button == 1)
1210     {
1211       button = GTK_BUTTON (widget);
1212       gtk_button_released (button);
1213     }
1214
1215   return TRUE;
1216 }
1217
1218 static gboolean
1219 gtk_button_key_release (GtkWidget   *widget,
1220                         GdkEventKey *event)
1221 {
1222   GtkButton *button = GTK_BUTTON (widget);
1223
1224   if (button->activate_timeout)
1225     {
1226       gtk_button_finish_activate (button, TRUE);
1227       return TRUE;
1228     }
1229   else if (GTK_WIDGET_CLASS (parent_class)->key_release_event)
1230     return GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
1231   else
1232     return FALSE;
1233 }
1234
1235 static gboolean
1236 gtk_button_enter_notify (GtkWidget        *widget,
1237                          GdkEventCrossing *event)
1238 {
1239   GtkButton *button;
1240   GtkWidget *event_widget;
1241
1242   button = GTK_BUTTON (widget);
1243   event_widget = gtk_get_event_widget ((GdkEvent*) event);
1244
1245   if ((event_widget == widget) &&
1246       (event->detail != GDK_NOTIFY_INFERIOR))
1247     {
1248       button->in_button = TRUE;
1249       gtk_button_enter (button);
1250     }
1251
1252   return FALSE;
1253 }
1254
1255 static gboolean
1256 gtk_button_leave_notify (GtkWidget        *widget,
1257                          GdkEventCrossing *event)
1258 {
1259   GtkButton *button;
1260   GtkWidget *event_widget;
1261
1262   button = GTK_BUTTON (widget);
1263   event_widget = gtk_get_event_widget ((GdkEvent*) event);
1264
1265   if ((event_widget == widget) &&
1266       (event->detail != GDK_NOTIFY_INFERIOR))
1267     {
1268       button->in_button = FALSE;
1269       gtk_button_leave (button);
1270     }
1271
1272   return FALSE;
1273 }
1274
1275 static void
1276 gtk_real_button_pressed (GtkButton *button)
1277 {
1278   if (button->activate_timeout)
1279     return;
1280   
1281   button->button_down = TRUE;
1282   gtk_button_update_state (button);
1283 }
1284
1285 static void
1286 gtk_real_button_released (GtkButton *button)
1287 {
1288   if (button->button_down)
1289     {
1290       button->button_down = FALSE;
1291
1292       if (button->activate_timeout)
1293         return;
1294       
1295       if (button->in_button)
1296         gtk_button_clicked (button);
1297
1298       gtk_button_update_state (button);
1299     }
1300 }
1301
1302 static gboolean
1303 button_activate_timeout (gpointer data)
1304 {
1305   GDK_THREADS_ENTER ();
1306   
1307   gtk_button_finish_activate (data, TRUE);
1308
1309   GDK_THREADS_LEAVE ();
1310
1311   return FALSE;
1312 }
1313
1314 static void
1315 gtk_real_button_activate (GtkButton *button)
1316 {
1317   GtkWidget *widget = GTK_WIDGET (button);
1318   
1319   if (GTK_WIDGET_REALIZED (button) && !button->activate_timeout)
1320     {
1321       if (gdk_keyboard_grab (button->event_window, TRUE,
1322                              gtk_get_current_event_time ()) == 0)
1323         {
1324           gtk_grab_add (widget);
1325           
1326           button->activate_timeout = g_timeout_add (ACTIVATE_TIMEOUT,
1327                                                     button_activate_timeout,
1328                                                     button);
1329           button->button_down = TRUE;
1330           gtk_button_update_state (button);
1331           gtk_widget_queue_draw (GTK_WIDGET (button));
1332         }
1333     }
1334 }
1335
1336 static void
1337 gtk_button_finish_activate (GtkButton *button,
1338                             gboolean   do_it)
1339 {
1340   GtkWidget *widget = GTK_WIDGET (button);
1341   
1342   g_source_remove (button->activate_timeout);
1343   button->activate_timeout = 0;
1344
1345   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget),
1346                                gtk_get_current_event_time ());
1347   gtk_grab_remove (widget);
1348
1349   button->button_down = FALSE;
1350
1351   gtk_button_update_state (button);
1352   gtk_widget_queue_draw (GTK_WIDGET (button));
1353
1354   if (do_it)
1355     gtk_button_clicked (button);
1356 }
1357
1358 /**
1359  * gtk_button_set_label:
1360  * @button: a #GtkButton
1361  * @label: a string
1362  *
1363  * Sets the text of the label of the button to @str. This text is
1364  * also used to select the stock item if gtk_button_set_use_stock()
1365  * is used.
1366  *
1367  * This will also clear any previously set labels.
1368  **/
1369 void
1370 gtk_button_set_label (GtkButton   *button,
1371                       const gchar *label)
1372 {
1373   gchar *new_label;
1374   
1375   g_return_if_fail (GTK_IS_BUTTON (button));
1376
1377   new_label = g_strdup (label);
1378   g_free (button->label_text);
1379   button->label_text = new_label;
1380   
1381   gtk_button_construct_child (button);
1382   
1383   g_object_notify (G_OBJECT (button), "label");
1384 }
1385
1386 /**
1387  * gtk_button_get_label:
1388  * @button: a #GtkButton
1389  *
1390  * Fetches the text from the label of the button, as set by
1391  * gtk_button_set_label(). If the label text has not 
1392  * been set the return value will be %NULL. This will be the 
1393  * case if you create an empty button with gtk_button_new() to 
1394  * use as a container.
1395  *
1396  * Return value: The text of the label widget. This string is owned
1397  * by the widget and must not be modified or freed.
1398  **/
1399 G_CONST_RETURN gchar *
1400 gtk_button_get_label (GtkButton *button)
1401 {
1402   g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
1403   
1404   return button->label_text;
1405 }
1406
1407 /**
1408  * gtk_button_set_use_underline:
1409  * @button: a #GtkButton
1410  * @use_underline: %TRUE if underlines in the text indicate mnemonics
1411  *
1412  * If true, an underline in the text of the button label indicates
1413  * the next character should be used for the mnemonic accelerator key.
1414  */
1415 void
1416 gtk_button_set_use_underline (GtkButton *button,
1417                               gboolean   use_underline)
1418 {
1419   g_return_if_fail (GTK_IS_BUTTON (button));
1420
1421   use_underline = use_underline != FALSE;
1422
1423   if (use_underline != button->use_underline)
1424     {
1425       button->use_underline = use_underline;
1426   
1427       gtk_button_construct_child (button);
1428       
1429       g_object_notify (G_OBJECT (button), "use_underline");
1430     }
1431 }
1432
1433 /**
1434  * gtk_button_get_use_underline:
1435  * @button: a #GtkButton
1436  *
1437  * Returns whether an embedded underline in the button label indicates a
1438  * mnemonic. See gtk_button_set_use_underline ().
1439  *
1440  * Return value: %TRUE if an embedded underline in the button label
1441  *               indicates the mnemonic accelerator keys.
1442  **/
1443 gboolean
1444 gtk_button_get_use_underline (GtkButton *button)
1445 {
1446   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
1447   
1448   return button->use_underline;
1449 }
1450
1451 /**
1452  * gtk_button_set_use_stock:
1453  * @button: a #GtkButton
1454  * @use_stock: %TRUE if the button should use a stock item
1455  *
1456  * If true, the label set on the button is used as a
1457  * stock id to select the stock item for the button.
1458  */
1459 void
1460 gtk_button_set_use_stock (GtkButton *button,
1461                           gboolean   use_stock)
1462 {
1463   g_return_if_fail (GTK_IS_BUTTON (button));
1464
1465   use_stock = use_stock != FALSE;
1466
1467   if (use_stock != button->use_stock)
1468     {
1469       button->use_stock = use_stock;
1470   
1471       gtk_button_construct_child (button);
1472       
1473       g_object_notify (G_OBJECT (button), "use_stock");
1474     }
1475 }
1476
1477 /**
1478  * gtk_button_get_use_stock:
1479  * @button: a #GtkButton
1480  *
1481  * Returns whether the button label is a stock item.
1482  *
1483  * Return value: %TRUE if the button label is used to
1484  *               select a stock item instead of being
1485  *               used directly as the label text.
1486  */
1487 gboolean
1488 gtk_button_get_use_stock (GtkButton *button)
1489 {
1490   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
1491   
1492   return button->use_stock;
1493 }
1494
1495 /**
1496  * gtk_button_set_focus_on_click:
1497  * @button: a #GtkButton
1498  * @focus_on_click: whether the button grabs focus when clicked with the mouse
1499  * 
1500  * Sets whether the button will grab focus when it is clicked with the mouse.
1501  * Making mouse clicks not grab focus is useful in places like toolbars where
1502  * you don't want the keyboard focus removed from the main area of the
1503  * application.
1504  *
1505  * Since: 2.4
1506  **/
1507 void
1508 gtk_button_set_focus_on_click (GtkButton *button,
1509                                gboolean   focus_on_click)
1510 {
1511   g_return_if_fail (GTK_IS_BUTTON (button));
1512   
1513   focus_on_click = focus_on_click != FALSE;
1514
1515   if (button->focus_on_click != focus_on_click)
1516     {
1517       button->focus_on_click = focus_on_click;
1518       
1519       g_object_notify (G_OBJECT (button), "focus_on_click");
1520     }
1521 }
1522
1523 /**
1524  * gtk_button_get_focus_on_click:
1525  * @button: a #GtkButton
1526  * 
1527  * Returns whether the button grabs focus when it is clicked with the mouse.
1528  * See gtk_button_set_focus_on_click().
1529  *
1530  * Return value: %TRUE if the button grabs focus when it is clicked with
1531  *               the mouse.
1532  *
1533  * Since: 2.4
1534  **/
1535 gboolean
1536 gtk_button_get_focus_on_click (GtkButton *button)
1537 {
1538   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
1539   
1540   return button->focus_on_click;
1541 }
1542
1543 /**
1544  * gtk_button_set_alignment:
1545  * @button: a #GtkButton
1546  * @xalign: the horizontal position of the child, 0.0 is left aligned, 
1547  *   1.0 is right aligned
1548  * @yalign: the vertical position of the child, 0.0 is top aligned, 
1549  *   1.0 is bottom aligned
1550  *
1551  * Sets the alignment of the child. This property has no effect unless 
1552  * the child is a #GtkMisc or a #GtkAligment.
1553  *
1554  * Since: 2.4
1555  */
1556 void
1557 gtk_button_set_alignment (GtkButton *button,
1558                           gfloat     xalign,
1559                           gfloat     yalign)
1560 {
1561   GtkButtonPrivate *priv;
1562
1563   g_return_if_fail (GTK_IS_BUTTON (button));
1564   
1565   priv = GTK_BUTTON_GET_PRIVATE (button);
1566
1567   priv->xalign = xalign;
1568   priv->yalign = yalign;
1569   priv->align_set = 1;
1570
1571   maybe_set_alignment (button, GTK_BIN (button)->child);
1572
1573   g_object_freeze_notify (G_OBJECT (button));
1574   g_object_notify (G_OBJECT (button), "xalign");
1575   g_object_notify (G_OBJECT (button), "yalign");
1576   g_object_thaw_notify (G_OBJECT (button));
1577 }
1578
1579 /**
1580  * gtk_button_get_alignment:
1581  * @button: a #GtkButton
1582  * @xalign: return location for horizontal alignment
1583  * @yalign: return location for vertical alignment
1584  *
1585  * Gets the alignment of the child in the button.
1586  *
1587  * Since: 2.4
1588  */
1589 void
1590 gtk_button_get_alignment (GtkButton *button,
1591                           gfloat    *xalign,
1592                           gfloat    *yalign)
1593 {
1594   GtkButtonPrivate *priv;
1595
1596   g_return_if_fail (GTK_IS_BUTTON (button));
1597   
1598   priv = GTK_BUTTON_GET_PRIVATE (button);
1599  
1600   if (xalign) 
1601     *xalign = priv->xalign;
1602
1603   if (yalign)
1604     *yalign = priv->yalign;
1605 }
1606
1607 /**
1608  * _gtk_button_set_depressed:
1609  * @button: a #GtkButton
1610  * @depressed: %TRUE if the button should be drawn with a recessed shadow.
1611  * 
1612  * Sets whether the button is currently drawn as down or not. This is 
1613  * purely a visual setting, and is meant only for use by derived widgets
1614  * such as #GtkToggleButton.
1615  **/
1616 void
1617 _gtk_button_set_depressed (GtkButton *button,
1618                            gboolean   depressed)
1619 {
1620   GtkWidget *widget = GTK_WIDGET (button);
1621
1622   depressed = depressed != FALSE;
1623
1624   if (depressed != button->depressed)
1625     {
1626       button->depressed = depressed;
1627       gtk_widget_queue_resize (widget);
1628     }
1629 }
1630
1631 static void
1632 gtk_button_update_state (GtkButton *button)
1633 {
1634   gboolean depressed;
1635   GtkStateType new_state;
1636
1637   if (button->activate_timeout)
1638     depressed = button->depress_on_activate;
1639   else
1640     depressed = button->in_button && button->button_down;
1641
1642   if (button->in_button && (!button->button_down || !depressed))
1643     new_state = GTK_STATE_PRELIGHT;
1644   else
1645     new_state = depressed ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL;
1646
1647   _gtk_button_set_depressed (button, depressed); 
1648   gtk_widget_set_state (GTK_WIDGET (button), new_state);
1649 }
1650
1651 static void 
1652 show_image_change_notify (GtkButton *button)
1653 {
1654   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
1655
1656   if (priv->image) 
1657     {
1658       if (show_image (button))
1659         gtk_widget_show (priv->image);
1660       else
1661         gtk_widget_hide (priv->image);
1662     }
1663 }
1664
1665 static void
1666 traverse_container (GtkWidget *widget,
1667                     gpointer   data)
1668 {
1669   if (GTK_IS_BUTTON (widget))
1670     show_image_change_notify (GTK_BUTTON (widget));
1671   else if (GTK_IS_CONTAINER (widget))
1672     gtk_container_forall (GTK_CONTAINER (widget), traverse_container, NULL);
1673 }
1674
1675 static void
1676 gtk_button_setting_changed (GtkSettings *settings)
1677 {
1678   GList *list, *l;
1679
1680   list = gtk_window_list_toplevels ();
1681
1682   for (l = list; l; l = l->next)
1683     gtk_container_forall (GTK_CONTAINER (l->data), 
1684                           traverse_container, NULL);
1685
1686   g_list_free (list);
1687 }
1688
1689
1690 static void
1691 gtk_button_screen_changed (GtkWidget *widget,
1692                            GdkScreen *previous_screen)
1693 {
1694   GtkSettings *settings;
1695   guint show_image_connection;
1696
1697   if (!gtk_widget_has_screen (widget))
1698     return;
1699
1700   settings = gtk_widget_get_settings (widget);
1701
1702   show_image_connection = 
1703     GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (settings), 
1704                                          "gtk-button-connection"));
1705   
1706   if (show_image_connection)
1707     return;
1708
1709   show_image_connection =
1710     g_signal_connect (settings, "notify::gtk-button-images",
1711                       G_CALLBACK (gtk_button_setting_changed), 0);
1712   g_object_set_data (G_OBJECT (settings), 
1713                      "gtk-button-connection",
1714                      GUINT_TO_POINTER (show_image_connection));
1715
1716   show_image_change_notify (GTK_BUTTON (widget));
1717 }
1718
1719 static void
1720 gtk_button_state_changed (GtkWidget    *widget,
1721                           GtkStateType  previous_state)
1722 {
1723   GtkButton *button = GTK_BUTTON (widget);
1724
1725   if (!GTK_WIDGET_IS_SENSITIVE (widget))
1726     {
1727       button->in_button = FALSE;
1728       gtk_real_button_released (button);
1729     }
1730 }
1731
1732 static void
1733 gtk_button_grab_notify (GtkWidget *widget,
1734                         gboolean   was_grabbed)
1735 {
1736   GtkButton *button = GTK_BUTTON (widget);
1737
1738   if (!was_grabbed)
1739     {
1740       button->in_button = FALSE;
1741       gtk_real_button_released (button);
1742     }
1743 }
1744
1745 /**
1746  * gtk_button_set_image:
1747  * @button: a #GtkButton
1748  * @image: a widget to set as the image for the button
1749  *
1750  * Set the image of @button to the given widget. Note that
1751  * it depends on the gtk-button-images setting whether the
1752  * image will be displayed or not.
1753  *
1754  * Since: 2.6
1755  */ 
1756 void
1757 gtk_button_set_image (GtkButton *button,
1758                       GtkWidget *image)
1759 {
1760   GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
1761
1762   priv->image = image;
1763   priv->image_is_stock = (image == NULL);
1764
1765   gtk_button_construct_child (button);
1766
1767   g_object_notify (G_OBJECT (button), "image");
1768 }
1769
1770 /**
1771  * gtk_button_get_image:
1772  * @button: a #GtkButton
1773  *
1774  * Gets the widget that is currenty set as the image of @button.
1775  * This may have been explicitly set by gtk_button_set_image()
1776  * or constructed by gtk_button_new_from_stock().
1777  *
1778  * Since: 2.6
1779  */
1780 GtkWidget *
1781 gtk_button_get_image (GtkButton *button)
1782 {
1783   GtkButtonPrivate *priv;
1784
1785   g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
1786
1787   priv = GTK_BUTTON_GET_PRIVATE (button);
1788   
1789   return priv->image;
1790 }
1791   
1792 #define __GTK_BUTTON_C__
1793 #include "gtkaliasdef.c"