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