gtkbutton.c 78.2 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
Elliot Lee's avatar
Elliot Lee committed
2 3 4
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
6 7 8 9 10 11
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
16
 */
17 18

/*
19
 * Modified by the GTK+ Team and others 1997-2001.  See the AUTHORS
20 21 22 23 24
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

25 26
/**
 * SECTION:gtkbutton
27
 * @Short_description: A widget that emits a signal when clicked on
28 29
 * @Title: GtkButton
 *
30
 * The #GtkButton widget is generally used to trigger a callback function that is
31 32 33
 * called when the button is pressed.  The various signals and how to use them
 * are outlined below.
 *
34 35
 * The #GtkButton widget can hold any valid child widget.  That is, it can hold
 * almost any other standard #GtkWidget.  The most commonly used child is the
36 37 38
 * #GtkLabel.
 */

39
#include "config.h"
40 41 42 43

#include "gtkbutton.h"
#include "gtkbuttonprivate.h"

44
#include <string.h>
45
#include "gtkalignment.h"
Elliot Lee's avatar
Elliot Lee committed
46 47
#include "gtklabel.h"
#include "gtkmain.h"
48
#include "gtkmarshalers.h"
49
#include "gtkimage.h"
50
#include "gtkbox.h"
51 52
#include "gtkstock.h"
#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 60
#include "gtkapplicationprivate.h"
#include "gtkactionable.h"
Elliot Lee's avatar
Elliot Lee committed
61

62 63
static const GtkBorder default_default_border = { 1, 1, 1, 1 };
static const GtkBorder default_default_outside_border = { 0, 0, 0, 0 };
Elliot Lee's avatar
Elliot Lee committed
64

Matthias Clasen's avatar
Matthias Clasen committed
65
/* Time out before giving up on getting a key release when animating
66 67 68
 * the close button.
 */
#define ACTIVATE_TIMEOUT 250
Elliot Lee's avatar
Elliot Lee committed
69

70

Elliot Lee's avatar
Elliot Lee committed
71 72 73 74 75 76
enum {
  PRESSED,
  RELEASED,
  CLICKED,
  ENTER,
  LEAVE,
77
  ACTIVATE,
Elliot Lee's avatar
Elliot Lee committed
78 79
  LAST_SIGNAL
};
80

81
enum {
82 83
  PROP_0,
  PROP_LABEL,
84
  PROP_IMAGE,
85 86
  PROP_RELIEF,
  PROP_USE_UNDERLINE,
87
  PROP_USE_STOCK,
88 89
  PROP_FOCUS_ON_CLICK,
  PROP_XALIGN,
90
  PROP_YALIGN,
91
  PROP_IMAGE_POSITION,
92 93
  PROP_ACTION_NAME,
  PROP_ACTION_TARGET,
94 95 96 97

  /* activatable properties */
  PROP_ACTIVATABLE_RELATED_ACTION,
  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 104 105 106 107 108 109 110 111 112
static void gtk_button_set_property   (GObject            *object,
                                       guint               prop_id,
                                       const GValue       *value,
                                       GParamSpec         *pspec);
static void gtk_button_get_property   (GObject            *object,
                                       guint               prop_id,
                                       GValue             *value,
                                       GParamSpec         *pspec);
static void gtk_button_screen_changed (GtkWidget          *widget,
				       GdkScreen          *previous_screen);
113 114 115 116
static void gtk_button_realize (GtkWidget * widget);
static void gtk_button_unrealize (GtkWidget * widget);
static void gtk_button_map (GtkWidget * widget);
static void gtk_button_unmap (GtkWidget * widget);
117
static void gtk_button_style_updated (GtkWidget * widget);
118 119
static void gtk_button_size_allocate (GtkWidget * widget,
				      GtkAllocation * allocation);
120
static gint gtk_button_draw (GtkWidget * widget, cairo_t *cr);
121 122 123 124
static gint gtk_button_button_press (GtkWidget * widget,
				     GdkEventButton * event);
static gint gtk_button_button_release (GtkWidget * widget,
				       GdkEventButton * event);
125 126
static gboolean gtk_button_touch (GtkWidget     *widget,
                                  GdkEventTouch *event);
127 128 129 130 131 132 133 134 135 136
static gint gtk_button_grab_broken (GtkWidget * widget,
				    GdkEventGrabBroken * event);
static gint gtk_button_key_release (GtkWidget * widget, GdkEventKey * event);
static gint gtk_button_enter_notify (GtkWidget * widget,
				     GdkEventCrossing * event);
static gint gtk_button_leave_notify (GtkWidget * widget,
				     GdkEventCrossing * event);
static void gtk_real_button_pressed (GtkButton * button);
static void gtk_real_button_released (GtkButton * button);
static void gtk_real_button_clicked (GtkButton * button);
137 138 139 140 141 142 143
static void gtk_real_button_activate  (GtkButton          *button);
static void gtk_button_update_state   (GtkButton          *button);
static void gtk_button_add            (GtkContainer       *container,
			               GtkWidget          *widget);
static GType gtk_button_child_type    (GtkContainer       *container);
static void gtk_button_finish_activate (GtkButton         *button,
					gboolean           do_it);
Elliot Lee's avatar
Elliot Lee committed
144

145 146 147
static GObject*	gtk_button_constructor (GType                  type,
					guint                  n_construct_properties,
					GObjectConstructParam *construct_params);
Matthias Clasen's avatar
Matthias Clasen committed
148
static void gtk_button_construct_child (GtkButton             *button);
149 150 151 152
static void gtk_button_state_changed   (GtkWidget             *widget,
					GtkStateType           previous_state);
static void gtk_button_grab_notify     (GtkWidget             *widget,
					gboolean               was_grabbed);
153 154
static void gtk_button_hierarchy_changed (GtkWidget           *widget,
                                          GtkWidget           *previous_toplevel);
155

156

157
static void gtk_button_actionable_iface_init     (GtkActionableInterface *iface);
158
static void gtk_button_activatable_interface_init(GtkActivatableIface  *iface);
159 160 161 162 163 164 165 166 167
static void gtk_button_update                    (GtkActivatable       *activatable,
				                  GtkAction            *action,
			                          const gchar          *property_name);
static void gtk_button_sync_action_properties    (GtkActivatable       *activatable,
                                                  GtkAction            *action);
static void gtk_button_set_related_action        (GtkButton            *button,
					          GtkAction            *action);
static void gtk_button_set_use_action_appearance (GtkButton            *button,
						  gboolean              use_appearance);
168

169
static void gtk_button_get_preferred_width       (GtkWidget           *widget,
170 171
						  gint                *minimum_size,
						  gint                *natural_size);
172
static void gtk_button_get_preferred_height      (GtkWidget           *widget,
173 174
						  gint                *minimum_size,
						  gint                *natural_size);
175
  
176
static guint button_signals[LAST_SIGNAL] = { 0 };
Elliot Lee's avatar
Elliot Lee committed
177

178
G_DEFINE_TYPE_WITH_CODE (GtkButton, gtk_button, GTK_TYPE_BIN,
179
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, gtk_button_actionable_iface_init)
180
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
181
						gtk_button_activatable_interface_init))
