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