]> Pileus Git - ~andy/gtk/blob - gtk/gtktable.c
Document expose event->region change and that gtk_widget_event doesn't
[~andy/gtk] / gtk / gtktable.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 "gtktable.h"
28
29 enum
30 {
31   ARG_0,
32   ARG_N_ROWS,
33   ARG_N_COLUMNS,
34   ARG_COLUMN_SPACING,
35   ARG_ROW_SPACING,
36   ARG_HOMOGENEOUS
37 };
38
39 enum
40 {
41   CHILD_ARG_0,
42   CHILD_ARG_LEFT_ATTACH,
43   CHILD_ARG_RIGHT_ATTACH,
44   CHILD_ARG_TOP_ATTACH,
45   CHILD_ARG_BOTTOM_ATTACH,
46   CHILD_ARG_X_OPTIONS,
47   CHILD_ARG_Y_OPTIONS,
48   CHILD_ARG_X_PADDING,
49   CHILD_ARG_Y_PADDING
50 };
51   
52
53 static void gtk_table_class_init    (GtkTableClass  *klass);
54 static void gtk_table_init          (GtkTable       *table);
55 static void gtk_table_finalize      (GObject        *object);
56 static void gtk_table_map           (GtkWidget      *widget);
57 static void gtk_table_unmap         (GtkWidget      *widget);
58 static void gtk_table_size_request  (GtkWidget      *widget,
59                                      GtkRequisition *requisition);
60 static void gtk_table_size_allocate (GtkWidget      *widget,
61                                      GtkAllocation  *allocation);
62 static void gtk_table_add           (GtkContainer   *container,
63                                      GtkWidget      *widget);
64 static void gtk_table_remove        (GtkContainer   *container,
65                                      GtkWidget      *widget);
66 static void gtk_table_forall        (GtkContainer   *container,
67                                      gboolean        include_internals,
68                                      GtkCallback     callback,
69                                      gpointer        callback_data);
70 static void gtk_table_get_arg       (GtkObject      *object,
71                                      GtkArg         *arg,
72                                      guint           arg_id);
73 static void gtk_table_set_arg       (GtkObject      *object,
74                                      GtkArg         *arg,
75                                      guint           arg_id);
76 static void gtk_table_set_child_arg (GtkContainer   *container,
77                                      GtkWidget      *child,
78                                      GtkArg         *arg,
79                                      guint           arg_id);
80 static void gtk_table_get_child_arg (GtkContainer   *container,
81                                      GtkWidget      *child,
82                                      GtkArg         *arg,
83                                      guint           arg_id);
84 static GtkType gtk_table_child_type (GtkContainer   *container);
85
86
87 static void gtk_table_size_request_init  (GtkTable *table);
88 static void gtk_table_size_request_pass1 (GtkTable *table);
89 static void gtk_table_size_request_pass2 (GtkTable *table);
90 static void gtk_table_size_request_pass3 (GtkTable *table);
91
92 static void gtk_table_size_allocate_init  (GtkTable *table);
93 static void gtk_table_size_allocate_pass1 (GtkTable *table);
94 static void gtk_table_size_allocate_pass2 (GtkTable *table);
95
96
97 static GtkContainerClass *parent_class = NULL;
98
99
100 GtkType
101 gtk_table_get_type (void)
102 {
103   static GtkType table_type = 0;
104   
105   if (!table_type)
106     {
107       static const GtkTypeInfo table_info =
108       {
109         "GtkTable",
110         sizeof (GtkTable),
111         sizeof (GtkTableClass),
112         (GtkClassInitFunc) gtk_table_class_init,
113         (GtkObjectInitFunc) gtk_table_init,
114         /* reserved_1 */ NULL,
115         /* reserved_2 */ NULL,
116         (GtkClassInitFunc) NULL,
117       };
118       
119       table_type = gtk_type_unique (gtk_container_get_type (), &table_info);
120     }
121   
122   return table_type;
123 }
124
125 static void
126 gtk_table_class_init (GtkTableClass *class)
127 {
128   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
129   GtkObjectClass *object_class;
130   GtkWidgetClass *widget_class;
131   GtkContainerClass *container_class;
132   
133   object_class = (GtkObjectClass*) class;
134   widget_class = (GtkWidgetClass*) class;
135   container_class = (GtkContainerClass*) class;
136   
137   parent_class = gtk_type_class (gtk_container_get_type ());
138
139   gobject_class->finalize = gtk_table_finalize;
140
141   object_class->get_arg = gtk_table_get_arg;
142   object_class->set_arg = gtk_table_set_arg;
143   
144   widget_class->map = gtk_table_map;
145   widget_class->unmap = gtk_table_unmap;
146   widget_class->size_request = gtk_table_size_request;
147   widget_class->size_allocate = gtk_table_size_allocate;
148   
149   container_class->add = gtk_table_add;
150   container_class->remove = gtk_table_remove;
151   container_class->forall = gtk_table_forall;
152   container_class->child_type = gtk_table_child_type;
153   container_class->set_child_arg = gtk_table_set_child_arg;
154   container_class->get_child_arg = gtk_table_get_child_arg;
155   
156   gtk_object_add_arg_type ("GtkTable::n_rows", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_N_ROWS);
157   gtk_object_add_arg_type ("GtkTable::n_columns", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_N_COLUMNS);
158   gtk_object_add_arg_type ("GtkTable::row_spacing", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_ROW_SPACING);
159   gtk_object_add_arg_type ("GtkTable::column_spacing", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_COLUMN_SPACING);
160   gtk_object_add_arg_type ("GtkTable::homogeneous", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HOMOGENEOUS);
161   gtk_container_add_child_arg_type ("GtkTable::left_attach", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_LEFT_ATTACH);
162   gtk_container_add_child_arg_type ("GtkTable::right_attach", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_RIGHT_ATTACH);
163   gtk_container_add_child_arg_type ("GtkTable::top_attach", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_TOP_ATTACH);
164   gtk_container_add_child_arg_type ("GtkTable::bottom_attach", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_BOTTOM_ATTACH);
165   gtk_container_add_child_arg_type ("GtkTable::x_options", GTK_TYPE_ATTACH_OPTIONS, GTK_ARG_READWRITE, CHILD_ARG_X_OPTIONS);
166   gtk_container_add_child_arg_type ("GtkTable::y_options", GTK_TYPE_ATTACH_OPTIONS, GTK_ARG_READWRITE, CHILD_ARG_Y_OPTIONS);
167   gtk_container_add_child_arg_type ("GtkTable::x_padding", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_X_PADDING);
168   gtk_container_add_child_arg_type ("GtkTable::y_padding", GTK_TYPE_UINT, GTK_ARG_READWRITE, CHILD_ARG_Y_PADDING);
169 }
170
171 static GtkType
172 gtk_table_child_type (GtkContainer   *container)
173 {
174   return GTK_TYPE_WIDGET;
175 }
176
177 static void
178 gtk_table_get_arg (GtkObject      *object,
179                    GtkArg         *arg,
180                    guint           arg_id)
181 {
182   GtkTable *table;
183
184   table = GTK_TABLE (object);
185
186   switch (arg_id)
187     {
188     case ARG_N_ROWS:
189       GTK_VALUE_UINT (*arg) = table->nrows;
190       break;
191     case ARG_N_COLUMNS:
192       GTK_VALUE_UINT (*arg) = table->ncols;
193       break;
194     case ARG_ROW_SPACING:
195       GTK_VALUE_UINT (*arg) = table->row_spacing;
196       break;
197     case ARG_COLUMN_SPACING:
198       GTK_VALUE_UINT (*arg) = table->column_spacing;
199       break;
200     case ARG_HOMOGENEOUS:
201       GTK_VALUE_BOOL (*arg) = table->homogeneous;
202       break;
203     default:
204       arg->type = GTK_TYPE_INVALID;
205       break;
206     }
207 }
208
209 static void
210 gtk_table_set_arg (GtkObject      *object,
211                    GtkArg         *arg,
212                    guint           arg_id)
213 {
214   GtkTable *table;
215
216   table = GTK_TABLE (object);
217
218   switch (arg_id)
219     {
220     case ARG_N_ROWS:
221       gtk_table_resize (table, GTK_VALUE_UINT (*arg), table->ncols);
222       break;
223     case ARG_N_COLUMNS:
224       gtk_table_resize (table, table->nrows, GTK_VALUE_UINT (*arg));
225       break;
226     case ARG_ROW_SPACING:
227       gtk_table_set_row_spacings (table, GTK_VALUE_UINT (*arg));
228       break;
229     case ARG_COLUMN_SPACING:
230       gtk_table_set_col_spacings (table, GTK_VALUE_UINT (*arg));
231       break;
232     case ARG_HOMOGENEOUS:
233       gtk_table_set_homogeneous (table, GTK_VALUE_BOOL (*arg));
234       break;
235     default:
236       break;
237     }
238 }
239
240 static void
241 gtk_table_set_child_arg (GtkContainer   *container,
242                          GtkWidget      *child,
243                          GtkArg         *arg,
244                          guint           arg_id)
245 {
246   GtkTable *table;
247   GtkTableChild *table_child;
248   GList *list;
249
250   table = GTK_TABLE (container);
251   table_child = NULL;
252   for (list = table->children; list; list = list->next)
253     {
254       table_child = list->data;
255
256       if (table_child->widget == child)
257         break;
258     }
259   if (!list)
260     return;
261
262   switch (arg_id)
263     {
264     case CHILD_ARG_LEFT_ATTACH:
265       table_child->left_attach = GTK_VALUE_UINT (*arg);
266       if (table_child->right_attach <= table_child->left_attach)
267         table_child->right_attach = table_child->left_attach + 1;
268       if (table_child->right_attach >= table->ncols)
269         gtk_table_resize (table, table->ncols, table_child->right_attach);
270       break;
271     case CHILD_ARG_RIGHT_ATTACH:
272       if (GTK_VALUE_UINT (*arg) > 0)
273         {
274           table_child->right_attach = GTK_VALUE_UINT (*arg);
275           if (table_child->right_attach <= table_child->left_attach)
276             table_child->left_attach = table_child->right_attach - 1;
277           if (table_child->right_attach >= table->ncols)
278             gtk_table_resize (table, table->ncols, table_child->right_attach);
279         }
280       break;
281     case CHILD_ARG_TOP_ATTACH:
282       table_child->top_attach = GTK_VALUE_UINT (*arg);
283       if (table_child->bottom_attach <= table_child->top_attach)
284         table_child->bottom_attach = table_child->top_attach + 1;
285       if (table_child->bottom_attach >= table->nrows)
286         gtk_table_resize (table, table_child->bottom_attach, table->ncols);
287       break;
288     case CHILD_ARG_BOTTOM_ATTACH:
289       if (GTK_VALUE_UINT (*arg) > 0)
290         {
291           table_child->bottom_attach = GTK_VALUE_UINT (*arg);
292           if (table_child->bottom_attach <= table_child->top_attach)
293             table_child->top_attach = table_child->bottom_attach - 1;
294           if (table_child->bottom_attach >= table->nrows)
295             gtk_table_resize (table, table_child->bottom_attach, table->ncols);
296         }
297       break;
298     case CHILD_ARG_X_OPTIONS:
299       table_child->xexpand = (GTK_VALUE_FLAGS (*arg) & GTK_EXPAND) != 0;
300       table_child->xshrink = (GTK_VALUE_FLAGS (*arg) & GTK_SHRINK) != 0;
301       table_child->xfill = (GTK_VALUE_FLAGS (*arg) & GTK_FILL) != 0;
302       break;
303     case CHILD_ARG_Y_OPTIONS:
304       table_child->yexpand = (GTK_VALUE_FLAGS (*arg) & GTK_EXPAND) != 0;
305       table_child->yshrink = (GTK_VALUE_FLAGS (*arg) & GTK_SHRINK) != 0;
306       table_child->yfill = (GTK_VALUE_FLAGS (*arg) & GTK_FILL) != 0;
307       break;
308     case CHILD_ARG_X_PADDING:
309       table_child->xpadding = GTK_VALUE_UINT (*arg);
310       break;
311     case CHILD_ARG_Y_PADDING:
312       table_child->ypadding = GTK_VALUE_UINT (*arg);
313       break;
314     default:
315       break;
316     }
317   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (table))
318     gtk_widget_queue_resize (child);
319 }
320
321 static void
322 gtk_table_get_child_arg (GtkContainer   *container,
323                          GtkWidget      *child,
324                          GtkArg         *arg,
325                          guint           arg_id)
326 {
327   GtkTable *table;
328   GtkTableChild *table_child;
329   GList *list;
330
331   table = GTK_TABLE (container);
332   table_child = NULL;
333   for (list = table->children; list; list = list->next)
334     {
335       table_child = list->data;
336
337       if (table_child->widget == child)
338         break;
339     }
340   if (!list)
341     return;
342
343   switch (arg_id)
344     {
345     case CHILD_ARG_LEFT_ATTACH:
346       GTK_VALUE_UINT (*arg) = table_child->left_attach;
347       break;
348     case CHILD_ARG_RIGHT_ATTACH:
349       GTK_VALUE_UINT (*arg) = table_child->right_attach;
350       break;
351     case CHILD_ARG_TOP_ATTACH:
352       GTK_VALUE_UINT (*arg) = table_child->top_attach;
353       break;
354     case CHILD_ARG_BOTTOM_ATTACH:
355       GTK_VALUE_UINT (*arg) = table_child->bottom_attach;
356       break;
357     case CHILD_ARG_X_OPTIONS:
358       GTK_VALUE_FLAGS (*arg) = (table_child->xexpand * GTK_EXPAND |
359                                 table_child->xshrink * GTK_SHRINK |
360                                 table_child->xfill * GTK_FILL);
361       break;
362     case CHILD_ARG_Y_OPTIONS:
363       GTK_VALUE_FLAGS (*arg) = (table_child->yexpand * GTK_EXPAND |
364                                 table_child->yshrink * GTK_SHRINK |
365                                 table_child->yfill * GTK_FILL);
366       break;
367     case CHILD_ARG_X_PADDING:
368       GTK_VALUE_UINT (*arg) = table_child->xpadding;
369       break;
370     case CHILD_ARG_Y_PADDING:
371       GTK_VALUE_UINT (*arg) = table_child->ypadding;
372       break;
373     default:
374       arg->type = GTK_TYPE_INVALID;
375       break;
376     }
377 }
378
379 static void
380 gtk_table_init (GtkTable *table)
381 {
382   GTK_WIDGET_SET_FLAGS (table, GTK_NO_WINDOW);
383   
384   table->children = NULL;
385   table->rows = NULL;
386   table->cols = NULL;
387   table->nrows = 0;
388   table->ncols = 0;
389   table->column_spacing = 0;
390   table->row_spacing = 0;
391   table->homogeneous = FALSE;
392
393   gtk_table_resize (table, 1, 1);
394 }
395
396 GtkWidget*
397 gtk_table_new (guint    rows,
398                guint    columns,
399                gboolean homogeneous)
400 {
401   GtkTable *table;
402
403   if (rows == 0)
404           rows = 1;
405   if (columns == 0)
406           columns = 1;
407   
408   table = gtk_type_new (gtk_table_get_type ());
409   
410   table->homogeneous = (homogeneous ? TRUE : FALSE);
411
412   gtk_table_resize (table, rows, columns);
413   
414   return GTK_WIDGET (table);
415 }
416
417 void
418 gtk_table_resize (GtkTable *table,
419                   guint     n_rows,
420                   guint     n_cols)
421 {
422   g_return_if_fail (table != NULL);
423   g_return_if_fail (GTK_IS_TABLE (table));
424
425   n_rows = MAX (n_rows, 1);
426   n_cols = MAX (n_cols, 1);
427   
428   if (n_rows != table->nrows ||
429       n_cols != table->ncols)
430     {
431       GList *list;
432       
433       for (list = table->children; list; list = list->next)
434         {
435           GtkTableChild *child;
436           
437           child = list->data;
438           
439           n_rows = MAX (n_rows, child->bottom_attach);
440           n_cols = MAX (n_cols, child->right_attach);
441         }
442       
443       if (n_rows != table->nrows)
444         {
445           guint i;
446
447           i = table->nrows;
448           table->nrows = n_rows;
449           table->rows = g_realloc (table->rows, table->nrows * sizeof (GtkTableRowCol));
450           
451           for (; i < table->nrows; i++)
452             {
453               table->rows[i].requisition = 0;
454               table->rows[i].allocation = 0;
455               table->rows[i].spacing = table->row_spacing;
456               table->rows[i].need_expand = 0;
457               table->rows[i].need_shrink = 0;
458               table->rows[i].expand = 0;
459               table->rows[i].shrink = 0;
460             }
461         }
462
463       if (n_cols != table->ncols)
464         {
465           guint i;
466
467           i = table->ncols;
468           table->ncols = n_cols;
469           table->cols = g_realloc (table->cols, table->ncols * sizeof (GtkTableRowCol));
470           
471           for (; i < table->ncols; i++)
472             {
473               table->cols[i].requisition = 0;
474               table->cols[i].allocation = 0;
475               table->cols[i].spacing = table->column_spacing;
476               table->cols[i].need_expand = 0;
477               table->cols[i].need_shrink = 0;
478               table->cols[i].expand = 0;
479               table->cols[i].shrink = 0;
480             }
481         }
482     }
483 }
484
485 void
486 gtk_table_attach (GtkTable        *table,
487                   GtkWidget       *child,
488                   guint            left_attach,
489                   guint            right_attach,
490                   guint            top_attach,
491                   guint            bottom_attach,
492                   GtkAttachOptions xoptions,
493                   GtkAttachOptions yoptions,
494                   guint            xpadding,
495                   guint            ypadding)
496 {
497   GtkTableChild *table_child;
498   
499   g_return_if_fail (table != NULL);
500   g_return_if_fail (GTK_IS_TABLE (table));
501   g_return_if_fail (child != NULL);
502   g_return_if_fail (GTK_IS_WIDGET (child));
503   g_return_if_fail (child->parent == NULL);
504   
505   /* g_return_if_fail (left_attach >= 0); */
506   g_return_if_fail (left_attach < right_attach);
507   /* g_return_if_fail (top_attach >= 0); */
508   g_return_if_fail (top_attach < bottom_attach);
509   
510   if (right_attach >= table->ncols)
511     gtk_table_resize (table, table->nrows, right_attach);
512   
513   if (bottom_attach >= table->nrows)
514     gtk_table_resize (table, bottom_attach, table->ncols);
515   
516   table_child = g_new (GtkTableChild, 1);
517   table_child->widget = child;
518   table_child->left_attach = left_attach;
519   table_child->right_attach = right_attach;
520   table_child->top_attach = top_attach;
521   table_child->bottom_attach = bottom_attach;
522   table_child->xexpand = (xoptions & GTK_EXPAND) != 0;
523   table_child->xshrink = (xoptions & GTK_SHRINK) != 0;
524   table_child->xfill = (xoptions & GTK_FILL) != 0;
525   table_child->xpadding = xpadding;
526   table_child->yexpand = (yoptions & GTK_EXPAND) != 0;
527   table_child->yshrink = (yoptions & GTK_SHRINK) != 0;
528   table_child->yfill = (yoptions & GTK_FILL) != 0;
529   table_child->ypadding = ypadding;
530   
531   table->children = g_list_prepend (table->children, table_child);
532   
533   gtk_widget_set_parent (child, GTK_WIDGET (table));
534   
535   if (GTK_WIDGET_REALIZED (child->parent))
536     gtk_widget_realize (child);
537
538   if (GTK_WIDGET_VISIBLE (child->parent) && GTK_WIDGET_VISIBLE (child))
539     {
540       if (GTK_WIDGET_MAPPED (child->parent))
541         gtk_widget_map (child);
542
543       gtk_widget_queue_resize (child);
544     }
545 }
546
547 void
548 gtk_table_attach_defaults (GtkTable  *table,
549                            GtkWidget *widget,
550                            guint      left_attach,
551                            guint      right_attach,
552                            guint      top_attach,
553                            guint      bottom_attach)
554 {
555   gtk_table_attach (table, widget,
556                     left_attach, right_attach,
557                     top_attach, bottom_attach,
558                     GTK_EXPAND | GTK_FILL,
559                     GTK_EXPAND | GTK_FILL,
560                     0, 0);
561 }
562
563 void
564 gtk_table_set_row_spacing (GtkTable *table,
565                            guint     row,
566                            guint     spacing)
567 {
568   g_return_if_fail (table != NULL);
569   g_return_if_fail (GTK_IS_TABLE (table));
570   g_return_if_fail (row < table->nrows);
571   
572   if (table->rows[row].spacing != spacing)
573     {
574       table->rows[row].spacing = spacing;
575       
576       if (GTK_WIDGET_VISIBLE (table))
577         gtk_widget_queue_resize (GTK_WIDGET (table));
578     }
579 }
580
581 void
582 gtk_table_set_col_spacing (GtkTable *table,
583                            guint     column,
584                            guint     spacing)
585 {
586   g_return_if_fail (table != NULL);
587   g_return_if_fail (GTK_IS_TABLE (table));
588   g_return_if_fail (column < table->ncols);
589   
590   if (table->cols[column].spacing != spacing)
591     {
592       table->cols[column].spacing = spacing;
593       
594       if (GTK_WIDGET_VISIBLE (table))
595         gtk_widget_queue_resize (GTK_WIDGET (table));
596     }
597 }
598
599 void
600 gtk_table_set_row_spacings (GtkTable *table,
601                             guint     spacing)
602 {
603   guint row;
604   
605   g_return_if_fail (table != NULL);
606   g_return_if_fail (GTK_IS_TABLE (table));
607   
608   table->row_spacing = spacing;
609   for (row = 0; row < table->nrows; row++)
610     table->rows[row].spacing = spacing;
611   
612   if (GTK_WIDGET_VISIBLE (table))
613     gtk_widget_queue_resize (GTK_WIDGET (table));
614 }
615
616 void
617 gtk_table_set_col_spacings (GtkTable *table,
618                             guint     spacing)
619 {
620   guint col;
621   
622   g_return_if_fail (table != NULL);
623   g_return_if_fail (GTK_IS_TABLE (table));
624   
625   table->column_spacing = spacing;
626   for (col = 0; col < table->ncols; col++)
627     table->cols[col].spacing = spacing;
628   
629   if (GTK_WIDGET_VISIBLE (table))
630     gtk_widget_queue_resize (GTK_WIDGET (table));
631 }
632
633 void
634 gtk_table_set_homogeneous (GtkTable *table,
635                            gboolean  homogeneous)
636 {
637   g_return_if_fail (table != NULL);
638   g_return_if_fail (GTK_IS_TABLE (table));
639
640   homogeneous = (homogeneous != 0);
641   if (homogeneous != table->homogeneous)
642     {
643       table->homogeneous = homogeneous;
644       
645       if (GTK_WIDGET_VISIBLE (table))
646         gtk_widget_queue_resize (GTK_WIDGET (table));
647     }
648 }
649
650 static void
651 gtk_table_finalize (GObject *object)
652 {
653   GtkTable *table;
654   
655   g_return_if_fail (GTK_IS_TABLE (object));
656   
657   table = GTK_TABLE (object);
658   
659   g_free (table->rows);
660   g_free (table->cols);
661   
662   G_OBJECT_CLASS (parent_class)->finalize (object);
663 }
664
665 static void
666 gtk_table_map (GtkWidget *widget)
667 {
668   GtkTable *table;
669   GtkTableChild *child;
670   GList *children;
671   
672   g_return_if_fail (widget != NULL);
673   g_return_if_fail (GTK_IS_TABLE (widget));
674   
675   table = GTK_TABLE (widget);
676   GTK_WIDGET_SET_FLAGS (table, GTK_MAPPED);
677   
678   children = table->children;
679   while (children)
680     {
681       child = children->data;
682       children = children->next;
683       
684       if (GTK_WIDGET_VISIBLE (child->widget) &&
685           !GTK_WIDGET_MAPPED (child->widget))
686         gtk_widget_map (child->widget);
687     }
688 }
689
690 static void
691 gtk_table_unmap (GtkWidget *widget)
692 {
693   GtkTable *table;
694   GtkTableChild *child;
695   GList *children;
696   
697   g_return_if_fail (widget != NULL);
698   g_return_if_fail (GTK_IS_TABLE (widget));
699   
700   table = GTK_TABLE (widget);
701   GTK_WIDGET_UNSET_FLAGS (table, GTK_MAPPED);
702   
703   children = table->children;
704   while (children)
705     {
706       child = children->data;
707       children = children->next;
708       
709       if (GTK_WIDGET_VISIBLE (child->widget) &&
710           GTK_WIDGET_MAPPED (child->widget))
711         gtk_widget_unmap (child->widget);
712     }
713 }
714
715 static void
716 gtk_table_size_request (GtkWidget      *widget,
717                         GtkRequisition *requisition)
718 {
719   GtkTable *table;
720   gint row, col;
721   
722   g_return_if_fail (widget != NULL);
723   g_return_if_fail (GTK_IS_TABLE (widget));
724   g_return_if_fail (requisition != NULL);
725   
726   table = GTK_TABLE (widget);
727   
728   requisition->width = 0;
729   requisition->height = 0;
730   
731   gtk_table_size_request_init (table);
732   gtk_table_size_request_pass1 (table);
733   gtk_table_size_request_pass2 (table);
734   gtk_table_size_request_pass3 (table);
735   gtk_table_size_request_pass2 (table);
736   
737   for (col = 0; col < table->ncols; col++)
738     requisition->width += table->cols[col].requisition;
739   for (col = 0; col + 1 < table->ncols; col++)
740     requisition->width += table->cols[col].spacing;
741   
742   for (row = 0; row < table->nrows; row++)
743     requisition->height += table->rows[row].requisition;
744   for (row = 0; row + 1 < table->nrows; row++)
745     requisition->height += table->rows[row].spacing;
746   
747   requisition->width += GTK_CONTAINER (table)->border_width * 2;
748   requisition->height += GTK_CONTAINER (table)->border_width * 2;
749 }
750
751 static void
752 gtk_table_size_allocate (GtkWidget     *widget,
753                          GtkAllocation *allocation)
754 {
755   GtkTable *table;
756   
757   g_return_if_fail (widget != NULL);
758   g_return_if_fail (GTK_IS_TABLE (widget));
759   g_return_if_fail (allocation != NULL);
760   
761   widget->allocation = *allocation;
762   table = GTK_TABLE (widget);
763   
764   gtk_table_size_allocate_init (table);
765   gtk_table_size_allocate_pass1 (table);
766   gtk_table_size_allocate_pass2 (table);
767 }
768
769 static void
770 gtk_table_add (GtkContainer *container,
771                GtkWidget    *widget)
772 {
773   g_return_if_fail (container != NULL);
774   g_return_if_fail (GTK_IS_TABLE (container));
775   g_return_if_fail (widget != NULL);
776   
777   gtk_table_attach_defaults (GTK_TABLE (container), widget, 0, 1, 0, 1);
778 }
779
780 static void
781 gtk_table_remove (GtkContainer *container,
782                   GtkWidget    *widget)
783 {
784   GtkTable *table;
785   GtkTableChild *child;
786   GList *children;
787   
788   g_return_if_fail (container != NULL);
789   g_return_if_fail (GTK_IS_TABLE (container));
790   g_return_if_fail (widget != NULL);
791   
792   table = GTK_TABLE (container);
793   children = table->children;
794   
795   while (children)
796     {
797       child = children->data;
798       children = children->next;
799       
800       if (child->widget == widget)
801         {
802           gboolean was_visible = GTK_WIDGET_VISIBLE (widget);
803           
804           gtk_widget_unparent (widget);
805           
806           table->children = g_list_remove (table->children, child);
807           g_free (child);
808           
809           if (was_visible && GTK_WIDGET_VISIBLE (container))
810             gtk_container_queue_resize (container);
811           break;
812         }
813     }
814 }
815
816 static void
817 gtk_table_forall (GtkContainer *container,
818                   gboolean      include_internals,
819                   GtkCallback   callback,
820                   gpointer      callback_data)
821 {
822   GtkTable *table;
823   GtkTableChild *child;
824   GList *children;
825   
826   g_return_if_fail (container != NULL);
827   g_return_if_fail (GTK_IS_TABLE (container));
828   g_return_if_fail (callback != NULL);
829   
830   table = GTK_TABLE (container);
831   children = table->children;
832   
833   while (children)
834     {
835       child = children->data;
836       children = children->next;
837       
838       (* callback) (child->widget, callback_data);
839     }
840 }
841
842 static void
843 gtk_table_size_request_init (GtkTable *table)
844 {
845   GtkTableChild *child;
846   GList *children;
847   gint row, col;
848   
849   for (row = 0; row < table->nrows; row++)
850     table->rows[row].requisition = 0;
851   for (col = 0; col < table->ncols; col++)
852     table->cols[col].requisition = 0;
853   
854   children = table->children;
855   while (children)
856     {
857       child = children->data;
858       children = children->next;
859       
860       if (GTK_WIDGET_VISIBLE (child->widget))
861         gtk_widget_size_request (child->widget, NULL);
862     }
863 }
864
865 static void
866 gtk_table_size_request_pass1 (GtkTable *table)
867 {
868   GtkTableChild *child;
869   GList *children;
870   gint width;
871   gint height;
872   
873   children = table->children;
874   while (children)
875     {
876       child = children->data;
877       children = children->next;
878       
879       if (GTK_WIDGET_VISIBLE (child->widget))
880         {
881           GtkRequisition child_requisition;
882           gtk_widget_get_child_requisition (child->widget, &child_requisition);
883
884           /* Child spans a single column.
885            */
886           if (child->left_attach == (child->right_attach - 1))
887             {
888               width = child_requisition.width + child->xpadding * 2;
889               table->cols[child->left_attach].requisition = MAX (table->cols[child->left_attach].requisition, width);
890             }
891           
892           /* Child spans a single row.
893            */
894           if (child->top_attach == (child->bottom_attach - 1))
895             {
896               height = child_requisition.height + child->ypadding * 2;
897               table->rows[child->top_attach].requisition = MAX (table->rows[child->top_attach].requisition, height);
898             }
899         }
900     }
901 }
902
903 static void
904 gtk_table_size_request_pass2 (GtkTable *table)
905 {
906   gint max_width;
907   gint max_height;
908   gint row, col;
909   
910   if (table->homogeneous)
911     {
912       max_width = 0;
913       max_height = 0;
914       
915       for (col = 0; col < table->ncols; col++)
916         max_width = MAX (max_width, table->cols[col].requisition);
917       for (row = 0; row < table->nrows; row++)
918         max_height = MAX (max_height, table->rows[row].requisition);
919       
920       for (col = 0; col < table->ncols; col++)
921         table->cols[col].requisition = max_width;
922       for (row = 0; row < table->nrows; row++)
923         table->rows[row].requisition = max_height;
924     }
925 }
926
927 static void
928 gtk_table_size_request_pass3 (GtkTable *table)
929 {
930   GtkTableChild *child;
931   GList *children;
932   gint width, height;
933   gint row, col;
934   gint extra;
935   
936   children = table->children;
937   while (children)
938     {
939       child = children->data;
940       children = children->next;
941       
942       if (GTK_WIDGET_VISIBLE (child->widget))
943         {
944           /* Child spans multiple columns.
945            */
946           if (child->left_attach != (child->right_attach - 1))
947             {
948               GtkRequisition child_requisition;
949
950               gtk_widget_get_child_requisition (child->widget, &child_requisition);
951               
952               /* Check and see if there is already enough space
953                *  for the child.
954                */
955               width = 0;
956               for (col = child->left_attach; col < child->right_attach; col++)
957                 {
958                   width += table->cols[col].requisition;
959                   if ((col + 1) < child->right_attach)
960                     width += table->cols[col].spacing;
961                 }
962               
963               /* If we need to request more space for this child to fill
964                *  its requisition, then divide up the needed space evenly
965                *  amongst the columns it spans.
966                */
967               if (width < child_requisition.width + child->xpadding * 2)
968                 {
969                   width = child_requisition.width + child->xpadding * 2 - width;
970                   
971                   for (col = child->left_attach; col < child->right_attach; col++)
972                     {
973                       extra = width / (child->right_attach - col);
974                       table->cols[col].requisition += extra;
975                       width -= extra;
976                     }
977                 }
978             }
979           
980           /* Child spans multiple rows.
981            */
982           if (child->top_attach != (child->bottom_attach - 1))
983             {
984               GtkRequisition child_requisition;
985
986               gtk_widget_get_child_requisition (child->widget, &child_requisition);
987
988               /* Check and see if there is already enough space
989                *  for the child.
990                */
991               height = 0;
992               for (row = child->top_attach; row < child->bottom_attach; row++)
993                 {
994                   height += table->rows[row].requisition;
995                   if ((row + 1) < child->bottom_attach)
996                     height += table->rows[row].spacing;
997                 }
998               
999               /* If we need to request more space for this child to fill
1000                *  its requisition, then divide up the needed space evenly
1001                *  amongst the columns it spans.
1002                */
1003               if (height < child_requisition.height + child->ypadding * 2)
1004                 {
1005                   height = child_requisition.height + child->ypadding * 2 - height;
1006                   
1007                   for (row = child->top_attach; row < child->bottom_attach; row++)
1008                     {
1009                       extra = height / (child->bottom_attach - row);
1010                       table->rows[row].requisition += extra;
1011                       height -= extra;
1012                     }
1013                 }
1014             }
1015         }
1016     }
1017 }
1018
1019 static void
1020 gtk_table_size_allocate_init (GtkTable *table)
1021 {
1022   GtkTableChild *child;
1023   GList *children;
1024   gint row, col;
1025   gint has_expand;
1026   gint has_shrink;
1027   
1028   /* Initialize the rows and cols.
1029    *  By default, rows and cols do not expand and do shrink.
1030    *  Those values are modified by the children that occupy
1031    *  the rows and cols.
1032    */
1033   for (col = 0; col < table->ncols; col++)
1034     {
1035       table->cols[col].allocation = table->cols[col].requisition;
1036       table->cols[col].need_expand = FALSE;
1037       table->cols[col].need_shrink = TRUE;
1038       table->cols[col].expand = FALSE;
1039       table->cols[col].shrink = TRUE;
1040       table->cols[col].empty = TRUE;
1041     }
1042   for (row = 0; row < table->nrows; row++)
1043     {
1044       table->rows[row].allocation = table->rows[row].requisition;
1045       table->rows[row].need_expand = FALSE;
1046       table->rows[row].need_shrink = TRUE;
1047       table->rows[row].expand = FALSE;
1048       table->rows[row].shrink = TRUE;
1049       table->rows[row].empty = TRUE;
1050     }
1051   
1052   /* Loop over all the children and adjust the row and col values
1053    *  based on whether the children want to be allowed to expand
1054    *  or shrink. This loop handles children that occupy a single
1055    *  row or column.
1056    */
1057   children = table->children;
1058   while (children)
1059     {
1060       child = children->data;
1061       children = children->next;
1062       
1063       if (GTK_WIDGET_VISIBLE (child->widget))
1064         {
1065           if (child->left_attach == (child->right_attach - 1))
1066             {
1067               if (child->xexpand)
1068                 table->cols[child->left_attach].expand = TRUE;
1069               
1070               if (!child->xshrink)
1071                 table->cols[child->left_attach].shrink = FALSE;
1072               
1073               table->cols[child->left_attach].empty = FALSE;
1074             }
1075           
1076           if (child->top_attach == (child->bottom_attach - 1))
1077             {
1078               if (child->yexpand)
1079                 table->rows[child->top_attach].expand = TRUE;
1080               
1081               if (!child->yshrink)
1082                 table->rows[child->top_attach].shrink = FALSE;
1083
1084               table->rows[child->top_attach].empty = FALSE;
1085             }
1086         }
1087     }
1088   
1089   /* Loop over all the children again and this time handle children
1090    *  which span multiple rows or columns.
1091    */
1092   children = table->children;
1093   while (children)
1094     {
1095       child = children->data;
1096       children = children->next;
1097       
1098       if (GTK_WIDGET_VISIBLE (child->widget))
1099         {
1100           if (child->left_attach != (child->right_attach - 1))
1101             {
1102               for (col = child->left_attach; col < child->right_attach; col++)
1103                 table->cols[col].empty = FALSE;
1104
1105               if (child->xexpand)
1106                 {
1107                   has_expand = FALSE;
1108                   for (col = child->left_attach; col < child->right_attach; col++)
1109                     if (table->cols[col].expand)
1110                       {
1111                         has_expand = TRUE;
1112                         break;
1113                       }
1114                   
1115                   if (!has_expand)
1116                     for (col = child->left_attach; col < child->right_attach; col++)
1117                       table->cols[col].need_expand = TRUE;
1118                 }
1119               
1120               if (!child->xshrink)
1121                 {
1122                   has_shrink = TRUE;
1123                   for (col = child->left_attach; col < child->right_attach; col++)
1124                     if (!table->cols[col].shrink)
1125                       {
1126                         has_shrink = FALSE;
1127                         break;
1128                       }
1129                   
1130                   if (has_shrink)
1131                     for (col = child->left_attach; col < child->right_attach; col++)
1132                       table->cols[col].need_shrink = FALSE;
1133                 }
1134             }
1135           
1136           if (child->top_attach != (child->bottom_attach - 1))
1137             {
1138               for (row = child->top_attach; row < child->bottom_attach; row++)
1139                 table->rows[row].empty = FALSE;
1140
1141               if (child->yexpand)
1142                 {
1143                   has_expand = FALSE;
1144                   for (row = child->top_attach; row < child->bottom_attach; row++)
1145                     if (table->rows[row].expand)
1146                       {
1147                         has_expand = TRUE;
1148                         break;
1149                       }
1150                   
1151                   if (!has_expand)
1152                     for (row = child->top_attach; row < child->bottom_attach; row++)
1153                       table->rows[row].need_expand = TRUE;
1154                 }
1155               
1156               if (!child->yshrink)
1157                 {
1158                   has_shrink = TRUE;
1159                   for (row = child->top_attach; row < child->bottom_attach; row++)
1160                     if (!table->rows[row].shrink)
1161                       {
1162                         has_shrink = FALSE;
1163                         break;
1164                       }
1165                   
1166                   if (has_shrink)
1167                     for (row = child->top_attach; row < child->bottom_attach; row++)
1168                       table->rows[row].need_shrink = FALSE;
1169                 }
1170             }
1171         }
1172     }
1173   
1174   /* Loop over the columns and set the expand and shrink values
1175    *  if the column can be expanded or shrunk.
1176    */
1177   for (col = 0; col < table->ncols; col++)
1178     {
1179       if (table->cols[col].empty)
1180         {
1181           table->cols[col].expand = FALSE;
1182           table->cols[col].shrink = FALSE;
1183         }
1184       else
1185         {
1186           if (table->cols[col].need_expand)
1187             table->cols[col].expand = TRUE;
1188           if (!table->cols[col].need_shrink)
1189             table->cols[col].shrink = FALSE;
1190         }
1191     }
1192   
1193   /* Loop over the rows and set the expand and shrink values
1194    *  if the row can be expanded or shrunk.
1195    */
1196   for (row = 0; row < table->nrows; row++)
1197     {
1198       if (table->rows[row].empty)
1199         {
1200           table->rows[row].expand = FALSE;
1201           table->rows[row].shrink = FALSE;
1202         }
1203       else
1204         {
1205           if (table->rows[row].need_expand)
1206             table->rows[row].expand = TRUE;
1207           if (!table->rows[row].need_shrink)
1208             table->rows[row].shrink = FALSE;
1209         }
1210     }
1211 }
1212
1213 static void
1214 gtk_table_size_allocate_pass1 (GtkTable *table)
1215 {
1216   gint real_width;
1217   gint real_height;
1218   gint width, height;
1219   gint row, col;
1220   gint nexpand;
1221   gint nshrink;
1222   gint extra;
1223   
1224   /* If we were allocated more space than we requested
1225    *  then we have to expand any expandable rows and columns
1226    *  to fill in the extra space.
1227    */
1228   
1229   real_width = GTK_WIDGET (table)->allocation.width - GTK_CONTAINER (table)->border_width * 2;
1230   real_height = GTK_WIDGET (table)->allocation.height - GTK_CONTAINER (table)->border_width * 2;
1231   
1232   if (table->homogeneous)
1233     {
1234       nexpand = 0;
1235       for (col = 0; col < table->ncols; col++)
1236         if (table->cols[col].expand)
1237           {
1238             nexpand += 1;
1239             break;
1240           }
1241       
1242       if (nexpand > 0)
1243         {
1244           width = real_width;
1245           
1246           for (col = 0; col + 1 < table->ncols; col++)
1247             width -= table->cols[col].spacing;
1248           
1249           for (col = 0; col < table->ncols; col++)
1250             {
1251               extra = width / (table->ncols - col);
1252               table->cols[col].allocation = MAX (1, extra);
1253               width -= extra;
1254             }
1255         }
1256     }
1257   else
1258     {
1259       width = 0;
1260       nexpand = 0;
1261       nshrink = 0;
1262       
1263       for (col = 0; col < table->ncols; col++)
1264         {
1265           width += table->cols[col].requisition;
1266           if (table->cols[col].expand)
1267             nexpand += 1;
1268           if (table->cols[col].shrink)
1269             nshrink += 1;
1270         }
1271       for (col = 0; col + 1 < table->ncols; col++)
1272         width += table->cols[col].spacing;
1273       
1274       /* Check to see if we were allocated more width than we requested.
1275        */
1276       if ((width < real_width) && (nexpand >= 1))
1277         {
1278           width = real_width - width;
1279           
1280           for (col = 0; col < table->ncols; col++)
1281             if (table->cols[col].expand)
1282               {
1283                 extra = width / nexpand;
1284                 table->cols[col].allocation += extra;
1285                 
1286                 width -= extra;
1287                 nexpand -= 1;
1288               }
1289         }
1290       
1291       /* Check to see if we were allocated less width than we requested,
1292        * then shrink until we fit the size give.
1293        */
1294       if (width > real_width)
1295         {
1296           gint total_nshrink = nshrink;
1297
1298           extra = width - real_width;
1299           while (total_nshrink > 0 && extra > 0)
1300             {
1301               nshrink = total_nshrink;
1302               for (col = 0; col < table->ncols; col++)
1303                 if (table->cols[col].shrink)
1304                   {
1305                     gint allocation = table->cols[col].allocation;
1306
1307                     table->cols[col].allocation = MAX (1, (gint) table->cols[col].allocation - extra / nshrink);
1308                     extra -= allocation - table->cols[col].allocation;
1309                     nshrink -= 1;
1310                     if (table->cols[col].allocation < 2)
1311                       {
1312                         total_nshrink -= 1;
1313                         table->cols[col].shrink = FALSE;
1314                       }
1315                   }
1316             }
1317         }
1318     }
1319   
1320   if (table->homogeneous)
1321     {
1322       nexpand = 0;
1323       for (row = 0; row < table->nrows; row++)
1324         if (table->rows[row].expand)
1325           {
1326             nexpand += 1;
1327             break;
1328           }
1329       
1330       if (nexpand > 0)
1331         {
1332           height = real_height;
1333           
1334           for (row = 0; row + 1 < table->nrows; row++)
1335             height -= table->rows[row].spacing;
1336           
1337           
1338           for (row = 0; row < table->nrows; row++)
1339             {
1340               extra = height / (table->nrows - row);
1341               table->rows[row].allocation = MAX (1, extra);
1342               height -= extra;
1343             }
1344         }
1345     }
1346   else
1347     {
1348       height = 0;
1349       nexpand = 0;
1350       nshrink = 0;
1351       
1352       for (row = 0; row < table->nrows; row++)
1353         {
1354           height += table->rows[row].requisition;
1355           if (table->rows[row].expand)
1356             nexpand += 1;
1357           if (table->rows[row].shrink)
1358             nshrink += 1;
1359         }
1360       for (row = 0; row + 1 < table->nrows; row++)
1361         height += table->rows[row].spacing;
1362       
1363       /* Check to see if we were allocated more height than we requested.
1364        */
1365       if ((height < real_height) && (nexpand >= 1))
1366         {
1367           height = real_height - height;
1368           
1369           for (row = 0; row < table->nrows; row++)
1370             if (table->rows[row].expand)
1371               {
1372                 extra = height / nexpand;
1373                 table->rows[row].allocation += extra;
1374                 
1375                 height -= extra;
1376                 nexpand -= 1;
1377               }
1378         }
1379       
1380       /* Check to see if we were allocated less height than we requested.
1381        * then shrink until we fit the size give.
1382        */
1383       if (height > real_height)
1384         {
1385           gint total_nshrink = nshrink;
1386           
1387           extra = height - real_height;
1388           while (total_nshrink > 0 && extra > 0)
1389             {
1390               nshrink = total_nshrink;
1391               for (row = 0; row < table->nrows; row++)
1392                 if (table->rows[row].shrink)
1393                   {
1394                     gint allocation = table->rows[row].allocation;
1395                     
1396                     table->rows[row].allocation = MAX (1, (gint) table->rows[row].allocation - extra / nshrink);
1397                     extra -= allocation - table->rows[row].allocation;
1398                     nshrink -= 1;
1399                     if (table->rows[row].allocation < 2)
1400                       {
1401                         total_nshrink -= 1;
1402                         table->rows[row].shrink = FALSE;
1403                       }
1404                   }
1405             }
1406         }
1407     }
1408 }
1409
1410 static void
1411 gtk_table_size_allocate_pass2 (GtkTable *table)
1412 {
1413   GtkTableChild *child;
1414   GList *children;
1415   gint max_width;
1416   gint max_height;
1417   gint x, y;
1418   gint row, col;
1419   GtkAllocation allocation;
1420   GtkWidget *widget = GTK_WIDGET (table);
1421   
1422   children = table->children;
1423   while (children)
1424     {
1425       child = children->data;
1426       children = children->next;
1427       
1428       if (GTK_WIDGET_VISIBLE (child->widget))
1429         {
1430           GtkRequisition child_requisition;
1431           gtk_widget_get_child_requisition (child->widget, &child_requisition);
1432
1433           x = GTK_WIDGET (table)->allocation.x + GTK_CONTAINER (table)->border_width;
1434           y = GTK_WIDGET (table)->allocation.y + GTK_CONTAINER (table)->border_width;
1435           max_width = 0;
1436           max_height = 0;
1437           
1438           for (col = 0; col < child->left_attach; col++)
1439             {
1440               x += table->cols[col].allocation;
1441               x += table->cols[col].spacing;
1442             }
1443           
1444           for (col = child->left_attach; col < child->right_attach; col++)
1445             {
1446               max_width += table->cols[col].allocation;
1447               if ((col + 1) < child->right_attach)
1448                 max_width += table->cols[col].spacing;
1449             }
1450           
1451           for (row = 0; row < child->top_attach; row++)
1452             {
1453               y += table->rows[row].allocation;
1454               y += table->rows[row].spacing;
1455             }
1456           
1457           for (row = child->top_attach; row < child->bottom_attach; row++)
1458             {
1459               max_height += table->rows[row].allocation;
1460               if ((row + 1) < child->bottom_attach)
1461                 max_height += table->rows[row].spacing;
1462             }
1463           
1464           if (child->xfill)
1465             {
1466               allocation.width = MAX (1, max_width - (gint)child->xpadding * 2);
1467               allocation.x = x + (max_width - allocation.width) / 2;
1468             }
1469           else
1470             {
1471               allocation.width = child_requisition.width;
1472               allocation.x = x + (max_width - allocation.width) / 2;
1473             }
1474           
1475           if (child->yfill)
1476             {
1477               allocation.height = MAX (1, max_height - (gint)child->ypadding * 2);
1478               allocation.y = y + (max_height - allocation.height) / 2;
1479             }
1480           else
1481             {
1482               allocation.height = child_requisition.height;
1483               allocation.y = y + (max_height - allocation.height) / 2;
1484             }
1485
1486           if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1487             allocation.x = widget->allocation.x + widget->allocation.width
1488               - (allocation.x - widget->allocation.x) - allocation.width;
1489           
1490           gtk_widget_size_allocate (child->widget, &allocation);
1491         }
1492     }
1493 }