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