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