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