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