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