]> Pileus Git - ~andy/gtk/blob - gtk/gtkbutton.c
Add properties for labels, mnemonics and stock items. Added C accessor
[~andy/gtk] / gtk / gtkbutton.c
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 <string.h>
28 #include "gtkbutton.h"
29 #include "gtklabel.h"
30 #include "gtkmain.h"
31 #include "gtksignal.h"
32 #include "gtkimage.h"
33 #include "gtkhbox.h"
34 #include "gtkstock.h"
35 #include "gtkiconfactory.h"
36 #include "gtkintl.h"
37
38 #define CHILD_SPACING     1
39
40 static GtkBorder default_default_border = { 1, 1, 1, 1 };
41 static GtkBorder default_default_outside_border = { 0, 0, 0, 0 };
42
43 /* Time out before giving up on getting a key release when animatng
44  * the close button.
45  */
46 #define ACTIVATE_TIMEOUT 250
47
48 enum {
49   PRESSED,
50   RELEASED,
51   CLICKED,
52   ENTER,
53   LEAVE,
54   ACTIVATE,
55   LAST_SIGNAL
56 };
57
58 enum {
59   PROP_0,
60   PROP_LABEL,
61   PROP_RELIEF,
62   PROP_USE_UNDERLINE,
63   PROP_USE_STOCK
64 };
65
66 static void gtk_button_class_init     (GtkButtonClass   *klass);
67 static void gtk_button_init           (GtkButton        *button);
68 static void gtk_button_set_property   (GObject         *object,
69                                        guint            prop_id,
70                                        const GValue    *value,
71                                        GParamSpec      *pspec);
72 static void gtk_button_get_property   (GObject         *object,
73                                        guint            prop_id,
74                                        GValue          *value,
75                                        GParamSpec      *pspec);
76 static void gtk_button_realize        (GtkWidget        *widget);
77 static void gtk_button_unrealize      (GtkWidget        *widget);
78 static void gtk_button_size_request   (GtkWidget        *widget,
79                                        GtkRequisition   *requisition);
80 static void gtk_button_size_allocate  (GtkWidget        *widget,
81                                        GtkAllocation    *allocation);
82 static void gtk_button_paint          (GtkWidget        *widget,
83                                        GdkRectangle     *area);
84 static gint gtk_button_expose         (GtkWidget        *widget,
85                                        GdkEventExpose   *event);
86 static gint gtk_button_button_press   (GtkWidget        *widget,
87                                        GdkEventButton   *event);
88 static gint gtk_button_button_release (GtkWidget        *widget,
89                                        GdkEventButton   *event);
90 static gint gtk_button_key_release    (GtkWidget        *widget,
91                                        GdkEventKey      *event);
92 static gint gtk_button_enter_notify   (GtkWidget        *widget,
93                                        GdkEventCrossing *event);
94 static gint gtk_button_leave_notify   (GtkWidget        *widget,
95                                        GdkEventCrossing *event);
96 static void gtk_real_button_pressed   (GtkButton        *button);
97 static void gtk_real_button_released  (GtkButton        *button);
98 static void gtk_real_button_activate (GtkButton         *button);
99 static void gtk_button_update_state   (GtkButton        *button);
100 static GtkType gtk_button_child_type  (GtkContainer     *container);
101 static void gtk_button_finish_activate (GtkButton *button,
102                                         gboolean   do_it);
103
104 static GObject* gtk_button_constructor     (GType                  type,
105                                             guint                  n_construct_properties,
106                                             GObjectConstructParam *construct_params);
107 static void     gtk_button_construct_child (GtkButton             *button);
108
109
110 static GtkBinClass *parent_class = NULL;
111 static guint button_signals[LAST_SIGNAL] = { 0 };
112
113
114 GtkType
115 gtk_button_get_type (void)
116 {
117   static GtkType button_type = 0;
118
119   if (!button_type)
120     {
121       static const GTypeInfo button_info =
122       {
123         sizeof (GtkButtonClass),
124         NULL,           /* base_init */
125         NULL,           /* base_finalize */
126         (GClassInitFunc) gtk_button_class_init,
127         NULL,           /* class_finalize */
128         NULL,           /* class_data */
129         sizeof (GtkButton),
130         16,             /* n_preallocs */
131         (GInstanceInitFunc) gtk_button_init,
132       };
133
134       button_type = g_type_register_static (GTK_TYPE_BIN, "GtkButton", &button_info, 0);
135     }
136
137   return button_type;
138 }
139
140 static void
141 gtk_button_class_init (GtkButtonClass *klass)
142 {
143   GObjectClass *g_object_class;
144   GtkObjectClass *object_class;
145   GtkWidgetClass *widget_class;
146   GtkContainerClass *container_class;
147
148   g_object_class = G_OBJECT_CLASS (klass);
149   object_class = (GtkObjectClass*) klass;
150   widget_class = (GtkWidgetClass*) klass;
151   container_class = (GtkContainerClass*) klass;
152   
153   parent_class = g_type_class_peek_parent (klass);
154
155   g_object_class->constructor = gtk_button_constructor;
156   g_object_class->set_property = gtk_button_set_property;
157   g_object_class->get_property = gtk_button_get_property;
158
159   widget_class->realize = gtk_button_realize;
160   widget_class->unrealize = gtk_button_unrealize;
161   widget_class->size_request = gtk_button_size_request;
162   widget_class->size_allocate = gtk_button_size_allocate;
163   widget_class->expose_event = gtk_button_expose;
164   widget_class->button_press_event = gtk_button_button_press;
165   widget_class->button_release_event = gtk_button_button_release;
166   widget_class->key_release_event = gtk_button_key_release;
167   widget_class->enter_notify_event = gtk_button_enter_notify;
168   widget_class->leave_notify_event = gtk_button_leave_notify;
169
170   container_class->child_type = gtk_button_child_type;
171
172   klass->pressed = gtk_real_button_pressed;
173   klass->released = gtk_real_button_released;
174   klass->clicked = NULL;
175   klass->enter = gtk_button_update_state;
176   klass->leave = gtk_button_update_state;
177   klass->activate = gtk_real_button_activate;
178
179   g_object_class_install_property (G_OBJECT_CLASS(object_class),
180                                    PROP_LABEL,
181                                    g_param_spec_string ("label",
182                                                         _("Label"),
183                                                         _("Text of the label widget inside the button, if the button contains a label widget."),
184                                                         NULL,
185                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
186   
187   g_object_class_install_property (G_OBJECT_CLASS(object_class),
188                                    PROP_USE_UNDERLINE,
189                                    g_param_spec_boolean ("use_underline",
190                                                          _("Use underline"),
191                                                          _("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
192                                                         FALSE,
193                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
194   
195   g_object_class_install_property (G_OBJECT_CLASS(object_class),
196                                    PROP_USE_STOCK,
197                                    g_param_spec_boolean ("use_stock",
198                                                          _("Use stock"),
199                                                          _("If set, the label is used to pick a stock item instead of being displayed"),
200                                                         FALSE,
201                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
202   
203   g_object_class_install_property (G_OBJECT_CLASS(object_class),
204                                    PROP_RELIEF,
205                                    g_param_spec_enum ("relief",
206                                                       _("Border relief"),
207                                                       _("The border relief style."),
208                                                       GTK_TYPE_RELIEF_STYLE,
209                                                       GTK_RELIEF_NORMAL,
210                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
211
212   button_signals[PRESSED] =
213     gtk_signal_new ("pressed",
214                     GTK_RUN_FIRST,
215                     GTK_CLASS_TYPE (object_class),
216                     GTK_SIGNAL_OFFSET (GtkButtonClass, pressed),
217                     gtk_marshal_VOID__VOID,
218                     GTK_TYPE_NONE, 0);
219   button_signals[RELEASED] =
220     gtk_signal_new ("released",
221                     GTK_RUN_FIRST,
222                     GTK_CLASS_TYPE (object_class),
223                     GTK_SIGNAL_OFFSET (GtkButtonClass, released),
224                     gtk_marshal_VOID__VOID,
225                     GTK_TYPE_NONE, 0);
226   button_signals[CLICKED] =
227     gtk_signal_new ("clicked",
228                     GTK_RUN_FIRST | GTK_RUN_ACTION,
229                     GTK_CLASS_TYPE (object_class),
230                     GTK_SIGNAL_OFFSET (GtkButtonClass, clicked),
231                     gtk_marshal_VOID__VOID,
232                     GTK_TYPE_NONE, 0);
233   button_signals[ENTER] =
234     gtk_signal_new ("enter",
235                     GTK_RUN_FIRST,
236                     GTK_CLASS_TYPE (object_class),
237                     GTK_SIGNAL_OFFSET (GtkButtonClass, enter),
238                     gtk_marshal_VOID__VOID,
239                     GTK_TYPE_NONE, 0);
240   button_signals[LEAVE] =
241     gtk_signal_new ("leave",
242                     GTK_RUN_FIRST,
243                     GTK_CLASS_TYPE (object_class),
244                     GTK_SIGNAL_OFFSET (GtkButtonClass, leave),
245                     gtk_marshal_VOID__VOID,
246                     GTK_TYPE_NONE, 0);
247   button_signals[ACTIVATE] =
248     gtk_signal_new ("activate",
249                     GTK_RUN_FIRST,
250                     GTK_CLASS_TYPE (object_class),
251                     GTK_SIGNAL_OFFSET (GtkButtonClass, activate),
252                     gtk_marshal_VOID__VOID,
253                     GTK_TYPE_NONE, 0);
254   widget_class->activate_signal = button_signals[ACTIVATE];
255
256   gtk_widget_class_install_style_property (widget_class,
257                                            g_param_spec_boxed ("default_border",
258                                                                _("Default Spacing"),
259                                                                _("Extra space to add for CAN_DEFAULT buttons"),
260                                                                GTK_TYPE_BORDER,
261                                                                G_PARAM_READABLE));
262
263   gtk_widget_class_install_style_property (widget_class,
264                                            g_param_spec_boxed ("default_outside_border",
265                                                                _("Default Outside Spacing"),
266                                                                _("Extra space to add for CAN_DEFAULT buttons that is always drawn outside the border"),
267                                                                GTK_TYPE_BORDER,
268                                                                G_PARAM_READABLE));
269   gtk_widget_class_install_style_property (widget_class,
270                                            g_param_spec_int ("child_displacement_x",
271                                                              _("Child X Displacement"),
272                                                              _("How far in the x direction to move the child when the button is depressed"),
273                                                              G_MININT,
274                                                              G_MAXINT,
275                                                              0,
276                                                              G_PARAM_READABLE));
277   gtk_widget_class_install_style_property (widget_class,
278                                            g_param_spec_int ("child_displacement_y",
279                                                              _("Child Y Displacement"),
280                                                              _("How far in the y direction to move the child when the button is depressed"),
281                                                              G_MININT,
282                                                              G_MAXINT,
283                                                              0,
284                                                              G_PARAM_READABLE));
285 }
286
287 static void
288 gtk_button_init (GtkButton *button)
289 {
290   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_FOCUS | GTK_RECEIVES_DEFAULT);
291   GTK_WIDGET_UNSET_FLAGS (button, GTK_NO_WINDOW);
292
293   button->label_text = NULL;
294   
295   button->constructed = FALSE;
296   button->in_button = FALSE;
297   button->button_down = FALSE;
298   button->relief = GTK_RELIEF_NORMAL;
299   button->use_stock = FALSE;
300   button->use_underline = FALSE;
301   button->depressed = FALSE;
302 }
303
304 static GObject*
305 gtk_button_constructor (GType                  type,
306                         guint                  n_construct_properties,
307                         GObjectConstructParam *construct_params)
308 {
309   GObject *object;
310   GtkButton *button;
311
312   object = (* G_OBJECT_CLASS (parent_class)->constructor) (type,
313                                                            n_construct_properties,
314                                                            construct_params);
315
316   button = GTK_BUTTON (object);
317   button->constructed = TRUE;
318
319   if (button->label_text != NULL)
320     gtk_button_construct_child (button);
321   
322   return object;
323 }
324
325
326 static GtkType
327 gtk_button_child_type  (GtkContainer     *container)
328 {
329   if (!GTK_BIN (container)->child)
330     return GTK_TYPE_WIDGET;
331   else
332     return GTK_TYPE_NONE;
333 }
334
335 static void
336 gtk_button_set_property (GObject         *object,
337                          guint            prop_id,
338                          const GValue    *value,
339                          GParamSpec      *pspec)
340 {
341   GtkButton *button;
342
343   button = GTK_BUTTON (object);
344
345   switch (prop_id)
346     {
347     case PROP_LABEL:
348       gtk_button_set_label (button, g_value_get_string (value));
349       break;
350     case PROP_RELIEF:
351       gtk_button_set_relief (button, g_value_get_enum (value));
352       break;
353     case PROP_USE_UNDERLINE:
354       gtk_button_set_use_underline (button, g_value_get_boolean (value));
355       break;
356     case PROP_USE_STOCK:
357       gtk_button_set_use_stock (button, g_value_get_boolean (value));
358       break;
359     default:
360       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
361       break;
362     }
363 }
364
365 static void
366 gtk_button_get_property (GObject         *object,
367                          guint            prop_id,
368                          GValue          *value,
369                          GParamSpec      *pspec)
370 {
371   GtkButton *button;
372
373   button = GTK_BUTTON (object);
374
375   switch (prop_id)
376     {
377     case PROP_LABEL:
378       g_value_set_string (value, button->label_text);
379       break;
380     case PROP_RELIEF:
381       g_value_set_enum (value, gtk_button_get_relief (button));
382       break;
383     case PROP_USE_UNDERLINE:
384       g_value_set_boolean (value, button->use_underline);
385       break;
386     case PROP_USE_STOCK:
387       g_value_set_boolean (value, button->use_stock);
388       break;
389     default:
390       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
391       break;
392     }
393 }
394
395 GtkWidget*
396 gtk_button_new (void)
397 {
398   return GTK_WIDGET (gtk_type_new (gtk_button_get_type ()));
399 }
400
401 static void
402 gtk_button_construct_child (GtkButton *button)
403 {
404   GtkStockItem item;
405   GtkWidget *label;
406   GtkWidget *image;
407   GtkWidget *hbox;
408
409   if (!button->constructed)
410     return;
411   
412   if (button->label_text == NULL)
413     return;
414
415   if (GTK_BIN (button)->child)
416     gtk_container_remove (GTK_CONTAINER (button),
417                           GTK_BIN (button)->child);
418
419   
420   if (button->use_stock &&
421       gtk_stock_lookup (button->label_text, &item))
422     {
423       label = gtk_label_new_with_mnemonic (item.label);
424
425       gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
426       
427       image = gtk_image_new_from_stock (button->label_text, GTK_ICON_SIZE_BUTTON);
428       hbox = gtk_hbox_new (FALSE, 1);
429
430       gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
431       gtk_box_pack_end (GTK_BOX (hbox), label, TRUE, TRUE, 0);
432       
433       gtk_container_add (GTK_CONTAINER (button), hbox);
434       gtk_widget_show_all (hbox);
435
436       return;
437     }
438
439   if (button->use_underline)
440     {
441       label = gtk_label_new_with_mnemonic (button->label_text);
442       gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
443     }
444   else
445     label = gtk_label_new (button->label_text);
446   
447   gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
448
449   gtk_widget_show (label);
450   gtk_container_add (GTK_CONTAINER (button), label);
451 }
452
453
454 GtkWidget*
455 gtk_button_new_with_label (const gchar *label)
456 {
457   return g_object_new (GTK_TYPE_BUTTON, "label", label, NULL);
458 }
459
460 /**
461  * gtk_button_new_from_stock:
462  * @stock_id: the name of the stock item 
463  * @returns: a new #GtkButton
464  *
465  * Creates a new #GtkButton containing the image and text from a stock item.
466  * Some stock ids have preprocessor macros like #GTK_STOCK_OK and
467  * #GTK_STOCK_APPLY.
468  **/
469 GtkWidget*
470 gtk_button_new_from_stock (const gchar   *stock_id)
471 {
472   return g_object_new (GTK_TYPE_BUTTON, "label", stock_id, "use_stock", TRUE,  NULL);
473 }
474
475 /**
476  * gtk_button_new_with_mnemonic:
477  * @label: The text of the button, with an underscore in front of the
478  *         mnemonic character
479  * @returns: a new #GtkButton
480  *
481  * Creates a new #GtkButton containing a label.
482  * If characters in @label are preceded by an underscore, they are underlined
483  * indicating that they represent a keyboard accelerator called a mnemonic.
484  * Pressing Alt and that key activates the button.
485  **/
486 GtkWidget*
487 gtk_button_new_with_mnemonic (const gchar *label)
488 {
489   return g_object_new (GTK_TYPE_BUTTON, "label", label, "use_underline", TRUE,  NULL);
490 }
491
492 void
493 gtk_button_pressed (GtkButton *button)
494 {
495   g_return_if_fail (GTK_IS_BUTTON (button));
496
497   gtk_signal_emit (GTK_OBJECT (button), button_signals[PRESSED]);
498 }
499
500 void
501 gtk_button_released (GtkButton *button)
502 {
503   g_return_if_fail (GTK_IS_BUTTON (button));
504
505   gtk_signal_emit (GTK_OBJECT (button), button_signals[RELEASED]);
506 }
507
508 void
509 gtk_button_clicked (GtkButton *button)
510 {
511   g_return_if_fail (GTK_IS_BUTTON (button));
512
513   gtk_signal_emit (GTK_OBJECT (button), button_signals[CLICKED]);
514 }
515
516 void
517 gtk_button_enter (GtkButton *button)
518 {
519   g_return_if_fail (GTK_IS_BUTTON (button));
520
521   gtk_signal_emit (GTK_OBJECT (button), button_signals[ENTER]);
522 }
523
524 void
525 gtk_button_leave (GtkButton *button)
526 {
527   g_return_if_fail (GTK_IS_BUTTON (button));
528
529   gtk_signal_emit (GTK_OBJECT (button), button_signals[LEAVE]);
530 }
531
532 void
533 gtk_button_set_relief (GtkButton *button,
534                        GtkReliefStyle newrelief)
535 {
536   g_return_if_fail (GTK_IS_BUTTON (button));
537
538   button->relief = newrelief;
539   g_object_notify(G_OBJECT(button), "relief");
540   gtk_widget_queue_draw (GTK_WIDGET (button));
541 }
542
543 GtkReliefStyle
544 gtk_button_get_relief (GtkButton *button)
545 {
546   g_return_val_if_fail (button != NULL, GTK_RELIEF_NORMAL);
547   g_return_val_if_fail (GTK_IS_BUTTON (button), GTK_RELIEF_NORMAL);
548
549   return button->relief;
550 }
551
552 static void
553 gtk_button_realize (GtkWidget *widget)
554 {
555   GtkButton *button;
556   GdkWindowAttr attributes;
557   gint attributes_mask;
558   gint border_width;
559
560   g_return_if_fail (GTK_IS_BUTTON (widget));
561
562   button = GTK_BUTTON (widget);
563   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
564
565   border_width = GTK_CONTAINER (widget)->border_width;
566
567   attributes.window_type = GDK_WINDOW_CHILD;
568   attributes.x = widget->allocation.x + border_width;
569   attributes.y = widget->allocation.y + border_width;
570   attributes.width = widget->allocation.width - border_width * 2;
571   attributes.height = widget->allocation.height - border_width * 2;
572   attributes.wclass = GDK_INPUT_OUTPUT;
573   attributes.visual = gtk_widget_get_visual (widget);
574   attributes.colormap = gtk_widget_get_colormap (widget);
575   attributes.event_mask = gtk_widget_get_events (widget);
576   attributes.event_mask |= (GDK_EXPOSURE_MASK |
577                             GDK_BUTTON_PRESS_MASK |
578                             GDK_BUTTON_RELEASE_MASK |
579                             GDK_ENTER_NOTIFY_MASK |
580                             GDK_LEAVE_NOTIFY_MASK);
581
582   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
583
584   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
585   gdk_window_set_user_data (widget->window, button);
586
587   widget->style = gtk_style_attach (widget->style, widget->window);
588   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
589 }
590
591 static void
592 gtk_button_unrealize (GtkWidget *widget)
593 {
594   GtkButton *button = GTK_BUTTON (widget);
595
596   if (button->activate_timeout)
597     gtk_button_finish_activate (button, FALSE);
598     
599   GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
600 }
601
602 static void
603 gtk_button_get_props (GtkButton *button,
604                       GtkBorder *default_border,
605                       GtkBorder *default_outside_border,
606                       gboolean  *interior_focus)
607 {
608   GtkWidget *widget =  GTK_WIDGET (button);
609   GtkBorder *tmp_border;
610
611   if (default_border)
612     {
613       gtk_widget_style_get (widget, "default_border", &tmp_border, NULL);
614
615       if (tmp_border)
616         {
617           *default_border = *tmp_border;
618           g_free (tmp_border);
619         }
620       else
621         *default_border = default_default_border;
622     }
623
624   if (default_outside_border)
625     {
626       gtk_widget_style_get (widget, "default_outside_border", &tmp_border, NULL);
627
628       if (tmp_border)
629         {
630           *default_outside_border = *tmp_border;
631           g_free (tmp_border);
632         }
633       else
634         *default_outside_border = default_default_outside_border;
635     }
636
637   if (interior_focus)
638     gtk_widget_style_get (widget, "interior_focus", interior_focus, NULL);
639 }
640         
641 static void
642 gtk_button_size_request (GtkWidget      *widget,
643                          GtkRequisition *requisition)
644 {
645   GtkButton *button = GTK_BUTTON (widget);
646   GtkBorder default_border;
647   gboolean interior_focus;
648
649   gtk_button_get_props (button, &default_border, NULL, &interior_focus);
650   
651   requisition->width = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
652                         GTK_WIDGET (widget)->style->xthickness) * 2;
653   requisition->height = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
654                          GTK_WIDGET (widget)->style->ythickness) * 2;
655
656   if (GTK_WIDGET_CAN_DEFAULT (widget))
657     {
658       requisition->width += default_border.left + default_border.right;
659       requisition->height += default_border.top + default_border.bottom;
660     }
661
662   if (GTK_BIN (button)->child && GTK_WIDGET_VISIBLE (GTK_BIN (button)->child))
663     {
664       GtkRequisition child_requisition;
665
666       gtk_widget_size_request (GTK_BIN (button)->child, &child_requisition);
667
668       requisition->width += child_requisition.width;
669       requisition->height += child_requisition.height;
670     }
671
672   if (interior_focus)
673     {
674       requisition->width += 2;
675       requisition->height += 2;
676     }
677 }
678
679 static void
680 gtk_button_size_allocate (GtkWidget     *widget,
681                           GtkAllocation *allocation)
682 {
683   GtkButton *button = GTK_BUTTON (widget);
684   GtkAllocation child_allocation;
685
686   gint border_width = GTK_CONTAINER (widget)->border_width;
687   gint xthickness = GTK_WIDGET (widget)->style->xthickness;
688   gint ythickness = GTK_WIDGET (widget)->style->ythickness;
689   GtkBorder default_border;
690
691   gtk_button_get_props (button, &default_border, NULL, NULL);
692   
693   widget->allocation = *allocation;
694
695   if (GTK_WIDGET_REALIZED (widget))
696     gdk_window_move_resize (widget->window,
697                             widget->allocation.x + border_width,
698                             widget->allocation.y + border_width,
699                             widget->allocation.width - border_width * 2,
700                             widget->allocation.height - border_width * 2);
701
702   if (GTK_BIN (button)->child && GTK_WIDGET_VISIBLE (GTK_BIN (button)->child))
703     {
704       child_allocation.x = (CHILD_SPACING + xthickness);
705       child_allocation.y = (CHILD_SPACING + ythickness);
706
707       child_allocation.width = MAX (1, (gint)widget->allocation.width - child_allocation.x * 2 -
708                                  border_width * 2);
709       child_allocation.height = MAX (1, (gint)widget->allocation.height - child_allocation.y * 2 -
710                                   border_width * 2);
711
712       if (GTK_WIDGET_CAN_DEFAULT (button))
713         {
714           child_allocation.x += default_border.left;
715           child_allocation.y += default_border.top;
716           child_allocation.width =  MAX (1, child_allocation.width - default_border.left - default_border.right);
717           child_allocation.height = MAX (1, child_allocation.height - default_border.top - default_border.bottom);
718         }
719
720       if (button->depressed)
721         {
722           gint child_displacement_x;
723           gint child_displacement_y;
724           
725           gtk_widget_style_get (widget,
726                                 "child_displacement_x", &child_displacement_x, 
727                                 "child_displacement_y", &child_displacement_y,
728                                 NULL);
729           child_allocation.x += child_displacement_x;
730           child_allocation.y += child_displacement_y;
731         }
732
733       gtk_widget_size_allocate (GTK_BIN (button)->child, &child_allocation);
734     }
735 }
736
737 /*
738  * +------------------------------------------------+
739  * |                   BORDER                       |
740  * |  +------------------------------------------+  |
741  * |  |\\\\\\\\\\\\\\\\DEFAULT\\\\\\\\\\\\\\\\\  |  |
742  * |  |\\+------------------------------------+  |  |
743  * |  |\\| |           SPACING       3      | |  |  |
744  * |  |\\| +--------------------------------+ |  |  |
745  * |  |\\| |########## FOCUS ###############| |  |  |
746  * |  |\\| |#+----------------------------+#| |  |  |
747  * |  |\\| |#|         RELIEF            \|#| |  |  |
748  * |  |\\| |#|  +-----------------------+\|#| |  |  |
749  * |  |\\|1|#|  +     THE TEXT          +\|#|2|  |  |
750  * |  |\\| |#|  +-----------------------+\|#| |  |  |
751  * |  |\\| |#| \\\\\ ythickness \\\\\\\\\\|#| |  |  |
752  * |  |\\| |#+----------------------------+#| |  |  |
753  * |  |\\| |########### 1 ##################| |  |  |
754  * |  |\\| +--------------------------------+ |  |  |
755  * |  |\\| |        default spacing   4     | |  |  |
756  * |  |\\+------------------------------------+  |  |
757  * |  |\            ythickness                   |  |
758  * |  +------------------------------------------+  |
759  * |                border_width                    |
760  * +------------------------------------------------+
761  */
762
763 static void
764 gtk_button_paint (GtkWidget    *widget,
765                   GdkRectangle *area)
766 {
767   GtkButton *button;
768   GtkShadowType shadow_type;
769   gint width, height;
770   gint x, y;
771   GtkBorder default_border;
772   GtkBorder default_outside_border;
773   gboolean interior_focus;
774    
775   if (GTK_WIDGET_DRAWABLE (widget))
776     {
777       button = GTK_BUTTON (widget);
778
779       gtk_button_get_props (button, &default_border, &default_outside_border, &interior_focus);
780         
781       x = 0;
782       y = 0;
783       width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2;
784       height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2;
785
786       gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
787       gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height);
788
789       if (GTK_WIDGET_HAS_DEFAULT (widget) &&
790           GTK_BUTTON (widget)->relief == GTK_RELIEF_NORMAL)
791         {
792           gtk_paint_box (widget->style, widget->window,
793                          GTK_STATE_NORMAL, GTK_SHADOW_IN,
794                          area, widget, "buttondefault",
795                          x, y, width, height);
796
797           x += default_border.left;
798           y += default_border.top;
799           width -= default_border.left + default_border.right;
800           height -= default_border.top + default_border.bottom;
801         }
802       else if (GTK_WIDGET_CAN_DEFAULT (widget))
803         {
804           x += default_outside_border.left;
805           y += default_outside_border.top;
806           width -= default_outside_border.left + default_outside_border.right;
807           height -= default_outside_border.top + default_outside_border.bottom;
808         }
809        
810       if (!interior_focus && GTK_WIDGET_HAS_FOCUS (widget))
811         {
812           x += 1;
813           y += 1;
814           width -= 2;
815           height -= 2;
816         }
817
818       shadow_type = button->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
819
820       if ((button->relief != GTK_RELIEF_NONE) ||
821           ((GTK_WIDGET_STATE(widget) != GTK_STATE_NORMAL) &&
822            (GTK_WIDGET_STATE(widget) != GTK_STATE_INSENSITIVE)))
823         gtk_paint_box (widget->style, widget->window,
824                        GTK_WIDGET_STATE (widget),
825                        shadow_type, area, widget, "button",
826                        x, y, width, height);
827        
828       if (GTK_WIDGET_HAS_FOCUS (widget))
829         {
830           if (interior_focus)
831             {
832               x += widget->style->xthickness + 1;
833               y += widget->style->ythickness + 1;
834               width -= 2 * (widget->style->xthickness + 1);
835               height -=  2 * (widget->style->xthickness + 1);
836             }
837           else
838             {
839               x -= 1;
840               y -= 1;
841               width += 2;
842               height += 2;
843             }
844
845           gtk_paint_focus (widget->style, widget->window,
846                            area, widget, "button",
847                            x, y, width - 1, height - 1);
848         }
849     }
850 }
851
852 static gboolean
853 gtk_button_expose (GtkWidget      *widget,
854                    GdkEventExpose *event)
855 {
856   GtkBin *bin;
857
858   g_return_val_if_fail (widget != NULL, FALSE);
859   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
860   g_return_val_if_fail (event != NULL, FALSE);
861
862   if (GTK_WIDGET_DRAWABLE (widget))
863     {
864       bin = GTK_BIN (widget);
865       
866       gtk_button_paint (widget, &event->area);
867       
868       (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
869     }
870   
871   return FALSE;
872 }
873
874 static gboolean
875 gtk_button_button_press (GtkWidget      *widget,
876                          GdkEventButton *event)
877 {
878   GtkButton *button;
879
880   g_return_val_if_fail (widget != NULL, FALSE);
881   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
882   g_return_val_if_fail (event != NULL, FALSE);
883
884   if (event->type == GDK_BUTTON_PRESS)
885     {
886       button = GTK_BUTTON (widget);
887
888       if (!GTK_WIDGET_HAS_FOCUS (widget))
889         gtk_widget_grab_focus (widget);
890
891       if (event->button == 1)
892         gtk_button_pressed (button);
893     }
894
895   return TRUE;
896 }
897
898 static gboolean
899 gtk_button_button_release (GtkWidget      *widget,
900                            GdkEventButton *event)
901 {
902   GtkButton *button;
903
904   g_return_val_if_fail (widget != NULL, FALSE);
905   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
906   g_return_val_if_fail (event != NULL, FALSE);
907
908   if (event->button == 1)
909     {
910       button = GTK_BUTTON (widget);
911       gtk_button_released (button);
912     }
913
914   return TRUE;
915 }
916
917 static gboolean
918 gtk_button_key_release (GtkWidget   *widget,
919                         GdkEventKey *event)
920 {
921   GtkButton *button = GTK_BUTTON (widget);
922
923   if (button->activate_timeout)
924     {
925       gtk_button_finish_activate (button, TRUE);
926       return TRUE;
927     }
928   else if (GTK_WIDGET_CLASS (parent_class)->key_release_event)
929     return GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
930   else
931     return FALSE;
932 }
933
934 static gboolean
935 gtk_button_enter_notify (GtkWidget        *widget,
936                          GdkEventCrossing *event)
937 {
938   GtkButton *button;
939   GtkWidget *event_widget;
940
941   g_return_val_if_fail (widget != NULL, FALSE);
942   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
943   g_return_val_if_fail (event != NULL, FALSE);
944
945   button = GTK_BUTTON (widget);
946   event_widget = gtk_get_event_widget ((GdkEvent*) event);
947
948   if ((event_widget == widget) &&
949       (event->detail != GDK_NOTIFY_INFERIOR))
950     {
951       button->in_button = TRUE;
952       gtk_button_enter (button);
953     }
954
955   return FALSE;
956 }
957
958 static gboolean
959 gtk_button_leave_notify (GtkWidget        *widget,
960                          GdkEventCrossing *event)
961 {
962   GtkButton *button;
963   GtkWidget *event_widget;
964
965   g_return_val_if_fail (widget != NULL, FALSE);
966   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
967   g_return_val_if_fail (event != NULL, FALSE);
968
969   button = GTK_BUTTON (widget);
970   event_widget = gtk_get_event_widget ((GdkEvent*) event);
971
972   if ((event_widget == widget) &&
973       (event->detail != GDK_NOTIFY_INFERIOR))
974     {
975       button->in_button = FALSE;
976       gtk_button_leave (button);
977     }
978
979   return FALSE;
980 }
981
982 static void
983 gtk_real_button_pressed (GtkButton *button)
984 {
985   if (button->activate_timeout)
986     return;
987   
988   button->button_down = TRUE;
989   gtk_button_update_state (button);
990 }
991
992 static void
993 gtk_real_button_released (GtkButton *button)
994 {
995   if (button->button_down)
996     {
997       button->button_down = FALSE;
998
999       if (button->activate_timeout)
1000         return;
1001       
1002       if (button->in_button)
1003         gtk_button_clicked (button);
1004
1005       gtk_button_update_state (button);
1006     }
1007 }
1008
1009 static gboolean
1010 button_activate_timeout (gpointer data)
1011 {
1012   GDK_THREADS_ENTER ();
1013   
1014   gtk_button_finish_activate (data, TRUE);
1015
1016   GDK_THREADS_LEAVE ();
1017
1018   return FALSE;
1019 }
1020
1021 static void
1022 gtk_real_button_activate (GtkButton *button)
1023 {
1024   GtkWidget *widget = GTK_WIDGET (button);
1025   
1026   g_return_if_fail (GTK_IS_BUTTON (button));
1027
1028   if (GTK_WIDGET_REALIZED (button) && !button->activate_timeout)
1029     {
1030       if (gdk_keyboard_grab (widget->window, TRUE,
1031                              gtk_get_current_event_time ()) == 0)
1032         {
1033           gtk_grab_add (widget);
1034           
1035           button->activate_timeout = g_timeout_add (ACTIVATE_TIMEOUT,
1036                                                     button_activate_timeout,
1037                                                     button);
1038           button->button_down = TRUE;
1039           gtk_button_update_state (button);
1040         }
1041     }
1042 }
1043
1044 static void
1045 gtk_button_finish_activate (GtkButton *button,
1046                             gboolean   do_it)
1047 {
1048   GtkWidget *widget = GTK_WIDGET (button);
1049   
1050   g_source_remove (button->activate_timeout);
1051   button->activate_timeout = 0;
1052
1053   gdk_keyboard_ungrab (gtk_get_current_event_time ());
1054   gtk_grab_remove (widget);
1055
1056   button->button_down = FALSE;
1057   gtk_button_update_state (button);
1058
1059   if (do_it)
1060     gtk_button_clicked (button);
1061 }
1062
1063 /**
1064  * gtk_button_set_label:
1065  * @button: a #GtkButton
1066  * @label: a string
1067  *
1068  * Sets the text of the label of the button to @str. This text is
1069  * also used to select the stock item if gtk_button_set_use_stock()
1070  * is used.
1071  *
1072  * This will also clear any previously set labels.
1073  **/
1074 void
1075 gtk_button_set_label (GtkButton   *button,
1076                       const gchar *label)
1077 {
1078   g_return_if_fail (GTK_IS_BUTTON (button));
1079   
1080   g_free (button->label_text);
1081   button->label_text = g_strdup (label);
1082   
1083   gtk_button_construct_child (button);
1084   
1085   g_object_notify (G_OBJECT (button), "label");
1086 }
1087
1088 /**
1089  * gtk_button_get_label:
1090  * @button: a #GtkButton
1091  *
1092  * Fetches the text from the label of the button, as set by
1093  * gtk_button_set_label().
1094  *
1095  * Return value: the text of the label widget. This string is
1096  *   owned by the widget and must not be modified or freed.
1097  *   If the label text has not been set the return value
1098  *   will be NULL. This will be the case if you create an
1099  *   empty button with gtk_button_new() to use as a container.
1100  **/
1101 G_CONST_RETURN gchar *
1102 gtk_button_get_label (GtkButton *button)
1103 {
1104   g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
1105   
1106   return button->label_text;
1107 }
1108
1109 /**
1110  * gtk_button_set_use_underline:
1111  * @button: a #GtkButton
1112  * @use_underline: %TRUE if underlines in the text indicate mnemonics
1113  *
1114  * If true, an underline in the text of the button label indicates
1115  * the next character should be used for the mnemonic accelerator key.
1116  */
1117 void
1118 gtk_button_set_use_underline (GtkButton *button,
1119                               gboolean   use_underline)
1120 {
1121   g_return_if_fail (GTK_IS_BUTTON (button));
1122
1123   use_underline = use_underline != FALSE;
1124
1125   if (use_underline != button->use_underline)
1126     {
1127       button->use_underline = use_underline;
1128   
1129       gtk_button_construct_child (button);
1130       
1131       g_object_notify (G_OBJECT (button), "use_underline");
1132     }
1133 }
1134
1135 /**
1136  * gtk_button_get_use_underline:
1137  * @label: a #GtkButton
1138  *
1139  * Returns whether an embedded underline in the button label indicates a
1140  * mnemonic. See gtk_button_set_use_underline ().
1141  *
1142  * Return value: %TRUE if an embedded underline in the button label
1143  *               indicates the mnemonic accelerator keys.
1144  **/
1145 gboolean
1146 gtk_button_get_use_underline (GtkButton *button)
1147 {
1148   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
1149   
1150   return button->use_underline;
1151 }
1152
1153 /**
1154  * gtk_button_set_use_stock:
1155  * @button: a #GtkButton
1156  * @use_stock: %TRUE if the button should use a stock item
1157  *
1158  * If true, the label set on the button is used as a
1159  * stock id to select the stock item for the button.
1160  */
1161 void
1162 gtk_button_set_use_stock (GtkButton *button,
1163                           gboolean   use_stock)
1164 {
1165   g_return_if_fail (GTK_IS_BUTTON (button));
1166
1167   use_stock = use_stock != FALSE;
1168
1169   if (use_stock != button->use_stock)
1170     {
1171       button->use_stock = use_stock;
1172   
1173       gtk_button_construct_child (button);
1174       
1175       g_object_notify (G_OBJECT (button), "use_stock");
1176     }
1177 }
1178
1179 /**
1180  * gtk_button_get_use_stock:
1181  * @button: a #GtkButton
1182  *
1183  * Returns whether the button label is a stock item.
1184  *
1185  * Return value: %TRUE if the button label is used to
1186  *               select a stock item instead of being
1187  *               used directly as the label text.
1188  */
1189 gboolean
1190 gtk_button_get_use_stock (GtkButton *button)
1191 {
1192   g_return_val_if_fail (GTK_IS_BUTTON (button), FALSE);
1193   
1194   return button->use_stock;
1195 }
1196
1197 /**
1198  * _gtk_button_set_depressed:
1199  * @button: a #GtkButton
1200  * @depressed: %TRUE if the button should be drawn with a recessed shadow.
1201  * 
1202  * Sets whether the button is currently drawn as down or not. This is 
1203  * purely a visual setting, and is meant only for use by derived widgets
1204  * such as #GtkToggleButton.
1205  **/
1206 void
1207 _gtk_button_set_depressed (GtkButton *button,
1208                            gboolean   depressed)
1209 {
1210   GtkWidget *widget = GTK_WIDGET (button);
1211
1212   depressed = depressed != FALSE;
1213
1214   if (depressed != button->depressed)
1215     {
1216       button->depressed = depressed;
1217       gtk_widget_queue_resize (widget);
1218     }
1219 }
1220
1221 static void
1222 gtk_button_update_state (GtkButton *button)
1223 {
1224   gboolean depressed;
1225   GtkStateType new_state;
1226
1227   depressed = button->in_button && button->button_down;
1228       
1229   if (!button->button_down && button->in_button)
1230     new_state = GTK_STATE_PRELIGHT;
1231   else
1232     new_state = depressed ? GTK_STATE_ACTIVE: GTK_STATE_NORMAL;
1233
1234   _gtk_button_set_depressed (button, depressed); 
1235   gtk_widget_set_state (GTK_WIDGET (button), new_state);
1236 }