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