]> Pileus Git - ~andy/gtk/blob - gtk/gtkbutton.c
applied patch from Andreas Persenius <ndap@swipnet.se> that updates the
[~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-2000.  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
33
34 #define CHILD_SPACING     1
35 #define DEFAULT_LEFT_POS  4
36 #define DEFAULT_TOP_POS   4
37 #define DEFAULT_SPACING   7
38
39
40 enum {
41   PRESSED,
42   RELEASED,
43   CLICKED,
44   ENTER,
45   LEAVE,
46   LAST_SIGNAL
47 };
48 enum {
49   ARG_0,
50   ARG_LABEL,
51   ARG_RELIEF
52 };
53
54
55
56 static void gtk_button_class_init     (GtkButtonClass   *klass);
57 static void gtk_button_init           (GtkButton        *button);
58 static void gtk_button_set_arg        (GtkObject        *object,
59                                        GtkArg           *arg,
60                                        guint             arg_id);
61 static void gtk_button_get_arg        (GtkObject        *object,
62                                        GtkArg           *arg,
63                                        guint             arg_id);
64 static void gtk_button_realize        (GtkWidget        *widget);
65 static void gtk_button_size_request   (GtkWidget        *widget,
66                                        GtkRequisition   *requisition);
67 static void gtk_button_size_allocate  (GtkWidget        *widget,
68                                        GtkAllocation    *allocation);
69 static void gtk_button_paint          (GtkWidget        *widget,
70                                        GdkRectangle     *area);
71 static void gtk_button_draw           (GtkWidget        *widget,
72                                        GdkRectangle     *area);
73 static void gtk_button_draw_focus     (GtkWidget        *widget);
74 static void gtk_button_draw_default   (GtkWidget        *widget);
75 static gint gtk_button_expose         (GtkWidget        *widget,
76                                        GdkEventExpose   *event);
77 static gint gtk_button_button_press   (GtkWidget        *widget,
78                                        GdkEventButton   *event);
79 static gint gtk_button_button_release (GtkWidget        *widget,
80                                        GdkEventButton   *event);
81 static gint gtk_button_enter_notify   (GtkWidget        *widget,
82                                        GdkEventCrossing *event);
83 static gint gtk_button_leave_notify   (GtkWidget        *widget,
84                                        GdkEventCrossing *event);
85 static gint gtk_button_focus_in       (GtkWidget        *widget,
86                                        GdkEventFocus    *event);
87 static gint gtk_button_focus_out      (GtkWidget        *widget,
88                                        GdkEventFocus    *event);
89 static void gtk_button_add            (GtkContainer     *container,
90                                        GtkWidget        *widget);
91 static void gtk_button_remove         (GtkContainer     *container,
92                                        GtkWidget        *widget);
93 static void gtk_real_button_pressed   (GtkButton        *button);
94 static void gtk_real_button_released  (GtkButton        *button);
95 static void gtk_real_button_enter     (GtkButton        *button);
96 static void gtk_real_button_leave     (GtkButton        *button);
97 static GtkType gtk_button_child_type  (GtkContainer     *container);
98
99
100 static GtkBinClass *parent_class = NULL;
101 static guint button_signals[LAST_SIGNAL] = { 0 };
102
103
104 GtkType
105 gtk_button_get_type (void)
106 {
107   static GtkType button_type = 0;
108
109   if (!button_type)
110     {
111       static const GTypeInfo button_info =
112       {
113         sizeof (GtkButtonClass),
114         NULL,           /* base_init */
115         NULL,           /* base_finalize */
116         (GClassInitFunc) gtk_button_class_init,
117         NULL,           /* class_finalize */
118         NULL,           /* class_data */
119         sizeof (GtkButton),
120         16,             /* n_preallocs */
121         (GInstanceInitFunc) gtk_button_init,
122       };
123
124       button_type = g_type_register_static (GTK_TYPE_BIN, "GtkButton", &button_info);
125     }
126
127   return button_type;
128 }
129
130 static void
131 gtk_button_class_init (GtkButtonClass *klass)
132 {
133   GtkObjectClass *object_class;
134   GtkWidgetClass *widget_class;
135   GtkContainerClass *container_class;
136
137   object_class = (GtkObjectClass*) klass;
138   widget_class = (GtkWidgetClass*) klass;
139   container_class = (GtkContainerClass*) klass;
140
141   parent_class = gtk_type_class (GTK_TYPE_BIN);
142
143   gtk_object_add_arg_type ("GtkButton::label", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_LABEL);
144   gtk_object_add_arg_type ("GtkButton::relief", GTK_TYPE_RELIEF_STYLE, GTK_ARG_READWRITE, ARG_RELIEF);
145
146   button_signals[PRESSED] =
147     gtk_signal_new ("pressed",
148                     GTK_RUN_FIRST,
149                     GTK_CLASS_TYPE (object_class),
150                     GTK_SIGNAL_OFFSET (GtkButtonClass, pressed),
151                     gtk_marshal_NONE__NONE,
152                     GTK_TYPE_NONE, 0);
153   button_signals[RELEASED] =
154     gtk_signal_new ("released",
155                     GTK_RUN_FIRST,
156                     GTK_CLASS_TYPE (object_class),
157                     GTK_SIGNAL_OFFSET (GtkButtonClass, released),
158                     gtk_marshal_NONE__NONE,
159                     GTK_TYPE_NONE, 0);
160   button_signals[CLICKED] =
161     gtk_signal_new ("clicked",
162                     GTK_RUN_FIRST | GTK_RUN_ACTION,
163                     GTK_CLASS_TYPE (object_class),
164                     GTK_SIGNAL_OFFSET (GtkButtonClass, clicked),
165                     gtk_marshal_NONE__NONE,
166                     GTK_TYPE_NONE, 0);
167   button_signals[ENTER] =
168     gtk_signal_new ("enter",
169                     GTK_RUN_FIRST,
170                     GTK_CLASS_TYPE (object_class),
171                     GTK_SIGNAL_OFFSET (GtkButtonClass, enter),
172                     gtk_marshal_NONE__NONE,
173                     GTK_TYPE_NONE, 0);
174   button_signals[LEAVE] =
175     gtk_signal_new ("leave",
176                     GTK_RUN_FIRST,
177                     GTK_CLASS_TYPE (object_class),
178                     GTK_SIGNAL_OFFSET (GtkButtonClass, leave),
179                     gtk_marshal_NONE__NONE,
180                     GTK_TYPE_NONE, 0);
181
182   gtk_object_class_add_signals (object_class, button_signals, LAST_SIGNAL);
183
184   object_class->set_arg = gtk_button_set_arg;
185   object_class->get_arg = gtk_button_get_arg;
186
187   widget_class->activate_signal = button_signals[CLICKED];
188   widget_class->realize = gtk_button_realize;
189   widget_class->draw = gtk_button_draw;
190   widget_class->draw_focus = gtk_button_draw_focus;
191   widget_class->draw_default = gtk_button_draw_default;
192   widget_class->size_request = gtk_button_size_request;
193   widget_class->size_allocate = gtk_button_size_allocate;
194   widget_class->expose_event = gtk_button_expose;
195   widget_class->button_press_event = gtk_button_button_press;
196   widget_class->button_release_event = gtk_button_button_release;
197   widget_class->enter_notify_event = gtk_button_enter_notify;
198   widget_class->leave_notify_event = gtk_button_leave_notify;
199   widget_class->focus_in_event = gtk_button_focus_in;
200   widget_class->focus_out_event = gtk_button_focus_out;
201
202   container_class->add = gtk_button_add;
203   container_class->remove = gtk_button_remove;
204   container_class->child_type = gtk_button_child_type;
205
206   klass->pressed = gtk_real_button_pressed;
207   klass->released = gtk_real_button_released;
208   klass->clicked = NULL;
209   klass->enter = gtk_real_button_enter;
210   klass->leave = gtk_real_button_leave;
211 }
212
213 static void
214 gtk_button_init (GtkButton *button)
215 {
216   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_FOCUS | GTK_RECEIVES_DEFAULT);
217   GTK_WIDGET_UNSET_FLAGS (button, GTK_NO_WINDOW);
218
219   button->child = NULL;
220   button->in_button = FALSE;
221   button->button_down = FALSE;
222   button->relief = GTK_RELIEF_NORMAL;
223 }
224
225 static GtkType
226 gtk_button_child_type  (GtkContainer     *container)
227 {
228   if (!GTK_BIN (container)->child)
229     return GTK_TYPE_WIDGET;
230   else
231     return GTK_TYPE_NONE;
232 }
233
234 static void
235 gtk_button_set_arg (GtkObject *object,
236                     GtkArg    *arg,
237                     guint      arg_id)
238 {
239   GtkButton *button;
240
241   button = GTK_BUTTON (object);
242
243   switch (arg_id)
244     {
245       GtkWidget *child;
246
247     case ARG_LABEL:
248       child = GTK_BIN (button)->child;
249       if (!child)
250         child = gtk_widget_new (GTK_TYPE_LABEL,
251                                 "visible", TRUE,
252                                 "parent", button,
253                                 NULL);
254       if (GTK_IS_LABEL (child))
255         gtk_label_set_text (GTK_LABEL (child),
256                        GTK_VALUE_STRING (*arg) ? GTK_VALUE_STRING (*arg) : "");
257       break;
258     case ARG_RELIEF:
259       gtk_button_set_relief (button, GTK_VALUE_ENUM (*arg));
260       break;
261     default:
262       break;
263     }
264 }
265
266 static void
267 gtk_button_get_arg (GtkObject *object,
268                     GtkArg    *arg,
269                     guint      arg_id)
270 {
271   GtkButton *button;
272
273   button = GTK_BUTTON (object);
274
275   switch (arg_id)
276     {
277     case ARG_LABEL:
278       if (GTK_BIN (button)->child && GTK_IS_LABEL (GTK_BIN (button)->child))
279         GTK_VALUE_STRING (*arg) = g_strdup (GTK_LABEL (GTK_BIN (button)->child)->label);
280       else
281         GTK_VALUE_STRING (*arg) = NULL;
282       break;
283     case ARG_RELIEF:
284       GTK_VALUE_ENUM (*arg) = gtk_button_get_relief (button);
285       break;
286     default:
287       arg->type = GTK_TYPE_INVALID;
288       break;
289     }
290 }
291
292 GtkWidget*
293 gtk_button_new (void)
294 {
295   return GTK_WIDGET (gtk_type_new (gtk_button_get_type ()));
296 }
297
298 GtkWidget*
299 gtk_button_new_with_label (const gchar *label)
300 {
301   GtkWidget *button;
302   GtkWidget *label_widget;
303
304   button = gtk_button_new ();
305   label_widget = gtk_label_new (label);
306   gtk_misc_set_alignment (GTK_MISC (label_widget), 0.5, 0.5);
307
308   gtk_container_add (GTK_CONTAINER (button), label_widget);
309   gtk_widget_show (label_widget);
310
311   return button;
312 }
313
314 void
315 gtk_button_pressed (GtkButton *button)
316 {
317   g_return_if_fail (button != NULL);
318   g_return_if_fail (GTK_IS_BUTTON (button));
319
320   gtk_signal_emit (GTK_OBJECT (button), button_signals[PRESSED]);
321 }
322
323 void
324 gtk_button_released (GtkButton *button)
325 {
326   g_return_if_fail (button != NULL);
327   g_return_if_fail (GTK_IS_BUTTON (button));
328
329   gtk_signal_emit (GTK_OBJECT (button), button_signals[RELEASED]);
330 }
331
332 void
333 gtk_button_clicked (GtkButton *button)
334 {
335   g_return_if_fail (button != NULL);
336   g_return_if_fail (GTK_IS_BUTTON (button));
337
338   gtk_signal_emit (GTK_OBJECT (button), button_signals[CLICKED]);
339 }
340
341 void
342 gtk_button_enter (GtkButton *button)
343 {
344   g_return_if_fail (button != NULL);
345   g_return_if_fail (GTK_IS_BUTTON (button));
346
347   gtk_signal_emit (GTK_OBJECT (button), button_signals[ENTER]);
348 }
349
350 void
351 gtk_button_leave (GtkButton *button)
352 {
353   g_return_if_fail (button != NULL);
354   g_return_if_fail (GTK_IS_BUTTON (button));
355
356   gtk_signal_emit (GTK_OBJECT (button), button_signals[LEAVE]);
357 }
358
359 void
360 gtk_button_set_relief (GtkButton *button,
361                        GtkReliefStyle newrelief)
362 {
363   g_return_if_fail (button != NULL);
364   g_return_if_fail (GTK_IS_BUTTON (button));
365
366   button->relief = newrelief;
367   gtk_widget_queue_draw (GTK_WIDGET (button));
368 }
369
370 GtkReliefStyle
371 gtk_button_get_relief (GtkButton *button)
372 {
373   g_return_val_if_fail (button != NULL, GTK_RELIEF_NORMAL);
374   g_return_val_if_fail (GTK_IS_BUTTON (button), GTK_RELIEF_NORMAL);
375
376   return button->relief;
377 }
378
379 static void
380 gtk_button_realize (GtkWidget *widget)
381 {
382   GtkButton *button;
383   GdkWindowAttr attributes;
384   gint attributes_mask;
385   gint border_width;
386
387   g_return_if_fail (widget != NULL);
388   g_return_if_fail (GTK_IS_BUTTON (widget));
389
390   button = GTK_BUTTON (widget);
391   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
392
393   border_width = GTK_CONTAINER (widget)->border_width;
394
395   attributes.window_type = GDK_WINDOW_CHILD;
396   attributes.x = widget->allocation.x + border_width;
397   attributes.y = widget->allocation.y + border_width;
398   attributes.width = widget->allocation.width - border_width * 2;
399   attributes.height = widget->allocation.height - border_width * 2;
400   attributes.wclass = GDK_INPUT_OUTPUT;
401   attributes.visual = gtk_widget_get_visual (widget);
402   attributes.colormap = gtk_widget_get_colormap (widget);
403   attributes.event_mask = gtk_widget_get_events (widget);
404   attributes.event_mask |= (GDK_EXPOSURE_MASK |
405                             GDK_BUTTON_PRESS_MASK |
406                             GDK_BUTTON_RELEASE_MASK |
407                             GDK_ENTER_NOTIFY_MASK |
408                             GDK_LEAVE_NOTIFY_MASK);
409
410   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
411
412   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
413   gdk_window_set_user_data (widget->window, button);
414
415   widget->style = gtk_style_attach (widget->style, widget->window);
416   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
417 }
418
419 static void
420 gtk_button_size_request (GtkWidget      *widget,
421                          GtkRequisition *requisition)
422 {
423   GtkButton *button;
424
425   g_return_if_fail (widget != NULL);
426   g_return_if_fail (GTK_IS_BUTTON (widget));
427   g_return_if_fail (requisition != NULL);
428
429   button = GTK_BUTTON (widget);
430
431   requisition->width = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
432                         GTK_WIDGET (widget)->style->xthickness) * 2;
433   requisition->height = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
434                          GTK_WIDGET (widget)->style->ythickness) * 2;
435
436   if (GTK_WIDGET_CAN_DEFAULT (widget))
437     {
438       requisition->width += (GTK_WIDGET (widget)->style->xthickness * 2 +
439                              DEFAULT_SPACING);
440       requisition->height += (GTK_WIDGET (widget)->style->ythickness * 2 +
441                               DEFAULT_SPACING);
442     }
443
444   if (GTK_BIN (button)->child && GTK_WIDGET_VISIBLE (GTK_BIN (button)->child))
445     {
446       GtkRequisition child_requisition;
447
448       gtk_widget_size_request (GTK_BIN (button)->child, &child_requisition);
449
450       requisition->width += child_requisition.width;
451       requisition->height += child_requisition.height;
452     }
453 }
454
455 static void
456 gtk_button_size_allocate (GtkWidget     *widget,
457                           GtkAllocation *allocation)
458 {
459   GtkButton *button;
460   GtkAllocation child_allocation;
461   gint border_width;
462
463   g_return_if_fail (widget != NULL);
464   g_return_if_fail (GTK_IS_BUTTON (widget));
465   g_return_if_fail (allocation != NULL);
466
467   widget->allocation = *allocation;
468   border_width = GTK_CONTAINER (widget)->border_width;
469
470   if (GTK_WIDGET_REALIZED (widget))
471     gdk_window_move_resize (widget->window,
472                             widget->allocation.x + border_width,
473                             widget->allocation.y + border_width,
474                             widget->allocation.width - border_width * 2,
475                             widget->allocation.height - border_width * 2);
476
477   button = GTK_BUTTON (widget);
478
479   if (GTK_BIN (button)->child && GTK_WIDGET_VISIBLE (GTK_BIN (button)->child))
480     {
481       child_allocation.x = (CHILD_SPACING + GTK_WIDGET (widget)->style->xthickness);
482       child_allocation.y = (CHILD_SPACING + GTK_WIDGET (widget)->style->ythickness);
483
484       child_allocation.width = MAX (1, (gint)widget->allocation.width - child_allocation.x * 2 -
485                                  border_width * 2);
486       child_allocation.height = MAX (1, (gint)widget->allocation.height - child_allocation.y * 2 -
487                                   border_width * 2);
488
489       if (GTK_WIDGET_CAN_DEFAULT (button))
490         {
491           child_allocation.x += (GTK_WIDGET (widget)->style->xthickness +
492                                  DEFAULT_LEFT_POS);
493           child_allocation.y += (GTK_WIDGET (widget)->style->ythickness +
494                                  DEFAULT_TOP_POS);
495           child_allocation.width =  MAX (1, (gint)child_allocation.width -
496                                          (gint)(GTK_WIDGET (widget)->style->xthickness * 2 + DEFAULT_SPACING));
497           child_allocation.height = MAX (1, (gint)child_allocation.height -
498                                          (gint)(GTK_WIDGET (widget)->style->xthickness * 2 + DEFAULT_SPACING));
499         }
500
501       gtk_widget_size_allocate (GTK_BIN (button)->child, &child_allocation);
502     }
503 }
504
505 /*
506  * +------------------------------------------------+
507  * |                   BORDER                       |
508  * |  +------------------------------------------+  |
509  * |  |\\\\\\\\\\\\\\\\DEFAULT\\\\\\\\\\\\\\\\\  |  |
510  * |  |\\+------------------------------------+  |  |
511  * |  |\\| |           SPACING       3      | |  |  |
512  * |  |\\| +--------------------------------+ |  |  |
513  * |  |\\| |########## FOCUS ###############| |  |  |
514  * |  |\\| |#+----------------------------+#| |  |  |
515  * |  |\\| |#|         RELIEF            \|#| |  |  |
516  * |  |\\| |#|  +-----------------------+\|#| |  |  |
517  * |  |\\|1|#|  +     THE TEXT          +\|#|2|  |  |
518  * |  |\\| |#|  +-----------------------+\|#| |  |  |
519  * |  |\\| |#| \\\\\ ythickness \\\\\\\\\\|#| |  |  |
520  * |  |\\| |#+----------------------------+#| |  |  |
521  * |  |\\| |########### 1 ##################| |  |  |
522  * |  |\\| +--------------------------------+ |  |  |
523  * |  |\\| |        default spacing   4     | |  |  |
524  * |  |\\+------------------------------------+  |  |
525  * |  |\            ythickness                   |  |
526  * |  +------------------------------------------+  |
527  * |                border_width                    |
528  * +------------------------------------------------+
529  */
530
531 static void
532 gtk_button_paint (GtkWidget    *widget,
533                   GdkRectangle *area)
534 {
535   GtkButton *button;
536   GtkShadowType shadow_type;
537   gint width, height;
538   gint x, y;
539    
540   if (GTK_WIDGET_DRAWABLE (widget))
541     {
542       button = GTK_BUTTON (widget);
543         
544       x = 0;
545       y = 0;
546       width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2;
547       height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2;
548
549       gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
550       gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height);
551
552       if (GTK_WIDGET_HAS_DEFAULT (widget) &&
553           GTK_BUTTON (widget)->relief == GTK_RELIEF_NORMAL)
554         {
555           gtk_paint_box (widget->style, widget->window,
556                          GTK_STATE_NORMAL, GTK_SHADOW_IN,
557                          area, widget, "buttondefault",
558                          x, y, width, height);
559         }
560
561       if (GTK_WIDGET_CAN_DEFAULT (widget))
562         {
563           x += widget->style->xthickness;
564           y += widget->style->ythickness;
565           width -= 2 * x + DEFAULT_SPACING;
566           height -= 2 * y + DEFAULT_SPACING;
567           x += DEFAULT_LEFT_POS;
568           y += DEFAULT_TOP_POS;
569         }
570        
571       if (GTK_WIDGET_HAS_FOCUS (widget))
572         {
573           x += 1;
574           y += 1;
575           width -= 2;
576           height -= 2;
577         }
578         
579       if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE)
580         shadow_type = GTK_SHADOW_IN;
581       else
582         shadow_type = GTK_SHADOW_OUT;
583
584       if ((button->relief != GTK_RELIEF_NONE) ||
585           ((GTK_WIDGET_STATE(widget) != GTK_STATE_NORMAL) &&
586            (GTK_WIDGET_STATE(widget) != GTK_STATE_INSENSITIVE)))
587         gtk_paint_box (widget->style, widget->window,
588                        GTK_WIDGET_STATE (widget),
589                        shadow_type, area, widget, "button",
590                        x, y, width, height);
591        
592       if (GTK_WIDGET_HAS_FOCUS (widget))
593         {
594           x -= 1;
595           y -= 1;
596           width += 2;
597           height += 2;
598
599           gtk_paint_focus (widget->style, widget->window,
600                            area, widget, "button",
601                            x, y, width - 1, height - 1);
602         }
603     }
604 }
605
606 static void
607 gtk_button_draw (GtkWidget    *widget,
608                  GdkRectangle *area)
609 {
610   GtkButton *button;
611   GdkRectangle child_area;
612   GdkRectangle tmp_area;
613
614   g_return_if_fail (widget != NULL);
615   g_return_if_fail (GTK_IS_BUTTON (widget));
616   g_return_if_fail (area != NULL);
617
618   if (GTK_WIDGET_DRAWABLE (widget))
619     {
620       button = GTK_BUTTON (widget);
621
622       tmp_area = *area;
623       tmp_area.x -= GTK_CONTAINER (button)->border_width;
624       tmp_area.y -= GTK_CONTAINER (button)->border_width;
625
626       gtk_button_paint (widget, &tmp_area);
627
628       if (GTK_BIN (button)->child && gtk_widget_intersect (GTK_BIN (button)->child, &tmp_area, &child_area))
629         gtk_widget_draw (GTK_BIN (button)->child, &child_area);
630     }
631 }
632
633 static void
634 gtk_button_draw_focus (GtkWidget *widget)
635 {
636   gtk_widget_draw (widget, NULL);
637 }
638
639 static void
640 gtk_button_draw_default (GtkWidget *widget)
641 {
642   gtk_widget_draw (widget, NULL);
643 }
644
645 static gint
646 gtk_button_expose (GtkWidget      *widget,
647                    GdkEventExpose *event)
648 {
649   GtkBin *bin;
650   GdkEventExpose child_event;
651
652   g_return_val_if_fail (widget != NULL, FALSE);
653   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
654   g_return_val_if_fail (event != NULL, FALSE);
655
656   if (GTK_WIDGET_DRAWABLE (widget))
657     {
658       bin = GTK_BIN (widget);
659       
660       gtk_button_paint (widget, &event->area);
661
662       child_event = *event;
663       if (bin->child && GTK_WIDGET_NO_WINDOW (bin->child) &&
664           gtk_widget_intersect (bin->child, &event->area, &child_event.area))
665         gtk_widget_event (bin->child, (GdkEvent*) &child_event);
666     }
667
668   return FALSE;
669 }
670
671 static gint
672 gtk_button_button_press (GtkWidget      *widget,
673                          GdkEventButton *event)
674 {
675   GtkButton *button;
676
677   g_return_val_if_fail (widget != NULL, FALSE);
678   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
679   g_return_val_if_fail (event != NULL, FALSE);
680
681   if (event->type == GDK_BUTTON_PRESS)
682     {
683       button = GTK_BUTTON (widget);
684
685       if (!GTK_WIDGET_HAS_FOCUS (widget))
686         gtk_widget_grab_focus (widget);
687
688       if (event->button == 1)
689         {
690           gtk_grab_add (GTK_WIDGET (button));
691           gtk_button_pressed (button);
692         }
693     }
694
695   return TRUE;
696 }
697
698 static gint
699 gtk_button_button_release (GtkWidget      *widget,
700                            GdkEventButton *event)
701 {
702   GtkButton *button;
703
704   g_return_val_if_fail (widget != NULL, FALSE);
705   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
706   g_return_val_if_fail (event != NULL, FALSE);
707
708   if (event->button == 1)
709     {
710       button = GTK_BUTTON (widget);
711       gtk_grab_remove (GTK_WIDGET (button));
712       gtk_button_released (button);
713     }
714
715   return TRUE;
716 }
717
718 static gint
719 gtk_button_enter_notify (GtkWidget        *widget,
720                          GdkEventCrossing *event)
721 {
722   GtkButton *button;
723   GtkWidget *event_widget;
724
725   g_return_val_if_fail (widget != NULL, FALSE);
726   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
727   g_return_val_if_fail (event != NULL, FALSE);
728
729   button = GTK_BUTTON (widget);
730   event_widget = gtk_get_event_widget ((GdkEvent*) event);
731
732   if ((event_widget == widget) &&
733       (event->detail != GDK_NOTIFY_INFERIOR))
734     {
735       button->in_button = TRUE;
736       gtk_button_enter (button);
737     }
738
739   return FALSE;
740 }
741
742 static gint
743 gtk_button_leave_notify (GtkWidget        *widget,
744                          GdkEventCrossing *event)
745 {
746   GtkButton *button;
747   GtkWidget *event_widget;
748
749   g_return_val_if_fail (widget != NULL, FALSE);
750   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
751   g_return_val_if_fail (event != NULL, FALSE);
752
753   button = GTK_BUTTON (widget);
754   event_widget = gtk_get_event_widget ((GdkEvent*) event);
755
756   if ((event_widget == widget) &&
757       (event->detail != GDK_NOTIFY_INFERIOR))
758     {
759       button->in_button = FALSE;
760       gtk_button_leave (button);
761     }
762
763   return FALSE;
764 }
765
766 static gint
767 gtk_button_focus_in (GtkWidget     *widget,
768                      GdkEventFocus *event)
769 {
770   g_return_val_if_fail (widget != NULL, FALSE);
771   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
772   g_return_val_if_fail (event != NULL, FALSE);
773
774   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
775   gtk_widget_draw_focus (widget);
776
777   return FALSE;
778 }
779
780 static gint
781 gtk_button_focus_out (GtkWidget     *widget,
782                       GdkEventFocus *event)
783 {
784   g_return_val_if_fail (widget != NULL, FALSE);
785   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
786   g_return_val_if_fail (event != NULL, FALSE);
787
788   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
789   gtk_widget_draw_focus (widget);
790
791   return FALSE;
792 }
793
794 static void
795 gtk_button_add (GtkContainer *container,
796                 GtkWidget    *widget)
797 {
798   g_return_if_fail (container != NULL);
799   g_return_if_fail (widget != NULL);
800
801   if (GTK_CONTAINER_CLASS (parent_class)->add)
802     GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
803
804   GTK_BUTTON (container)->child = GTK_BIN (container)->child;
805 }
806
807 static void
808 gtk_button_remove (GtkContainer *container,
809                    GtkWidget    *widget)
810 {
811   g_return_if_fail (container != NULL);
812   g_return_if_fail (widget != NULL);
813
814   if (GTK_CONTAINER_CLASS (parent_class)->remove)
815     GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
816
817   GTK_BUTTON (container)->child = GTK_BIN (container)->child;
818 }
819
820 static void
821 gtk_real_button_pressed (GtkButton *button)
822 {
823   GtkStateType new_state;
824
825   g_return_if_fail (button != NULL);
826   g_return_if_fail (GTK_IS_BUTTON (button));
827
828   button->button_down = TRUE;
829
830   new_state = (button->in_button ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL);
831
832   if (GTK_WIDGET_STATE (button) != new_state)
833     {
834       gtk_widget_set_state (GTK_WIDGET (button), new_state);
835       gtk_widget_queue_draw (GTK_WIDGET (button));
836     }
837 }
838
839 static void
840 gtk_real_button_released (GtkButton *button)
841 {
842   GtkStateType new_state;
843
844   g_return_if_fail (button != NULL);
845   g_return_if_fail (GTK_IS_BUTTON (button));
846
847   if (button->button_down)
848     {
849       button->button_down = FALSE;
850
851       if (button->in_button)
852         gtk_button_clicked (button);
853
854       new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL);
855
856       if (GTK_WIDGET_STATE (button) != new_state)
857         {
858           gtk_widget_set_state (GTK_WIDGET (button), new_state);
859           /* We _draw () instead of queue_draw so that if the operation
860            * blocks, the label doesn't vanish.
861            */
862           gtk_widget_draw (GTK_WIDGET (button), NULL);
863         }
864     }
865 }
866
867 static void
868 gtk_real_button_enter (GtkButton *button)
869 {
870   GtkStateType new_state;
871
872   g_return_if_fail (button != NULL);
873   g_return_if_fail (GTK_IS_BUTTON (button));
874
875   new_state = (button->button_down ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT);
876
877   if (GTK_WIDGET_STATE (button) != new_state)
878     {
879       gtk_widget_set_state (GTK_WIDGET (button), new_state);
880       gtk_widget_queue_draw (GTK_WIDGET (button));
881     }
882 }
883
884 static void
885 gtk_real_button_leave (GtkButton *button)
886 {
887   g_return_if_fail (button != NULL);
888   g_return_if_fail (GTK_IS_BUTTON (button));
889
890   if (GTK_WIDGET_STATE (button) != GTK_STATE_NORMAL)
891     {
892       gtk_widget_set_state (GTK_WIDGET (button), GTK_STATE_NORMAL);
893       gtk_widget_queue_draw (GTK_WIDGET (button));
894     }
895 }