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