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