]> Pileus Git - ~andy/gtk/blob - gtk/gtkbox.c
27c4de118ca0e4546f00363cbcc95771fefbd6e9
[~andy/gtk] / gtk / gtkbox.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
29 #include "gtkbox.h"
30 #include "gtkorientable.h"
31 #include "gtkextendedlayout.h"
32 #include "gtkprivate.h"
33 #include "gtkintl.h"
34 #include "gtkalias.h"
35
36 enum {
37   PROP_0,
38   PROP_ORIENTATION,
39   PROP_SPACING,
40   PROP_HOMOGENEOUS
41 };
42
43 enum {
44   CHILD_PROP_0,
45   CHILD_PROP_EXPAND,
46   CHILD_PROP_FILL,
47   CHILD_PROP_PADDING,
48   CHILD_PROP_PACK_TYPE,
49   CHILD_PROP_POSITION
50 };
51
52
53 typedef struct _GtkBoxPrivate GtkBoxPrivate;
54
55 struct _GtkBoxPrivate
56 {
57   GtkOrientation orientation;
58   guint          default_expand : 1;
59   guint          spacing_set    : 1;
60 };
61
62 #define GTK_BOX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_BOX, GtkBoxPrivate))
63
64 typedef struct _GtkBoxDesiredSizes GtkBoxDesiredSizes;
65 typedef struct _GtkBoxSpreading    GtkBoxSpreading;
66
67 struct _GtkBoxDesiredSizes
68 {
69   gint minimum_size;
70   gint natural_size;
71 };
72
73 struct _GtkBoxSpreading
74 {
75   GtkBoxChild *child;
76   gint index;
77 };
78
79 static void gtk_box_size_allocate         (GtkWidget              *widget,
80                                            GtkAllocation          *allocation);
81
82 static void gtk_box_set_property       (GObject        *object,
83                                         guint           prop_id,
84                                         const GValue   *value,
85                                         GParamSpec     *pspec);
86 static void gtk_box_get_property       (GObject        *object,
87                                         guint           prop_id,
88                                         GValue         *value,
89                                         GParamSpec     *pspec);
90
91 static void gtk_box_add                (GtkContainer   *container,
92                                         GtkWidget      *widget);
93 static void gtk_box_remove             (GtkContainer   *container,
94                                         GtkWidget      *widget);
95 static void gtk_box_forall             (GtkContainer   *container,
96                                         gboolean        include_internals,
97                                         GtkCallback     callback,
98                                         gpointer        callback_data);
99 static void gtk_box_set_child_property (GtkContainer   *container,
100                                         GtkWidget      *child,
101                                         guint           property_id,
102                                         const GValue   *value,
103                                         GParamSpec     *pspec);
104 static void gtk_box_get_child_property (GtkContainer   *container,
105                                         GtkWidget      *child,
106                                         guint           property_id,
107                                         GValue         *value,
108                                         GParamSpec     *pspec);
109 static GType gtk_box_child_type        (GtkContainer   *container);
110
111
112 static void gtk_box_extended_layout_init  (GtkExtendedLayoutIface *iface);
113 static void gtk_box_get_desired_size      (GtkExtendedLayout      *layout,
114                                            GtkRequisition         *minimum_size,
115                                            GtkRequisition         *natural_size);
116 static gboolean gtk_box_is_height_for_width (GtkExtendedLayout      *layout);
117 static void gtk_box_get_width_for_height  (GtkExtendedLayout      *layout,
118                                            gint                    height,
119                                            gint                   *minimum_width,
120                                            gint                   *natural_width);
121 static void gtk_box_get_height_for_width  (GtkExtendedLayout      *layout,
122                                            gint                    width,
123                                            gint                   *minimum_height,
124                                            gint                   *natural_height);
125
126 static GtkExtendedLayoutIface *parent_extended_layout_iface;
127
128 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkBox, gtk_box, GTK_TYPE_CONTAINER,
129                                   G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
130                                                          NULL)
131                                   G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
132                                                          gtk_box_extended_layout_init));
133
134 static void
135 gtk_box_class_init (GtkBoxClass *class)
136 {
137   GObjectClass *object_class = G_OBJECT_CLASS (class);
138   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
139   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
140
141   object_class->set_property = gtk_box_set_property;
142   object_class->get_property = gtk_box_get_property;
143
144   widget_class->size_allocate = gtk_box_size_allocate;
145
146   container_class->add = gtk_box_add;
147   container_class->remove = gtk_box_remove;
148   container_class->forall = gtk_box_forall;
149   container_class->child_type = gtk_box_child_type;
150   container_class->set_child_property = gtk_box_set_child_property;
151   container_class->get_child_property = gtk_box_get_child_property;
152
153   g_object_class_override_property (object_class,
154                                     PROP_ORIENTATION,
155                                     "orientation");
156
157   g_object_class_install_property (object_class,
158                                    PROP_SPACING,
159                                    g_param_spec_int ("spacing",
160                                                      P_("Spacing"),
161                                                      P_("The amount of space between children"),
162                                                      0,
163                                                      G_MAXINT,
164                                                      0,
165                                                      GTK_PARAM_READWRITE));
166
167   g_object_class_install_property (object_class,
168                                    PROP_HOMOGENEOUS,
169                                    g_param_spec_boolean ("homogeneous",
170                                                          P_("Homogeneous"),
171                                                          P_("Whether the children should all be the same size"),
172                                                          FALSE,
173                                                          GTK_PARAM_READWRITE));
174
175   gtk_container_class_install_child_property (container_class,
176                                               CHILD_PROP_EXPAND,
177                                               g_param_spec_boolean ("expand", 
178                                                                     P_("Expand"), 
179                                                                     P_("Whether the child should receive extra space when the parent grows"),
180                                                                     TRUE,
181                                                                     GTK_PARAM_READWRITE));
182   gtk_container_class_install_child_property (container_class,
183                                               CHILD_PROP_FILL,
184                                               g_param_spec_boolean ("fill", 
185                                                                     P_("Fill"), 
186                                                                     P_("Whether extra space given to the child should be allocated to the child or used as padding"),
187                                                                     TRUE,
188                                                                     GTK_PARAM_READWRITE));
189   gtk_container_class_install_child_property (container_class,
190                                               CHILD_PROP_PADDING,
191                                               g_param_spec_uint ("padding", 
192                                                                  P_("Padding"), 
193                                                                  P_("Extra space to put between the child and its neighbors, in pixels"),
194                                                                  0, G_MAXINT, 0,
195                                                                  GTK_PARAM_READWRITE));
196   gtk_container_class_install_child_property (container_class,
197                                               CHILD_PROP_PACK_TYPE,
198                                               g_param_spec_enum ("pack-type", 
199                                                                  P_("Pack type"), 
200                                                                  P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
201                                                                  GTK_TYPE_PACK_TYPE, GTK_PACK_START,
202                                                                  GTK_PARAM_READWRITE));
203   gtk_container_class_install_child_property (container_class,
204                                               CHILD_PROP_POSITION,
205                                               g_param_spec_int ("position", 
206                                                                 P_("Position"), 
207                                                                 P_("The index of the child in the parent"),
208                                                                 -1, G_MAXINT, 0,
209                                                                 GTK_PARAM_READWRITE));
210
211   g_type_class_add_private (object_class, sizeof (GtkBoxPrivate));
212 }
213
214 static void
215 gtk_box_init (GtkBox *box)
216 {
217   GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (box);
218
219   gtk_widget_set_has_window (GTK_WIDGET (box), FALSE);
220   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (box), FALSE);
221
222   box->children = NULL;
223   box->spacing = 0;
224   box->homogeneous = FALSE;
225
226   private->orientation = GTK_ORIENTATION_HORIZONTAL;
227   private->default_expand = FALSE;
228   private->spacing_set = FALSE;
229 }
230
231 static void
232 gtk_box_set_property (GObject      *object,
233                       guint         prop_id,
234                       const GValue *value,
235                       GParamSpec   *pspec)
236 {
237   GtkBox *box = GTK_BOX (object);
238   GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (box);
239
240   switch (prop_id)
241     {
242     case PROP_ORIENTATION:
243       private->orientation = g_value_get_enum (value);
244       gtk_widget_queue_resize (GTK_WIDGET (box));
245       break;
246     case PROP_SPACING:
247       gtk_box_set_spacing (box, g_value_get_int (value));
248       break;
249     case PROP_HOMOGENEOUS:
250       gtk_box_set_homogeneous (box, g_value_get_boolean (value));
251       break;
252     default:
253       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
254       break;
255     }
256 }
257
258 static void
259 gtk_box_get_property (GObject    *object,
260                       guint       prop_id,
261                       GValue     *value,
262                       GParamSpec *pspec)
263 {
264   GtkBox *box = GTK_BOX (object);
265   GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (box);
266
267   switch (prop_id)
268     {
269     case PROP_ORIENTATION:
270       g_value_set_enum (value, private->orientation);
271       break;
272     case PROP_SPACING:
273       g_value_set_int (value, box->spacing);
274       break;
275     case PROP_HOMOGENEOUS:
276       g_value_set_boolean (value, box->homogeneous);
277       break;
278     default:
279       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
280       break;
281     }
282 }
283
284
285 static gint
286 gtk_box_compare_gap (gconstpointer p1,
287                       gconstpointer p2,
288                       gpointer      data)
289 {
290   GtkBoxDesiredSizes *sizes = data;
291   const GtkBoxSpreading *c1 = p1;
292   const GtkBoxSpreading *c2 = p2;
293
294   const gint d1 = MAX (sizes[c1->index].natural_size -
295                        sizes[c1->index].minimum_size,
296                        0);
297   const gint d2 = MAX (sizes[c2->index].natural_size -
298                        sizes[c2->index].minimum_size,
299                        0);
300
301   gint delta = (d2 - d1);
302
303   if (0 == delta)
304     delta = (c2->index - c1->index);
305
306   return delta;
307 }
308
309
310 static void
311 gtk_box_size_allocate (GtkWidget     *widget,
312                        GtkAllocation *allocation)
313 {
314   GtkBox *box = GTK_BOX (widget);
315   GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (box);
316   GtkBoxChild *child;
317   GList *children;
318   gint nvis_children;
319   gint nexpand_children;
320
321   widget->allocation = *allocation;
322
323   nvis_children = 0;
324   nexpand_children = 0;
325
326   for (children = box->children; children; children = children->next)
327     {
328       child = children->data;
329
330       if (gtk_widget_get_visible (child->widget))
331         {
332           nvis_children += 1;
333           if (child->expand)
334             nexpand_children += 1;
335         }
336     }
337
338   if (nvis_children > 0)
339     {
340       gint border_width = GTK_CONTAINER (box)->border_width;
341       GtkTextDirection direction = gtk_widget_get_direction (widget);
342       GtkAllocation child_allocation;
343       GtkBoxSpreading *spreading = g_newa (GtkBoxSpreading, nvis_children);
344       GtkBoxDesiredSizes *sizes = g_newa (GtkBoxDesiredSizes, nvis_children);
345
346       GtkPackType packing;
347
348       gint size;
349       gint extra;
350       gint x, y, i;
351       gint child_size;
352
353       if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
354         size = allocation->width - border_width * 2 - (nvis_children - 1) * box->spacing;
355       else
356         size = allocation->height - border_width * 2 - (nvis_children - 1) * box->spacing;
357
358       /* Retrieve desired size for visible children */
359       i = 0;
360       children = box->children;
361       while (children)
362         {
363           child = children->data;
364           children = children->next;
365           
366           if (gtk_widget_get_visible (child->widget))
367             {
368               if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
369                 gtk_extended_layout_get_width_for_height (GTK_EXTENDED_LAYOUT (child->widget),
370                                                           allocation->height,
371                                                           &sizes[i].minimum_size,
372                                                           &sizes[i].natural_size);
373               else
374                 gtk_extended_layout_get_height_for_width (GTK_EXTENDED_LAYOUT (child->widget),
375                                                           allocation->width,
376                                                           &sizes[i].minimum_size,
377                                                           &sizes[i].natural_size);
378               
379               
380               /* Assert the api is working properly */
381               g_assert (sizes[i].minimum_size >= 0);
382               g_assert (sizes[i].natural_size >= sizes[i].minimum_size);
383               
384               size -= sizes[i].minimum_size;
385               size -= child->padding * 2;
386               
387               spreading[i].index = i;
388               spreading[i].child = child;
389               
390               i += 1;
391             }
392         }
393
394       if (box->homogeneous)
395         {
396           /* If were homogenous we still need to run the above loop to get the minimum sizes
397            * for children that are not going to fill 
398            */
399           if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
400             size = allocation->width - border_width * 2 - (nvis_children - 1) * box->spacing;
401           else
402             size = allocation->height - border_width * 2 - (nvis_children - 1) * box->spacing;
403           
404           extra = size / nvis_children;
405         }
406       else
407         {
408
409           /* Distribute the container's extra space c_gap. We want to assign
410            * this space such that the sum of extra space assigned to children
411            * (c^i_gap) is equal to c_cap. The case that there's not enough
412            * space for all children to take their natural size needs some
413            * attention. The goals we want to achieve are:
414            *
415            *   a) Maximize number of children taking their natural size.
416            *   b) The allocated size of children should be a continuous
417            *   function of c_gap.  That is, increasing the container size by
418            *   one pixel should never make drastic changes in the distribution.
419            *   c) If child i takes its natural size and child j doesn't,
420            *   child j should have received at least as much gap as child i.
421            *
422            * The following code distributes the additional space by following
423            * this rules.
424            */
425
426           /* Sort descending by gap and position. */
427
428           g_qsort_with_data (spreading,
429                              nvis_children, sizeof (GtkBoxSpreading),
430                              gtk_box_compare_gap, sizes);
431
432           /* Distribute available space.
433            * This master piece of a loop was conceived by Behdad Esfahbod.
434            */
435           for (i = nvis_children - 1; i >= 0; --i)
436             {
437               /* Divide remaining space by number of remaining children.
438                * Sort order and reducing remaining space by assigned space
439                * ensures that space is distributed equally.
440                */
441               gint glue = (size + i) / (i + 1);
442               gint gap = sizes[spreading[i].index].natural_size
443                        - sizes[spreading[i].index].minimum_size;
444
445               extra = MIN (glue, gap);
446               sizes[spreading[i].index].minimum_size += extra;
447
448               size -= extra;
449             }
450
451           /* Calculate space which hasn't distributed yet,
452            * and is available for expanding children.
453            */
454           if (nexpand_children > 0)
455             extra = size / nexpand_children;
456           else
457             extra = 0;
458         }
459
460       /* Allocate child positions. */
461
462       for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
463         {
464           if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
465             {
466               child_allocation.y = allocation->y + border_width;
467               child_allocation.height = MAX (1, allocation->height - border_width * 2);
468               if (packing == GTK_PACK_START)
469                 x = allocation->x + border_width;
470               else
471                 x = allocation->x + allocation->width - border_width;
472             }
473           else
474             {
475               child_allocation.x = allocation->x + border_width;
476               child_allocation.width = MAX (1, allocation->width - border_width * 2);
477               if (packing == GTK_PACK_START)
478                 y = allocation->y + border_width;
479               else
480                 y = allocation->y + allocation->height - border_width;
481             }
482
483           i = 0;
484           children = box->children;
485           while (children)
486             {
487               child = children->data;
488               children = children->next;
489
490               if (gtk_widget_get_visible (child->widget))
491                 {
492                   if (child->pack == packing)
493                     {
494                       /* Assign the child's size. */
495                       if (box->homogeneous)
496                         {
497                           if (nvis_children == 1)
498                             child_size = size;
499                           else
500                             child_size = extra;
501
502                           nvis_children -= 1;
503                           size -= extra;
504                         }
505                       else
506                         {
507                           child_size = sizes[i].minimum_size + child->padding * 2;
508
509                           if (child->expand)
510                             {
511                               if (nexpand_children == 1)
512                                 child_size += size;
513                               else
514                                 child_size += extra;
515
516                               nexpand_children -= 1;
517                               size -= extra;
518                             }
519                         }
520
521                       /* Assign the child's position. */
522                       if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
523                         {
524                           if (child->fill)
525                             {
526                               child_allocation.width = MAX (1, child_size - child->padding * 2);
527                               child_allocation.x = x + child->padding;
528                             }
529                           else
530                             {
531                               child_allocation.width = sizes[i].minimum_size;
532                               child_allocation.x = x + (child_size - child_allocation.width) / 2;
533                             }
534                           
535                           if (direction == GTK_TEXT_DIR_RTL)
536                             child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
537
538                           if (packing == GTK_PACK_START)
539                             {
540                               x += child_size + box->spacing;
541                             }
542                           else
543                             {
544                               x -= child_size + box->spacing;
545
546                               child_allocation.x -= child_allocation.width;
547                             }
548                         }
549                       else /* (private->orientation == GTK_ORIENTATION_VERTICAL) */
550                         {
551                           if (child->fill)
552                             {
553                               child_allocation.height = MAX (1, child_size - child->padding * 2);
554                               child_allocation.y = y + child->padding;
555                             }
556                           else
557                             {
558                               child_allocation.height = sizes[i].minimum_size;
559                               child_allocation.y = y + (child_size - child_allocation.height) / 2;
560                             }
561
562                          if (packing == GTK_PACK_START)
563                            {
564                              y += child_size + box->spacing;
565                            }
566                          else
567                            {
568                              y -= child_size + box->spacing;
569
570                              child_allocation.y -= child_allocation.height;
571                            }
572                         }
573                       gtk_widget_size_allocate (child->widget, &child_allocation);
574
575                     }
576
577                   i += 1;
578                 }
579             }
580         }
581     }
582 }
583
584 static GType
585 gtk_box_child_type (GtkContainer   *container)
586 {
587   return GTK_TYPE_WIDGET;
588 }
589
590 static void
591 gtk_box_set_child_property (GtkContainer *container,
592                             GtkWidget    *child,
593                             guint         property_id,
594                             const GValue *value,
595                             GParamSpec   *pspec)
596 {
597   gboolean expand = 0;
598   gboolean fill = 0;
599   guint padding = 0;
600   GtkPackType pack_type = 0;
601
602   if (property_id != CHILD_PROP_POSITION)
603     gtk_box_query_child_packing (GTK_BOX (container),
604                                  child,
605                                  &expand,
606                                  &fill,
607                                  &padding,
608                                  &pack_type);
609   switch (property_id)
610     {
611     case CHILD_PROP_EXPAND:
612       gtk_box_set_child_packing (GTK_BOX (container),
613                                  child,
614                                  g_value_get_boolean (value),
615                                  fill,
616                                  padding,
617                                  pack_type);
618       break;
619     case CHILD_PROP_FILL:
620       gtk_box_set_child_packing (GTK_BOX (container),
621                                  child,
622                                  expand,
623                                  g_value_get_boolean (value),
624                                  padding,
625                                  pack_type);
626       break;
627     case CHILD_PROP_PADDING:
628       gtk_box_set_child_packing (GTK_BOX (container),
629                                  child,
630                                  expand,
631                                  fill,
632                                  g_value_get_uint (value),
633                                  pack_type);
634       break;
635     case CHILD_PROP_PACK_TYPE:
636       gtk_box_set_child_packing (GTK_BOX (container),
637                                  child,
638                                  expand,
639                                  fill,
640                                  padding,
641                                  g_value_get_enum (value));
642       break;
643     case CHILD_PROP_POSITION:
644       gtk_box_reorder_child (GTK_BOX (container),
645                              child,
646                              g_value_get_int (value));
647       break;
648     default:
649       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
650       break;
651     }
652 }
653
654 static void
655 gtk_box_get_child_property (GtkContainer *container,
656                             GtkWidget    *child,
657                             guint         property_id,
658                             GValue       *value,
659                             GParamSpec   *pspec)
660 {
661   gboolean expand = 0;
662   gboolean fill = 0;
663   guint padding = 0;
664   GtkPackType pack_type = 0;
665   GList *list;
666
667   if (property_id != CHILD_PROP_POSITION)
668     gtk_box_query_child_packing (GTK_BOX (container),
669                                  child,
670                                  &expand,
671                                  &fill,
672                                  &padding,
673                                  &pack_type);
674   switch (property_id)
675     {
676       guint i;
677     case CHILD_PROP_EXPAND:
678       g_value_set_boolean (value, expand);
679       break;
680     case CHILD_PROP_FILL:
681       g_value_set_boolean (value, fill);
682       break;
683     case CHILD_PROP_PADDING:
684       g_value_set_uint (value, padding);
685       break;
686     case CHILD_PROP_PACK_TYPE:
687       g_value_set_enum (value, pack_type);
688       break;
689     case CHILD_PROP_POSITION:
690       i = 0;
691       for (list = GTK_BOX (container)->children; list; list = list->next)
692         {
693           GtkBoxChild *child_entry;
694
695           child_entry = list->data;
696           if (child_entry->widget == child)
697             break;
698           i++;
699         }
700       g_value_set_int (value, list ? i : -1);
701       break;
702     default:
703       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
704       break;
705     }
706 }
707
708 static void
709 gtk_box_pack (GtkBox      *box,
710               GtkWidget   *child,
711               gboolean     expand,
712               gboolean     fill,
713               guint        padding,
714               GtkPackType  pack_type)
715 {
716   GtkBoxChild *child_info;
717
718   g_return_if_fail (GTK_IS_BOX (box));
719   g_return_if_fail (GTK_IS_WIDGET (child));
720   g_return_if_fail (child->parent == NULL);
721
722   child_info = g_new (GtkBoxChild, 1);
723   child_info->widget = child;
724   child_info->padding = padding;
725   child_info->expand = expand ? TRUE : FALSE;
726   child_info->fill = fill ? TRUE : FALSE;
727   child_info->pack = pack_type;
728   child_info->is_secondary = FALSE;
729
730   box->children = g_list_append (box->children, child_info);
731
732   gtk_widget_freeze_child_notify (child);
733
734   gtk_widget_set_parent (child, GTK_WIDGET (box));
735   
736   gtk_widget_child_notify (child, "expand");
737   gtk_widget_child_notify (child, "fill");
738   gtk_widget_child_notify (child, "padding");
739   gtk_widget_child_notify (child, "pack-type");
740   gtk_widget_child_notify (child, "position");
741   gtk_widget_thaw_child_notify (child);
742 }
743
744
745
746 static void
747 gtk_box_extended_layout_init (GtkExtendedLayoutIface *iface)
748 {
749   parent_extended_layout_iface = g_type_interface_peek_parent (iface);
750
751   iface->is_height_for_width  = gtk_box_is_height_for_width;
752   iface->get_desired_size     = gtk_box_get_desired_size;
753   iface->get_height_for_width = gtk_box_get_height_for_width;
754   iface->get_width_for_height = gtk_box_get_width_for_height;
755 }
756
757 static gboolean 
758 gtk_box_is_height_for_width (GtkExtendedLayout      *layout)
759 {
760   GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (layout);
761
762   return (private->orientation == GTK_ORIENTATION_HORIZONTAL);
763 }
764
765 static void
766 gtk_box_get_desired_size (GtkExtendedLayout *layout,
767                           GtkRequisition    *minimum_size,
768                           GtkRequisition    *natural_size)
769 {
770   GtkBox *box;
771   GtkBoxPrivate *private;
772   GList *children;
773   gint nvis_children;
774   gint border_width;
775
776   box = GTK_BOX (layout);
777   private = GTK_BOX_GET_PRIVATE (box);
778   border_width = GTK_CONTAINER (box)->border_width;
779
780   minimum_size->width = minimum_size->height = 0;
781   natural_size->width = natural_size->height = 0;
782
783   nvis_children = 0;
784   children = box->children;
785   while (children)
786     {
787       GtkBoxChild *child;
788
789       child = children->data;
790       children = children->next;
791
792       if (gtk_widget_get_visible (child->widget))
793         {
794           GtkRequisition child_minimum_size;
795           GtkRequisition child_natural_size;
796
797           gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (child->widget),
798                                                 &child_minimum_size,
799                                                 &child_natural_size);
800
801           if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
802             {
803               if (box->homogeneous)
804                 {
805                   gint width;
806
807                   width = child_minimum_size.width + child->padding * 2;
808                   minimum_size->width = MAX (minimum_size->width, width);
809
810                   width = child_natural_size.width + child->padding * 2;
811                   natural_size->width = MAX (natural_size->width, width);
812                 }
813               else
814                 {
815                   minimum_size->width += child_minimum_size.width + child->padding * 2;
816                   natural_size->width += child_natural_size.width + child->padding * 2;
817                 }
818
819               minimum_size->height = MAX (minimum_size->height, child_minimum_size.height);
820               natural_size->height = MAX (natural_size->height, child_natural_size.height);
821             }
822           else
823             {
824               if (box->homogeneous)
825                 {
826                   gint height;
827
828                   height = child_minimum_size.height + child->padding * 2;
829                   minimum_size->height = MAX (minimum_size->height, height);
830
831                   height = child_natural_size.height + child->padding * 2;
832                   natural_size->height = MAX (natural_size->height, height);
833                 }
834               else
835                 {
836                   minimum_size->height += child_minimum_size.height + child->padding * 2;
837                   natural_size->height += child_natural_size.height + child->padding * 2;
838                 }
839
840               minimum_size->width = MAX (minimum_size->width, child_minimum_size.width);
841               natural_size->width = MAX (natural_size->width, child_natural_size.width);
842             }
843
844
845           nvis_children += 1;
846         }
847     }
848   if (nvis_children > 0)
849     {
850       if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
851         {
852           if (box->homogeneous)
853             {
854              minimum_size->width *= nvis_children;
855              natural_size->width *= nvis_children;
856             }
857
858           minimum_size->width += (nvis_children - 1) * box->spacing;
859           natural_size->width += (nvis_children - 1) * box->spacing;
860         }
861       else
862         {
863           if (box->homogeneous)
864             {
865              minimum_size->height *= nvis_children;
866              natural_size->height *= nvis_children;
867             }
868
869           minimum_size->height += (nvis_children - 1) * box->spacing;
870           natural_size->height += (nvis_children - 1) * box->spacing;
871         }
872     }
873
874   minimum_size->width += border_width * 2;
875   minimum_size->height += border_width * 2;
876
877   natural_size->width += border_width * 2;
878   natural_size->height += border_width * 2;
879 }
880
881
882 /**
883  * size_fits_for_dimension:
884  * @box: a GtkBox
885  * @avail_size: the allocated size in @box's opposing orientation
886  * @check_size: the size in @box's orientation to check
887  * @check_natural: whether to check natural sizes or minimum sizes.
888  *
889  * This checks if the required size of @box and its children fit into @avail_size
890  * in @box's opposing orientation if @box were given @check_size as an allocation
891  * in @box's orientation.
892  *
893  * In context: A GtkVBox will check if it fits into the available allocated height
894  * if it were given the @check_size in width.
895  *
896  */
897 static gboolean
898 size_fits_for_dimension (GtkBox  *box,
899                          gint     avail_size,
900                          gint     check_size,
901                          gboolean check_natural)
902 {
903   GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (box);
904   GList         *children;
905   gint           nvis_children = 0;
906   gint           required_size = 0, child_size;
907   gint           largest_child = 0;
908
909   avail_size -= GTK_CONTAINER (box)->border_width * 2;
910
911   for (children = box->children; children != NULL; 
912        children = children->next, nvis_children++)
913     {
914       GtkBoxChild *child = children->data;
915
916       if (gtk_widget_get_visible (child->widget))
917         {
918
919           if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
920             {
921               if (check_natural)
922                 gtk_extended_layout_get_width_for_height (GTK_EXTENDED_LAYOUT (child->widget),
923                                                           avail_size, NULL, &child_size);
924               else
925                 gtk_extended_layout_get_width_for_height (GTK_EXTENDED_LAYOUT (child->widget),
926                                                           avail_size, &child_size, NULL);
927             }
928           else
929             {
930               if (check_natural)
931                 gtk_extended_layout_get_height_for_width (GTK_EXTENDED_LAYOUT (child->widget),
932                                                           avail_size, NULL, &child_size);
933               else
934                 gtk_extended_layout_get_height_for_width (GTK_EXTENDED_LAYOUT (child->widget),
935                                                           avail_size, &child_size, NULL);
936             }
937
938           child_size += child->padding * 2;
939
940           if (child_size > largest_child)
941             largest_child = child_size;
942
943           required_size += child_size;
944         }
945     }
946
947   if (nvis_children > 0)
948     {
949       if (box->homogeneous)
950         required_size = largest_child * nvis_children;
951
952       required_size += (nvis_children - 1) * box->spacing;
953     }
954
955   required_size += GTK_CONTAINER (box)->border_width * 2;
956
957   return required_size <= check_size;
958 }
959
960
961 static void 
962 gtk_box_bisect_for_size_in_opposing_orientation (GtkBox   *box,
963                                                  gboolean  check_natural,
964                                                  gint      avail_size,
965                                                  gint      floor,
966                                                  gint      ceiling,
967                                                  gint     *size)
968 {
969   if (ceiling - floor <= 1)
970     *size = ceiling;
971   else
972     {
973       gint check_size = floor + (ceiling - floor) / 2;
974
975       if (size_fits_for_dimension (box, avail_size, check_size, check_natural))
976
977         /* If check_size is large enough for box to fit into avail_size, we go on
978          * to check between the given floor and check_size as the new ceiling
979          */
980
981         gtk_box_bisect_for_size_in_opposing_orientation (box, check_natural, avail_size,
982                                                          floor, check_size, size);
983       else
984         gtk_box_bisect_for_size_in_opposing_orientation (box, check_natural, avail_size,
985                                                          check_size, ceiling, size);
986
987     }
988 }
989
990 static void 
991 gtk_box_compute_size_for_opposing_orientation (GtkBox *box,
992                                                gint    avail_size,
993                                                gint   *minimum_size,
994                                                gint   *natural_size)
995 {
996   gint minimum, natural;
997   gint min_ceiling, nat_ceiling;
998   gint step = 200;
999
1000   /* First a large gap to search inside of
1001    */
1002   for (min_ceiling = (step + 1); !size_fits_for_dimension (box, avail_size, min_ceiling, FALSE); min_ceiling += step);
1003
1004   /* This will find the minimum sizes by halfing the guesses until they are found
1005    */
1006   gtk_box_bisect_for_size_in_opposing_orientation (box, FALSE, avail_size,
1007                                                    min_ceiling - step,
1008                                                    min_ceiling,
1009                                                    &minimum);
1010
1011   /* Basing the natural size on the found minimum, do the same operation for the natural size */
1012   for (nat_ceiling = minimum + step; !size_fits_for_dimension (box, avail_size, nat_ceiling, TRUE); nat_ceiling += step);
1013   gtk_box_bisect_for_size_in_opposing_orientation (box, TRUE, avail_size,
1014                                                    nat_ceiling - step,
1015                                                    nat_ceiling,
1016                                                    &natural);
1017
1018   if (minimum_size)
1019     *minimum_size = minimum;
1020
1021   if (natural_size)
1022     *natural_size = natural;
1023
1024 }  
1025
1026 static void 
1027 gtk_box_compute_size_for_orientation (GtkBox *box,
1028                                       gint    avail_size,
1029                                       gint   *minimum_size,
1030                                       gint   *natural_size)
1031 {
1032   GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (box);
1033   GList         *children;
1034   gint           nvis_children = 0;
1035   gint           required_size = 0, required_natural = 0, child_size, child_natural;
1036   gint           largest_child = 0, largest_natural = 0;
1037
1038   avail_size -= GTK_CONTAINER (box)->border_width * 2;
1039
1040   for (children = box->children; children != NULL; 
1041        children = children->next, nvis_children++)
1042     {
1043       GtkBoxChild *child = children->data;
1044
1045       if (gtk_widget_get_visible (child->widget))
1046         {
1047
1048           if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
1049             gtk_extended_layout_get_width_for_height (GTK_EXTENDED_LAYOUT (child->widget),
1050                                                       avail_size, &child_size, &child_natural);
1051           else
1052             gtk_extended_layout_get_height_for_width (GTK_EXTENDED_LAYOUT (child->widget),
1053                                                       avail_size, &child_size, &child_natural);
1054
1055
1056           child_size    += child->padding * 2;
1057           child_natural += child->padding * 2;
1058
1059           if (child_size > largest_child)
1060             largest_child = child_size;
1061
1062           if (child_natural > largest_natural)
1063             largest_natural = child_natural;
1064
1065           required_size    += child_size;
1066           required_natural += child_natural;
1067         }
1068     }
1069
1070   if (nvis_children > 0)
1071     {
1072       if (box->homogeneous)
1073         {
1074           required_size    = largest_child   * nvis_children;
1075           required_natural = largest_natural * nvis_children;
1076         }
1077
1078       required_size     += (nvis_children - 1) * box->spacing;
1079       required_natural  += (nvis_children - 1) * box->spacing;
1080     }
1081
1082   required_size    += GTK_CONTAINER (box)->border_width * 2;
1083   required_natural += GTK_CONTAINER (box)->border_width * 2;
1084
1085   if (minimum_size)
1086     *minimum_size = required_size;
1087
1088   if (natural_size)
1089     *natural_size = required_natural;
1090 }
1091
1092 static void 
1093 gtk_box_get_width_for_height (GtkExtendedLayout *layout,
1094                               gint               height,
1095                               gint              *minimum_width,
1096                               gint              *natural_width)
1097 {
1098   GtkBox        *box     = GTK_BOX (layout);
1099   GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (layout);
1100
1101   if (private->orientation == GTK_ORIENTATION_VERTICAL)
1102     {
1103 #if 0
1104     gtk_box_compute_size_for_opposing_orientation (box, height, minimum_width, natural_width); 
1105 #else
1106     /* Have the base class return the values previously computed by get_desired_size() */  
1107     parent_extended_layout_iface->get_width_for_height (layout, height, minimum_width, natural_width);
1108 #endif
1109     }
1110   else
1111     gtk_box_compute_size_for_orientation (box, height, minimum_width, natural_width);
1112 }
1113
1114 static void 
1115 gtk_box_get_height_for_width (GtkExtendedLayout *layout,
1116                               gint               width,
1117                               gint              *minimum_height,
1118                               gint              *natural_height)
1119 {
1120   GtkBox        *box     = GTK_BOX (layout);
1121   GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (layout);
1122
1123   if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
1124     {
1125 #if 0
1126       gtk_box_compute_size_for_opposing_orientation (box, width, minimum_height, natural_height);
1127 #else
1128       /* Have the base class return the values previously computed by get_desired_size() */
1129       parent_extended_layout_iface->get_height_for_width (layout, width, minimum_height, natural_height);
1130 #endif
1131     }
1132   else
1133     gtk_box_compute_size_for_orientation (box, width, minimum_height, natural_height);
1134 }
1135
1136 /**
1137  * gtk_box_new:
1138  * @orientation: the box' orientation.
1139  * @homogeneous: %TRUE if all children are to be given equal space allocations.
1140  * @spacing: the number of pixels to place by default between children.
1141  *
1142  * Creates a new #GtkHBox.
1143  *
1144  * Return value: a new #GtkHBox.
1145  *
1146  * Since: 2.16
1147  **/
1148 GtkWidget*
1149 _gtk_box_new (GtkOrientation orientation,
1150               gboolean       homogeneous,
1151               gint           spacing)
1152 {
1153   return g_object_new (GTK_TYPE_BOX,
1154                        "orientation", orientation,
1155                        "spacing",     spacing,
1156                        "homogeneous", homogeneous ? TRUE : FALSE,
1157                        NULL);
1158 }
1159
1160 /**
1161  * gtk_box_pack_start:
1162  * @box: a #GtkBox
1163  * @child: the #GtkWidget to be added to @box
1164  * @expand: %TRUE if the new child is to be given extra space allocated to
1165  * @box.  The extra space will be divided evenly between all children of
1166  * @box that use this option
1167  * @fill: %TRUE if space given to @child by the @expand option is
1168  *   actually allocated to @child, rather than just padding it.  This
1169  *   parameter has no effect if @expand is set to %FALSE.  A child is
1170  *   always allocated the full height of a #GtkHBox and the full width 
1171  *   of a #GtkVBox. This option affects the other dimension
1172  * @padding: extra space in pixels to put between this child and its
1173  *   neighbors, over and above the global amount specified by
1174  *   #GtkBox:spacing property.  If @child is a widget at one of the 
1175  *   reference ends of @box, then @padding pixels are also put between 
1176  *   @child and the reference edge of @box
1177  *
1178  * Adds @child to @box, packed with reference to the start of @box.
1179  * The @child is packed after any other child packed with reference 
1180  * to the start of @box.
1181  */
1182 void
1183 gtk_box_pack_start (GtkBox    *box,
1184                     GtkWidget *child,
1185                     gboolean   expand,
1186                     gboolean   fill,
1187                     guint      padding)
1188 {
1189   gtk_box_pack (box, child, expand, fill, padding, GTK_PACK_START);
1190 }
1191
1192 /**
1193  * gtk_box_pack_end:
1194  * @box: a #GtkBox
1195  * @child: the #GtkWidget to be added to @box
1196  * @expand: %TRUE if the new child is to be given extra space allocated 
1197  *   to @box. The extra space will be divided evenly between all children 
1198  *   of @box that use this option
1199  * @fill: %TRUE if space given to @child by the @expand option is
1200  *   actually allocated to @child, rather than just padding it.  This
1201  *   parameter has no effect if @expand is set to %FALSE.  A child is
1202  *   always allocated the full height of a #GtkHBox and the full width 
1203  *   of a #GtkVBox.  This option affects the other dimension
1204  * @padding: extra space in pixels to put between this child and its
1205  *   neighbors, over and above the global amount specified by
1206  *   #GtkBox:spacing property.  If @child is a widget at one of the 
1207  *   reference ends of @box, then @padding pixels are also put between 
1208  *   @child and the reference edge of @box
1209  *
1210  * Adds @child to @box, packed with reference to the end of @box.  
1211  * The @child is packed after (away from end of) any other child 
1212  * packed with reference to the end of @box.
1213  */
1214 void
1215 gtk_box_pack_end (GtkBox    *box,
1216                   GtkWidget *child,
1217                   gboolean   expand,
1218                   gboolean   fill,
1219                   guint      padding)
1220 {
1221   gtk_box_pack (box, child, expand, fill, padding, GTK_PACK_END);
1222 }
1223
1224 /**
1225  * gtk_box_pack_start_defaults:
1226  * @box: a #GtkBox
1227  * @widget: the #GtkWidget to be added to @box
1228  *
1229  * Adds @widget to @box, packed with reference to the start of @box.
1230  * The child is packed after any other child packed with reference 
1231  * to the start of @box. 
1232  * 
1233  * Parameters for how to pack the child @widget, #GtkBox:expand, 
1234  * #GtkBox:fill and #GtkBox:padding, are given their default
1235  * values, %TRUE, %TRUE, and 0, respectively.
1236  *
1237  * Deprecated: 2.14: Use gtk_box_pack_start()
1238  */
1239 void
1240 gtk_box_pack_start_defaults (GtkBox    *box,
1241                              GtkWidget *child)
1242 {
1243   gtk_box_pack_start (box, child, TRUE, TRUE, 0);
1244 }
1245
1246 /**
1247  * gtk_box_pack_end_defaults:
1248  * @box: a #GtkBox
1249  * @widget: the #GtkWidget to be added to @box
1250  *
1251  * Adds @widget to @box, packed with reference to the end of @box.
1252  * The child is packed after any other child packed with reference 
1253  * to the start of @box. 
1254  * 
1255  * Parameters for how to pack the child @widget, #GtkBox:expand, 
1256  * #GtkBox:fill and #GtkBox:padding, are given their default
1257  * values, %TRUE, %TRUE, and 0, respectively.
1258  *
1259  * Deprecated: 2.14: Use gtk_box_pack_end()
1260  */
1261 void
1262 gtk_box_pack_end_defaults (GtkBox    *box,
1263                            GtkWidget *child)
1264 {
1265   gtk_box_pack_end (box, child, TRUE, TRUE, 0);
1266 }
1267
1268 /**
1269  * gtk_box_set_homogeneous:
1270  * @box: a #GtkBox
1271  * @homogeneous: a boolean value, %TRUE to create equal allotments,
1272  *   %FALSE for variable allotments
1273  * 
1274  * Sets the #GtkBox:homogeneous property of @box, controlling 
1275  * whether or not all children of @box are given equal space 
1276  * in the box.
1277  */
1278 void
1279 gtk_box_set_homogeneous (GtkBox  *box,
1280                          gboolean homogeneous)
1281 {
1282   g_return_if_fail (GTK_IS_BOX (box));
1283
1284   if ((homogeneous ? TRUE : FALSE) != box->homogeneous)
1285     {
1286       box->homogeneous = homogeneous ? TRUE : FALSE;
1287       g_object_notify (G_OBJECT (box), "homogeneous");
1288       gtk_widget_queue_resize (GTK_WIDGET (box));
1289     }
1290 }
1291
1292 /**
1293  * gtk_box_get_homogeneous:
1294  * @box: a #GtkBox
1295  *
1296  * Returns whether the box is homogeneous (all children are the
1297  * same size). See gtk_box_set_homogeneous().
1298  *
1299  * Return value: %TRUE if the box is homogeneous.
1300  **/
1301 gboolean
1302 gtk_box_get_homogeneous (GtkBox *box)
1303 {
1304   g_return_val_if_fail (GTK_IS_BOX (box), FALSE);
1305
1306   return box->homogeneous;
1307 }
1308
1309 /**
1310  * gtk_box_set_spacing:
1311  * @box: a #GtkBox
1312  * @spacing: the number of pixels to put between children
1313  *
1314  * Sets the #GtkBox:spacing property of @box, which is the 
1315  * number of pixels to place between children of @box.
1316  */
1317 void
1318 gtk_box_set_spacing (GtkBox *box,
1319                      gint    spacing)
1320 {
1321   g_return_if_fail (GTK_IS_BOX (box));
1322
1323   if (spacing != box->spacing)
1324     {
1325       box->spacing = spacing;
1326       _gtk_box_set_spacing_set (box, TRUE);
1327
1328       g_object_notify (G_OBJECT (box), "spacing");
1329
1330       gtk_widget_queue_resize (GTK_WIDGET (box));
1331     }
1332 }
1333
1334 /**
1335  * gtk_box_get_spacing:
1336  * @box: a #GtkBox
1337  * 
1338  * Gets the value set by gtk_box_set_spacing().
1339  * 
1340  * Return value: spacing between children
1341  **/
1342 gint
1343 gtk_box_get_spacing (GtkBox *box)
1344 {
1345   g_return_val_if_fail (GTK_IS_BOX (box), 0);
1346
1347   return box->spacing;
1348 }
1349
1350 void
1351 _gtk_box_set_spacing_set (GtkBox  *box,
1352                           gboolean spacing_set)
1353 {
1354   GtkBoxPrivate *private;
1355
1356   g_return_if_fail (GTK_IS_BOX (box));
1357
1358   private = GTK_BOX_GET_PRIVATE (box);
1359
1360   private->spacing_set = spacing_set ? TRUE : FALSE;
1361 }
1362
1363 gboolean
1364 _gtk_box_get_spacing_set (GtkBox *box)
1365 {
1366   GtkBoxPrivate *private;
1367
1368   g_return_val_if_fail (GTK_IS_BOX (box), FALSE);
1369
1370   private = GTK_BOX_GET_PRIVATE (box);
1371
1372   return private->spacing_set;
1373 }
1374
1375 /**
1376  * gtk_box_reorder_child:
1377  * @box: a #GtkBox
1378  * @child: the #GtkWidget to move
1379  * @position: the new position for @child in the list of children 
1380  *   of @box, starting from 0. If negative, indicates the end of 
1381  *   the list
1382  *
1383  * Moves @child to a new @position in the list of @box children.  
1384  * The list is the <structfield>children</structfield> field of
1385  * #GtkBox-struct, and contains both widgets packed #GTK_PACK_START 
1386  * as well as widgets packed #GTK_PACK_END, in the order that these 
1387  * widgets were added to @box.
1388  * 
1389  * A widget's position in the @box children list determines where 
1390  * the widget is packed into @box.  A child widget at some position 
1391  * in the list will be packed just after all other widgets of the 
1392  * same packing type that appear earlier in the list.
1393  */ 
1394 void
1395 gtk_box_reorder_child (GtkBox    *box,
1396                        GtkWidget *child,
1397                        gint       position)
1398 {
1399   GList *old_link;
1400   GList *new_link;
1401   GtkBoxChild *child_info = NULL;
1402   gint old_position;
1403
1404   g_return_if_fail (GTK_IS_BOX (box));
1405   g_return_if_fail (GTK_IS_WIDGET (child));
1406
1407   old_link = box->children;
1408   old_position = 0;
1409   while (old_link)
1410     {
1411       child_info = old_link->data;
1412       if (child_info->widget == child)
1413         break;
1414
1415       old_link = old_link->next;
1416       old_position++;
1417     }
1418
1419   g_return_if_fail (old_link != NULL);
1420
1421   if (position == old_position)
1422     return;
1423
1424   box->children = g_list_delete_link (box->children, old_link);
1425
1426   if (position < 0)
1427     new_link = NULL;
1428   else
1429     new_link = g_list_nth (box->children, position);
1430
1431   box->children = g_list_insert_before (box->children, new_link, child_info);
1432
1433   gtk_widget_child_notify (child, "position");
1434   if (gtk_widget_get_visible (child)
1435       && gtk_widget_get_visible (GTK_WIDGET (box)))
1436     gtk_widget_queue_resize (child);
1437 }
1438
1439 /**
1440  * gtk_box_query_child_packing:
1441  * @box: a #GtkBox
1442  * @child: the #GtkWidget of the child to query
1443  * @expand: pointer to return location for #GtkBox:expand child property 
1444  * @fill: pointer to return location for #GtkBox:fill child property 
1445  * @padding: pointer to return location for #GtkBox:padding child property 
1446  * @pack_type: pointer to return location for #GtkBox:pack-type child property 
1447  * 
1448  * Obtains information about how @child is packed into @box.
1449  */
1450 void
1451 gtk_box_query_child_packing (GtkBox      *box,
1452                              GtkWidget   *child,
1453                              gboolean    *expand,
1454                              gboolean    *fill,
1455                              guint       *padding,
1456                              GtkPackType *pack_type)
1457 {
1458   GList *list;
1459   GtkBoxChild *child_info = NULL;
1460
1461   g_return_if_fail (GTK_IS_BOX (box));
1462   g_return_if_fail (GTK_IS_WIDGET (child));
1463
1464   list = box->children;
1465   while (list)
1466     {
1467       child_info = list->data;
1468       if (child_info->widget == child)
1469         break;
1470
1471       list = list->next;
1472     }
1473
1474   if (list)
1475     {
1476       if (expand)
1477         *expand = child_info->expand;
1478       if (fill)
1479         *fill = child_info->fill;
1480       if (padding)
1481         *padding = child_info->padding;
1482       if (pack_type)
1483         *pack_type = child_info->pack;
1484     }
1485 }
1486
1487 /**
1488  * gtk_box_set_child_packing:
1489  * @box: a #GtkBox
1490  * @child: the #GtkWidget of the child to set
1491  * @expand: the new value of the #GtkBox:expand child property 
1492  * @fill: the new value of the #GtkBox:fill child property
1493  * @padding: the new value of the #GtkBox:padding child property
1494  * @pack_type: the new value of the #GtkBox:pack-type child property
1495  *
1496  * Sets the way @child is packed into @box.
1497  */
1498 void
1499 gtk_box_set_child_packing (GtkBox      *box,
1500                            GtkWidget   *child,
1501                            gboolean     expand,
1502                            gboolean     fill,
1503                            guint        padding,
1504                            GtkPackType  pack_type)
1505 {
1506   GList *list;
1507   GtkBoxChild *child_info = NULL;
1508
1509   g_return_if_fail (GTK_IS_BOX (box));
1510   g_return_if_fail (GTK_IS_WIDGET (child));
1511
1512   list = box->children;
1513   while (list)
1514     {
1515       child_info = list->data;
1516       if (child_info->widget == child)
1517         break;
1518
1519       list = list->next;
1520     }
1521
1522   gtk_widget_freeze_child_notify (child);
1523   if (list)
1524     {
1525       child_info->expand = expand != FALSE;
1526       gtk_widget_child_notify (child, "expand");
1527       child_info->fill = fill != FALSE;
1528       gtk_widget_child_notify (child, "fill");
1529       child_info->padding = padding;
1530       gtk_widget_child_notify (child, "padding");
1531       if (pack_type == GTK_PACK_END)
1532         child_info->pack = GTK_PACK_END;
1533       else
1534         child_info->pack = GTK_PACK_START;
1535       gtk_widget_child_notify (child, "pack-type");
1536
1537       if (gtk_widget_get_visible (child)
1538           && gtk_widget_get_visible (GTK_WIDGET (box)))
1539         gtk_widget_queue_resize (child);
1540     }
1541   gtk_widget_thaw_child_notify (child);
1542 }
1543
1544 void
1545 _gtk_box_set_old_defaults (GtkBox *box)
1546 {
1547   GtkBoxPrivate *private;
1548
1549   g_return_if_fail (GTK_IS_BOX (box));
1550
1551   private = GTK_BOX_GET_PRIVATE (box);
1552
1553   private->default_expand = TRUE;
1554 }
1555
1556 static void
1557 gtk_box_add (GtkContainer *container,
1558              GtkWidget    *widget)
1559 {
1560   GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (container);
1561
1562   gtk_box_pack_start (GTK_BOX (container), widget,
1563                       private->default_expand,
1564                       private->default_expand,
1565                       0);
1566 }
1567
1568 static void
1569 gtk_box_remove (GtkContainer *container,
1570                 GtkWidget    *widget)
1571 {
1572   GtkBox *box = GTK_BOX (container);
1573   GtkBoxChild *child;
1574   GList *children;
1575
1576   children = box->children;
1577   while (children)
1578     {
1579       child = children->data;
1580
1581       if (child->widget == widget)
1582         {
1583           gboolean was_visible;
1584
1585           was_visible = gtk_widget_get_visible (widget);
1586           gtk_widget_unparent (widget);
1587
1588           box->children = g_list_remove_link (box->children, children);
1589           g_list_free (children);
1590           g_free (child);
1591
1592           /* queue resize regardless of gtk_widget_get_visible (container),
1593            * since that's what is needed by toplevels.
1594            */
1595           if (was_visible)
1596             gtk_widget_queue_resize (GTK_WIDGET (container));
1597
1598           break;
1599         }
1600
1601       children = children->next;
1602     }
1603 }
1604
1605 static void
1606 gtk_box_forall (GtkContainer *container,
1607                 gboolean      include_internals,
1608                 GtkCallback   callback,
1609                 gpointer      callback_data)
1610 {
1611   GtkBox *box = GTK_BOX (container);
1612   GtkBoxChild *child;
1613   GList *children;
1614
1615   children = box->children;
1616   while (children)
1617     {
1618       child = children->data;
1619       children = children->next;
1620
1621       if (child->pack == GTK_PACK_START)
1622         (* callback) (child->widget, callback_data);
1623     }
1624
1625   children = g_list_last (box->children);
1626   while (children)
1627     {
1628       child = children->data;
1629       children = children->prev;
1630
1631       if (child->pack == GTK_PACK_END)
1632         (* callback) (child->widget, callback_data);
1633     }
1634 }
1635
1636 #define __GTK_BOX_C__
1637 #include "gtkaliasdef.c"