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