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