]> Pileus Git - ~andy/gtk/blob - gtk/gtkbutton.c
button: Remove _gtk_button_paint()
[~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 static gboolean
1681 gtk_button_draw (GtkWidget *widget,
1682                  cairo_t   *cr)
1683 {
1684   GtkButton *button = GTK_BUTTON (widget);
1685   GtkButtonPrivate *priv = button->priv;
1686   gint x, y;
1687   GtkBorder default_border;
1688   GtkBorder default_outside_border;
1689   gboolean interior_focus;
1690   gint focus_width;
1691   gint focus_pad;
1692   GtkAllocation allocation;
1693   GtkStyleContext *context;
1694   GtkStateFlags state;
1695   gboolean draw_focus;
1696   gint width, height;
1697
1698   context = gtk_widget_get_style_context (widget);
1699   state = gtk_style_context_get_state (context);
1700
1701   gtk_button_get_props (button, &default_border, &default_outside_border, NULL, NULL, &interior_focus);
1702   gtk_style_context_get_style (context,
1703                                "focus-line-width", &focus_width,
1704                                "focus-padding", &focus_pad,
1705                                NULL);
1706
1707   gtk_widget_get_allocation (widget, &allocation);
1708
1709   x = 0;
1710   y = 0;
1711   width = allocation.width;
1712   height = allocation.height;
1713
1714   if (gtk_widget_has_default (widget) &&
1715       priv->relief == GTK_RELIEF_NORMAL)
1716     {
1717       x += default_border.left;
1718       y += default_border.top;
1719       width -= default_border.left + default_border.right;
1720       height -= default_border.top + default_border.bottom;
1721     }
1722   else if (gtk_widget_get_can_default (widget))
1723     {
1724       x += default_outside_border.left;
1725       y += default_outside_border.top;
1726       width -= default_outside_border.left + default_outside_border.right;
1727       height -= default_outside_border.top + default_outside_border.bottom;
1728     }
1729
1730   draw_focus = gtk_widget_has_visible_focus (widget);
1731
1732
1733   if (!interior_focus && draw_focus)
1734     {
1735       x += focus_width + focus_pad;
1736       y += focus_width + focus_pad;
1737       width -= 2 * (focus_width + focus_pad);
1738       height -= 2 * (focus_width + focus_pad);
1739     }
1740
1741   if (priv->relief != GTK_RELIEF_NONE || priv->depressed ||
1742       state & GTK_STATE_FLAG_PRELIGHT)
1743     {
1744       gtk_render_background (context, cr,
1745                              x, y, width, height);
1746       gtk_render_frame (context, cr,
1747                         x, y, width, height);
1748     }
1749
1750   if (draw_focus)
1751     {
1752       gint child_displacement_x;
1753       gint child_displacement_y;
1754       gboolean displace_focus;
1755       GtkBorder border;
1756
1757       gtk_style_context_get_style (context,
1758                                    "child-displacement-y", &child_displacement_y,
1759                                    "child-displacement-x", &child_displacement_x,
1760                                    "displace-focus", &displace_focus,
1761                                    NULL);
1762       gtk_style_context_get_border (context, state, &border);
1763
1764       if (interior_focus)
1765         {
1766           x += border.left + focus_pad;
1767           y += border.top + focus_pad;
1768           width -= (2 * focus_pad) + border.left + border.right;
1769           height -=  (2 * focus_pad) + border.top + border.bottom;
1770         }
1771       else
1772         {
1773           x -= focus_width + focus_pad;
1774           y -= focus_width + focus_pad;
1775           width += 2 * (focus_width + focus_pad);
1776           height += 2 * (focus_width + focus_pad);
1777         }
1778
1779       if (priv->depressed && displace_focus)
1780         {
1781           x += child_displacement_x;
1782           y += child_displacement_y;
1783         }
1784
1785       gtk_render_focus (context, cr, x, y, width, height);
1786     }
1787
1788   GTK_WIDGET_CLASS (gtk_button_parent_class)->draw (widget, cr);
1789
1790   return FALSE;
1791 }
1792
1793 static gboolean
1794 gtk_button_button_press (GtkWidget      *widget,
1795                          GdkEventButton *event)
1796 {
1797   GtkButton *button;
1798   GtkButtonPrivate *priv;
1799
1800   if (event->type == GDK_BUTTON_PRESS)
1801     {
1802       button = GTK_BUTTON (widget);
1803       priv = button->priv;
1804
1805       if (priv->focus_on_click && !gtk_widget_has_focus (widget))
1806         gtk_widget_grab_focus (widget);
1807
1808       if (event->button == GDK_BUTTON_PRIMARY)
1809         g_signal_emit (button, button_signals[PRESSED], 0);
1810     }
1811
1812   return TRUE;
1813 }
1814
1815 static gboolean
1816 gtk_button_button_release (GtkWidget      *widget,
1817                            GdkEventButton *event)
1818 {
1819   GtkButton *button;
1820
1821   if (event->button == GDK_BUTTON_PRIMARY)
1822     {
1823       button = GTK_BUTTON (widget);
1824       g_signal_emit (button, button_signals[RELEASED], 0);
1825     }
1826
1827   return TRUE;
1828 }
1829
1830 static gboolean
1831 gtk_button_touch (GtkWidget     *widget,
1832                   GdkEventTouch *event)
1833 {
1834   GtkButton *button = GTK_BUTTON (widget);
1835   GtkButtonPrivate *priv = button->priv;
1836
1837   if (event->type == GDK_TOUCH_BEGIN)
1838     {
1839       if (priv->focus_on_click && !gtk_widget_has_focus (widget))
1840         gtk_widget_grab_focus (widget);
1841
1842       g_signal_emit (button, button_signals[PRESSED], 0);
1843     }
1844   else if (event->type == GDK_TOUCH_END)
1845     {
1846       g_signal_emit (button, button_signals[RELEASED], 0);
1847     }
1848
1849   return TRUE;
1850 }
1851
1852 static gboolean
1853 gtk_button_grab_broken (GtkWidget          *widget,
1854                         GdkEventGrabBroken *event)
1855 {
1856   GtkButton *button = GTK_BUTTON (widget);
1857   GtkButtonPrivate *priv = button->priv;
1858   gboolean save_in;
1859   
1860   /* Simulate a button release without the pointer in the button */
1861   if (priv->button_down)
1862     {
1863       save_in = priv->in_button;
1864       priv->in_button = FALSE;
1865       g_signal_emit (button, button_signals[RELEASED], 0);
1866       if (save_in != priv->in_button)
1867         {
1868           priv->in_button = save_in;
1869           gtk_button_update_state (button);
1870         }
1871     }
1872
1873   return TRUE;
1874 }
1875
1876 static gboolean
1877 gtk_button_key_release (GtkWidget   *widget,
1878                         GdkEventKey *event)
1879 {
1880   GtkButton *button = GTK_BUTTON (widget);
1881   GtkButtonPrivate *priv = button->priv;
1882
1883   if (priv->activate_timeout)
1884     {
1885       gtk_button_finish_activate (button, TRUE);
1886       return TRUE;
1887     }
1888   else if (GTK_WIDGET_CLASS (gtk_button_parent_class)->key_release_event)
1889     return GTK_WIDGET_CLASS (gtk_button_parent_class)->key_release_event (widget, event);
1890   else
1891     return FALSE;
1892 }
1893
1894 static gboolean
1895 gtk_button_enter_notify (GtkWidget        *widget,
1896                          GdkEventCrossing *event)
1897 {
1898   GtkButton *button = GTK_BUTTON (widget);
1899   GtkButtonPrivate *priv = button->priv;
1900
1901   if ((event->window == button->priv->event_window) &&
1902       (event->detail != GDK_NOTIFY_INFERIOR))
1903     {
1904       priv->in_button = TRUE;
1905       g_signal_emit (button, button_signals[ENTER], 0);
1906     }
1907
1908   return FALSE;
1909 }
1910
1911 static gboolean
1912 gtk_button_leave_notify (GtkWidget        *widget,
1913                          GdkEventCrossing *event)
1914 {
1915   GtkButton *button = GTK_BUTTON (widget);
1916   GtkButtonPrivate *priv = button->priv;
1917
1918   if ((event->window == button->priv->event_window) &&
1919       (event->detail != GDK_NOTIFY_INFERIOR) &&
1920       (gtk_widget_get_sensitive (widget)))
1921     {
1922       priv->in_button = FALSE;
1923       g_signal_emit (button, button_signals[LEAVE], 0);
1924     }
1925
1926   return FALSE;
1927 }
1928
1929 static void
1930 gtk_real_button_pressed (GtkButton *button)
1931 {
1932   GtkButtonPrivate *priv = button->priv;
1933
1934   if (priv->activate_timeout)
1935     return;
1936
1937   priv->button_down = TRUE;
1938   gtk_button_update_state (button);
1939 }
1940
1941 static gboolean
1942 touch_release_in_button (GtkButton *button)
1943 {
1944   GtkButtonPrivate *priv;
1945   gint width, height;
1946   GdkEvent *event;
1947   gdouble x, y;
1948
1949   priv = button->priv;
1950   event = gtk_get_current_event ();
1951
1952   if (!event)
1953     return FALSE;
1954
1955   if (event->type != GDK_TOUCH_END ||
1956       event->touch.window != priv->event_window)
1957     {
1958       gdk_event_free (event);
1959       return FALSE;
1960     }
1961
1962   gdk_event_get_coords (event, &x, &y);
1963   width = gdk_window_get_width (priv->event_window);
1964   height = gdk_window_get_height (priv->event_window);
1965
1966   gdk_event_free (event);
1967
1968   if (x >= 0 && x <= width &&
1969       y >= 0 && y <= height)
1970     return TRUE;
1971
1972   return FALSE;
1973 }
1974
1975 static void
1976 gtk_real_button_released (GtkButton *button)
1977 {
1978   GtkButtonPrivate *priv = button->priv;
1979
1980   if (priv->button_down)
1981     {
1982       priv->button_down = FALSE;
1983
1984       if (priv->activate_timeout)
1985         return;
1986
1987       if (priv->in_button ||
1988           touch_release_in_button (button))
1989         gtk_button_clicked (button);
1990
1991       gtk_button_update_state (button);
1992     }
1993 }
1994
1995 static void 
1996 gtk_real_button_clicked (GtkButton *button)
1997 {
1998   GtkButtonPrivate *priv = button->priv;
1999
2000   if (priv->action_observer)
2001     g_simple_action_observer_activate (priv->action_observer);
2002
2003   if (priv->action)
2004     gtk_action_activate (priv->action);
2005 }
2006
2007 static gboolean
2008 button_activate_timeout (gpointer data)
2009 {
2010   gtk_button_finish_activate (data, TRUE);
2011
2012   return FALSE;
2013 }
2014
2015 static void
2016 gtk_real_button_activate (GtkButton *button)
2017 {
2018   GtkWidget *widget = GTK_WIDGET (button);
2019   GtkButtonPrivate *priv = button->priv;
2020   GdkDevice *device;
2021   guint32 time;
2022
2023   device = gtk_get_current_event_device ();
2024
2025   if (device && gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
2026     device = gdk_device_get_associated_device (device);
2027
2028   if (gtk_widget_get_realized (widget) && !priv->activate_timeout)
2029     {
2030       time = gtk_get_current_event_time ();
2031
2032       /* bgo#626336 - Only grab if we have a device (from an event), not if we
2033        * were activated programmatically when no event is available.
2034        */
2035       if (device && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
2036         {
2037           if (gdk_device_grab (device, priv->event_window,
2038                                GDK_OWNERSHIP_WINDOW, TRUE,
2039                                GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
2040                                NULL, time) == GDK_GRAB_SUCCESS)
2041             {
2042               gtk_device_grab_add (widget, device, TRUE);
2043               priv->grab_keyboard = device;
2044               priv->grab_time = time;
2045             }
2046         }
2047
2048       priv->activate_timeout = gdk_threads_add_timeout (ACTIVATE_TIMEOUT,
2049                                                 button_activate_timeout,
2050                                                 button);
2051       priv->button_down = TRUE;
2052       gtk_button_update_state (button);
2053       gtk_widget_queue_draw (GTK_WIDGET (button));
2054     }
2055 }
2056
2057 static void
2058 gtk_button_finish_activate (GtkButton *button,
2059                             gboolean   do_it)
2060 {
2061   GtkWidget *widget = GTK_WIDGET (button);
2062   GtkButtonPrivate *priv = button->priv;
2063
2064   g_source_remove (priv->activate_timeout);
2065   priv->activate_timeout = 0;
2066
2067   if (priv->grab_keyboard)
2068     {
2069       gdk_device_ungrab (priv->grab_keyboard, priv->grab_time);
2070       gtk_device_grab_remove (widget, priv->grab_keyboard);
2071       priv->grab_keyboard = NULL;
2072     }
2073
2074   priv->button_down = FALSE;
2075
2076   gtk_button_update_state (button);
2077   gtk_widget_queue_draw (GTK_WIDGET (button));
2078
2079   if (do_it)
2080     gtk_button_clicked (button);
2081 }
2082
2083
2084 static void
2085 gtk_button_get_size (GtkWidget      *widget,
2086                      GtkOrientation  orientation,
2087                      gint           *minimum_size,
2088                      gint           *natural_size)
2089 {
2090   GtkButton *button = GTK_BUTTON (widget);
2091   GtkStyleContext *context;
2092   GtkWidget *child;
2093   GtkBorder default_border;
2094   GtkBorder padding;
2095   GtkBorder border;
2096   gint focus_width;
2097   gint focus_pad;
2098   gint minimum, natural;
2099
2100   context = gtk_widget_get_style_context (widget);
2101
2102   gtk_button_get_props (button, &default_border, NULL,
2103                         &padding, &border, NULL);
2104   gtk_style_context_get_style (context,
2105                                "focus-line-width", &focus_width,
2106                                "focus-padding", &focus_pad,
2107                                NULL);
2108
2109   if (orientation == GTK_ORIENTATION_HORIZONTAL)
2110     {
2111       minimum = padding.left + padding.right +
2112         border.left + border.right;
2113
2114       if (gtk_widget_get_can_default (GTK_WIDGET (widget)))
2115         minimum += default_border.left + default_border.right;
2116     }
2117   else
2118     {
2119       minimum = padding.top + padding.bottom +
2120         border.top + border.bottom;
2121
2122       if (gtk_widget_get_can_default (GTK_WIDGET (widget)))
2123         minimum += default_border.top + default_border.bottom;
2124     }  
2125
2126   minimum += 2 * (focus_width + focus_pad);
2127   natural = minimum;
2128
2129   if ((child = gtk_bin_get_child (GTK_BIN (button))) && 
2130       gtk_widget_get_visible (child))
2131     {
2132       gint child_min, child_nat;
2133
2134       if (orientation == GTK_ORIENTATION_HORIZONTAL)
2135         gtk_widget_get_preferred_width (child, &child_min, &child_nat);
2136       else
2137         gtk_widget_get_preferred_height (child, &child_min, &child_nat);
2138
2139       minimum += child_min;
2140       natural += child_nat;
2141     }
2142
2143   if (minimum_size)
2144     *minimum_size = minimum;
2145
2146   if (natural_size)
2147     *natural_size = natural;
2148 }
2149
2150 static void 
2151 gtk_button_get_preferred_width (GtkWidget *widget,
2152                                 gint      *minimum_size,
2153                                 gint      *natural_size)
2154 {
2155   gtk_button_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
2156 }
2157
2158 static void 
2159 gtk_button_get_preferred_height (GtkWidget *widget,
2160                                  gint      *minimum_size,
2161                                  gint      *natural_size)
2162 {
2163   gtk_button_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
2164 }
2165
2166 /**
2167  * gtk_button_set_label:
2168  * @button: a #GtkButton
2169  * @label: a string
2170  *
2171  * Sets the text of the label of the button to @str. This text is
2172  * also used to select the stock item if gtk_button_set_use_stock()
2173  * is used.
2174  *
2175  * This will also clear any previously set labels.
2176  **/
2177 void
2178 gtk_button_set_label (GtkButton   *button,
2179                       const gchar *label)
2180 {
2181   GtkButtonPrivate *priv;
2182   gchar *new_label;
2183
2184   g_return_if_fail (GTK_IS_BUTTON (button));
2185
2186   priv = button->priv;
2187
2188   new_label = g_strdup (label);
2189   g_free (priv->label_text);
2190   priv->label_text = new_label;
2191
2192   gtk_button_construct_child (button);
2193   
2194   g_object_notify (G_OBJECT (button), "label");
2195 }
2196
2197 /**
2198  * gtk_button_get_label:
2199  * @button: a #GtkButton
2200  *
2201  * Fetches the text from the label of the button, as set by
2202  * gtk_button_set_label(). If the label text has not 
2203  * been set the return value will be %NULL. This will be the 
2204  * case if you create an empty button with gtk_button_new() to 
2205  * use as a container.
2206  *
2207  * Return value: The text of the label widget. This string is owned
2208  * by the widget and must not be modified or freed.
2209  **/
2210 const gchar *
2211 gtk_button_get_label (GtkButton *button)
2212 {
2213   g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
2214
2215   return button->priv->label_text;
2216 }
2217
2218 /**
2219  * gtk_button_set_use_underline:
2220  * @button: a #GtkButton
2221  * @use_underline: %TRUE if underlines in the text indicate mnemonics
2222  *
2223  * If true, an underline in the text of the button label indicates
2224  * the next character should be used for the mnemonic accelerator key.
2225  */
2226 void
2227 gtk_button_set_use_underline (GtkButton *button,
2228                               gboolean   use_underline)
2229 {
2230   GtkButtonPrivate *priv;
2231
2232   g_return_if_fail (GTK_IS_BUTTON (button));
2233
2234   priv = button->priv;
2235
2236   use_underline = use_underline != FALSE;
2237
2238   if (use_underline != priv->use_underline)
2239     {
2240       priv->use_underline = use_underline;
2241
2242       gtk_button_construct_child (button);
2243       
2244       g_object_notify (G_OBJECT (button), "use-underline");
2245     }
2246 }
2247
2248 /**
2249  * gtk_button_get_use_underline:
2250  * @button: a #GtkButton
2251  *
2252  * Returns whether an embedded underline in the button label indicates a
2253  * mnemonic. See gtk_button_set_use_underline ().
2254  *
2255  * Return value: %TRUE if an embedded underline in the button label
2256  *               indicates the mnemonic accelerator keys.
2257  **/
2258 gboolean
2259 gtk_button_get_use_underline (GtkButton *button)
2260 {
2261   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
2262
2263   return button->priv->use_underline;
2264 }
2265
2266 /**
2267  * gtk_button_set_use_stock:
2268  * @button: a #GtkButton
2269  * @use_stock: %TRUE if the button should use a stock item
2270  *
2271  * If %TRUE, the label set on the button is used as a
2272  * stock id to select the stock item for the button.
2273  */
2274 void
2275 gtk_button_set_use_stock (GtkButton *button,
2276                           gboolean   use_stock)
2277 {
2278   GtkButtonPrivate *priv;
2279
2280   g_return_if_fail (GTK_IS_BUTTON (button));
2281
2282   priv = button->priv;
2283
2284   use_stock = use_stock != FALSE;
2285
2286   if (use_stock != priv->use_stock)
2287     {
2288       priv->use_stock = use_stock;
2289
2290       gtk_button_construct_child (button);
2291       
2292       g_object_notify (G_OBJECT (button), "use-stock");
2293     }
2294 }
2295
2296 /**
2297  * gtk_button_get_use_stock:
2298  * @button: a #GtkButton
2299  *
2300  * Returns whether the button label is a stock item.
2301  *
2302  * Return value: %TRUE if the button label is used to
2303  *               select a stock item instead of being
2304  *               used directly as the label text.
2305  */
2306 gboolean
2307 gtk_button_get_use_stock (GtkButton *button)
2308 {
2309   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
2310
2311   return button->priv->use_stock;
2312 }
2313
2314 /**
2315  * gtk_button_set_focus_on_click:
2316  * @button: a #GtkButton
2317  * @focus_on_click: whether the button grabs focus when clicked with the mouse
2318  *
2319  * Sets whether the button will grab focus when it is clicked with the mouse.
2320  * Making mouse clicks not grab focus is useful in places like toolbars where
2321  * you don't want the keyboard focus removed from the main area of the
2322  * application.
2323  *
2324  * Since: 2.4
2325  **/
2326 void
2327 gtk_button_set_focus_on_click (GtkButton *button,
2328                                gboolean   focus_on_click)
2329 {
2330   GtkButtonPrivate *priv;
2331
2332   g_return_if_fail (GTK_IS_BUTTON (button));
2333
2334   priv = button->priv;
2335
2336   focus_on_click = focus_on_click != FALSE;
2337
2338   if (priv->focus_on_click != focus_on_click)
2339     {
2340       priv->focus_on_click = focus_on_click;
2341       
2342       g_object_notify (G_OBJECT (button), "focus-on-click");
2343     }
2344 }
2345
2346 /**
2347  * gtk_button_get_focus_on_click:
2348  * @button: a #GtkButton
2349  *
2350  * Returns whether the button grabs focus when it is clicked with the mouse.
2351  * See gtk_button_set_focus_on_click().
2352  *
2353  * Return value: %TRUE if the button grabs focus when it is clicked with
2354  *               the mouse.
2355  *
2356  * Since: 2.4
2357  **/
2358 gboolean
2359 gtk_button_get_focus_on_click (GtkButton *button)
2360 {
2361   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
2362   
2363   return button->priv->focus_on_click;
2364 }
2365
2366 /**
2367  * gtk_button_set_alignment:
2368  * @button: a #GtkButton
2369  * @xalign: the horizontal position of the child, 0.0 is left aligned, 
2370  *   1.0 is right aligned
2371  * @yalign: the vertical position of the child, 0.0 is top aligned, 
2372  *   1.0 is bottom aligned
2373  *
2374  * Sets the alignment of the child. This property has no effect unless 
2375  * the child is a #GtkMisc or a #GtkAlignment.
2376  *
2377  * Since: 2.4
2378  */
2379 void
2380 gtk_button_set_alignment (GtkButton *button,
2381                           gfloat     xalign,
2382                           gfloat     yalign)
2383 {
2384   GtkButtonPrivate *priv;
2385
2386   g_return_if_fail (GTK_IS_BUTTON (button));
2387   
2388   priv = button->priv;
2389
2390   priv->xalign = xalign;
2391   priv->yalign = yalign;
2392   priv->align_set = 1;
2393
2394   maybe_set_alignment (button, gtk_bin_get_child (GTK_BIN (button)));
2395
2396   g_object_freeze_notify (G_OBJECT (button));
2397   g_object_notify (G_OBJECT (button), "xalign");
2398   g_object_notify (G_OBJECT (button), "yalign");
2399   g_object_thaw_notify (G_OBJECT (button));
2400 }
2401
2402 /**
2403  * gtk_button_get_alignment:
2404  * @button: a #GtkButton
2405  * @xalign: (out): return location for horizontal alignment
2406  * @yalign: (out): return location for vertical alignment
2407  *
2408  * Gets the alignment of the child in the button.
2409  *
2410  * Since: 2.4
2411  */
2412 void
2413 gtk_button_get_alignment (GtkButton *button,
2414                           gfloat    *xalign,
2415                           gfloat    *yalign)
2416 {
2417   GtkButtonPrivate *priv;
2418
2419   g_return_if_fail (GTK_IS_BUTTON (button));
2420   
2421   priv = button->priv;
2422  
2423   if (xalign) 
2424     *xalign = priv->xalign;
2425
2426   if (yalign)
2427     *yalign = priv->yalign;
2428 }
2429
2430 /**
2431  * _gtk_button_set_depressed:
2432  * @button: a #GtkButton
2433  * @depressed: %TRUE if the button should be drawn with a recessed shadow.
2434  *
2435  * Sets whether the button is currently drawn as down or not. This is 
2436  * purely a visual setting, and is meant only for use by derived widgets
2437  * such as #GtkToggleButton.
2438  **/
2439 void
2440 _gtk_button_set_depressed (GtkButton *button,
2441                            gboolean   depressed)
2442 {
2443   GtkWidget *widget = GTK_WIDGET (button);
2444   GtkButtonPrivate *priv = button->priv;
2445
2446   depressed = depressed != FALSE;
2447
2448   if (depressed != priv->depressed)
2449     {
2450       priv->depressed = depressed;
2451       gtk_widget_queue_resize (widget);
2452     }
2453 }
2454
2455 static void
2456 gtk_button_update_state (GtkButton *button)
2457 {
2458   GtkButtonPrivate *priv = button->priv;
2459   GtkStateFlags new_state;
2460   gboolean depressed;
2461
2462   if (priv->activate_timeout)
2463     depressed = priv->depress_on_activate;
2464   else
2465     depressed = priv->in_button && priv->button_down;
2466
2467   new_state = gtk_widget_get_state_flags (GTK_WIDGET (button)) &
2468     ~(GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_ACTIVE);
2469
2470   if (priv->in_button)
2471     new_state |= GTK_STATE_FLAG_PRELIGHT;
2472
2473   if (depressed)
2474     new_state |= GTK_STATE_FLAG_ACTIVE;
2475
2476   _gtk_button_set_depressed (button, depressed);
2477   gtk_widget_set_state_flags (GTK_WIDGET (button), new_state, TRUE);
2478 }
2479
2480 static void 
2481 show_image_change_notify (GtkButton *button)
2482 {
2483   GtkButtonPrivate *priv = button->priv;
2484
2485   if (priv->image) 
2486     {
2487       if (show_image (button))
2488         gtk_widget_show (priv->image);
2489       else
2490         gtk_widget_hide (priv->image);
2491     }
2492 }
2493
2494 static void
2495 traverse_container (GtkWidget *widget,
2496                     gpointer   data)
2497 {
2498   if (GTK_IS_BUTTON (widget))
2499     show_image_change_notify (GTK_BUTTON (widget));
2500   else if (GTK_IS_CONTAINER (widget))
2501     gtk_container_forall (GTK_CONTAINER (widget), traverse_container, NULL);
2502 }
2503
2504 static void
2505 gtk_button_setting_changed (GtkSettings *settings)
2506 {
2507   GList *list, *l;
2508
2509   list = gtk_window_list_toplevels ();
2510
2511   for (l = list; l; l = l->next)
2512     gtk_container_forall (GTK_CONTAINER (l->data), 
2513                           traverse_container, NULL);
2514
2515   g_list_free (list);
2516 }
2517
2518
2519 static void
2520 gtk_button_screen_changed (GtkWidget *widget,
2521                            GdkScreen *previous_screen)
2522 {
2523   GtkButton *button;
2524   GtkButtonPrivate *priv;
2525   GtkSettings *settings;
2526   gulong show_image_connection;
2527
2528   if (!gtk_widget_has_screen (widget))
2529     return;
2530
2531   button = GTK_BUTTON (widget);
2532   priv = button->priv;
2533
2534   /* If the button is being pressed while the screen changes the
2535     release might never occur, so we reset the state. */
2536   if (priv->button_down)
2537     {
2538       priv->button_down = FALSE;
2539       gtk_button_update_state (button);
2540     }
2541
2542   settings = gtk_widget_get_settings (widget);
2543
2544   show_image_connection = 
2545     g_signal_handler_find (settings, G_SIGNAL_MATCH_FUNC, 0, 0,
2546                            NULL, gtk_button_setting_changed, NULL);
2547   
2548   if (show_image_connection)
2549     return;
2550
2551   g_signal_connect (settings, "notify::gtk-button-images",
2552                     G_CALLBACK (gtk_button_setting_changed), NULL);
2553
2554   show_image_change_notify (button);
2555 }
2556
2557 static void
2558 gtk_button_state_changed (GtkWidget    *widget,
2559                           GtkStateType  previous_state)
2560 {
2561   GtkButton *button = GTK_BUTTON (widget);
2562   GtkButtonPrivate *priv = button->priv;
2563
2564   if (!gtk_widget_is_sensitive (widget))
2565     {
2566       priv->in_button = FALSE;
2567       gtk_real_button_released (button);
2568     }
2569 }
2570
2571 static void
2572 gtk_button_grab_notify (GtkWidget *widget,
2573                         gboolean   was_grabbed)
2574 {
2575   GtkButton *button = GTK_BUTTON (widget);
2576   GtkButtonPrivate *priv = button->priv;
2577   gboolean save_in;
2578
2579   if (priv->activate_timeout &&
2580       priv->grab_keyboard &&
2581       gtk_widget_device_is_shadowed (widget, priv->grab_keyboard))
2582     gtk_button_finish_activate (button, FALSE);
2583
2584   if (!was_grabbed)
2585     {
2586       save_in = priv->in_button;
2587       priv->in_button = FALSE;
2588       gtk_real_button_released (button);
2589       if (save_in != priv->in_button)
2590         {
2591           priv->in_button = save_in;
2592           gtk_button_update_state (button);
2593         }
2594     }
2595 }
2596
2597 static void
2598 gtk_button_hierarchy_changed (GtkWidget *widget,
2599                               GtkWidget *previous_toplevel)
2600 {
2601   GtkButton *button = GTK_BUTTON (widget);
2602   GtkWidgetClass *parent_class;
2603
2604   parent_class = GTK_WIDGET_CLASS (gtk_button_parent_class);
2605   if (parent_class->hierarchy_changed)
2606     parent_class->hierarchy_changed (widget, previous_toplevel);
2607
2608   if (button->priv->action_name)
2609     {
2610       GtkWidget *toplevel;
2611
2612       toplevel = gtk_widget_get_toplevel (widget);
2613
2614       if (toplevel != previous_toplevel)
2615         gtk_button_update_action_observer (button);
2616     }
2617 }
2618
2619 /**
2620  * gtk_button_set_image:
2621  * @button: a #GtkButton
2622  * @image: a widget to set as the image for the button
2623  *
2624  * Set the image of @button to the given widget. Note that
2625  * it depends on the #GtkSettings:gtk-button-images setting whether the
2626  * image will be displayed or not, you don't have to call
2627  * gtk_widget_show() on @image yourself.
2628  *
2629  * Since: 2.6
2630  */ 
2631 void
2632 gtk_button_set_image (GtkButton *button,
2633                       GtkWidget *image)
2634 {
2635   GtkButtonPrivate *priv;
2636   GtkWidget *parent;
2637
2638   g_return_if_fail (GTK_IS_BUTTON (button));
2639   g_return_if_fail (image == NULL || GTK_IS_WIDGET (image));
2640
2641   priv = button->priv;
2642
2643   if (priv->image)
2644     {
2645       parent = gtk_widget_get_parent (priv->image);
2646       if (parent)
2647         gtk_container_remove (GTK_CONTAINER (parent), priv->image);
2648     }
2649
2650   priv->image = image;
2651   priv->image_is_stock = (image == NULL);
2652
2653   gtk_button_construct_child (button);
2654
2655   g_object_notify (G_OBJECT (button), "image");
2656 }
2657
2658 /**
2659  * gtk_button_get_image:
2660  * @button: a #GtkButton
2661  *
2662  * Gets the widget that is currenty set as the image of @button.
2663  * This may have been explicitly set by gtk_button_set_image()
2664  * or constructed by gtk_button_new_from_stock().
2665  *
2666  * Return value: (transfer none): a #GtkWidget or %NULL in case there is no image
2667  *
2668  * Since: 2.6
2669  */
2670 GtkWidget *
2671 gtk_button_get_image (GtkButton *button)
2672 {
2673   g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
2674   
2675   return button->priv->image;
2676 }
2677
2678 /**
2679  * gtk_button_set_image_position:
2680  * @button: a #GtkButton
2681  * @position: the position
2682  *
2683  * Sets the position of the image relative to the text 
2684  * inside the button.
2685  *
2686  * Since: 2.10
2687  */ 
2688 void
2689 gtk_button_set_image_position (GtkButton       *button,
2690                                GtkPositionType  position)
2691 {
2692   GtkButtonPrivate *priv;
2693
2694   g_return_if_fail (GTK_IS_BUTTON (button));
2695   g_return_if_fail (position >= GTK_POS_LEFT && position <= GTK_POS_BOTTOM);
2696   
2697   priv = button->priv;
2698
2699   if (priv->image_position != position)
2700     {
2701       priv->image_position = position;
2702
2703       gtk_button_construct_child (button);
2704
2705       g_object_notify (G_OBJECT (button), "image-position");
2706     }
2707 }
2708
2709 /**
2710  * gtk_button_get_image_position:
2711  * @button: a #GtkButton
2712  *
2713  * Gets the position of the image relative to the text 
2714  * inside the button.
2715  *
2716  * Return value: the position
2717  *
2718  * Since: 2.10
2719  */
2720 GtkPositionType
2721 gtk_button_get_image_position (GtkButton *button)
2722 {
2723   g_return_val_if_fail (GTK_IS_BUTTON (button), GTK_POS_LEFT);
2724   
2725   return button->priv->image_position;
2726 }
2727
2728 /**
2729  * gtk_button_get_event_window:
2730  * @button: a #GtkButton
2731  *
2732  * Returns the button's event window if it is realized, %NULL otherwise.
2733  * This function should be rarely needed.
2734  *
2735  * Return value: (transfer none): @button's event window.
2736  *
2737  * Since: 2.22
2738  */
2739 GdkWindow*
2740 gtk_button_get_event_window (GtkButton *button)
2741 {
2742   g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
2743
2744   return button->priv->event_window;
2745 }