]> Pileus Git - ~andy/gtk/blob - gtk/gtkbutton.c
stylecontext: Do invalidation on first resize container
[~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, see <http://www.gnu.org/licenses/>.
16  */
17
18 /*
19  * Modified by the GTK+ Team and others 1997-2001.  See the AUTHORS
20  * file for a list of people on the GTK+ Team.  See the ChangeLog
21  * files for a list of changes.  These files are distributed with
22  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
23  */
24
25 /**
26  * SECTION:gtkbutton
27  * @Short_description: A widget that emits a signal when clicked on
28  * @Title: GtkButton
29  *
30  * The #GtkButton widget is generally used to trigger a callback function that is
31  * called when the button is pressed.  The various signals and how to use them
32  * are outlined below.
33  *
34  * The #GtkButton widget can hold any valid child widget.  That is, it can hold
35  * almost any other standard #GtkWidget.  The most commonly used child is the
36  * #GtkLabel.
37  */
38
39 #include "config.h"
40
41 #include "gtkbutton.h"
42 #include "gtkbuttonprivate.h"
43
44 #include <string.h>
45 #include "gtkalignment.h"
46 #include "gtklabel.h"
47 #include "gtkmain.h"
48 #include "gtkmarshalers.h"
49 #include "gtkimage.h"
50 #include "gtkbox.h"
51 #include "gtkstock.h"
52 #include "gtkiconfactory.h"
53 #include "gtkactivatable.h"
54 #include "gtksizerequest.h"
55 #include "gtktypebuiltins.h"
56 #include "gtkprivate.h"
57 #include "gtkintl.h"
58 #include "a11y/gtkbuttonaccessible.h"
59 #include "gtkapplicationprivate.h"
60 #include "gtkactionhelper.h"
61
62 static const GtkBorder default_default_border = { 1, 1, 1, 1 };
63 static const GtkBorder default_default_outside_border = { 0, 0, 0, 0 };
64
65 /* Time out before giving up on getting a key release when animating
66  * the close button.
67  */
68 #define ACTIVATE_TIMEOUT 250
69
70
71 enum {
72   PRESSED,
73   RELEASED,
74   CLICKED,
75   ENTER,
76   LEAVE,
77   ACTIVATE,
78   LAST_SIGNAL
79 };
80
81 enum {
82   PROP_0,
83   PROP_LABEL,
84   PROP_IMAGE,
85   PROP_RELIEF,
86   PROP_USE_UNDERLINE,
87   PROP_USE_STOCK,
88   PROP_FOCUS_ON_CLICK,
89   PROP_XALIGN,
90   PROP_YALIGN,
91   PROP_IMAGE_POSITION,
92   PROP_ACTION_NAME,
93   PROP_ACTION_TARGET,
94   PROP_ALWAYS_SHOW_IMAGE,
95
96   /* activatable properties */
97   PROP_ACTIVATABLE_RELATED_ACTION,
98   PROP_ACTIVATABLE_USE_ACTION_APPEARANCE
99 };
100
101
102 static void gtk_button_destroy        (GtkWidget          *widget);
103 static void gtk_button_dispose        (GObject            *object);
104 static void gtk_button_set_property   (GObject            *object,
105                                        guint               prop_id,
106                                        const GValue       *value,
107                                        GParamSpec         *pspec);
108 static void gtk_button_get_property   (GObject            *object,
109                                        guint               prop_id,
110                                        GValue             *value,
111                                        GParamSpec         *pspec);
112 static void gtk_button_screen_changed (GtkWidget          *widget,
113                                        GdkScreen          *previous_screen);
114 static void gtk_button_realize (GtkWidget * widget);
115 static void gtk_button_unrealize (GtkWidget * widget);
116 static void gtk_button_map (GtkWidget * widget);
117 static void gtk_button_unmap (GtkWidget * widget);
118 static void gtk_button_style_updated (GtkWidget * widget);
119 static void gtk_button_size_allocate (GtkWidget * widget,
120                                       GtkAllocation * allocation);
121 static gint gtk_button_draw (GtkWidget * widget, cairo_t *cr);
122 static gint gtk_button_button_press (GtkWidget * widget,
123                                      GdkEventButton * event);
124 static gint gtk_button_button_release (GtkWidget * widget,
125                                        GdkEventButton * event);
126 static gboolean gtk_button_touch (GtkWidget     *widget,
127                                   GdkEventTouch *event);
128 static gint gtk_button_grab_broken (GtkWidget * widget,
129                                     GdkEventGrabBroken * event);
130 static gint gtk_button_key_release (GtkWidget * widget, GdkEventKey * event);
131 static gint gtk_button_enter_notify (GtkWidget * widget,
132                                      GdkEventCrossing * event);
133 static gint gtk_button_leave_notify (GtkWidget * widget,
134                                      GdkEventCrossing * event);
135 static void gtk_real_button_pressed (GtkButton * button);
136 static void gtk_real_button_released (GtkButton * button);
137 static void gtk_real_button_clicked (GtkButton * button);
138 static void gtk_real_button_activate  (GtkButton          *button);
139 static void gtk_button_update_state   (GtkButton          *button);
140 static void gtk_button_add            (GtkContainer       *container,
141                                        GtkWidget          *widget);
142 static GType gtk_button_child_type    (GtkContainer       *container);
143 static void gtk_button_finish_activate (GtkButton         *button,
144                                         gboolean           do_it);
145
146 static GObject* gtk_button_constructor (GType                  type,
147                                         guint                  n_construct_properties,
148                                         GObjectConstructParam *construct_params);
149 static void gtk_button_construct_child (GtkButton             *button);
150 static void gtk_button_state_changed   (GtkWidget             *widget,
151                                         GtkStateType           previous_state);
152 static void gtk_button_grab_notify     (GtkWidget             *widget,
153                                         gboolean               was_grabbed);
154
155 static void gtk_button_actionable_iface_init     (GtkActionableInterface *iface);
156 static void gtk_button_activatable_interface_init(GtkActivatableIface  *iface);
157 static void gtk_button_update                    (GtkActivatable       *activatable,
158                                                   GtkAction            *action,
159                                                   const gchar          *property_name);
160 static void gtk_button_sync_action_properties    (GtkActivatable       *activatable,
161                                                   GtkAction            *action);
162 static void gtk_button_set_related_action        (GtkButton            *button,
163                                                   GtkAction            *action);
164 static void gtk_button_set_use_action_appearance (GtkButton            *button,
165                                                   gboolean              use_appearance);
166
167 static void gtk_button_get_preferred_width       (GtkWidget           *widget,
168                                                   gint                *minimum_size,
169                                                   gint                *natural_size);
170 static void gtk_button_get_preferred_height      (GtkWidget           *widget,
171                                                   gint                *minimum_size,
172                                                   gint                *natural_size);
173   
174 static guint button_signals[LAST_SIGNAL] = { 0 };
175
176 G_DEFINE_TYPE_WITH_CODE (GtkButton, gtk_button, GTK_TYPE_BIN,
177                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, gtk_button_actionable_iface_init)
178                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
179                                                 gtk_button_activatable_interface_init))
180
181 static void
182 gtk_button_class_init (GtkButtonClass *klass)
183 {
184   GObjectClass *gobject_class;
185   GtkWidgetClass *widget_class;
186   GtkContainerClass *container_class;
187
188   gobject_class = G_OBJECT_CLASS (klass);
189   widget_class = (GtkWidgetClass*) klass;
190   container_class = (GtkContainerClass*) klass;
191   
192   gobject_class->constructor  = gtk_button_constructor;
193   gobject_class->dispose      = gtk_button_dispose;
194   gobject_class->set_property = gtk_button_set_property;
195   gobject_class->get_property = gtk_button_get_property;
196
197   widget_class->get_preferred_width  = gtk_button_get_preferred_width;
198   widget_class->get_preferred_height = gtk_button_get_preferred_height;
199   widget_class->destroy = gtk_button_destroy;
200   widget_class->screen_changed = gtk_button_screen_changed;
201   widget_class->realize = gtk_button_realize;
202   widget_class->unrealize = gtk_button_unrealize;
203   widget_class->map = gtk_button_map;
204   widget_class->unmap = gtk_button_unmap;
205   widget_class->style_updated = gtk_button_style_updated;
206   widget_class->size_allocate = gtk_button_size_allocate;
207   widget_class->draw = gtk_button_draw;
208   widget_class->button_press_event = gtk_button_button_press;
209   widget_class->button_release_event = gtk_button_button_release;
210   widget_class->touch_event = gtk_button_touch;
211   widget_class->grab_broken_event = gtk_button_grab_broken;
212   widget_class->key_release_event = gtk_button_key_release;
213   widget_class->enter_notify_event = gtk_button_enter_notify;
214   widget_class->leave_notify_event = gtk_button_leave_notify;
215   widget_class->state_changed = gtk_button_state_changed;
216   widget_class->grab_notify = gtk_button_grab_notify;
217
218   container_class->child_type = gtk_button_child_type;
219   container_class->add = gtk_button_add;
220   gtk_container_class_handle_border_width (container_class);
221
222   klass->pressed = gtk_real_button_pressed;
223   klass->released = gtk_real_button_released;
224   klass->clicked = NULL;
225   klass->enter = gtk_button_update_state;
226   klass->leave = gtk_button_update_state;
227   klass->activate = gtk_real_button_activate;
228
229   g_object_class_install_property (gobject_class,
230                                    PROP_LABEL,
231                                    g_param_spec_string ("label",
232                                                         P_("Label"),
233                                                         P_("Text of the label widget inside the button, if the button contains a label widget"),
234                                                         NULL,
235                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
236   
237   g_object_class_install_property (gobject_class,
238                                    PROP_USE_UNDERLINE,
239                                    g_param_spec_boolean ("use-underline",
240                                                          P_("Use underline"),
241                                                          P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
242                                                         FALSE,
243                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
244   
245   g_object_class_install_property (gobject_class,
246                                    PROP_USE_STOCK,
247                                    g_param_spec_boolean ("use-stock",
248                                                          P_("Use stock"),
249                                                          P_("If set, the label is used to pick a stock item instead of being displayed"),
250                                                         FALSE,
251                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
252   
253   g_object_class_install_property (gobject_class,
254                                    PROP_FOCUS_ON_CLICK,
255                                    g_param_spec_boolean ("focus-on-click",
256                                                          P_("Focus on click"),
257                                                          P_("Whether the button grabs focus when it is clicked with the mouse"),
258                                                          TRUE,
259                                                          GTK_PARAM_READWRITE));
260   
261   g_object_class_install_property (gobject_class,
262                                    PROP_RELIEF,
263                                    g_param_spec_enum ("relief",
264                                                       P_("Border relief"),
265                                                       P_("The border relief style"),
266                                                       GTK_TYPE_RELIEF_STYLE,
267                                                       GTK_RELIEF_NORMAL,
268                                                       GTK_PARAM_READWRITE));
269   
270   /**
271    * GtkButton:xalign:
272    *
273    * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
274    * can be used to control its horizontal alignment. 0.0 is left aligned, 
275    * 1.0 is right aligned.
276    *
277    * Since: 2.4
278    */
279   g_object_class_install_property (gobject_class,
280                                    PROP_XALIGN,
281                                    g_param_spec_float("xalign",
282                                                       P_("Horizontal alignment for child"),
283                                                       P_("Horizontal position of child in available space. 0.0 is left aligned, 1.0 is right aligned"),
284                                                       0.0,
285                                                       1.0,
286                                                       0.5,
287                                                       GTK_PARAM_READWRITE));
288
289   /**
290    * GtkButton:yalign:
291    *
292    * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
293    * can be used to control its vertical alignment. 0.0 is top aligned, 
294    * 1.0 is bottom aligned.
295    *
296    * Since: 2.4
297    */
298   g_object_class_install_property (gobject_class,
299                                    PROP_YALIGN,
300                                    g_param_spec_float("yalign",
301                                                       P_("Vertical alignment for child"),
302                                                       P_("Vertical position of child in available space. 0.0 is top aligned, 1.0 is bottom aligned"),
303                                                       0.0,
304                                                       1.0,
305                                                       0.5,
306                                                       GTK_PARAM_READWRITE));
307
308   /**
309    * GtkButton:image:
310    *
311    * The child widget to appear next to the button text.
312    *
313    * Since: 2.6
314    */
315   g_object_class_install_property (gobject_class,
316                                    PROP_IMAGE,
317                                    g_param_spec_object ("image",
318                                                         P_("Image widget"),
319                                                         P_("Child widget to appear next to the button text"),
320                                                         GTK_TYPE_WIDGET,
321                                                         GTK_PARAM_READWRITE));
322
323   /**
324    * GtkButton:image-position:
325    *
326    * The position of the image relative to the text inside the button.
327    *
328    * Since: 2.10
329    */
330   g_object_class_install_property (gobject_class,
331                                    PROP_IMAGE_POSITION,
332                                    g_param_spec_enum ("image-position",
333                                             P_("Image position"),
334                                                       P_("The position of the image relative to the text"),
335                                                       GTK_TYPE_POSITION_TYPE,
336                                                       GTK_POS_LEFT,
337                                                       GTK_PARAM_READWRITE));
338
339   /**
340    * GtkButton:always-show-image:
341    *
342    * If %TRUE, the button will ignore the #GtkSettings:gtk-button-images
343    * setting and always show the image, if available.
344    *
345    * Use this property if the button would be useless or hard to use
346    * without the image.
347    *
348    * Since: 3.6
349    */
350   g_object_class_install_property (gobject_class,
351                                    PROP_ALWAYS_SHOW_IMAGE,
352                                    g_param_spec_boolean ("always-show-image",
353                                                          P_("Always show image"),
354                                                          P_("Whether the image will always be shown"),
355                                                          FALSE,
356                                                          GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
357
358   g_object_class_override_property (gobject_class, PROP_ACTION_NAME, "action-name");
359   g_object_class_override_property (gobject_class, PROP_ACTION_TARGET, "action-target");
360
361   g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action");
362   g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance");
363
364   /**
365    * GtkButton::pressed:
366    * @button: the object that received the signal
367    *
368    * Emitted when the button is pressed.
369    *
370    * Deprecated: 2.8: Use the #GtkWidget::button-press-event signal.
371    */ 
372   button_signals[PRESSED] =
373     g_signal_new (I_("pressed"),
374                   G_OBJECT_CLASS_TYPE (gobject_class),
375                   G_SIGNAL_RUN_FIRST,
376                   G_STRUCT_OFFSET (GtkButtonClass, pressed),
377                   NULL, NULL,
378                   _gtk_marshal_VOID__VOID,
379                   G_TYPE_NONE, 0);
380
381   /**
382    * GtkButton::released:
383    * @button: the object that received the signal
384    *
385    * Emitted when the button is released.
386    *
387    * Deprecated: 2.8: Use the #GtkWidget::button-release-event signal.
388    */ 
389   button_signals[RELEASED] =
390     g_signal_new (I_("released"),
391                   G_OBJECT_CLASS_TYPE (gobject_class),
392                   G_SIGNAL_RUN_FIRST,
393                   G_STRUCT_OFFSET (GtkButtonClass, released),
394                   NULL, NULL,
395                   _gtk_marshal_VOID__VOID,
396                   G_TYPE_NONE, 0);
397
398   /**
399    * GtkButton::clicked:
400    * @button: the object that received the signal
401    *
402    * Emitted when the button has been activated (pressed and released).
403    */ 
404   button_signals[CLICKED] =
405     g_signal_new (I_("clicked"),
406                   G_OBJECT_CLASS_TYPE (gobject_class),
407                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
408                   G_STRUCT_OFFSET (GtkButtonClass, clicked),
409                   NULL, NULL,
410                   _gtk_marshal_VOID__VOID,
411                   G_TYPE_NONE, 0);
412
413   /**
414    * GtkButton::enter:
415    * @button: the object that received the signal
416    *
417    * Emitted when the pointer enters the button.
418    *
419    * Deprecated: 2.8: Use the #GtkWidget::enter-notify-event signal.
420    */ 
421   button_signals[ENTER] =
422     g_signal_new (I_("enter"),
423                   G_OBJECT_CLASS_TYPE (gobject_class),
424                   G_SIGNAL_RUN_FIRST,
425                   G_STRUCT_OFFSET (GtkButtonClass, enter),
426                   NULL, NULL,
427                   _gtk_marshal_VOID__VOID,
428                   G_TYPE_NONE, 0);
429
430   /**
431    * GtkButton::leave:
432    * @button: the object that received the signal
433    *
434    * Emitted when the pointer leaves the button.
435    *
436    * Deprecated: 2.8: Use the #GtkWidget::leave-notify-event signal.
437    */ 
438   button_signals[LEAVE] =
439     g_signal_new (I_("leave"),
440                   G_OBJECT_CLASS_TYPE (gobject_class),
441                   G_SIGNAL_RUN_FIRST,
442                   G_STRUCT_OFFSET (GtkButtonClass, leave),
443                   NULL, NULL,
444                   _gtk_marshal_VOID__VOID,
445                   G_TYPE_NONE, 0);
446
447   /**
448    * GtkButton::activate:
449    * @widget: the object which received the signal.
450    *
451    * The ::activate signal on GtkButton is an action signal and
452    * emitting it causes the button to animate press then release. 
453    * Applications should never connect to this signal, but use the
454    * #GtkButton::clicked signal.
455    */
456   button_signals[ACTIVATE] =
457     g_signal_new (I_("activate"),
458                   G_OBJECT_CLASS_TYPE (gobject_class),
459                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
460                   G_STRUCT_OFFSET (GtkButtonClass, activate),
461                   NULL, NULL,
462                   _gtk_marshal_VOID__VOID,
463                   G_TYPE_NONE, 0);
464   widget_class->activate_signal = button_signals[ACTIVATE];
465
466   /**
467    * GtkButton:default-border:
468    *
469    * The "default-border" style property defines the extra space to add
470    * around a button that can become the default widget of its window.
471    * For more information about default widgets, see gtk_widget_grab_default().
472    */
473
474   gtk_widget_class_install_style_property (widget_class,
475                                            g_param_spec_boxed ("default-border",
476                                                                P_("Default Spacing"),
477                                                                P_("Extra space to add for GTK_CAN_DEFAULT buttons"),
478                                                                GTK_TYPE_BORDER,
479                                                                GTK_PARAM_READABLE));
480
481   /**
482    * GtkButton:default-outside-border:
483    *
484    * The "default-outside-border" style property defines the extra outside
485    * space to add around a button that can become the default widget of its
486    * window. Extra outside space is always drawn outside the button border.
487    * For more information about default widgets, see gtk_widget_grab_default().
488    */
489   gtk_widget_class_install_style_property (widget_class,
490                                            g_param_spec_boxed ("default-outside-border",
491                                                                P_("Default Outside Spacing"),
492                                                                P_("Extra space to add for GTK_CAN_DEFAULT buttons that is always drawn outside the border"),
493                                                                GTK_TYPE_BORDER,
494                                                                GTK_PARAM_READABLE));
495   gtk_widget_class_install_style_property (widget_class,
496                                            g_param_spec_int ("child-displacement-x",
497                                                              P_("Child X Displacement"),
498                                                              P_("How far in the x direction to move the child when the button is depressed"),
499                                                              G_MININT,
500                                                              G_MAXINT,
501                                                              0,
502                                                              GTK_PARAM_READABLE));
503   gtk_widget_class_install_style_property (widget_class,
504                                            g_param_spec_int ("child-displacement-y",
505                                                              P_("Child Y Displacement"),
506                                                              P_("How far in the y direction to move the child when the button is depressed"),
507                                                              G_MININT,
508                                                              G_MAXINT,
509                                                              0,
510                                                              GTK_PARAM_READABLE));
511
512   /**
513    * GtkButton:displace-focus:
514    *
515    * Whether the child_displacement_x/child_displacement_y properties 
516    * should also affect the focus rectangle.
517    *
518    * Since: 2.6
519    */
520   gtk_widget_class_install_style_property (widget_class,
521                                            g_param_spec_boolean ("displace-focus",
522                                                                  P_("Displace focus"),
523                                                                  P_("Whether the child_displacement_x/_y properties should also affect the focus rectangle"),
524                                                                  FALSE,
525                                                                  GTK_PARAM_READABLE));
526
527   /**
528    * GtkButton:inner-border:
529    *
530    * Sets the border between the button edges and child.
531    *
532    * Since: 2.10
533    *
534    * Deprecated: 3.4: Use the standard border and padding CSS properties;
535    *   the value of this style property is ignored.
536    */
537   gtk_widget_class_install_style_property (widget_class,
538                                            g_param_spec_boxed ("inner-border",
539                                                                P_("Inner Border"),
540                                                                P_("Border between button edges and child."),
541                                                                GTK_TYPE_BORDER,
542                                                                GTK_PARAM_READABLE));
543
544   /**
545    * GtkButton::image-spacing:
546    *
547    * Spacing in pixels between the image and label.
548    *
549    * Since: 2.10
550    */
551   gtk_widget_class_install_style_property (widget_class,
552                                            g_param_spec_int ("image-spacing",
553                                                              P_("Image spacing"),
554                                                              P_("Spacing in pixels between the image and label"),
555                                                              0,
556                                                              G_MAXINT,
557                                                              2,
558                                                              GTK_PARAM_READABLE));
559
560   g_type_class_add_private (gobject_class, sizeof (GtkButtonPrivate));
561
562   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_BUTTON_ACCESSIBLE);
563 }
564
565 static void
566 gtk_button_init (GtkButton *button)
567 {
568   GtkButtonPrivate *priv;
569   GtkStyleContext *context;
570
571   button->priv = G_TYPE_INSTANCE_GET_PRIVATE (button,
572                                               GTK_TYPE_BUTTON,
573                                               GtkButtonPrivate);
574   priv = button->priv;
575
576   gtk_widget_set_can_focus (GTK_WIDGET (button), TRUE);
577   gtk_widget_set_receives_default (GTK_WIDGET (button), TRUE);
578   gtk_widget_set_has_window (GTK_WIDGET (button), FALSE);
579
580   priv->label_text = NULL;
581
582   priv->constructed = FALSE;
583   priv->in_button = FALSE;
584   priv->button_down = FALSE;
585   priv->relief = GTK_RELIEF_NORMAL;
586   priv->use_stock = FALSE;
587   priv->use_underline = FALSE;
588   priv->depressed = FALSE;
589   priv->depress_on_activate = TRUE;
590   priv->focus_on_click = TRUE;
591
592   priv->xalign = 0.5;
593   priv->yalign = 0.5;
594   priv->align_set = 0;
595   priv->image_is_stock = TRUE;
596   priv->image_position = GTK_POS_LEFT;
597   priv->use_action_appearance = TRUE;
598
599   context = gtk_widget_get_style_context (GTK_WIDGET (button));
600   gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
601 }
602
603 static void
604 gtk_button_destroy (GtkWidget *widget)
605 {
606   GtkButton *button = GTK_BUTTON (widget);
607   GtkButtonPrivate *priv = button->priv;
608
609   if (priv->label_text)
610     {
611       g_free (priv->label_text);
612       priv->label_text = NULL;
613     }
614
615   GTK_WIDGET_CLASS (gtk_button_parent_class)->destroy (widget);
616 }
617
618 static GObject*
619 gtk_button_constructor (GType                  type,
620                         guint                  n_construct_properties,
621                         GObjectConstructParam *construct_params)
622 {
623   GObject *object;
624   GtkButton *button;
625   GtkButtonPrivate *priv;
626
627   object = G_OBJECT_CLASS (gtk_button_parent_class)->constructor (type,
628                                                                   n_construct_properties,
629                                                                   construct_params);
630
631   button = GTK_BUTTON (object);
632   priv = button->priv;
633
634   priv->constructed = TRUE;
635
636   if (priv->label_text != NULL)
637     gtk_button_construct_child (button);
638   
639   return object;
640 }
641
642
643 static GType
644 gtk_button_child_type  (GtkContainer     *container)
645 {
646   if (!gtk_bin_get_child (GTK_BIN (container)))
647     return GTK_TYPE_WIDGET;
648   else
649     return G_TYPE_NONE;
650 }
651
652 static void
653 maybe_set_alignment (GtkButton *button,
654                      GtkWidget *widget)
655 {
656   GtkButtonPrivate *priv = button->priv;
657
658   if (GTK_IS_MISC (widget))
659     {
660       GtkMisc *misc = GTK_MISC (widget);
661       
662       if (priv->align_set)
663         gtk_misc_set_alignment (misc, priv->xalign, priv->yalign);
664     }
665   else if (GTK_IS_ALIGNMENT (widget))
666     {
667       GtkAlignment *alignment = GTK_ALIGNMENT (widget);
668       gfloat xscale, yscale;
669
670       g_object_get (alignment,
671                     "xscale", &xscale,
672                     "yscale", &yscale,
673                     NULL);
674
675       if (priv->align_set)
676         gtk_alignment_set (alignment,
677                            priv->xalign, priv->yalign,
678                            xscale, yscale);
679     }
680 }
681
682 static void
683 gtk_button_add (GtkContainer *container,
684                 GtkWidget    *widget)
685 {
686   maybe_set_alignment (GTK_BUTTON (container), widget);
687
688   GTK_CONTAINER_CLASS (gtk_button_parent_class)->add (container, widget);
689 }
690
691 static void 
692 gtk_button_dispose (GObject *object)
693 {
694   GtkButton *button = GTK_BUTTON (object);
695   GtkButtonPrivate *priv = button->priv;
696
697   g_clear_object (&priv->action_helper);
698
699   if (priv->action)
700     {
701       gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (button), NULL);
702       priv->action = NULL;
703     }
704   G_OBJECT_CLASS (gtk_button_parent_class)->dispose (object);
705 }
706
707 static void
708 gtk_button_set_action_name (GtkActionable *actionable,
709                             const gchar   *action_name)
710 {
711   GtkButton *button = GTK_BUTTON (actionable);
712
713   g_return_if_fail (button->priv->action == NULL);
714
715   if (!button->priv->action_helper)
716     button->priv->action_helper = gtk_action_helper_new (actionable);
717
718   g_signal_handlers_disconnect_by_func (button, gtk_real_button_clicked, NULL);
719   if (action_name)
720     g_signal_connect_after (button, "clicked", G_CALLBACK (gtk_real_button_clicked), NULL);
721
722   gtk_action_helper_set_action_name (button->priv->action_helper, action_name);
723 }
724
725 static void
726 gtk_button_set_action_target_value (GtkActionable *actionable,
727                                     GVariant      *action_target)
728 {
729   GtkButton *button = GTK_BUTTON (actionable);
730
731   if (!button->priv->action_helper)
732     button->priv->action_helper = gtk_action_helper_new (actionable);
733
734   gtk_action_helper_set_action_target_value (button->priv->action_helper, action_target);
735 }
736
737 static void
738 gtk_button_set_property (GObject         *object,
739                          guint            prop_id,
740                          const GValue    *value,
741                          GParamSpec      *pspec)
742 {
743   GtkButton *button = GTK_BUTTON (object);
744   GtkButtonPrivate *priv = button->priv;
745
746   switch (prop_id)
747     {
748     case PROP_LABEL:
749       gtk_button_set_label (button, g_value_get_string (value));
750       break;
751     case PROP_IMAGE:
752       gtk_button_set_image (button, (GtkWidget *) g_value_get_object (value));
753       break;
754     case PROP_ALWAYS_SHOW_IMAGE:
755       gtk_button_set_always_show_image (button, g_value_get_boolean (value));
756       break;
757     case PROP_RELIEF:
758       gtk_button_set_relief (button, g_value_get_enum (value));
759       break;
760     case PROP_USE_UNDERLINE:
761       gtk_button_set_use_underline (button, g_value_get_boolean (value));
762       break;
763     case PROP_USE_STOCK:
764       gtk_button_set_use_stock (button, g_value_get_boolean (value));
765       break;
766     case PROP_FOCUS_ON_CLICK:
767       gtk_button_set_focus_on_click (button, g_value_get_boolean (value));
768       break;
769     case PROP_XALIGN:
770       gtk_button_set_alignment (button, g_value_get_float (value), priv->yalign);
771       break;
772     case PROP_YALIGN:
773       gtk_button_set_alignment (button, priv->xalign, g_value_get_float (value));
774       break;
775     case PROP_IMAGE_POSITION:
776       gtk_button_set_image_position (button, g_value_get_enum (value));
777       break;
778     case PROP_ACTIVATABLE_RELATED_ACTION:
779       gtk_button_set_related_action (button, g_value_get_object (value));
780       break;
781     case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
782       gtk_button_set_use_action_appearance (button, g_value_get_boolean (value));
783       break;
784     case PROP_ACTION_NAME:
785       gtk_button_set_action_name (GTK_ACTIONABLE (button), g_value_get_string (value));
786       break;
787     case PROP_ACTION_TARGET:
788       gtk_button_set_action_target_value (GTK_ACTIONABLE (button), g_value_get_variant (value));
789       break;
790     default:
791       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
792       break;
793     }
794 }
795
796 static void
797 gtk_button_get_property (GObject         *object,
798                          guint            prop_id,
799                          GValue          *value,
800                          GParamSpec      *pspec)
801 {
802   GtkButton *button = GTK_BUTTON (object);
803   GtkButtonPrivate *priv = button->priv;
804
805   switch (prop_id)
806     {
807     case PROP_LABEL:
808       g_value_set_string (value, priv->label_text);
809       break;
810     case PROP_IMAGE:
811       g_value_set_object (value, (GObject *)priv->image);
812       break;
813     case PROP_ALWAYS_SHOW_IMAGE:
814       g_value_set_boolean (value, gtk_button_get_always_show_image (button));
815       break;
816     case PROP_RELIEF:
817       g_value_set_enum (value, priv->relief);
818       break;
819     case PROP_USE_UNDERLINE:
820       g_value_set_boolean (value, priv->use_underline);
821       break;
822     case PROP_USE_STOCK:
823       g_value_set_boolean (value, priv->use_stock);
824       break;
825     case PROP_FOCUS_ON_CLICK:
826       g_value_set_boolean (value, priv->focus_on_click);
827       break;
828     case PROP_XALIGN:
829       g_value_set_float (value, priv->xalign);
830       break;
831     case PROP_YALIGN:
832       g_value_set_float (value, priv->yalign);
833       break;
834     case PROP_IMAGE_POSITION:
835       g_value_set_enum (value, priv->image_position);
836       break;
837     case PROP_ACTIVATABLE_RELATED_ACTION:
838       g_value_set_object (value, priv->action);
839       break;
840     case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
841       g_value_set_boolean (value, priv->use_action_appearance);
842       break;
843     case PROP_ACTION_NAME:
844       g_value_set_string (value, gtk_action_helper_get_action_name (priv->action_helper));
845       break;
846     case PROP_ACTION_TARGET:
847       g_value_set_variant (value, gtk_action_helper_get_action_target_value (priv->action_helper));
848       break;
849     default:
850       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
851       break;
852     }
853 }
854
855 static const gchar *
856 gtk_button_get_action_name (GtkActionable *actionable)
857 {
858   GtkButton *button = GTK_BUTTON (actionable);
859
860   return gtk_action_helper_get_action_name (button->priv->action_helper);
861 }
862
863 static GVariant *
864 gtk_button_get_action_target_value (GtkActionable *actionable)
865 {
866   GtkButton *button = GTK_BUTTON (actionable);
867
868   return gtk_action_helper_get_action_target_value (button->priv->action_helper);
869 }
870
871 static void
872 gtk_button_actionable_iface_init (GtkActionableInterface *iface)
873 {
874   iface->get_action_name = gtk_button_get_action_name;
875   iface->set_action_name = gtk_button_set_action_name;
876   iface->get_action_target_value = gtk_button_get_action_target_value;
877   iface->set_action_target_value = gtk_button_set_action_target_value;
878 }
879
880 static void 
881 gtk_button_activatable_interface_init (GtkActivatableIface  *iface)
882 {
883   iface->update = gtk_button_update;
884   iface->sync_action_properties = gtk_button_sync_action_properties;
885 }
886
887 static void
888 activatable_update_stock_id (GtkButton *button,
889                              GtkAction *action)
890 {
891   if (!gtk_button_get_use_stock (button))
892     return;
893
894   gtk_button_set_label (button, gtk_action_get_stock_id (action));
895 }
896
897 static void
898 activatable_update_short_label (GtkButton *button,
899                                 GtkAction *action)
900 {
901   GtkWidget *child;
902   GtkWidget *image;
903
904   if (gtk_button_get_use_stock (button))
905     return;
906
907   image = gtk_button_get_image (button);
908
909   /* Dont touch custom child... */
910   child = gtk_bin_get_child (GTK_BIN (button));
911   if (GTK_IS_IMAGE (image) ||
912       child == NULL ||
913       GTK_IS_LABEL (child))
914     {
915       gtk_button_set_label (button, gtk_action_get_short_label (action));
916       gtk_button_set_use_underline (button, TRUE);
917     }
918 }
919
920 static void
921 activatable_update_icon_name (GtkButton *button,
922                               GtkAction *action)
923 {
924   GtkWidget *image;
925               
926   if (gtk_button_get_use_stock (button))
927     return;
928
929   image = gtk_button_get_image (button);
930
931   if (GTK_IS_IMAGE (image) &&
932       (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
933        gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_ICON_NAME))
934     gtk_image_set_from_icon_name (GTK_IMAGE (image),
935                                   gtk_action_get_icon_name (action), GTK_ICON_SIZE_MENU);
936 }
937
938 static void
939 activatable_update_gicon (GtkButton *button,
940                           GtkAction *action)
941 {
942   GtkWidget *image = gtk_button_get_image (button);
943   GIcon *icon = gtk_action_get_gicon (action);
944   
945   if (GTK_IS_IMAGE (image) &&
946       (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
947        gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_GICON))
948     gtk_image_set_from_gicon (GTK_IMAGE (image), icon, GTK_ICON_SIZE_BUTTON);
949 }
950
951 static void 
952 gtk_button_update (GtkActivatable *activatable,
953                    GtkAction      *action,
954                    const gchar    *property_name)
955 {
956   GtkButton *button = GTK_BUTTON (activatable);
957   GtkButtonPrivate *priv = button->priv;
958
959   if (strcmp (property_name, "visible") == 0)
960     {
961       if (gtk_action_is_visible (action))
962         gtk_widget_show (GTK_WIDGET (activatable));
963       else
964         gtk_widget_hide (GTK_WIDGET (activatable));
965     }
966   else if (strcmp (property_name, "sensitive") == 0)
967     gtk_widget_set_sensitive (GTK_WIDGET (activatable), gtk_action_is_sensitive (action));
968
969   if (!priv->use_action_appearance)
970     return;
971
972   if (strcmp (property_name, "stock-id") == 0)
973     activatable_update_stock_id (GTK_BUTTON (activatable), action);
974   else if (strcmp (property_name, "gicon") == 0)
975     activatable_update_gicon (GTK_BUTTON (activatable), action);
976   else if (strcmp (property_name, "short-label") == 0)
977     activatable_update_short_label (GTK_BUTTON (activatable), action);
978   else if (strcmp (property_name, "icon-name") == 0)
979     activatable_update_icon_name (GTK_BUTTON (activatable), action);
980 }
981
982 static void
983 gtk_button_sync_action_properties (GtkActivatable *activatable,
984                                    GtkAction      *action)
985 {
986   GtkButton *button = GTK_BUTTON (activatable);
987   GtkButtonPrivate *priv = button->priv;
988
989   if (!action)
990     return;
991
992   if (gtk_action_is_visible (action))
993     gtk_widget_show (GTK_WIDGET (activatable));
994   else
995     gtk_widget_hide (GTK_WIDGET (activatable));
996   
997   gtk_widget_set_sensitive (GTK_WIDGET (activatable), gtk_action_is_sensitive (action));
998   
999   if (priv->use_action_appearance)
1000     {
1001       activatable_update_stock_id (GTK_BUTTON (activatable), action);
1002       activatable_update_short_label (GTK_BUTTON (activatable), action);
1003       activatable_update_gicon (GTK_BUTTON (activatable), action);
1004       activatable_update_icon_name (GTK_BUTTON (activatable), action);
1005     }
1006
1007   gtk_button_set_always_show_image (button,
1008                                     gtk_action_get_always_show_image (action));
1009 }
1010
1011 static void
1012 gtk_button_set_related_action (GtkButton *button,
1013                                GtkAction *action)
1014 {
1015   GtkButtonPrivate *priv = button->priv;
1016
1017   g_return_if_fail (gtk_action_helper_get_action_name (button->priv->action_helper) == NULL);
1018
1019   if (priv->action == action)
1020     return;
1021
1022   /* This should be a default handler, but for compatibility reasons
1023    * we need to support derived classes that don't chain up their
1024    * clicked handler.
1025    */
1026   g_signal_handlers_disconnect_by_func (button, gtk_real_button_clicked, NULL);
1027   if (action)
1028     g_signal_connect_after (button, "clicked",
1029                             G_CALLBACK (gtk_real_button_clicked), NULL);
1030
1031   gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (button), action);
1032
1033   priv->action = action;
1034 }
1035
1036 static void
1037 gtk_button_set_use_action_appearance (GtkButton *button,
1038                                       gboolean   use_appearance)
1039 {
1040   GtkButtonPrivate *priv = button->priv;
1041
1042   if (priv->use_action_appearance != use_appearance)
1043     {
1044       priv->use_action_appearance = use_appearance;
1045
1046       gtk_activatable_sync_action_properties (GTK_ACTIVATABLE (button), priv->action);
1047     }
1048 }
1049
1050 /**
1051  * gtk_button_new:
1052  *
1053  * Creates a new #GtkButton widget. To add a child widget to the button,
1054  * use gtk_container_add().
1055  *
1056  * Returns: The newly created #GtkButton widget.
1057  */
1058 GtkWidget*
1059 gtk_button_new (void)
1060 {
1061   return g_object_new (GTK_TYPE_BUTTON, NULL);
1062 }
1063
1064 static gboolean
1065 show_image (GtkButton *button)
1066 {
1067   GtkButtonPrivate *priv = button->priv;
1068   gboolean show;
1069
1070   if (priv->label_text && !priv->always_show_image)
1071     {
1072       GtkSettings *settings;
1073
1074       settings = gtk_widget_get_settings (GTK_WIDGET (button));        
1075       g_object_get (settings, "gtk-button-images", &show, NULL);
1076     }
1077   else
1078     show = TRUE;
1079
1080   return show;
1081 }
1082
1083
1084 static void
1085 gtk_button_construct_child (GtkButton *button)
1086 {
1087   GtkButtonPrivate *priv = button->priv;
1088   GtkStyleContext *context;
1089   GtkStockItem item;
1090   GtkWidget *child;
1091   GtkWidget *label;
1092   GtkWidget *box;
1093   GtkWidget *align;
1094   GtkWidget *image = NULL;
1095   gchar *label_text = NULL;
1096   gint image_spacing;
1097
1098   if (!priv->constructed)
1099     return;
1100
1101   if (!priv->label_text && !priv->image)
1102     return;
1103
1104   context = gtk_widget_get_style_context (GTK_WIDGET (button));
1105
1106   gtk_style_context_get_style (context,
1107                                "image-spacing", &image_spacing,
1108                                NULL);
1109
1110   if (priv->image && !priv->image_is_stock)
1111     {
1112       GtkWidget *parent;
1113
1114       image = g_object_ref (priv->image);
1115
1116       parent = gtk_widget_get_parent (image);
1117       if (parent)
1118         gtk_container_remove (GTK_CONTAINER (parent), image);
1119     }
1120
1121   priv->image = NULL;
1122
1123   child = gtk_bin_get_child (GTK_BIN (button));
1124   if (child)
1125     gtk_container_remove (GTK_CONTAINER (button), child);
1126
1127   if (priv->use_stock &&
1128       priv->label_text &&
1129       gtk_stock_lookup (priv->label_text, &item))
1130     {
1131       if (!image)
1132         image = g_object_ref (gtk_image_new_from_stock (priv->label_text, GTK_ICON_SIZE_BUTTON));
1133
1134       label_text = item.label;
1135     }
1136   else
1137     label_text = priv->label_text;
1138
1139   if (image)
1140     {
1141       priv->image = image;
1142       g_object_set (priv->image,
1143                     "visible", show_image (button),
1144                     "no-show-all", TRUE,
1145                     NULL);
1146
1147       if (priv->image_position == GTK_POS_LEFT ||
1148           priv->image_position == GTK_POS_RIGHT)
1149         box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, image_spacing);
1150       else
1151         box = gtk_box_new (GTK_ORIENTATION_VERTICAL, image_spacing);
1152
1153       if (priv->align_set)
1154         align = gtk_alignment_new (priv->xalign, priv->yalign, 0.0, 0.0);
1155       else
1156         align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1157
1158       if (priv->image_position == GTK_POS_LEFT ||
1159           priv->image_position == GTK_POS_TOP)
1160         gtk_box_pack_start (GTK_BOX (box), priv->image, FALSE, FALSE, 0);
1161       else
1162         gtk_box_pack_end (GTK_BOX (box), priv->image, FALSE, FALSE, 0);
1163
1164       if (label_text)
1165         {
1166           if (priv->use_underline || priv->use_stock)
1167             {
1168               label = gtk_label_new_with_mnemonic (label_text);
1169               gtk_label_set_mnemonic_widget (GTK_LABEL (label),
1170                                              GTK_WIDGET (button));
1171             }
1172           else
1173             label = gtk_label_new (label_text);
1174
1175           if (priv->image_position == GTK_POS_RIGHT ||
1176               priv->image_position == GTK_POS_BOTTOM)
1177             gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
1178           else
1179             gtk_box_pack_end (GTK_BOX (box), label, FALSE, FALSE, 0);
1180         }
1181
1182       gtk_container_add (GTK_CONTAINER (button), align);
1183       gtk_container_add (GTK_CONTAINER (align), box);
1184       gtk_widget_show_all (align);
1185
1186       g_object_unref (image);
1187
1188       return;
1189     }
1190
1191   if (priv->use_underline || priv->use_stock)
1192     {
1193       label = gtk_label_new_with_mnemonic (priv->label_text);
1194       gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
1195     }
1196   else
1197     label = gtk_label_new (priv->label_text);
1198
1199   if (priv->align_set)
1200     gtk_misc_set_alignment (GTK_MISC (label), priv->xalign, priv->yalign);
1201
1202   gtk_widget_show (label);
1203   gtk_container_add (GTK_CONTAINER (button), label);
1204 }
1205
1206
1207 /**
1208  * gtk_button_new_with_label:
1209  * @label: The text you want the #GtkLabel to hold.
1210  *
1211  * Creates a #GtkButton widget with a #GtkLabel child containing the given
1212  * text.
1213  *
1214  * Returns: The newly created #GtkButton widget.
1215  */
1216 GtkWidget*
1217 gtk_button_new_with_label (const gchar *label)
1218 {
1219   return g_object_new (GTK_TYPE_BUTTON, "label", label, NULL);
1220 }
1221
1222 /**
1223  * gtk_button_new_from_stock:
1224  * @stock_id: the name of the stock item 
1225  *
1226  * Creates a new #GtkButton containing the image and text from a stock item.
1227  * Some stock ids have preprocessor macros like #GTK_STOCK_OK and
1228  * #GTK_STOCK_APPLY.
1229  *
1230  * If @stock_id is unknown, then it will be treated as a mnemonic
1231  * label (as for gtk_button_new_with_mnemonic()).
1232  *
1233  * Returns: a new #GtkButton
1234  **/
1235 GtkWidget*
1236 gtk_button_new_from_stock (const gchar *stock_id)
1237 {
1238   return g_object_new (GTK_TYPE_BUTTON,
1239                        "label", stock_id,
1240                        "use-stock", TRUE,
1241                        "use-underline", TRUE,
1242                        NULL);
1243 }
1244
1245 /**
1246  * gtk_button_new_with_mnemonic:
1247  * @label: The text of the button, with an underscore in front of the
1248  *         mnemonic character
1249  *
1250  * Creates a new #GtkButton containing a label.
1251  * If characters in @label are preceded by an underscore, they are underlined.
1252  * If you need a literal underscore character in a label, use '__' (two
1253  * underscores). The first underlined character represents a keyboard
1254  * accelerator called a mnemonic.
1255  * Pressing Alt and that key activates the button.
1256  *
1257  * Returns: a new #GtkButton
1258  **/
1259 GtkWidget*
1260 gtk_button_new_with_mnemonic (const gchar *label)
1261 {
1262   return g_object_new (GTK_TYPE_BUTTON, "label", label, "use-underline", TRUE,  NULL);
1263 }
1264
1265 /**
1266  * gtk_button_pressed:
1267  * @button: The #GtkButton you want to send the signal to.
1268  *
1269  * Emits a #GtkButton::pressed signal to the given #GtkButton.
1270  *
1271  * Deprecated: 2.20: Use the #GtkWidget::button-press-event signal.
1272  */
1273 void
1274 gtk_button_pressed (GtkButton *button)
1275 {
1276   g_return_if_fail (GTK_IS_BUTTON (button));
1277
1278   g_signal_emit (button, button_signals[PRESSED], 0);
1279 }
1280
1281 /**
1282  * gtk_button_released:
1283  * @button: The #GtkButton you want to send the signal to.
1284  *
1285  * Emits a #GtkButton::released signal to the given #GtkButton.
1286  *
1287  * Deprecated: 2.20: Use the #GtkWidget::button-release-event signal.
1288  */
1289 void
1290 gtk_button_released (GtkButton *button)
1291 {
1292   g_return_if_fail (GTK_IS_BUTTON (button));
1293
1294   g_signal_emit (button, button_signals[RELEASED], 0);
1295 }
1296
1297 /**
1298  * gtk_button_clicked:
1299  * @button: The #GtkButton you want to send the signal to.
1300  *
1301  * Emits a #GtkButton::clicked signal to the given #GtkButton.
1302  */
1303 void
1304 gtk_button_clicked (GtkButton *button)
1305 {
1306   g_return_if_fail (GTK_IS_BUTTON (button));
1307
1308   g_signal_emit (button, button_signals[CLICKED], 0);
1309 }
1310
1311 /**
1312  * gtk_button_enter:
1313  * @button: The #GtkButton you want to send the signal to.
1314  *
1315  * Emits a #GtkButton::enter signal to the given #GtkButton.
1316  *
1317  * Deprecated: 2.20: Use the #GtkWidget::enter-notify-event signal.
1318  */
1319 void
1320 gtk_button_enter (GtkButton *button)
1321 {
1322   g_return_if_fail (GTK_IS_BUTTON (button));
1323
1324   g_signal_emit (button, button_signals[ENTER], 0);
1325 }
1326
1327 /**
1328  * gtk_button_leave:
1329  * @button: The #GtkButton you want to send the signal to.
1330  *
1331  * Emits a #GtkButton::leave signal to the given #GtkButton.
1332  *
1333  * Deprecated: 2.20: Use the #GtkWidget::leave-notify-event signal.
1334  */
1335 void
1336 gtk_button_leave (GtkButton *button)
1337 {
1338   g_return_if_fail (GTK_IS_BUTTON (button));
1339
1340   g_signal_emit (button, button_signals[LEAVE], 0);
1341 }
1342
1343 /**
1344  * gtk_button_set_relief:
1345  * @button: The #GtkButton you want to set relief styles of.
1346  * @newstyle: The GtkReliefStyle as described above.
1347  *
1348  * Sets the relief style of the edges of the given #GtkButton widget.
1349  * Three styles exist, GTK_RELIEF_NORMAL, GTK_RELIEF_HALF, GTK_RELIEF_NONE.
1350  * The default style is, as one can guess, GTK_RELIEF_NORMAL.
1351  *
1352  * <!-- FIXME: put pictures of each style -->
1353  */
1354 void
1355 gtk_button_set_relief (GtkButton *button,
1356                        GtkReliefStyle newrelief)
1357 {
1358   GtkButtonPrivate *priv;
1359
1360   g_return_if_fail (GTK_IS_BUTTON (button));
1361
1362   priv = button->priv;
1363
1364   if (newrelief != priv->relief)
1365     {
1366        priv->relief = newrelief;
1367        g_object_notify (G_OBJECT (button), "relief");
1368        gtk_widget_queue_draw (GTK_WIDGET (button));
1369     }
1370 }
1371
1372 /**
1373  * gtk_button_get_relief:
1374  * @button: The #GtkButton you want the #GtkReliefStyle from.
1375  *
1376  * Returns the current relief style of the given #GtkButton.
1377  *
1378  * Returns: The current #GtkReliefStyle
1379  */
1380 GtkReliefStyle
1381 gtk_button_get_relief (GtkButton *button)
1382 {
1383   g_return_val_if_fail (GTK_IS_BUTTON (button), GTK_RELIEF_NORMAL);
1384
1385   return button->priv->relief;
1386 }
1387
1388 static void
1389 gtk_button_realize (GtkWidget *widget)
1390 {
1391   GtkButton *button = GTK_BUTTON (widget);
1392   GtkButtonPrivate *priv = button->priv;
1393   GtkAllocation allocation;
1394   GdkWindow *window;
1395   GdkWindowAttr attributes;
1396   gint attributes_mask;
1397
1398   gtk_widget_get_allocation (widget, &allocation);
1399
1400   gtk_widget_set_realized (widget, TRUE);
1401
1402   attributes.window_type = GDK_WINDOW_CHILD;
1403   attributes.x = allocation.x;
1404   attributes.y = allocation.y;
1405   attributes.width = allocation.width;
1406   attributes.height = allocation.height;
1407   attributes.wclass = GDK_INPUT_ONLY;
1408   attributes.event_mask = gtk_widget_get_events (widget);
1409   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1410                             GDK_BUTTON_RELEASE_MASK |
1411                             GDK_TOUCH_MASK |
1412                             GDK_ENTER_NOTIFY_MASK |
1413                             GDK_LEAVE_NOTIFY_MASK);
1414
1415   attributes_mask = GDK_WA_X | GDK_WA_Y;
1416
1417   window = gtk_widget_get_parent_window (widget);
1418   gtk_widget_set_window (widget, window);
1419   g_object_ref (window);
1420
1421   priv->event_window = gdk_window_new (window,
1422                                        &attributes, attributes_mask);
1423   gtk_widget_register_window (widget, priv->event_window);
1424 }
1425
1426 static void
1427 gtk_button_unrealize (GtkWidget *widget)
1428 {
1429   GtkButton *button = GTK_BUTTON (widget);
1430   GtkButtonPrivate *priv = button->priv;
1431
1432   if (priv->activate_timeout)
1433     gtk_button_finish_activate (button, FALSE);
1434
1435   if (priv->event_window)
1436     {
1437       gtk_widget_unregister_window (widget, priv->event_window);
1438       gdk_window_destroy (priv->event_window);
1439       priv->event_window = NULL;
1440     }
1441
1442   GTK_WIDGET_CLASS (gtk_button_parent_class)->unrealize (widget);
1443 }
1444
1445 static void
1446 gtk_button_map (GtkWidget *widget)
1447 {
1448   GtkButton *button = GTK_BUTTON (widget);
1449   GtkButtonPrivate *priv = button->priv;
1450
1451   GTK_WIDGET_CLASS (gtk_button_parent_class)->map (widget);
1452
1453   if (priv->event_window)
1454     gdk_window_show (priv->event_window);
1455 }
1456
1457 static void
1458 gtk_button_unmap (GtkWidget *widget)
1459 {
1460   GtkButton *button = GTK_BUTTON (widget);
1461   GtkButtonPrivate *priv = button->priv;
1462
1463   if (priv->event_window)
1464     {
1465       gdk_window_hide (priv->event_window);
1466       priv->in_button = FALSE;
1467     }
1468
1469   GTK_WIDGET_CLASS (gtk_button_parent_class)->unmap (widget);
1470 }
1471
1472 static void
1473 gtk_button_update_image_spacing (GtkButton       *button,
1474                                  GtkStyleContext *context)
1475 {
1476   GtkButtonPrivate *priv = button->priv;
1477   GtkWidget *child; 
1478   gint spacing;
1479
1480   /* Keep in sync with gtk_button_construct_child,
1481    * we only want to update the spacing if the box 
1482    * was constructed there.
1483    */
1484   if (!priv->constructed || !priv->image)
1485     return;
1486
1487   child = gtk_bin_get_child (GTK_BIN (button));
1488   if (GTK_IS_ALIGNMENT (child))
1489     {
1490       child = gtk_bin_get_child (GTK_BIN (child));
1491       if (GTK_IS_BOX (child))
1492         {
1493           gtk_style_context_get_style (context,
1494                                        "image-spacing", &spacing,
1495                                        NULL);
1496
1497           gtk_box_set_spacing (GTK_BOX (child), spacing);
1498         }
1499     }
1500 }
1501
1502 static void
1503 gtk_button_style_updated (GtkWidget *widget)
1504 {
1505   GtkStyleContext *context;
1506
1507   GTK_WIDGET_CLASS (gtk_button_parent_class)->style_updated (widget);
1508
1509   context = gtk_widget_get_style_context (widget);
1510
1511   gtk_button_update_image_spacing (GTK_BUTTON (widget), context);
1512 }
1513
1514 static void
1515 gtk_button_get_props (GtkButton *button,
1516                       GtkBorder *default_border,
1517                       GtkBorder *default_outside_border,
1518                       GtkBorder *padding,
1519                       GtkBorder *border,
1520                       gboolean  *interior_focus)
1521 {
1522   GtkStyleContext *context;
1523   GtkStateFlags state;
1524   GtkBorder *tmp_border;
1525
1526   context = gtk_widget_get_style_context (GTK_WIDGET (button));
1527   state = gtk_style_context_get_state (context);
1528
1529   if (default_border)
1530     {
1531       gtk_style_context_get_style (context,
1532                                    "default-border", &tmp_border,
1533                                    NULL);
1534
1535       if (tmp_border)
1536         {
1537           *default_border = *tmp_border;
1538           gtk_border_free (tmp_border);
1539         }
1540       else
1541         *default_border = default_default_border;
1542     }
1543
1544   if (default_outside_border)
1545     {
1546       gtk_style_context_get_style (context,
1547                                    "default-outside-border", &tmp_border,
1548                                    NULL);
1549
1550       if (tmp_border)
1551         {
1552           *default_outside_border = *tmp_border;
1553           gtk_border_free (tmp_border);
1554         }
1555       else
1556         *default_outside_border = default_default_outside_border;
1557     }
1558
1559   if (interior_focus)
1560     {
1561       gtk_style_context_get_style (context,
1562                                    "interior-focus", interior_focus,
1563                                    NULL);
1564     }
1565
1566   if (padding)
1567     gtk_style_context_get_padding (context, state, padding);
1568
1569   if (border)
1570     gtk_style_context_get_border (context, state, border);
1571 }
1572
1573 static void
1574 gtk_button_size_allocate (GtkWidget     *widget,
1575                           GtkAllocation *allocation)
1576 {
1577   GtkButton *button = GTK_BUTTON (widget);
1578   GtkButtonPrivate *priv = button->priv;
1579   GtkAllocation child_allocation;
1580   GtkStyleContext *context;
1581   GtkWidget *child;
1582   GtkBorder default_border;
1583   GtkBorder padding;
1584   GtkBorder border;
1585   gint focus_width;
1586   gint focus_pad;
1587
1588   context = gtk_widget_get_style_context (widget);
1589
1590   gtk_button_get_props (button, &default_border, NULL,
1591                         &padding, &border, NULL);
1592   gtk_style_context_get_style (context,
1593                               "focus-line-width", &focus_width,
1594                               "focus-padding", &focus_pad,
1595                               NULL);
1596
1597   gtk_widget_set_allocation (widget, allocation);
1598
1599   if (gtk_widget_get_realized (widget))
1600     gdk_window_move_resize (priv->event_window,
1601                             allocation->x,
1602                             allocation->y,
1603                             allocation->width,
1604                             allocation->height);
1605
1606   child = gtk_bin_get_child (GTK_BIN (button));
1607   if (child && gtk_widget_get_visible (child))
1608     {
1609       child_allocation.x = allocation->x + padding.left + border.left;
1610       child_allocation.y = allocation->y + padding.top + border.top;
1611
1612       child_allocation.width =
1613         allocation->width -
1614         (padding.left + padding.right) -
1615         (border.left + border.right);
1616
1617       child_allocation.height = 
1618         allocation->height -
1619         (padding.top + padding.bottom) -
1620         (border.top + border.bottom);
1621
1622       if (gtk_widget_get_can_default (GTK_WIDGET (button)))
1623         {
1624           child_allocation.x += default_border.left;
1625           child_allocation.y += default_border.top;
1626           child_allocation.width =  child_allocation.width - default_border.left - default_border.right;
1627           child_allocation.height = child_allocation.height - default_border.top - default_border.bottom;
1628         }
1629
1630       if (gtk_widget_get_can_focus (GTK_WIDGET (button)))
1631         {
1632           child_allocation.x += focus_width + focus_pad;
1633           child_allocation.y += focus_width + focus_pad;
1634           child_allocation.width =  child_allocation.width - (focus_width + focus_pad) * 2;
1635           child_allocation.height = child_allocation.height - (focus_width + focus_pad) * 2;
1636         }
1637
1638       if (priv->depressed)
1639         {
1640           gint child_displacement_x;
1641           gint child_displacement_y;
1642
1643           gtk_style_context_get_style (context,
1644                                        "child-displacement-x", &child_displacement_x,
1645                                        "child-displacement-y", &child_displacement_y,
1646                                        NULL);
1647           child_allocation.x += child_displacement_x;
1648           child_allocation.y += child_displacement_y;
1649         }
1650
1651       child_allocation.width  = MAX (1, child_allocation.width);
1652       child_allocation.height = MAX (1, child_allocation.height);
1653
1654       gtk_widget_size_allocate (child, &child_allocation);
1655     }
1656 }
1657
1658 static gboolean
1659 gtk_button_draw (GtkWidget *widget,
1660                  cairo_t   *cr)
1661 {
1662   GtkButton *button = GTK_BUTTON (widget);
1663   GtkButtonPrivate *priv = button->priv;
1664   gint x, y;
1665   GtkBorder default_border;
1666   GtkBorder default_outside_border;
1667   gboolean interior_focus;
1668   gint focus_width;
1669   gint focus_pad;
1670   GtkAllocation allocation;
1671   GtkStyleContext *context;
1672   GtkStateFlags state;
1673   gboolean draw_focus;
1674   gint width, height;
1675
1676   context = gtk_widget_get_style_context (widget);
1677   state = gtk_style_context_get_state (context);
1678
1679   gtk_button_get_props (button, &default_border, &default_outside_border, NULL, NULL, &interior_focus);
1680   gtk_style_context_get_style (context,
1681                                "focus-line-width", &focus_width,
1682                                "focus-padding", &focus_pad,
1683                                NULL);
1684
1685   gtk_widget_get_allocation (widget, &allocation);
1686
1687   x = 0;
1688   y = 0;
1689   width = allocation.width;
1690   height = allocation.height;
1691
1692   if (gtk_widget_has_default (widget) &&
1693       priv->relief == GTK_RELIEF_NORMAL)
1694     {
1695       x += default_border.left;
1696       y += default_border.top;
1697       width -= default_border.left + default_border.right;
1698       height -= default_border.top + default_border.bottom;
1699     }
1700   else if (gtk_widget_get_can_default (widget))
1701     {
1702       x += default_outside_border.left;
1703       y += default_outside_border.top;
1704       width -= default_outside_border.left + default_outside_border.right;
1705       height -= default_outside_border.top + default_outside_border.bottom;
1706     }
1707
1708   draw_focus = gtk_widget_has_visible_focus (widget);
1709
1710
1711   if (!interior_focus && draw_focus)
1712     {
1713       x += focus_width + focus_pad;
1714       y += focus_width + focus_pad;
1715       width -= 2 * (focus_width + focus_pad);
1716       height -= 2 * (focus_width + focus_pad);
1717     }
1718
1719   if (priv->relief != GTK_RELIEF_NONE || priv->depressed ||
1720       state & GTK_STATE_FLAG_PRELIGHT)
1721     {
1722       gtk_render_background (context, cr,
1723                              x, y, width, height);
1724       gtk_render_frame (context, cr,
1725                         x, y, width, height);
1726     }
1727
1728   if (draw_focus)
1729     {
1730       gint child_displacement_x;
1731       gint child_displacement_y;
1732       gboolean displace_focus;
1733       GtkBorder border;
1734
1735       gtk_style_context_get_style (context,
1736                                    "child-displacement-y", &child_displacement_y,
1737                                    "child-displacement-x", &child_displacement_x,
1738                                    "displace-focus", &displace_focus,
1739                                    NULL);
1740       gtk_style_context_get_border (context, state, &border);
1741
1742       if (interior_focus)
1743         {
1744           x += border.left + focus_pad;
1745           y += border.top + focus_pad;
1746           width -= (2 * focus_pad) + border.left + border.right;
1747           height -=  (2 * focus_pad) + border.top + border.bottom;
1748         }
1749       else
1750         {
1751           x -= focus_width + focus_pad;
1752           y -= focus_width + focus_pad;
1753           width += 2 * (focus_width + focus_pad);
1754           height += 2 * (focus_width + focus_pad);
1755         }
1756
1757       if (priv->depressed && displace_focus)
1758         {
1759           x += child_displacement_x;
1760           y += child_displacement_y;
1761         }
1762
1763       gtk_render_focus (context, cr, x, y, width, height);
1764     }
1765
1766   GTK_WIDGET_CLASS (gtk_button_parent_class)->draw (widget, cr);
1767
1768   return FALSE;
1769 }
1770
1771 static gboolean
1772 gtk_button_button_press (GtkWidget      *widget,
1773                          GdkEventButton *event)
1774 {
1775   GtkButton *button;
1776   GtkButtonPrivate *priv;
1777
1778   if (event->type == GDK_BUTTON_PRESS)
1779     {
1780       button = GTK_BUTTON (widget);
1781       priv = button->priv;
1782
1783       if (priv->focus_on_click && !gtk_widget_has_focus (widget))
1784         gtk_widget_grab_focus (widget);
1785
1786       if (event->button == GDK_BUTTON_PRIMARY)
1787         g_signal_emit (button, button_signals[PRESSED], 0);
1788     }
1789
1790   return TRUE;
1791 }
1792
1793 static gboolean
1794 gtk_button_button_release (GtkWidget      *widget,
1795                            GdkEventButton *event)
1796 {
1797   GtkButton *button;
1798
1799   if (event->button == GDK_BUTTON_PRIMARY)
1800     {
1801       button = GTK_BUTTON (widget);
1802       g_signal_emit (button, button_signals[RELEASED], 0);
1803     }
1804
1805   return TRUE;
1806 }
1807
1808 static gboolean
1809 gtk_button_touch (GtkWidget     *widget,
1810                   GdkEventTouch *event)
1811 {
1812   GtkButton *button = GTK_BUTTON (widget);
1813   GtkButtonPrivate *priv = button->priv;
1814
1815   if (event->type == GDK_TOUCH_BEGIN)
1816     {
1817       if (priv->focus_on_click && !gtk_widget_has_focus (widget))
1818         gtk_widget_grab_focus (widget);
1819
1820       g_signal_emit (button, button_signals[PRESSED], 0);
1821     }
1822   else if (event->type == GDK_TOUCH_END)
1823     {
1824       g_signal_emit (button, button_signals[RELEASED], 0);
1825     }
1826
1827   return TRUE;
1828 }
1829
1830 static gboolean
1831 gtk_button_grab_broken (GtkWidget          *widget,
1832                         GdkEventGrabBroken *event)
1833 {
1834   GtkButton *button = GTK_BUTTON (widget);
1835   GtkButtonPrivate *priv = button->priv;
1836   gboolean save_in;
1837   
1838   /* Simulate a button release without the pointer in the button */
1839   if (priv->button_down)
1840     {
1841       save_in = priv->in_button;
1842       priv->in_button = FALSE;
1843       g_signal_emit (button, button_signals[RELEASED], 0);
1844       if (save_in != priv->in_button)
1845         {
1846           priv->in_button = save_in;
1847           gtk_button_update_state (button);
1848         }
1849     }
1850
1851   return TRUE;
1852 }
1853
1854 static gboolean
1855 gtk_button_key_release (GtkWidget   *widget,
1856                         GdkEventKey *event)
1857 {
1858   GtkButton *button = GTK_BUTTON (widget);
1859   GtkButtonPrivate *priv = button->priv;
1860
1861   if (priv->activate_timeout)
1862     {
1863       gtk_button_finish_activate (button, TRUE);
1864       return TRUE;
1865     }
1866   else if (GTK_WIDGET_CLASS (gtk_button_parent_class)->key_release_event)
1867     return GTK_WIDGET_CLASS (gtk_button_parent_class)->key_release_event (widget, event);
1868   else
1869     return FALSE;
1870 }
1871
1872 static gboolean
1873 gtk_button_enter_notify (GtkWidget        *widget,
1874                          GdkEventCrossing *event)
1875 {
1876   GtkButton *button = GTK_BUTTON (widget);
1877   GtkButtonPrivate *priv = button->priv;
1878
1879   if ((event->window == button->priv->event_window) &&
1880       (event->detail != GDK_NOTIFY_INFERIOR))
1881     {
1882       priv->in_button = TRUE;
1883       g_signal_emit (button, button_signals[ENTER], 0);
1884     }
1885
1886   return FALSE;
1887 }
1888
1889 static gboolean
1890 gtk_button_leave_notify (GtkWidget        *widget,
1891                          GdkEventCrossing *event)
1892 {
1893   GtkButton *button = GTK_BUTTON (widget);
1894   GtkButtonPrivate *priv = button->priv;
1895
1896   if ((event->window == button->priv->event_window) &&
1897       (event->detail != GDK_NOTIFY_INFERIOR) &&
1898       (gtk_widget_get_sensitive (widget)))
1899     {
1900       priv->in_button = FALSE;
1901       g_signal_emit (button, button_signals[LEAVE], 0);
1902     }
1903
1904   return FALSE;
1905 }
1906
1907 static void
1908 gtk_real_button_pressed (GtkButton *button)
1909 {
1910   GtkButtonPrivate *priv = button->priv;
1911
1912   if (priv->activate_timeout)
1913     return;
1914
1915   priv->button_down = TRUE;
1916   gtk_button_update_state (button);
1917 }
1918
1919 static gboolean
1920 touch_release_in_button (GtkButton *button)
1921 {
1922   GtkButtonPrivate *priv;
1923   gint width, height;
1924   GdkEvent *event;
1925   gdouble x, y;
1926
1927   priv = button->priv;
1928   event = gtk_get_current_event ();
1929
1930   if (!event)
1931     return FALSE;
1932
1933   if (event->type != GDK_TOUCH_END ||
1934       event->touch.window != priv->event_window)
1935     {
1936       gdk_event_free (event);
1937       return FALSE;
1938     }
1939
1940   gdk_event_get_coords (event, &x, &y);
1941   width = gdk_window_get_width (priv->event_window);
1942   height = gdk_window_get_height (priv->event_window);
1943
1944   gdk_event_free (event);
1945
1946   if (x >= 0 && x <= width &&
1947       y >= 0 && y <= height)
1948     return TRUE;
1949
1950   return FALSE;
1951 }
1952
1953 static void
1954 gtk_real_button_released (GtkButton *button)
1955 {
1956   GtkButtonPrivate *priv = button->priv;
1957
1958   if (priv->button_down)
1959     {
1960       priv->button_down = FALSE;
1961
1962       if (priv->activate_timeout)
1963         return;
1964
1965       if (priv->in_button ||
1966           touch_release_in_button (button))
1967         gtk_button_clicked (button);
1968
1969       gtk_button_update_state (button);
1970     }
1971 }
1972
1973 static void 
1974 gtk_real_button_clicked (GtkButton *button)
1975 {
1976   GtkButtonPrivate *priv = button->priv;
1977
1978   if (priv->action_helper)
1979     gtk_action_helper_activate (priv->action_helper);
1980
1981   if (priv->action)
1982     gtk_action_activate (priv->action);
1983 }
1984
1985 static gboolean
1986 button_activate_timeout (gpointer data)
1987 {
1988   gtk_button_finish_activate (data, TRUE);
1989
1990   return FALSE;
1991 }
1992
1993 static void
1994 gtk_real_button_activate (GtkButton *button)
1995 {
1996   GtkWidget *widget = GTK_WIDGET (button);
1997   GtkButtonPrivate *priv = button->priv;
1998   GdkDevice *device;
1999   guint32 time;
2000
2001   device = gtk_get_current_event_device ();
2002
2003   if (device && gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
2004     device = gdk_device_get_associated_device (device);
2005
2006   if (gtk_widget_get_realized (widget) && !priv->activate_timeout)
2007     {
2008       time = gtk_get_current_event_time ();
2009
2010       /* bgo#626336 - Only grab if we have a device (from an event), not if we
2011        * were activated programmatically when no event is available.
2012        */
2013       if (device && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
2014         {
2015           if (gdk_device_grab (device, priv->event_window,
2016                                GDK_OWNERSHIP_WINDOW, TRUE,
2017                                GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
2018                                NULL, time) == GDK_GRAB_SUCCESS)
2019             {
2020               gtk_device_grab_add (widget, device, TRUE);
2021               priv->grab_keyboard = device;
2022               priv->grab_time = time;
2023             }
2024         }
2025
2026       priv->activate_timeout = gdk_threads_add_timeout (ACTIVATE_TIMEOUT,
2027                                                 button_activate_timeout,
2028                                                 button);
2029       priv->button_down = TRUE;
2030       gtk_button_update_state (button);
2031       gtk_widget_queue_draw (GTK_WIDGET (button));
2032     }
2033 }
2034
2035 static void
2036 gtk_button_finish_activate (GtkButton *button,
2037                             gboolean   do_it)
2038 {
2039   GtkWidget *widget = GTK_WIDGET (button);
2040   GtkButtonPrivate *priv = button->priv;
2041
2042   g_source_remove (priv->activate_timeout);
2043   priv->activate_timeout = 0;
2044
2045   if (priv->grab_keyboard)
2046     {
2047       gdk_device_ungrab (priv->grab_keyboard, priv->grab_time);
2048       gtk_device_grab_remove (widget, priv->grab_keyboard);
2049       priv->grab_keyboard = NULL;
2050     }
2051
2052   priv->button_down = FALSE;
2053
2054   gtk_button_update_state (button);
2055   gtk_widget_queue_draw (GTK_WIDGET (button));
2056
2057   if (do_it)
2058     gtk_button_clicked (button);
2059 }
2060
2061
2062 static void
2063 gtk_button_get_size (GtkWidget      *widget,
2064                      GtkOrientation  orientation,
2065                      gint           *minimum_size,
2066                      gint           *natural_size)
2067 {
2068   GtkButton *button = GTK_BUTTON (widget);
2069   GtkStyleContext *context;
2070   GtkWidget *child;
2071   GtkBorder default_border;
2072   GtkBorder padding;
2073   GtkBorder border;
2074   gint focus_width;
2075   gint focus_pad;
2076   gint minimum, natural;
2077
2078   context = gtk_widget_get_style_context (widget);
2079
2080   gtk_button_get_props (button, &default_border, NULL,
2081                         &padding, &border, NULL);
2082   gtk_style_context_get_style (context,
2083                                "focus-line-width", &focus_width,
2084                                "focus-padding", &focus_pad,
2085                                NULL);
2086
2087   if (orientation == GTK_ORIENTATION_HORIZONTAL)
2088     {
2089       minimum = padding.left + padding.right +
2090         border.left + border.right;
2091
2092       if (gtk_widget_get_can_default (GTK_WIDGET (widget)))
2093         minimum += default_border.left + default_border.right;
2094     }
2095   else
2096     {
2097       minimum = padding.top + padding.bottom +
2098         border.top + border.bottom;
2099
2100       if (gtk_widget_get_can_default (GTK_WIDGET (widget)))
2101         minimum += default_border.top + default_border.bottom;
2102     }  
2103
2104   minimum += 2 * (focus_width + focus_pad);
2105   natural = minimum;
2106
2107   if ((child = gtk_bin_get_child (GTK_BIN (button))) && 
2108       gtk_widget_get_visible (child))
2109     {
2110       gint child_min, child_nat;
2111
2112       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2113         gtk_widget_get_preferred_width (child, &child_min, &child_nat);
2114       else
2115         gtk_widget_get_preferred_height (child, &child_min, &child_nat);
2116
2117       minimum += child_min;
2118       natural += child_nat;
2119     }
2120
2121   if (minimum_size)
2122     *minimum_size = minimum;
2123
2124   if (natural_size)
2125     *natural_size = natural;
2126 }
2127
2128 static void 
2129 gtk_button_get_preferred_width (GtkWidget *widget,
2130                                 gint      *minimum_size,
2131                                 gint      *natural_size)
2132 {
2133   gtk_button_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
2134 }
2135
2136 static void 
2137 gtk_button_get_preferred_height (GtkWidget *widget,
2138                                  gint      *minimum_size,
2139                                  gint      *natural_size)
2140 {
2141   gtk_button_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
2142 }
2143
2144 /**
2145  * gtk_button_set_label:
2146  * @button: a #GtkButton
2147  * @label: a string
2148  *
2149  * Sets the text of the label of the button to @str. This text is
2150  * also used to select the stock item if gtk_button_set_use_stock()
2151  * is used.
2152  *
2153  * This will also clear any previously set labels.
2154  **/
2155 void
2156 gtk_button_set_label (GtkButton   *button,
2157                       const gchar *label)
2158 {
2159   GtkButtonPrivate *priv;
2160   gchar *new_label;
2161
2162   g_return_if_fail (GTK_IS_BUTTON (button));
2163
2164   priv = button->priv;
2165
2166   new_label = g_strdup (label);
2167   g_free (priv->label_text);
2168   priv->label_text = new_label;
2169
2170   gtk_button_construct_child (button);
2171   
2172   g_object_notify (G_OBJECT (button), "label");
2173 }
2174
2175 /**
2176  * gtk_button_get_label:
2177  * @button: a #GtkButton
2178  *
2179  * Fetches the text from the label of the button, as set by
2180  * gtk_button_set_label(). If the label text has not 
2181  * been set the return value will be %NULL. This will be the 
2182  * case if you create an empty button with gtk_button_new() to 
2183  * use as a container.
2184  *
2185  * Return value: The text of the label widget. This string is owned
2186  * by the widget and must not be modified or freed.
2187  **/
2188 const gchar *
2189 gtk_button_get_label (GtkButton *button)
2190 {
2191   g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
2192
2193   return button->priv->label_text;
2194 }
2195
2196 /**
2197  * gtk_button_set_use_underline:
2198  * @button: a #GtkButton
2199  * @use_underline: %TRUE if underlines in the text indicate mnemonics
2200  *
2201  * If true, an underline in the text of the button label indicates
2202  * the next character should be used for the mnemonic accelerator key.
2203  */
2204 void
2205 gtk_button_set_use_underline (GtkButton *button,
2206                               gboolean   use_underline)
2207 {
2208   GtkButtonPrivate *priv;
2209
2210   g_return_if_fail (GTK_IS_BUTTON (button));
2211
2212   priv = button->priv;
2213
2214   use_underline = use_underline != FALSE;
2215
2216   if (use_underline != priv->use_underline)
2217     {
2218       priv->use_underline = use_underline;
2219
2220       gtk_button_construct_child (button);
2221       
2222       g_object_notify (G_OBJECT (button), "use-underline");
2223     }
2224 }
2225
2226 /**
2227  * gtk_button_get_use_underline:
2228  * @button: a #GtkButton
2229  *
2230  * Returns whether an embedded underline in the button label indicates a
2231  * mnemonic. See gtk_button_set_use_underline ().
2232  *
2233  * Return value: %TRUE if an embedded underline in the button label
2234  *               indicates the mnemonic accelerator keys.
2235  **/
2236 gboolean
2237 gtk_button_get_use_underline (GtkButton *button)
2238 {
2239   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
2240
2241   return button->priv->use_underline;
2242 }
2243
2244 /**
2245  * gtk_button_set_use_stock:
2246  * @button: a #GtkButton
2247  * @use_stock: %TRUE if the button should use a stock item
2248  *
2249  * If %TRUE, the label set on the button is used as a
2250  * stock id to select the stock item for the button.
2251  */
2252 void
2253 gtk_button_set_use_stock (GtkButton *button,
2254                           gboolean   use_stock)
2255 {
2256   GtkButtonPrivate *priv;
2257
2258   g_return_if_fail (GTK_IS_BUTTON (button));
2259
2260   priv = button->priv;
2261
2262   use_stock = use_stock != FALSE;
2263
2264   if (use_stock != priv->use_stock)
2265     {
2266       priv->use_stock = use_stock;
2267
2268       gtk_button_construct_child (button);
2269       
2270       g_object_notify (G_OBJECT (button), "use-stock");
2271     }
2272 }
2273
2274 /**
2275  * gtk_button_get_use_stock:
2276  * @button: a #GtkButton
2277  *
2278  * Returns whether the button label is a stock item.
2279  *
2280  * Return value: %TRUE if the button label is used to
2281  *               select a stock item instead of being
2282  *               used directly as the label text.
2283  */
2284 gboolean
2285 gtk_button_get_use_stock (GtkButton *button)
2286 {
2287   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
2288
2289   return button->priv->use_stock;
2290 }
2291
2292 /**
2293  * gtk_button_set_focus_on_click:
2294  * @button: a #GtkButton
2295  * @focus_on_click: whether the button grabs focus when clicked with the mouse
2296  *
2297  * Sets whether the button will grab focus when it is clicked with the mouse.
2298  * Making mouse clicks not grab focus is useful in places like toolbars where
2299  * you don't want the keyboard focus removed from the main area of the
2300  * application.
2301  *
2302  * Since: 2.4
2303  **/
2304 void
2305 gtk_button_set_focus_on_click (GtkButton *button,
2306                                gboolean   focus_on_click)
2307 {
2308   GtkButtonPrivate *priv;
2309
2310   g_return_if_fail (GTK_IS_BUTTON (button));
2311
2312   priv = button->priv;
2313
2314   focus_on_click = focus_on_click != FALSE;
2315
2316   if (priv->focus_on_click != focus_on_click)
2317     {
2318       priv->focus_on_click = focus_on_click;
2319       
2320       g_object_notify (G_OBJECT (button), "focus-on-click");
2321     }
2322 }
2323
2324 /**
2325  * gtk_button_get_focus_on_click:
2326  * @button: a #GtkButton
2327  *
2328  * Returns whether the button grabs focus when it is clicked with the mouse.
2329  * See gtk_button_set_focus_on_click().
2330  *
2331  * Return value: %TRUE if the button grabs focus when it is clicked with
2332  *               the mouse.
2333  *
2334  * Since: 2.4
2335  **/
2336 gboolean
2337 gtk_button_get_focus_on_click (GtkButton *button)
2338 {
2339   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
2340   
2341   return button->priv->focus_on_click;
2342 }
2343
2344 /**
2345  * gtk_button_set_alignment:
2346  * @button: a #GtkButton
2347  * @xalign: the horizontal position of the child, 0.0 is left aligned, 
2348  *   1.0 is right aligned
2349  * @yalign: the vertical position of the child, 0.0 is top aligned, 
2350  *   1.0 is bottom aligned
2351  *
2352  * Sets the alignment of the child. This property has no effect unless 
2353  * the child is a #GtkMisc or a #GtkAlignment.
2354  *
2355  * Since: 2.4
2356  */
2357 void
2358 gtk_button_set_alignment (GtkButton *button,
2359                           gfloat     xalign,
2360                           gfloat     yalign)
2361 {
2362   GtkButtonPrivate *priv;
2363
2364   g_return_if_fail (GTK_IS_BUTTON (button));
2365   
2366   priv = button->priv;
2367
2368   priv->xalign = xalign;
2369   priv->yalign = yalign;
2370   priv->align_set = 1;
2371
2372   maybe_set_alignment (button, gtk_bin_get_child (GTK_BIN (button)));
2373
2374   g_object_freeze_notify (G_OBJECT (button));
2375   g_object_notify (G_OBJECT (button), "xalign");
2376   g_object_notify (G_OBJECT (button), "yalign");
2377   g_object_thaw_notify (G_OBJECT (button));
2378 }
2379
2380 /**
2381  * gtk_button_get_alignment:
2382  * @button: a #GtkButton
2383  * @xalign: (out): return location for horizontal alignment
2384  * @yalign: (out): return location for vertical alignment
2385  *
2386  * Gets the alignment of the child in the button.
2387  *
2388  * Since: 2.4
2389  */
2390 void
2391 gtk_button_get_alignment (GtkButton *button,
2392                           gfloat    *xalign,
2393                           gfloat    *yalign)
2394 {
2395   GtkButtonPrivate *priv;
2396
2397   g_return_if_fail (GTK_IS_BUTTON (button));
2398   
2399   priv = button->priv;
2400  
2401   if (xalign) 
2402     *xalign = priv->xalign;
2403
2404   if (yalign)
2405     *yalign = priv->yalign;
2406 }
2407
2408 /**
2409  * _gtk_button_set_depressed:
2410  * @button: a #GtkButton
2411  * @depressed: %TRUE if the button should be drawn with a recessed shadow.
2412  *
2413  * Sets whether the button is currently drawn as down or not. This is 
2414  * purely a visual setting, and is meant only for use by derived widgets
2415  * such as #GtkToggleButton.
2416  **/
2417 void
2418 _gtk_button_set_depressed (GtkButton *button,
2419                            gboolean   depressed)
2420 {
2421   GtkWidget *widget = GTK_WIDGET (button);
2422   GtkButtonPrivate *priv = button->priv;
2423
2424   depressed = depressed != FALSE;
2425
2426   if (depressed != priv->depressed)
2427     {
2428       priv->depressed = depressed;
2429       gtk_widget_queue_resize (widget);
2430     }
2431 }
2432
2433 static void
2434 gtk_button_update_state (GtkButton *button)
2435 {
2436   GtkButtonPrivate *priv = button->priv;
2437   GtkStateFlags new_state;
2438   gboolean depressed;
2439
2440   if (priv->activate_timeout)
2441     depressed = priv->depress_on_activate;
2442   else
2443     depressed = priv->in_button && priv->button_down;
2444
2445   new_state = gtk_widget_get_state_flags (GTK_WIDGET (button)) &
2446     ~(GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_ACTIVE);
2447
2448   if (priv->in_button)
2449     new_state |= GTK_STATE_FLAG_PRELIGHT;
2450
2451   if (depressed)
2452     new_state |= GTK_STATE_FLAG_ACTIVE;
2453
2454   _gtk_button_set_depressed (button, depressed);
2455   gtk_widget_set_state_flags (GTK_WIDGET (button), new_state, TRUE);
2456 }
2457
2458 static void 
2459 show_image_change_notify (GtkButton *button)
2460 {
2461   GtkButtonPrivate *priv = button->priv;
2462
2463   if (priv->image) 
2464     {
2465       if (show_image (button))
2466         gtk_widget_show (priv->image);
2467       else
2468         gtk_widget_hide (priv->image);
2469     }
2470 }
2471
2472 static void
2473 traverse_container (GtkWidget *widget,
2474                     gpointer   data)
2475 {
2476   if (GTK_IS_BUTTON (widget))
2477     show_image_change_notify (GTK_BUTTON (widget));
2478   else if (GTK_IS_CONTAINER (widget))
2479     gtk_container_forall (GTK_CONTAINER (widget), traverse_container, NULL);
2480 }
2481
2482 static void
2483 gtk_button_setting_changed (GtkSettings *settings)
2484 {
2485   GList *list, *l;
2486
2487   list = gtk_window_list_toplevels ();
2488
2489   for (l = list; l; l = l->next)
2490     gtk_container_forall (GTK_CONTAINER (l->data), 
2491                           traverse_container, NULL);
2492
2493   g_list_free (list);
2494 }
2495
2496
2497 static void
2498 gtk_button_screen_changed (GtkWidget *widget,
2499                            GdkScreen *previous_screen)
2500 {
2501   GtkButton *button;
2502   GtkButtonPrivate *priv;
2503   GtkSettings *settings;
2504   gulong show_image_connection;
2505
2506   if (!gtk_widget_has_screen (widget))
2507     return;
2508
2509   button = GTK_BUTTON (widget);
2510   priv = button->priv;
2511
2512   /* If the button is being pressed while the screen changes the
2513     release might never occur, so we reset the state. */
2514   if (priv->button_down)
2515     {
2516       priv->button_down = FALSE;
2517       gtk_button_update_state (button);
2518     }
2519
2520   settings = gtk_widget_get_settings (widget);
2521
2522   show_image_connection = 
2523     g_signal_handler_find (settings, G_SIGNAL_MATCH_FUNC, 0, 0,
2524                            NULL, gtk_button_setting_changed, NULL);
2525   
2526   if (show_image_connection)
2527     return;
2528
2529   g_signal_connect (settings, "notify::gtk-button-images",
2530                     G_CALLBACK (gtk_button_setting_changed), NULL);
2531
2532   show_image_change_notify (button);
2533 }
2534
2535 static void
2536 gtk_button_state_changed (GtkWidget    *widget,
2537                           GtkStateType  previous_state)
2538 {
2539   GtkButton *button = GTK_BUTTON (widget);
2540   GtkButtonPrivate *priv = button->priv;
2541
2542   if (!gtk_widget_is_sensitive (widget))
2543     {
2544       priv->in_button = FALSE;
2545       gtk_real_button_released (button);
2546     }
2547 }
2548
2549 static void
2550 gtk_button_grab_notify (GtkWidget *widget,
2551                         gboolean   was_grabbed)
2552 {
2553   GtkButton *button = GTK_BUTTON (widget);
2554   GtkButtonPrivate *priv = button->priv;
2555   gboolean save_in;
2556
2557   if (priv->activate_timeout &&
2558       priv->grab_keyboard &&
2559       gtk_widget_device_is_shadowed (widget, priv->grab_keyboard))
2560     gtk_button_finish_activate (button, FALSE);
2561
2562   if (!was_grabbed)
2563     {
2564       save_in = priv->in_button;
2565       priv->in_button = FALSE;
2566       gtk_real_button_released (button);
2567       if (save_in != priv->in_button)
2568         {
2569           priv->in_button = save_in;
2570           gtk_button_update_state (button);
2571         }
2572     }
2573 }
2574
2575 /**
2576  * gtk_button_set_image:
2577  * @button: a #GtkButton
2578  * @image: a widget to set as the image for the button
2579  *
2580  * Set the image of @button to the given widget. Note that
2581  * it depends on the #GtkSettings:gtk-button-images setting whether the
2582  * image will be displayed or not, you don't have to call
2583  * gtk_widget_show() on @image yourself.
2584  *
2585  * Since: 2.6
2586  */ 
2587 void
2588 gtk_button_set_image (GtkButton *button,
2589                       GtkWidget *image)
2590 {
2591   GtkButtonPrivate *priv;
2592   GtkWidget *parent;
2593
2594   g_return_if_fail (GTK_IS_BUTTON (button));
2595   g_return_if_fail (image == NULL || GTK_IS_WIDGET (image));
2596
2597   priv = button->priv;
2598
2599   if (priv->image)
2600     {
2601       parent = gtk_widget_get_parent (priv->image);
2602       if (parent)
2603         gtk_container_remove (GTK_CONTAINER (parent), priv->image);
2604     }
2605
2606   priv->image = image;
2607   priv->image_is_stock = (image == NULL);
2608
2609   gtk_button_construct_child (button);
2610
2611   g_object_notify (G_OBJECT (button), "image");
2612 }
2613
2614 /**
2615  * gtk_button_get_image:
2616  * @button: a #GtkButton
2617  *
2618  * Gets the widget that is currenty set as the image of @button.
2619  * This may have been explicitly set by gtk_button_set_image()
2620  * or constructed by gtk_button_new_from_stock().
2621  *
2622  * Return value: (transfer none): a #GtkWidget or %NULL in case there is no image
2623  *
2624  * Since: 2.6
2625  */
2626 GtkWidget *
2627 gtk_button_get_image (GtkButton *button)
2628 {
2629   g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
2630   
2631   return button->priv->image;
2632 }
2633
2634 /**
2635  * gtk_button_set_image_position:
2636  * @button: a #GtkButton
2637  * @position: the position
2638  *
2639  * Sets the position of the image relative to the text 
2640  * inside the button.
2641  *
2642  * Since: 2.10
2643  */ 
2644 void
2645 gtk_button_set_image_position (GtkButton       *button,
2646                                GtkPositionType  position)
2647 {
2648   GtkButtonPrivate *priv;
2649
2650   g_return_if_fail (GTK_IS_BUTTON (button));
2651   g_return_if_fail (position >= GTK_POS_LEFT && position <= GTK_POS_BOTTOM);
2652   
2653   priv = button->priv;
2654
2655   if (priv->image_position != position)
2656     {
2657       priv->image_position = position;
2658
2659       gtk_button_construct_child (button);
2660
2661       g_object_notify (G_OBJECT (button), "image-position");
2662     }
2663 }
2664
2665 /**
2666  * gtk_button_get_image_position:
2667  * @button: a #GtkButton
2668  *
2669  * Gets the position of the image relative to the text 
2670  * inside the button.
2671  *
2672  * Return value: the position
2673  *
2674  * Since: 2.10
2675  */
2676 GtkPositionType
2677 gtk_button_get_image_position (GtkButton *button)
2678 {
2679   g_return_val_if_fail (GTK_IS_BUTTON (button), GTK_POS_LEFT);
2680   
2681   return button->priv->image_position;
2682 }
2683
2684 /**
2685  * gtk_button_set_always_show_image:
2686  * @button: a #GtkButton
2687  * @always_show: %TRUE if the menuitem should always show the image
2688  *
2689  * If %TRUE, the button will ignore the #GtkSettings:gtk-button-images
2690  * setting and always show the image, if available.
2691  *
2692  * Use this property if the button  would be useless or hard to use
2693  * without the image.
2694  *
2695  * Since: 3.6
2696  */
2697 void
2698 gtk_button_set_always_show_image (GtkButton *button,
2699                                   gboolean    always_show)
2700 {
2701   GtkButtonPrivate *priv;
2702
2703   g_return_if_fail (GTK_IS_BUTTON (button));
2704
2705   priv = button->priv;
2706
2707   if (priv->always_show_image != always_show)
2708     {
2709       priv->always_show_image = always_show;
2710
2711       if (priv->image)
2712         {
2713           if (show_image (button))
2714             gtk_widget_show (priv->image);
2715           else
2716             gtk_widget_hide (priv->image);
2717         }
2718
2719       g_object_notify (G_OBJECT (button), "always-show-image");
2720     }
2721 }
2722
2723 /**
2724  * gtk_button_get_always_show_image:
2725  * @button: a #GtkButton
2726  *
2727  * Returns whether the button will ignore the #GtkSettings:gtk-button-images
2728  * setting and always show the image, if available.
2729  *
2730  * Returns: %TRUE if the button will always show the image
2731  *
2732  * Since: 3.6
2733  */
2734 gboolean
2735 gtk_button_get_always_show_image (GtkButton *button)
2736 {
2737   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
2738
2739   return button->priv->always_show_image;
2740 }
2741
2742 /**
2743  * gtk_button_get_event_window:
2744  * @button: a #GtkButton
2745  *
2746  * Returns the button's event window if it is realized, %NULL otherwise.
2747  * This function should be rarely needed.
2748  *
2749  * Return value: (transfer none): @button's event window.
2750  *
2751  * Since: 2.22
2752  */
2753 GdkWindow*
2754 gtk_button_get_event_window (GtkButton *button)
2755 {
2756   g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
2757
2758   return button->priv->event_window;
2759 }