]> Pileus Git - ~andy/gtk/blob - gtk/gtktable.c
Deprecate widget flag: GTK_WIDGET_VISIBLE
[~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_get_visible (child) &&
376       gtk_widget_get_visible (GTK_WIDGET (table)))
377     gtk_widget_queue_resize (child);
378 }
379
380 static void
381 gtk_table_get_child_property (GtkContainer    *container,
382                               GtkWidget       *child,
383                               guint            property_id,
384                               GValue          *value,
385                               GParamSpec      *pspec)
386 {
387   GtkTable *table = GTK_TABLE (container);
388   GtkTableChild *table_child;
389   GList *list;
390
391   table_child = NULL;
392   for (list = table->children; list; list = list->next)
393     {
394       table_child = list->data;
395
396       if (table_child->widget == child)
397         break;
398     }
399   if (!list)
400     {
401       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
402       return;
403     }
404
405   switch (property_id)
406     {
407     case CHILD_PROP_LEFT_ATTACH:
408       g_value_set_uint (value, table_child->left_attach);
409       break;
410     case CHILD_PROP_RIGHT_ATTACH:
411       g_value_set_uint (value, table_child->right_attach);
412       break;
413     case CHILD_PROP_TOP_ATTACH:
414       g_value_set_uint (value, table_child->top_attach);
415       break;
416     case CHILD_PROP_BOTTOM_ATTACH:
417       g_value_set_uint (value, table_child->bottom_attach);
418       break;
419     case CHILD_PROP_X_OPTIONS:
420       g_value_set_flags (value, (table_child->xexpand * GTK_EXPAND |
421                                  table_child->xshrink * GTK_SHRINK |
422                                  table_child->xfill * GTK_FILL));
423       break;
424     case CHILD_PROP_Y_OPTIONS:
425       g_value_set_flags (value, (table_child->yexpand * GTK_EXPAND |
426                                  table_child->yshrink * GTK_SHRINK |
427                                  table_child->yfill * GTK_FILL));
428       break;
429     case CHILD_PROP_X_PADDING:
430       g_value_set_uint (value, table_child->xpadding);
431       break;
432     case CHILD_PROP_Y_PADDING:
433       g_value_set_uint (value, table_child->ypadding);
434       break;
435     default:
436       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
437       break;
438     }
439 }
440
441 static void
442 gtk_table_init (GtkTable *table)
443 {
444   GTK_WIDGET_SET_FLAGS (table, GTK_NO_WINDOW);
445   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (table), FALSE);
446   
447   table->children = NULL;
448   table->rows = NULL;
449   table->cols = NULL;
450   table->nrows = 0;
451   table->ncols = 0;
452   table->column_spacing = 0;
453   table->row_spacing = 0;
454   table->homogeneous = FALSE;
455
456   gtk_table_resize (table, 1, 1);
457 }
458
459 GtkWidget*
460 gtk_table_new (guint    rows,
461                guint    columns,
462                gboolean homogeneous)
463 {
464   GtkTable *table;
465
466   if (rows == 0)
467     rows = 1;
468   if (columns == 0)
469     columns = 1;
470   
471   table = g_object_new (GTK_TYPE_TABLE, NULL);
472   
473   table->homogeneous = (homogeneous ? TRUE : FALSE);
474
475   gtk_table_resize (table, rows, columns);
476   
477   return GTK_WIDGET (table);
478 }
479
480 void
481 gtk_table_resize (GtkTable *table,
482                   guint     n_rows,
483                   guint     n_cols)
484 {
485   g_return_if_fail (GTK_IS_TABLE (table));
486   g_return_if_fail (n_rows > 0 && n_rows <= 65535);
487   g_return_if_fail (n_cols > 0 && n_cols <= 65535);
488
489   n_rows = MAX (n_rows, 1);
490   n_cols = MAX (n_cols, 1);
491
492   if (n_rows != table->nrows ||
493       n_cols != table->ncols)
494     {
495       GList *list;
496       
497       for (list = table->children; list; list = list->next)
498         {
499           GtkTableChild *child;
500           
501           child = list->data;
502           
503           n_rows = MAX (n_rows, child->bottom_attach);
504           n_cols = MAX (n_cols, child->right_attach);
505         }
506       
507       if (n_rows != table->nrows)
508         {
509           guint i;
510
511           i = table->nrows;
512           table->nrows = n_rows;
513           table->rows = g_realloc (table->rows, table->nrows * sizeof (GtkTableRowCol));
514           
515           for (; i < table->nrows; i++)
516             {
517               table->rows[i].requisition = 0;
518               table->rows[i].allocation = 0;
519               table->rows[i].spacing = table->row_spacing;
520               table->rows[i].need_expand = 0;
521               table->rows[i].need_shrink = 0;
522               table->rows[i].expand = 0;
523               table->rows[i].shrink = 0;
524             }
525
526           g_object_notify (G_OBJECT (table), "n-rows");
527         }
528
529       if (n_cols != table->ncols)
530         {
531           guint i;
532
533           i = table->ncols;
534           table->ncols = n_cols;
535           table->cols = g_realloc (table->cols, table->ncols * sizeof (GtkTableRowCol));
536           
537           for (; i < table->ncols; i++)
538             {
539               table->cols[i].requisition = 0;
540               table->cols[i].allocation = 0;
541               table->cols[i].spacing = table->column_spacing;
542               table->cols[i].need_expand = 0;
543               table->cols[i].need_shrink = 0;
544               table->cols[i].expand = 0;
545               table->cols[i].shrink = 0;
546             }
547
548           g_object_notify (G_OBJECT (table), "n-columns");
549         }
550     }
551 }
552
553 void
554 gtk_table_attach (GtkTable        *table,
555                   GtkWidget       *child,
556                   guint            left_attach,
557                   guint            right_attach,
558                   guint            top_attach,
559                   guint            bottom_attach,
560                   GtkAttachOptions xoptions,
561                   GtkAttachOptions yoptions,
562                   guint            xpadding,
563                   guint            ypadding)
564 {
565   GtkTableChild *table_child;
566   
567   g_return_if_fail (GTK_IS_TABLE (table));
568   g_return_if_fail (GTK_IS_WIDGET (child));
569   g_return_if_fail (child->parent == NULL);
570   
571   /* g_return_if_fail (left_attach >= 0); */
572   g_return_if_fail (left_attach < right_attach);
573   /* g_return_if_fail (top_attach >= 0); */
574   g_return_if_fail (top_attach < bottom_attach);
575   
576   if (right_attach >= table->ncols)
577     gtk_table_resize (table, table->nrows, right_attach);
578   
579   if (bottom_attach >= table->nrows)
580     gtk_table_resize (table, bottom_attach, table->ncols);
581   
582   table_child = g_new (GtkTableChild, 1);
583   table_child->widget = child;
584   table_child->left_attach = left_attach;
585   table_child->right_attach = right_attach;
586   table_child->top_attach = top_attach;
587   table_child->bottom_attach = bottom_attach;
588   table_child->xexpand = (xoptions & GTK_EXPAND) != 0;
589   table_child->xshrink = (xoptions & GTK_SHRINK) != 0;
590   table_child->xfill = (xoptions & GTK_FILL) != 0;
591   table_child->xpadding = xpadding;
592   table_child->yexpand = (yoptions & GTK_EXPAND) != 0;
593   table_child->yshrink = (yoptions & GTK_SHRINK) != 0;
594   table_child->yfill = (yoptions & GTK_FILL) != 0;
595   table_child->ypadding = ypadding;
596   
597   table->children = g_list_prepend (table->children, table_child);
598   
599   gtk_widget_set_parent (child, GTK_WIDGET (table));
600 }
601
602 void
603 gtk_table_attach_defaults (GtkTable  *table,
604                            GtkWidget *widget,
605                            guint      left_attach,
606                            guint      right_attach,
607                            guint      top_attach,
608                            guint      bottom_attach)
609 {
610   gtk_table_attach (table, widget,
611                     left_attach, right_attach,
612                     top_attach, bottom_attach,
613                     GTK_EXPAND | GTK_FILL,
614                     GTK_EXPAND | GTK_FILL,
615                     0, 0);
616 }
617
618 void
619 gtk_table_set_row_spacing (GtkTable *table,
620                            guint     row,
621                            guint     spacing)
622 {
623   g_return_if_fail (GTK_IS_TABLE (table));
624   g_return_if_fail (row < table->nrows);
625   
626   if (table->rows[row].spacing != spacing)
627     {
628       table->rows[row].spacing = spacing;
629       
630       if (gtk_widget_get_visible (GTK_WIDGET (table)))
631         gtk_widget_queue_resize (GTK_WIDGET (table));
632     }
633 }
634
635 /**
636  * gtk_table_get_row_spacing:
637  * @table: a #GtkTable
638  * @row: a row in the table, 0 indicates the first row
639  *
640  * Gets the amount of space between row @row, and
641  * row @row + 1. See gtk_table_set_row_spacing().
642  *
643  * Return value: the row spacing
644  **/
645 guint
646 gtk_table_get_row_spacing (GtkTable *table,
647                            guint     row)
648 {
649   g_return_val_if_fail (GTK_IS_TABLE (table), 0);
650   g_return_val_if_fail (row < table->nrows - 1, 0);
651  
652   return table->rows[row].spacing;
653 }
654
655 void
656 gtk_table_set_col_spacing (GtkTable *table,
657                            guint     column,
658                            guint     spacing)
659 {
660   g_return_if_fail (GTK_IS_TABLE (table));
661   g_return_if_fail (column < table->ncols);
662   
663   if (table->cols[column].spacing != spacing)
664     {
665       table->cols[column].spacing = spacing;
666       
667       if (gtk_widget_get_visible (GTK_WIDGET (table)))
668         gtk_widget_queue_resize (GTK_WIDGET (table));
669     }
670 }
671
672 /**
673  * gtk_table_get_col_spacing:
674  * @table: a #GtkTable
675  * @column: a column in the table, 0 indicates the first column
676  *
677  * Gets the amount of space between column @col, and
678  * column @col + 1. See gtk_table_set_col_spacing().
679  *
680  * Return value: the column spacing
681  **/
682 guint
683 gtk_table_get_col_spacing (GtkTable *table,
684                            guint     column)
685 {
686   g_return_val_if_fail (GTK_IS_TABLE (table), 0);
687   g_return_val_if_fail (column < table->ncols, 0);
688
689   return table->cols[column].spacing;
690 }
691
692 void
693 gtk_table_set_row_spacings (GtkTable *table,
694                             guint     spacing)
695 {
696   guint row;
697   
698   g_return_if_fail (GTK_IS_TABLE (table));
699   
700   table->row_spacing = spacing;
701   for (row = 0; row < table->nrows; row++)
702     table->rows[row].spacing = spacing;
703   
704   if (gtk_widget_get_visible (GTK_WIDGET (table)))
705     gtk_widget_queue_resize (GTK_WIDGET (table));
706
707   g_object_notify (G_OBJECT (table), "row-spacing");
708 }
709
710 /**
711  * gtk_table_get_default_row_spacing:
712  * @table: a #GtkTable
713  *
714  * Gets the default row spacing for the table. This is
715  * the spacing that will be used for newly added rows.
716  * (See gtk_table_set_row_spacings())
717  *
718  * Return value: the default row spacing
719  **/
720 guint
721 gtk_table_get_default_row_spacing (GtkTable *table)
722 {
723   g_return_val_if_fail (GTK_IS_TABLE (table), 0);
724
725   return table->row_spacing;
726 }
727
728 void
729 gtk_table_set_col_spacings (GtkTable *table,
730                             guint     spacing)
731 {
732   guint col;
733   
734   g_return_if_fail (GTK_IS_TABLE (table));
735   
736   table->column_spacing = spacing;
737   for (col = 0; col < table->ncols; col++)
738     table->cols[col].spacing = spacing;
739   
740   if (gtk_widget_get_visible (GTK_WIDGET (table)))
741     gtk_widget_queue_resize (GTK_WIDGET (table));
742
743   g_object_notify (G_OBJECT (table), "column-spacing");
744 }
745
746 /**
747  * gtk_table_get_default_col_spacing:
748  * @table: a #GtkTable
749  *
750  * Gets the default column spacing for the table. This is
751  * the spacing that will be used for newly added columns.
752  * (See gtk_table_set_col_spacings())
753  *
754  * Return value: the default column spacing
755  **/
756 guint
757 gtk_table_get_default_col_spacing (GtkTable *table)
758 {
759   g_return_val_if_fail (GTK_IS_TABLE (table), 0);
760
761   return table->column_spacing;
762 }
763
764 void
765 gtk_table_set_homogeneous (GtkTable *table,
766                            gboolean  homogeneous)
767 {
768   g_return_if_fail (GTK_IS_TABLE (table));
769
770   homogeneous = (homogeneous != 0);
771   if (homogeneous != table->homogeneous)
772     {
773       table->homogeneous = homogeneous;
774       
775       if (gtk_widget_get_visible (GTK_WIDGET (table)))
776         gtk_widget_queue_resize (GTK_WIDGET (table));
777
778       g_object_notify (G_OBJECT (table), "homogeneous");
779     }
780 }
781
782 /**
783  * gtk_table_get_homogeneous:
784  * @table: a #GtkTable
785  *
786  * Returns whether the table cells are all constrained to the same
787  * width and height. (See gtk_table_set_homogenous ())
788  *
789  * Return value: %TRUE if the cells are all constrained to the same size
790  **/
791 gboolean
792 gtk_table_get_homogeneous (GtkTable *table)
793 {
794   g_return_val_if_fail (GTK_IS_TABLE (table), FALSE);
795
796   return table->homogeneous;
797 }
798
799 static void
800 gtk_table_finalize (GObject *object)
801 {
802   GtkTable *table = GTK_TABLE (object);
803
804   g_free (table->rows);
805   g_free (table->cols);
806   
807   G_OBJECT_CLASS (gtk_table_parent_class)->finalize (object);
808 }
809
810 static void
811 gtk_table_size_request (GtkWidget      *widget,
812                         GtkRequisition *requisition)
813 {
814   GtkTable *table = GTK_TABLE (widget);
815   gint row, col;
816
817   requisition->width = 0;
818   requisition->height = 0;
819   
820   gtk_table_size_request_init (table);
821   gtk_table_size_request_pass1 (table);
822   gtk_table_size_request_pass2 (table);
823   gtk_table_size_request_pass3 (table);
824   gtk_table_size_request_pass2 (table);
825   
826   for (col = 0; col < table->ncols; col++)
827     requisition->width += table->cols[col].requisition;
828   for (col = 0; col + 1 < table->ncols; col++)
829     requisition->width += table->cols[col].spacing;
830   
831   for (row = 0; row < table->nrows; row++)
832     requisition->height += table->rows[row].requisition;
833   for (row = 0; row + 1 < table->nrows; row++)
834     requisition->height += table->rows[row].spacing;
835   
836   requisition->width += GTK_CONTAINER (table)->border_width * 2;
837   requisition->height += GTK_CONTAINER (table)->border_width * 2;
838 }
839
840 static void
841 gtk_table_size_allocate (GtkWidget     *widget,
842                          GtkAllocation *allocation)
843 {
844   GtkTable *table = GTK_TABLE (widget);
845
846   widget->allocation = *allocation;
847
848   gtk_table_size_allocate_init (table);
849   gtk_table_size_allocate_pass1 (table);
850   gtk_table_size_allocate_pass2 (table);
851 }
852
853 static void
854 gtk_table_add (GtkContainer *container,
855                GtkWidget    *widget)
856 {
857   gtk_table_attach_defaults (GTK_TABLE (container), widget, 0, 1, 0, 1);
858 }
859
860 static void
861 gtk_table_remove (GtkContainer *container,
862                   GtkWidget    *widget)
863 {
864   GtkTable *table = GTK_TABLE (container);
865   GtkTableChild *child;
866   GtkWidget *widget_container = GTK_WIDGET (container);
867   GList *children;
868
869   children = table->children;
870   
871   while (children)
872     {
873       child = children->data;
874       children = children->next;
875       
876       if (child->widget == widget)
877         {
878           gboolean was_visible = gtk_widget_get_visible (widget);
879           
880           gtk_widget_unparent (widget);
881           
882           table->children = g_list_remove (table->children, child);
883           g_free (child);
884           
885           if (was_visible && gtk_widget_get_visible (widget_container))
886             gtk_widget_queue_resize (widget_container);
887           break;
888         }
889     }
890 }
891
892 static void
893 gtk_table_forall (GtkContainer *container,
894                   gboolean      include_internals,
895                   GtkCallback   callback,
896                   gpointer      callback_data)
897 {
898   GtkTable *table = GTK_TABLE (container);
899   GtkTableChild *child;
900   GList *children;
901
902   children = table->children;
903   
904   while (children)
905     {
906       child = children->data;
907       children = children->next;
908       
909       (* callback) (child->widget, callback_data);
910     }
911 }
912
913 static void
914 gtk_table_size_request_init (GtkTable *table)
915 {
916   GtkTableChild *child;
917   GList *children;
918   gint row, col;
919   
920   for (row = 0; row < table->nrows; row++)
921     {
922       table->rows[row].requisition = 0;
923       table->rows[row].expand = FALSE;
924     }
925   for (col = 0; col < table->ncols; col++)
926     {
927       table->cols[col].requisition = 0;
928       table->cols[col].expand = FALSE;
929     }
930   
931   children = table->children;
932   while (children)
933     {
934       child = children->data;
935       children = children->next;
936       
937       if (gtk_widget_get_visible (child->widget))
938         gtk_widget_size_request (child->widget, NULL);
939
940       if (child->left_attach == (child->right_attach - 1) && child->xexpand)
941         table->cols[child->left_attach].expand = TRUE;
942       
943       if (child->top_attach == (child->bottom_attach - 1) && child->yexpand)
944         table->rows[child->top_attach].expand = TRUE;
945     }
946 }
947
948 static void
949 gtk_table_size_request_pass1 (GtkTable *table)
950 {
951   GtkTableChild *child;
952   GList *children;
953   gint width;
954   gint height;
955   
956   children = table->children;
957   while (children)
958     {
959       child = children->data;
960       children = children->next;
961       
962       if (gtk_widget_get_visible (child->widget))
963         {
964           GtkRequisition child_requisition;
965           gtk_widget_get_child_requisition (child->widget, &child_requisition);
966
967           /* Child spans a single column.
968            */
969           if (child->left_attach == (child->right_attach - 1))
970             {
971               width = child_requisition.width + child->xpadding * 2;
972               table->cols[child->left_attach].requisition = MAX (table->cols[child->left_attach].requisition, width);
973             }
974           
975           /* Child spans a single row.
976            */
977           if (child->top_attach == (child->bottom_attach - 1))
978             {
979               height = child_requisition.height + child->ypadding * 2;
980               table->rows[child->top_attach].requisition = MAX (table->rows[child->top_attach].requisition, height);
981             }
982         }
983     }
984 }
985
986 static void
987 gtk_table_size_request_pass2 (GtkTable *table)
988 {
989   gint max_width;
990   gint max_height;
991   gint row, col;
992   
993   if (table->homogeneous)
994     {
995       max_width = 0;
996       max_height = 0;
997       
998       for (col = 0; col < table->ncols; col++)
999         max_width = MAX (max_width, table->cols[col].requisition);
1000       for (row = 0; row < table->nrows; row++)
1001         max_height = MAX (max_height, table->rows[row].requisition);
1002       
1003       for (col = 0; col < table->ncols; col++)
1004         table->cols[col].requisition = max_width;
1005       for (row = 0; row < table->nrows; row++)
1006         table->rows[row].requisition = max_height;
1007     }
1008 }
1009
1010 static void
1011 gtk_table_size_request_pass3 (GtkTable *table)
1012 {
1013   GtkTableChild *child;
1014   GList *children;
1015   gint width, height;
1016   gint row, col;
1017   gint extra;
1018   
1019   children = table->children;
1020   while (children)
1021     {
1022       child = children->data;
1023       children = children->next;
1024       
1025       if (gtk_widget_get_visible (child->widget))
1026         {
1027           /* Child spans multiple columns.
1028            */
1029           if (child->left_attach != (child->right_attach - 1))
1030             {
1031               GtkRequisition child_requisition;
1032
1033               gtk_widget_get_child_requisition (child->widget, &child_requisition);
1034               
1035               /* Check and see if there is already enough space
1036                *  for the child.
1037                */
1038               width = 0;
1039               for (col = child->left_attach; col < child->right_attach; col++)
1040                 {
1041                   width += table->cols[col].requisition;
1042                   if ((col + 1) < child->right_attach)
1043                     width += table->cols[col].spacing;
1044                 }
1045               
1046               /* If we need to request more space for this child to fill
1047                *  its requisition, then divide up the needed space amongst the
1048                *  columns it spans, favoring expandable columns if any.
1049                */
1050               if (width < child_requisition.width + child->xpadding * 2)
1051                 {
1052                   gint n_expand = 0;
1053                   gboolean force_expand = FALSE;
1054                   
1055                   width = child_requisition.width + child->xpadding * 2 - width;
1056
1057                   for (col = child->left_attach; col < child->right_attach; col++)
1058                     if (table->cols[col].expand)
1059                       n_expand++;
1060
1061                   if (n_expand == 0)
1062                     {
1063                       n_expand = (child->right_attach - child->left_attach);
1064                       force_expand = TRUE;
1065                     }
1066                     
1067                   for (col = child->left_attach; col < child->right_attach; col++)
1068                     if (force_expand || table->cols[col].expand)
1069                       {
1070                         extra = width / n_expand;
1071                         table->cols[col].requisition += extra;
1072                         width -= extra;
1073                         n_expand--;
1074                       }
1075                 }
1076             }
1077           
1078           /* Child spans multiple rows.
1079            */
1080           if (child->top_attach != (child->bottom_attach - 1))
1081             {
1082               GtkRequisition child_requisition;
1083
1084               gtk_widget_get_child_requisition (child->widget, &child_requisition);
1085
1086               /* Check and see if there is already enough space
1087                *  for the child.
1088                */
1089               height = 0;
1090               for (row = child->top_attach; row < child->bottom_attach; row++)
1091                 {
1092                   height += table->rows[row].requisition;
1093                   if ((row + 1) < child->bottom_attach)
1094                     height += table->rows[row].spacing;
1095                 }
1096               
1097               /* If we need to request more space for this child to fill
1098                *  its requisition, then divide up the needed space amongst the
1099                *  rows it spans, favoring expandable rows if any.
1100                */
1101               if (height < child_requisition.height + child->ypadding * 2)
1102                 {
1103                   gint n_expand = 0;
1104                   gboolean force_expand = FALSE;
1105                   
1106                   height = child_requisition.height + child->ypadding * 2 - height;
1107                   
1108                   for (row = child->top_attach; row < child->bottom_attach; row++)
1109                     {
1110                       if (table->rows[row].expand)
1111                         n_expand++;
1112                     }
1113
1114                   if (n_expand == 0)
1115                     {
1116                       n_expand = (child->bottom_attach - child->top_attach);
1117                       force_expand = TRUE;
1118                     }
1119                     
1120                   for (row = child->top_attach; row < child->bottom_attach; row++)
1121                     if (force_expand || table->rows[row].expand)
1122                       {
1123                         extra = height / n_expand;
1124                         table->rows[row].requisition += extra;
1125                         height -= extra;
1126                         n_expand--;
1127                       }
1128                 }
1129             }
1130         }
1131     }
1132 }
1133
1134 static void
1135 gtk_table_size_allocate_init (GtkTable *table)
1136 {
1137   GtkTableChild *child;
1138   GList *children;
1139   gint row, col;
1140   gint has_expand;
1141   gint has_shrink;
1142   
1143   /* Initialize the rows and cols.
1144    *  By default, rows and cols do not expand and do shrink.
1145    *  Those values are modified by the children that occupy
1146    *  the rows and cols.
1147    */
1148   for (col = 0; col < table->ncols; col++)
1149     {
1150       table->cols[col].allocation = table->cols[col].requisition;
1151       table->cols[col].need_expand = FALSE;
1152       table->cols[col].need_shrink = TRUE;
1153       table->cols[col].expand = FALSE;
1154       table->cols[col].shrink = TRUE;
1155       table->cols[col].empty = TRUE;
1156     }
1157   for (row = 0; row < table->nrows; row++)
1158     {
1159       table->rows[row].allocation = table->rows[row].requisition;
1160       table->rows[row].need_expand = FALSE;
1161       table->rows[row].need_shrink = TRUE;
1162       table->rows[row].expand = FALSE;
1163       table->rows[row].shrink = TRUE;
1164       table->rows[row].empty = TRUE;
1165     }
1166   
1167   /* Loop over all the children and adjust the row and col values
1168    *  based on whether the children want to be allowed to expand
1169    *  or shrink. This loop handles children that occupy a single
1170    *  row or column.
1171    */
1172   children = table->children;
1173   while (children)
1174     {
1175       child = children->data;
1176       children = children->next;
1177       
1178       if (gtk_widget_get_visible (child->widget))
1179         {
1180           if (child->left_attach == (child->right_attach - 1))
1181             {
1182               if (child->xexpand)
1183                 table->cols[child->left_attach].expand = TRUE;
1184               
1185               if (!child->xshrink)
1186                 table->cols[child->left_attach].shrink = FALSE;
1187               
1188               table->cols[child->left_attach].empty = FALSE;
1189             }
1190           
1191           if (child->top_attach == (child->bottom_attach - 1))
1192             {
1193               if (child->yexpand)
1194                 table->rows[child->top_attach].expand = TRUE;
1195               
1196               if (!child->yshrink)
1197                 table->rows[child->top_attach].shrink = FALSE;
1198
1199               table->rows[child->top_attach].empty = FALSE;
1200             }
1201         }
1202     }
1203   
1204   /* Loop over all the children again and this time handle children
1205    *  which span multiple rows or columns.
1206    */
1207   children = table->children;
1208   while (children)
1209     {
1210       child = children->data;
1211       children = children->next;
1212       
1213       if (gtk_widget_get_visible (child->widget))
1214         {
1215           if (child->left_attach != (child->right_attach - 1))
1216             {
1217               for (col = child->left_attach; col < child->right_attach; col++)
1218                 table->cols[col].empty = FALSE;
1219
1220               if (child->xexpand)
1221                 {
1222                   has_expand = FALSE;
1223                   for (col = child->left_attach; col < child->right_attach; col++)
1224                     if (table->cols[col].expand)
1225                       {
1226                         has_expand = TRUE;
1227                         break;
1228                       }
1229                   
1230                   if (!has_expand)
1231                     for (col = child->left_attach; col < child->right_attach; col++)
1232                       table->cols[col].need_expand = TRUE;
1233                 }
1234               
1235               if (!child->xshrink)
1236                 {
1237                   has_shrink = TRUE;
1238                   for (col = child->left_attach; col < child->right_attach; col++)
1239                     if (!table->cols[col].shrink)
1240                       {
1241                         has_shrink = FALSE;
1242                         break;
1243                       }
1244                   
1245                   if (has_shrink)
1246                     for (col = child->left_attach; col < child->right_attach; col++)
1247                       table->cols[col].need_shrink = FALSE;
1248                 }
1249             }
1250           
1251           if (child->top_attach != (child->bottom_attach - 1))
1252             {
1253               for (row = child->top_attach; row < child->bottom_attach; row++)
1254                 table->rows[row].empty = FALSE;
1255
1256               if (child->yexpand)
1257                 {
1258                   has_expand = FALSE;
1259                   for (row = child->top_attach; row < child->bottom_attach; row++)
1260                     if (table->rows[row].expand)
1261                       {
1262                         has_expand = TRUE;
1263                         break;
1264                       }
1265                   
1266                   if (!has_expand)
1267                     for (row = child->top_attach; row < child->bottom_attach; row++)
1268                       table->rows[row].need_expand = TRUE;
1269                 }
1270               
1271               if (!child->yshrink)
1272                 {
1273                   has_shrink = TRUE;
1274                   for (row = child->top_attach; row < child->bottom_attach; row++)
1275                     if (!table->rows[row].shrink)
1276                       {
1277                         has_shrink = FALSE;
1278                         break;
1279                       }
1280                   
1281                   if (has_shrink)
1282                     for (row = child->top_attach; row < child->bottom_attach; row++)
1283                       table->rows[row].need_shrink = FALSE;
1284                 }
1285             }
1286         }
1287     }
1288   
1289   /* Loop over the columns and set the expand and shrink values
1290    *  if the column can be expanded or shrunk.
1291    */
1292   for (col = 0; col < table->ncols; col++)
1293     {
1294       if (table->cols[col].empty)
1295         {
1296           table->cols[col].expand = FALSE;
1297           table->cols[col].shrink = FALSE;
1298         }
1299       else
1300         {
1301           if (table->cols[col].need_expand)
1302             table->cols[col].expand = TRUE;
1303           if (!table->cols[col].need_shrink)
1304             table->cols[col].shrink = FALSE;
1305         }
1306     }
1307   
1308   /* Loop over the rows and set the expand and shrink values
1309    *  if the row can be expanded or shrunk.
1310    */
1311   for (row = 0; row < table->nrows; row++)
1312     {
1313       if (table->rows[row].empty)
1314         {
1315           table->rows[row].expand = FALSE;
1316           table->rows[row].shrink = FALSE;
1317         }
1318       else
1319         {
1320           if (table->rows[row].need_expand)
1321             table->rows[row].expand = TRUE;
1322           if (!table->rows[row].need_shrink)
1323             table->rows[row].shrink = FALSE;
1324         }
1325     }
1326 }
1327
1328 static void
1329 gtk_table_size_allocate_pass1 (GtkTable *table)
1330 {
1331   gint real_width;
1332   gint real_height;
1333   gint width, height;
1334   gint row, col;
1335   gint nexpand;
1336   gint nshrink;
1337   gint extra;
1338   
1339   /* If we were allocated more space than we requested
1340    *  then we have to expand any expandable rows and columns
1341    *  to fill in the extra space.
1342    */
1343   
1344   real_width = GTK_WIDGET (table)->allocation.width - GTK_CONTAINER (table)->border_width * 2;
1345   real_height = GTK_WIDGET (table)->allocation.height - GTK_CONTAINER (table)->border_width * 2;
1346   
1347   if (table->homogeneous)
1348     {
1349       if (!table->children)
1350         nexpand = 1;
1351       else
1352         {
1353           nexpand = 0;
1354           for (col = 0; col < table->ncols; col++)
1355             if (table->cols[col].expand)
1356               {
1357                 nexpand += 1;
1358                 break;
1359               }
1360         }
1361       if (nexpand)
1362         {
1363           width = real_width;
1364           for (col = 0; col + 1 < table->ncols; col++)
1365             width -= table->cols[col].spacing;
1366           
1367           for (col = 0; col < table->ncols; col++)
1368             {
1369               extra = width / (table->ncols - col);
1370               table->cols[col].allocation = MAX (1, extra);
1371               width -= extra;
1372             }
1373         }
1374     }
1375   else
1376     {
1377       width = 0;
1378       nexpand = 0;
1379       nshrink = 0;
1380       
1381       for (col = 0; col < table->ncols; col++)
1382         {
1383           width += table->cols[col].requisition;
1384           if (table->cols[col].expand)
1385             nexpand += 1;
1386           if (table->cols[col].shrink)
1387             nshrink += 1;
1388         }
1389       for (col = 0; col + 1 < table->ncols; col++)
1390         width += table->cols[col].spacing;
1391       
1392       /* Check to see if we were allocated more width than we requested.
1393        */
1394       if ((width < real_width) && (nexpand >= 1))
1395         {
1396           width = real_width - width;
1397           
1398           for (col = 0; col < table->ncols; col++)
1399             if (table->cols[col].expand)
1400               {
1401                 extra = width / nexpand;
1402                 table->cols[col].allocation += extra;
1403                 
1404                 width -= extra;
1405                 nexpand -= 1;
1406               }
1407         }
1408       
1409       /* Check to see if we were allocated less width than we requested,
1410        * then shrink until we fit the size give.
1411        */
1412       if (width > real_width)
1413         {
1414           gint total_nshrink = nshrink;
1415
1416           extra = width - real_width;
1417           while (total_nshrink > 0 && extra > 0)
1418             {
1419               nshrink = total_nshrink;
1420               for (col = 0; col < table->ncols; col++)
1421                 if (table->cols[col].shrink)
1422                   {
1423                     gint allocation = table->cols[col].allocation;
1424
1425                     table->cols[col].allocation = MAX (1, (gint) table->cols[col].allocation - extra / nshrink);
1426                     extra -= allocation - table->cols[col].allocation;
1427                     nshrink -= 1;
1428                     if (table->cols[col].allocation < 2)
1429                       {
1430                         total_nshrink -= 1;
1431                         table->cols[col].shrink = FALSE;
1432                       }
1433                   }
1434             }
1435         }
1436     }
1437   
1438   if (table->homogeneous)
1439     {
1440       if (!table->children)
1441         nexpand = 1;
1442       else
1443         {
1444           nexpand = 0;
1445           for (row = 0; row < table->nrows; row++)
1446             if (table->rows[row].expand)
1447               {
1448                 nexpand += 1;
1449                 break;
1450               }
1451         }
1452       if (nexpand)
1453         {
1454           height = real_height;
1455           
1456           for (row = 0; row + 1 < table->nrows; row++)
1457             height -= table->rows[row].spacing;
1458           
1459           
1460           for (row = 0; row < table->nrows; row++)
1461             {
1462               extra = height / (table->nrows - row);
1463               table->rows[row].allocation = MAX (1, extra);
1464               height -= extra;
1465             }
1466         }
1467     }
1468   else
1469     {
1470       height = 0;
1471       nexpand = 0;
1472       nshrink = 0;
1473       
1474       for (row = 0; row < table->nrows; row++)
1475         {
1476           height += table->rows[row].requisition;
1477           if (table->rows[row].expand)
1478             nexpand += 1;
1479           if (table->rows[row].shrink)
1480             nshrink += 1;
1481         }
1482       for (row = 0; row + 1 < table->nrows; row++)
1483         height += table->rows[row].spacing;
1484       
1485       /* Check to see if we were allocated more height than we requested.
1486        */
1487       if ((height < real_height) && (nexpand >= 1))
1488         {
1489           height = real_height - height;
1490           
1491           for (row = 0; row < table->nrows; row++)
1492             if (table->rows[row].expand)
1493               {
1494                 extra = height / nexpand;
1495                 table->rows[row].allocation += extra;
1496                 
1497                 height -= extra;
1498                 nexpand -= 1;
1499               }
1500         }
1501       
1502       /* Check to see if we were allocated less height than we requested.
1503        * then shrink until we fit the size give.
1504        */
1505       if (height > real_height)
1506         {
1507           gint total_nshrink = nshrink;
1508           
1509           extra = height - real_height;
1510           while (total_nshrink > 0 && extra > 0)
1511             {
1512               nshrink = total_nshrink;
1513               for (row = 0; row < table->nrows; row++)
1514                 if (table->rows[row].shrink)
1515                   {
1516                     gint allocation = table->rows[row].allocation;
1517                     
1518                     table->rows[row].allocation = MAX (1, (gint) table->rows[row].allocation - extra / nshrink);
1519                     extra -= allocation - table->rows[row].allocation;
1520                     nshrink -= 1;
1521                     if (table->rows[row].allocation < 2)
1522                       {
1523                         total_nshrink -= 1;
1524                         table->rows[row].shrink = FALSE;
1525                       }
1526                   }
1527             }
1528         }
1529     }
1530 }
1531
1532 static void
1533 gtk_table_size_allocate_pass2 (GtkTable *table)
1534 {
1535   GtkTableChild *child;
1536   GList *children;
1537   gint max_width;
1538   gint max_height;
1539   gint x, y;
1540   gint row, col;
1541   GtkAllocation allocation;
1542   GtkWidget *widget = GTK_WIDGET (table);
1543   
1544   children = table->children;
1545   while (children)
1546     {
1547       child = children->data;
1548       children = children->next;
1549       
1550       if (gtk_widget_get_visible (child->widget))
1551         {
1552           GtkRequisition child_requisition;
1553           gtk_widget_get_child_requisition (child->widget, &child_requisition);
1554
1555           x = GTK_WIDGET (table)->allocation.x + GTK_CONTAINER (table)->border_width;
1556           y = GTK_WIDGET (table)->allocation.y + GTK_CONTAINER (table)->border_width;
1557           max_width = 0;
1558           max_height = 0;
1559           
1560           for (col = 0; col < child->left_attach; col++)
1561             {
1562               x += table->cols[col].allocation;
1563               x += table->cols[col].spacing;
1564             }
1565           
1566           for (col = child->left_attach; col < child->right_attach; col++)
1567             {
1568               max_width += table->cols[col].allocation;
1569               if ((col + 1) < child->right_attach)
1570                 max_width += table->cols[col].spacing;
1571             }
1572           
1573           for (row = 0; row < child->top_attach; row++)
1574             {
1575               y += table->rows[row].allocation;
1576               y += table->rows[row].spacing;
1577             }
1578           
1579           for (row = child->top_attach; row < child->bottom_attach; row++)
1580             {
1581               max_height += table->rows[row].allocation;
1582               if ((row + 1) < child->bottom_attach)
1583                 max_height += table->rows[row].spacing;
1584             }
1585           
1586           if (child->xfill)
1587             {
1588               allocation.width = MAX (1, max_width - (gint)child->xpadding * 2);
1589               allocation.x = x + (max_width - allocation.width) / 2;
1590             }
1591           else
1592             {
1593               allocation.width = child_requisition.width;
1594               allocation.x = x + (max_width - allocation.width) / 2;
1595             }
1596           
1597           if (child->yfill)
1598             {
1599               allocation.height = MAX (1, max_height - (gint)child->ypadding * 2);
1600               allocation.y = y + (max_height - allocation.height) / 2;
1601             }
1602           else
1603             {
1604               allocation.height = child_requisition.height;
1605               allocation.y = y + (max_height - allocation.height) / 2;
1606             }
1607
1608           if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1609             allocation.x = widget->allocation.x + widget->allocation.width
1610               - (allocation.x - widget->allocation.x) - allocation.width;
1611           
1612           gtk_widget_size_allocate (child->widget, &allocation);
1613         }
1614     }
1615 }
1616
1617 #define __GTK_TABLE_C__
1618 #include "gtkaliasdef.c"