1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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/.
29 #include "gtkalignment.h"
30 #include "gtkbutton.h"
33 #include "gtkmarshalers.h"
37 #include "gtkiconfactory.h"
41 #define CHILD_SPACING 1
43 static const GtkBorder default_default_border = { 1, 1, 1, 1 };
44 static const GtkBorder default_default_outside_border = { 0, 0, 0, 0 };
46 /* Time out before giving up on getting a key release when animating
49 #define ACTIVATE_TIMEOUT 250
73 #define GTK_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_BUTTON, GtkButtonPrivate))
74 typedef struct _GtkButtonPrivate GtkButtonPrivate;
76 struct _GtkButtonPrivate
82 guint image_is_stock : 1;
85 static void gtk_button_class_init (GtkButtonClass *klass);
86 static void gtk_button_init (GtkButton *button);
87 static void gtk_button_destroy (GtkObject *object);
88 static void gtk_button_set_property (GObject *object,
92 static void gtk_button_get_property (GObject *object,
96 static void gtk_button_screen_changed (GtkWidget *widget,
97 GdkScreen *previous_screen);
98 static void gtk_button_realize (GtkWidget *widget);
99 static void gtk_button_unrealize (GtkWidget *widget);
100 static void gtk_button_map (GtkWidget *widget);
101 static void gtk_button_unmap (GtkWidget *widget);
102 static void gtk_button_size_request (GtkWidget *widget,
103 GtkRequisition *requisition);
104 static void gtk_button_size_allocate (GtkWidget *widget,
105 GtkAllocation *allocation);
106 static gint gtk_button_expose (GtkWidget *widget,
107 GdkEventExpose *event);
108 static gint gtk_button_button_press (GtkWidget *widget,
109 GdkEventButton *event);
110 static gint gtk_button_button_release (GtkWidget *widget,
111 GdkEventButton *event);
112 static gint gtk_button_key_release (GtkWidget *widget,
114 static gint gtk_button_enter_notify (GtkWidget *widget,
115 GdkEventCrossing *event);
116 static gint gtk_button_leave_notify (GtkWidget *widget,
117 GdkEventCrossing *event);
118 static void gtk_real_button_pressed (GtkButton *button);
119 static void gtk_real_button_released (GtkButton *button);
120 static void gtk_real_button_activate (GtkButton *button);
121 static void gtk_button_update_state (GtkButton *button);
122 static void gtk_button_add (GtkContainer *container,
124 static GType gtk_button_child_type (GtkContainer *container);
125 static void gtk_button_finish_activate (GtkButton *button,
128 static GObject* gtk_button_constructor (GType type,
129 guint n_construct_properties,
130 GObjectConstructParam *construct_params);
131 static void gtk_button_construct_child (GtkButton *button);
132 static void gtk_button_state_changed (GtkWidget *widget,
133 GtkStateType previous_state);
134 static void gtk_button_grab_notify (GtkWidget *widget,
135 gboolean was_grabbed);
139 static GtkBinClass *parent_class = NULL;
140 static guint button_signals[LAST_SIGNAL] = { 0 };
144 gtk_button_get_type (void)
146 static GType button_type = 0;
150 static const GTypeInfo button_info =
152 sizeof (GtkButtonClass),
153 NULL, /* base_init */
154 NULL, /* base_finalize */
155 (GClassInitFunc) gtk_button_class_init,
156 NULL, /* class_finalize */
157 NULL, /* class_data */
159 16, /* n_preallocs */
160 (GInstanceInitFunc) gtk_button_init,
163 button_type = g_type_register_static (GTK_TYPE_BIN, "GtkButton",
171 gtk_button_class_init (GtkButtonClass *klass)
173 GObjectClass *gobject_class;
174 GtkObjectClass *object_class;
175 GtkWidgetClass *widget_class;
176 GtkContainerClass *container_class;
178 gobject_class = G_OBJECT_CLASS (klass);
179 object_class = (GtkObjectClass*) klass;
180 widget_class = (GtkWidgetClass*) klass;
181 container_class = (GtkContainerClass*) klass;
183 parent_class = g_type_class_peek_parent (klass);
185 gobject_class->constructor = gtk_button_constructor;
186 gobject_class->set_property = gtk_button_set_property;
187 gobject_class->get_property = gtk_button_get_property;
189 object_class->destroy = gtk_button_destroy;
191 widget_class->screen_changed = gtk_button_screen_changed;
192 widget_class->realize = gtk_button_realize;
193 widget_class->unrealize = gtk_button_unrealize;
194 widget_class->map = gtk_button_map;
195 widget_class->unmap = gtk_button_unmap;
196 widget_class->size_request = gtk_button_size_request;
197 widget_class->size_allocate = gtk_button_size_allocate;
198 widget_class->expose_event = gtk_button_expose;
199 widget_class->button_press_event = gtk_button_button_press;
200 widget_class->button_release_event = gtk_button_button_release;
201 widget_class->key_release_event = gtk_button_key_release;
202 widget_class->enter_notify_event = gtk_button_enter_notify;
203 widget_class->leave_notify_event = gtk_button_leave_notify;
204 widget_class->state_changed = gtk_button_state_changed;
205 widget_class->grab_notify = gtk_button_grab_notify;
207 container_class->child_type = gtk_button_child_type;
208 container_class->add = gtk_button_add;
210 klass->pressed = gtk_real_button_pressed;
211 klass->released = gtk_real_button_released;
212 klass->clicked = NULL;
213 klass->enter = gtk_button_update_state;
214 klass->leave = gtk_button_update_state;
215 klass->activate = gtk_real_button_activate;
217 #define STATIC_STRINGS G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
219 g_object_class_install_property (gobject_class,
221 g_param_spec_string ("label",
223 P_("Text of the label widget inside the button, if the button contains a label widget"),
225 G_PARAM_READWRITE | STATIC_STRINGS | G_PARAM_CONSTRUCT));
227 g_object_class_install_property (gobject_class,
229 g_param_spec_boolean ("use-underline",
231 P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
233 G_PARAM_READWRITE | STATIC_STRINGS | G_PARAM_CONSTRUCT));
235 g_object_class_install_property (gobject_class,
237 g_param_spec_boolean ("use-stock",
239 P_("If set, the label is used to pick a stock item instead of being displayed"),
241 G_PARAM_READWRITE | STATIC_STRINGS | G_PARAM_CONSTRUCT));
243 g_object_class_install_property (gobject_class,
245 g_param_spec_boolean ("focus-on-click",
246 P_("Focus on click"),
247 P_("Whether the button grabs focus when it is clicked with the mouse"),
249 G_PARAM_READWRITE | STATIC_STRINGS));
251 g_object_class_install_property (gobject_class,
253 g_param_spec_enum ("relief",
255 P_("The border relief style"),
256 GTK_TYPE_RELIEF_STYLE,
258 G_PARAM_READWRITE | STATIC_STRINGS));
263 * If the child of the button is a #GtkMisc or #GtkAlignment, this property
264 * can be used to control it's horizontal alignment. 0.0 is left aligned,
265 * 1.0 is right aligned.
269 g_object_class_install_property (gobject_class,
271 g_param_spec_float("xalign",
272 P_("Horizontal alignment for child"),
273 P_("Horizontal position of child in available space. 0.0 is left aligned, 1.0 is right aligned"),
277 G_PARAM_READWRITE | STATIC_STRINGS));
282 * If the child of the button is a #GtkMisc or #GtkAlignment, this property
283 * can be used to control it's vertical alignment. 0.0 is top aligned,
284 * 1.0 is bottom aligned.
288 g_object_class_install_property (gobject_class,
290 g_param_spec_float("yalign",
291 P_("Vertical alignment for child"),
292 P_("Vertical position of child in available space. 0.0 is top aligned, 1.0 is bottom aligned"),
296 G_PARAM_READWRITE | STATIC_STRINGS));
301 * The child widget to appear next to the button text.
305 g_object_class_install_property (gobject_class,
307 g_param_spec_object ("image",
309 P_("Child widget to appear next to the button text"),
311 G_PARAM_READWRITE | STATIC_STRINGS));
313 button_signals[PRESSED] =
314 g_signal_new ("pressed",
315 G_OBJECT_CLASS_TYPE (object_class),
317 G_STRUCT_OFFSET (GtkButtonClass, pressed),
319 _gtk_marshal_VOID__VOID,
321 button_signals[RELEASED] =
322 g_signal_new ("released",
323 G_OBJECT_CLASS_TYPE (object_class),
325 G_STRUCT_OFFSET (GtkButtonClass, released),
327 _gtk_marshal_VOID__VOID,
329 button_signals[CLICKED] =
330 g_signal_new ("clicked",
331 G_OBJECT_CLASS_TYPE (object_class),
332 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
333 G_STRUCT_OFFSET (GtkButtonClass, clicked),
335 _gtk_marshal_VOID__VOID,
337 button_signals[ENTER] =
338 g_signal_new ("enter",
339 G_OBJECT_CLASS_TYPE (object_class),
341 G_STRUCT_OFFSET (GtkButtonClass, enter),
343 _gtk_marshal_VOID__VOID,
345 button_signals[LEAVE] =
346 g_signal_new ("leave",
347 G_OBJECT_CLASS_TYPE (object_class),
349 G_STRUCT_OFFSET (GtkButtonClass, leave),
351 _gtk_marshal_VOID__VOID,
355 * GtkButton::activate:
356 * @widget: the object which received the signal.
358 * The "activate" signal on GtkButton is an action signal and
359 * emitting it causes the button to animate press then release.
360 * Applications should never connect to this signal, but use the
363 button_signals[ACTIVATE] =
364 g_signal_new ("activate",
365 G_OBJECT_CLASS_TYPE (object_class),
366 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
367 G_STRUCT_OFFSET (GtkButtonClass, activate),
369 _gtk_marshal_VOID__VOID,
371 widget_class->activate_signal = button_signals[ACTIVATE];
373 gtk_widget_class_install_style_property (widget_class,
374 g_param_spec_boxed ("default-border",
375 P_("Default Spacing"),
376 P_("Extra space to add for CAN_DEFAULT buttons"),
378 G_PARAM_READABLE | STATIC_STRINGS));
380 gtk_widget_class_install_style_property (widget_class,
381 g_param_spec_boxed ("default-outside-border",
382 P_("Default Outside Spacing"),
383 P_("Extra space to add for CAN_DEFAULT buttons that is always drawn outside the border"),
385 G_PARAM_READABLE | STATIC_STRINGS));
386 gtk_widget_class_install_style_property (widget_class,
387 g_param_spec_int ("child-displacement-x",
388 P_("Child X Displacement"),
389 P_("How far in the x direction to move the child when the button is depressed"),
393 G_PARAM_READABLE | STATIC_STRINGS));
394 gtk_widget_class_install_style_property (widget_class,
395 g_param_spec_int ("child-displacement-y",
396 P_("Child Y Displacement"),
397 P_("How far in the y direction to move the child when the button is depressed"),
401 G_PARAM_READABLE | STATIC_STRINGS));
404 * GtkButton:displace-focus:
406 * Whether the child_displacement_x/child_displacement_y properties should also
407 * affect the focus rectangle.
411 gtk_widget_class_install_style_property (widget_class,
412 g_param_spec_boolean ("displace-focus",
413 P_("Displace focus"),
414 P_("Whether the child_displacement_x/_y properties should also affect the focus rectangle"),
416 G_PARAM_READABLE | STATIC_STRINGS));
418 gtk_settings_install_property (g_param_spec_boolean ("gtk-button-images",
419 P_("Show button images"),
420 P_("Whether stock icons should be shown in buttons"),
422 G_PARAM_READWRITE | STATIC_STRINGS));
424 g_type_class_add_private (gobject_class, sizeof (GtkButtonPrivate));
428 gtk_button_init (GtkButton *button)
430 GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
432 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_FOCUS | GTK_RECEIVES_DEFAULT);
433 GTK_WIDGET_SET_FLAGS (button, GTK_NO_WINDOW);
435 button->label_text = NULL;
437 button->constructed = FALSE;
438 button->in_button = FALSE;
439 button->button_down = FALSE;
440 button->relief = GTK_RELIEF_NORMAL;
441 button->use_stock = FALSE;
442 button->use_underline = FALSE;
443 button->depressed = FALSE;
444 button->depress_on_activate = TRUE;
445 button->focus_on_click = TRUE;
450 priv->image_is_stock = TRUE;
454 gtk_button_destroy (GtkObject *object)
456 GtkButton *button = GTK_BUTTON (object);
458 if (button->label_text)
460 g_free (button->label_text);
461 button->label_text = NULL;
464 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
468 gtk_button_constructor (GType type,
469 guint n_construct_properties,
470 GObjectConstructParam *construct_params)
475 object = (* G_OBJECT_CLASS (parent_class)->constructor) (type,
476 n_construct_properties,
479 button = GTK_BUTTON (object);
480 button->constructed = TRUE;
482 if (button->label_text != NULL)
483 gtk_button_construct_child (button);
490 gtk_button_child_type (GtkContainer *container)
492 if (!GTK_BIN (container)->child)
493 return GTK_TYPE_WIDGET;
499 maybe_set_alignment (GtkButton *button,
502 GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
504 if (GTK_IS_MISC (widget))
506 GtkMisc *misc = GTK_MISC (widget);
509 gtk_misc_set_alignment (misc, priv->xalign, priv->yalign);
511 else if (GTK_IS_ALIGNMENT (widget))
513 GtkAlignment *alignment = GTK_ALIGNMENT (widget);
516 gtk_alignment_set (alignment, priv->xalign, priv->yalign,
517 alignment->xscale, alignment->yscale);
522 gtk_button_add (GtkContainer *container,
525 maybe_set_alignment (GTK_BUTTON (container), widget);
527 GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
531 gtk_button_set_property (GObject *object,
536 GtkButton *button = GTK_BUTTON (object);
537 GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
542 gtk_button_set_label (button, g_value_get_string (value));
545 gtk_button_set_image (button, (GtkWidget *) g_value_get_object (value));
548 gtk_button_set_relief (button, g_value_get_enum (value));
550 case PROP_USE_UNDERLINE:
551 gtk_button_set_use_underline (button, g_value_get_boolean (value));
554 gtk_button_set_use_stock (button, g_value_get_boolean (value));
556 case PROP_FOCUS_ON_CLICK:
557 gtk_button_set_focus_on_click (button, g_value_get_boolean (value));
560 gtk_button_set_alignment (button, g_value_get_float (value), priv->yalign);
563 gtk_button_set_alignment (button, priv->xalign, g_value_get_float (value));
566 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
572 gtk_button_get_property (GObject *object,
577 GtkButton *button = GTK_BUTTON (object);
578 GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
583 g_value_set_string (value, button->label_text);
586 g_value_set_object (value, (GObject *)priv->image);
589 g_value_set_enum (value, gtk_button_get_relief (button));
591 case PROP_USE_UNDERLINE:
592 g_value_set_boolean (value, button->use_underline);
595 g_value_set_boolean (value, button->use_stock);
597 case PROP_FOCUS_ON_CLICK:
598 g_value_set_boolean (value, button->focus_on_click);
601 g_value_set_float (value, priv->xalign);
604 g_value_set_float (value, priv->yalign);
607 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
613 gtk_button_new (void)
615 return g_object_new (GTK_TYPE_BUTTON, NULL);
619 show_image (GtkButton *button)
621 GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (button));
624 g_object_get (settings, "gtk-button-images", &show, NULL);
630 gtk_button_construct_child (GtkButton *button)
632 GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
637 GtkWidget *image = NULL;
638 gchar *label_text = NULL;
640 if (!button->constructed)
643 if (button->label_text == NULL)
646 if (GTK_BIN (button)->child)
648 if (priv->image && !priv->image_is_stock)
649 image = g_object_ref (priv->image);
651 gtk_container_remove (GTK_CONTAINER (button),
652 GTK_BIN (button)->child);
657 if (button->use_stock &&
658 gtk_stock_lookup (button->label_text, &item))
661 image = g_object_ref (gtk_image_new_from_stock (button->label_text, GTK_ICON_SIZE_BUTTON));
663 label_text = item.label;
666 label_text = button->label_text;
670 label = gtk_label_new_with_mnemonic (label_text);
671 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
675 g_object_set (priv->image,
676 "visible", show_image (button),
679 hbox = gtk_hbox_new (FALSE, 2);
682 align = gtk_alignment_new (priv->xalign, priv->yalign, 0.0, 0.0);
684 align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
686 gtk_box_pack_start (GTK_BOX (hbox), priv->image, FALSE, FALSE, 0);
687 gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
689 gtk_container_add (GTK_CONTAINER (button), align);
690 gtk_container_add (GTK_CONTAINER (align), hbox);
691 gtk_widget_show_all (align);
693 g_object_unref (image);
698 if (button->use_underline)
700 label = gtk_label_new_with_mnemonic (button->label_text);
701 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
704 label = gtk_label_new (button->label_text);
707 gtk_misc_set_alignment (GTK_MISC (label), priv->xalign, priv->yalign);
709 gtk_widget_show (label);
710 gtk_container_add (GTK_CONTAINER (button), label);
715 gtk_button_new_with_label (const gchar *label)
717 return g_object_new (GTK_TYPE_BUTTON, "label", label, NULL);
721 * gtk_button_new_from_stock:
722 * @stock_id: the name of the stock item
724 * Creates a new #GtkButton containing the image and text from a stock item.
725 * Some stock ids have preprocessor macros like #GTK_STOCK_OK and
728 * If @stock_id is unknown, then it will be treated as a mnemonic
729 * label (as for gtk_button_new_with_mnemonic()).
731 * Returns: a new #GtkButton
734 gtk_button_new_from_stock (const gchar *stock_id)
736 return g_object_new (GTK_TYPE_BUTTON,
739 "use_underline", TRUE,
744 * gtk_button_new_with_mnemonic:
745 * @label: The text of the button, with an underscore in front of the
747 * @returns: a new #GtkButton
749 * Creates a new #GtkButton containing a label.
750 * If characters in @label are preceded by an underscore, they are underlined.
751 * If you need a literal underscore character in a label, use '__' (two
752 * underscores). The first underlined character represents a keyboard
753 * accelerator called a mnemonic.
754 * Pressing Alt and that key activates the button.
757 gtk_button_new_with_mnemonic (const gchar *label)
759 return g_object_new (GTK_TYPE_BUTTON, "label", label, "use_underline", TRUE, NULL);
763 gtk_button_pressed (GtkButton *button)
765 g_return_if_fail (GTK_IS_BUTTON (button));
768 g_signal_emit (button, button_signals[PRESSED], 0);
772 gtk_button_released (GtkButton *button)
774 g_return_if_fail (GTK_IS_BUTTON (button));
776 g_signal_emit (button, button_signals[RELEASED], 0);
780 gtk_button_clicked (GtkButton *button)
782 g_return_if_fail (GTK_IS_BUTTON (button));
784 g_signal_emit (button, button_signals[CLICKED], 0);
788 gtk_button_enter (GtkButton *button)
790 g_return_if_fail (GTK_IS_BUTTON (button));
792 g_signal_emit (button, button_signals[ENTER], 0);
796 gtk_button_leave (GtkButton *button)
798 g_return_if_fail (GTK_IS_BUTTON (button));
800 g_signal_emit (button, button_signals[LEAVE], 0);
804 gtk_button_set_relief (GtkButton *button,
805 GtkReliefStyle newrelief)
807 g_return_if_fail (GTK_IS_BUTTON (button));
809 if (newrelief != button->relief)
811 button->relief = newrelief;
812 g_object_notify (G_OBJECT (button), "relief");
813 gtk_widget_queue_draw (GTK_WIDGET (button));
818 gtk_button_get_relief (GtkButton *button)
820 g_return_val_if_fail (GTK_IS_BUTTON (button), GTK_RELIEF_NORMAL);
822 return button->relief;
826 gtk_button_realize (GtkWidget *widget)
829 GdkWindowAttr attributes;
830 gint attributes_mask;
833 button = GTK_BUTTON (widget);
834 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
836 border_width = GTK_CONTAINER (widget)->border_width;
838 attributes.window_type = GDK_WINDOW_CHILD;
839 attributes.x = widget->allocation.x + border_width;
840 attributes.y = widget->allocation.y + border_width;
841 attributes.width = widget->allocation.width - border_width * 2;
842 attributes.height = widget->allocation.height - border_width * 2;
843 attributes.wclass = GDK_INPUT_ONLY;
844 attributes.event_mask = gtk_widget_get_events (widget);
845 attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
846 GDK_BUTTON_RELEASE_MASK |
847 GDK_ENTER_NOTIFY_MASK |
848 GDK_LEAVE_NOTIFY_MASK);
850 attributes_mask = GDK_WA_X | GDK_WA_Y;
852 widget->window = gtk_widget_get_parent_window (widget);
853 g_object_ref (widget->window);
855 button->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
856 &attributes, attributes_mask);
857 gdk_window_set_user_data (button->event_window, button);
859 widget->style = gtk_style_attach (widget->style, widget->window);
863 gtk_button_unrealize (GtkWidget *widget)
865 GtkButton *button = GTK_BUTTON (widget);
867 if (button->activate_timeout)
868 gtk_button_finish_activate (button, FALSE);
870 if (button->event_window)
872 gdk_window_set_user_data (button->event_window, NULL);
873 gdk_window_destroy (button->event_window);
874 button->event_window = NULL;
877 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
881 gtk_button_map (GtkWidget *widget)
883 GtkButton *button = GTK_BUTTON (widget);
885 GTK_WIDGET_CLASS (parent_class)->map (widget);
887 if (button->event_window)
888 gdk_window_show (button->event_window);
892 gtk_button_unmap (GtkWidget *widget)
894 GtkButton *button = GTK_BUTTON (widget);
896 if (button->event_window)
897 gdk_window_hide (button->event_window);
899 GTK_WIDGET_CLASS (parent_class)->unmap (widget);
903 gtk_button_get_props (GtkButton *button,
904 GtkBorder *default_border,
905 GtkBorder *default_outside_border,
906 gboolean *interior_focus)
908 GtkWidget *widget = GTK_WIDGET (button);
909 GtkBorder *tmp_border;
913 gtk_widget_style_get (widget, "default_border", &tmp_border, NULL);
917 *default_border = *tmp_border;
921 *default_border = default_default_border;
924 if (default_outside_border)
926 gtk_widget_style_get (widget, "default_outside_border", &tmp_border, NULL);
930 *default_outside_border = *tmp_border;
934 *default_outside_border = default_default_outside_border;
938 gtk_widget_style_get (widget, "interior_focus", interior_focus, NULL);
942 gtk_button_size_request (GtkWidget *widget,
943 GtkRequisition *requisition)
945 GtkButton *button = GTK_BUTTON (widget);
946 GtkBorder default_border;
950 gtk_button_get_props (button, &default_border, NULL, NULL);
951 gtk_widget_style_get (GTK_WIDGET (widget),
952 "focus-line-width", &focus_width,
953 "focus-padding", &focus_pad,
956 requisition->width = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
957 GTK_WIDGET (widget)->style->xthickness) * 2;
958 requisition->height = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
959 GTK_WIDGET (widget)->style->ythickness) * 2;
961 if (GTK_WIDGET_CAN_DEFAULT (widget))
963 requisition->width += default_border.left + default_border.right;
964 requisition->height += default_border.top + default_border.bottom;
967 if (GTK_BIN (button)->child && GTK_WIDGET_VISIBLE (GTK_BIN (button)->child))
969 GtkRequisition child_requisition;
971 gtk_widget_size_request (GTK_BIN (button)->child, &child_requisition);
973 requisition->width += child_requisition.width;
974 requisition->height += child_requisition.height;
977 requisition->width += 2 * (focus_width + focus_pad);
978 requisition->height += 2 * (focus_width + focus_pad);
982 gtk_button_size_allocate (GtkWidget *widget,
983 GtkAllocation *allocation)
985 GtkButton *button = GTK_BUTTON (widget);
986 GtkAllocation child_allocation;
988 gint border_width = GTK_CONTAINER (widget)->border_width;
989 gint xthickness = GTK_WIDGET (widget)->style->xthickness;
990 gint ythickness = GTK_WIDGET (widget)->style->ythickness;
991 GtkBorder default_border;
995 gtk_button_get_props (button, &default_border, NULL, NULL);
996 gtk_widget_style_get (GTK_WIDGET (widget),
997 "focus-line-width", &focus_width,
998 "focus-padding", &focus_pad,
1002 widget->allocation = *allocation;
1004 if (GTK_WIDGET_REALIZED (widget))
1005 gdk_window_move_resize (button->event_window,
1006 widget->allocation.x + border_width,
1007 widget->allocation.y + border_width,
1008 widget->allocation.width - border_width * 2,
1009 widget->allocation.height - border_width * 2);
1011 if (GTK_BIN (button)->child && GTK_WIDGET_VISIBLE (GTK_BIN (button)->child))
1013 child_allocation.x = widget->allocation.x + border_width + CHILD_SPACING + xthickness;
1014 child_allocation.y = widget->allocation.y + border_width + CHILD_SPACING + ythickness;
1016 child_allocation.width = MAX (1, widget->allocation.width - (CHILD_SPACING + xthickness) * 2 -
1018 child_allocation.height = MAX (1, widget->allocation.height - (CHILD_SPACING + ythickness) * 2 -
1021 if (GTK_WIDGET_CAN_DEFAULT (button))
1023 child_allocation.x += default_border.left;
1024 child_allocation.y += default_border.top;
1025 child_allocation.width = MAX (1, child_allocation.width - default_border.left - default_border.right);
1026 child_allocation.height = MAX (1, child_allocation.height - default_border.top - default_border.bottom);
1029 if (GTK_WIDGET_CAN_FOCUS (button))
1031 child_allocation.x += focus_width + focus_pad;
1032 child_allocation.y += focus_width + focus_pad;
1033 child_allocation.width = MAX (1, child_allocation.width - (focus_width + focus_pad) * 2);
1034 child_allocation.height = MAX (1, child_allocation.height - (focus_width + focus_pad) * 2);
1037 if (button->depressed)
1039 gint child_displacement_x;
1040 gint child_displacement_y;
1042 gtk_widget_style_get (widget,
1043 "child_displacement_x", &child_displacement_x,
1044 "child_displacement_y", &child_displacement_y,
1046 child_allocation.x += child_displacement_x;
1047 child_allocation.y += child_displacement_y;
1050 gtk_widget_size_allocate (GTK_BIN (button)->child, &child_allocation);
1055 _gtk_button_paint (GtkButton *button,
1057 GtkStateType state_type,
1058 GtkShadowType shadow_type,
1059 const gchar *main_detail,
1060 const gchar *default_detail)
1066 GtkBorder default_border;
1067 GtkBorder default_outside_border;
1068 gboolean interior_focus;
1072 if (GTK_WIDGET_DRAWABLE (button))
1074 widget = GTK_WIDGET (button);
1075 border_width = GTK_CONTAINER (widget)->border_width;
1077 gtk_button_get_props (button, &default_border, &default_outside_border, &interior_focus);
1078 gtk_widget_style_get (GTK_WIDGET (widget),
1079 "focus-line-width", &focus_width,
1080 "focus-padding", &focus_pad,
1083 x = widget->allocation.x + border_width;
1084 y = widget->allocation.y + border_width;
1085 width = widget->allocation.width - border_width * 2;
1086 height = widget->allocation.height - border_width * 2;
1088 if (GTK_WIDGET_HAS_DEFAULT (widget) &&
1089 GTK_BUTTON (widget)->relief == GTK_RELIEF_NORMAL)
1091 gtk_paint_box (widget->style, widget->window,
1092 GTK_STATE_NORMAL, GTK_SHADOW_IN,
1093 area, widget, "buttondefault",
1094 x, y, width, height);
1096 x += default_border.left;
1097 y += default_border.top;
1098 width -= default_border.left + default_border.right;
1099 height -= default_border.top + default_border.bottom;
1101 else if (GTK_WIDGET_CAN_DEFAULT (widget))
1103 x += default_outside_border.left;
1104 y += default_outside_border.top;
1105 width -= default_outside_border.left + default_outside_border.right;
1106 height -= default_outside_border.top + default_outside_border.bottom;
1109 if (!interior_focus && GTK_WIDGET_HAS_FOCUS (widget))
1111 x += focus_width + focus_pad;
1112 y += focus_width + focus_pad;
1113 width -= 2 * (focus_width + focus_pad);
1114 height -= 2 * (focus_width + focus_pad);
1117 if (button->relief != GTK_RELIEF_NONE || button->depressed ||
1118 GTK_WIDGET_STATE(widget) == GTK_STATE_PRELIGHT)
1119 gtk_paint_box (widget->style, widget->window,
1121 shadow_type, area, widget, "button",
1122 x, y, width, height);
1124 if (GTK_WIDGET_HAS_FOCUS (widget))
1126 gint child_displacement_x;
1127 gint child_displacement_y;
1128 gboolean displace_focus;
1130 gtk_widget_style_get (GTK_WIDGET (widget),
1131 "child_displacement_y", &child_displacement_y,
1132 "child_displacement_x", &child_displacement_x,
1133 "displace_focus", &displace_focus,
1138 x += widget->style->xthickness + focus_pad;
1139 y += widget->style->ythickness + focus_pad;
1140 width -= 2 * (widget->style->xthickness + focus_pad);
1141 height -= 2 * (widget->style->ythickness + focus_pad);
1145 x -= focus_width + focus_pad;
1146 y -= focus_width + focus_pad;
1147 width += 2 * (focus_width + focus_pad);
1148 height += 2 * (focus_width + focus_pad);
1151 if (button->depressed && displace_focus)
1153 x += child_displacement_x;
1154 y += child_displacement_y;
1157 gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
1158 area, widget, "button",
1159 x, y, width, height);
1165 gtk_button_expose (GtkWidget *widget,
1166 GdkEventExpose *event)
1168 if (GTK_WIDGET_DRAWABLE (widget))
1170 GtkButton *button = GTK_BUTTON (widget);
1172 _gtk_button_paint (button, &event->area,
1173 GTK_WIDGET_STATE (widget),
1174 button->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
1175 "button", "buttondefault");
1177 (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
1184 gtk_button_button_press (GtkWidget *widget,
1185 GdkEventButton *event)
1189 if (event->type == GDK_BUTTON_PRESS)
1191 button = GTK_BUTTON (widget);
1193 if (button->focus_on_click && !GTK_WIDGET_HAS_FOCUS (widget))
1194 gtk_widget_grab_focus (widget);
1196 if (event->button == 1)
1197 gtk_button_pressed (button);
1204 gtk_button_button_release (GtkWidget *widget,
1205 GdkEventButton *event)
1209 if (event->button == 1)
1211 button = GTK_BUTTON (widget);
1212 gtk_button_released (button);
1219 gtk_button_key_release (GtkWidget *widget,
1222 GtkButton *button = GTK_BUTTON (widget);
1224 if (button->activate_timeout)
1226 gtk_button_finish_activate (button, TRUE);
1229 else if (GTK_WIDGET_CLASS (parent_class)->key_release_event)
1230 return GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
1236 gtk_button_enter_notify (GtkWidget *widget,
1237 GdkEventCrossing *event)
1240 GtkWidget *event_widget;
1242 button = GTK_BUTTON (widget);
1243 event_widget = gtk_get_event_widget ((GdkEvent*) event);
1245 if ((event_widget == widget) &&
1246 (event->detail != GDK_NOTIFY_INFERIOR))
1248 button->in_button = TRUE;
1249 gtk_button_enter (button);
1256 gtk_button_leave_notify (GtkWidget *widget,
1257 GdkEventCrossing *event)
1260 GtkWidget *event_widget;
1262 button = GTK_BUTTON (widget);
1263 event_widget = gtk_get_event_widget ((GdkEvent*) event);
1265 if ((event_widget == widget) &&
1266 (event->detail != GDK_NOTIFY_INFERIOR))
1268 button->in_button = FALSE;
1269 gtk_button_leave (button);
1276 gtk_real_button_pressed (GtkButton *button)
1278 if (button->activate_timeout)
1281 button->button_down = TRUE;
1282 gtk_button_update_state (button);
1286 gtk_real_button_released (GtkButton *button)
1288 if (button->button_down)
1290 button->button_down = FALSE;
1292 if (button->activate_timeout)
1295 if (button->in_button)
1296 gtk_button_clicked (button);
1298 gtk_button_update_state (button);
1303 button_activate_timeout (gpointer data)
1305 GDK_THREADS_ENTER ();
1307 gtk_button_finish_activate (data, TRUE);
1309 GDK_THREADS_LEAVE ();
1315 gtk_real_button_activate (GtkButton *button)
1317 GtkWidget *widget = GTK_WIDGET (button);
1319 if (GTK_WIDGET_REALIZED (button) && !button->activate_timeout)
1321 if (gdk_keyboard_grab (button->event_window, TRUE,
1322 gtk_get_current_event_time ()) == 0)
1324 gtk_grab_add (widget);
1326 button->activate_timeout = g_timeout_add (ACTIVATE_TIMEOUT,
1327 button_activate_timeout,
1329 button->button_down = TRUE;
1330 gtk_button_update_state (button);
1331 gtk_widget_queue_draw (GTK_WIDGET (button));
1337 gtk_button_finish_activate (GtkButton *button,
1340 GtkWidget *widget = GTK_WIDGET (button);
1342 g_source_remove (button->activate_timeout);
1343 button->activate_timeout = 0;
1345 gdk_display_keyboard_ungrab (gtk_widget_get_display (widget),
1346 gtk_get_current_event_time ());
1347 gtk_grab_remove (widget);
1349 button->button_down = FALSE;
1351 gtk_button_update_state (button);
1352 gtk_widget_queue_draw (GTK_WIDGET (button));
1355 gtk_button_clicked (button);
1359 * gtk_button_set_label:
1360 * @button: a #GtkButton
1363 * Sets the text of the label of the button to @str. This text is
1364 * also used to select the stock item if gtk_button_set_use_stock()
1367 * This will also clear any previously set labels.
1370 gtk_button_set_label (GtkButton *button,
1375 g_return_if_fail (GTK_IS_BUTTON (button));
1377 new_label = g_strdup (label);
1378 g_free (button->label_text);
1379 button->label_text = new_label;
1381 gtk_button_construct_child (button);
1383 g_object_notify (G_OBJECT (button), "label");
1387 * gtk_button_get_label:
1388 * @button: a #GtkButton
1390 * Fetches the text from the label of the button, as set by
1391 * gtk_button_set_label(). If the label text has not
1392 * been set the return value will be %NULL. This will be the
1393 * case if you create an empty button with gtk_button_new() to
1394 * use as a container.
1396 * Return value: The text of the label widget. This string is owned
1397 * by the widget and must not be modified or freed.
1399 G_CONST_RETURN gchar *
1400 gtk_button_get_label (GtkButton *button)
1402 g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
1404 return button->label_text;
1408 * gtk_button_set_use_underline:
1409 * @button: a #GtkButton
1410 * @use_underline: %TRUE if underlines in the text indicate mnemonics
1412 * If true, an underline in the text of the button label indicates
1413 * the next character should be used for the mnemonic accelerator key.
1416 gtk_button_set_use_underline (GtkButton *button,
1417 gboolean use_underline)
1419 g_return_if_fail (GTK_IS_BUTTON (button));
1421 use_underline = use_underline != FALSE;
1423 if (use_underline != button->use_underline)
1425 button->use_underline = use_underline;
1427 gtk_button_construct_child (button);
1429 g_object_notify (G_OBJECT (button), "use_underline");
1434 * gtk_button_get_use_underline:
1435 * @button: a #GtkButton
1437 * Returns whether an embedded underline in the button label indicates a
1438 * mnemonic. See gtk_button_set_use_underline ().
1440 * Return value: %TRUE if an embedded underline in the button label
1441 * indicates the mnemonic accelerator keys.
1444 gtk_button_get_use_underline (GtkButton *button)
1446 g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
1448 return button->use_underline;
1452 * gtk_button_set_use_stock:
1453 * @button: a #GtkButton
1454 * @use_stock: %TRUE if the button should use a stock item
1456 * If true, the label set on the button is used as a
1457 * stock id to select the stock item for the button.
1460 gtk_button_set_use_stock (GtkButton *button,
1463 g_return_if_fail (GTK_IS_BUTTON (button));
1465 use_stock = use_stock != FALSE;
1467 if (use_stock != button->use_stock)
1469 button->use_stock = use_stock;
1471 gtk_button_construct_child (button);
1473 g_object_notify (G_OBJECT (button), "use_stock");
1478 * gtk_button_get_use_stock:
1479 * @button: a #GtkButton
1481 * Returns whether the button label is a stock item.
1483 * Return value: %TRUE if the button label is used to
1484 * select a stock item instead of being
1485 * used directly as the label text.
1488 gtk_button_get_use_stock (GtkButton *button)
1490 g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
1492 return button->use_stock;
1496 * gtk_button_set_focus_on_click:
1497 * @button: a #GtkButton
1498 * @focus_on_click: whether the button grabs focus when clicked with the mouse
1500 * Sets whether the button will grab focus when it is clicked with the mouse.
1501 * Making mouse clicks not grab focus is useful in places like toolbars where
1502 * you don't want the keyboard focus removed from the main area of the
1508 gtk_button_set_focus_on_click (GtkButton *button,
1509 gboolean focus_on_click)
1511 g_return_if_fail (GTK_IS_BUTTON (button));
1513 focus_on_click = focus_on_click != FALSE;
1515 if (button->focus_on_click != focus_on_click)
1517 button->focus_on_click = focus_on_click;
1519 g_object_notify (G_OBJECT (button), "focus_on_click");
1524 * gtk_button_get_focus_on_click:
1525 * @button: a #GtkButton
1527 * Returns whether the button grabs focus when it is clicked with the mouse.
1528 * See gtk_button_set_focus_on_click().
1530 * Return value: %TRUE if the button grabs focus when it is clicked with
1536 gtk_button_get_focus_on_click (GtkButton *button)
1538 g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
1540 return button->focus_on_click;
1544 * gtk_button_set_alignment:
1545 * @button: a #GtkButton
1546 * @xalign: the horizontal position of the child, 0.0 is left aligned,
1547 * 1.0 is right aligned
1548 * @yalign: the vertical position of the child, 0.0 is top aligned,
1549 * 1.0 is bottom aligned
1551 * Sets the alignment of the child. This property has no effect unless
1552 * the child is a #GtkMisc or a #GtkAligment.
1557 gtk_button_set_alignment (GtkButton *button,
1561 GtkButtonPrivate *priv;
1563 g_return_if_fail (GTK_IS_BUTTON (button));
1565 priv = GTK_BUTTON_GET_PRIVATE (button);
1567 priv->xalign = xalign;
1568 priv->yalign = yalign;
1569 priv->align_set = 1;
1571 maybe_set_alignment (button, GTK_BIN (button)->child);
1573 g_object_freeze_notify (G_OBJECT (button));
1574 g_object_notify (G_OBJECT (button), "xalign");
1575 g_object_notify (G_OBJECT (button), "yalign");
1576 g_object_thaw_notify (G_OBJECT (button));
1580 * gtk_button_get_alignment:
1581 * @button: a #GtkButton
1582 * @xalign: return location for horizontal alignment
1583 * @yalign: return location for vertical alignment
1585 * Gets the alignment of the child in the button.
1590 gtk_button_get_alignment (GtkButton *button,
1594 GtkButtonPrivate *priv;
1596 g_return_if_fail (GTK_IS_BUTTON (button));
1598 priv = GTK_BUTTON_GET_PRIVATE (button);
1601 *xalign = priv->xalign;
1604 *yalign = priv->yalign;
1608 * _gtk_button_set_depressed:
1609 * @button: a #GtkButton
1610 * @depressed: %TRUE if the button should be drawn with a recessed shadow.
1612 * Sets whether the button is currently drawn as down or not. This is
1613 * purely a visual setting, and is meant only for use by derived widgets
1614 * such as #GtkToggleButton.
1617 _gtk_button_set_depressed (GtkButton *button,
1620 GtkWidget *widget = GTK_WIDGET (button);
1622 depressed = depressed != FALSE;
1624 if (depressed != button->depressed)
1626 button->depressed = depressed;
1627 gtk_widget_queue_resize (widget);
1632 gtk_button_update_state (GtkButton *button)
1635 GtkStateType new_state;
1637 if (button->activate_timeout)
1638 depressed = button->depress_on_activate;
1640 depressed = button->in_button && button->button_down;
1642 if (button->in_button && (!button->button_down || !depressed))
1643 new_state = GTK_STATE_PRELIGHT;
1645 new_state = depressed ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL;
1647 _gtk_button_set_depressed (button, depressed);
1648 gtk_widget_set_state (GTK_WIDGET (button), new_state);
1652 show_image_change_notify (GtkButton *button)
1654 GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
1658 if (show_image (button))
1659 gtk_widget_show (priv->image);
1661 gtk_widget_hide (priv->image);
1666 traverse_container (GtkWidget *widget,
1669 if (GTK_IS_BUTTON (widget))
1670 show_image_change_notify (GTK_BUTTON (widget));
1671 else if (GTK_IS_CONTAINER (widget))
1672 gtk_container_forall (GTK_CONTAINER (widget), traverse_container, NULL);
1676 gtk_button_setting_changed (GtkSettings *settings)
1680 list = gtk_window_list_toplevels ();
1682 for (l = list; l; l = l->next)
1683 gtk_container_forall (GTK_CONTAINER (l->data),
1684 traverse_container, NULL);
1691 gtk_button_screen_changed (GtkWidget *widget,
1692 GdkScreen *previous_screen)
1694 GtkSettings *settings;
1695 guint show_image_connection;
1697 if (!gtk_widget_has_screen (widget))
1700 settings = gtk_widget_get_settings (widget);
1702 show_image_connection =
1703 GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (settings),
1704 "gtk-button-connection"));
1706 if (show_image_connection)
1709 show_image_connection =
1710 g_signal_connect (settings, "notify::gtk-button-images",
1711 G_CALLBACK (gtk_button_setting_changed), 0);
1712 g_object_set_data (G_OBJECT (settings),
1713 "gtk-button-connection",
1714 GUINT_TO_POINTER (show_image_connection));
1716 show_image_change_notify (GTK_BUTTON (widget));
1720 gtk_button_state_changed (GtkWidget *widget,
1721 GtkStateType previous_state)
1723 GtkButton *button = GTK_BUTTON (widget);
1725 if (!GTK_WIDGET_IS_SENSITIVE (widget))
1727 button->in_button = FALSE;
1728 gtk_real_button_released (button);
1733 gtk_button_grab_notify (GtkWidget *widget,
1734 gboolean was_grabbed)
1736 GtkButton *button = GTK_BUTTON (widget);
1740 button->in_button = FALSE;
1741 gtk_real_button_released (button);
1746 * gtk_button_set_image:
1747 * @button: a #GtkButton
1748 * @image: a widget to set as the image for the button
1750 * Set the image of @button to the given widget. Note that
1751 * it depends on the gtk-button-images setting whether the
1752 * image will be displayed or not.
1757 gtk_button_set_image (GtkButton *button,
1760 GtkButtonPrivate *priv = GTK_BUTTON_GET_PRIVATE (button);
1762 priv->image = image;
1763 priv->image_is_stock = (image == NULL);
1765 gtk_button_construct_child (button);
1767 g_object_notify (G_OBJECT (button), "image");
1771 * gtk_button_get_image:
1772 * @button: a #GtkButton
1774 * Gets the widget that is currenty set as the image of @button.
1775 * This may have been explicitly set by gtk_button_set_image()
1776 * or constructed by gtk_button_new_from_stock().
1781 gtk_button_get_image (GtkButton *button)
1783 GtkButtonPrivate *priv;
1785 g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
1787 priv = GTK_BUTTON_GET_PRIVATE (button);
1792 #define __GTK_BUTTON_C__
1793 #include "gtkaliasdef.c"