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/.
28 #include "gtkalignment.h"
29 #include "gtkbutton.h"
32 #include "gtksignal.h"
36 #include "gtkiconfactory.h"
39 #define CHILD_SPACING 1
41 static GtkBorder default_default_border = { 1, 1, 1, 1 };
42 static GtkBorder default_default_outside_border = { 0, 0, 0, 0 };
44 /* Time out before giving up on getting a key release when animatng
47 #define ACTIVATE_TIMEOUT 250
67 static void gtk_button_class_init (GtkButtonClass *klass);
68 static void gtk_button_init (GtkButton *button);
69 static void gtk_button_set_property (GObject *object,
73 static void gtk_button_get_property (GObject *object,
77 static void gtk_button_realize (GtkWidget *widget);
78 static void gtk_button_unrealize (GtkWidget *widget);
79 static void gtk_button_size_request (GtkWidget *widget,
80 GtkRequisition *requisition);
81 static void gtk_button_size_allocate (GtkWidget *widget,
82 GtkAllocation *allocation);
83 static void gtk_button_paint (GtkWidget *widget,
85 static gint gtk_button_expose (GtkWidget *widget,
86 GdkEventExpose *event);
87 static gint gtk_button_button_press (GtkWidget *widget,
88 GdkEventButton *event);
89 static gint gtk_button_button_release (GtkWidget *widget,
90 GdkEventButton *event);
91 static gint gtk_button_key_release (GtkWidget *widget,
93 static gint gtk_button_enter_notify (GtkWidget *widget,
94 GdkEventCrossing *event);
95 static gint gtk_button_leave_notify (GtkWidget *widget,
96 GdkEventCrossing *event);
97 static void gtk_real_button_pressed (GtkButton *button);
98 static void gtk_real_button_released (GtkButton *button);
99 static void gtk_real_button_activate (GtkButton *button);
100 static void gtk_button_update_state (GtkButton *button);
101 static GtkType gtk_button_child_type (GtkContainer *container);
102 static void gtk_button_finish_activate (GtkButton *button,
105 static GObject* gtk_button_constructor (GType type,
106 guint n_construct_properties,
107 GObjectConstructParam *construct_params);
108 static void gtk_button_construct_child (GtkButton *button);
111 static GtkBinClass *parent_class = NULL;
112 static guint button_signals[LAST_SIGNAL] = { 0 };
116 gtk_button_get_type (void)
118 static GtkType button_type = 0;
122 static const GTypeInfo button_info =
124 sizeof (GtkButtonClass),
125 NULL, /* base_init */
126 NULL, /* base_finalize */
127 (GClassInitFunc) gtk_button_class_init,
128 NULL, /* class_finalize */
129 NULL, /* class_data */
131 16, /* n_preallocs */
132 (GInstanceInitFunc) gtk_button_init,
135 button_type = g_type_register_static (GTK_TYPE_BIN, "GtkButton", &button_info, 0);
142 gtk_button_class_init (GtkButtonClass *klass)
144 GObjectClass *g_object_class;
145 GtkObjectClass *object_class;
146 GtkWidgetClass *widget_class;
147 GtkContainerClass *container_class;
149 g_object_class = G_OBJECT_CLASS (klass);
150 object_class = (GtkObjectClass*) klass;
151 widget_class = (GtkWidgetClass*) klass;
152 container_class = (GtkContainerClass*) klass;
154 parent_class = g_type_class_peek_parent (klass);
156 g_object_class->constructor = gtk_button_constructor;
157 g_object_class->set_property = gtk_button_set_property;
158 g_object_class->get_property = gtk_button_get_property;
160 widget_class->realize = gtk_button_realize;
161 widget_class->unrealize = gtk_button_unrealize;
162 widget_class->size_request = gtk_button_size_request;
163 widget_class->size_allocate = gtk_button_size_allocate;
164 widget_class->expose_event = gtk_button_expose;
165 widget_class->button_press_event = gtk_button_button_press;
166 widget_class->button_release_event = gtk_button_button_release;
167 widget_class->key_release_event = gtk_button_key_release;
168 widget_class->enter_notify_event = gtk_button_enter_notify;
169 widget_class->leave_notify_event = gtk_button_leave_notify;
171 container_class->child_type = gtk_button_child_type;
173 klass->pressed = gtk_real_button_pressed;
174 klass->released = gtk_real_button_released;
175 klass->clicked = NULL;
176 klass->enter = gtk_button_update_state;
177 klass->leave = gtk_button_update_state;
178 klass->activate = gtk_real_button_activate;
180 g_object_class_install_property (G_OBJECT_CLASS(object_class),
182 g_param_spec_string ("label",
184 _("Text of the label widget inside the button, if the button contains a label widget."),
186 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
188 g_object_class_install_property (G_OBJECT_CLASS(object_class),
190 g_param_spec_boolean ("use_underline",
192 _("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
194 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
196 g_object_class_install_property (G_OBJECT_CLASS(object_class),
198 g_param_spec_boolean ("use_stock",
200 _("If set, the label is used to pick a stock item instead of being displayed"),
202 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
204 g_object_class_install_property (G_OBJECT_CLASS(object_class),
206 g_param_spec_enum ("relief",
208 _("The border relief style."),
209 GTK_TYPE_RELIEF_STYLE,
211 G_PARAM_READABLE | G_PARAM_WRITABLE));
213 button_signals[PRESSED] =
214 gtk_signal_new ("pressed",
216 GTK_CLASS_TYPE (object_class),
217 GTK_SIGNAL_OFFSET (GtkButtonClass, pressed),
218 gtk_marshal_VOID__VOID,
220 button_signals[RELEASED] =
221 gtk_signal_new ("released",
223 GTK_CLASS_TYPE (object_class),
224 GTK_SIGNAL_OFFSET (GtkButtonClass, released),
225 gtk_marshal_VOID__VOID,
227 button_signals[CLICKED] =
228 gtk_signal_new ("clicked",
229 GTK_RUN_FIRST | GTK_RUN_ACTION,
230 GTK_CLASS_TYPE (object_class),
231 GTK_SIGNAL_OFFSET (GtkButtonClass, clicked),
232 gtk_marshal_VOID__VOID,
234 button_signals[ENTER] =
235 gtk_signal_new ("enter",
237 GTK_CLASS_TYPE (object_class),
238 GTK_SIGNAL_OFFSET (GtkButtonClass, enter),
239 gtk_marshal_VOID__VOID,
241 button_signals[LEAVE] =
242 gtk_signal_new ("leave",
244 GTK_CLASS_TYPE (object_class),
245 GTK_SIGNAL_OFFSET (GtkButtonClass, leave),
246 gtk_marshal_VOID__VOID,
248 button_signals[ACTIVATE] =
249 gtk_signal_new ("activate",
251 GTK_CLASS_TYPE (object_class),
252 GTK_SIGNAL_OFFSET (GtkButtonClass, activate),
253 gtk_marshal_VOID__VOID,
255 widget_class->activate_signal = button_signals[ACTIVATE];
257 gtk_widget_class_install_style_property (widget_class,
258 g_param_spec_boxed ("default_border",
259 _("Default Spacing"),
260 _("Extra space to add for CAN_DEFAULT buttons"),
264 gtk_widget_class_install_style_property (widget_class,
265 g_param_spec_boxed ("default_outside_border",
266 _("Default Outside Spacing"),
267 _("Extra space to add for CAN_DEFAULT buttons that is always drawn outside the border"),
270 gtk_widget_class_install_style_property (widget_class,
271 g_param_spec_int ("child_displacement_x",
272 _("Child X Displacement"),
273 _("How far in the x direction to move the child when the button is depressed"),
278 gtk_widget_class_install_style_property (widget_class,
279 g_param_spec_int ("child_displacement_y",
280 _("Child Y Displacement"),
281 _("How far in the y direction to move the child when the button is depressed"),
289 gtk_button_init (GtkButton *button)
291 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_FOCUS | GTK_RECEIVES_DEFAULT);
292 GTK_WIDGET_UNSET_FLAGS (button, GTK_NO_WINDOW);
294 button->label_text = NULL;
296 button->constructed = FALSE;
297 button->in_button = FALSE;
298 button->button_down = FALSE;
299 button->relief = GTK_RELIEF_NORMAL;
300 button->use_stock = FALSE;
301 button->use_underline = FALSE;
302 button->depressed = FALSE;
306 gtk_button_constructor (GType type,
307 guint n_construct_properties,
308 GObjectConstructParam *construct_params)
313 object = (* G_OBJECT_CLASS (parent_class)->constructor) (type,
314 n_construct_properties,
317 button = GTK_BUTTON (object);
318 button->constructed = TRUE;
320 if (button->label_text != NULL)
321 gtk_button_construct_child (button);
328 gtk_button_child_type (GtkContainer *container)
330 if (!GTK_BIN (container)->child)
331 return GTK_TYPE_WIDGET;
333 return GTK_TYPE_NONE;
337 gtk_button_set_property (GObject *object,
344 button = GTK_BUTTON (object);
349 gtk_button_set_label (button, g_value_get_string (value));
352 gtk_button_set_relief (button, g_value_get_enum (value));
354 case PROP_USE_UNDERLINE:
355 gtk_button_set_use_underline (button, g_value_get_boolean (value));
358 gtk_button_set_use_stock (button, g_value_get_boolean (value));
361 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
367 gtk_button_get_property (GObject *object,
374 button = GTK_BUTTON (object);
379 g_value_set_string (value, button->label_text);
382 g_value_set_enum (value, gtk_button_get_relief (button));
384 case PROP_USE_UNDERLINE:
385 g_value_set_boolean (value, button->use_underline);
388 g_value_set_boolean (value, button->use_stock);
391 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
397 gtk_button_new (void)
399 return GTK_WIDGET (gtk_type_new (gtk_button_get_type ()));
403 gtk_button_construct_child (GtkButton *button)
411 if (!button->constructed)
414 if (button->label_text == NULL)
417 if (GTK_BIN (button)->child)
418 gtk_container_remove (GTK_CONTAINER (button),
419 GTK_BIN (button)->child);
422 if (button->use_stock &&
423 gtk_stock_lookup (button->label_text, &item))
425 label = gtk_label_new_with_mnemonic (item.label);
427 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
429 image = gtk_image_new_from_stock (button->label_text, GTK_ICON_SIZE_BUTTON);
430 hbox = gtk_hbox_new (FALSE, 2);
432 align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
434 gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
435 gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
437 gtk_container_add (GTK_CONTAINER (button), align);
438 gtk_container_add (GTK_CONTAINER (align), hbox);
439 gtk_widget_show_all (align);
444 if (button->use_underline)
446 label = gtk_label_new_with_mnemonic (button->label_text);
447 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
450 label = gtk_label_new (button->label_text);
452 gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
454 gtk_widget_show (label);
455 gtk_container_add (GTK_CONTAINER (button), label);
460 gtk_button_new_with_label (const gchar *label)
462 return g_object_new (GTK_TYPE_BUTTON, "label", label, NULL);
466 * gtk_button_new_from_stock:
467 * @stock_id: the name of the stock item
469 * Creates a new #GtkButton containing the image and text from a stock item.
470 * Some stock ids have preprocessor macros like #GTK_STOCK_OK and
473 * If @stock_id is unknown, then it will be treated as a mnemonic
474 * label (as for gtk_button_new_with_mnemonic()).
476 * Returns: a new #GtkButton
479 gtk_button_new_from_stock (const gchar *stock_id)
481 return g_object_new (GTK_TYPE_BUTTON,
484 "use_underline", TRUE,
489 * gtk_button_new_with_mnemonic:
490 * @label: The text of the button, with an underscore in front of the
492 * @returns: a new #GtkButton
494 * Creates a new #GtkButton containing a label.
495 * If characters in @label are preceded by an underscore, they are underlined
496 * indicating that they represent a keyboard accelerator called a mnemonic.
497 * Pressing Alt and that key activates the button.
500 gtk_button_new_with_mnemonic (const gchar *label)
502 return g_object_new (GTK_TYPE_BUTTON, "label", label, "use_underline", TRUE, NULL);
506 gtk_button_pressed (GtkButton *button)
508 g_return_if_fail (GTK_IS_BUTTON (button));
510 gtk_signal_emit (GTK_OBJECT (button), button_signals[PRESSED]);
514 gtk_button_released (GtkButton *button)
516 g_return_if_fail (GTK_IS_BUTTON (button));
518 gtk_signal_emit (GTK_OBJECT (button), button_signals[RELEASED]);
522 gtk_button_clicked (GtkButton *button)
524 g_return_if_fail (GTK_IS_BUTTON (button));
526 gtk_signal_emit (GTK_OBJECT (button), button_signals[CLICKED]);
530 gtk_button_enter (GtkButton *button)
532 g_return_if_fail (GTK_IS_BUTTON (button));
534 gtk_signal_emit (GTK_OBJECT (button), button_signals[ENTER]);
538 gtk_button_leave (GtkButton *button)
540 g_return_if_fail (GTK_IS_BUTTON (button));
542 gtk_signal_emit (GTK_OBJECT (button), button_signals[LEAVE]);
546 gtk_button_set_relief (GtkButton *button,
547 GtkReliefStyle newrelief)
549 g_return_if_fail (GTK_IS_BUTTON (button));
551 button->relief = newrelief;
552 g_object_notify(G_OBJECT(button), "relief");
553 gtk_widget_queue_draw (GTK_WIDGET (button));
557 gtk_button_get_relief (GtkButton *button)
559 g_return_val_if_fail (button != NULL, GTK_RELIEF_NORMAL);
560 g_return_val_if_fail (GTK_IS_BUTTON (button), GTK_RELIEF_NORMAL);
562 return button->relief;
566 gtk_button_realize (GtkWidget *widget)
569 GdkWindowAttr attributes;
570 gint attributes_mask;
573 g_return_if_fail (GTK_IS_BUTTON (widget));
575 button = GTK_BUTTON (widget);
576 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
578 border_width = GTK_CONTAINER (widget)->border_width;
580 attributes.window_type = GDK_WINDOW_CHILD;
581 attributes.x = widget->allocation.x + border_width;
582 attributes.y = widget->allocation.y + border_width;
583 attributes.width = widget->allocation.width - border_width * 2;
584 attributes.height = widget->allocation.height - border_width * 2;
585 attributes.wclass = GDK_INPUT_OUTPUT;
586 attributes.visual = gtk_widget_get_visual (widget);
587 attributes.colormap = gtk_widget_get_colormap (widget);
588 attributes.event_mask = gtk_widget_get_events (widget);
589 attributes.event_mask |= (GDK_EXPOSURE_MASK |
590 GDK_BUTTON_PRESS_MASK |
591 GDK_BUTTON_RELEASE_MASK |
592 GDK_ENTER_NOTIFY_MASK |
593 GDK_LEAVE_NOTIFY_MASK);
595 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
597 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
598 gdk_window_set_user_data (widget->window, button);
600 widget->style = gtk_style_attach (widget->style, widget->window);
601 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
605 gtk_button_unrealize (GtkWidget *widget)
607 GtkButton *button = GTK_BUTTON (widget);
609 if (button->activate_timeout)
610 gtk_button_finish_activate (button, FALSE);
612 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
616 gtk_button_get_props (GtkButton *button,
617 GtkBorder *default_border,
618 GtkBorder *default_outside_border,
619 gboolean *interior_focus)
621 GtkWidget *widget = GTK_WIDGET (button);
622 GtkBorder *tmp_border;
626 gtk_widget_style_get (widget, "default_border", &tmp_border, NULL);
630 *default_border = *tmp_border;
634 *default_border = default_default_border;
637 if (default_outside_border)
639 gtk_widget_style_get (widget, "default_outside_border", &tmp_border, NULL);
643 *default_outside_border = *tmp_border;
647 *default_outside_border = default_default_outside_border;
651 gtk_widget_style_get (widget, "interior_focus", interior_focus, NULL);
655 gtk_button_size_request (GtkWidget *widget,
656 GtkRequisition *requisition)
658 GtkButton *button = GTK_BUTTON (widget);
659 GtkBorder default_border;
660 gboolean interior_focus;
662 gtk_button_get_props (button, &default_border, NULL, &interior_focus);
664 requisition->width = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
665 GTK_WIDGET (widget)->style->xthickness) * 2;
666 requisition->height = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
667 GTK_WIDGET (widget)->style->ythickness) * 2;
669 if (GTK_WIDGET_CAN_DEFAULT (widget))
671 requisition->width += default_border.left + default_border.right;
672 requisition->height += default_border.top + default_border.bottom;
675 if (GTK_BIN (button)->child && GTK_WIDGET_VISIBLE (GTK_BIN (button)->child))
677 GtkRequisition child_requisition;
679 gtk_widget_size_request (GTK_BIN (button)->child, &child_requisition);
681 requisition->width += child_requisition.width;
682 requisition->height += child_requisition.height;
687 requisition->width += 2;
688 requisition->height += 2;
693 gtk_button_size_allocate (GtkWidget *widget,
694 GtkAllocation *allocation)
696 GtkButton *button = GTK_BUTTON (widget);
697 GtkAllocation child_allocation;
699 gint border_width = GTK_CONTAINER (widget)->border_width;
700 gint xthickness = GTK_WIDGET (widget)->style->xthickness;
701 gint ythickness = GTK_WIDGET (widget)->style->ythickness;
702 GtkBorder default_border;
704 gtk_button_get_props (button, &default_border, NULL, NULL);
706 widget->allocation = *allocation;
708 if (GTK_WIDGET_REALIZED (widget))
709 gdk_window_move_resize (widget->window,
710 widget->allocation.x + border_width,
711 widget->allocation.y + border_width,
712 widget->allocation.width - border_width * 2,
713 widget->allocation.height - border_width * 2);
715 if (GTK_BIN (button)->child && GTK_WIDGET_VISIBLE (GTK_BIN (button)->child))
717 child_allocation.x = (CHILD_SPACING + xthickness);
718 child_allocation.y = (CHILD_SPACING + ythickness);
720 child_allocation.width = MAX (1, (gint)widget->allocation.width - child_allocation.x * 2 -
722 child_allocation.height = MAX (1, (gint)widget->allocation.height - child_allocation.y * 2 -
725 if (GTK_WIDGET_CAN_DEFAULT (button))
727 child_allocation.x += default_border.left;
728 child_allocation.y += default_border.top;
729 child_allocation.width = MAX (1, child_allocation.width - default_border.left - default_border.right);
730 child_allocation.height = MAX (1, child_allocation.height - default_border.top - default_border.bottom);
733 if (button->depressed)
735 gint child_displacement_x;
736 gint child_displacement_y;
738 gtk_widget_style_get (widget,
739 "child_displacement_x", &child_displacement_x,
740 "child_displacement_y", &child_displacement_y,
742 child_allocation.x += child_displacement_x;
743 child_allocation.y += child_displacement_y;
746 gtk_widget_size_allocate (GTK_BIN (button)->child, &child_allocation);
751 * +------------------------------------------------+
753 * | +------------------------------------------+ |
754 * | |\\\\\\\\\\\\\\\\DEFAULT\\\\\\\\\\\\\\\\\ | |
755 * | |\\+------------------------------------+ | |
756 * | |\\| | SPACING 3 | | | |
757 * | |\\| +--------------------------------+ | | |
758 * | |\\| |########## FOCUS ###############| | | |
759 * | |\\| |#+----------------------------+#| | | |
760 * | |\\| |#| RELIEF \|#| | | |
761 * | |\\| |#| +-----------------------+\|#| | | |
762 * | |\\|1|#| + THE TEXT +\|#|2| | |
763 * | |\\| |#| +-----------------------+\|#| | | |
764 * | |\\| |#| \\\\\ ythickness \\\\\\\\\\|#| | | |
765 * | |\\| |#+----------------------------+#| | | |
766 * | |\\| |########### 1 ##################| | | |
767 * | |\\| +--------------------------------+ | | |
768 * | |\\| | default spacing 4 | | | |
769 * | |\\+------------------------------------+ | |
770 * | |\ ythickness | |
771 * | +------------------------------------------+ |
773 * +------------------------------------------------+
777 gtk_button_paint (GtkWidget *widget,
781 GtkShadowType shadow_type;
784 GtkBorder default_border;
785 GtkBorder default_outside_border;
786 gboolean interior_focus;
788 if (GTK_WIDGET_DRAWABLE (widget))
790 button = GTK_BUTTON (widget);
792 gtk_button_get_props (button, &default_border, &default_outside_border, &interior_focus);
796 width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2;
797 height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2;
799 gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
800 gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height);
802 if (GTK_WIDGET_HAS_DEFAULT (widget) &&
803 GTK_BUTTON (widget)->relief == GTK_RELIEF_NORMAL)
805 gtk_paint_box (widget->style, widget->window,
806 GTK_STATE_NORMAL, GTK_SHADOW_IN,
807 area, widget, "buttondefault",
808 x, y, width, height);
810 x += default_border.left;
811 y += default_border.top;
812 width -= default_border.left + default_border.right;
813 height -= default_border.top + default_border.bottom;
815 else if (GTK_WIDGET_CAN_DEFAULT (widget))
817 x += default_outside_border.left;
818 y += default_outside_border.top;
819 width -= default_outside_border.left + default_outside_border.right;
820 height -= default_outside_border.top + default_outside_border.bottom;
823 if (!interior_focus && GTK_WIDGET_HAS_FOCUS (widget))
831 shadow_type = button->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
833 if ((button->relief != GTK_RELIEF_NONE) ||
834 ((GTK_WIDGET_STATE(widget) != GTK_STATE_NORMAL) &&
835 (GTK_WIDGET_STATE(widget) != GTK_STATE_INSENSITIVE)))
836 gtk_paint_box (widget->style, widget->window,
837 GTK_WIDGET_STATE (widget),
838 shadow_type, area, widget, "button",
839 x, y, width, height);
841 if (GTK_WIDGET_HAS_FOCUS (widget))
845 x += widget->style->xthickness + 1;
846 y += widget->style->ythickness + 1;
847 width -= 2 * (widget->style->xthickness + 1);
848 height -= 2 * (widget->style->xthickness + 1);
858 gtk_paint_focus (widget->style, widget->window,
859 area, widget, "button",
860 x, y, width - 1, height - 1);
866 gtk_button_expose (GtkWidget *widget,
867 GdkEventExpose *event)
871 g_return_val_if_fail (widget != NULL, FALSE);
872 g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
873 g_return_val_if_fail (event != NULL, FALSE);
875 if (GTK_WIDGET_DRAWABLE (widget))
877 bin = GTK_BIN (widget);
879 gtk_button_paint (widget, &event->area);
881 (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
888 gtk_button_button_press (GtkWidget *widget,
889 GdkEventButton *event)
893 g_return_val_if_fail (widget != NULL, FALSE);
894 g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
895 g_return_val_if_fail (event != NULL, FALSE);
897 if (event->type == GDK_BUTTON_PRESS)
899 button = GTK_BUTTON (widget);
901 if (!GTK_WIDGET_HAS_FOCUS (widget))
902 gtk_widget_grab_focus (widget);
904 if (event->button == 1)
905 gtk_button_pressed (button);
912 gtk_button_button_release (GtkWidget *widget,
913 GdkEventButton *event)
917 g_return_val_if_fail (widget != NULL, FALSE);
918 g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
919 g_return_val_if_fail (event != NULL, FALSE);
921 if (event->button == 1)
923 button = GTK_BUTTON (widget);
924 gtk_button_released (button);
931 gtk_button_key_release (GtkWidget *widget,
934 GtkButton *button = GTK_BUTTON (widget);
936 if (button->activate_timeout)
938 gtk_button_finish_activate (button, TRUE);
941 else if (GTK_WIDGET_CLASS (parent_class)->key_release_event)
942 return GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
948 gtk_button_enter_notify (GtkWidget *widget,
949 GdkEventCrossing *event)
952 GtkWidget *event_widget;
954 g_return_val_if_fail (widget != NULL, FALSE);
955 g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
956 g_return_val_if_fail (event != NULL, FALSE);
958 button = GTK_BUTTON (widget);
959 event_widget = gtk_get_event_widget ((GdkEvent*) event);
961 if ((event_widget == widget) &&
962 (event->detail != GDK_NOTIFY_INFERIOR))
964 button->in_button = TRUE;
965 gtk_button_enter (button);
972 gtk_button_leave_notify (GtkWidget *widget,
973 GdkEventCrossing *event)
976 GtkWidget *event_widget;
978 g_return_val_if_fail (widget != NULL, FALSE);
979 g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
980 g_return_val_if_fail (event != NULL, FALSE);
982 button = GTK_BUTTON (widget);
983 event_widget = gtk_get_event_widget ((GdkEvent*) event);
985 if ((event_widget == widget) &&
986 (event->detail != GDK_NOTIFY_INFERIOR))
988 button->in_button = FALSE;
989 gtk_button_leave (button);
996 gtk_real_button_pressed (GtkButton *button)
998 if (button->activate_timeout)
1001 button->button_down = TRUE;
1002 gtk_button_update_state (button);
1006 gtk_real_button_released (GtkButton *button)
1008 if (button->button_down)
1010 button->button_down = FALSE;
1012 if (button->activate_timeout)
1015 if (button->in_button)
1016 gtk_button_clicked (button);
1018 gtk_button_update_state (button);
1023 button_activate_timeout (gpointer data)
1025 GDK_THREADS_ENTER ();
1027 gtk_button_finish_activate (data, TRUE);
1029 GDK_THREADS_LEAVE ();
1035 gtk_real_button_activate (GtkButton *button)
1037 GtkWidget *widget = GTK_WIDGET (button);
1039 g_return_if_fail (GTK_IS_BUTTON (button));
1041 if (GTK_WIDGET_REALIZED (button) && !button->activate_timeout)
1043 if (gdk_keyboard_grab (widget->window, TRUE,
1044 gtk_get_current_event_time ()) == 0)
1046 gtk_grab_add (widget);
1048 button->activate_timeout = g_timeout_add (ACTIVATE_TIMEOUT,
1049 button_activate_timeout,
1051 button->button_down = TRUE;
1052 gtk_button_update_state (button);
1058 gtk_button_finish_activate (GtkButton *button,
1061 GtkWidget *widget = GTK_WIDGET (button);
1063 g_source_remove (button->activate_timeout);
1064 button->activate_timeout = 0;
1066 gdk_keyboard_ungrab (gtk_get_current_event_time ());
1067 gtk_grab_remove (widget);
1069 button->button_down = FALSE;
1071 gtk_button_update_state (button);
1074 gtk_button_clicked (button);
1078 * gtk_button_set_label:
1079 * @button: a #GtkButton
1082 * Sets the text of the label of the button to @str. This text is
1083 * also used to select the stock item if gtk_button_set_use_stock()
1086 * This will also clear any previously set labels.
1089 gtk_button_set_label (GtkButton *button,
1092 g_return_if_fail (GTK_IS_BUTTON (button));
1094 g_free (button->label_text);
1095 button->label_text = g_strdup (label);
1097 gtk_button_construct_child (button);
1099 g_object_notify (G_OBJECT (button), "label");
1103 * gtk_button_get_label:
1104 * @button: a #GtkButton
1106 * Fetches the text from the label of the button, as set by
1107 * gtk_button_set_label().
1109 * Return value: the text of the label widget. This string is
1110 * owned by the widget and must not be modified or freed.
1111 * If the label text has not been set the return value
1112 * will be NULL. This will be the case if you create an
1113 * empty button with gtk_button_new() to use as a container.
1115 G_CONST_RETURN gchar *
1116 gtk_button_get_label (GtkButton *button)
1118 g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
1120 return button->label_text;
1124 * gtk_button_set_use_underline:
1125 * @button: a #GtkButton
1126 * @use_underline: %TRUE if underlines in the text indicate mnemonics
1128 * If true, an underline in the text of the button label indicates
1129 * the next character should be used for the mnemonic accelerator key.
1132 gtk_button_set_use_underline (GtkButton *button,
1133 gboolean use_underline)
1135 g_return_if_fail (GTK_IS_BUTTON (button));
1137 use_underline = use_underline != FALSE;
1139 if (use_underline != button->use_underline)
1141 button->use_underline = use_underline;
1143 gtk_button_construct_child (button);
1145 g_object_notify (G_OBJECT (button), "use_underline");
1150 * gtk_button_get_use_underline:
1151 * @button: a #GtkButton
1153 * Returns whether an embedded underline in the button label indicates a
1154 * mnemonic. See gtk_button_set_use_underline ().
1156 * Return value: %TRUE if an embedded underline in the button label
1157 * indicates the mnemonic accelerator keys.
1160 gtk_button_get_use_underline (GtkButton *button)
1162 g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
1164 return button->use_underline;
1168 * gtk_button_set_use_stock:
1169 * @button: a #GtkButton
1170 * @use_stock: %TRUE if the button should use a stock item
1172 * If true, the label set on the button is used as a
1173 * stock id to select the stock item for the button.
1176 gtk_button_set_use_stock (GtkButton *button,
1179 g_return_if_fail (GTK_IS_BUTTON (button));
1181 use_stock = use_stock != FALSE;
1183 if (use_stock != button->use_stock)
1185 button->use_stock = use_stock;
1187 gtk_button_construct_child (button);
1189 g_object_notify (G_OBJECT (button), "use_stock");
1194 * gtk_button_get_use_stock:
1195 * @button: a #GtkButton
1197 * Returns whether the button label is a stock item.
1199 * Return value: %TRUE if the button label is used to
1200 * select a stock item instead of being
1201 * used directly as the label text.
1204 gtk_button_get_use_stock (GtkButton *button)
1206 g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
1208 return button->use_stock;
1212 * _gtk_button_set_depressed:
1213 * @button: a #GtkButton
1214 * @depressed: %TRUE if the button should be drawn with a recessed shadow.
1216 * Sets whether the button is currently drawn as down or not. This is
1217 * purely a visual setting, and is meant only for use by derived widgets
1218 * such as #GtkToggleButton.
1221 _gtk_button_set_depressed (GtkButton *button,
1224 GtkWidget *widget = GTK_WIDGET (button);
1226 depressed = depressed != FALSE;
1228 if (depressed != button->depressed)
1230 button->depressed = depressed;
1231 gtk_widget_queue_resize (widget);
1236 gtk_button_update_state (GtkButton *button)
1239 GtkStateType new_state;
1241 depressed = button->button_down && (button->in_button || button->activate_timeout);
1243 if (!button->button_down && button->in_button)
1244 new_state = GTK_STATE_PRELIGHT;
1246 new_state = depressed ? GTK_STATE_ACTIVE: GTK_STATE_NORMAL;
1248 _gtk_button_set_depressed (button, depressed);
1249 gtk_widget_set_state (GTK_WIDGET (button), new_state);