Initial packaging to sync OBS with git/gerrit
[profile/ivi/gtk3.git] / 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, see <http://www.gnu.org/licenses/>.
16  */
17
18 /*
19  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20  * file for a list of people on the GTK+ Team.  See the ChangeLog
21  * files for a list of changes.  These files are distributed with
22  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23  */
24
25 /**
26  * SECTION:gtkbox
27  * @Short_description: A container box
28  * @Title: GtkBox
29  * @See_also: #GtkFrame, #GtkGrid, #GtkLayout
30  *
31  * The GtkBox widget organizes child widgets into a rectangular area.
32  *
33  * The rectangular area of a GtkBox is organized into either a single row
34  * or a single column of child widgets depending upon the orientation.
35  * Thus, all children of a GtkBox are allocated one dimension in common,
36  * which is the height of a row, or the width of a column.
37  *
38  * GtkBox uses a notion of <emphasis>packing</emphasis>. Packing refers
39  * to adding widgets with reference to a particular position in a
40  * #GtkContainer. For a GtkBox, there are two reference positions: the
41  * <emphasis>start</emphasis> and the <emphasis>end</emphasis> of the box.
42  * For a vertical #GtkBox, the start is defined as the top of the box and
43  * the end is defined as the bottom. For a horizontal #GtkBox the start
44  * is defined as the left side and the end is defined as the right side.
45  *
46  * Use repeated calls to gtk_box_pack_start() to pack widgets into a
47  * GtkBox from start to end. Use gtk_box_pack_end() to add widgets from
48  * end to start. You may intersperse these calls and add widgets from
49  * both ends of the same GtkBox.
50  *
51  * Because GtkBox is a #GtkContainer, you may also use gtk_container_add()
52  * to insert widgets into the box, and they will be packed with the default
53  * values for #GtkBox:expand and #GtkBox:fill. Use gtk_container_remove()
54  * to remove widgets from the GtkBox.
55  *
56  * Use gtk_box_set_homogeneous() to specify whether or not all children
57  * of the GtkBox are forced to get the same amount of space.
58  *
59  * Use gtk_box_set_spacing() to determine how much space will be
60  * minimally placed between all children in the GtkBox. Note that
61  * spacing is added <emphasis>between</emphasis> the children, while
62  * padding added by gtk_box_pack_start() or gtk_box_pack_end() is added
63  * <emphasis>on either side</emphasis> of the widget it belongs to.
64  *
65  * Use gtk_box_reorder_child() to move a GtkBox child to a different
66  * place in the box.
67  *
68  * Use gtk_box_set_child_packing() to reset the #GtkBox:expand,
69  * #GtkBox:fill and #GtkBox:padding child properties.
70  * Use gtk_box_query_child_packing() to query these fields.
71  *
72  * <note><para>
73  * Note that a single-row or single-column #GtkGrid provides exactly
74  * the same functionality as #GtkBox.
75  * </para></note>
76  */
77
78 #include "config.h"
79
80 #include "gtkbox.h"
81 #include "gtkboxprivate.h"
82 #include "gtkintl.h"
83 #include "gtkorientable.h"
84 #include "gtkprivate.h"
85 #include "gtktypebuiltins.h"
86 #include "gtksizerequest.h"
87 #include "gtkwidgetpath.h"
88 #include "a11y/gtkboxaccessible.h"
89
90
91 enum {
92   PROP_0,
93   PROP_ORIENTATION,
94   PROP_SPACING,
95   PROP_HOMOGENEOUS
96 };
97
98 enum {
99   CHILD_PROP_0,
100   CHILD_PROP_EXPAND,
101   CHILD_PROP_FILL,
102   CHILD_PROP_PADDING,
103   CHILD_PROP_PACK_TYPE,
104   CHILD_PROP_POSITION
105 };
106
107 struct _GtkBoxPrivate
108 {
109   GList          *children;
110
111   GtkOrientation  orientation;
112   gint16          spacing;
113
114   guint           default_expand : 1;
115   guint           homogeneous    : 1;
116   guint           spacing_set    : 1;
117 };
118
119 typedef struct _GtkBoxChild        GtkBoxChild;
120
121 /*
122  * GtkBoxChild:
123  * @widget: the child widget, packed into the GtkBox.
124  * @padding: the number of extra pixels to put between this child and its
125  *  neighbors, set when packed, zero by default.
126  * @expand: flag indicates whether extra space should be given to this child.
127  *  Any extra space given to the parent GtkBox is divided up among all children
128  *  with this attribute set to %TRUE; set when packed, %TRUE by default.
129  * @fill: flag indicates whether any extra space given to this child due to its
130  *  @expand attribute being set is actually allocated to the child, rather than
131  *  being used as padding around the widget; set when packed, %TRUE by default.
132  * @pack: one of #GtkPackType indicating whether the child is packed with
133  *  reference to the start (top/left) or end (bottom/right) of the GtkBox.
134  */
135 struct _GtkBoxChild
136 {
137   GtkWidget *widget;
138
139   guint16    padding;
140
141   guint      expand : 1;
142   guint      fill   : 1;
143   guint      pack   : 1;
144 };
145
146 static void gtk_box_size_allocate         (GtkWidget              *widget,
147                                            GtkAllocation          *allocation);
148
149 static void gtk_box_compute_expand     (GtkWidget      *widget,
150                                         gboolean       *hexpand,
151                                         gboolean       *vexpand);
152 static void gtk_box_direction_changed  (GtkWidget        *widget,
153                                         GtkTextDirection  previous_direction);
154
155 static void gtk_box_set_property       (GObject        *object,
156                                         guint           prop_id,
157                                         const GValue   *value,
158                                         GParamSpec     *pspec);
159 static void gtk_box_get_property       (GObject        *object,
160                                         guint           prop_id,
161                                         GValue         *value,
162                                         GParamSpec     *pspec);
163 static void gtk_box_add                (GtkContainer   *container,
164                                         GtkWidget      *widget);
165 static void gtk_box_remove             (GtkContainer   *container,
166                                         GtkWidget      *widget);
167 static void gtk_box_forall             (GtkContainer   *container,
168                                         gboolean        include_internals,
169                                         GtkCallback     callback,
170                                         gpointer        callback_data);
171 static void gtk_box_set_child_property (GtkContainer   *container,
172                                         GtkWidget      *child,
173                                         guint           property_id,
174                                         const GValue   *value,
175                                         GParamSpec     *pspec);
176 static void gtk_box_get_child_property (GtkContainer   *container,
177                                         GtkWidget      *child,
178                                         guint           property_id,
179                                         GValue         *value,
180                                         GParamSpec     *pspec);
181 static GType gtk_box_child_type        (GtkContainer   *container);
182 static GtkWidgetPath * gtk_box_get_path_for_child
183                                        (GtkContainer   *container,
184                                         GtkWidget      *child);
185
186
187 static void               gtk_box_get_preferred_width            (GtkWidget           *widget,
188                                                                   gint                *minimum_size,
189                                                                   gint                *natural_size);
190 static void               gtk_box_get_preferred_height           (GtkWidget           *widget,
191                                                                   gint                *minimum_size,
192                                                                   gint                *natural_size);
193 static void               gtk_box_get_preferred_width_for_height (GtkWidget           *widget,
194                                                                   gint                 height,
195                                                                   gint                *minimum_width,
196                                                                   gint                *natural_width);
197 static void               gtk_box_get_preferred_height_for_width (GtkWidget           *widget,
198                                                                   gint                 width,
199                                                                   gint                *minimum_height,
200                                                                   gint                *natural_height);
201
202
203 G_DEFINE_TYPE_WITH_CODE (GtkBox, gtk_box, GTK_TYPE_CONTAINER,
204                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
205                                                 NULL))
206
207 static void
208 gtk_box_class_init (GtkBoxClass *class)
209 {
210   GObjectClass *object_class = G_OBJECT_CLASS (class);
211   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
212   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
213
214   object_class->set_property = gtk_box_set_property;
215   object_class->get_property = gtk_box_get_property;
216
217   widget_class->size_allocate                  = gtk_box_size_allocate;
218   widget_class->get_preferred_width            = gtk_box_get_preferred_width;
219   widget_class->get_preferred_height           = gtk_box_get_preferred_height;
220   widget_class->get_preferred_height_for_width = gtk_box_get_preferred_height_for_width;
221   widget_class->get_preferred_width_for_height = gtk_box_get_preferred_width_for_height;
222   widget_class->compute_expand                 = gtk_box_compute_expand;
223   widget_class->direction_changed              = gtk_box_direction_changed;
224
225   container_class->add = gtk_box_add;
226   container_class->remove = gtk_box_remove;
227   container_class->forall = gtk_box_forall;
228   container_class->child_type = gtk_box_child_type;
229   container_class->set_child_property = gtk_box_set_child_property;
230   container_class->get_child_property = gtk_box_get_child_property;
231   container_class->get_path_for_child = gtk_box_get_path_for_child;
232   gtk_container_class_handle_border_width (container_class);
233
234   g_object_class_override_property (object_class,
235                                     PROP_ORIENTATION,
236                                     "orientation");
237
238   g_object_class_install_property (object_class,
239                                    PROP_SPACING,
240                                    g_param_spec_int ("spacing",
241                                                      P_("Spacing"),
242                                                      P_("The amount of space between children"),
243                                                      0,
244                                                      G_MAXINT,
245                                                      0,
246                                                      GTK_PARAM_READWRITE));
247
248   g_object_class_install_property (object_class,
249                                    PROP_HOMOGENEOUS,
250                                    g_param_spec_boolean ("homogeneous",
251                                                          P_("Homogeneous"),
252                                                          P_("Whether the children should all be the same size"),
253                                                          FALSE,
254                                                          GTK_PARAM_READWRITE));
255
256   /**
257    * GtkBox:expand:
258    *
259    * Whether the child should receive extra space when the parent grows.
260    *
261    * Note that the default value for this property is %FALSE for GtkBox,
262    * but #GtkHBox, #GtkVBox and other subclasses use the old default
263    * of %TRUE.
264    *
265    * Note that the #GtkWidget:halign, #GtkWidget:valign, #GtkWidget:hexpand
266    * and #GtkWidget:vexpand properties are the preferred way to influence
267    * child size allocation in containers.
268    */
269   gtk_container_class_install_child_property (container_class,
270                                               CHILD_PROP_EXPAND,
271                                               g_param_spec_boolean ("expand",
272                                                                     P_("Expand"),
273                                                                     P_("Whether the child should receive extra space when the parent grows"),
274                                                                     FALSE,
275                                                                     GTK_PARAM_READWRITE));
276
277   /**
278    * GtkBox:fill:
279    *
280    * Whether the child should receive extra space when the parent grows.
281    *
282    * Note that the #GtkWidget:halign, #GtkWidget:valign, #GtkWidget:hexpand
283    * and #GtkWidget:vexpand properties are the preferred way to influence
284    * child size allocation in containers.
285    */
286   gtk_container_class_install_child_property (container_class,
287                                               CHILD_PROP_FILL,
288                                               g_param_spec_boolean ("fill",
289                                                                     P_("Fill"),
290                                                                     P_("Whether extra space given to the child should be allocated to the child or used as padding"),
291                                                                     TRUE,
292                                                                     GTK_PARAM_READWRITE));
293
294   gtk_container_class_install_child_property (container_class,
295                                               CHILD_PROP_PADDING,
296                                               g_param_spec_uint ("padding",
297                                                                  P_("Padding"),
298                                                                  P_("Extra space to put between the child and its neighbors, in pixels"),
299                                                                  0, G_MAXINT, 0,
300                                                                  GTK_PARAM_READWRITE));
301   gtk_container_class_install_child_property (container_class,
302                                               CHILD_PROP_PACK_TYPE,
303                                               g_param_spec_enum ("pack-type",
304                                                                  P_("Pack type"),
305                                                                  P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
306                                                                  GTK_TYPE_PACK_TYPE, GTK_PACK_START,
307                                                                  GTK_PARAM_READWRITE));
308   gtk_container_class_install_child_property (container_class,
309                                               CHILD_PROP_POSITION,
310                                               g_param_spec_int ("position",
311                                                                 P_("Position"),
312                                                                 P_("The index of the child in the parent"),
313                                                                 -1, G_MAXINT, 0,
314                                                                 GTK_PARAM_READWRITE));
315
316   g_type_class_add_private (object_class, sizeof (GtkBoxPrivate));
317
318   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_BOX_ACCESSIBLE);
319 }
320
321 static void
322 gtk_box_init (GtkBox *box)
323 {
324   GtkBoxPrivate *private;
325
326   box->priv = G_TYPE_INSTANCE_GET_PRIVATE (box,
327                                            GTK_TYPE_BOX,
328                                            GtkBoxPrivate);
329   private = box->priv;
330
331   gtk_widget_set_has_window (GTK_WIDGET (box), FALSE);
332   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (box), FALSE);
333
334   private->orientation = GTK_ORIENTATION_HORIZONTAL;
335   private->children = NULL;
336
337   private->default_expand = FALSE;
338   private->homogeneous = FALSE;
339   private->spacing = 0;
340   private->spacing_set = FALSE;
341 }
342
343 static void
344 gtk_box_set_property (GObject      *object,
345                       guint         prop_id,
346                       const GValue *value,
347                       GParamSpec   *pspec)
348 {
349   GtkBox *box = GTK_BOX (object);
350   GtkBoxPrivate *private = box->priv;
351
352   switch (prop_id)
353     {
354     case PROP_ORIENTATION:
355       private->orientation = g_value_get_enum (value);
356       gtk_widget_queue_resize (GTK_WIDGET (box));
357       break;
358     case PROP_SPACING:
359       gtk_box_set_spacing (box, g_value_get_int (value));
360       break;
361     case PROP_HOMOGENEOUS:
362       gtk_box_set_homogeneous (box, g_value_get_boolean (value));
363       break;
364     default:
365       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
366       break;
367     }
368 }
369
370 static void
371 gtk_box_get_property (GObject    *object,
372                       guint       prop_id,
373                       GValue     *value,
374                       GParamSpec *pspec)
375 {
376   GtkBox *box = GTK_BOX (object);
377   GtkBoxPrivate *private = box->priv;
378
379   switch (prop_id)
380     {
381     case PROP_ORIENTATION:
382       g_value_set_enum (value, private->orientation);
383       break;
384     case PROP_SPACING:
385       g_value_set_int (value, private->spacing);
386       break;
387     case PROP_HOMOGENEOUS:
388       g_value_set_boolean (value, private->homogeneous);
389       break;
390     default:
391       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
392       break;
393     }
394 }
395
396
397 static void
398 count_expand_children (GtkBox *box,
399                        gint *visible_children,
400                        gint *expand_children)
401 {
402   GtkBoxPrivate  *private = box->priv;
403   GList       *children;
404   GtkBoxChild *child;
405
406   *visible_children = *expand_children = 0;
407
408   for (children = private->children; children; children = children->next)
409     {
410       child = children->data;
411
412       if (gtk_widget_get_visible (child->widget))
413         {
414           *visible_children += 1;
415           if (child->expand || gtk_widget_compute_expand (child->widget, private->orientation))
416             *expand_children += 1;
417         }
418     }
419 }
420
421 static void
422 gtk_box_size_allocate (GtkWidget     *widget,
423                        GtkAllocation *allocation)
424 {
425   GtkBox *box = GTK_BOX (widget);
426   GtkBoxPrivate *private = box->priv;
427   GtkBoxChild *child;
428   GList *children;
429   gint nvis_children;
430   gint nexpand_children;
431
432   GtkTextDirection direction;
433   GtkAllocation child_allocation;
434   GtkRequestedSize *sizes;
435
436   GtkPackType packing;
437
438   gint size;
439   gint extra;
440   gint n_extra_widgets = 0; /* Number of widgets that receive 1 extra px */
441   gint x = 0, y = 0, i;
442   gint child_size;
443
444
445   gtk_widget_set_allocation (widget, allocation);
446
447   count_expand_children (box, &nvis_children, &nexpand_children);
448
449   /* If there is no visible child, simply return. */
450   if (nvis_children <= 0)
451     return;
452
453   direction = gtk_widget_get_direction (widget);
454   sizes = g_newa (GtkRequestedSize, nvis_children);
455
456   if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
457     size = allocation->width - (nvis_children - 1) * private->spacing;
458   else
459     size = allocation->height - (nvis_children - 1) * private->spacing;
460
461   /* Retrieve desired size for visible children. */
462   for (i = 0, children = private->children; children; children = children->next)
463     {
464       child = children->data;
465
466       if (!gtk_widget_get_visible (child->widget))
467         continue;
468
469       if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
470         gtk_widget_get_preferred_width_for_height (child->widget,
471                                                    allocation->height,
472                                                    &sizes[i].minimum_size,
473                                                    &sizes[i].natural_size);
474       else
475         gtk_widget_get_preferred_height_for_width (child->widget,
476                                                    allocation->width,
477                                                    &sizes[i].minimum_size,
478                                                    &sizes[i].natural_size);
479
480
481       /* Assert the api is working properly */
482       if (sizes[i].minimum_size < 0)
483         g_error ("GtkBox child %s minimum %s: %d < 0 for %s %d",
484                  gtk_widget_get_name (GTK_WIDGET (child->widget)),
485                  (private->orientation == GTK_ORIENTATION_HORIZONTAL) ? "width" : "height",
486                  sizes[i].minimum_size,
487                  (private->orientation == GTK_ORIENTATION_HORIZONTAL) ? "height" : "width",
488                  (private->orientation == GTK_ORIENTATION_HORIZONTAL) ? allocation->height : allocation->width);
489
490       if (sizes[i].natural_size < sizes[i].minimum_size)
491         g_error ("GtkBox child %s natural %s: %d < minimum %d for %s %d",
492                  gtk_widget_get_name (GTK_WIDGET (child->widget)),
493                  (private->orientation == GTK_ORIENTATION_HORIZONTAL) ? "width" : "height",
494                  sizes[i].natural_size,
495                  sizes[i].minimum_size,
496                  (private->orientation == GTK_ORIENTATION_HORIZONTAL) ? "height" : "width",
497                  (private->orientation == GTK_ORIENTATION_HORIZONTAL) ? allocation->height : allocation->width);
498
499       size -= sizes[i].minimum_size;
500       size -= child->padding * 2;
501
502       sizes[i].data = child;
503
504       i++;
505     }
506
507   if (private->homogeneous)
508     {
509       /* If were homogenous we still need to run the above loop to get the
510        * minimum sizes for children that are not going to fill
511        */
512       if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
513         size = allocation->width - (nvis_children - 1) * private->spacing;
514       else
515         size = allocation->height - (nvis_children - 1) * private->spacing;
516
517       extra = size / nvis_children;
518       n_extra_widgets = size % nvis_children;
519     }
520   else
521     {
522       /* Bring children up to size first */
523       size = gtk_distribute_natural_allocation (MAX (0, size), nvis_children, sizes);
524
525       /* Calculate space which hasn't distributed yet,
526        * and is available for expanding children.
527        */
528       if (nexpand_children > 0)
529         {
530           extra = size / nexpand_children;
531           n_extra_widgets = size % nexpand_children;
532         }
533       else
534         extra = 0;
535     }
536
537   /* Allocate child positions. */
538   for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
539     {
540       if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
541         {
542           child_allocation.y = allocation->y;
543           child_allocation.height = MAX (1, allocation->height);
544           if (packing == GTK_PACK_START)
545             x = allocation->x;
546           else
547             x = allocation->x + allocation->width;
548         }
549       else
550         {
551           child_allocation.x = allocation->x;
552           child_allocation.width = MAX (1, allocation->width);
553           if (packing == GTK_PACK_START)
554             y = allocation->y;
555           else
556             y = allocation->y + allocation->height;
557         }
558
559       for (i = 0, children = private->children;
560            children;
561            children = children->next)
562         {
563           child = children->data;
564
565           /* If widget is not visible, skip it. */
566           if (!gtk_widget_get_visible (child->widget))
567             continue;
568
569           /* If widget is packed differently skip it, but still increment i,
570            * since widget is visible and will be handled in next loop iteration.
571            */
572           if (child->pack != packing)
573             {
574               i++;
575               continue;
576             }
577
578           /* Assign the child's size. */
579           if (private->homogeneous)
580             {
581               child_size = extra;
582
583               if (n_extra_widgets > 0)
584                 {
585                   child_size++;
586                   n_extra_widgets--;
587                 }
588             }
589           else
590             {
591               child_size = sizes[i].minimum_size + child->padding * 2;
592
593               if (child->expand || gtk_widget_compute_expand (child->widget, private->orientation))
594                 {
595                   child_size += extra;
596
597                   if (n_extra_widgets > 0)
598                     {
599                       child_size++;
600                       n_extra_widgets--;
601                     }
602                 }
603             }
604
605           /* Assign the child's position. */
606           if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
607             {
608               if (child->fill)
609                 {
610                   child_allocation.width = MAX (1, child_size - child->padding * 2);
611                   child_allocation.x = x + child->padding;
612                 }
613               else
614                 {
615                   child_allocation.width = sizes[i].minimum_size;
616                   child_allocation.x = x + (child_size - child_allocation.width) / 2;
617                 }
618
619               if (packing == GTK_PACK_START)
620                 {
621                   x += child_size + private->spacing;
622                 }
623               else
624                 {
625                   x -= child_size + private->spacing;
626
627                   child_allocation.x -= child_size;
628                 }
629
630               if (direction == GTK_TEXT_DIR_RTL)
631                 child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
632
633             }
634           else /* (private->orientation == GTK_ORIENTATION_VERTICAL) */
635             {
636               if (child->fill)
637                 {
638                   child_allocation.height = MAX (1, child_size - child->padding * 2);
639                   child_allocation.y = y + child->padding;
640                 }
641               else
642                 {
643                   child_allocation.height = sizes[i].minimum_size;
644                   child_allocation.y = y + (child_size - child_allocation.height) / 2;
645                 }
646
647               if (packing == GTK_PACK_START)
648                 {
649                   y += child_size + private->spacing;
650                 }
651               else
652                 {
653                   y -= child_size + private->spacing;
654
655                   child_allocation.y -= child_size;
656                 }
657             }
658           gtk_widget_size_allocate (child->widget, &child_allocation);
659
660           i++;
661         }
662     }
663 }
664
665 static void
666 gtk_box_compute_expand (GtkWidget      *widget,
667                         gboolean       *hexpand_p,
668                         gboolean       *vexpand_p)
669 {
670   GtkBoxPrivate  *private = GTK_BOX (widget)->priv;
671   GList       *children;
672   GtkBoxChild *child;
673   gboolean our_expand;
674   gboolean opposite_expand;
675   GtkOrientation opposite_orientation;
676
677   if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
678     opposite_orientation = GTK_ORIENTATION_VERTICAL;
679   else
680     opposite_orientation = GTK_ORIENTATION_HORIZONTAL;
681
682   our_expand = FALSE;
683   opposite_expand = FALSE;
684
685   for (children = private->children; children; children = children->next)
686     {
687       child = children->data;
688
689       /* we don't recurse into children anymore as soon as we know
690        * expand=TRUE in an orientation
691        */
692
693       if (child->expand || (!our_expand && gtk_widget_compute_expand (child->widget, private->orientation)))
694         our_expand = TRUE;
695
696       if (!opposite_expand && gtk_widget_compute_expand (child->widget, opposite_orientation))
697         opposite_expand = TRUE;
698
699       if (our_expand && opposite_expand)
700         break;
701     }
702
703   if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
704     {
705       *hexpand_p = our_expand;
706       *vexpand_p = opposite_expand;
707     }
708   else
709     {
710       *hexpand_p = opposite_expand;
711       *vexpand_p = our_expand;
712     }
713 }
714
715 static GType
716 gtk_box_child_type (GtkContainer   *container)
717 {
718   return GTK_TYPE_WIDGET;
719 }
720
721 static void
722 gtk_box_set_child_property (GtkContainer *container,
723                             GtkWidget    *child,
724                             guint         property_id,
725                             const GValue *value,
726                             GParamSpec   *pspec)
727 {
728   gboolean expand = 0;
729   gboolean fill = 0;
730   guint padding = 0;
731   GtkPackType pack_type = 0;
732
733   if (property_id != CHILD_PROP_POSITION)
734     gtk_box_query_child_packing (GTK_BOX (container),
735                                  child,
736                                  &expand,
737                                  &fill,
738                                  &padding,
739                                  &pack_type);
740   switch (property_id)
741     {
742     case CHILD_PROP_EXPAND:
743       gtk_box_set_child_packing (GTK_BOX (container),
744                                  child,
745                                  g_value_get_boolean (value),
746                                  fill,
747                                  padding,
748                                  pack_type);
749       break;
750     case CHILD_PROP_FILL:
751       gtk_box_set_child_packing (GTK_BOX (container),
752                                  child,
753                                  expand,
754                                  g_value_get_boolean (value),
755                                  padding,
756                                  pack_type);
757       break;
758     case CHILD_PROP_PADDING:
759       gtk_box_set_child_packing (GTK_BOX (container),
760                                  child,
761                                  expand,
762                                  fill,
763                                  g_value_get_uint (value),
764                                  pack_type);
765       break;
766     case CHILD_PROP_PACK_TYPE:
767       gtk_box_set_child_packing (GTK_BOX (container),
768                                  child,
769                                  expand,
770                                  fill,
771                                  padding,
772                                  g_value_get_enum (value));
773       break;
774     case CHILD_PROP_POSITION:
775       gtk_box_reorder_child (GTK_BOX (container),
776                              child,
777                              g_value_get_int (value));
778       break;
779     default:
780       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
781       break;
782     }
783 }
784
785 static void
786 gtk_box_get_child_property (GtkContainer *container,
787                             GtkWidget    *child,
788                             guint         property_id,
789                             GValue       *value,
790                             GParamSpec   *pspec)
791 {
792   gboolean expand = FALSE;
793   gboolean fill = FALSE;
794   guint padding = 0;
795   GtkPackType pack_type = 0;
796   GList *list;
797
798   if (property_id != CHILD_PROP_POSITION)
799     gtk_box_query_child_packing (GTK_BOX (container),
800                                  child,
801                                  &expand,
802                                  &fill,
803                                  &padding,
804                                  &pack_type);
805   switch (property_id)
806     {
807       guint i;
808     case CHILD_PROP_EXPAND:
809       g_value_set_boolean (value, expand);
810       break;
811     case CHILD_PROP_FILL:
812       g_value_set_boolean (value, fill);
813       break;
814     case CHILD_PROP_PADDING:
815       g_value_set_uint (value, padding);
816       break;
817     case CHILD_PROP_PACK_TYPE:
818       g_value_set_enum (value, pack_type);
819       break;
820     case CHILD_PROP_POSITION:
821       i = 0;
822       for (list = GTK_BOX (container)->priv->children; list; list = list->next)
823         {
824           GtkBoxChild *child_entry;
825
826           child_entry = list->data;
827           if (child_entry->widget == child)
828             break;
829           i++;
830         }
831       g_value_set_int (value, list ? i : -1);
832       break;
833     default:
834       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
835       break;
836     }
837 }
838
839 typedef struct _CountingData CountingData;
840 struct _CountingData {
841   GtkWidget *widget;
842   gboolean found;
843   guint before;
844   guint after;
845 };
846
847 static void
848 count_widget_position (GtkWidget *widget,
849                        gpointer   data)
850 {
851   CountingData *count = data;
852
853   if (!gtk_widget_get_visible (widget))
854     return;
855
856   if (count->widget == widget)
857     count->found = TRUE;
858   else if (count->found)
859     count->after++;
860   else
861     count->before++;
862 }
863
864 static gint
865 gtk_box_get_visible_position (GtkBox    *box,
866                               GtkWidget *child)
867 {
868   CountingData count = { child, FALSE, 0, 0 };
869
870   /* foreach iterates in visible order */
871   gtk_container_foreach (GTK_CONTAINER (box),
872                          count_widget_position,
873                          &count);
874
875   /* the child wasn't found, it's likely an internal child of some
876    * subclass, return -1 to indicate that there is no sibling relation
877    * to the regular box children
878    */
879   if (!count.found)
880     return -1;
881
882   if (box->priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
883       gtk_widget_get_direction (GTK_WIDGET (box)) == GTK_TEXT_DIR_RTL)
884     return count.after;
885   else
886     return count.before;
887 }
888
889 static GtkWidgetPath *
890 gtk_box_get_path_for_child (GtkContainer *container,
891                             GtkWidget    *child)
892 {
893   GtkWidgetPath *path, *sibling_path;
894   GtkBox *box;
895   GtkBoxPrivate *private;
896   GList *list, *children;
897
898   box = GTK_BOX (container);
899   private = box->priv;
900
901   path = gtk_widget_path_copy (gtk_widget_get_path (GTK_WIDGET (container)));
902
903   if (gtk_widget_get_visible (child))
904     {
905       gint position;
906
907       sibling_path = gtk_widget_path_new ();
908
909       /* get_children works in visible order */
910       children = gtk_container_get_children (container);
911       if (private->orientation == GTK_ORIENTATION_HORIZONTAL &&
912           gtk_widget_get_direction (GTK_WIDGET (box)) == GTK_TEXT_DIR_RTL)
913         children = g_list_reverse (children);
914
915       for (list = children; list; list = list->next)
916         {
917           if (!gtk_widget_get_visible (list->data))
918             continue;
919
920           gtk_widget_path_append_for_widget (sibling_path, list->data);
921         }
922
923       g_list_free (children);
924
925       position = gtk_box_get_visible_position (box, child);
926
927       if (position >= 0)
928         gtk_widget_path_append_with_siblings (path, sibling_path, position);
929       else
930         gtk_widget_path_append_for_widget (path, child);
931
932       gtk_widget_path_unref (sibling_path);
933     }
934   else
935     gtk_widget_path_append_for_widget (path, child);
936
937   return path;
938 }
939
940 static void
941 gtk_box_invalidate_order (GtkBox *box)
942 {
943   gtk_container_foreach (GTK_CONTAINER (box),
944                          (GtkCallback) gtk_widget_reset_style,
945                          NULL);
946 }
947
948 static void
949 gtk_box_direction_changed (GtkWidget        *widget,
950                            GtkTextDirection  previous_direction)
951 {
952   gtk_box_invalidate_order (GTK_BOX (widget));
953 }
954
955 static void
956 box_child_visibility_notify_cb (GObject *obj,
957                                 GParamSpec *pspec,
958                                 gpointer user_data)
959 {
960   GtkBox *box = user_data;
961
962   gtk_box_invalidate_order (box);
963 }
964
965 static void
966 gtk_box_pack (GtkBox      *box,
967               GtkWidget   *child,
968               gboolean     expand,
969               gboolean     fill,
970               guint        padding,
971               GtkPackType  pack_type)
972 {
973   GtkBoxPrivate *private = box->priv;
974   GtkBoxChild *child_info;
975
976   g_return_if_fail (GTK_IS_BOX (box));
977   g_return_if_fail (GTK_IS_WIDGET (child));
978   g_return_if_fail (gtk_widget_get_parent (child) == NULL);
979
980   child_info = g_new (GtkBoxChild, 1);
981   child_info->widget = child;
982   child_info->padding = padding;
983   child_info->expand = expand ? TRUE : FALSE;
984   child_info->fill = fill ? TRUE : FALSE;
985   child_info->pack = pack_type;
986
987   private->children = g_list_append (private->children, child_info);
988
989   gtk_widget_freeze_child_notify (child);
990
991   gtk_box_invalidate_order (box);
992   gtk_widget_set_parent (child, GTK_WIDGET (box));
993
994   g_signal_connect (child, "notify::visible",
995                     G_CALLBACK (box_child_visibility_notify_cb), box);
996
997   gtk_widget_child_notify (child, "expand");
998   gtk_widget_child_notify (child, "fill");
999   gtk_widget_child_notify (child, "padding");
1000   gtk_widget_child_notify (child, "pack-type");
1001   gtk_widget_child_notify (child, "position");
1002   gtk_widget_thaw_child_notify (child);
1003 }
1004
1005 static void
1006 gtk_box_get_size (GtkWidget      *widget,
1007                   GtkOrientation  orientation,
1008                   gint           *minimum_size,
1009                   gint           *natural_size)
1010 {
1011   GtkBox *box;
1012   GtkBoxPrivate *private;
1013   GList *children;
1014   gint nvis_children;
1015   gint minimum, natural;
1016
1017   box = GTK_BOX (widget);
1018   private = box->priv;
1019
1020   minimum = natural = 0;
1021
1022   nvis_children = 0;
1023
1024   for (children = private->children; children; children = children->next)
1025     {
1026       GtkBoxChild *child = children->data;
1027
1028       if (gtk_widget_get_visible (child->widget))
1029         {
1030           gint child_minimum, child_natural;
1031
1032           if (orientation == GTK_ORIENTATION_HORIZONTAL)
1033             gtk_widget_get_preferred_width (child->widget,
1034                                             &child_minimum, &child_natural);
1035           else
1036             gtk_widget_get_preferred_height (child->widget,
1037                                              &child_minimum, &child_natural);
1038
1039           if (private->orientation == orientation)
1040             {
1041               if (private->homogeneous)
1042                 {
1043                   gint largest;
1044
1045                   largest = child_minimum + child->padding * 2;
1046                   minimum = MAX (minimum, largest);
1047
1048                   largest = child_natural + child->padding * 2;
1049                   natural = MAX (natural, largest);
1050                 }
1051               else
1052                 {
1053                   minimum += child_minimum + child->padding * 2;
1054                   natural += child_natural + child->padding * 2;
1055                 }
1056             }
1057           else
1058             {
1059               /* The biggest mins and naturals in the opposing orientation */
1060               minimum = MAX (minimum, child_minimum);
1061               natural = MAX (natural, child_natural);
1062             }
1063
1064           nvis_children += 1;
1065         }
1066     }
1067
1068   if (nvis_children > 0 && private->orientation == orientation)
1069     {
1070       if (private->homogeneous)
1071         {
1072           minimum *= nvis_children;
1073           natural *= nvis_children;
1074         }
1075       minimum += (nvis_children - 1) * private->spacing;
1076       natural += (nvis_children - 1) * private->spacing;
1077     }
1078
1079   if (minimum_size)
1080     *minimum_size = minimum;
1081
1082   if (natural_size)
1083     *natural_size = natural;
1084 }
1085
1086 static void
1087 gtk_box_get_preferred_width (GtkWidget *widget,
1088                              gint      *minimum_size,
1089                              gint      *natural_size)
1090 {
1091   gtk_box_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
1092 }
1093
1094 static void
1095 gtk_box_get_preferred_height (GtkWidget *widget,
1096                               gint      *minimum_size,
1097                               gint      *natural_size)
1098 {
1099   gtk_box_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
1100 }
1101
1102 static void
1103 gtk_box_compute_size_for_opposing_orientation (GtkBox *box,
1104                                                gint    avail_size,
1105                                                gint   *minimum_size,
1106                                                gint   *natural_size)
1107 {
1108   GtkBoxPrivate       *private = box->priv;
1109   GtkBoxChild      *child;
1110   GList            *children;
1111   gint              nvis_children;
1112   gint              nexpand_children;
1113   gint              computed_minimum = 0, computed_natural = 0;
1114   GtkRequestedSize *sizes;
1115   GtkPackType       packing;
1116   gint              size, extra, i;
1117   gint              child_size, child_minimum, child_natural;
1118   gint              n_extra_widgets = 0;
1119
1120   count_expand_children (box, &nvis_children, &nexpand_children);
1121
1122   if (nvis_children <= 0)
1123     return;
1124
1125   sizes = g_newa (GtkRequestedSize, nvis_children);
1126   size = avail_size - (nvis_children - 1) * private->spacing;
1127
1128   /* Retrieve desired size for visible children */
1129   for (i = 0, children = private->children; children; children = children->next)
1130     {
1131       child = children->data;
1132
1133       if (gtk_widget_get_visible (child->widget))
1134         {
1135           if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
1136             gtk_widget_get_preferred_width (child->widget,
1137                                             &sizes[i].minimum_size,
1138                                             &sizes[i].natural_size);
1139           else
1140             gtk_widget_get_preferred_height (child->widget,
1141                                              &sizes[i].minimum_size,
1142                                              &sizes[i].natural_size);
1143
1144           /* Assert the api is working properly */
1145           if (sizes[i].minimum_size < 0)
1146             g_error ("GtkBox child %s minimum %s: %d < 0",
1147                      gtk_widget_get_name (GTK_WIDGET (child->widget)),
1148                      (private->orientation == GTK_ORIENTATION_HORIZONTAL) ? "width" : "height",
1149                      sizes[i].minimum_size);
1150
1151           if (sizes[i].natural_size < sizes[i].minimum_size)
1152             g_error ("GtkBox child %s natural %s: %d < minimum %d",
1153                      gtk_widget_get_name (GTK_WIDGET (child->widget)),
1154                      (private->orientation == GTK_ORIENTATION_HORIZONTAL) ? "width" : "height",
1155                      sizes[i].natural_size,
1156                      sizes[i].minimum_size);
1157
1158           size -= sizes[i].minimum_size;
1159           size -= child->padding * 2;
1160
1161           sizes[i].data = child;
1162
1163           i += 1;
1164         }
1165     }
1166
1167   if (private->homogeneous)
1168     {
1169       /* If were homogenous we still need to run the above loop to get the
1170        * minimum sizes for children that are not going to fill
1171        */
1172       size = avail_size - (nvis_children - 1) * private->spacing;
1173       extra = size / nvis_children;
1174       n_extra_widgets = size % nvis_children;
1175     }
1176   else
1177     {
1178       /* Bring children up to size first */
1179       size = gtk_distribute_natural_allocation (MAX (0, size), nvis_children, sizes);
1180
1181       /* Calculate space which hasn't distributed yet,
1182        * and is available for expanding children.
1183        */
1184       if (nexpand_children > 0)
1185         {
1186           extra = size / nexpand_children;
1187           n_extra_widgets = size % nexpand_children;
1188         }
1189       else
1190         extra = 0;
1191     }
1192
1193   /* Allocate child positions. */
1194   for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
1195     {
1196       for (i = 0, children = private->children;
1197            children;
1198            children = children->next)
1199         {
1200           child = children->data;
1201
1202           /* If widget is not visible, skip it. */
1203           if (!gtk_widget_get_visible (child->widget))
1204             continue;
1205
1206           /* If widget is packed differently skip it, but still increment i,
1207            * since widget is visible and will be handled in next loop iteration.
1208            */
1209           if (child->pack != packing)
1210             {
1211               i++;
1212               continue;
1213             }
1214
1215           if (child->pack == packing)
1216             {
1217               /* Assign the child's size. */
1218               if (private->homogeneous)
1219                 {
1220                   child_size = extra;
1221
1222                   if (n_extra_widgets > 0)
1223                     {
1224                       child_size++;
1225                       n_extra_widgets--;
1226                     }
1227                 }
1228               else
1229                 {
1230                   child_size = sizes[i].minimum_size + child->padding * 2;
1231
1232                   if (child->expand || gtk_widget_compute_expand (child->widget, private->orientation))
1233                     {
1234                       child_size += extra;
1235
1236                       if (n_extra_widgets > 0)
1237                         {
1238                           child_size++;
1239                           n_extra_widgets--;
1240                         }
1241                     }
1242                 }
1243
1244               if (child->fill)
1245                 {
1246                   child_size = MAX (1, child_size - child->padding * 2);
1247                 }
1248               else
1249                 {
1250                   child_size = sizes[i].minimum_size;
1251                 }
1252
1253
1254               /* Assign the child's position. */
1255               if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
1256                 gtk_widget_get_preferred_height_for_width (child->widget,
1257                                                            child_size, &child_minimum, &child_natural);
1258               else /* (private->orientation == GTK_ORIENTATION_VERTICAL) */
1259                 gtk_widget_get_preferred_width_for_height (child->widget,
1260                                                            child_size, &child_minimum, &child_natural);
1261
1262
1263               computed_minimum = MAX (computed_minimum, child_minimum);
1264               computed_natural = MAX (computed_natural, child_natural);
1265             }
1266           i += 1;
1267         }
1268     }
1269
1270   if (minimum_size)
1271     *minimum_size = computed_minimum;
1272   if (natural_size)
1273     *natural_size = computed_natural;
1274 }
1275
1276 static void
1277 gtk_box_compute_size_for_orientation (GtkBox *box,
1278                                       gint    avail_size,
1279                                       gint   *minimum_size,
1280                                       gint   *natural_size)
1281 {
1282   GtkBoxPrivate    *private = box->priv;
1283   GList         *children;
1284   gint           nvis_children = 0;
1285   gint           required_size = 0, required_natural = 0, child_size, child_natural;
1286   gint           largest_child = 0, largest_natural = 0;
1287
1288   for (children = private->children; children != NULL;
1289        children = children->next)
1290     {
1291       GtkBoxChild *child = children->data;
1292
1293       if (gtk_widget_get_visible (child->widget))
1294         {
1295
1296           if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
1297             gtk_widget_get_preferred_width_for_height (child->widget,
1298                                                        avail_size, &child_size, &child_natural);
1299           else
1300             gtk_widget_get_preferred_height_for_width (child->widget,
1301                                                        avail_size, &child_size, &child_natural);
1302
1303
1304           child_size    += child->padding * 2;
1305           child_natural += child->padding * 2;
1306
1307           if (child_size > largest_child)
1308             largest_child = child_size;
1309
1310           if (child_natural > largest_natural)
1311             largest_natural = child_natural;
1312
1313           required_size    += child_size;
1314           required_natural += child_natural;
1315
1316           nvis_children += 1;
1317         }
1318     }
1319
1320   if (nvis_children > 0)
1321     {
1322       if (private->homogeneous)
1323         {
1324           required_size    = largest_child   * nvis_children;
1325           required_natural = largest_natural * nvis_children;
1326         }
1327
1328       required_size     += (nvis_children - 1) * private->spacing;
1329       required_natural  += (nvis_children - 1) * private->spacing;
1330     }
1331
1332   if (minimum_size)
1333     *minimum_size = required_size;
1334
1335   if (natural_size)
1336     *natural_size = required_natural;
1337 }
1338
1339 static void
1340 gtk_box_get_preferred_width_for_height (GtkWidget *widget,
1341                                         gint       height,
1342                                         gint      *minimum_width,
1343                                         gint      *natural_width)
1344 {
1345   GtkBox        *box     = GTK_BOX (widget);
1346   GtkBoxPrivate *private = box->priv;
1347
1348   if (private->orientation == GTK_ORIENTATION_VERTICAL)
1349     gtk_box_compute_size_for_opposing_orientation (box, height, minimum_width, natural_width);
1350   else
1351     gtk_box_compute_size_for_orientation (box, height, minimum_width, natural_width);
1352 }
1353
1354 static void
1355 gtk_box_get_preferred_height_for_width (GtkWidget *widget,
1356                                         gint       width,
1357                                         gint      *minimum_height,
1358                                         gint      *natural_height)
1359 {
1360   GtkBox        *box     = GTK_BOX (widget);
1361   GtkBoxPrivate *private = box->priv;
1362
1363   if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
1364     gtk_box_compute_size_for_opposing_orientation (box, width, minimum_height, natural_height);
1365   else
1366     gtk_box_compute_size_for_orientation (box, width, minimum_height, natural_height);
1367 }
1368
1369 /**
1370  * gtk_box_new:
1371  * @orientation: the box's orientation.
1372  * @spacing: the number of pixels to place by default between children.
1373  *
1374  * Creates a new #GtkBox.
1375  *
1376  * Return value: a new #GtkBox.
1377  *
1378  * Since: 3.0
1379  **/
1380 GtkWidget*
1381 gtk_box_new (GtkOrientation orientation,
1382              gint           spacing)
1383 {
1384   return g_object_new (GTK_TYPE_BOX,
1385                        "orientation", orientation,
1386                        "spacing",     spacing,
1387                        NULL);
1388 }
1389
1390 /**
1391  * gtk_box_pack_start:
1392  * @box: a #GtkBox
1393  * @child: the #GtkWidget to be added to @box
1394  * @expand: %TRUE if the new child is to be given extra space allocated
1395  *     to @box. The extra space will be divided evenly between all children
1396  *     that use this option
1397  * @fill: %TRUE if space given to @child by the @expand option is
1398  *     actually allocated to @child, rather than just padding it.  This
1399  *     parameter has no effect if @expand is set to %FALSE.  A child is
1400  *     always allocated the full height of a horizontal #GtkBox and the full width
1401  *     of a vertical #GtkBox. This option affects the other dimension
1402  * @padding: extra space in pixels to put between this child and its
1403  *   neighbors, over and above the global amount specified by
1404  *   #GtkBox:spacing property.  If @child is a widget at one of the
1405  *   reference ends of @box, then @padding pixels are also put between
1406  *   @child and the reference edge of @box
1407  *
1408  * Adds @child to @box, packed with reference to the start of @box.
1409  * The @child is packed after any other child packed with reference
1410  * to the start of @box.
1411  */
1412 void
1413 gtk_box_pack_start (GtkBox    *box,
1414                     GtkWidget *child,
1415                     gboolean   expand,
1416                     gboolean   fill,
1417                     guint      padding)
1418 {
1419   gtk_box_pack (box, child, expand, fill, padding, GTK_PACK_START);
1420 }
1421
1422 /**
1423  * gtk_box_pack_end:
1424  * @box: a #GtkBox
1425  * @child: the #GtkWidget to be added to @box
1426  * @expand: %TRUE if the new child is to be given extra space allocated
1427  *   to @box. The extra space will be divided evenly between all children
1428  *   of @box that use this option
1429  * @fill: %TRUE if space given to @child by the @expand option is
1430  *   actually allocated to @child, rather than just padding it.  This
1431  *   parameter has no effect if @expand is set to %FALSE.  A child is
1432  *   always allocated the full height of a horizontal #GtkBox and the full width
1433  *   of a vertical #GtkBox.  This option affects the other dimension
1434  * @padding: extra space in pixels to put between this child and its
1435  *   neighbors, over and above the global amount specified by
1436  *   #GtkBox:spacing property.  If @child is a widget at one of the
1437  *   reference ends of @box, then @padding pixels are also put between
1438  *   @child and the reference edge of @box
1439  *
1440  * Adds @child to @box, packed with reference to the end of @box.
1441  * The @child is packed after (away from end of) any other child
1442  * packed with reference to the end of @box.
1443  */
1444 void
1445 gtk_box_pack_end (GtkBox    *box,
1446                   GtkWidget *child,
1447                   gboolean   expand,
1448                   gboolean   fill,
1449                   guint      padding)
1450 {
1451   gtk_box_pack (box, child, expand, fill, padding, GTK_PACK_END);
1452 }
1453
1454 /**
1455  * gtk_box_set_homogeneous:
1456  * @box: a #GtkBox
1457  * @homogeneous: a boolean value, %TRUE to create equal allotments,
1458  *   %FALSE for variable allotments
1459  *
1460  * Sets the #GtkBox:homogeneous property of @box, controlling
1461  * whether or not all children of @box are given equal space
1462  * in the box.
1463  */
1464 void
1465 gtk_box_set_homogeneous (GtkBox  *box,
1466                          gboolean homogeneous)
1467 {
1468   GtkBoxPrivate *private;
1469
1470   g_return_if_fail (GTK_IS_BOX (box));
1471
1472   private = box->priv;
1473
1474   if ((homogeneous ? TRUE : FALSE) != private->homogeneous)
1475     {
1476       private->homogeneous = homogeneous ? TRUE : FALSE;
1477       g_object_notify (G_OBJECT (box), "homogeneous");
1478       gtk_widget_queue_resize (GTK_WIDGET (box));
1479     }
1480 }
1481
1482 /**
1483  * gtk_box_get_homogeneous:
1484  * @box: a #GtkBox
1485  *
1486  * Returns whether the box is homogeneous (all children are the
1487  * same size). See gtk_box_set_homogeneous().
1488  *
1489  * Return value: %TRUE if the box is homogeneous.
1490  **/
1491 gboolean
1492 gtk_box_get_homogeneous (GtkBox *box)
1493 {
1494   g_return_val_if_fail (GTK_IS_BOX (box), FALSE);
1495
1496   return box->priv->homogeneous;
1497 }
1498
1499 /**
1500  * gtk_box_set_spacing:
1501  * @box: a #GtkBox
1502  * @spacing: the number of pixels to put between children
1503  *
1504  * Sets the #GtkBox:spacing property of @box, which is the
1505  * number of pixels to place between children of @box.
1506  */
1507 void
1508 gtk_box_set_spacing (GtkBox *box,
1509                      gint    spacing)
1510 {
1511   GtkBoxPrivate *private;
1512
1513   g_return_if_fail (GTK_IS_BOX (box));
1514
1515   private = box->priv;
1516
1517   if (spacing != private->spacing)
1518     {
1519       private->spacing = spacing;
1520       _gtk_box_set_spacing_set (box, TRUE);
1521
1522       g_object_notify (G_OBJECT (box), "spacing");
1523
1524       gtk_widget_queue_resize (GTK_WIDGET (box));
1525     }
1526 }
1527
1528 /**
1529  * gtk_box_get_spacing:
1530  * @box: a #GtkBox
1531  *
1532  * Gets the value set by gtk_box_set_spacing().
1533  *
1534  * Return value: spacing between children
1535  **/
1536 gint
1537 gtk_box_get_spacing (GtkBox *box)
1538 {
1539   g_return_val_if_fail (GTK_IS_BOX (box), 0);
1540
1541   return box->priv->spacing;
1542 }
1543
1544 void
1545 _gtk_box_set_spacing_set (GtkBox  *box,
1546                           gboolean spacing_set)
1547 {
1548   GtkBoxPrivate *private;
1549
1550   g_return_if_fail (GTK_IS_BOX (box));
1551
1552   private = box->priv;
1553
1554   private->spacing_set = spacing_set ? TRUE : FALSE;
1555 }
1556
1557 gboolean
1558 _gtk_box_get_spacing_set (GtkBox *box)
1559 {
1560   GtkBoxPrivate *private;
1561
1562   g_return_val_if_fail (GTK_IS_BOX (box), FALSE);
1563
1564   private = box->priv;
1565
1566   return private->spacing_set;
1567 }
1568
1569 /**
1570  * gtk_box_reorder_child:
1571  * @box: a #GtkBox
1572  * @child: the #GtkWidget to move
1573  * @position: the new position for @child in the list of children
1574  *   of @box, starting from 0. If negative, indicates the end of
1575  *   the list
1576  *
1577  * Moves @child to a new @position in the list of @box children.
1578  * The list is the <structfield>children</structfield> field of
1579  * #GtkBox-struct, and contains both widgets packed #GTK_PACK_START
1580  * as well as widgets packed #GTK_PACK_END, in the order that these
1581  * widgets were added to @box.
1582  *
1583  * A widget's position in the @box children list determines where
1584  * the widget is packed into @box.  A child widget at some position
1585  * in the list will be packed just after all other widgets of the
1586  * same packing type that appear earlier in the list.
1587  */
1588 void
1589 gtk_box_reorder_child (GtkBox    *box,
1590                        GtkWidget *child,
1591                        gint       position)
1592 {
1593   GtkBoxPrivate *priv;
1594   GList *old_link;
1595   GList *new_link;
1596   GtkBoxChild *child_info = NULL;
1597   gint old_position;
1598
1599   g_return_if_fail (GTK_IS_BOX (box));
1600   g_return_if_fail (GTK_IS_WIDGET (child));
1601
1602   priv = box->priv;
1603
1604   old_link = priv->children;
1605   old_position = 0;
1606   while (old_link)
1607     {
1608       child_info = old_link->data;
1609       if (child_info->widget == child)
1610         break;
1611
1612       old_link = old_link->next;
1613       old_position++;
1614     }
1615
1616   g_return_if_fail (old_link != NULL);
1617
1618   if (position == old_position)
1619     return;
1620
1621   priv->children = g_list_delete_link (priv->children, old_link);
1622
1623   if (position < 0)
1624     new_link = NULL;
1625   else
1626     new_link = g_list_nth (priv->children, position);
1627
1628   priv->children = g_list_insert_before (priv->children, new_link, child_info);
1629
1630   gtk_widget_child_notify (child, "position");
1631   if (gtk_widget_get_visible (child)
1632       && gtk_widget_get_visible (GTK_WIDGET (box)))
1633     {
1634       gtk_box_invalidate_order (box);
1635       gtk_widget_queue_resize (child);
1636     }
1637 }
1638
1639 /**
1640  * gtk_box_query_child_packing:
1641  * @box: a #GtkBox
1642  * @child: the #GtkWidget of the child to query
1643  * @expand: (out): pointer to return location for #GtkBox:expand child
1644  *     property
1645  * @fill: (out): pointer to return location for #GtkBox:fill child
1646  *     property
1647  * @padding: (out): pointer to return location for #GtkBox:padding
1648  *     child property
1649  * @pack_type: (out): pointer to return location for #GtkBox:pack-type
1650  *     child property
1651  *
1652  * Obtains information about how @child is packed into @box.
1653  */
1654 void
1655 gtk_box_query_child_packing (GtkBox      *box,
1656                              GtkWidget   *child,
1657                              gboolean    *expand,
1658                              gboolean    *fill,
1659                              guint       *padding,
1660                              GtkPackType *pack_type)
1661 {
1662   GtkBoxPrivate *private;
1663   GList *list;
1664   GtkBoxChild *child_info = NULL;
1665
1666   g_return_if_fail (GTK_IS_BOX (box));
1667   g_return_if_fail (GTK_IS_WIDGET (child));
1668
1669   private = box->priv;
1670
1671   list = private->children;
1672   while (list)
1673     {
1674       child_info = list->data;
1675       if (child_info->widget == child)
1676         break;
1677
1678       list = list->next;
1679     }
1680
1681   if (list)
1682     {
1683       if (expand)
1684         *expand = child_info->expand;
1685       if (fill)
1686         *fill = child_info->fill;
1687       if (padding)
1688         *padding = child_info->padding;
1689       if (pack_type)
1690         *pack_type = child_info->pack;
1691     }
1692 }
1693
1694 /**
1695  * gtk_box_set_child_packing:
1696  * @box: a #GtkBox
1697  * @child: the #GtkWidget of the child to set
1698  * @expand: the new value of the #GtkBox:expand child property
1699  * @fill: the new value of the #GtkBox:fill child property
1700  * @padding: the new value of the #GtkBox:padding child property
1701  * @pack_type: the new value of the #GtkBox:pack-type child property
1702  *
1703  * Sets the way @child is packed into @box.
1704  */
1705 void
1706 gtk_box_set_child_packing (GtkBox      *box,
1707                            GtkWidget   *child,
1708                            gboolean     expand,
1709                            gboolean     fill,
1710                            guint        padding,
1711                            GtkPackType  pack_type)
1712 {
1713   GtkBoxPrivate *private;
1714   GList *list;
1715   GtkBoxChild *child_info = NULL;
1716
1717   g_return_if_fail (GTK_IS_BOX (box));
1718   g_return_if_fail (GTK_IS_WIDGET (child));
1719
1720   private = box->priv;
1721
1722   list = private->children;
1723   while (list)
1724     {
1725       child_info = list->data;
1726       if (child_info->widget == child)
1727         break;
1728
1729       list = list->next;
1730     }
1731
1732   gtk_widget_freeze_child_notify (child);
1733   if (list)
1734     {
1735       gboolean expanded;
1736
1737       expanded = expand != FALSE;
1738
1739       /* avoid setting expand if unchanged, since queue_compute_expand
1740        * can be expensive-ish
1741        */
1742       if (child_info->expand != expanded)
1743         {
1744           child_info->expand = expand != FALSE;
1745           gtk_widget_queue_compute_expand (GTK_WIDGET (box));
1746           gtk_widget_child_notify (child, "expand");
1747         }
1748
1749       child_info->fill = fill != FALSE;
1750       gtk_widget_child_notify (child, "fill");
1751       child_info->padding = padding;
1752       gtk_widget_child_notify (child, "padding");
1753       if (pack_type != GTK_PACK_END)
1754         pack_type = GTK_PACK_START;
1755       if (child_info->pack != pack_type)
1756         {
1757           child_info->pack = GTK_PACK_END;
1758           gtk_widget_child_notify (child, "pack-type");
1759           gtk_box_invalidate_order (box);
1760         }
1761
1762       if (gtk_widget_get_visible (child)
1763           && gtk_widget_get_visible (GTK_WIDGET (box)))
1764         gtk_widget_queue_resize (child);
1765     }
1766   gtk_widget_thaw_child_notify (child);
1767 }
1768
1769 void
1770 _gtk_box_set_old_defaults (GtkBox *box)
1771 {
1772   GtkBoxPrivate *private;
1773
1774   g_return_if_fail (GTK_IS_BOX (box));
1775
1776   private = box->priv;
1777
1778   private->default_expand = TRUE;
1779 }
1780
1781 static void
1782 gtk_box_add (GtkContainer *container,
1783              GtkWidget    *widget)
1784 {
1785   GtkBoxPrivate *priv = GTK_BOX (container)->priv;
1786
1787   gtk_box_pack_start (GTK_BOX (container), widget,
1788                       priv->default_expand,
1789                       TRUE,
1790                       0);
1791 }
1792
1793 static void
1794 gtk_box_remove (GtkContainer *container,
1795                 GtkWidget    *widget)
1796 {
1797   GtkBox *box = GTK_BOX (container);
1798   GtkBoxPrivate *priv = box->priv;
1799   GtkBoxChild *child;
1800   GList *children;
1801
1802   children = priv->children;
1803   while (children)
1804     {
1805       child = children->data;
1806
1807       if (child->widget == widget)
1808         {
1809           gboolean was_visible;
1810
1811           g_signal_handlers_disconnect_by_func (widget,
1812                                                 box_child_visibility_notify_cb,
1813                                                 box);
1814
1815           was_visible = gtk_widget_get_visible (widget);
1816           gtk_widget_unparent (widget);
1817
1818           priv->children = g_list_remove_link (priv->children, children);
1819           g_list_free (children);
1820           g_free (child);
1821
1822           /* queue resize regardless of gtk_widget_get_visible (container),
1823            * since that's what is needed by toplevels.
1824            */
1825           if (was_visible)
1826             {
1827               gtk_box_invalidate_order (box);
1828               gtk_widget_queue_resize (GTK_WIDGET (container));
1829             }
1830
1831           break;
1832         }
1833
1834       children = children->next;
1835     }
1836 }
1837
1838 static void
1839 gtk_box_forall (GtkContainer *container,
1840                 gboolean      include_internals,
1841                 GtkCallback   callback,
1842                 gpointer      callback_data)
1843 {
1844   GtkBox *box = GTK_BOX (container);
1845   GtkBoxPrivate *priv = box->priv;
1846   GtkBoxChild *child;
1847   GList *children;
1848
1849   children = priv->children;
1850   while (children)
1851     {
1852       child = children->data;
1853       children = children->next;
1854
1855       if (child->pack == GTK_PACK_START)
1856         (* callback) (child->widget, callback_data);
1857     }
1858
1859   children = g_list_last (priv->children);
1860   while (children)
1861     {
1862       child = children->data;
1863       children = children->prev;
1864
1865       if (child->pack == GTK_PACK_END)
1866         (* callback) (child->widget, callback_data);
1867     }
1868 }
1869
1870 GList *
1871 _gtk_box_get_children (GtkBox *box)
1872 {
1873   GtkBoxPrivate *priv;
1874   GtkBoxChild *child;
1875   GList *children;
1876   GList *retval = NULL;
1877
1878   g_return_val_if_fail (GTK_IS_BOX (box), NULL);
1879
1880   priv = box->priv;
1881
1882   children = priv->children;
1883   while (children)
1884     {
1885       child = children->data;
1886       children = children->next;
1887
1888       retval = g_list_prepend (retval, child->widget);
1889     }
1890
1891   return g_list_reverse (retval);
1892 }