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