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