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