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