]> Pileus Git - ~andy/gtk/blob - gtk/gtkbutton.c
typedef gint gboolean; this is needed to provide portability with
[~andy/gtk] / gtk / gtkbutton.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU 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 };
44
45
46
47 static void gtk_button_class_init     (GtkButtonClass   *klass);
48 static void gtk_button_init           (GtkButton        *button);
49 static void gtk_button_set_arg        (GtkButton        *button,
50                                        GtkArg           *arg,
51                                        guint             arg_id);
52 static void gtk_button_map            (GtkWidget        *widget);
53 static void gtk_button_unmap          (GtkWidget        *widget);
54 static void gtk_button_realize        (GtkWidget        *widget);
55 static void gtk_button_size_request   (GtkWidget        *widget,
56                                        GtkRequisition   *requisition);
57 static void gtk_button_size_allocate  (GtkWidget        *widget,
58                                        GtkAllocation    *allocation);
59 static void gtk_button_paint          (GtkWidget        *widget,
60                                        GdkRectangle     *area);
61 static void gtk_button_draw           (GtkWidget        *widget,
62                                        GdkRectangle     *area);
63 static void gtk_button_draw_focus     (GtkWidget        *widget);
64 static void gtk_button_draw_default   (GtkWidget        *widget);
65 static gint gtk_button_expose         (GtkWidget        *widget,
66                                        GdkEventExpose   *event);
67 static gint gtk_button_button_press   (GtkWidget        *widget,
68                                        GdkEventButton   *event);
69 static gint gtk_button_button_release (GtkWidget        *widget,
70                                        GdkEventButton   *event);
71 static gint gtk_button_enter_notify   (GtkWidget        *widget,
72                                        GdkEventCrossing *event);
73 static gint gtk_button_leave_notify   (GtkWidget        *widget,
74                                        GdkEventCrossing *event);
75 static gint gtk_button_focus_in       (GtkWidget        *widget,
76                                        GdkEventFocus    *event);
77 static gint gtk_button_focus_out      (GtkWidget        *widget,
78                                        GdkEventFocus    *event);
79 static void gtk_button_add            (GtkContainer     *container,
80                                        GtkWidget        *widget);
81 static void gtk_button_remove         (GtkContainer     *container,
82                                        GtkWidget        *widget);
83 static void gtk_button_foreach        (GtkContainer     *container,
84                                        GtkCallback       callback,
85                                        gpointer          callback_data);
86 static void gtk_real_button_pressed   (GtkButton        *button);
87 static void gtk_real_button_released  (GtkButton        *button);
88 static void gtk_real_button_enter     (GtkButton        *button);
89 static void gtk_real_button_leave     (GtkButton        *button);
90
91
92 static GtkContainerClass *parent_class;
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         (GtkArgSetFunc) gtk_button_set_arg,
111         (GtkArgGetFunc) NULL,
112       };
113
114       button_type = gtk_type_unique (gtk_container_get_type (), &button_info);
115       gtk_type_set_chunk_alloc (button_type, 16);
116     }
117
118   return button_type;
119 }
120
121 static void
122 gtk_button_class_init (GtkButtonClass *klass)
123 {
124   GtkObjectClass *object_class;
125   GtkWidgetClass *widget_class;
126   GtkContainerClass *container_class;
127
128   object_class = (GtkObjectClass*) klass;
129   widget_class = (GtkWidgetClass*) klass;
130   container_class = (GtkContainerClass*) klass;
131
132   parent_class = gtk_type_class (gtk_container_get_type ());
133
134   gtk_object_add_arg_type ("GtkButton::label", GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_LABEL);
135
136   button_signals[PRESSED] =
137     gtk_signal_new ("pressed",
138                     GTK_RUN_FIRST,
139                     object_class->type,
140                     GTK_SIGNAL_OFFSET (GtkButtonClass, pressed),
141                     gtk_signal_default_marshaller,
142                     GTK_TYPE_NONE, 0);
143   button_signals[RELEASED] =
144     gtk_signal_new ("released",
145                     GTK_RUN_FIRST,
146                     object_class->type,
147                     GTK_SIGNAL_OFFSET (GtkButtonClass, released),
148                     gtk_signal_default_marshaller,
149                     GTK_TYPE_NONE, 0);
150   button_signals[CLICKED] =
151     gtk_signal_new ("clicked",
152                     GTK_RUN_FIRST,
153                     object_class->type,
154                     GTK_SIGNAL_OFFSET (GtkButtonClass, clicked),
155                     gtk_signal_default_marshaller,
156                     GTK_TYPE_NONE, 0);
157   button_signals[ENTER] =
158     gtk_signal_new ("enter",
159                     GTK_RUN_FIRST,
160                     object_class->type,
161                     GTK_SIGNAL_OFFSET (GtkButtonClass, enter),
162                     gtk_signal_default_marshaller,
163                     GTK_TYPE_NONE, 0);
164   button_signals[LEAVE] =
165     gtk_signal_new ("leave",
166                     GTK_RUN_FIRST,
167                     object_class->type,
168                     GTK_SIGNAL_OFFSET (GtkButtonClass, leave),
169                     gtk_signal_default_marshaller,
170                     GTK_TYPE_NONE, 0);
171
172   gtk_object_class_add_signals (object_class, button_signals, LAST_SIGNAL);
173
174   widget_class->activate_signal = button_signals[CLICKED];
175   widget_class->map = gtk_button_map;
176   widget_class->unmap = gtk_button_unmap;
177   widget_class->realize = gtk_button_realize;
178   widget_class->draw = gtk_button_draw;
179   widget_class->draw_focus = gtk_button_draw_focus;
180   widget_class->draw_default = gtk_button_draw_default;
181   widget_class->size_request = gtk_button_size_request;
182   widget_class->size_allocate = gtk_button_size_allocate;
183   widget_class->expose_event = gtk_button_expose;
184   widget_class->button_press_event = gtk_button_button_press;
185   widget_class->button_release_event = gtk_button_button_release;
186   widget_class->enter_notify_event = gtk_button_enter_notify;
187   widget_class->leave_notify_event = gtk_button_leave_notify;
188   widget_class->focus_in_event = gtk_button_focus_in;
189   widget_class->focus_out_event = gtk_button_focus_out;
190
191   container_class->add = gtk_button_add;
192   container_class->remove = gtk_button_remove;
193   container_class->foreach = gtk_button_foreach;
194
195   klass->pressed = gtk_real_button_pressed;
196   klass->released = gtk_real_button_released;
197   klass->clicked = NULL;
198   klass->enter = gtk_real_button_enter;
199   klass->leave = gtk_real_button_leave;
200 }
201
202 static void
203 gtk_button_init (GtkButton *button)
204 {
205   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_FOCUS);
206
207   button->child = NULL;
208   button->in_button = FALSE;
209   button->button_down = FALSE;
210   button->relief = GTK_RELIEF_NORMAL;
211 }
212
213 static void
214 gtk_button_set_arg (GtkButton *button,
215                     GtkArg    *arg,
216                     guint      arg_id)
217 {
218   GtkWidget *label;
219
220   switch (arg_id)
221     {
222     case ARG_LABEL:
223       gtk_container_disable_resize (GTK_CONTAINER (button));
224
225       if (button->child)
226         {
227           gtk_widget_unparent (button->child);
228           button->child = NULL;
229         }
230
231       label = gtk_label_new (GTK_VALUE_STRING(*arg));
232       gtk_widget_show (label);
233
234       gtk_container_add (GTK_CONTAINER (button), label);
235       gtk_container_enable_resize (GTK_CONTAINER (button));
236       break;
237     default:
238       arg->type = GTK_TYPE_INVALID;
239       break;
240     }
241 }
242
243 GtkWidget*
244 gtk_button_new (void)
245 {
246   return GTK_WIDGET (gtk_type_new (gtk_button_get_type ()));
247 }
248
249 GtkWidget*
250 gtk_button_new_with_label (const gchar *label)
251 {
252   GtkWidget *button;
253   GtkWidget *label_widget;
254
255   button = gtk_button_new ();
256   label_widget = gtk_label_new (label);
257   gtk_misc_set_alignment (GTK_MISC (label_widget), 0.5, 0.5);
258
259   gtk_container_add (GTK_CONTAINER (button), label_widget);
260   gtk_widget_show (label_widget);
261
262   return button;
263 }
264
265 void
266 gtk_button_pressed (GtkButton *button)
267 {
268   gtk_signal_emit (GTK_OBJECT (button), button_signals[PRESSED]);
269 }
270
271 void
272 gtk_button_released (GtkButton *button)
273 {
274   gtk_signal_emit (GTK_OBJECT (button), button_signals[RELEASED]);
275 }
276
277 void
278 gtk_button_clicked (GtkButton *button)
279 {
280   gtk_signal_emit (GTK_OBJECT (button), button_signals[CLICKED]);
281 }
282
283 void
284 gtk_button_enter (GtkButton *button)
285 {
286   gtk_signal_emit (GTK_OBJECT (button), button_signals[ENTER]);
287 }
288
289 void
290 gtk_button_leave (GtkButton *button)
291 {
292   gtk_signal_emit (GTK_OBJECT (button), button_signals[LEAVE]);
293 }
294
295 void
296 gtk_button_set_relief (GtkButton *button,
297                        GtkReliefStyle newrelief)
298 {
299   g_return_if_fail (button != NULL);
300   g_return_if_fail (GTK_IS_BUTTON (button));
301
302   button->relief = newrelief;
303 }
304
305 GtkReliefStyle
306 gtk_button_get_relief(GtkButton *button)
307 {
308   g_return_val_if_fail (button != NULL, GTK_RELIEF_NORMAL);
309   g_return_val_if_fail (GTK_IS_BUTTON (button), GTK_RELIEF_NORMAL);
310
311   return button->relief;
312 }
313
314 static void
315 gtk_button_map (GtkWidget *widget)
316 {
317   GtkButton *button;
318
319   g_return_if_fail (widget != NULL);
320   g_return_if_fail (GTK_IS_BUTTON (widget));
321
322   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
323   gdk_window_show (widget->window);
324
325   button = GTK_BUTTON (widget);
326
327   if (button->child &&
328       GTK_WIDGET_VISIBLE (button->child) &&
329       !GTK_WIDGET_MAPPED (button->child))
330     gtk_widget_map (button->child);
331 }
332
333 static void
334 gtk_button_unmap (GtkWidget *widget)
335 {
336   g_return_if_fail (widget != NULL);
337   g_return_if_fail (GTK_IS_BUTTON (widget));
338
339   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
340   gdk_window_hide (widget->window);
341 }
342
343 static void
344 gtk_button_realize (GtkWidget *widget)
345 {
346   GtkButton *button;
347   GdkWindowAttr attributes;
348   gint attributes_mask;
349   gint border_width;
350
351   g_return_if_fail (widget != NULL);
352   g_return_if_fail (GTK_IS_BUTTON (widget));
353
354   button = GTK_BUTTON (widget);
355   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
356
357   border_width = GTK_CONTAINER (widget)->border_width;
358
359   attributes.window_type = GDK_WINDOW_CHILD;
360   attributes.x = widget->allocation.x + border_width;
361   attributes.y = widget->allocation.y + border_width;
362   attributes.width = widget->allocation.width - border_width * 2;
363   attributes.height = widget->allocation.height - border_width * 2;
364   attributes.wclass = GDK_INPUT_OUTPUT;
365   attributes.visual = gtk_widget_get_visual (widget);
366   attributes.colormap = gtk_widget_get_colormap (widget);
367   attributes.event_mask = gtk_widget_get_events (widget);
368   attributes.event_mask |= (GDK_EXPOSURE_MASK |
369                             GDK_BUTTON_PRESS_MASK |
370                             GDK_BUTTON_RELEASE_MASK |
371                             GDK_ENTER_NOTIFY_MASK |
372                             GDK_LEAVE_NOTIFY_MASK);
373
374   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
375
376   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
377   gdk_window_set_user_data (widget->window, button);
378
379   widget->style = gtk_style_attach (widget->style, widget->window);
380   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
381 }
382
383 static void
384 gtk_button_size_request (GtkWidget      *widget,
385                          GtkRequisition *requisition)
386 {
387   GtkButton *button;
388
389   g_return_if_fail (widget != NULL);
390   g_return_if_fail (GTK_IS_BUTTON (widget));
391   g_return_if_fail (requisition != NULL);
392
393   button = GTK_BUTTON (widget);
394
395   requisition->width = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
396                         GTK_WIDGET (widget)->style->klass->xthickness) * 2;
397   requisition->height = (GTK_CONTAINER (widget)->border_width + CHILD_SPACING +
398                          GTK_WIDGET (widget)->style->klass->ythickness) * 2;
399
400   if (GTK_WIDGET_CAN_DEFAULT (widget))
401     {
402       requisition->width += (GTK_WIDGET (widget)->style->klass->xthickness * 2 +
403                              DEFAULT_SPACING);
404       requisition->height += (GTK_WIDGET (widget)->style->klass->ythickness * 2 +
405                               DEFAULT_SPACING);
406     }
407
408   if (button->child && GTK_WIDGET_VISIBLE (button->child))
409     {
410       gtk_widget_size_request (button->child, &button->child->requisition);
411
412       requisition->width += button->child->requisition.width;
413       requisition->height += button->child->requisition.height;
414     }
415 }
416
417 static void
418 gtk_button_size_allocate (GtkWidget     *widget,
419                           GtkAllocation *allocation)
420 {
421   GtkButton *button;
422   GtkAllocation child_allocation;
423   gint border_width;
424
425   g_return_if_fail (widget != NULL);
426   g_return_if_fail (GTK_IS_BUTTON (widget));
427   g_return_if_fail (allocation != NULL);
428
429   widget->allocation = *allocation;
430   border_width = GTK_CONTAINER (widget)->border_width;
431
432   if (GTK_WIDGET_REALIZED (widget))
433     gdk_window_move_resize (widget->window,
434                             widget->allocation.x + border_width,
435                             widget->allocation.y + border_width,
436                             widget->allocation.width - border_width * 2,
437                             widget->allocation.height - border_width * 2);
438
439   button = GTK_BUTTON (widget);
440
441   if (button->child && GTK_WIDGET_VISIBLE (button->child))
442     {
443       child_allocation.x = (CHILD_SPACING + GTK_WIDGET (widget)->style->klass->xthickness);
444       child_allocation.y = (CHILD_SPACING + GTK_WIDGET (widget)->style->klass->ythickness);
445
446       child_allocation.width = MAX (1, widget->allocation.width - child_allocation.x * 2 -
447                                  border_width * 2);
448       child_allocation.height = MAX (1, widget->allocation.height - child_allocation.y * 2 -
449                                   border_width * 2);
450
451       if (GTK_WIDGET_CAN_DEFAULT (button))
452         {
453           child_allocation.x += (GTK_WIDGET (widget)->style->klass->xthickness +
454                                  DEFAULT_LEFT_POS);
455           child_allocation.y += (GTK_WIDGET (widget)->style->klass->ythickness +
456                                  DEFAULT_TOP_POS);
457           child_allocation.width =  MAX (1, child_allocation.width -
458                                         (GTK_WIDGET (widget)->style->klass->xthickness * 2 + DEFAULT_SPACING));
459           child_allocation.height = MAX (1, child_allocation.height -
460                                          (GTK_WIDGET (widget)->style->klass->xthickness * 2 + DEFAULT_SPACING));
461         }
462
463       gtk_widget_size_allocate (button->child, &child_allocation);
464     }
465 }
466
467 /*
468  * +------------------------------------------------+
469  * |                   BORDER                       |
470  * |  +------------------------------------------+  |
471  * |  |\\\\\\\\\\\\\\\\DEFAULT\\\\\\\\\\\\\\\\\  |  |
472  * |  |\\+------------------------------------+  |  |
473  * |  |\\| |           SPACING       3      | |  |  |
474  * |  |\\| +--------------------------------+ |  |  |
475  * |  |\\| |########## FOCUS ###############| |  |  |
476  * |  |\\| |#+----------------------------+#| |  |  |
477  * |  |\\| |#|         RELIEF            \|#| |  |  |
478  * |  |\\| |#|  +-----------------------+\|#| |  |  |
479  * |  |\\|1|#|  +     THE TEXT          +\|#|2|  |  |
480  * |  |\\| |#|  +-----------------------+\|#| |  |  |
481  * |  |\\| |#| \\\\\ ythickness \\\\\\\\\\|#| |  |  |
482  * |  |\\| |#+----------------------------+#| |  |  |
483  * |  |\\| |########### 1 ##################| |  |  |
484  * |  |\\| +--------------------------------+ |  |  |
485  * |  |\\| |        default spacing   4     | |  |  |
486  * |  |\\+------------------------------------+  |  |
487  * |  |\            ythickness                   |  |
488  * |  +------------------------------------------+  |
489  * |                border_width                    |
490  * +------------------------------------------------+
491  */
492
493 static void
494 gtk_button_paint (GtkWidget    *widget,
495                   GdkRectangle *area)
496 {
497   GdkRectangle restrict_area;
498   GdkRectangle outer_area;
499   GdkRectangle tmp_area;
500   GdkRectangle new_area;
501   gint xthickness;
502   gint ythickness;
503
504   g_return_if_fail (widget != NULL);
505   g_return_if_fail (GTK_IS_BUTTON (widget));
506
507   xthickness = widget->style->klass->xthickness;
508   ythickness = widget->style->klass->ythickness;
509
510   if (GTK_WIDGET_DRAWABLE (widget))
511     {
512       restrict_area.x = xthickness;
513       restrict_area.y = ythickness;
514       restrict_area.width = GTK_WIDGET (widget)->allocation.width -
515         restrict_area.x * 2 - GTK_CONTAINER (widget)->border_width * 2;
516       restrict_area.height = GTK_WIDGET (widget)->allocation.height -
517         restrict_area.y * 2 - GTK_CONTAINER (widget)->border_width * 2;
518
519       outer_area = restrict_area;
520
521       if (GTK_WIDGET_CAN_DEFAULT (widget))
522         {
523           restrict_area.x += DEFAULT_LEFT_POS;
524           restrict_area.y += DEFAULT_TOP_POS;
525           restrict_area.width -= DEFAULT_SPACING;
526           restrict_area.height -= DEFAULT_SPACING;
527         }
528
529       if (gdk_rectangle_intersect (area, &restrict_area, &new_area))
530         {
531           if ((GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT) &&
532               (GTK_BUTTON (widget)->relief == GTK_RELIEF_NONE))
533             gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
534           else
535             gtk_style_set_background (widget->style, widget->window, GTK_WIDGET_STATE (widget));
536           gdk_window_clear_area (widget->window,
537                                  new_area.x, new_area.y,
538                                  new_area.width, new_area.height);
539         }
540
541       if (GTK_WIDGET_CAN_DEFAULT (widget))
542         {
543           /* Now fill spacing area between the default border and the button */
544
545  /* 1 */  tmp_area = outer_area;
546           tmp_area.width = restrict_area.x - outer_area.x;
547           if (gdk_rectangle_intersect (area, &tmp_area, &new_area))
548             gdk_draw_rectangle (widget->window,
549                                 widget->style->bg_gc[GTK_STATE_NORMAL],
550                                 TRUE,
551                                 new_area.x, new_area.y,
552                                 new_area.width, new_area.height);
553
554   /* 2 */ tmp_area.x = restrict_area.x + restrict_area.width;
555
556           if (gdk_rectangle_intersect (area, &tmp_area, &new_area))
557             gdk_draw_rectangle (widget->window,
558                                 widget->style->bg_gc[GTK_STATE_NORMAL],
559                                 TRUE,
560                                 new_area.x, new_area.y,
561                                 new_area.width, new_area.height);
562
563   /* 3 */ tmp_area.width = restrict_area.width;
564           tmp_area.height = restrict_area.y - outer_area.y;
565           tmp_area.x = restrict_area.x;
566
567           if (gdk_rectangle_intersect (area, &tmp_area, &new_area))
568             gdk_draw_rectangle (widget->window,
569                                 widget->style->bg_gc[GTK_STATE_NORMAL],
570                                 TRUE,
571                                 new_area.x, new_area.y,
572                                 new_area.width, new_area.height);
573
574   /* 4 */ tmp_area.y = restrict_area.y + restrict_area.height;
575
576           if (gdk_rectangle_intersect (area, &tmp_area, &new_area))
577             gdk_draw_rectangle (widget->window,
578                                 widget->style->bg_gc[GTK_STATE_NORMAL],
579                                 TRUE,
580                                 new_area.x, new_area.y,
581                                 new_area.width, new_area.height);
582         }
583     }
584 }
585
586 static void
587 gtk_button_draw (GtkWidget    *widget,
588                  GdkRectangle *area)
589 {
590   GtkButton *button;
591   GdkRectangle child_area;
592   GdkRectangle tmp_area;
593
594   g_return_if_fail (widget != NULL);
595   g_return_if_fail (GTK_IS_BUTTON (widget));
596   g_return_if_fail (area != NULL);
597
598   if (GTK_WIDGET_DRAWABLE (widget))
599     {
600       button = GTK_BUTTON (widget);
601
602       tmp_area = *area;
603       tmp_area.x -= GTK_CONTAINER (button)->border_width;
604       tmp_area.y -= GTK_CONTAINER (button)->border_width;
605
606       gtk_button_paint (widget, &tmp_area);
607
608       if (button->child && gtk_widget_intersect (button->child, &tmp_area, &child_area))
609         gtk_widget_draw (button->child, &child_area);
610
611       gtk_widget_draw_default (widget);
612       gtk_widget_draw_focus (widget);
613     }
614 }
615
616 static void
617 gtk_button_draw_focus (GtkWidget *widget)
618 {
619   GtkButton *button;
620   GtkShadowType shadow_type;
621   gint width, height;
622   gint x, y;
623
624   g_return_if_fail (widget != NULL);
625   g_return_if_fail (GTK_IS_BUTTON (widget));
626
627   if (GTK_WIDGET_DRAWABLE (widget))
628     {
629       button = GTK_BUTTON (widget);
630
631       x = 0;
632       y = 0;
633       width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2;
634       height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2;
635
636       if (GTK_WIDGET_CAN_DEFAULT (widget))
637         {
638           x += widget->style->klass->xthickness;
639           y += widget->style->klass->ythickness;
640           width -= 2 * x + DEFAULT_SPACING;
641           height -= 2 * y + DEFAULT_SPACING;
642           x += DEFAULT_LEFT_POS;
643           y += DEFAULT_TOP_POS;
644         }
645
646       if (GTK_WIDGET_HAS_FOCUS (widget))
647         {
648           x += 1;
649           y += 1;
650           width -= 2;
651           height -= 2;
652         }
653       else
654         {
655           if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE)
656             gdk_draw_rectangle (widget->window,
657                                 widget->style->bg_gc[GTK_WIDGET_STATE (widget)], FALSE,
658                                 x + 1, y + 1, width - 4, height - 4);
659           else if (button->relief == GTK_RELIEF_NORMAL)
660             gdk_draw_rectangle (widget->window,
661                                 widget->style->bg_gc[GTK_WIDGET_STATE (widget)], FALSE,
662                                 x + 2, y + 2, width - 5, height - 5);
663           else
664             gdk_draw_rectangle (widget->window,
665                                 widget->style->bg_gc[GTK_WIDGET_STATE (widget)], FALSE,
666                                 x, y, width - 1, height - 1);
667         }
668
669       if (GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE)
670         shadow_type = GTK_SHADOW_IN;
671       else
672         shadow_type = GTK_SHADOW_OUT;
673
674       if ((button->relief == GTK_RELIEF_NORMAL) ||
675           ((GTK_WIDGET_STATE (widget) != GTK_STATE_NORMAL) &&
676            (GTK_WIDGET_STATE (widget) != GTK_STATE_INSENSITIVE)))
677         {
678           gtk_draw_shadow (widget->style, widget->window,
679                            GTK_WIDGET_STATE (widget), shadow_type,
680                            x, y, width, height);
681         }
682
683       if (GTK_WIDGET_HAS_FOCUS (widget))
684         {
685           x -= 1;
686           y -= 1;
687           width += 2;
688           height += 2;
689
690           gdk_draw_rectangle (widget->window,
691                               widget->style->black_gc, FALSE,
692                               x, y, width - 1, height - 1);
693         }
694     }
695 }
696
697 static void
698 gtk_button_draw_default (GtkWidget *widget)
699 {
700   gint width, height;
701   gint x, y;
702
703   g_return_if_fail (widget != NULL);
704   g_return_if_fail (GTK_IS_BUTTON (widget));
705
706   if (GTK_WIDGET_DRAWABLE (widget))
707     {
708       x = 0;
709       y = 0;
710       width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2;
711       height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2;
712
713       if (GTK_WIDGET_HAS_DEFAULT (widget) && gtk_button_get_relief (GTK_BUTTON (widget)) == GTK_RELIEF_NORMAL)
714         {
715           gtk_draw_shadow (widget->style, widget->window,
716                            GTK_STATE_NORMAL, GTK_SHADOW_IN,
717                            x, y, width, height);
718         }
719       else
720         {
721           gdk_draw_rectangle (widget->window, widget->style->bg_gc[GTK_STATE_NORMAL],
722                               FALSE, x, y, width - 1, height - 1);
723           gdk_draw_rectangle (widget->window, widget->style->bg_gc[GTK_STATE_NORMAL],
724                               FALSE, x + 1, y + 1, width - 3, height - 3);
725         }
726     }
727 }
728
729 static gint
730 gtk_button_expose (GtkWidget      *widget,
731                    GdkEventExpose *event)
732 {
733   GtkButton *button;
734   GdkEventExpose child_event;
735
736   g_return_val_if_fail (widget != NULL, FALSE);
737   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
738   g_return_val_if_fail (event != NULL, FALSE);
739
740   if (GTK_WIDGET_DRAWABLE (widget))
741     {
742       button = GTK_BUTTON (widget);
743
744       gtk_button_paint (widget, &event->area);
745
746       child_event = *event;
747       if (button->child && GTK_WIDGET_NO_WINDOW (button->child) &&
748           gtk_widget_intersect (button->child, &event->area, &child_event.area))
749         gtk_widget_event (button->child, (GdkEvent*) &child_event);
750
751       gtk_widget_draw_default (widget);
752       gtk_widget_draw_focus (widget);
753     }
754
755   return FALSE;
756 }
757
758 static gint
759 gtk_button_button_press (GtkWidget      *widget,
760                          GdkEventButton *event)
761 {
762   GtkButton *button;
763
764   g_return_val_if_fail (widget != NULL, FALSE);
765   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
766   g_return_val_if_fail (event != NULL, FALSE);
767
768   if (event->type == GDK_BUTTON_PRESS)
769     {
770       button = GTK_BUTTON (widget);
771
772       if (GTK_WIDGET_CAN_DEFAULT (widget) && (event->button == 1))
773         gtk_widget_grab_default (widget);
774       if (!GTK_WIDGET_HAS_FOCUS (widget))
775         gtk_widget_grab_focus (widget);
776
777       if (event->button == 1)
778         {
779           gtk_grab_add (GTK_WIDGET (button));
780           gtk_button_pressed (button);
781         }
782     }
783
784   return TRUE;
785 }
786
787 static gint
788 gtk_button_button_release (GtkWidget      *widget,
789                            GdkEventButton *event)
790 {
791   GtkButton *button;
792
793   g_return_val_if_fail (widget != NULL, FALSE);
794   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
795   g_return_val_if_fail (event != NULL, FALSE);
796
797   if (event->button == 1)
798     {
799       button = GTK_BUTTON (widget);
800       gtk_grab_remove (GTK_WIDGET (button));
801       gtk_button_released (button);
802     }
803
804   return TRUE;
805 }
806
807 static gint
808 gtk_button_enter_notify (GtkWidget        *widget,
809                          GdkEventCrossing *event)
810 {
811   GtkButton *button;
812   GtkWidget *event_widget;
813
814   g_return_val_if_fail (widget != NULL, FALSE);
815   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
816   g_return_val_if_fail (event != NULL, FALSE);
817
818   button = GTK_BUTTON (widget);
819   event_widget = gtk_get_event_widget ((GdkEvent*) event);
820
821   if ((event_widget == widget) &&
822       (event->detail != GDK_NOTIFY_INFERIOR))
823     {
824       button->in_button = TRUE;
825       gtk_button_enter (button);
826     }
827
828   return FALSE;
829 }
830
831 static gint
832 gtk_button_leave_notify (GtkWidget        *widget,
833                          GdkEventCrossing *event)
834 {
835   GtkButton *button;
836   GtkWidget *event_widget;
837
838   g_return_val_if_fail (widget != NULL, FALSE);
839   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
840   g_return_val_if_fail (event != NULL, FALSE);
841
842   button = GTK_BUTTON (widget);
843   event_widget = gtk_get_event_widget ((GdkEvent*) event);
844
845   if ((event_widget == widget) &&
846       (event->detail != GDK_NOTIFY_INFERIOR))
847     {
848       button->in_button = FALSE;
849       gtk_button_leave (button);
850     }
851
852   return FALSE;
853 }
854
855 static gint
856 gtk_button_focus_in (GtkWidget     *widget,
857                      GdkEventFocus *event)
858 {
859   g_return_val_if_fail (widget != NULL, FALSE);
860   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
861   g_return_val_if_fail (event != NULL, FALSE);
862
863   GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
864   gtk_widget_draw_focus (widget);
865
866   return FALSE;
867 }
868
869 static gint
870 gtk_button_focus_out (GtkWidget     *widget,
871                       GdkEventFocus *event)
872 {
873   g_return_val_if_fail (widget != NULL, FALSE);
874   g_return_val_if_fail (GTK_IS_BUTTON (widget), FALSE);
875   g_return_val_if_fail (event != NULL, FALSE);
876
877   GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
878   gtk_widget_draw_focus (widget);
879
880   return FALSE;
881 }
882
883 static void
884 gtk_button_add (GtkContainer *container,
885                 GtkWidget    *widget)
886 {
887   GtkButton *button;
888
889   g_return_if_fail (container != NULL);
890   g_return_if_fail (GTK_IS_BUTTON (container));
891   g_return_if_fail (widget != NULL);
892   g_return_if_fail (gtk_widget_basic (widget));
893
894   button = GTK_BUTTON (container);
895
896   if (!button->child)
897     {
898       gtk_widget_set_parent (widget, GTK_WIDGET (container));
899
900       if (GTK_WIDGET_VISIBLE (widget->parent))
901         {
902           if (GTK_WIDGET_REALIZED (widget->parent) &&
903               !GTK_WIDGET_REALIZED (widget))
904             gtk_widget_realize (widget);
905
906           if (GTK_WIDGET_MAPPED (widget->parent) &&
907               !GTK_WIDGET_MAPPED (widget))
908             gtk_widget_map (widget);
909         }
910
911       button->child = widget;
912
913       if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container))
914         gtk_widget_queue_resize (widget);
915     }
916 }
917
918 static void
919 gtk_button_remove (GtkContainer *container,
920                    GtkWidget    *widget)
921 {
922   GtkButton *button;
923
924   g_return_if_fail (container != NULL);
925   g_return_if_fail (GTK_IS_BUTTON (container));
926   g_return_if_fail (widget != NULL);
927
928   button = GTK_BUTTON (container);
929
930   if (button->child == widget)
931     {
932       gboolean widget_was_visible = GTK_WIDGET_VISIBLE(widget);
933
934       gtk_widget_unparent (widget);
935
936       button->child = NULL;
937
938       if (widget_was_visible && GTK_WIDGET_VISIBLE (container))
939         gtk_widget_queue_resize (GTK_WIDGET (container));
940
941     }
942 }
943
944 static void
945 gtk_button_foreach (GtkContainer *container,
946                     GtkCallback   callback,
947                     gpointer      callback_data)
948 {
949   GtkButton *button;
950
951   g_return_if_fail (container != NULL);
952   g_return_if_fail (GTK_IS_BUTTON (container));
953   g_return_if_fail (callback != NULL);
954
955   button = GTK_BUTTON (container);
956
957   if (button->child)
958     (* callback) (button->child, callback_data);
959 }
960
961 static void
962 gtk_real_button_pressed (GtkButton *button)
963 {
964   GtkStateType new_state;
965
966   g_return_if_fail (button != NULL);
967   g_return_if_fail (GTK_IS_BUTTON (button));
968
969   button->button_down = TRUE;
970
971   new_state = (button->in_button ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL);
972
973   if (GTK_WIDGET_STATE (button) != new_state)
974     {
975       gtk_widget_set_state (GTK_WIDGET (button), new_state);
976       gtk_widget_queue_draw (GTK_WIDGET (button));
977     }
978 }
979
980 static void
981 gtk_real_button_released (GtkButton *button)
982 {
983   GtkStateType new_state;
984
985   g_return_if_fail (button != NULL);
986   g_return_if_fail (GTK_IS_BUTTON (button));
987
988   if (button->button_down)
989     {
990       button->button_down = FALSE;
991
992       if (button->in_button)
993         gtk_button_clicked (button);
994
995       new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL);
996
997       if (GTK_WIDGET_STATE (button) != new_state)
998         {
999           gtk_widget_set_state (GTK_WIDGET (button), new_state);
1000           /* We _draw () instead of queue_draw so that if the operation
1001            * blocks, the label doesn't vanish.
1002            */
1003           gtk_widget_draw (GTK_WIDGET (button), NULL);
1004         }
1005     }
1006 }
1007
1008 static void
1009 gtk_real_button_enter (GtkButton *button)
1010 {
1011   GtkStateType new_state;
1012
1013   g_return_if_fail (button != NULL);
1014   g_return_if_fail (GTK_IS_BUTTON (button));
1015
1016   new_state = (button->button_down ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT);
1017
1018   if (GTK_WIDGET_STATE (button) != new_state)
1019     {
1020       gtk_widget_set_state (GTK_WIDGET (button), new_state);
1021       gtk_widget_queue_draw (GTK_WIDGET (button));
1022     }
1023 }
1024
1025 static void
1026 gtk_real_button_leave (GtkButton *button)
1027 {
1028   g_return_if_fail (button != NULL);
1029   g_return_if_fail (GTK_IS_BUTTON (button));
1030
1031   if (GTK_WIDGET_STATE (button) != GTK_STATE_NORMAL)
1032     {
1033       gtk_widget_set_state (GTK_WIDGET (button), GTK_STATE_NORMAL);
1034       gtk_widget_queue_draw (GTK_WIDGET (button));
1035     }
1036 }