]> Pileus Git - ~andy/gtk/blob - gtk/gtkbutton.c
NEWS file update for upcoming release of Gtk+ version 1.1.2, binary age 0,
[~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       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,
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),
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),
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 = gtk_real_button_enter;
202   klass->leave = 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 (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   gtk_signal_emit (GTK_OBJECT (button), button_signals[PRESSED]);
310 }
311
312 void
313 gtk_button_released (GtkButton *button)
314 {
315   gtk_signal_emit (GTK_OBJECT (button), button_signals[RELEASED]);
316 }
317
318 void
319 gtk_button_clicked (GtkButton *button)
320 {
321   gtk_signal_emit (GTK_OBJECT (button), button_signals[CLICKED]);
322 }
323
324 void
325 gtk_button_enter (GtkButton *button)
326 {
327   gtk_signal_emit (GTK_OBJECT (button), button_signals[ENTER]);
328 }
329
330 void
331 gtk_button_leave (GtkButton *button)
332 {
333   gtk_signal_emit (GTK_OBJECT (button), button_signals[LEAVE]);
334 }
335
336 void
337 gtk_button_set_relief (GtkButton *button,
338                        GtkReliefStyle newrelief)
339 {
340   g_return_if_fail (button != NULL);
341   g_return_if_fail (GTK_IS_BUTTON (button));
342
343   button->relief = newrelief;
344   gtk_widget_queue_draw (GTK_WIDGET (button));
345 }
346
347 GtkReliefStyle
348 gtk_button_get_relief (GtkButton *button)
349 {
350   g_return_val_if_fail (button != NULL, GTK_RELIEF_NORMAL);
351   g_return_val_if_fail (GTK_IS_BUTTON (button), GTK_RELIEF_NORMAL);
352
353   return button->relief;
354 }
355
356 static void
357 gtk_button_realize (GtkWidget *widget)
358 {
359   GtkButton *button;
360   GdkWindowAttr attributes;
361   gint attributes_mask;
362   gint border_width;
363
364   g_return_if_fail (widget != NULL);
365   g_return_if_fail (GTK_IS_BUTTON (widget));
366
367   button = GTK_BUTTON (widget);
368   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
369
370   border_width = GTK_CONTAINER (widget)->border_width;
371
372   attributes.window_type = GDK_WINDOW_CHILD;
373   attributes.x = widget->allocation.x + border_width;
374   attributes.y = widget->allocation.y + border_width;
375   attributes.width = widget->allocation.width - border_width * 2;
376   attributes.height = widget->allocation.height - border_width * 2;
377   attributes.wclass = GDK_INPUT_OUTPUT;
378   attributes.visual = gtk_widget_get_visual (widget);
379   attributes.colormap = gtk_widget_get_colormap (widget);
380   attributes.event_mask = gtk_widget_get_events (widget);
381   attributes.event_mask |= (GDK_EXPOSURE_MASK |
382                             GDK_BUTTON_PRESS_MASK |
383                             GDK_BUTTON_RELEASE_MASK |
384                             GDK_ENTER_NOTIFY_MASK |
385                             GDK_LEAVE_NOTIFY_MASK);
386
387   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
388
389   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
390   gdk_window_set_user_data (widget->window, button);
391
392   widget->style = gtk_style_attach (widget->style, widget->window);
393   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
394 }
395
396 static void
397 gtk_button_size_request (GtkWidget      *widget,
398                          GtkRequisition *requisition)
399 {
400   GtkButton *button;
401
402   g_return_if_fail (widget != NULL);
403   g_return_if_fail (GTK_IS_BUTTON (widget));
404   g_return_if_fail (requisition != NULL);
405
406   button = GTK_BUTTON (widget);
407
408   requisition->width = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
409                         GTK_WIDGET (widget)->style->klass->xthickness) * 2;
410   requisition->height = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
411                          GTK_WIDGET (widget)->style->klass->ythickness) * 2;
412
413   if (GTK_WIDGET_CAN_DEFAULT (widget))
414     {
415       requisition->width += (GTK_WIDGET (widget)->style->klass->xthickness * 2 +
416                              DEFAULT_SPACING);
417       requisition->height += (GTK_WIDGET (widget)->style->klass->ythickness * 2 +
418                               DEFAULT_SPACING);
419     }
420
421   if (GTK_BIN (button)->child && GTK_WIDGET_VISIBLE (GTK_BIN (button)->child))
422     {
423       gtk_widget_size_request (GTK_BIN (button)->child, &GTK_BIN (button)->child->requisition);
424
425       requisition->width += GTK_BIN (button)->child->requisition.width;
426       requisition->height += GTK_BIN (button)->child->requisition.height;
427     }
428 }
429
430 static void
431 gtk_button_size_allocate (GtkWidget     *widget,
432                           GtkAllocation *allocation)
433 {
434   GtkButton *button;
435   GtkAllocation child_allocation;
436   gint border_width;
437
438   g_return_if_fail (widget != NULL);
439   g_return_if_fail (GTK_IS_BUTTON (widget));
440   g_return_if_fail (allocation != NULL);
441
442   widget->allocation = *allocation;
443   border_width = GTK_CONTAINER (widget)->border_width;
444
445   if (GTK_WIDGET_REALIZED (widget))
446     gdk_window_move_resize (widget->window,
447                             widget->allocation.x + border_width,
448                             widget->allocation.y + border_width,
449                             widget->allocation.width - border_width * 2,
450                             widget->allocation.height - border_width * 2);
451
452   button = GTK_BUTTON (widget);
453
454   if (GTK_BIN (button)->child && GTK_WIDGET_VISIBLE (GTK_BIN (button)->child))
455     {
456       child_allocation.x = (CHILD_SPACING + GTK_WIDGET (widget)->style->klass->xthickness);
457       child_allocation.y = (CHILD_SPACING + GTK_WIDGET (widget)->style->klass->ythickness);
458
459       child_allocation.width = MAX (1, widget->allocation.width - child_allocation.x * 2 -
460                                  border_width * 2);
461       child_allocation.height = MAX (1, widget->allocation.height - child_allocation.y * 2 -
462                                   border_width * 2);
463
464       if (GTK_WIDGET_CAN_DEFAULT (button))
465         {
466           child_allocation.x += (GTK_WIDGET (widget)->style->klass->xthickness +
467                                  DEFAULT_LEFT_POS);
468           child_allocation.y += (GTK_WIDGET (widget)->style->klass->ythickness +
469                                  DEFAULT_TOP_POS);
470           child_allocation.width =  MAX (1, child_allocation.width -
471                                         (GTK_WIDGET (widget)->style->klass->xthickness * 2 + DEFAULT_SPACING));
472           child_allocation.height = MAX (1, child_allocation.height -
473                                          (GTK_WIDGET (widget)->style->klass->xthickness * 2 + DEFAULT_SPACING));
474         }
475
476       gtk_widget_size_allocate (GTK_BIN (button)->child, &child_allocation);
477     }
478 }
479
480 /*
481  * +------------------------------------------------+
482  * |                   BORDER                       |
483  * |  +------------------------------------------+  |
484  * |  |\\\\\\\\\\\\\\\\DEFAULT\\\\\\\\\\\\\\\\\  |  |
485  * |  |\\+------------------------------------+  |  |
486  * |  |\\| |           SPACING       3      | |  |  |
487  * |  |\\| +--------------------------------+ |  |  |
488  * |  |\\| |########## FOCUS ###############| |  |  |
489  * |  |\\| |#+----------------------------+#| |  |  |
490  * |  |\\| |#|         RELIEF            \|#| |  |  |
491  * |  |\\| |#|  +-----------------------+\|#| |  |  |
492  * |  |\\|1|#|  +     THE TEXT          +\|#|2|  |  |
493  * |  |\\| |#|  +-----------------------+\|#| |  |  |
494  * |  |\\| |#| \\\\\ ythickness \\\\\\\\\\|#| |  |  |
495  * |  |\\| |#+----------------------------+#| |  |  |
496  * |  |\\| |########### 1 ##################| |  |  |
497  * |  |\\| +--------------------------------+ |  |  |
498  * |  |\\| |        default spacing   4     | |  |  |
499  * |  |\\+------------------------------------+  |  |
500  * |  |\            ythickness                   |  |
501  * |  +------------------------------------------+  |
502  * |                border_width                    |
503  * +------------------------------------------------+
504  */
505
506 static void
507 gtk_button_paint (GtkWidget    *widget,
508                   GdkRectangle *area)
509 {
510   GdkRectangle restrict_area;
511   GdkRectangle outer_area;
512   GdkRectangle tmp_area;
513   GdkRectangle new_area;
514   gint xthickness;
515   gint ythickness;
516
517   g_return_if_fail (widget != NULL);
518   g_return_if_fail (GTK_IS_BUTTON (widget));
519
520   xthickness = widget->style->klass->xthickness;
521   ythickness = widget->style->klass->ythickness;
522
523   if (GTK_WIDGET_DRAWABLE (widget))
524     {
525       restrict_area.x = xthickness;
526       restrict_area.y = ythickness;
527       restrict_area.width = GTK_WIDGET (widget)->allocation.width -
528         restrict_area.x * 2 - GTK_CONTAINER (widget)->border_width * 2;
529       restrict_area.height = GTK_WIDGET (widget)->allocation.height -
530         restrict_area.y * 2 - GTK_CONTAINER (widget)->border_width * 2;
531
532       outer_area = restrict_area;
533
534       if (GTK_WIDGET_CAN_DEFAULT (widget))
535         {
536           restrict_area.x += DEFAULT_LEFT_POS;
537           restrict_area.y += DEFAULT_TOP_POS;
538           restrict_area.width -= DEFAULT_SPACING;
539           restrict_area.height -= DEFAULT_SPACING;
540         }
541
542       if (gdk_rectangle_intersect (area, &restrict_area, &new_area))
543         {
544           if ((GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT) &&
545               (GTK_BUTTON (widget)->relief != GTK_RELIEF_NORMAL))
546             gtk_style_set_background (widget->style, widget->window,
547                                       GTK_BUTTON (widget)->relief == GTK_RELIEF_NONE ? GTK_STATE_NORMAL : GTK_WIDGET_STATE (widget));
548           else
549             gtk_style_set_background (widget->style, widget->window, GTK_WIDGET_STATE (widget));
550           gdk_window_clear_area (widget->window,
551                                  new_area.x, new_area.y,
552                                  new_area.width, new_area.height);
553         }
554
555       if (GTK_WIDGET_CAN_DEFAULT (widget))
556         {
557           /* Now fill spacing area between the default border and the button */
558
559  /* 1 */  tmp_area = outer_area;
560           tmp_area.width = restrict_area.x - outer_area.x;
561           if (gdk_rectangle_intersect (area, &tmp_area, &new_area))
562             gdk_draw_rectangle (widget->window,
563                                 widget->style->bg_gc[GTK_STATE_NORMAL],
564                                 TRUE,
565                                 new_area.x, new_area.y,
566                                 new_area.width, new_area.height);
567
568   /* 2 */ tmp_area.x = restrict_area.x + restrict_area.width;
569
570           if (gdk_rectangle_intersect (area, &tmp_area, &new_area))
571             gdk_draw_rectangle (widget->window,
572                                 widget->style->bg_gc[GTK_STATE_NORMAL],
573                                 TRUE,
574                                 new_area.x, new_area.y,
575                                 new_area.width, new_area.height);
576
577   /* 3 */ tmp_area.width = restrict_area.width;
578           tmp_area.height = restrict_area.y - outer_area.y;
579           tmp_area.x = restrict_area.x;
580
581           if (gdk_rectangle_intersect (area, &tmp_area, &new_area))
582             gdk_draw_rectangle (widget->window,
583                                 widget->style->bg_gc[GTK_STATE_NORMAL],
584                                 TRUE,
585                                 new_area.x, new_area.y,
586                                 new_area.width, new_area.height);
587
588   /* 4 */ tmp_area.y = restrict_area.y + restrict_area.height;
589
590           if (gdk_rectangle_intersect (area, &tmp_area, &new_area))
591             gdk_draw_rectangle (widget->window,
592                                 widget->style->bg_gc[GTK_STATE_NORMAL],
593                                 TRUE,
594                                 new_area.x, new_area.y,
595                                 new_area.width, new_area.height);
596         }
597     }
598 }
599
600 static void
601 gtk_button_draw (GtkWidget    *widget,
602                  GdkRectangle *area)
603 {
604   GtkButton *button;
605   GdkRectangle child_area;
606   GdkRectangle tmp_area;
607
608   g_return_if_fail (widget != NULL);
609   g_return_if_fail (GTK_IS_BUTTON (widget));
610   g_return_if_fail (area != NULL);
611
612   if (GTK_WIDGET_DRAWABLE (widget))
613     {
614       button = GTK_BUTTON (widget);
615
616       tmp_area = *area;
617       tmp_area.x -= GTK_CONTAINER (button)->border_width;
618       tmp_area.y -= GTK_CONTAINER (button)->border_width;
619
620       gtk_button_paint (widget, &tmp_area);
621
622       if (GTK_BIN (button)->child && gtk_widget_intersect (GTK_BIN (button)->child, &tmp_area, &child_area))
623         gtk_widget_draw (GTK_BIN (button)->child, &child_area);
624
625       gtk_widget_draw_default (widget);
626       gtk_widget_draw_focus (widget);
627     }
628 }
629
630 static void
631 gtk_button_draw_focus (GtkWidget *widget)
632 {
633   GtkButton *button;
634   GtkShadowType shadow_type;
635   gint width, height;
636   gint x, y;
637
638   g_return_if_fail (widget != NULL);
639   g_return_if_fail (GTK_IS_BUTTON (widget));
640
641   if (GTK_WIDGET_DRAWABLE (widget))
642     {
643       button = GTK_BUTTON (widget);
644
645       x = 0;
646       y = 0;
647       width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2;
648       height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2;
649
650       if (GTK_WIDGET_CAN_DEFAULT (widget))
651         {
652           x += widget->style->klass->xthickness;
653           y += widget->style->klass->ythickness;
654           width -= 2 * x + DEFAULT_SPACING;
655           height -= 2 * y + DEFAULT_SPACING;
656           x += DEFAULT_LEFT_POS;
657           y += DEFAULT_TOP_POS;
658         }
659
660       if (GTK_WIDGET_HAS_FOCUS (widget))
661         {
662           x += 1;
663           y += 1;
664           width -= 2;
665           height -= 2;
666         }
667       else
668         {
669           if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE)
670             gdk_draw_rectangle (widget->window,
671                                 widget->style->bg_gc[GTK_WIDGET_STATE (widget)], FALSE,
672                                 x + 1, y + 1, width - 4, height - 4);
673           else if (button->relief == GTK_RELIEF_NORMAL)
674             gdk_draw_rectangle (widget->window,
675                                 widget->style->bg_gc[GTK_WIDGET_STATE (widget)], FALSE,
676                                 x + 2, y + 2, width - 5, height - 5);
677           else
678             gdk_draw_rectangle (widget->window,
679                                 widget->style->bg_gc[GTK_WIDGET_STATE (widget)], FALSE,
680                                 x, y, width - 1, height - 1);
681         }
682
683       if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE)
684         shadow_type = GTK_SHADOW_IN;
685       else
686         shadow_type = GTK_SHADOW_OUT;
687
688       if ((button->relief == GTK_RELIEF_NORMAL) ||
689           ((GTK_WIDGET_STATE (widget) != GTK_STATE_NORMAL) &&
690            (GTK_WIDGET_STATE (widget) != GTK_STATE_INSENSITIVE)))
691         {
692           gtk_draw_shadow (widget->style, widget->window,
693                            button->relief == GTK_RELIEF_NONE ? GTK_STATE_NORMAL : GTK_WIDGET_STATE (widget),
694                            shadow_type,
695                            x, y, width, height);
696         }
697
698       if (GTK_WIDGET_HAS_FOCUS (widget))
699         {
700           x -= 1;
701           y -= 1;
702           width += 2;
703           height += 2;
704
705           gdk_draw_rectangle (widget->window,
706                               widget->style->black_gc, FALSE,
707                               x, y, width - 1, height - 1);
708         }
709     }
710 }
711
712 static void
713 gtk_button_draw_default (GtkWidget *widget)
714 {
715   gint width, height;
716   gint x, y;
717
718   g_return_if_fail (widget != NULL);
719   g_return_if_fail (GTK_IS_BUTTON (widget));
720
721   if (GTK_WIDGET_DRAWABLE (widget))
722     {
723       x = 0;
724       y = 0;
725       width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2;
726       height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2;
727
728       if (GTK_WIDGET_HAS_DEFAULT (widget) &&
729           GTK_BUTTON (widget)->relief == GTK_RELIEF_NORMAL)
730         {
731           gtk_draw_shadow (widget->style, widget->window,
732                            GTK_STATE_NORMAL, GTK_SHADOW_IN,
733                            x, y, width, height);
734         }
735       else
736         {
737           gdk_draw_rectangle (widget->window, widget->style->bg_gc[GTK_STATE_NORMAL],
738                               FALSE, x, y, width - 1, height - 1);
739           gdk_draw_rectangle (widget->window, widget->style->bg_gc[GTK_STATE_NORMAL],
740                               FALSE, x + 1, y + 1, width - 3, height - 3);
741         }
742     }
743 }
744
745 static gint
746 gtk_button_expose (GtkWidget      *widget,
747                    GdkEventExpose *event)
748 {
749   GtkButton *button;
750   GdkEventExpose child_event;
751
752   g_return_val_if_fail (widget != NULL, FALSE);
753   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
754   g_return_val_if_fail (event != NULL, FALSE);
755
756   if (GTK_WIDGET_DRAWABLE (widget))
757     {
758       button = GTK_BUTTON (widget);
759
760       gtk_button_paint (widget, &event->area);
761
762       child_event = *event;
763       if (GTK_BIN (button)->child && GTK_WIDGET_NO_WINDOW (GTK_BIN (button)->child) &&
764           gtk_widget_intersect (GTK_BIN (button)->child, &event->area, &child_event.area))
765         gtk_widget_event (GTK_BIN (button)->child, (GdkEvent*) &child_event);
766
767       gtk_widget_draw_default (widget);
768       gtk_widget_draw_focus (widget);
769     }
770
771   return FALSE;
772 }
773
774 static gint
775 gtk_button_button_press (GtkWidget      *widget,
776                          GdkEventButton *event)
777 {
778   GtkButton *button;
779
780   g_return_val_if_fail (widget != NULL, FALSE);
781   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
782   g_return_val_if_fail (event != NULL, FALSE);
783
784   if (event->type == GDK_BUTTON_PRESS)
785     {
786       button = GTK_BUTTON (widget);
787
788       if (GTK_WIDGET_CAN_DEFAULT (widget) && (event->button == 1))
789         gtk_widget_grab_default (widget);
790       if (!GTK_WIDGET_HAS_FOCUS (widget))
791         gtk_widget_grab_focus (widget);
792
793       if (event->button == 1)
794         {
795           gtk_grab_add (GTK_WIDGET (button));
796           gtk_button_pressed (button);
797         }
798     }
799
800   return TRUE;
801 }
802
803 static gint
804 gtk_button_button_release (GtkWidget      *widget,
805                            GdkEventButton *event)
806 {
807   GtkButton *button;
808
809   g_return_val_if_fail (widget != NULL, FALSE);
810   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
811   g_return_val_if_fail (event != NULL, FALSE);
812
813   if (event->button == 1)
814     {
815       button = GTK_BUTTON (widget);
816       gtk_grab_remove (GTK_WIDGET (button));
817       gtk_button_released (button);
818     }
819
820   return TRUE;
821 }
822
823 static gint
824 gtk_button_enter_notify (GtkWidget        *widget,
825                          GdkEventCrossing *event)
826 {
827   GtkButton *button;
828   GtkWidget *event_widget;
829
830   g_return_val_if_fail (widget != NULL, FALSE);
831   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
832   g_return_val_if_fail (event != NULL, FALSE);
833
834   button = GTK_BUTTON (widget);
835   event_widget = gtk_get_event_widget ((GdkEvent*) event);
836
837   if ((event_widget == widget) &&
838       (event->detail != GDK_NOTIFY_INFERIOR))
839     {
840       button->in_button = TRUE;
841       gtk_button_enter (button);
842     }
843
844   return FALSE;
845 }
846
847 static gint
848 gtk_button_leave_notify (GtkWidget        *widget,
849                          GdkEventCrossing *event)
850 {
851   GtkButton *button;
852   GtkWidget *event_widget;
853
854   g_return_val_if_fail (widget != NULL, FALSE);
855   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
856   g_return_val_if_fail (event != NULL, FALSE);
857
858   button = GTK_BUTTON (widget);
859   event_widget = gtk_get_event_widget ((GdkEvent*) event);
860
861   if ((event_widget == widget) &&
862       (event->detail != GDK_NOTIFY_INFERIOR))
863     {
864       button->in_button = FALSE;
865       gtk_button_leave (button);
866     }
867
868   return FALSE;
869 }
870
871 static gint
872 gtk_button_focus_in (GtkWidget     *widget,
873                      GdkEventFocus *event)
874 {
875   g_return_val_if_fail (widget != NULL, FALSE);
876   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
877   g_return_val_if_fail (event != NULL, FALSE);
878
879   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
880   gtk_widget_draw_focus (widget);
881
882   return FALSE;
883 }
884
885 static gint
886 gtk_button_focus_out (GtkWidget     *widget,
887                       GdkEventFocus *event)
888 {
889   g_return_val_if_fail (widget != NULL, FALSE);
890   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
891   g_return_val_if_fail (event != NULL, FALSE);
892
893   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
894   gtk_widget_draw_focus (widget);
895
896   return FALSE;
897 }
898
899 static void
900 gtk_button_add (GtkContainer *container,
901                 GtkWidget    *widget)
902 {
903   g_return_if_fail (container != NULL);
904   g_return_if_fail (widget != NULL);
905
906   if (GTK_CONTAINER_CLASS (parent_class)->add)
907     GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
908
909   GTK_BUTTON (container)->child = GTK_BIN (container)->child;
910 }
911
912 static void
913 gtk_button_remove (GtkContainer *container,
914                    GtkWidget    *widget)
915 {
916   g_return_if_fail (container != NULL);
917   g_return_if_fail (widget != NULL);
918
919   if (GTK_CONTAINER_CLASS (parent_class)->remove)
920     GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
921
922   GTK_BUTTON (container)->child = GTK_BIN (container)->child;
923 }
924
925 static void
926 gtk_real_button_pressed (GtkButton *button)
927 {
928   GtkStateType new_state;
929
930   g_return_if_fail (button != NULL);
931   g_return_if_fail (GTK_IS_BUTTON (button));
932
933   button->button_down = TRUE;
934
935   new_state = (button->in_button ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL);
936
937   if (GTK_WIDGET_STATE (button) != new_state)
938     {
939       gtk_widget_set_state (GTK_WIDGET (button), new_state);
940       gtk_widget_queue_draw (GTK_WIDGET (button));
941     }
942 }
943
944 static void
945 gtk_real_button_released (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->button_down)
953     {
954       button->button_down = FALSE;
955
956       if (button->in_button)
957         gtk_button_clicked (button);
958
959       new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL);
960
961       if (GTK_WIDGET_STATE (button) != new_state)
962         {
963           gtk_widget_set_state (GTK_WIDGET (button), new_state);
964           /* We _draw () instead of queue_draw so that if the operation
965            * blocks, the label doesn't vanish.
966            */
967           gtk_widget_draw (GTK_WIDGET (button), NULL);
968         }
969     }
970 }
971
972 static void
973 gtk_real_button_enter (GtkButton *button)
974 {
975   GtkStateType new_state;
976
977   g_return_if_fail (button != NULL);
978   g_return_if_fail (GTK_IS_BUTTON (button));
979
980   new_state = (button->button_down ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT);
981
982   if (GTK_WIDGET_STATE (button) != new_state)
983     {
984       gtk_widget_set_state (GTK_WIDGET (button), new_state);
985       gtk_widget_queue_draw (GTK_WIDGET (button));
986     }
987 }
988
989 static void
990 gtk_real_button_leave (GtkButton *button)
991 {
992   g_return_if_fail (button != NULL);
993   g_return_if_fail (GTK_IS_BUTTON (button));
994
995   if (GTK_WIDGET_STATE (button) != GTK_STATE_NORMAL)
996     {
997       gtk_widget_set_state (GTK_WIDGET (button), GTK_STATE_NORMAL);
998       gtk_widget_queue_draw (GTK_WIDGET (button));
999     }
1000 }