]> Pileus Git - ~andy/gtk/blob - gtk/gtkframe.c
Add hidden aliases for exported symbols which are used internally in order
[~andy/gtk] / gtk / gtkframe.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <config.h>
28 #include <string.h>
29 #include "gtkalias.h"
30 #include "gtkframe.h"
31 #include "gtklabel.h"
32 #include "gtkintl.h"
33
34 #define LABEL_PAD 1
35 #define LABEL_SIDE_PAD 2
36
37 enum {
38   PROP_0,
39   PROP_LABEL,
40   PROP_LABEL_XALIGN,
41   PROP_LABEL_YALIGN,
42   PROP_SHADOW,
43   PROP_SHADOW_TYPE,
44   PROP_LABEL_WIDGET
45 };
46
47
48 static void gtk_frame_class_init    (GtkFrameClass  *klass);
49 static void gtk_frame_init          (GtkFrame       *frame);
50 static void gtk_frame_set_property (GObject      *object,
51                                     guint         param_id,
52                                     const GValue *value,
53                                     GParamSpec   *pspec);
54 static void gtk_frame_get_property (GObject     *object,
55                                     guint        param_id,
56                                     GValue      *value,
57                                     GParamSpec  *pspec);
58 static void gtk_frame_paint         (GtkWidget      *widget,
59                                      GdkRectangle   *area);
60 static gint gtk_frame_expose        (GtkWidget      *widget,
61                                      GdkEventExpose *event);
62 static void gtk_frame_size_request  (GtkWidget      *widget,
63                                      GtkRequisition *requisition);
64 static void gtk_frame_size_allocate (GtkWidget      *widget,
65                                      GtkAllocation  *allocation);
66 static void gtk_frame_remove        (GtkContainer   *container,
67                                      GtkWidget      *child);
68 static void gtk_frame_forall        (GtkContainer   *container,
69                                      gboolean        include_internals,
70                                      GtkCallback     callback,
71                                      gpointer        callback_data);
72
73 static void gtk_frame_compute_child_allocation      (GtkFrame      *frame,
74                                                      GtkAllocation *child_allocation);
75 static void gtk_frame_real_compute_child_allocation (GtkFrame      *frame,
76                                                      GtkAllocation *child_allocation);
77
78 static GtkBinClass *parent_class = NULL;
79
80
81 GType
82 gtk_frame_get_type (void)
83 {
84   static GType frame_type = 0;
85
86   if (!frame_type)
87     {
88       static const GTypeInfo frame_info =
89       {
90         sizeof (GtkFrameClass),
91         NULL,           /* base_init */
92         NULL,           /* base_finalize */
93         (GClassInitFunc) gtk_frame_class_init,
94         NULL,           /* class_finalize */
95         NULL,           /* class_data */
96         sizeof (GtkFrame),
97         0,              /* n_preallocs */
98         (GInstanceInitFunc) gtk_frame_init,
99       };
100
101       frame_type = g_type_register_static (GTK_TYPE_BIN, "GtkFrame",
102                                            &frame_info, 0);
103     }
104
105   return frame_type;
106 }
107
108 static void
109 gtk_frame_class_init (GtkFrameClass *class)
110 {
111   GObjectClass *gobject_class;
112   GtkWidgetClass *widget_class;
113   GtkContainerClass *container_class;
114
115   gobject_class = (GObjectClass*) class;
116   widget_class = GTK_WIDGET_CLASS (class);
117   container_class = GTK_CONTAINER_CLASS (class);
118
119   parent_class = g_type_class_peek_parent (class);
120
121   gobject_class->set_property = gtk_frame_set_property;
122   gobject_class->get_property = gtk_frame_get_property;
123
124   g_object_class_install_property (gobject_class,
125                                    PROP_LABEL,
126                                    g_param_spec_string ("label",
127                                                         P_("Label"),
128                                                         P_("Text of the frame's label"),
129                                                         NULL,
130                                                         G_PARAM_READABLE |
131                                                         G_PARAM_WRITABLE));
132   g_object_class_install_property (gobject_class,
133                                    PROP_LABEL_XALIGN,
134                                    g_param_spec_float ("label_xalign",
135                                                        P_("Label xalign"),
136                                                        P_("The horizontal alignment of the label"),
137                                                        0.0,
138                                                        1.0,
139                                                        0.5,
140                                                        G_PARAM_READABLE |
141                                                        G_PARAM_WRITABLE));
142   g_object_class_install_property (gobject_class,
143                                    PROP_LABEL_YALIGN,
144                                    g_param_spec_float ("label_yalign",
145                                                        P_("Label yalign"),
146                                                        P_("The vertical alignment of the label"),
147                                                        0.0,
148                                                        1.0,
149                                                        0.5,
150                                                        G_PARAM_READABLE |
151                                                        G_PARAM_WRITABLE));
152   g_object_class_install_property (gobject_class,
153                                    PROP_SHADOW,
154                                    g_param_spec_enum ("shadow", NULL,
155                                                       P_("Deprecated property, use shadow_type instead"),
156                                                       GTK_TYPE_SHADOW_TYPE,
157                                                       GTK_SHADOW_ETCHED_IN,
158                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
159   g_object_class_install_property (gobject_class,
160                                    PROP_SHADOW_TYPE,
161                                    g_param_spec_enum ("shadow_type",
162                                                       P_("Frame shadow"),
163                                                       P_("Appearance of the frame border"),
164                                                       GTK_TYPE_SHADOW_TYPE,
165                                                       GTK_SHADOW_ETCHED_IN,
166                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
167
168   g_object_class_install_property (gobject_class,
169                                    PROP_LABEL_WIDGET,
170                                    g_param_spec_object ("label_widget",
171                                                         P_("Label widget"),
172                                                         P_("A widget to display in place of the usual frame label"),
173                                                         GTK_TYPE_WIDGET,
174                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));
175   
176   widget_class->expose_event = gtk_frame_expose;
177   widget_class->size_request = gtk_frame_size_request;
178   widget_class->size_allocate = gtk_frame_size_allocate;
179
180   container_class->remove = gtk_frame_remove;
181   container_class->forall = gtk_frame_forall;
182
183   class->compute_child_allocation = gtk_frame_real_compute_child_allocation;
184 }
185
186 static void
187 gtk_frame_init (GtkFrame *frame)
188 {
189   frame->label_widget = NULL;
190   frame->shadow_type = GTK_SHADOW_ETCHED_IN;
191   frame->label_xalign = 0.0;
192   frame->label_yalign = 0.5;
193 }
194
195 static void 
196 gtk_frame_set_property (GObject         *object,
197                         guint            prop_id,
198                         const GValue    *value,
199                         GParamSpec      *pspec)
200 {
201   GtkFrame *frame;
202
203   frame = GTK_FRAME (object);
204
205   switch (prop_id)
206     {
207     case PROP_LABEL:
208       gtk_frame_set_label (frame, g_value_get_string (value));
209       break;
210     case PROP_LABEL_XALIGN:
211       gtk_frame_set_label_align (frame, g_value_get_float (value), 
212                                  frame->label_yalign);
213       break;
214     case PROP_LABEL_YALIGN:
215       gtk_frame_set_label_align (frame, frame->label_xalign, 
216                                  g_value_get_float (value));
217       break;
218     case PROP_SHADOW:
219     case PROP_SHADOW_TYPE:
220       gtk_frame_set_shadow_type (frame, g_value_get_enum (value));
221       break;
222     case PROP_LABEL_WIDGET:
223       gtk_frame_set_label_widget (frame, g_value_get_object (value));
224       break;
225     default:      
226       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
227       break;
228     }
229 }
230
231 static void 
232 gtk_frame_get_property (GObject         *object,
233                         guint            prop_id,
234                         GValue          *value,
235                         GParamSpec      *pspec)
236 {
237   GtkFrame *frame;
238
239   frame = GTK_FRAME (object);
240
241   switch (prop_id)
242     {
243     case PROP_LABEL:
244       g_value_set_string (value, gtk_frame_get_label (frame));
245       break;
246     case PROP_LABEL_XALIGN:
247       g_value_set_float (value, frame->label_xalign);
248       break;
249     case PROP_LABEL_YALIGN:
250       g_value_set_float (value, frame->label_yalign);
251       break;
252     case PROP_SHADOW:
253     case PROP_SHADOW_TYPE:
254       g_value_set_enum (value, frame->shadow_type);
255       break;
256     case PROP_LABEL_WIDGET:
257       g_value_set_object (value,
258                           frame->label_widget ?
259                           G_OBJECT (frame->label_widget) : NULL);
260       break;
261     default:
262       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
263       break;
264     }
265 }
266
267 /**
268  * gtk_frame_new:
269  * @label: the text to use as the label of the frame
270  * 
271  * Creates a new #GtkFrame, with optional label @label.
272  * If @label is %NULL, the label is omitted.
273  * 
274  * Return value: a new #GtkFrame widget
275  **/
276 GtkWidget*
277 gtk_frame_new (const gchar *label)
278 {
279   return g_object_new (GTK_TYPE_FRAME, "label", label, NULL);
280 }
281
282 static void
283 gtk_frame_remove (GtkContainer *container,
284                   GtkWidget    *child)
285 {
286   GtkFrame *frame = GTK_FRAME (container);
287
288   if (frame->label_widget == child)
289     gtk_frame_set_label_widget (frame, NULL);
290   else
291     GTK_CONTAINER_CLASS (parent_class)->remove (container, child);
292 }
293
294 static void
295 gtk_frame_forall (GtkContainer *container,
296                   gboolean      include_internals,
297                   GtkCallback   callback,
298                   gpointer      callback_data)
299 {
300   GtkBin *bin = GTK_BIN (container);
301   GtkFrame *frame = GTK_FRAME (container);
302
303   if (bin->child)
304     (* callback) (bin->child, callback_data);
305
306   if (frame->label_widget)
307     (* callback) (frame->label_widget, callback_data);
308 }
309
310 /**
311  * gtk_frame_set_label:
312  * @frame: a #GtkFrame
313  * @label: the text to use as the label of the frame
314  * 
315  * Sets the text of the label. If @label is %NULL,
316  * the current label is removed.
317  **/
318 void
319 gtk_frame_set_label (GtkFrame *frame,
320                      const gchar *label)
321 {
322   g_return_if_fail (GTK_IS_FRAME (frame));
323
324   if (!label)
325     {
326       gtk_frame_set_label_widget (frame, NULL);
327     }
328   else
329     {
330       GtkWidget *child = gtk_label_new (label);
331       gtk_widget_show (child);
332
333       gtk_frame_set_label_widget (frame, child);
334     }
335 }
336
337 /**
338  * gtk_frame_get_label:
339  * @frame: a #GtkFrame
340  * 
341  * If the frame's label widget is a #GtkLabel, returns the
342  * text in the label widget. (The frame will have a #GtkLabel
343  * for the label widget if a non-%NULL argument was passed
344  * to gtk_frame_new().)
345  * 
346  * Return value: the text in the label, or %NULL if there
347  *               was no label widget or the lable widget was not
348  *               a #GtkLabel. This string is owned by GTK+ and
349  *               must not be modified or freed.
350  **/
351 G_CONST_RETURN gchar *
352 gtk_frame_get_label (GtkFrame *frame)
353 {
354   g_return_val_if_fail (GTK_IS_FRAME (frame), NULL);
355
356   if (frame->label_widget && GTK_IS_LABEL (frame->label_widget))
357     return gtk_label_get_text (GTK_LABEL (frame->label_widget));
358   else
359     return NULL;
360 }
361
362 /**
363  * gtk_frame_set_label_widget:
364  * @frame: a #GtkFrame
365  * @label_widget: the new label widget
366  * 
367  * Sets the label widget for the frame. This is the widget that
368  * will appear embedded in the top edge of the frame as a
369  * title.
370  **/
371 void
372 gtk_frame_set_label_widget (GtkFrame  *frame,
373                             GtkWidget *label_widget)
374 {
375   gboolean need_resize = FALSE;
376   
377   g_return_if_fail (GTK_IS_FRAME (frame));
378   g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget));
379   g_return_if_fail (label_widget == NULL || label_widget->parent == NULL);
380   
381   if (frame->label_widget == label_widget)
382     return;
383   
384   if (frame->label_widget)
385     {
386       need_resize = GTK_WIDGET_VISIBLE (frame->label_widget);
387       gtk_widget_unparent (frame->label_widget);
388     }
389
390   frame->label_widget = label_widget;
391     
392   if (label_widget)
393     {
394       frame->label_widget = label_widget;
395       gtk_widget_set_parent (label_widget, GTK_WIDGET (frame));
396       need_resize |= GTK_WIDGET_VISIBLE (label_widget);
397     }
398   
399   if (GTK_WIDGET_VISIBLE (frame) && need_resize)
400     gtk_widget_queue_resize (GTK_WIDGET (frame));
401
402   g_object_freeze_notify (G_OBJECT (frame));
403   g_object_notify (G_OBJECT (frame), "label_widget");
404   g_object_notify (G_OBJECT (frame), "label");
405   g_object_thaw_notify (G_OBJECT (frame));
406 }
407
408 /**
409  * gtk_frame_get_label_widget:
410  * @frame: a #GtkFrame
411  *
412  * Retrieves the label widget for the frame. See
413  * gtk_frame_set_label_widget().
414  *
415  * Return value: the label widget, or %NULL if there is none.
416  **/
417 GtkWidget *
418 gtk_frame_get_label_widget (GtkFrame *frame)
419 {
420   g_return_val_if_fail (GTK_IS_FRAME (frame), NULL);
421
422   return frame->label_widget;
423 }
424
425 /**
426  * gtk_frame_set_label_align:
427  * @frame: a #GtkFrame
428  * @xalign: The position of the label along the top edge
429  *   of the widget. A value of 0.0 represents left alignment;
430  *   1.0 represents right alignment.
431  * @yalign: The y alignment of the label. A value of 0.0 aligns under 
432  *   the frame; 1.0 aligns above the frame.
433  * 
434  * Sets the alignment of the frame widget's label. The
435  * default values for a newly created frame are 0.0 and 0.5.
436  **/
437 void
438 gtk_frame_set_label_align (GtkFrame *frame,
439                            gfloat    xalign,
440                            gfloat    yalign)
441 {
442   g_return_if_fail (GTK_IS_FRAME (frame));
443
444   xalign = CLAMP (xalign, 0.0, 1.0);
445   yalign = CLAMP (yalign, 0.0, 1.0);
446
447   g_object_freeze_notify (G_OBJECT (frame));
448   if (xalign != frame->label_xalign)
449     {
450       frame->label_xalign = xalign;
451       g_object_notify (G_OBJECT (frame), "label_xalign");
452     }
453
454   if (yalign != frame->label_yalign)
455     {
456       frame->label_yalign = yalign;
457       g_object_notify (G_OBJECT (frame), "label_yalign");
458     }
459
460   g_object_thaw_notify (G_OBJECT (frame));
461   gtk_widget_queue_resize (GTK_WIDGET (frame));
462 }
463
464 /**
465  * gtk_frame_get_label_align:
466  * @frame: a #GtkFrame
467  * @xalign: location to store X alignment of frame's label, or %NULL
468  * @yalign: location to store X alignment of frame's label, or %NULL
469  * 
470  * Retrieves the X and Y alignment of the frame's label. See
471  * gtk_frame_set_label_align().
472  **/
473 void
474 gtk_frame_get_label_align (GtkFrame *frame,
475                            gfloat   *xalign,
476                            gfloat   *yalign)
477 {
478   g_return_if_fail (GTK_IS_FRAME (frame));
479
480   if (xalign)
481     *xalign = frame->label_xalign;
482   if (yalign)
483     *yalign = frame->label_yalign;
484 }
485
486 /**
487  * gtk_frame_set_shadow_type:
488  * @frame: a #GtkFrame
489  * @type: the new #GtkShadowType
490  * 
491  * Sets the shadow type for @frame.
492  **/
493 void
494 gtk_frame_set_shadow_type (GtkFrame      *frame,
495                            GtkShadowType  type)
496 {
497   g_return_if_fail (GTK_IS_FRAME (frame));
498
499   if ((GtkShadowType) frame->shadow_type != type)
500     {
501       frame->shadow_type = type;
502       g_object_notify (G_OBJECT (frame), "shadow_type");
503
504       if (GTK_WIDGET_DRAWABLE (frame))
505         {
506           gtk_widget_queue_draw (GTK_WIDGET (frame));
507         }
508       
509       gtk_widget_queue_resize (GTK_WIDGET (frame));
510     }
511 }
512
513 /**
514  * gtk_frame_get_shadow_type:
515  * @frame: a #GtkFrame
516  *
517  * Retrieves the shadow type of the frame. See
518  * gtk_frame_set_shadow_type().
519  *
520  * Return value: the current shadow type of the frame.
521  **/
522 GtkShadowType
523 gtk_frame_get_shadow_type (GtkFrame *frame)
524 {
525   g_return_val_if_fail (GTK_IS_FRAME (frame), GTK_SHADOW_ETCHED_IN);
526
527   return frame->shadow_type;
528 }
529
530 static void
531 gtk_frame_paint (GtkWidget    *widget,
532                  GdkRectangle *area)
533 {
534   GtkFrame *frame;
535   gint x, y, width, height;
536
537   if (GTK_WIDGET_DRAWABLE (widget))
538     {
539       frame = GTK_FRAME (widget);
540
541       x = frame->child_allocation.x - widget->style->xthickness;
542       y = frame->child_allocation.y - widget->style->ythickness;
543       width = frame->child_allocation.width + 2 * widget->style->xthickness;
544       height =  frame->child_allocation.height + 2 * widget->style->ythickness;
545
546       if (frame->label_widget)
547         {
548           GtkRequisition child_requisition;
549           gfloat xalign;
550           gint height_extra;
551           gint x2;
552
553           gtk_widget_get_child_requisition (frame->label_widget, &child_requisition);
554
555           if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
556             xalign = frame->label_xalign;
557           else
558             xalign = 1 - frame->label_xalign;
559
560           height_extra = MAX (0, child_requisition.height - widget->style->ythickness);
561           height_extra *= (1 - frame->label_yalign);
562           y -= height_extra;
563           height += height_extra;
564           
565           x2 = widget->style->xthickness + (frame->child_allocation.width - child_requisition.width - 2 * LABEL_PAD - 2 * LABEL_SIDE_PAD) * xalign + LABEL_SIDE_PAD;
566
567           
568           gtk_paint_shadow_gap (widget->style, widget->window,
569                                 GTK_STATE_NORMAL, frame->shadow_type,
570                                 area, widget, "frame",
571                                 x, y, width, height,
572                                 GTK_POS_TOP, 
573                                 x2, child_requisition.width + 2 * LABEL_PAD);
574         }
575        else
576          gtk_paint_shadow (widget->style, widget->window,
577                            GTK_STATE_NORMAL, frame->shadow_type,
578                            area, widget, "frame",
579                            x, y, width, height);
580     }
581 }
582
583 static gboolean
584 gtk_frame_expose (GtkWidget      *widget,
585                   GdkEventExpose *event)
586 {
587   if (GTK_WIDGET_DRAWABLE (widget))
588     {
589       gtk_frame_paint (widget, &event->area);
590
591       (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
592     }
593
594   return FALSE;
595 }
596
597 static void
598 gtk_frame_size_request (GtkWidget      *widget,
599                         GtkRequisition *requisition)
600 {
601   GtkFrame *frame = GTK_FRAME (widget);
602   GtkBin *bin = GTK_BIN (widget);
603   GtkRequisition child_requisition;
604   
605   if (frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget))
606     {
607       gtk_widget_size_request (frame->label_widget, &child_requisition);
608
609       requisition->width = child_requisition.width + 2 * LABEL_PAD + 2 * LABEL_SIDE_PAD;
610       requisition->height =
611         MAX (0, child_requisition.height - GTK_WIDGET (widget)->style->ythickness);
612     }
613   else
614     {
615       requisition->width = 0;
616       requisition->height = 0;
617     }
618   
619   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
620     {
621       gtk_widget_size_request (bin->child, &child_requisition);
622
623       requisition->width = MAX (requisition->width, child_requisition.width);
624       requisition->height += child_requisition.height;
625     }
626
627   requisition->width += (GTK_CONTAINER (widget)->border_width +
628                          GTK_WIDGET (widget)->style->xthickness) * 2;
629   requisition->height += (GTK_CONTAINER (widget)->border_width +
630                           GTK_WIDGET (widget)->style->ythickness) * 2;
631 }
632
633 static void
634 gtk_frame_size_allocate (GtkWidget     *widget,
635                          GtkAllocation *allocation)
636 {
637   GtkFrame *frame = GTK_FRAME (widget);
638   GtkBin *bin = GTK_BIN (widget);
639   GtkAllocation new_allocation;
640
641   widget->allocation = *allocation;
642
643   gtk_frame_compute_child_allocation (frame, &new_allocation);
644   
645   /* If the child allocation changed, that means that the frame is drawn
646    * in a new place, so we must redraw the entire widget.
647    */
648   if (GTK_WIDGET_MAPPED (widget) &&
649       (new_allocation.x != frame->child_allocation.x ||
650        new_allocation.y != frame->child_allocation.y ||
651        new_allocation.width != frame->child_allocation.width ||
652        new_allocation.height != frame->child_allocation.height))
653     gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
654   
655   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
656     gtk_widget_size_allocate (bin->child, &new_allocation);
657   
658   frame->child_allocation = new_allocation;
659   
660   if (frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget))
661     {
662       GtkRequisition child_requisition;
663       GtkAllocation child_allocation;
664       gfloat xalign;
665
666       gtk_widget_get_child_requisition (frame->label_widget, &child_requisition);
667
668       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
669         xalign = frame->label_xalign;
670       else
671         xalign = 1 - frame->label_xalign;
672       
673       child_allocation.x = frame->child_allocation.x + LABEL_SIDE_PAD +
674         (frame->child_allocation.width - child_requisition.width - 2 * LABEL_PAD - 2 * LABEL_SIDE_PAD) * xalign + LABEL_PAD;
675       child_allocation.width = child_requisition.width;
676
677       child_allocation.y = frame->child_allocation.y - child_requisition.height;
678       child_allocation.height = child_requisition.height;
679
680       gtk_widget_size_allocate (frame->label_widget, &child_allocation);
681     }
682 }
683
684 static void
685 gtk_frame_compute_child_allocation (GtkFrame      *frame,
686                                     GtkAllocation *child_allocation)
687 {
688   g_return_if_fail (GTK_IS_FRAME (frame));
689   g_return_if_fail (child_allocation != NULL);
690
691   GTK_FRAME_GET_CLASS (frame)->compute_child_allocation (frame, child_allocation);
692 }
693
694 static void
695 gtk_frame_real_compute_child_allocation (GtkFrame      *frame,
696                                          GtkAllocation *child_allocation)
697 {
698   GtkWidget *widget = GTK_WIDGET (frame);
699   GtkAllocation *allocation = &widget->allocation;
700   GtkRequisition child_requisition;
701   gint top_margin;
702
703   if (frame->label_widget)
704     {
705       gtk_widget_get_child_requisition (frame->label_widget, &child_requisition);
706       top_margin = MAX (child_requisition.height, widget->style->ythickness);
707     }
708   else
709     top_margin = widget->style->ythickness;
710   
711   child_allocation->x = (GTK_CONTAINER (frame)->border_width +
712                          widget->style->xthickness);
713   child_allocation->width = MAX(1, (gint)allocation->width - child_allocation->x * 2);
714   
715   child_allocation->y = (GTK_CONTAINER (frame)->border_width + top_margin);
716   child_allocation->height = MAX (1, ((gint)allocation->height - child_allocation->y -
717                                       (gint)GTK_CONTAINER (frame)->border_width -
718                                       (gint)widget->style->ythickness));
719   
720   child_allocation->x += allocation->x;
721   child_allocation->y += allocation->y;
722 }