Elliot Lee's avatar
Elliot Lee committed
182 183 184 185

static void
gtk_button_class_init (GtkButtonClass *klass)
{
Manish Singh's avatar
Manish Singh committed
186
  GObjectClass *gobject_class;
Elliot Lee's avatar
Elliot Lee committed
187 188 189
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;

Manish Singh's avatar
Manish Singh committed
190
  gobject_class = G_OBJECT_CLASS (klass);
Elliot Lee's avatar
Elliot Lee committed
191 192
  widget_class = (GtkWidgetClass*) klass;
  container_class = (GtkContainerClass*) klass;
193
  
194 195
  gobject_class->constructor  = gtk_button_constructor;
  gobject_class->dispose      = gtk_button_dispose;
Manish Singh's avatar
Manish Singh committed
196 197
  gobject_class->set_property = gtk_button_set_property;
  gobject_class->get_property = gtk_button_get_property;
198

199 200
  widget_class->get_preferred_width  = gtk_button_get_preferred_width;
  widget_class->get_preferred_height = gtk_button_get_preferred_height;
201
  widget_class->destroy = gtk_button_destroy;
Matthias Clasen's avatar
Matthias Clasen committed
202
  widget_class->screen_changed = gtk_button_screen_changed;
203
  widget_class->realize = gtk_button_realize;
204
  widget_class->unrealize = gtk_button_unrealize;
205 206
  widget_class->map = gtk_button_map;
  widget_class->unmap = gtk_button_unmap;
207
  widget_class->style_updated = gtk_button_style_updated;
208
  widget_class->size_allocate = gtk_button_size_allocate;
209
  widget_class->draw = gtk_button_draw;
210 211
  widget_class->button_press_event = gtk_button_button_press;
  widget_class->button_release_event = gtk_button_button_release;
212
  widget_class->touch_event = gtk_button_touch;
Matthias Clasen's avatar
Matthias Clasen committed
213
  widget_class->grab_broken_event = gtk_button_grab_broken;
214
  widget_class->key_release_event = gtk_button_key_release;
215 216
  widget_class->enter_notify_event = gtk_button_enter_notify;
  widget_class->leave_notify_event = gtk_button_leave_notify;
217 218
  widget_class->state_changed = gtk_button_state_changed;
  widget_class->grab_notify = gtk_button_grab_notify;
219
  widget_class->hierarchy_changed = gtk_button_hierarchy_changed;
220 221

  container_class->child_type = gtk_button_child_type;
222
  container_class->add = gtk_button_add;
223
  gtk_container_class_handle_border_width (container_class);
224 225 226

  klass->pressed = gtk_real_button_pressed;
  klass->released = gtk_real_button_released;
227
  klass->clicked = NULL;
228 229
  klass->enter = gtk_button_update_state;
  klass->leave = gtk_button_update_state;
230
  klass->activate = gtk_real_button_activate;
231

Manish Singh's avatar
Manish Singh committed
232
  g_object_class_install_property (gobject_class,
233 234
                                   PROP_LABEL,
                                   g_param_spec_string ("label",
235 236
                                                        P_("Label"),
                                                        P_("Text of the label widget inside the button, if the button contains a label widget"),
237
                                                        NULL,
238
                                                        GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
239
  
Manish Singh's avatar
Manish Singh committed
240
  g_object_class_install_property (gobject_class,
241
                                   PROP_USE_UNDERLINE,
Matthias Clasen's avatar
x  
Matthias Clasen committed
242
                                   g_param_spec_boolean ("use-underline",
243 244
							 P_("Use underline"),
							 P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
245
                                                        FALSE,
246
                                                        GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
247
  
Manish Singh's avatar
Manish Singh committed
248
  g_object_class_install_property (gobject_class,
249
                                   PROP_USE_STOCK,
Matthias Clasen's avatar
x  
Matthias Clasen committed
250
                                   g_param_spec_boolean ("use-stock",
251 252
							 P_("Use stock"),
							 P_("If set, the label is used to pick a stock item instead of being displayed"),
253
                                                        FALSE,
254
                                                        GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
255
  
256 257
  g_object_class_install_property (gobject_class,
                                   PROP_FOCUS_ON_CLICK,
Matthias Clasen's avatar
x  
Matthias Clasen committed
258
                                   g_param_spec_boolean ("focus-on-click",
259 260
							 P_("Focus on click"),
							 P_("Whether the button grabs focus when it is clicked with the mouse"),
261
							 TRUE,
262
							 GTK_PARAM_READWRITE));
263
  
Manish Singh's avatar
Manish Singh committed
264
  g_object_class_install_property (gobject_class,
265 266
                                   PROP_RELIEF,
                                   g_param_spec_enum ("relief",
267 268
                                                      P_("Border relief"),
                                                      P_("The border relief style"),
269 270
                                                      GTK_TYPE_RELIEF_STYLE,
                                                      GTK_RELIEF_NORMAL,
271
                                                      GTK_PARAM_READWRITE));
272 273 274 275 276
  
  /**
   * GtkButton:xalign:
   *
   * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
277
   * can be used to control its horizontal alignment. 0.0 is left aligned, 
278
   * 1.0 is right aligned.
279
   *
280 281 282 283 284
   * Since: 2.4
   */
  g_object_class_install_property (gobject_class,
                                   PROP_XALIGN,
                                   g_param_spec_float("xalign",
285 286
                                                      P_("Horizontal alignment for child"),
                                                      P_("Horizontal position of child in available space. 0.0 is left aligned, 1.0 is right aligned"),
287 288 289
                                                      0.0,
                                                      1.0,
                                                      0.5,
290
                                                      GTK_PARAM_READWRITE));
291 292 293 294 295

  /**
   * GtkButton:yalign:
   *
   * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
296
   * can be used to control its vertical alignment. 0.0 is top aligned, 
297
   * 1.0 is bottom aligned.
298
   *
299 300 301 302 303
   * Since: 2.4
   */
  g_object_class_install_property (gobject_class,
                                   PROP_YALIGN,
                                   g_param_spec_float("yalign",
304 305
                                                      P_("Vertical alignment for child"),
                                                      P_("Vertical position of child in available space. 0.0 is top aligned, 1.0 is bottom aligned"),
306 307 308
                                                      0.0,
                                                      1.0,
                                                      0.5,
309
                                                      GTK_PARAM_READWRITE));
Elliot Lee's avatar
Elliot Lee committed
310

311
  /**
312
   * GtkButton:image:
313
   *
314
   * The child widget to appear next to the button text.
315
   *
316 317 318 319 320 321 322 323
   * Since: 2.6
   */
  g_object_class_install_property (gobject_class,
                                   PROP_IMAGE,
                                   g_param_spec_object ("image",
                                                        P_("Image widget"),
                                                        P_("Child widget to appear next to the button text"),
                                                        GTK_TYPE_WIDGET,
324
                                                        GTK_PARAM_READWRITE));
325

326 327 328
  /**
   * GtkButton:image-position:
   *
329
   * The position of the image relative to the text inside the button.
330
   *
331 332 333 334 335
   * Since: 2.10
   */
  g_object_class_install_property (gobject_class,
                                   PROP_IMAGE_POSITION,
                                   g_param_spec_enum ("image-position",
336
                                            P_("Image position"),
337 338 339 340 341
                                                      P_("The position of the image relative to the text"),
                                                      GTK_TYPE_POSITION_TYPE,
                                                      GTK_POS_LEFT,
                                                      GTK_PARAM_READWRITE));

342 343 344
  g_object_class_override_property (gobject_class, PROP_ACTION_NAME, "action-name");
  g_object_class_override_property (gobject_class, PROP_ACTION_TARGET, "action-target");

345 346 347
  g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action");
  g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance");

348 349 350 351 352
  /**
   * GtkButton::pressed:
   * @button: the object that received the signal
   *
   * Emitted when the button is pressed.
353
   *
354
   * Deprecated: 2.8: Use the #GtkWidget::button-press-event signal.
355
   */ 
Elliot Lee's avatar
Elliot Lee committed
356
  button_signals[PRESSED] =
357
    g_signal_new (I_("pressed"),
358
		  G_OBJECT_CLASS_TYPE (gobject_class),
Manish Singh's avatar
Manish Singh committed
359 360 361 362 363
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkButtonClass, pressed),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
364 365 366 367 368 369

  /**
   * GtkButton::released:
   * @button: the object that received the signal
   *
   * Emitted when the button is released.
370
   *
371
   * Deprecated: 2.8: Use the #GtkWidget::button-release-event signal.
372
   */ 
Elliot Lee's avatar
Elliot Lee committed
373
  button_signals[RELEASED] =
374
    g_signal_new (I_("released"),
375
		  G_OBJECT_CLASS_TYPE (gobject_class),
Manish Singh's avatar
Manish Singh committed
376 377 378 379 380
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkButtonClass, released),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
381 382 383 384 385 386 387

  /**
   * GtkButton::clicked:
   * @button: the object that received the signal
   *
   * Emitted when the button has been activated (pressed and released).
   */ 
Elliot Lee's avatar
Elliot Lee committed
388
  button_signals[CLICKED] =
389
    g_signal_new (I_("clicked"),
390
		  G_OBJECT_CLASS_TYPE (gobject_class),
Manish Singh's avatar
Manish Singh committed
391 392 393 394 395
		  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
		  G_STRUCT_OFFSET (GtkButtonClass, clicked),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
396 397 398 399 400 401

  /**
   * GtkButton::enter:
   * @button: the object that received the signal
   *
   * Emitted when the pointer enters the button.
402
   *
403
   * Deprecated: 2.8: Use the #GtkWidget::enter-notify-event signal.
404
   */ 
Elliot Lee's avatar
Elliot Lee committed
405
  button_signals[ENTER] =
406
    g_signal_new (I_("enter"),
407
		  G_OBJECT_CLASS_TYPE (gobject_class),
Manish Singh's avatar
Manish Singh committed
408 409 410 411 412
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkButtonClass, enter),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
413 414 415 416 417 418

  /**
   * GtkButton::leave:
   * @button: the object that received the signal
   *
   * Emitted when the pointer leaves the button.
419
   *
420
   * Deprecated: 2.8: Use the #GtkWidget::leave-notify-event signal.
421
   */ 
Elliot Lee's avatar
Elliot Lee committed
422
  button_signals[LEAVE] =
423
    g_signal_new (I_("leave"),
424
		  G_OBJECT_CLASS_TYPE (gobject_class),
Manish Singh's avatar
Manish Singh committed
425 426 427 428 429
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkButtonClass, leave),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
430 431 432

  /**
   * GtkButton::activate:
Matthias Clasen's avatar
Matthias Clasen committed
433
   * @widget: the object which received the signal.
434
   *
435
   * The ::activate signal on GtkButton is an action signal and
436 437
   * emitting it causes the button to animate press then release. 
   * Applications should never connect to this signal, but use the
438
   * #GtkButton::clicked signal.
439
   */
440
  button_signals[ACTIVATE] =
441
    g_signal_new (I_("activate"),
442
		  G_OBJECT_CLASS_TYPE (gobject_class),
Manish Singh's avatar
Manish Singh committed
443 444 445 446 447
		  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
		  G_STRUCT_OFFSET (GtkButtonClass, activate),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
448
  widget_class->activate_signal = button_signals[ACTIVATE];
449

450 451 452 453 454 455 456 457
  /**
   * GtkButton:default-border:
   *
   * The "default-border" style property defines the extra space to add
   * around a button that can become the default widget of its window.
   * For more information about default widgets, see gtk_widget_grab_default().
   */

458
  gtk_widget_class_install_style_property (widget_class,
Matthias Clasen's avatar
x  
Matthias Clasen committed
459
					   g_param_spec_boxed ("default-border",
460
							       P_("Default Spacing"),
461
							       P_("Extra space to add for GTK_CAN_DEFAULT buttons"),
462
							       GTK_TYPE_BORDER,
463
							       GTK_PARAM_READABLE));
464

465 466 467 468 469 470 471 472
  /**
   * GtkButton:default-outside-border:
   *
   * The "default-outside-border" style property defines the extra outside
   * space to add around a button that can become the default widget of its
   * window. Extra outside space is always drawn outside the button border.
   * For more information about default widgets, see gtk_widget_grab_default().
   */
473
  gtk_widget_class_install_style_property (widget_class,
Matthias Clasen's avatar
x  
Matthias Clasen committed
474
					   g_param_spec_boxed ("default-outside-border",
475
							       P_("Default Outside Spacing"),
476
							       P_("Extra space to add for GTK_CAN_DEFAULT buttons that is always drawn outside the border"),
477
							       GTK_TYPE_BORDER,
478
							       GTK_PARAM_READABLE));
479
  gtk_widget_class_install_style_property (widget_class,
Matthias Clasen's avatar
x  
Matthias Clasen committed
480
					   g_param_spec_int ("child-displacement-x",
481 482
							     P_("Child X Displacement"),
							     P_("How far in the x direction to move the child when the button is depressed"),
483 484 485
							     G_MININT,
							     G_MAXINT,
							     0,
486
							     GTK_PARAM_READABLE));
487
  gtk_widget_class_install_style_property (widget_class,
Matthias Clasen's avatar
x  
Matthias Clasen committed
488
					   g_param_spec_int ("child-displacement-y",
489 490
							     P_("Child Y Displacement"),
							     P_("How far in the y direction to move the child when the button is depressed"),
491 492 493
							     G_MININT,
							     G_MAXINT,
							     0,
494
							     GTK_PARAM_READABLE));
495

496 497 498
  /**
   * GtkButton:displace-focus:
   *
499 500
   * Whether the child_displacement_x/child_displacement_y properties 
   * should also affect the focus rectangle.
501 502 503 504 505 506 507
   *
   * Since: 2.6
   */
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_boolean ("displace-focus",
								 P_("Displace focus"),
								 P_("Whether the child_displacement_x/_y properties should also affect the focus rectangle"),
Johan Dahlin's avatar
Johan Dahlin committed
508 509
								 FALSE,
								 GTK_PARAM_READABLE));
510

511
  /**
512
   * GtkButton:inner-border:
513
   *
514
   * Sets the border between the button edges and child.
515 516
   *
   * Since: 2.10
517 518 519
   *
   * Deprecated: 3.4: Use the standard border and padding CSS properties;
   *   the value of this style property is ignored.
520 521
   */
  gtk_widget_class_install_style_property (widget_class,
522 523 524 525 526
					   g_param_spec_boxed ("inner-border",
                                                               P_("Inner Border"),
                                                               P_("Border between button edges and child."),
                                                               GTK_TYPE_BORDER,
                                                               GTK_PARAM_READABLE));
527

528 529
  /**
   * GtkButton::image-spacing:
530
   *
531
   * Spacing in pixels between the image and label.
532
   *
533 534 535 536 537 538 539 540 541 542 543
   * Since: 2.10
   */
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_int ("image-spacing",
							     P_("Image spacing"),
							     P_("Spacing in pixels between the image and label"),
							     0,
							     G_MAXINT,
							     2,
							     GTK_PARAM_READABLE));

544
  g_type_class_add_private (gobject_class, sizeof (GtkButtonPrivate));
545 546

  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_BUTTON_ACCESSIBLE);
Elliot Lee's avatar
Elliot Lee committed
547 548 549 550 551
}

static void
gtk_button_init (GtkButton *button)
{
552
  GtkButtonPrivate *priv;
553
  GtkStyleContext *context;
554 555 556 557 558

  button->priv = G_TYPE_INSTANCE_GET_PRIVATE (button,
                                              GTK_TYPE_BUTTON,
                                              GtkButtonPrivate);
  priv = button->priv;
559

560
  gtk_widget_set_can_focus (GTK_WIDGET (button), TRUE);
561
  gtk_widget_set_receives_default (GTK_WIDGET (button), TRUE);
562
  gtk_widget_set_has_window (GTK_WIDGET (button), FALSE);
Elliot Lee's avatar
Elliot Lee committed
563

564 565 566 567 568 569 570 571 572 573 574
  priv->label_text = NULL;

  priv->constructed = FALSE;
  priv->in_button = FALSE;
  priv->button_down = FALSE;
  priv->relief = GTK_RELIEF_NORMAL;
  priv->use_stock = FALSE;
  priv->use_underline = FALSE;
  priv->depressed = FALSE;
  priv->depress_on_activate = TRUE;
  priv->focus_on_click = TRUE;
575 576 577

  priv->xalign = 0.5;
  priv->yalign = 0.5;
578
  priv->align_set = 0;
579
  priv->image_is_stock = TRUE;
580
  priv->image_position = GTK_POS_LEFT;
581
  priv->use_action_appearance = TRUE;
582 583 584

  context = gtk_widget_get_style_context (GTK_WIDGET (button));
  gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
Elliot Lee's avatar
Elliot Lee committed
585 586
}

587
static void
588
gtk_button_destroy (GtkWidget *widget)
589
{
590
  GtkButton *button = GTK_BUTTON (widget);
591
  GtkButtonPrivate *priv = button->priv;
592

593
  if (priv->label_text)
594
    {
595 596
      g_free (priv->label_text);
      priv->label_text = NULL;
597
    }
598

599 600 601 602 603 604
  if (priv->action_name)
    {
      g_free (priv->action_name);
      priv->action_name = NULL;
    }

605
  GTK_WIDGET_CLASS (gtk_button_parent_class)->destroy (widget);
606 607
}

608 609 610 611 612 613 614
static GObject*
gtk_button_constructor (GType                  type,
			guint                  n_construct_properties,
			GObjectConstructParam *construct_params)
{
  GObject *object;
  GtkButton *button;
615
  GtkButtonPrivate *priv;
616

617 618 619
  object = G_OBJECT_CLASS (gtk_button_parent_class)->constructor (type,
                                                                  n_construct_properties,
                                                                  construct_params);
620 621

  button = GTK_BUTTON (object);
622 623 624
  priv = button->priv;

  priv->constructed = TRUE;
625

626
  if (priv->label_text != NULL)
627 628 629 630 631 632
    gtk_button_construct_child (button);
  
  return object;
}


Manish Singh's avatar
Manish Singh committed
633
static GType
634 635
gtk_button_child_type  (GtkContainer     *container)
{
Javier Jardón's avatar
Javier Jardón committed
636
  if (!gtk_bin_get_child (GTK_BIN (container)))
637 638
    return GTK_TYPE_WIDGET;
  else
Manish Singh's avatar
Manish Singh committed
639
    return G_TYPE_NONE;
640 641
}

642
static void
643 644
maybe_set_alignment (GtkButton *button,
		     GtkWidget *widget)
645
{
646
  GtkButtonPrivate *priv = button->priv;
647

648 649 650
  if (GTK_IS_MISC (widget))
    {
      GtkMisc *misc = GTK_MISC (widget);
651 652 653
      
      if (priv->align_set)
	gtk_misc_set_alignment (misc, priv->xalign, priv->yalign);
654 655 656 657
    }
  else if (GTK_IS_ALIGNMENT (widget))
    {
      GtkAlignment *alignment = GTK_ALIGNMENT (widget);
658 659 660 661 662 663
      gfloat xscale, yscale;

      g_object_get (alignment,
                    "xscale", &xscale,
                    "yscale", &yscale,
                    NULL);
664 665

      if (priv->align_set)
666 667 668
        gtk_alignment_set (alignment,
                           priv->xalign, priv->yalign,
                           xscale, yscale);
669 670 671 672 673 674 675
    }
}

static void
gtk_button_add (GtkContainer *container,
		GtkWidget    *widget)
{
676
  maybe_set_alignment (GTK_BUTTON (container), widget);
677

Matthias Clasen's avatar
Matthias Clasen committed
678
  GTK_CONTAINER_CLASS (gtk_button_parent_class)->add (container, widget);
679 680
}

681 682 683 684
static void 
gtk_button_dispose (GObject *object)
{
  GtkButton *button = GTK_BUTTON (object);
685
  GtkButtonPrivate *priv = button->priv;
686

687 688
  g_clear_object (&priv->action_observer);

689 690 691 692 693 694 695 696
  if (priv->action)
    {
      gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (button), NULL);
      priv->action = NULL;
    }
  G_OBJECT_CLASS (gtk_button_parent_class)->dispose (object);
}

697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
static void
gtk_button_update_action_observer (GtkButton *button)
{
  GtkWidget *window;

  g_signal_handlers_disconnect_by_func (button, gtk_real_button_clicked, NULL);

  /* we are the only owner so this will clear all the signals */
  g_clear_object (&button->priv->action_observer);

  window = gtk_widget_get_toplevel (GTK_WIDGET (button));

  if (GTK_IS_APPLICATION_WINDOW (window) && button->priv->action_name)
    {
      GSimpleActionObserver *observer;

713 714 715
      observer = gtk_application_window_create_observer (GTK_APPLICATION_WINDOW (window),
                                                         button->priv->action_name,
                                                         button->priv->action_target);
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735

      _gtk_button_set_depressed (button, g_simple_action_observer_get_active (observer));

      if (g_object_class_find_property (G_OBJECT_GET_CLASS (button), "active"))
        g_object_bind_property (observer, "active", button, "active", G_BINDING_SYNC_CREATE);
      g_object_bind_property (observer, "enabled", button, "sensitive", G_BINDING_SYNC_CREATE);

      button->priv->action_observer = observer;

      g_signal_connect_after (button, "clicked", G_CALLBACK (gtk_real_button_clicked), NULL);
    }
}

static void
gtk_button_set_action_name (GtkActionable *actionable,
                            const gchar   *action_name)
{
  GtkButton *button = GTK_BUTTON (actionable);

  g_return_if_fail (GTK_IS_BUTTON (button));
736
  g_return_if_fail (button->priv->action == NULL);
737

738 739
  g_free (button->priv->action_name);
  button->priv->action_name = g_strdup (action_name);
740

741
  gtk_button_update_action_observer (button);
742

743
  g_object_notify (G_OBJECT (button), "action-name");
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771
}

static void
gtk_button_set_action_target_value (GtkActionable *actionable,
                                    GVariant      *action_target)
{
  GtkButton *button = GTK_BUTTON (actionable);

  g_return_if_fail (GTK_IS_BUTTON (button));

  if (action_target != button->priv->action_target &&
      (!action_target || !button->priv->action_target ||
       !g_variant_equal (action_target, button->priv->action_target)))
    {
      if (button->priv->action_target)
        g_variant_unref (button->priv->action_target);

      button->priv->action_target = NULL;

      if (action_target)
        button->priv->action_target = g_variant_ref_sink (action_target);

      gtk_button_update_action_observer (button);

      g_object_notify (G_OBJECT (button), "action-target");
    }
}

Elliot Lee's avatar
Elliot Lee committed
772
static void
773 774 775 776
gtk_button_set_property (GObject         *object,
                         guint            prop_id,
                         const GValue    *value,
                         GParamSpec      *pspec)
Elliot Lee's avatar
Elliot Lee committed
777
{
778
  GtkButton *button = GTK_BUTTON (object);
779
  GtkButtonPrivate *priv = button->priv;
Elliot Lee's avatar
Elliot Lee committed
780

781
  switch (prop_id)
782
    {
783
    case PROP_LABEL:
784
      gtk_button_set_label (button, g_value_get_string (value));
785
      break;
786 787 788
    case PROP_IMAGE:
      gtk_button_set_image (button, (GtkWidget *) g_value_get_object (value));
      break;
789 790
    case PROP_RELIEF:
      gtk_button_set_relief (button, g_value_get_enum (value));
791
      break;
792 793 794 795 796 797
    case PROP_USE_UNDERLINE:
      gtk_button_set_use_underline (button, g_value_get_boolean (value));
      break;
    case PROP_USE_STOCK:
      gtk_button_set_use_stock (button, g_value_get_boolean (value));
      break;
798 799 800
    case PROP_FOCUS_ON_CLICK:
      gtk_button_set_focus_on_click (button, g_value_get_boolean (value));
      break;
801 802 803 804 805 806
    case PROP_XALIGN:
      gtk_button_set_alignment (button, g_value_get_float (value), priv->yalign);
      break;
    case PROP_YALIGN:
      gtk_button_set_alignment (button, priv->xalign, g_value_get_float (value));
      break;
807 808 809
    case PROP_IMAGE_POSITION:
      gtk_button_set_image_position (button, g_value_get_enum (value));
      break;
810 811 812 813 814 815
    case PROP_ACTIVATABLE_RELATED_ACTION:
      gtk_button_set_related_action (button, g_value_get_object (value));
      break;
    case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
      gtk_button_set_use_action_appearance (button, g_value_get_boolean (value));
      break;
816 817 818 819 820 821
    case PROP_ACTION_NAME:
      gtk_button_set_action_name (GTK_ACTIONABLE (button), g_value_get_string (value));
      break;
    case PROP_ACTION_TARGET:
      gtk_button_set_action_target_value (GTK_ACTIONABLE (button), g_value_get_variant (value));
      break;
822
    default:
823
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
824 825 826 827 828
      break;
    }
}

static void
829 830 831 832
gtk_button_get_property (GObject         *object,
                         guint            prop_id,
                         GValue          *value,
                         GParamSpec      *pspec)
833
{
834
  GtkButton *button = GTK_BUTTON (object);
835
  GtkButtonPrivate *priv = button->priv;
836

837
  switch (prop_id)
838
    {
839
    case PROP_LABEL:
840
      g_value_set_string (value, priv->label_text);
841
      break;
842 843 844
    case PROP_IMAGE:
      g_value_set_object (value, (GObject *)priv->image);
      break;
845
    case PROP_RELIEF:
846
      g_value_set_enum (value, priv->relief);
847
      break;
848
    case PROP_USE_UNDERLINE:
849
      g_value_set_boolean (value, priv->use_underline);
850 851
      break;
    case PROP_USE_STOCK:
852
      g_value_set_boolean (value, priv->use_stock);
853
      break;
854
    case PROP_FOCUS_ON_CLICK:
855
      g_value_set_boolean (value, priv->focus_on_click);
856
      break;
857 858 859 860 861 862
    case PROP_XALIGN:
      g_value_set_float (value, priv->xalign);
      break;
    case PROP_YALIGN:
      g_value_set_float (value, priv->yalign);
      break;
863 864 865
    case PROP_IMAGE_POSITION:
      g_value_set_enum (value, priv->image_position);
      break;
866 867 868 869 870 871
    case PROP_ACTIVATABLE_RELATED_ACTION:
      g_value_set_object (value, priv->action);
      break;
    case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE:
      g_value_set_boolean (value, priv->use_action_appearance);
      break;
872 873 874 875 876 877
    case PROP_ACTION_NAME:
      g_value_set_string (value, priv->action_name);
      break;
    case PROP_ACTION_TARGET:
      g_value_set_variant (value, priv->action_target);
      break;
Tim Janik's avatar
Tim Janik committed
878
    default:
879
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Tim Janik's avatar
Tim Janik committed
880
      break;
Elliot Lee's avatar
Elliot Lee committed
881 882 883
    }
}

884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
static const gchar *
gtk_button_get_action_name (GtkActionable *actionable)
{
  GtkButton *button = GTK_BUTTON (actionable);

  return button->priv->action_name;
}

static GVariant *
gtk_button_get_action_target_value (GtkActionable *actionable)
{
  GtkButton *button = GTK_BUTTON (actionable);

  return button->priv->action_target;
}

static void
gtk_button_actionable_iface_init (GtkActionableInterface *iface)
{
  iface->get_action_name = gtk_button_get_action_name;
  iface->set_action_name = gtk_button_set_action_name;
  iface->get_action_target_value = gtk_button_get_action_target_value;
  iface->set_action_target_value = gtk_button_set_action_target_value;
}

909 910 911
static void 
gtk_button_activatable_interface_init (GtkActivatableIface  *iface)
{
912 913
  iface->update = gtk_button_update;
  iface->sync_action_properties = gtk_button_sync_action_properties;
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
}

static void
activatable_update_stock_id (GtkButton *button,
			     GtkAction *action)
{
  if (!gtk_button_get_use_stock (button))
    return;

  gtk_button_set_label (button, gtk_action_get_stock_id (action));
}

static void
activatable_update_short_label (GtkButton *button,
				GtkAction *action)
{
Javier Jardón's avatar
Javier Jardón committed
930
  GtkWidget *child;
931 932 933 934 935 936 937 938
  GtkWidget *image;

  if (gtk_button_get_use_stock (button))
    return;

  image = gtk_button_get_image (button);

  /* Dont touch custom child... */
Javier Jardón's avatar
Javier Jardón committed
939
  child = gtk_bin_get_child (GTK_BIN (button));
940
  if (GTK_IS_IMAGE (image) ||
Javier Jardón's avatar
Javier Jardón committed
941 942
      child == NULL ||
      GTK_IS_LABEL (child))
943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980
    {
      gtk_button_set_label (button, gtk_action_get_short_label (action));
      gtk_button_set_use_underline (button, TRUE);
    }
}

static void
activatable_update_icon_name (GtkButton *button,
			      GtkAction *action)
{
  GtkWidget *image;
	      
  if (gtk_button_get_use_stock (button))
    return;

  image = gtk_button_get_image (button);

  if (GTK_IS_IMAGE (image) &&
      (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
       gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_ICON_NAME))
    gtk_image_set_from_icon_name (GTK_IMAGE (image),
				  gtk_action_get_icon_name (action), GTK_ICON_SIZE_MENU);
}

static void
activatable_update_gicon (GtkButton *button,
			  GtkAction *action)
{
  GtkWidget *image = gtk_button_get_image (button);
  GIcon *icon = gtk_action_get_gicon (action);
  
  if (GTK_IS_IMAGE (image) &&
      (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
       gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_GICON))
    gtk_image_set_from_gicon (GTK_IMAGE (image), icon, GTK_ICON_SIZE_BUTTON);
}

static void 
981 982 983
gtk_button_update (GtkActivatable *activatable,
		   GtkAction      *action,
	           const gchar    *property_name)
984
{
985 986
  GtkButton *button = GTK_BUTTON (activatable);
  GtkButtonPrivate *priv = button->priv;
987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010

  if (strcmp (property_name, "visible") == 0)
    {
      if (gtk_action_is_visible (action))
	gtk_widget_show (GTK_WIDGET (activatable));
      else
	gtk_widget_hide (GTK_WIDGET (activatable));
    }
  else if (strcmp (property_name, "sensitive") == 0)
    gtk_widget_set_sensitive (GTK_WIDGET (activatable), gtk_action_is_sensitive (action));

  if (!priv->use_action_appearance)
    return;

  if (strcmp (property_name, "stock-id") == 0)
    activatable_update_stock_id (GTK_BUTTON (activatable), action);
  else if (strcmp (property_name, "gicon") == 0)
    activatable_update_gicon (GTK_BUTTON (activatable), action);
  else if (strcmp (property_name, "short-label") == 0)
    activatable_update_short_label (GTK_BUTTON (activatable), action);
  else if (strcmp (property_name, "icon-name") == 0)
    activatable_update_icon_name (GTK_BUTTON (activatable), action);
}

1011 1012 1013
static void
gtk_button_sync_action_properties (GtkActivatable *activatable,
			           GtkAction      *action)
1014
{
1015 1016
  GtkButton *button = GTK_BUTTON (activatable);
  GtkButtonPrivate *priv = button->priv;
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037

  if (!action)
    return;

  if (gtk_action_is_visible (action))
    gtk_widget_show (GTK_WIDGET (activatable));
  else
    gtk_widget_hide (GTK_WIDGET (activatable));
  
  gtk_widget_set_sensitive (GTK_WIDGET (activatable), gtk_action_is_sensitive (action));
  
  if (priv->use_action_appearance)
    {
      activatable_update_stock_id (GTK_BUTTON (activatable), action);
      activatable_update_short_label (GTK_BUTTON (activatable), action);
      activatable_update_gicon (GTK_BUTTON (activatable), action);
      activatable_update_icon_name (GTK_BUTTON (activatable), action);
    }
}

static void
1038 1039
gtk_button_set_related_action (GtkButton *button,
			       GtkAction *action)
1040
{
1041
  GtkButtonPrivate *priv = button->priv;
1042

1043 1044
  g_return_if_fail (button->priv->action_name == NULL);

1045 1046 1047
  if (priv->action == action)
    return;

1048 1049 1050 1051 1052 1053
  /* This should be a default handler, but for compatibility reasons
   * we need to support derived classes that don't chain up their
   * clicked handler.
   */
  g_signal_handlers_disconnect_by_func (button, gtk_real_button_clicked, NULL);
  if (action)
1054
    g_signal_connect_after (button, "clicked",
1055 1056
                            G_CALLBACK (gtk_real_button_clicked), NULL);

1057 1058 1059 1060 1061 1062
  gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (button), action);

  priv->action = action;
}

static void
1063 1064
gtk_button_set_use_action_appearance (GtkButton *button,
				      gboolean   use_appearance)
1065
{
1066
  GtkButtonPrivate *priv = button->priv;
1067 1068 1069 1070

  if (priv->use_action_appearance != use_appearance)
    {
      priv->use_action_appearance = use_appearance;
1071 1072

      gtk_activatable_sync_action_properties (GTK_ACTIVATABLE (button), priv->action);
1073 1074 1075
    }
}

1076 1077 1078 1079 1080 1081 1082 1083
/**
 * gtk_button_new:
 *
 * Creates a new #GtkButton widget. To add a child widget to the button,
 * use gtk_container_add().
 *
 * Returns: The newly created #GtkButton widget.
 */
Elliot Lee's avatar
Elliot Lee committed
1084
GtkWidget*
1085
gtk_button_new (void)
Elliot Lee's avatar
Elliot Lee committed
1086
{
Manish Singh's avatar
Manish Singh committed
1087
  return g_object_new (GTK_TYPE_BUTTON, NULL);
Elliot Lee's avatar
Elliot Lee committed
1088 1089
}

Matthias Clasen's avatar
Matthias Clasen committed
1090 1091 1092
static gboolean
show_image (GtkButton *button)
{
1093
  GtkButtonPrivate *priv = button->priv;
Matthias Clasen's avatar
Matthias Clasen committed
1094
  gboolean show;
1095 1096

  if (priv->label_text)
1097 1098
    {
      GtkSettings *settings;
Matthias Clasen's avatar
Matthias Clasen committed
1099

1100 1101 1102 1103 1104
      settings = gtk_widget_get_settings (GTK_WIDGET (button));        
      g_object_get (settings, "gtk-button-images", &show, NULL);
    }
  else
    show = TRUE;
Matthias Clasen's avatar
Matthias Clasen committed
1105 1106 1107 1108

  return show;
}

1109 1110
static void
gtk_button_construct_child (GtkButton *button)
Elliot Lee's avatar
Elliot Lee committed
1111
{
1112
  GtkButtonPrivate *priv = button->priv;
1113
  GtkStyleContext *context;
1114
  GtkStockItem item;
Javier Jardón's avatar
Javier Jardón committed
1115
  GtkWidget *child;
1116
  GtkWidget *label;
1117
  GtkWidget *box;
1118
  GtkWidget *align;
1119 1120
  GtkWidget *image = NULL;
  gchar *label_text = NULL;
1121
  gint image_spacing;
1122

1123
  if (!priv->constructed)
1124
    return;
1125

1126
  if (!priv->label_text && !priv->image)
1127
    return;
1128

1129 1130 1131 1132 1133
  context = gtk_widget_get_style_context (GTK_WIDGET (button));

  gtk_style_context_get_style (context,
                               "image-spacing", &image_spacing,
                               NULL);
1134

1135 1136
  if (priv->image && !priv->image_is_stock)
    {
1137 1138
      GtkWidget *parent;

1139
      image = g_object_ref (priv->image);
1140 1141 1142 1143

      parent = gtk_widget_get_parent (image);
      if (parent)
	gtk_container_remove (GTK_CONTAINER (parent), image);
1144
    }
1145

1146 1147
  priv->image = NULL;

Javier Jardón's avatar
Javier Jardón committed
1148 1149 1150
  child = gtk_bin_get_child (GTK_BIN (button));
  if (child)
    gtk_container_remove (GTK_CONTAINER (button), child);
1151

1152 1153 1154
  if (priv->use_stock &&
      priv->label_text &&
      gtk_stock_lookup (priv->label_text, &item))
1155
    {
1156
      if (!image)
1157
	image = g_object_ref (gtk_image_new_from_stock (priv->label_text, GTK_ICON_SIZE_BUTTON));
1158 1159 1160 1161

      label_text = item.label;
    }
  else
1162
    label_text = priv->label_text;
1163

1164 1165 1166
  if (image)
    {
      priv->image = image;
1167
      g_object_set (priv->image,
Matthias Clasen's avatar
Matthias Clasen committed
1168
		    "visible", show_image (button),
1169
		    "no-show-all", TRUE,
Matthias Clasen's avatar
Matthias Clasen committed
1170
		    NULL);
1171 1172 1173

      if (priv->image_position == GTK_POS_LEFT ||
	  priv->image_position == GTK_POS_RIGHT)
1174
	box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, image_spacing);
1175
      else
1176
	box = gtk_box_new (GTK_ORIENTATION_VERTICAL, image_spacing);
1177

1178 1179 1180 1181
      if (priv->align_set)
	align = gtk_alignment_new (priv->xalign, priv->yalign, 0.0, 0.0);
      else
	align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1182 1183 1184 1185 1186 1187

      if (priv->image_position == GTK_POS_LEFT ||
	  priv->image_position == GTK_POS_TOP)
	gtk_box_pack_start (GTK_BOX (box), priv->image, FALSE, FALSE, 0);
      else
	gtk_box_pack_end (GTK_BOX (box), priv->image, FALSE, FALSE, 0);
1188 1189 1190

      if (label_text)
	{
1191
          if (priv->use_underline || priv->use_stock)
1192 1193 1194 1195 1196 1197 1198
            {
	      label = gtk_label_new_with_mnemonic (label_text);
	      gtk_label_set_mnemonic_widget (GTK_LABEL (label),
                                             GTK_WIDGET (button));
            }
          else
            label = gtk_label_new (label_text);
1199

1200 1201 1202 1203 1204
	  if (priv->image_position == GTK_POS_RIGHT ||
	      priv->image_position == GTK_POS_BOTTOM)
	    gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
	  else
	    gtk_box_pack_end (GTK_BOX (box), label, FALSE, FALSE, 0);
1205
	}
1206

1207
      gtk_container_add (GTK_CONTAINER (button), align);
1208
      gtk_container_add (GTK_CONTAINER (align), box);
1209
      gtk_widget_show_all (align);
1210

1211 1212
      g_object_unref (image);

1213
      return;
1214
    }
1215

1216
  if (priv->use_underline || priv->use_stock)
1217
    {
1218
      label = gtk_label_new_with_mnemonic (priv->label_text);
1219
      gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
1220
    }
1221
  else
1222
    label = gtk_label_new (priv->label_text);
1223

1224 1225
  if (priv->align_set)
    gtk_misc_set_alignment (GTK_MISC (label), priv->xalign, priv->yalign);
1226

1227 1228 1229 1230 1231
  gtk_widget_show (label);
  gtk_container_add (GTK_CONTAINER (button), label);
}


1232 1233 1234 1235 1236 1237 1238 1239 1240
/**
 * gtk_button_new_with_label:
 * @label: The text you want the #GtkLabel to hold.
 *
 * Creates a #GtkButton widget with a #GtkLabel child containing the given
 * text.
 *
 * Returns: The newly created #GtkButton widget.
 */
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
GtkWidget*
gtk_button_new_with_label (const gchar *label)
{
  return g_object_new (GTK_TYPE_BUTTON, "label", label, NULL);
}

/**
 * gtk_button_new_from_stock:
 * @stock_id: the name of the stock item 
 *
 * Creates a new #GtkButton containing the image and text from a stock item.
 * Some stock ids have preprocessor macros like #GTK_STOCK_OK and
 * #GTK_STOCK_APPLY.
1254 1255 1256 1257 1258
 *
 * If @stock_id is unknown, then it will be treated as a mnemonic
 * label (as for gtk_button_new_with_mnemonic()).
 *
 * Returns: a new #GtkButton
1259 1260
 **/
GtkWidget*
1261
gtk_button_new_from_stock (const gchar *stock_id)
1262
{
1263 1264
  return g_object_new (GTK_TYPE_BUTTON,
                       "label", stock_id,
1265 1266
                       "use-stock", TRUE,
                       "use-underline", TRUE,
1267
                       NULL);
1268 1269
}