]> Pileus Git - ~andy/gtk/blob - gtk/gtkcontainer.c
GtkScrolledWindow: use GdkFrameClock for kinetic scrolling
[~andy/gtk] / gtk / gtkcontainer.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 #include "config.h"
26
27 #include "gtkcontainer.h"
28 #include "gtkcontainerprivate.h"
29
30 #include <stdarg.h>
31 #include <string.h>
32 #include <stdlib.h>
33
34 #include <gobject/gobjectnotifyqueue.c>
35 #include <gobject/gvaluecollector.h>
36
37 #include "gtkadjustment.h"
38 #include "gtkbuildable.h"
39 #include "gtkbuilderprivate.h"
40 #include "gtktypebuiltins.h"
41 #include "gtkprivate.h"
42 #include "gtkmain.h"
43 #include "gtkmarshalers.h"
44 #include "gtksizerequest.h"
45 #include "gtksizerequestcacheprivate.h"
46 #include "gtkwidgetprivate.h"
47 #include "gtkwindow.h"
48 #include "gtkassistant.h"
49 #include "gtkintl.h"
50 #include "gtkstylecontextprivate.h"
51 #include "gtkwidgetpath.h"
52 #include "a11y/gtkcontaineraccessible.h"
53
54 /**
55  * SECTION:gtkcontainer
56  * @Short_description: Base class for widgets which contain other widgets
57  * @Title: GtkContainer
58  *
59  * A GTK+ user interface is constructed by nesting widgets inside widgets.
60  * Container widgets are the inner nodes in the resulting tree of widgets:
61  * they contain other widgets. So, for example, you might have a #GtkWindow
62  * containing a #GtkFrame containing a #GtkLabel. If you wanted an image instead
63  * of a textual label inside the frame, you might replace the #GtkLabel widget
64  * with a #GtkImage widget.
65  *
66  * There are two major kinds of container widgets in GTK+. Both are subclasses
67  * of the abstract GtkContainer base class.
68  *
69  * The first type of container widget has a single child widget and derives
70  * from #GtkBin. These containers are <emphasis>decorators</emphasis>, which
71  * add some kind of functionality to the child. For example, a #GtkButton makes
72  * its child into a clickable button; a #GtkFrame draws a frame around its child
73  * and a #GtkWindow places its child widget inside a top-level window.
74  *
75  * The second type of container can have more than one child; its purpose is to
76  * manage <emphasis>layout</emphasis>. This means that these containers assign
77  * sizes and positions to their children. For example, a #GtkHBox arranges its
78  * children in a horizontal row, and a #GtkGrid arranges the widgets it contains
79  * in a two-dimensional grid.
80  *
81  * <refsect2 id="container-geometry-management">
82  * <title>Height for width geometry management</title>
83  * <para>
84  * GTK+ uses a height-for-width (and width-for-height) geometry management system.
85  * Height-for-width means that a widget can change how much vertical space it needs,
86  * depending on the amount of horizontal space that it is given (and similar for
87  * width-for-height).
88  *
89  * There are some things to keep in mind when implementing container widgets
90  * that make use of GTK+'s height for width geometry management system. First,
91  * it's important to note that a container must prioritize one of its
92  * dimensions, that is to say that a widget or container can only have a
93  * #GtkSizeRequestMode that is %GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH or
94  * %GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT. However, every widget and container
95  * must be able to respond to the APIs for both dimensions, i.e. even if a
96  * widget has a request mode that is height-for-width, it is possible that
97  * its parent will request its sizes using the width-for-height APIs.
98  *
99  * To ensure that everything works properly, here are some guidelines to follow
100  * when implementing height-for-width (or width-for-height) containers.
101  *
102  * Each request mode involves 2 virtual methods. Height-for-width apis run
103  * through gtk_widget_get_preferred_width() and then through gtk_widget_get_preferred_height_for_width().
104  * When handling requests in the opposite #GtkSizeRequestMode it is important that
105  * every widget request at least enough space to display all of its content at all times.
106  *
107  * When gtk_widget_get_preferred_height() is called on a container that is height-for-width,
108  * the container must return the height for its minimum width. This is easily achieved by
109  * simply calling the reverse apis implemented for itself as follows:
110  *
111  * <programlisting><![CDATA[
112  * static void
113  * foo_container_get_preferred_height (GtkWidget *widget, gint *min_height, gint *nat_height)
114  * {
115  *    if (i_am_in_height_for_width_mode)
116  *      {
117  *        gint min_width;
118  *
119  *        GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_width, NULL);
120  *        GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, min_width,
121  *                                                                       min_height, nat_height);
122  *      }
123  *    else
124  *      {
125  *        ... many containers support both request modes, execute the real width-for-height
126  *        request here by returning the collective heights of all widgets that are
127  *        stacked vertically (or whatever is appropriate for this container) ...
128  *      }
129  * }
130  * ]]></programlisting>
131  *
132  * Similarly, when gtk_widget_get_preferred_width_for_height() is called for a container or widget
133  * that is height-for-width, it then only needs to return the base minimum width like so:
134  *
135  * <programlisting><![CDATA[
136  * static void
137  * foo_container_get_preferred_width_for_height (GtkWidget *widget, gint for_height,
138  *                                               gint *min_width, gint *nat_width)
139  * {
140  *    if (i_am_in_height_for_width_mode)
141  *      {
142  *        GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, min_width, nat_width);
143  *      }
144  *    else
145  *      {
146  *        ... execute the real width-for-height request here based on the required width
147  *        of the children collectively if the container were to be allocated the said height ...
148  *      }
149  * }
150  * ]]></programlisting>
151  *
152  * Height for width requests are generally implemented in terms of a virtual allocation
153  * of widgets in the input orientation. Assuming an height-for-width request mode, a container
154  * would implement the <function>get_preferred_height_for_width()</function> virtual function by first calling
155  * gtk_widget_get_preferred_width() for each of its children.
156  *
157  * For each potential group of children that are lined up horizontally, the values returned by
158  * gtk_widget_get_preferred_width() should be collected in an array of #GtkRequestedSize structures.
159  * Any child spacing should be removed from the input @for_width and then the collective size should be
160  * allocated using the gtk_distribute_natural_allocation() convenience function.
161  *
162  * The container will then move on to request the preferred height for each child by using
163  * gtk_widget_get_preferred_height_for_width() and using the sizes stored in the #GtkRequestedSize array.
164  *
165  * To allocate a height-for-width container, it's again important
166  * to consider that a container must prioritize one dimension over the other. So if
167  * a container is a height-for-width container it must first allocate all widgets horizontally
168  * using a #GtkRequestedSize array and gtk_distribute_natural_allocation() and then add any
169  * extra space (if and where appropriate) for the widget to expand.
170  *
171  * After adding all the expand space, the container assumes it was allocated sufficient
172  * height to fit all of its content. At this time, the container must use the total horizontal sizes
173  * of each widget to request the height-for-width of each of its children and store the requests in a
174  * #GtkRequestedSize array for any widgets that stack vertically (for tabular containers this can
175  * be generalized into the heights and widths of rows and columns).
176  * The vertical space must then again be distributed using gtk_distribute_natural_allocation()
177  * while this time considering the allocated height of the widget minus any vertical spacing
178  * that the container adds. Then vertical expand space should be added where appropriate and available
179  * and the container should go on to actually allocating the child widgets.
180  *
181  * See <link linkend="geometry-management">GtkWidget's geometry management section</link>
182  * to learn more about implementing height-for-width geometry management for widgets.
183  * </para>
184  * </refsect2>
185  * <refsect2 id="child-properties">
186  * <title>Child properties</title>
187  * <para>
188  * GtkContainer introduces <emphasis>child properties</emphasis>.
189  * These are object properties that are not specific
190  * to either the container or the contained widget, but rather to their relation.
191  * Typical examples of child properties are the position or pack-type of a widget
192  * which is contained in a #GtkBox.
193  *
194  * Use gtk_container_class_install_child_property() to install child properties
195  * for a container class and gtk_container_class_find_child_property() or
196  * gtk_container_class_list_child_properties() to get information about existing
197  * child properties.
198  *
199  * To set the value of a child property, use gtk_container_child_set_property(),
200  * gtk_container_child_set() or gtk_container_child_set_valist().
201  * To obtain the value of a child property, use
202  * gtk_container_child_get_property(), gtk_container_child_get() or
203  * gtk_container_child_get_valist(). To emit notification about child property
204  * changes, use gtk_widget_child_notify().
205  * </para>
206  * </refsect2>
207  * <refsect2 id="GtkContainer-BUILDER-UI">
208  * <title>GtkContainer as GtkBuildable</title>
209  * <para>
210  * The GtkContainer implementation of the GtkBuildable interface
211  * supports a &lt;packing&gt; element for children, which can
212  * contain multiple &lt;property&gt; elements that specify
213  * child properties for the child.
214  * <example>
215  * <title>Child properties in UI definitions</title>
216  * <programlisting><![CDATA[
217  * <object class="GtkVBox">
218  *   <child>
219  *     <object class="GtkLabel"/>
220  *     <packing>
221  *       <property name="pack-type">start</property>
222  *     </packing>
223  *   </child>
224  * </object>
225  * ]]></programlisting>
226  * </example>
227  * Since 2.16, child properties can also be marked as translatable using
228  * the same "translatable", "comments" and "context" attributes that are used
229  * for regular properties.
230  * </para>
231  * </refsect2>
232  */
233
234
235 struct _GtkContainerPrivate
236 {
237   GtkWidget *focus_child;
238
239   guint resize_handler;
240   GdkFrameClock *resize_clock;
241
242   guint border_width : 16;
243
244   guint has_focus_chain    : 1;
245   guint reallocate_redraws : 1;
246   guint resize_pending     : 1;
247   guint restyle_pending    : 1;
248   guint resize_mode        : 2;
249   guint request_mode       : 2;
250 };
251
252 enum {
253   ADD,
254   REMOVE,
255   CHECK_RESIZE,
256   SET_FOCUS_CHILD,
257   LAST_SIGNAL
258 };
259
260 enum {
261   PROP_0,
262   PROP_BORDER_WIDTH,
263   PROP_RESIZE_MODE,
264   PROP_CHILD
265 };
266
267 #define PARAM_SPEC_PARAM_ID(pspec)              ((pspec)->param_id)
268 #define PARAM_SPEC_SET_PARAM_ID(pspec, id)      ((pspec)->param_id = (id))
269
270
271 /* --- prototypes --- */
272 static void     gtk_container_base_class_init      (GtkContainerClass *klass);
273 static void     gtk_container_base_class_finalize  (GtkContainerClass *klass);
274 static void     gtk_container_class_init           (GtkContainerClass *klass);
275 static void     gtk_container_init                 (GtkContainer      *container);
276 static void     gtk_container_destroy              (GtkWidget         *widget);
277 static void     gtk_container_set_property         (GObject         *object,
278                                                     guint            prop_id,
279                                                     const GValue    *value,
280                                                     GParamSpec      *pspec);
281 static void     gtk_container_get_property         (GObject         *object,
282                                                     guint            prop_id,
283                                                     GValue          *value,
284                                                     GParamSpec      *pspec);
285 static void     gtk_container_add_unimplemented    (GtkContainer      *container,
286                                                     GtkWidget         *widget);
287 static void     gtk_container_remove_unimplemented (GtkContainer      *container,
288                                                     GtkWidget         *widget);
289 static void     gtk_container_real_check_resize    (GtkContainer      *container);
290 static void     gtk_container_compute_expand       (GtkWidget         *widget,
291                                                     gboolean          *hexpand_p,
292                                                     gboolean          *vexpand_p);
293 static gboolean gtk_container_focus                (GtkWidget         *widget,
294                                                     GtkDirectionType   direction);
295 static void     gtk_container_real_set_focus_child (GtkContainer      *container,
296                                                     GtkWidget         *widget);
297
298 static gboolean gtk_container_focus_move           (GtkContainer      *container,
299                                                     GList             *children,
300                                                     GtkDirectionType   direction);
301 static void     gtk_container_children_callback    (GtkWidget         *widget,
302                                                     gpointer           client_data);
303 static void     gtk_container_show_all             (GtkWidget         *widget);
304 static gint     gtk_container_draw                 (GtkWidget         *widget,
305                                                     cairo_t           *cr);
306 static void     gtk_container_map                  (GtkWidget         *widget);
307 static void     gtk_container_unmap                (GtkWidget         *widget);
308 static void     gtk_container_adjust_size_request  (GtkWidget         *widget,
309                                                     GtkOrientation     orientation,
310                                                     gint              *minimum_size,
311                                                     gint              *natural_size);
312 static void     gtk_container_adjust_size_allocation (GtkWidget       *widget,
313                                                       GtkOrientation   orientation,
314                                                       gint            *minimum_size,
315                                                       gint            *natural_size,
316                                                       gint            *allocated_pos,
317                                                       gint            *allocated_size);
318 static GtkSizeRequestMode gtk_container_get_request_mode (GtkWidget   *widget);
319
320 static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
321                                                           GtkWidget    *child);
322
323 static GtkWidgetPath * gtk_container_real_get_path_for_child (GtkContainer *container,
324                                                               GtkWidget    *child);
325
326 /* GtkBuildable */
327 static void gtk_container_buildable_init           (GtkBuildableIface *iface);
328 static void gtk_container_buildable_add_child      (GtkBuildable *buildable,
329                                                     GtkBuilder   *builder,
330                                                     GObject      *child,
331                                                     const gchar  *type);
332 static gboolean gtk_container_buildable_custom_tag_start (GtkBuildable  *buildable,
333                                                           GtkBuilder    *builder,
334                                                           GObject       *child,
335                                                           const gchar   *tagname,
336                                                           GMarkupParser *parser,
337                                                           gpointer      *data);
338 static void    gtk_container_buildable_custom_tag_end (GtkBuildable *buildable,
339                                                        GtkBuilder   *builder,
340                                                        GObject      *child,
341                                                        const gchar  *tagname,
342                                                        gpointer     *data);
343
344
345 /* --- variables --- */
346 static const gchar           vadjustment_key[] = "gtk-vadjustment";
347 static guint                 vadjustment_key_id = 0;
348 static const gchar           hadjustment_key[] = "gtk-hadjustment";
349 static guint                 hadjustment_key_id = 0;
350 static guint                 container_signals[LAST_SIGNAL] = { 0 };
351 static GtkWidgetClass       *parent_class = NULL;
352 extern GParamSpecPool       *_gtk_widget_child_property_pool;
353 extern GObjectNotifyContext *_gtk_widget_child_property_notify_context;
354 static GtkBuildableIface    *parent_buildable_iface;
355
356
357 /* --- functions --- */
358 GType
359 gtk_container_get_type (void)
360 {
361   static GType container_type = 0;
362
363   if (!container_type)
364     {
365       const GTypeInfo container_info =
366       {
367         sizeof (GtkContainerClass),
368         (GBaseInitFunc) gtk_container_base_class_init,
369         (GBaseFinalizeFunc) gtk_container_base_class_finalize,
370         (GClassInitFunc) gtk_container_class_init,
371         NULL        /* class_finalize */,
372         NULL        /* class_data */,
373         sizeof (GtkContainer),
374         0           /* n_preallocs */,
375         (GInstanceInitFunc) gtk_container_init,
376         NULL,       /* value_table */
377       };
378
379       const GInterfaceInfo buildable_info =
380       {
381         (GInterfaceInitFunc) gtk_container_buildable_init,
382         NULL,
383         NULL
384       };
385
386       container_type =
387         g_type_register_static (GTK_TYPE_WIDGET, I_("GtkContainer"),
388                                 &container_info, G_TYPE_FLAG_ABSTRACT);
389
390       g_type_add_interface_static (container_type,
391                                    GTK_TYPE_BUILDABLE,
392                                    &buildable_info);
393
394     }
395
396   return container_type;
397 }
398
399 static void
400 gtk_container_base_class_init (GtkContainerClass *class)
401 {
402   /* reset instance specifc class fields that don't get inherited */
403   class->set_child_property = NULL;
404   class->get_child_property = NULL;
405 }
406
407 static void
408 gtk_container_base_class_finalize (GtkContainerClass *class)
409 {
410   GList *list, *node;
411
412   list = g_param_spec_pool_list_owned (_gtk_widget_child_property_pool, G_OBJECT_CLASS_TYPE (class));
413   for (node = list; node; node = node->next)
414     {
415       GParamSpec *pspec = node->data;
416
417       g_param_spec_pool_remove (_gtk_widget_child_property_pool, pspec);
418       PARAM_SPEC_SET_PARAM_ID (pspec, 0);
419       g_param_spec_unref (pspec);
420     }
421   g_list_free (list);
422 }
423
424 static void
425 gtk_container_class_init (GtkContainerClass *class)
426 {
427   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
428   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
429
430   parent_class = g_type_class_peek_parent (class);
431
432   vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
433   hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
434
435   gobject_class->set_property = gtk_container_set_property;
436   gobject_class->get_property = gtk_container_get_property;
437
438   widget_class->destroy = gtk_container_destroy;
439   widget_class->compute_expand = gtk_container_compute_expand;
440   widget_class->show_all = gtk_container_show_all;
441   widget_class->draw = gtk_container_draw;
442   widget_class->map = gtk_container_map;
443   widget_class->unmap = gtk_container_unmap;
444   widget_class->focus = gtk_container_focus;
445
446   widget_class->adjust_size_request = gtk_container_adjust_size_request;
447   widget_class->adjust_size_allocation = gtk_container_adjust_size_allocation;
448   widget_class->get_request_mode = gtk_container_get_request_mode;
449
450   class->add = gtk_container_add_unimplemented;
451   class->remove = gtk_container_remove_unimplemented;
452   class->check_resize = gtk_container_real_check_resize;
453   class->forall = NULL;
454   class->set_focus_child = gtk_container_real_set_focus_child;
455   class->child_type = NULL;
456   class->composite_name = gtk_container_child_default_composite_name;
457   class->get_path_for_child = gtk_container_real_get_path_for_child;
458
459   g_object_class_install_property (gobject_class,
460                                    PROP_RESIZE_MODE,
461                                    g_param_spec_enum ("resize-mode",
462                                                       P_("Resize mode"),
463                                                       P_("Specify how resize events are handled"),
464                                                       GTK_TYPE_RESIZE_MODE,
465                                                       GTK_RESIZE_PARENT,
466                                                       GTK_PARAM_READWRITE));
467   g_object_class_install_property (gobject_class,
468                                    PROP_BORDER_WIDTH,
469                                    g_param_spec_uint ("border-width",
470                                                       P_("Border width"),
471                                                       P_("The width of the empty border outside the containers children"),
472                                                       0,
473                                                       65535,
474                                                       0,
475                                                       GTK_PARAM_READWRITE));
476   g_object_class_install_property (gobject_class,
477                                    PROP_CHILD,
478                                    g_param_spec_object ("child",
479                                                       P_("Child"),
480                                                       P_("Can be used to add a new child to the container"),
481                                                       GTK_TYPE_WIDGET,
482                                                       GTK_PARAM_WRITABLE));
483   container_signals[ADD] =
484     g_signal_new (I_("add"),
485                   G_OBJECT_CLASS_TYPE (gobject_class),
486                   G_SIGNAL_RUN_FIRST,
487                   G_STRUCT_OFFSET (GtkContainerClass, add),
488                   NULL, NULL,
489                   _gtk_marshal_VOID__OBJECT,
490                   G_TYPE_NONE, 1,
491                   GTK_TYPE_WIDGET);
492   container_signals[REMOVE] =
493     g_signal_new (I_("remove"),
494                   G_OBJECT_CLASS_TYPE (gobject_class),
495                   G_SIGNAL_RUN_FIRST,
496                   G_STRUCT_OFFSET (GtkContainerClass, remove),
497                   NULL, NULL,
498                   _gtk_marshal_VOID__OBJECT,
499                   G_TYPE_NONE, 1,
500                   GTK_TYPE_WIDGET);
501   container_signals[CHECK_RESIZE] =
502     g_signal_new (I_("check-resize"),
503                   G_OBJECT_CLASS_TYPE (gobject_class),
504                   G_SIGNAL_RUN_LAST,
505                   G_STRUCT_OFFSET (GtkContainerClass, check_resize),
506                   NULL, NULL,
507                   _gtk_marshal_VOID__VOID,
508                   G_TYPE_NONE, 0);
509   container_signals[SET_FOCUS_CHILD] =
510     g_signal_new (I_("set-focus-child"),
511                   G_OBJECT_CLASS_TYPE (gobject_class),
512                   G_SIGNAL_RUN_FIRST,
513                   G_STRUCT_OFFSET (GtkContainerClass, set_focus_child),
514                   NULL, NULL,
515                   _gtk_marshal_VOID__OBJECT,
516                   G_TYPE_NONE, 1,
517                   GTK_TYPE_WIDGET);
518
519   g_type_class_add_private (class, sizeof (GtkContainerPrivate));
520
521   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_CONTAINER_ACCESSIBLE);
522 }
523
524 static void
525 gtk_container_buildable_init (GtkBuildableIface *iface)
526 {
527   parent_buildable_iface = g_type_interface_peek_parent (iface);
528   iface->add_child = gtk_container_buildable_add_child;
529   iface->custom_tag_start = gtk_container_buildable_custom_tag_start;
530   iface->custom_tag_end = gtk_container_buildable_custom_tag_end;
531 }
532
533 static void
534 gtk_container_buildable_add_child (GtkBuildable  *buildable,
535                                    GtkBuilder    *builder,
536                                    GObject       *child,
537                                    const gchar   *type)
538 {
539   if (type)
540     {
541       GTK_BUILDER_WARN_INVALID_CHILD_TYPE (buildable, type);
542     }
543   else if (GTK_IS_WIDGET (child) &&
544            gtk_widget_get_parent (GTK_WIDGET (child)) == NULL)
545     {
546       gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child));
547     }
548   else
549     g_warning ("Cannot add an object of type %s to a container of type %s",
550                g_type_name (G_OBJECT_TYPE (child)), g_type_name (G_OBJECT_TYPE (buildable)));
551 }
552
553 static void
554 gtk_container_buildable_set_child_property (GtkContainer *container,
555                                             GtkBuilder   *builder,
556                                             GtkWidget    *child,
557                                             gchar        *name,
558                                             const gchar  *value)
559 {
560   GParamSpec *pspec;
561   GValue gvalue = G_VALUE_INIT;
562   GError *error = NULL;
563
564   pspec = gtk_container_class_find_child_property
565     (G_OBJECT_GET_CLASS (container), name);
566   if (!pspec)
567     {
568       g_warning ("%s does not have a property called %s",
569                  g_type_name (G_OBJECT_TYPE (container)), name);
570       return;
571     }
572
573   if (!gtk_builder_value_from_string (builder, pspec, value, &gvalue, &error))
574     {
575       g_warning ("Could not read property %s:%s with value %s of type %s: %s",
576                  g_type_name (G_OBJECT_TYPE (container)),
577                  name,
578                  value,
579                  g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
580                  error->message);
581       g_error_free (error);
582       return;
583     }
584
585   gtk_container_child_set_property (container, child, name, &gvalue);
586   g_value_unset (&gvalue);
587 }
588
589 typedef struct {
590   GtkBuilder   *builder;
591   GtkContainer *container;
592   GtkWidget    *child;
593   GString      *string;
594   gchar        *child_prop_name;
595   gchar        *context;
596   gboolean      translatable;
597 } PackingPropertiesData;
598
599 static void
600 attributes_start_element (GMarkupParseContext *context,
601                           const gchar         *element_name,
602                           const gchar        **names,
603                           const gchar        **values,
604                           gpointer             user_data,
605                           GError             **error)
606 {
607   PackingPropertiesData *parser_data = (PackingPropertiesData*)user_data;
608   guint i;
609
610   if (strcmp (element_name, "property") == 0)
611     {
612       for (i = 0; names[i]; i++)
613         if (strcmp (names[i], "name") == 0)
614           parser_data->child_prop_name = g_strdup (values[i]);
615         else if (strcmp (names[i], "translatable") == 0)
616           {
617             if (!_gtk_builder_boolean_from_string (values[1],
618                                                    &parser_data->translatable,
619                                                    error))
620               return;
621           }
622         else if (strcmp (names[i], "comments") == 0)
623           ; /* for translators */
624         else if (strcmp (names[i], "context") == 0)
625           parser_data->context = g_strdup (values[1]);
626         else
627           g_warning ("Unsupported attribute for GtkContainer Child "
628                      "property: %s\n", names[i]);
629     }
630   else if (strcmp (element_name, "packing") == 0)
631     return;
632   else
633     g_warning ("Unsupported tag for GtkContainer: %s\n", element_name);
634 }
635
636 static void
637 attributes_text_element (GMarkupParseContext *context,
638                          const gchar         *text,
639                          gsize                text_len,
640                          gpointer             user_data,
641                          GError             **error)
642 {
643   PackingPropertiesData *parser_data = (PackingPropertiesData*)user_data;
644
645   if (parser_data->child_prop_name)
646     g_string_append_len (parser_data->string, text, text_len);
647 }
648
649 static void
650 attributes_end_element (GMarkupParseContext *context,
651                         const gchar         *element_name,
652                         gpointer             user_data,
653                         GError             **error)
654 {
655   PackingPropertiesData *parser_data = (PackingPropertiesData*)user_data;
656
657   /* translate the string */
658   if (parser_data->string->len && parser_data->translatable)
659     {
660       gchar *translated;
661       const gchar* domain;
662
663       domain = gtk_builder_get_translation_domain (parser_data->builder);
664
665       translated = _gtk_builder_parser_translate (domain,
666                                                   parser_data->context,
667                                                   parser_data->string->str);
668       g_string_set_size (parser_data->string, 0);
669       g_string_append (parser_data->string, translated);
670     }
671
672   if (parser_data->child_prop_name)
673     gtk_container_buildable_set_child_property (parser_data->container,
674                                                 parser_data->builder,
675                                                 parser_data->child,
676                                                 parser_data->child_prop_name,
677                                                 parser_data->string->str);
678
679   g_string_set_size (parser_data->string, 0);
680   g_free (parser_data->child_prop_name);
681   g_free (parser_data->context);
682   parser_data->child_prop_name = NULL;
683   parser_data->context = NULL;
684   parser_data->translatable = FALSE;
685 }
686
687 static const GMarkupParser attributes_parser =
688   {
689     attributes_start_element,
690     attributes_end_element,
691     attributes_text_element,
692   };
693
694 static gboolean
695 gtk_container_buildable_custom_tag_start (GtkBuildable  *buildable,
696                                           GtkBuilder    *builder,
697                                           GObject       *child,
698                                           const gchar   *tagname,
699                                           GMarkupParser *parser,
700                                           gpointer      *data)
701 {
702   PackingPropertiesData *parser_data;
703
704   if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
705                                                 tagname, parser, data))
706     return TRUE;
707
708   if (child && strcmp (tagname, "packing") == 0)
709     {
710       parser_data = g_slice_new0 (PackingPropertiesData);
711       parser_data->string = g_string_new ("");
712       parser_data->builder = builder;
713       parser_data->container = GTK_CONTAINER (buildable);
714       parser_data->child = GTK_WIDGET (child);
715       parser_data->child_prop_name = NULL;
716
717       *parser = attributes_parser;
718       *data = parser_data;
719       return TRUE;
720     }
721
722   return FALSE;
723 }
724
725 static void
726 gtk_container_buildable_custom_tag_end (GtkBuildable *buildable,
727                                         GtkBuilder   *builder,
728                                         GObject      *child,
729                                         const gchar  *tagname,
730                                         gpointer     *data)
731 {
732   if (strcmp (tagname, "packing") == 0)
733     {
734       PackingPropertiesData *parser_data = (PackingPropertiesData*)data;
735       g_string_free (parser_data->string, TRUE);
736       g_slice_free (PackingPropertiesData, parser_data);
737       return;
738     }
739
740   if (parent_buildable_iface->custom_tag_end)
741     parent_buildable_iface->custom_tag_end (buildable, builder,
742                                             child, tagname, data);
743 }
744
745 /**
746  * gtk_container_child_type:
747  * @container: a #GtkContainer
748  *
749  * Returns the type of the children supported by the container.
750  *
751  * Note that this may return %G_TYPE_NONE to indicate that no more
752  * children can be added, e.g. for a #GtkPaned which already has two
753  * children.
754  *
755  * Return value: a #GType.
756  **/
757 GType
758 gtk_container_child_type (GtkContainer *container)
759 {
760   GType slot;
761   GtkContainerClass *class;
762
763   g_return_val_if_fail (GTK_IS_CONTAINER (container), 0);
764
765   class = GTK_CONTAINER_GET_CLASS (container);
766   if (class->child_type)
767     slot = class->child_type (container);
768   else
769     slot = G_TYPE_NONE;
770
771   return slot;
772 }
773
774 /* --- GtkContainer child property mechanism --- */
775
776 /**
777  * gtk_container_child_notify:
778  * @container: the #GtkContainer
779  * @child: the child widget
780  * @child_property: the name of a child property installed on
781  *     the class of @container
782  *
783  * Emits a #GtkWidget::child-notify signal for the
784  * <link linkend="child-properties">child property</link>
785  * @child_property on widget.
786  *
787  * This is an analogue of g_object_notify() for child properties.
788  *
789  * Also see gtk_widget_child_notify().
790  *
791  * Since: 3.2
792  */
793 void
794 gtk_container_child_notify (GtkContainer *container,
795                             GtkWidget    *child,
796                             const gchar  *child_property)
797 {
798   GObject *obj;
799   GParamSpec *pspec;
800
801   g_return_if_fail (GTK_IS_CONTAINER (container));
802   g_return_if_fail (GTK_IS_WIDGET (child));
803   g_return_if_fail (child_property != NULL);
804
805   obj = G_OBJECT (child);
806
807   if (obj->ref_count == 0)
808     return;
809
810   g_object_ref (obj);
811
812   pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool,
813                                     child_property,
814                                     G_OBJECT_TYPE (container),
815                                     TRUE);
816
817   if (pspec == NULL)
818     {
819       g_warning ("%s: container class `%s' has no child property named `%s'",
820                  G_STRLOC,
821                  G_OBJECT_TYPE_NAME (container),
822                  child_property);
823     }
824   else
825     {
826       GObjectNotifyQueue *nqueue;
827
828       nqueue = g_object_notify_queue_freeze (obj, _gtk_widget_child_property_notify_context);
829
830       g_object_notify_queue_add (obj, nqueue, pspec);
831       g_object_notify_queue_thaw (obj, nqueue);
832     }
833
834   g_object_unref (obj);
835 }
836
837 static inline void
838 container_get_child_property (GtkContainer *container,
839                               GtkWidget    *child,
840                               GParamSpec   *pspec,
841                               GValue       *value)
842 {
843   GtkContainerClass *class = g_type_class_peek (pspec->owner_type);
844
845   class->get_child_property (container, child, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
846 }
847
848 static inline void
849 container_set_child_property (GtkContainer       *container,
850                               GtkWidget          *child,
851                               GParamSpec         *pspec,
852                               const GValue       *value,
853                               GObjectNotifyQueue *nqueue)
854 {
855   GValue tmp_value = G_VALUE_INIT;
856   GtkContainerClass *class = g_type_class_peek (pspec->owner_type);
857
858   /* provide a copy to work from, convert (if necessary) and validate */
859   g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
860   if (!g_value_transform (value, &tmp_value))
861     g_warning ("unable to set child property `%s' of type `%s' from value of type `%s'",
862                pspec->name,
863                g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
864                G_VALUE_TYPE_NAME (value));
865   else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
866     {
867       gchar *contents = g_strdup_value_contents (value);
868
869       g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
870                  contents,
871                  G_VALUE_TYPE_NAME (value),
872                  pspec->name,
873                  g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
874       g_free (contents);
875     }
876   else
877     {
878       class->set_child_property (container, child, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
879       g_object_notify_queue_add (G_OBJECT (child), nqueue, pspec);
880     }
881   g_value_unset (&tmp_value);
882 }
883
884 /**
885  * gtk_container_child_get_valist:
886  * @container: a #GtkContainer
887  * @child: a widget which is a child of @container
888  * @first_property_name: the name of the first property to get
889  * @var_args: return location for the first property, followed
890  *     optionally by more name/return location pairs, followed by %NULL
891  *
892  * Gets the values of one or more child properties for @child and @container.
893  **/
894 void
895 gtk_container_child_get_valist (GtkContainer *container,
896                                 GtkWidget    *child,
897                                 const gchar  *first_property_name,
898                                 va_list       var_args)
899 {
900   const gchar *name;
901
902   g_return_if_fail (GTK_IS_CONTAINER (container));
903   g_return_if_fail (GTK_IS_WIDGET (child));
904
905   g_object_ref (container);
906   g_object_ref (child);
907
908   name = first_property_name;
909   while (name)
910     {
911       GValue value = G_VALUE_INIT;
912       GParamSpec *pspec;
913       gchar *error;
914
915       pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool,
916                                         name,
917                                         G_OBJECT_TYPE (container),
918                                         TRUE);
919       if (!pspec)
920         {
921           g_warning ("%s: container class `%s' has no child property named `%s'",
922                      G_STRLOC,
923                      G_OBJECT_TYPE_NAME (container),
924                      name);
925           break;
926         }
927       if (!(pspec->flags & G_PARAM_READABLE))
928         {
929           g_warning ("%s: child property `%s' of container class `%s' is not readable",
930                      G_STRLOC,
931                      pspec->name,
932                      G_OBJECT_TYPE_NAME (container));
933           break;
934         }
935       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
936       container_get_child_property (container, child, pspec, &value);
937       G_VALUE_LCOPY (&value, var_args, 0, &error);
938       if (error)
939         {
940           g_warning ("%s: %s", G_STRLOC, error);
941           g_free (error);
942           g_value_unset (&value);
943           break;
944         }
945       g_value_unset (&value);
946       name = va_arg (var_args, gchar*);
947     }
948
949   g_object_unref (child);
950   g_object_unref (container);
951 }
952
953 /**
954  * gtk_container_child_get_property:
955  * @container: a #GtkContainer
956  * @child: a widget which is a child of @container
957  * @property_name: the name of the property to get
958  * @value: a location to return the value
959  *
960  * Gets the value of a child property for @child and @container.
961  **/
962 void
963 gtk_container_child_get_property (GtkContainer *container,
964                                   GtkWidget    *child,
965                                   const gchar  *property_name,
966                                   GValue       *value)
967 {
968   GParamSpec *pspec;
969
970   g_return_if_fail (GTK_IS_CONTAINER (container));
971   g_return_if_fail (GTK_IS_WIDGET (child));
972   g_return_if_fail (property_name != NULL);
973   g_return_if_fail (G_IS_VALUE (value));
974
975   g_object_ref (container);
976   g_object_ref (child);
977   pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool, property_name,
978                                     G_OBJECT_TYPE (container), TRUE);
979   if (!pspec)
980     g_warning ("%s: container class `%s' has no child property named `%s'",
981                G_STRLOC,
982                G_OBJECT_TYPE_NAME (container),
983                property_name);
984   else if (!(pspec->flags & G_PARAM_READABLE))
985     g_warning ("%s: child property `%s' of container class `%s' is not readable",
986                G_STRLOC,
987                pspec->name,
988                G_OBJECT_TYPE_NAME (container));
989   else
990     {
991       GValue *prop_value, tmp_value = G_VALUE_INIT;
992
993       /* auto-conversion of the callers value type
994        */
995       if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
996         {
997           g_value_reset (value);
998           prop_value = value;
999         }
1000       else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
1001         {
1002           g_warning ("can't retrieve child property `%s' of type `%s' as value of type `%s'",
1003                      pspec->name,
1004                      g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1005                      G_VALUE_TYPE_NAME (value));
1006           g_object_unref (child);
1007           g_object_unref (container);
1008           return;
1009         }
1010       else
1011         {
1012           g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1013           prop_value = &tmp_value;
1014         }
1015       container_get_child_property (container, child, pspec, prop_value);
1016       if (prop_value != value)
1017         {
1018           g_value_transform (prop_value, value);
1019           g_value_unset (&tmp_value);
1020         }
1021     }
1022   g_object_unref (child);
1023   g_object_unref (container);
1024 }
1025
1026 /**
1027  * gtk_container_child_set_valist:
1028  * @container: a #GtkContainer
1029  * @child: a widget which is a child of @container
1030  * @first_property_name: the name of the first property to set
1031  * @var_args: a %NULL-terminated list of property names and values, starting
1032  *           with @first_prop_name
1033  *
1034  * Sets one or more child properties for @child and @container.
1035  **/
1036 void
1037 gtk_container_child_set_valist (GtkContainer *container,
1038                                 GtkWidget    *child,
1039                                 const gchar  *first_property_name,
1040                                 va_list       var_args)
1041 {
1042   GObjectNotifyQueue *nqueue;
1043   const gchar *name;
1044
1045   g_return_if_fail (GTK_IS_CONTAINER (container));
1046   g_return_if_fail (GTK_IS_WIDGET (child));
1047
1048   g_object_ref (container);
1049   g_object_ref (child);
1050
1051   nqueue = g_object_notify_queue_freeze (G_OBJECT (child), _gtk_widget_child_property_notify_context);
1052   name = first_property_name;
1053   while (name)
1054     {
1055       GValue value = G_VALUE_INIT;
1056       gchar *error = NULL;
1057       GParamSpec *pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool,
1058                                                     name,
1059                                                     G_OBJECT_TYPE (container),
1060                                                     TRUE);
1061       if (!pspec)
1062         {
1063           g_warning ("%s: container class `%s' has no child property named `%s'",
1064                      G_STRLOC,
1065                      G_OBJECT_TYPE_NAME (container),
1066                      name);
1067           break;
1068         }
1069       if (!(pspec->flags & G_PARAM_WRITABLE))
1070         {
1071           g_warning ("%s: child property `%s' of container class `%s' is not writable",
1072                      G_STRLOC,
1073                      pspec->name,
1074                      G_OBJECT_TYPE_NAME (container));
1075           break;
1076         }
1077
1078       G_VALUE_COLLECT_INIT (&value, G_PARAM_SPEC_VALUE_TYPE (pspec),
1079                             var_args, 0, &error);
1080       if (error)
1081         {
1082           g_warning ("%s: %s", G_STRLOC, error);
1083           g_free (error);
1084
1085           /* we purposely leak the value here, it might not be
1086            * in a sane state if an error condition occoured
1087            */
1088           break;
1089         }
1090       container_set_child_property (container, child, pspec, &value, nqueue);
1091       g_value_unset (&value);
1092       name = va_arg (var_args, gchar*);
1093     }
1094   g_object_notify_queue_thaw (G_OBJECT (child), nqueue);
1095
1096   g_object_unref (container);
1097   g_object_unref (child);
1098 }
1099
1100 /**
1101  * gtk_container_child_set_property:
1102  * @container: a #GtkContainer
1103  * @child: a widget which is a child of @container
1104  * @property_name: the name of the property to set
1105  * @value: the value to set the property to
1106  *
1107  * Sets a child property for @child and @container.
1108  **/
1109 void
1110 gtk_container_child_set_property (GtkContainer *container,
1111                                   GtkWidget    *child,
1112                                   const gchar  *property_name,
1113                                   const GValue *value)
1114 {
1115   GObjectNotifyQueue *nqueue;
1116   GParamSpec *pspec;
1117
1118   g_return_if_fail (GTK_IS_CONTAINER (container));
1119   g_return_if_fail (GTK_IS_WIDGET (child));
1120   g_return_if_fail (property_name != NULL);
1121   g_return_if_fail (G_IS_VALUE (value));
1122
1123   g_object_ref (container);
1124   g_object_ref (child);
1125
1126   nqueue = g_object_notify_queue_freeze (G_OBJECT (child), _gtk_widget_child_property_notify_context);
1127   pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool, property_name,
1128                                     G_OBJECT_TYPE (container), TRUE);
1129   if (!pspec)
1130     g_warning ("%s: container class `%s' has no child property named `%s'",
1131                G_STRLOC,
1132                G_OBJECT_TYPE_NAME (container),
1133                property_name);
1134   else if (!(pspec->flags & G_PARAM_WRITABLE))
1135     g_warning ("%s: child property `%s' of container class `%s' is not writable",
1136                G_STRLOC,
1137                pspec->name,
1138                G_OBJECT_TYPE_NAME (container));
1139   else
1140     {
1141       container_set_child_property (container, child, pspec, value, nqueue);
1142     }
1143   g_object_notify_queue_thaw (G_OBJECT (child), nqueue);
1144   g_object_unref (container);
1145   g_object_unref (child);
1146 }
1147
1148 /**
1149  * gtk_container_add_with_properties:
1150  * @container: a #GtkContainer
1151  * @widget: a widget to be placed inside @container
1152  * @first_prop_name: the name of the first child property to set
1153  * @...: a %NULL-terminated list of property names and values, starting
1154  *     with @first_prop_name
1155  *
1156  * Adds @widget to @container, setting child properties at the same time.
1157  * See gtk_container_add() and gtk_container_child_set() for more details.
1158  */
1159 void
1160 gtk_container_add_with_properties (GtkContainer *container,
1161                                    GtkWidget    *widget,
1162                                    const gchar  *first_prop_name,
1163                                    ...)
1164 {
1165   g_return_if_fail (GTK_IS_CONTAINER (container));
1166   g_return_if_fail (GTK_IS_WIDGET (widget));
1167   g_return_if_fail (gtk_widget_get_parent (widget) == NULL);
1168
1169   g_object_ref (container);
1170   g_object_ref (widget);
1171   gtk_widget_freeze_child_notify (widget);
1172
1173   g_signal_emit (container, container_signals[ADD], 0, widget);
1174   if (gtk_widget_get_parent (widget))
1175     {
1176       va_list var_args;
1177
1178       va_start (var_args, first_prop_name);
1179       gtk_container_child_set_valist (container, widget, first_prop_name, var_args);
1180       va_end (var_args);
1181     }
1182
1183   gtk_widget_thaw_child_notify (widget);
1184   g_object_unref (widget);
1185   g_object_unref (container);
1186 }
1187
1188 /**
1189  * gtk_container_child_set:
1190  * @container: a #GtkContainer
1191  * @child: a widget which is a child of @container
1192  * @first_prop_name: the name of the first property to set
1193  * @...: a %NULL-terminated list of property names and values, starting
1194  *     with @first_prop_name
1195  *
1196  * Sets one or more child properties for @child and @container.
1197  */
1198 void
1199 gtk_container_child_set (GtkContainer      *container,
1200                          GtkWidget         *child,
1201                          const gchar       *first_prop_name,
1202                          ...)
1203 {
1204   va_list var_args;
1205
1206   va_start (var_args, first_prop_name);
1207   gtk_container_child_set_valist (container, child, first_prop_name, var_args);
1208   va_end (var_args);
1209 }
1210
1211 /**
1212  * gtk_container_child_get:
1213  * @container: a #GtkContainer
1214  * @child: a widget which is a child of @container
1215  * @first_prop_name: the name of the first property to get
1216  * @...: return location for the first property, followed
1217  *     optionally by more name/return location pairs, followed by %NULL
1218  *
1219  * Gets the values of one or more child properties for @child and @container.
1220  */
1221 void
1222 gtk_container_child_get (GtkContainer      *container,
1223                          GtkWidget         *child,
1224                          const gchar       *first_prop_name,
1225                          ...)
1226 {
1227   va_list var_args;
1228
1229   va_start (var_args, first_prop_name);
1230   gtk_container_child_get_valist (container, child, first_prop_name, var_args);
1231   va_end (var_args);
1232 }
1233
1234 /**
1235  * gtk_container_class_install_child_property:
1236  * @cclass: a #GtkContainerClass
1237  * @property_id: the id for the property
1238  * @pspec: the #GParamSpec for the property
1239  *
1240  * Installs a child property on a container class.
1241  **/
1242 void
1243 gtk_container_class_install_child_property (GtkContainerClass *cclass,
1244                                             guint              property_id,
1245                                             GParamSpec        *pspec)
1246 {
1247   g_return_if_fail (GTK_IS_CONTAINER_CLASS (cclass));
1248   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1249   if (pspec->flags & G_PARAM_WRITABLE)
1250     g_return_if_fail (cclass->set_child_property != NULL);
1251   if (pspec->flags & G_PARAM_READABLE)
1252     g_return_if_fail (cclass->get_child_property != NULL);
1253   g_return_if_fail (property_id > 0);
1254   g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0);  /* paranoid */
1255   if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))
1256     g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
1257
1258   if (g_param_spec_pool_lookup (_gtk_widget_child_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (cclass), FALSE))
1259     {
1260       g_warning (G_STRLOC ": class `%s' already contains a child property named `%s'",
1261                  G_OBJECT_CLASS_NAME (cclass),
1262                  pspec->name);
1263       return;
1264     }
1265   g_param_spec_ref (pspec);
1266   g_param_spec_sink (pspec);
1267   PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
1268   g_param_spec_pool_insert (_gtk_widget_child_property_pool, pspec, G_OBJECT_CLASS_TYPE (cclass));
1269 }
1270
1271 /**
1272  * gtk_container_class_find_child_property:
1273  * @cclass: (type GtkContainerClass): a #GtkContainerClass
1274  * @property_name: the name of the child property to find
1275  *
1276  * Finds a child property of a container class by name.
1277  *
1278  * Returns: (transfer none): the #GParamSpec of the child property
1279  *     or %NULL if @class has no child property with that name.
1280  */
1281 GParamSpec*
1282 gtk_container_class_find_child_property (GObjectClass *cclass,
1283                                          const gchar  *property_name)
1284 {
1285   g_return_val_if_fail (GTK_IS_CONTAINER_CLASS (cclass), NULL);
1286   g_return_val_if_fail (property_name != NULL, NULL);
1287
1288   return g_param_spec_pool_lookup (_gtk_widget_child_property_pool,
1289                                    property_name,
1290                                    G_OBJECT_CLASS_TYPE (cclass),
1291                                    TRUE);
1292 }
1293
1294 /**
1295  * gtk_container_class_list_child_properties:
1296  * @cclass: (type GtkContainerClass): a #GtkContainerClass
1297  * @n_properties: location to return the number of child properties found
1298  *
1299  * Returns all child properties of a container class.
1300  *
1301  * Returns: (array length=n_properties) (transfer container):
1302  *     a newly allocated %NULL-terminated array of #GParamSpec*.
1303  *     The array must be freed with g_free().
1304  */
1305 GParamSpec**
1306 gtk_container_class_list_child_properties (GObjectClass *cclass,
1307                                            guint        *n_properties)
1308 {
1309   GParamSpec **pspecs;
1310   guint n;
1311
1312   g_return_val_if_fail (GTK_IS_CONTAINER_CLASS (cclass), NULL);
1313
1314   pspecs = g_param_spec_pool_list (_gtk_widget_child_property_pool,
1315                                    G_OBJECT_CLASS_TYPE (cclass),
1316                                    &n);
1317   if (n_properties)
1318     *n_properties = n;
1319
1320   return pspecs;
1321 }
1322
1323 static void
1324 gtk_container_add_unimplemented (GtkContainer     *container,
1325                                  GtkWidget        *widget)
1326 {
1327   g_warning ("GtkContainerClass::add not implemented for `%s'", g_type_name (G_TYPE_FROM_INSTANCE (container)));
1328 }
1329
1330 static void
1331 gtk_container_remove_unimplemented (GtkContainer     *container,
1332                                     GtkWidget        *widget)
1333 {
1334   g_warning ("GtkContainerClass::remove not implemented for `%s'", g_type_name (G_TYPE_FROM_INSTANCE (container)));
1335 }
1336
1337 static void
1338 gtk_container_init (GtkContainer *container)
1339 {
1340   GtkContainerPrivate *priv;
1341
1342   container->priv = G_TYPE_INSTANCE_GET_PRIVATE (container,
1343                                                  GTK_TYPE_CONTAINER,
1344                                                  GtkContainerPrivate);
1345   priv = container->priv;
1346
1347   priv->focus_child = NULL;
1348   priv->border_width = 0;
1349   priv->resize_mode = GTK_RESIZE_PARENT;
1350   priv->reallocate_redraws = FALSE;
1351 }
1352
1353 static void
1354 gtk_container_destroy (GtkWidget *widget)
1355 {
1356   GtkContainer *container = GTK_CONTAINER (widget);
1357   GtkContainerPrivate *priv = container->priv;
1358
1359   if (priv->resize_pending)
1360     _gtk_container_dequeue_resize_handler (container);
1361
1362   if (priv->restyle_pending)
1363     priv->restyle_pending = FALSE;
1364
1365   if (priv->resize_handler)
1366     {
1367       g_signal_handler_disconnect (priv->resize_clock, priv->resize_handler);
1368       priv->resize_handler = 0;
1369       priv->resize_clock = NULL;
1370     }
1371
1372   if (priv->focus_child)
1373     {
1374       g_object_unref (priv->focus_child);
1375       priv->focus_child = NULL;
1376     }
1377
1378   /* do this before walking child widgets, to avoid
1379    * removing children from focus chain one by one.
1380    */
1381   if (priv->has_focus_chain)
1382     gtk_container_unset_focus_chain (container);
1383
1384   gtk_container_foreach (container, (GtkCallback) gtk_widget_destroy, NULL);
1385
1386   GTK_WIDGET_CLASS (parent_class)->destroy (widget);
1387 }
1388
1389 static void
1390 gtk_container_set_property (GObject         *object,
1391                             guint            prop_id,
1392                             const GValue    *value,
1393                             GParamSpec      *pspec)
1394 {
1395   GtkContainer *container = GTK_CONTAINER (object);
1396
1397   switch (prop_id)
1398     {
1399     case PROP_BORDER_WIDTH:
1400       gtk_container_set_border_width (container, g_value_get_uint (value));
1401       break;
1402     case PROP_RESIZE_MODE:
1403       gtk_container_set_resize_mode (container, g_value_get_enum (value));
1404       break;
1405     case PROP_CHILD:
1406       gtk_container_add (container, GTK_WIDGET (g_value_get_object (value)));
1407       break;
1408     default:
1409       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1410       break;
1411     }
1412 }
1413
1414 static void
1415 gtk_container_get_property (GObject         *object,
1416                             guint            prop_id,
1417                             GValue          *value,
1418                             GParamSpec      *pspec)
1419 {
1420   GtkContainer *container = GTK_CONTAINER (object);
1421   GtkContainerPrivate *priv = container->priv;
1422
1423   switch (prop_id)
1424     {
1425     case PROP_BORDER_WIDTH:
1426       g_value_set_uint (value, priv->border_width);
1427       break;
1428     case PROP_RESIZE_MODE:
1429       g_value_set_enum (value, priv->resize_mode);
1430       break;
1431     default:
1432       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1433       break;
1434     }
1435 }
1436
1437 /**
1438  * gtk_container_set_border_width:
1439  * @container: a #GtkContainer
1440  * @border_width: amount of blank space to leave <emphasis>outside</emphasis>
1441  *   the container. Valid values are in the range 0-65535 pixels.
1442  *
1443  * Sets the border width of the container.
1444  *
1445  * The border width of a container is the amount of space to leave
1446  * around the outside of the container. The only exception to this is
1447  * #GtkWindow; because toplevel windows can't leave space outside,
1448  * they leave the space inside. The border is added on all sides of
1449  * the container. To add space to only one side, one approach is to
1450  * create a #GtkAlignment widget, call gtk_widget_set_size_request()
1451  * to give it a size, and place it on the side of the container as
1452  * a spacer.
1453  **/
1454 void
1455 gtk_container_set_border_width (GtkContainer *container,
1456                                 guint         border_width)
1457 {
1458   GtkContainerPrivate *priv;
1459
1460   g_return_if_fail (GTK_IS_CONTAINER (container));
1461
1462   priv = container->priv;
1463
1464   if (priv->border_width != border_width)
1465     {
1466       priv->border_width = border_width;
1467       g_object_notify (G_OBJECT (container), "border-width");
1468
1469       if (gtk_widget_get_realized (GTK_WIDGET (container)))
1470         gtk_widget_queue_resize (GTK_WIDGET (container));
1471     }
1472 }
1473
1474 /**
1475  * gtk_container_get_border_width:
1476  * @container: a #GtkContainer
1477  *
1478  * Retrieves the border width of the container. See
1479  * gtk_container_set_border_width().
1480  *
1481  * Return value: the current border width
1482  **/
1483 guint
1484 gtk_container_get_border_width (GtkContainer *container)
1485 {
1486   g_return_val_if_fail (GTK_IS_CONTAINER (container), 0);
1487
1488   return container->priv->border_width;
1489 }
1490
1491 /**
1492  * gtk_container_add:
1493  * @container: a #GtkContainer
1494  * @widget: a widget to be placed inside @container
1495  *
1496  * Adds @widget to @container. Typically used for simple containers
1497  * such as #GtkWindow, #GtkFrame, or #GtkButton; for more complicated
1498  * layout containers such as #GtkBox or #GtkGrid, this function will
1499  * pick default packing parameters that may not be correct.  So
1500  * consider functions such as gtk_box_pack_start() and
1501  * gtk_grid_attach() as an alternative to gtk_container_add() in
1502  * those cases. A widget may be added to only one container at a time;
1503  * you can't place the same widget inside two different containers.
1504  **/
1505 void
1506 gtk_container_add (GtkContainer *container,
1507                    GtkWidget    *widget)
1508 {
1509   GtkWidget *parent;
1510
1511   g_return_if_fail (GTK_IS_CONTAINER (container));
1512   g_return_if_fail (GTK_IS_WIDGET (widget));
1513
1514   parent = gtk_widget_get_parent (widget);
1515
1516   if (parent != NULL)
1517     {
1518       g_warning ("Attempting to add a widget with type %s to a container of "
1519                  "type %s, but the widget is already inside a container of type %s, "
1520                  "please use gtk_widget_reparent()" ,
1521                  g_type_name (G_OBJECT_TYPE (widget)),
1522                  g_type_name (G_OBJECT_TYPE (container)),
1523                  g_type_name (G_OBJECT_TYPE (parent)));
1524       return;
1525     }
1526
1527   g_signal_emit (container, container_signals[ADD], 0, widget);
1528 }
1529
1530 /**
1531  * gtk_container_remove:
1532  * @container: a #GtkContainer
1533  * @widget: a current child of @container
1534  *
1535  * Removes @widget from @container. @widget must be inside @container.
1536  * Note that @container will own a reference to @widget, and that this
1537  * may be the last reference held; so removing a widget from its
1538  * container can destroy that widget. If you want to use @widget
1539  * again, you need to add a reference to it while it's not inside
1540  * a container, using g_object_ref(). If you don't want to use @widget
1541  * again it's usually more efficient to simply destroy it directly
1542  * using gtk_widget_destroy() since this will remove it from the
1543  * container and help break any circular reference count cycles.
1544  **/
1545 void
1546 gtk_container_remove (GtkContainer *container,
1547                       GtkWidget    *widget)
1548 {
1549   g_return_if_fail (GTK_IS_CONTAINER (container));
1550   g_return_if_fail (GTK_IS_WIDGET (widget));
1551   g_return_if_fail (gtk_widget_get_parent (widget) == GTK_WIDGET (container) || GTK_IS_ASSISTANT (container));
1552
1553   g_signal_emit (container, container_signals[REMOVE], 0, widget);
1554 }
1555
1556 void
1557 _gtk_container_dequeue_resize_handler (GtkContainer *container)
1558 {
1559   g_return_if_fail (GTK_IS_CONTAINER (container));
1560   g_return_if_fail (container->priv->resize_pending);
1561
1562   container->priv->resize_pending = FALSE;
1563 }
1564
1565 /**
1566  * gtk_container_set_resize_mode:
1567  * @container: a #GtkContainer
1568  * @resize_mode: the new resize mode
1569  *
1570  * Sets the resize mode for the container.
1571  *
1572  * The resize mode of a container determines whether a resize request
1573  * will be passed to the container's parent, queued for later execution
1574  * or executed immediately.
1575  **/
1576 void
1577 gtk_container_set_resize_mode (GtkContainer  *container,
1578                                GtkResizeMode  resize_mode)
1579 {
1580   GtkContainerPrivate *priv;
1581
1582   g_return_if_fail (GTK_IS_CONTAINER (container));
1583   g_return_if_fail (resize_mode <= GTK_RESIZE_IMMEDIATE);
1584
1585   priv = container->priv;
1586
1587   if (gtk_widget_is_toplevel (GTK_WIDGET (container)) &&
1588       resize_mode == GTK_RESIZE_PARENT)
1589     {
1590       resize_mode = GTK_RESIZE_QUEUE;
1591     }
1592
1593   if (priv->resize_mode != resize_mode)
1594     {
1595       priv->resize_mode = resize_mode;
1596
1597       gtk_widget_queue_resize (GTK_WIDGET (container));
1598       g_object_notify (G_OBJECT (container), "resize-mode");
1599     }
1600 }
1601
1602 /**
1603  * gtk_container_get_resize_mode:
1604  * @container: a #GtkContainer
1605  *
1606  * Returns the resize mode for the container. See
1607  * gtk_container_set_resize_mode ().
1608  *
1609  * Return value: the current resize mode
1610  **/
1611 GtkResizeMode
1612 gtk_container_get_resize_mode (GtkContainer *container)
1613 {
1614   g_return_val_if_fail (GTK_IS_CONTAINER (container), GTK_RESIZE_PARENT);
1615
1616   return container->priv->resize_mode;
1617 }
1618
1619 /**
1620  * gtk_container_set_reallocate_redraws:
1621  * @container: a #GtkContainer
1622  * @needs_redraws: the new value for the container's @reallocate_redraws flag
1623  *
1624  * Sets the @reallocate_redraws flag of the container to the given value.
1625  *
1626  * Containers requesting reallocation redraws get automatically
1627  * redrawn if any of their children changed allocation.
1628  **/
1629 void
1630 gtk_container_set_reallocate_redraws (GtkContainer *container,
1631                                       gboolean      needs_redraws)
1632 {
1633   g_return_if_fail (GTK_IS_CONTAINER (container));
1634
1635   container->priv->reallocate_redraws = needs_redraws ? TRUE : FALSE;
1636 }
1637
1638 static void
1639 gtk_container_idle_sizer (GdkFrameClock *clock,
1640                           GtkContainer  *container)
1641 {
1642   /* We validate the style contexts in a single loop before even trying
1643    * to handle resizes instead of doing validations inline.
1644    * This is mostly necessary for compatibility reasons with old code,
1645    * because both style_updated and size_allocate functions often change
1646    * styles and so could cause infinite loops in this function.
1647    *
1648    * It's important to note that even an invalid style context returns
1649    * sane values. So the result of an invalid style context will never be
1650    * a program crash, but only a wrong layout or rendering.
1651    */
1652   if (container->priv->restyle_pending)
1653     {
1654       GtkBitmask *empty;
1655       gint64 current_time;
1656
1657       empty = _gtk_bitmask_new ();
1658       current_time = g_get_monotonic_time ();
1659
1660       container->priv->restyle_pending = FALSE;
1661       _gtk_style_context_validate (gtk_widget_get_style_context (GTK_WIDGET (container)),
1662                                    current_time,
1663                                    0,
1664                                    empty);
1665
1666       _gtk_bitmask_free (empty);
1667     }
1668
1669   /* we may be invoked with a container_resize_queue of NULL, because
1670    * queue_resize could have been adding an extra idle function while
1671    * the queue still got processed. we better just ignore such case
1672    * than trying to explicitely work around them with some extra flags,
1673    * since it doesn't cause any actual harm.
1674    */
1675   if (container->priv->resize_pending)
1676     {
1677       container->priv->resize_pending = FALSE;
1678       gtk_container_check_resize (container);
1679     }
1680
1681   if (!container->priv->restyle_pending && !container->priv->resize_pending)
1682     {
1683       g_signal_handler_disconnect (clock, container->priv->resize_handler);
1684       container->priv->resize_handler = 0;
1685       container->priv->resize_clock = NULL;
1686     }
1687   else
1688     {
1689       gdk_frame_clock_request_phase (clock,
1690                                      GDK_FRAME_CLOCK_PHASE_LAYOUT);
1691     }
1692 }
1693
1694 static void
1695 gtk_container_start_idle_sizer (GtkContainer *container)
1696 {
1697   GdkFrameClock *clock;
1698
1699   if (container->priv->resize_handler != 0)
1700     return;
1701
1702   clock = gtk_widget_get_frame_clock (GTK_WIDGET (container));
1703   if (clock == NULL)
1704     return;
1705
1706   container->priv->resize_clock = clock;
1707   container->priv->resize_handler = g_signal_connect (clock, "layout",
1708                                                       G_CALLBACK (gtk_container_idle_sizer), container);
1709   gdk_frame_clock_request_phase (clock,
1710                                  GDK_FRAME_CLOCK_PHASE_LAYOUT);
1711 }
1712
1713 static void
1714 gtk_container_queue_resize_handler (GtkContainer *container)
1715 {
1716   GtkWidget *widget;
1717
1718   g_return_if_fail (GTK_IS_RESIZE_CONTAINER (container));
1719
1720   widget = GTK_WIDGET (container);
1721
1722   if (gtk_widget_get_visible (widget) &&
1723       (gtk_widget_is_toplevel (widget) ||
1724        gtk_widget_get_realized (widget)))
1725     {
1726       switch (container->priv->resize_mode)
1727         {
1728         case GTK_RESIZE_QUEUE:
1729           if (!container->priv->resize_pending)
1730             {
1731               container->priv->resize_pending = TRUE;
1732               gtk_container_start_idle_sizer (container);
1733             }
1734           break;
1735
1736         case GTK_RESIZE_IMMEDIATE:
1737           gtk_container_check_resize (container);
1738           break;
1739
1740         case GTK_RESIZE_PARENT:
1741         default:
1742           g_assert_not_reached ();
1743           break;
1744         }
1745     }
1746 }
1747
1748 static void
1749 _gtk_container_queue_resize_internal (GtkContainer *container,
1750                                       gboolean      invalidate_only)
1751 {
1752   GtkWidget *widget;
1753
1754   g_return_if_fail (GTK_IS_CONTAINER (container));
1755
1756   widget = GTK_WIDGET (container);
1757
1758   do
1759     {
1760       _gtk_widget_set_alloc_needed (widget, TRUE);
1761       _gtk_size_request_cache_clear (_gtk_widget_peek_request_cache (widget));
1762
1763       if (GTK_IS_RESIZE_CONTAINER (widget))
1764         break;
1765
1766       widget = gtk_widget_get_parent (widget);
1767     }
1768   while (widget);
1769
1770   if (widget && !invalidate_only)
1771     gtk_container_queue_resize_handler (GTK_CONTAINER (widget));
1772 }
1773
1774 void
1775 _gtk_container_queue_restyle (GtkContainer *container)
1776 {
1777   GtkContainerPrivate *priv;
1778
1779   g_return_if_fail (GTK_CONTAINER (container));
1780
1781   priv = container->priv;
1782
1783   if (priv->restyle_pending)
1784     return;
1785
1786   gtk_container_start_idle_sizer (container);
1787   priv->restyle_pending = TRUE;
1788 }
1789
1790 /**
1791  * _gtk_container_queue_resize:
1792  * @container: a #GtkContainer
1793  *
1794  * Determines the "resize container" in the hierarchy above this container
1795  * (typically the toplevel, but other containers can be set as resize
1796  * containers with gtk_container_set_resize_mode()), marks the container
1797  * and all parents up to and including the resize container as needing
1798  * to have sizes recompted, and if necessary adds the resize container
1799  * to the queue of containers that will be resized out at idle.
1800  */
1801 void
1802 _gtk_container_queue_resize (GtkContainer *container)
1803 {
1804   _gtk_container_queue_resize_internal (container, FALSE);
1805 }
1806
1807 /**
1808  * _gtk_container_resize_invalidate:
1809  * @container: a #GtkContainer
1810  *
1811  * Invalidates cached sizes like _gtk_container_queue_resize() but doesn't
1812  * actually queue the resize container for resize.
1813  */
1814 void
1815 _gtk_container_resize_invalidate (GtkContainer *container)
1816 {
1817   _gtk_container_queue_resize_internal (container, TRUE);
1818 }
1819
1820 void
1821 _gtk_container_maybe_start_idle_sizer (GtkContainer *container)
1822 {
1823   if (container->priv->restyle_pending || container->priv->resize_pending)
1824     gtk_container_start_idle_sizer (container);
1825 }
1826
1827 void
1828 gtk_container_check_resize (GtkContainer *container)
1829 {
1830   g_return_if_fail (GTK_IS_CONTAINER (container));
1831
1832   g_signal_emit (container, container_signals[CHECK_RESIZE], 0);
1833 }
1834
1835 static void
1836 gtk_container_real_check_resize (GtkContainer *container)
1837 {
1838   GtkWidget *widget = GTK_WIDGET (container);
1839   GtkAllocation allocation;
1840   GtkRequisition requisition;
1841
1842   gtk_widget_get_preferred_size (widget,
1843                                  &requisition, NULL);
1844   gtk_widget_get_allocation (widget, &allocation);
1845
1846   if (requisition.width > allocation.width ||
1847       requisition.height > allocation.height)
1848     {
1849       if (GTK_IS_RESIZE_CONTAINER (container))
1850         {
1851           gtk_widget_size_allocate (widget, &allocation);
1852           gtk_widget_set_allocation (widget, &allocation);
1853         }
1854       else
1855         gtk_widget_queue_resize (widget);
1856     }
1857   else
1858     {
1859       gtk_container_resize_children (container);
1860     }
1861 }
1862
1863 /* The container hasn't changed size but one of its children
1864  *  queued a resize request. Which means that the allocation
1865  *  is not sufficient for the requisition of some child.
1866  *  We've already performed a size request at this point,
1867  *  so we simply need to reallocate and let the allocation
1868  *  trickle down via GTK_WIDGET_ALLOC_NEEDED flags.
1869  */
1870 void
1871 gtk_container_resize_children (GtkContainer *container)
1872 {
1873   GtkAllocation allocation;
1874   GtkWidget *widget;
1875
1876   /* resizing invariants:
1877    * toplevels have *always* resize_mode != GTK_RESIZE_PARENT set.
1878    * containers that have an idle sizer pending must be flagged with
1879    * RESIZE_PENDING.
1880    */
1881   g_return_if_fail (GTK_IS_CONTAINER (container));
1882
1883   widget = GTK_WIDGET (container);
1884   gtk_widget_get_allocation (widget, &allocation);
1885
1886   gtk_widget_size_allocate (widget, &allocation);
1887   gtk_widget_set_allocation (widget, &allocation);
1888 }
1889
1890 static void
1891 gtk_container_adjust_size_request (GtkWidget         *widget,
1892                                    GtkOrientation     orientation,
1893                                    gint              *minimum_size,
1894                                    gint              *natural_size)
1895 {
1896   GtkContainer *container;
1897
1898   container = GTK_CONTAINER (widget);
1899
1900   if (GTK_CONTAINER_GET_CLASS (widget)->_handle_border_width)
1901     {
1902       int border_width;
1903
1904       border_width = container->priv->border_width;
1905
1906       *minimum_size += border_width * 2;
1907       *natural_size += border_width * 2;
1908     }
1909
1910   /* chain up last so gtk_widget_set_size_request() values
1911    * will have a chance to overwrite our border width.
1912    */
1913   parent_class->adjust_size_request (widget, orientation,
1914                                      minimum_size, natural_size);
1915 }
1916
1917 static void
1918 gtk_container_adjust_size_allocation (GtkWidget         *widget,
1919                                       GtkOrientation     orientation,
1920                                       gint              *minimum_size,
1921                                       gint              *natural_size,
1922                                       gint              *allocated_pos,
1923                                       gint              *allocated_size)
1924 {
1925   GtkContainer *container;
1926   int border_width;
1927
1928   container = GTK_CONTAINER (widget);
1929
1930   if (GTK_CONTAINER_GET_CLASS (widget)->_handle_border_width)
1931     {
1932       border_width = container->priv->border_width;
1933
1934       *allocated_size -= border_width * 2;
1935       *allocated_pos += border_width;
1936       *minimum_size -= border_width * 2;
1937       *natural_size -= border_width * 2;
1938     }
1939
1940   /* Chain up to GtkWidgetClass *after* removing our border width from
1941    * the proposed allocation size. This is because it's possible that the
1942    * widget was allocated more space than it needs in a said orientation,
1943    * if GtkWidgetClass does any alignments and thus limits the size to the
1944    * natural size... then we need that to be done *after* removing any margins
1945    * and padding values.
1946    */
1947   parent_class->adjust_size_allocation (widget, orientation,
1948                                         minimum_size, natural_size, allocated_pos,
1949                                         allocated_size);
1950 }
1951
1952 typedef struct {
1953   gint hfw;
1954   gint wfh;
1955 } RequestModeCount;
1956
1957 static void
1958 count_request_modes (GtkWidget        *widget,
1959                      RequestModeCount *count)
1960 {
1961   GtkSizeRequestMode mode = gtk_widget_get_request_mode (widget);
1962
1963   switch (mode)
1964     {
1965     case GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH:
1966       count->hfw++;
1967       break;
1968     case GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT:
1969       count->wfh++;
1970       break;
1971     case GTK_SIZE_REQUEST_CONSTANT_SIZE:
1972     default:
1973       break;
1974     }
1975 }
1976
1977 static GtkSizeRequestMode 
1978 gtk_container_get_request_mode (GtkWidget *widget)
1979 {
1980   GtkContainer *container = GTK_CONTAINER (widget);
1981   RequestModeCount count = { 0, 0 };
1982
1983   gtk_container_forall (container, (GtkCallback)count_request_modes, &count);
1984
1985   if (!count.hfw && !count.wfh)
1986     return GTK_SIZE_REQUEST_CONSTANT_SIZE;
1987   else
1988     return count.wfh > count.hfw ? 
1989         GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT :
1990         GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
1991 }
1992
1993 /**
1994  * gtk_container_class_handle_border_width:
1995  * @klass: the class struct of a #GtkContainer subclass
1996  *
1997  * Modifies a subclass of #GtkContainerClass to automatically add and
1998  * remove the border-width setting on GtkContainer.  This allows the
1999  * subclass to ignore the border width in its size request and
2000  * allocate methods. The intent is for a subclass to invoke this
2001  * in its class_init function.
2002  *
2003  * gtk_container_class_handle_border_width() is necessary because it
2004  * would break API too badly to make this behavior the default. So
2005  * subclasses must "opt in" to the parent class handling border_width
2006  * for them.
2007  */
2008 void
2009 gtk_container_class_handle_border_width (GtkContainerClass *klass)
2010 {
2011   g_return_if_fail (GTK_IS_CONTAINER_CLASS (klass));
2012
2013   klass->_handle_border_width = TRUE;
2014 }
2015
2016 /**
2017  * gtk_container_forall:
2018  * @container: a #GtkContainer
2019  * @callback: (scope call) (closure callback_data): a callback
2020  * @callback_data: callback user data
2021  *
2022  * Invokes @callback on each child of @container, including children
2023  * that are considered "internal" (implementation details of the
2024  * container). "Internal" children generally weren't added by the user
2025  * of the container, but were added by the container implementation
2026  * itself.  Most applications should use gtk_container_foreach(),
2027  * rather than gtk_container_forall().
2028  *
2029  * Virtual: forall
2030  **/
2031 void
2032 gtk_container_forall (GtkContainer *container,
2033                       GtkCallback   callback,
2034                       gpointer      callback_data)
2035 {
2036   GtkContainerClass *class;
2037
2038   g_return_if_fail (GTK_IS_CONTAINER (container));
2039   g_return_if_fail (callback != NULL);
2040
2041   class = GTK_CONTAINER_GET_CLASS (container);
2042
2043   if (class->forall)
2044     class->forall (container, TRUE, callback, callback_data);
2045 }
2046
2047 /**
2048  * gtk_container_foreach:
2049  * @container: a #GtkContainer
2050  * @callback: (scope call):  a callback
2051  * @callback_data: callback user data
2052  *
2053  * Invokes @callback on each non-internal child of @container. See
2054  * gtk_container_forall() for details on what constitutes an
2055  * "internal" child.  Most applications should use
2056  * gtk_container_foreach(), rather than gtk_container_forall().
2057  **/
2058 void
2059 gtk_container_foreach (GtkContainer *container,
2060                        GtkCallback   callback,
2061                        gpointer      callback_data)
2062 {
2063   GtkContainerClass *class;
2064
2065   g_return_if_fail (GTK_IS_CONTAINER (container));
2066   g_return_if_fail (callback != NULL);
2067
2068   class = GTK_CONTAINER_GET_CLASS (container);
2069
2070   if (class->forall)
2071     class->forall (container, FALSE, callback, callback_data);
2072 }
2073
2074 /**
2075  * gtk_container_set_focus_child:
2076  * @container: a #GtkContainer
2077  * @child: (allow-none): a #GtkWidget, or %NULL
2078  *
2079  * Sets, or unsets if @child is %NULL, the focused child of @container.
2080  *
2081  * This function emits the GtkContainer::set_focus_child signal of
2082  * @container. Implementations of #GtkContainer can override the
2083  * default behaviour by overriding the class closure of this signal.
2084  *
2085  * This is function is mostly meant to be used by widgets. Applications can use
2086  * gtk_widget_grab_focus() to manualy set the focus to a specific widget.
2087  */
2088 void
2089 gtk_container_set_focus_child (GtkContainer *container,
2090                                GtkWidget    *child)
2091 {
2092   g_return_if_fail (GTK_IS_CONTAINER (container));
2093   if (child)
2094     g_return_if_fail (GTK_IS_WIDGET (child));
2095
2096   g_signal_emit (container, container_signals[SET_FOCUS_CHILD], 0, child);
2097 }
2098
2099 /**
2100  * gtk_container_get_focus_child:
2101  * @container: a #GtkContainer
2102  *
2103  * Returns the current focus child widget inside @container. This is not the
2104  * currently focused widget. That can be obtained by calling
2105  * gtk_window_get_focus().
2106  *
2107  * Returns: (transfer none): The child widget which will receive the
2108  *          focus inside @container when the @conatiner is focussed,
2109  *          or %NULL if none is set.
2110  *
2111  * Since: 2.14
2112  **/
2113 GtkWidget *
2114 gtk_container_get_focus_child (GtkContainer *container)
2115 {
2116   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
2117
2118   return container->priv->focus_child;
2119 }
2120
2121 /**
2122  * gtk_container_get_children:
2123  * @container: a #GtkContainer
2124  *
2125  * Returns the container's non-internal children. See
2126  * gtk_container_forall() for details on what constitutes an "internal" child.
2127  *
2128  * Return value: (element-type GtkWidget) (transfer container): a newly-allocated list of the container's non-internal children.
2129  **/
2130 GList*
2131 gtk_container_get_children (GtkContainer *container)
2132 {
2133   GList *children = NULL;
2134
2135   gtk_container_foreach (container,
2136                          gtk_container_children_callback,
2137                          &children);
2138
2139   return g_list_reverse (children);
2140 }
2141
2142 static void
2143 gtk_container_child_position_callback (GtkWidget *widget,
2144                                        gpointer   client_data)
2145 {
2146   struct {
2147     GtkWidget *child;
2148     guint i;
2149     guint index;
2150   } *data = client_data;
2151
2152   data->i++;
2153   if (data->child == widget)
2154     data->index = data->i;
2155 }
2156
2157 static gchar*
2158 gtk_container_child_default_composite_name (GtkContainer *container,
2159                                             GtkWidget    *child)
2160 {
2161   struct {
2162     GtkWidget *child;
2163     guint i;
2164     guint index;
2165   } data;
2166   gchar *name;
2167
2168   /* fallback implementation */
2169   data.child = child;
2170   data.i = 0;
2171   data.index = 0;
2172   gtk_container_forall (container,
2173                         gtk_container_child_position_callback,
2174                         &data);
2175
2176   name = g_strdup_printf ("%s-%u",
2177                           g_type_name (G_TYPE_FROM_INSTANCE (child)),
2178                           data.index);
2179
2180   return name;
2181 }
2182
2183 gchar*
2184 _gtk_container_child_composite_name (GtkContainer *container,
2185                                     GtkWidget    *child)
2186 {
2187   gboolean composite_child;
2188
2189   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
2190   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
2191   g_return_val_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (container), NULL);
2192
2193   g_object_get (child, "composite-child", &composite_child, NULL);
2194   if (composite_child)
2195     {
2196       static GQuark quark_composite_name = 0;
2197       gchar *name;
2198
2199       if (!quark_composite_name)
2200         quark_composite_name = g_quark_from_static_string ("gtk-composite-name");
2201
2202       name = g_object_get_qdata (G_OBJECT (child), quark_composite_name);
2203       if (!name)
2204         {
2205           GtkContainerClass *class;
2206
2207           class = GTK_CONTAINER_GET_CLASS (container);
2208           if (class->composite_name)
2209             name = class->composite_name (container, child);
2210         }
2211       else
2212         name = g_strdup (name);
2213
2214       return name;
2215     }
2216
2217   return NULL;
2218 }
2219
2220 typedef struct {
2221   gboolean hexpand;
2222   gboolean vexpand;
2223 } ComputeExpandData;
2224
2225 static void
2226 gtk_container_compute_expand_callback (GtkWidget *widget,
2227                                        gpointer   client_data)
2228 {
2229   ComputeExpandData *data = client_data;
2230
2231   /* note that we don't get_expand on the child if we already know we
2232    * have to expand, so we only recurse into children until we find
2233    * one that expands and then we basically don't do any more
2234    * work. This means that we can leave some children in a
2235    * need_compute_expand state, which is fine, as long as GtkWidget
2236    * doesn't rely on an invariant that "if a child has
2237    * need_compute_expand, its parents also do"
2238    *
2239    * gtk_widget_compute_expand() always returns FALSE if the
2240    * child is !visible so that's taken care of.
2241    */
2242   data->hexpand = data->hexpand ||
2243     gtk_widget_compute_expand (widget, GTK_ORIENTATION_HORIZONTAL);
2244
2245   data->vexpand = data->vexpand ||
2246     gtk_widget_compute_expand (widget, GTK_ORIENTATION_VERTICAL);
2247 }
2248
2249 static void
2250 gtk_container_compute_expand (GtkWidget         *widget,
2251                               gboolean          *hexpand_p,
2252                               gboolean          *vexpand_p)
2253 {
2254   ComputeExpandData data;
2255
2256   data.hexpand = FALSE;
2257   data.vexpand = FALSE;
2258
2259   gtk_container_forall (GTK_CONTAINER (widget),
2260                         gtk_container_compute_expand_callback,
2261                         &data);
2262
2263   *hexpand_p = data.hexpand;
2264   *vexpand_p = data.vexpand;
2265 }
2266
2267 static void
2268 gtk_container_real_set_focus_child (GtkContainer     *container,
2269                                     GtkWidget        *child)
2270 {
2271   GtkContainerPrivate *priv;
2272
2273   g_return_if_fail (GTK_IS_CONTAINER (container));
2274   g_return_if_fail (child == NULL || GTK_IS_WIDGET (child));
2275
2276   priv = container->priv;
2277
2278   if (child != priv->focus_child)
2279     {
2280       if (priv->focus_child)
2281         g_object_unref (priv->focus_child);
2282       priv->focus_child = child;
2283       if (priv->focus_child)
2284         g_object_ref (priv->focus_child);
2285     }
2286
2287
2288   /* check for h/v adjustments
2289    */
2290   if (priv->focus_child)
2291     {
2292       GtkAdjustment *hadj;
2293       GtkAdjustment *vadj;
2294       GtkAllocation allocation;
2295       GtkWidget *focus_child;
2296       gint x, y;
2297
2298       hadj = g_object_get_qdata (G_OBJECT (container), hadjustment_key_id);
2299       vadj = g_object_get_qdata (G_OBJECT (container), vadjustment_key_id);
2300       if (hadj || vadj)
2301         {
2302
2303           focus_child = priv->focus_child;
2304           while (GTK_IS_CONTAINER (focus_child) && gtk_container_get_focus_child (GTK_CONTAINER (focus_child)))
2305             {
2306               focus_child = gtk_container_get_focus_child (GTK_CONTAINER (focus_child));
2307             }
2308
2309           gtk_widget_translate_coordinates (focus_child, priv->focus_child,
2310                                             0, 0, &x, &y);
2311
2312           gtk_widget_get_allocation (priv->focus_child, &allocation);
2313           x += allocation.x;
2314           y += allocation.y;
2315
2316           gtk_widget_get_allocation (focus_child, &allocation);
2317
2318           if (vadj)
2319             gtk_adjustment_clamp_page (vadj, y, y + allocation.height);
2320
2321           if (hadj)
2322             gtk_adjustment_clamp_page (hadj, x, x + allocation.width);
2323         }
2324     }
2325 }
2326
2327 static GList*
2328 get_focus_chain (GtkContainer *container)
2329 {
2330   return g_object_get_data (G_OBJECT (container), "gtk-container-focus-chain");
2331 }
2332
2333 /* same as gtk_container_get_children, except it includes internals
2334  */
2335 GList *
2336 _gtk_container_get_all_children (GtkContainer *container)
2337 {
2338   GList *children = NULL;
2339
2340   gtk_container_forall (container,
2341                          gtk_container_children_callback,
2342                          &children);
2343
2344   return children;
2345 }
2346
2347 static GtkWidgetPath *
2348 gtk_container_real_get_path_for_child (GtkContainer *container,
2349                                        GtkWidget    *child)
2350 {
2351   GtkStyleContext *context;
2352   GtkWidgetPath *path;
2353   GList *classes;
2354
2355   context = gtk_widget_get_style_context (GTK_WIDGET (container));
2356   path = _gtk_widget_create_path (GTK_WIDGET (container));
2357
2358   /* Copy any permanent classes to the path */
2359   classes = gtk_style_context_list_classes (context);
2360
2361   while (classes)
2362     {
2363       GList *cur;
2364
2365       cur = classes;
2366       classes = classes->next;
2367
2368       gtk_widget_path_iter_add_class (path, -1, cur->data);
2369       g_list_free_1 (cur);
2370     }
2371
2372   gtk_widget_path_append_for_widget (path, child);
2373
2374   return path;
2375 }
2376
2377 static gboolean
2378 gtk_container_focus (GtkWidget        *widget,
2379                      GtkDirectionType  direction)
2380 {
2381   GList *children;
2382   GList *sorted_children;
2383   gint return_val;
2384   GtkContainer *container;
2385   GtkContainerPrivate *priv;
2386
2387   g_return_val_if_fail (GTK_IS_CONTAINER (widget), FALSE);
2388
2389   container = GTK_CONTAINER (widget);
2390   priv = container->priv;
2391
2392   return_val = FALSE;
2393
2394   if (gtk_widget_get_can_focus (widget))
2395     {
2396       if (!gtk_widget_has_focus (widget))
2397         {
2398           gtk_widget_grab_focus (widget);
2399           return_val = TRUE;
2400         }
2401     }
2402   else
2403     {
2404       /* Get a list of the containers children, allowing focus
2405        * chain to override.
2406        */
2407       if (priv->has_focus_chain)
2408         children = g_list_copy (get_focus_chain (container));
2409       else
2410         children = _gtk_container_get_all_children (container);
2411
2412       if (priv->has_focus_chain &&
2413           (direction == GTK_DIR_TAB_FORWARD ||
2414            direction == GTK_DIR_TAB_BACKWARD))
2415         {
2416           sorted_children = g_list_copy (children);
2417
2418           if (direction == GTK_DIR_TAB_BACKWARD)
2419             sorted_children = g_list_reverse (sorted_children);
2420         }
2421       else
2422         sorted_children = _gtk_container_focus_sort (container, children, direction, NULL);
2423
2424       return_val = gtk_container_focus_move (container, sorted_children, direction);
2425
2426       g_list_free (sorted_children);
2427       g_list_free (children);
2428     }
2429
2430   return return_val;
2431 }
2432
2433 static gint
2434 tab_compare (gconstpointer a,
2435              gconstpointer b,
2436              gpointer      data)
2437 {
2438   GtkAllocation child1_allocation, child2_allocation;
2439   const GtkWidget *child1 = a;
2440   const GtkWidget *child2 = b;
2441   GtkTextDirection text_direction = GPOINTER_TO_INT (data);
2442   gint y1, y2;
2443
2444   gtk_widget_get_allocation ((GtkWidget *) child1, &child1_allocation);
2445   gtk_widget_get_allocation ((GtkWidget *) child2, &child2_allocation);
2446
2447   y1 = child1_allocation.y + child1_allocation.height / 2;
2448   y2 = child2_allocation.y + child2_allocation.height / 2;
2449
2450   if (y1 == y2)
2451     {
2452       gint x1 = child1_allocation.x + child1_allocation.width / 2;
2453       gint x2 = child2_allocation.x + child2_allocation.width / 2;
2454
2455       if (text_direction == GTK_TEXT_DIR_RTL)
2456         return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1);
2457       else
2458         return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1);
2459     }
2460   else
2461     return (y1 < y2) ? -1 : 1;
2462 }
2463
2464 static GList *
2465 gtk_container_focus_sort_tab (GtkContainer     *container,
2466                               GList            *children,
2467                               GtkDirectionType  direction,
2468                               GtkWidget        *old_focus)
2469 {
2470   GtkTextDirection text_direction = gtk_widget_get_direction (GTK_WIDGET (container));
2471   children = g_list_sort_with_data (children, tab_compare, GINT_TO_POINTER (text_direction));
2472
2473   /* if we are going backwards then reverse the order
2474    *  of the children.
2475    */
2476   if (direction == GTK_DIR_TAB_BACKWARD)
2477     children = g_list_reverse (children);
2478
2479   return children;
2480 }
2481
2482 /* Get coordinates of @widget's allocation with respect to
2483  * allocation of @container.
2484  */
2485 static gboolean
2486 get_allocation_coords (GtkContainer  *container,
2487                        GtkWidget     *widget,
2488                        GdkRectangle  *allocation)
2489 {
2490   gtk_widget_get_allocation (widget, allocation);
2491
2492   return gtk_widget_translate_coordinates (widget, GTK_WIDGET (container),
2493                                            0, 0, &allocation->x, &allocation->y);
2494 }
2495
2496 /* Look for a child in @children that is intermediate between
2497  * the focus widget and container. This widget, if it exists,
2498  * acts as the starting widget for focus navigation.
2499  */
2500 static GtkWidget *
2501 find_old_focus (GtkContainer *container,
2502                 GList        *children)
2503 {
2504   GList *tmp_list = children;
2505   while (tmp_list)
2506     {
2507       GtkWidget *child = tmp_list->data;
2508       GtkWidget *widget = child;
2509
2510       while (widget && widget != (GtkWidget *)container)
2511         {
2512           GtkWidget *parent;
2513
2514           parent = gtk_widget_get_parent (widget);
2515
2516           if (parent && (gtk_container_get_focus_child (GTK_CONTAINER (parent)) != widget))
2517             goto next;
2518
2519           widget = parent;
2520         }
2521
2522       return child;
2523
2524     next:
2525       tmp_list = tmp_list->next;
2526     }
2527
2528   return NULL;
2529 }
2530
2531 static gboolean
2532 old_focus_coords (GtkContainer *container,
2533                   GdkRectangle *old_focus_rect)
2534 {
2535   GtkWidget *widget = GTK_WIDGET (container);
2536   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
2537   GtkWidget *old_focus;
2538
2539   if (GTK_IS_WINDOW (toplevel))
2540     {
2541       old_focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
2542       if (old_focus)
2543         return get_allocation_coords (container, old_focus, old_focus_rect);
2544     }
2545
2546   return FALSE;
2547 }
2548
2549 typedef struct _CompareInfo CompareInfo;
2550
2551 struct _CompareInfo
2552 {
2553   GtkContainer *container;
2554   gint x;
2555   gint y;
2556   gboolean reverse;
2557 };
2558
2559 static gint
2560 up_down_compare (gconstpointer a,
2561                  gconstpointer b,
2562                  gpointer      data)
2563 {
2564   GdkRectangle allocation1;
2565   GdkRectangle allocation2;
2566   CompareInfo *compare = data;
2567   gint y1, y2;
2568
2569   get_allocation_coords (compare->container, (GtkWidget *)a, &allocation1);
2570   get_allocation_coords (compare->container, (GtkWidget *)b, &allocation2);
2571
2572   y1 = allocation1.y + allocation1.height / 2;
2573   y2 = allocation2.y + allocation2.height / 2;
2574
2575   if (y1 == y2)
2576     {
2577       gint x1 = abs (allocation1.x + allocation1.width / 2 - compare->x);
2578       gint x2 = abs (allocation2.x + allocation2.width / 2 - compare->x);
2579
2580       if (compare->reverse)
2581         return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1);
2582       else
2583         return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1);
2584     }
2585   else
2586     return (y1 < y2) ? -1 : 1;
2587 }
2588
2589 static GList *
2590 gtk_container_focus_sort_up_down (GtkContainer     *container,
2591                                   GList            *children,
2592                                   GtkDirectionType  direction,
2593                                   GtkWidget        *old_focus)
2594 {
2595   CompareInfo compare;
2596   GList *tmp_list;
2597   GdkRectangle old_allocation;
2598
2599   compare.container = container;
2600   compare.reverse = (direction == GTK_DIR_UP);
2601
2602   if (!old_focus)
2603       old_focus = find_old_focus (container, children);
2604
2605   if (old_focus && get_allocation_coords (container, old_focus, &old_allocation))
2606     {
2607       gint compare_x1;
2608       gint compare_x2;
2609       gint compare_y;
2610
2611       /* Delete widgets from list that don't match minimum criteria */
2612
2613       compare_x1 = old_allocation.x;
2614       compare_x2 = old_allocation.x + old_allocation.width;
2615
2616       if (direction == GTK_DIR_UP)
2617         compare_y = old_allocation.y;
2618       else
2619         compare_y = old_allocation.y + old_allocation.height;
2620
2621       tmp_list = children;
2622       while (tmp_list)
2623         {
2624           GtkWidget *child = tmp_list->data;
2625           GList *next = tmp_list->next;
2626           gint child_x1, child_x2;
2627           GdkRectangle child_allocation;
2628
2629           if (child != old_focus)
2630             {
2631               if (get_allocation_coords (container, child, &child_allocation))
2632                 {
2633                   child_x1 = child_allocation.x;
2634                   child_x2 = child_allocation.x + child_allocation.width;
2635
2636                   if ((child_x2 <= compare_x1 || child_x1 >= compare_x2) /* No horizontal overlap */ ||
2637                       (direction == GTK_DIR_DOWN && child_allocation.y + child_allocation.height < compare_y) || /* Not below */
2638                       (direction == GTK_DIR_UP && child_allocation.y > compare_y)) /* Not above */
2639                     {
2640                       children = g_list_delete_link (children, tmp_list);
2641                     }
2642                 }
2643               else
2644                 children = g_list_delete_link (children, tmp_list);
2645             }
2646
2647           tmp_list = next;
2648         }
2649
2650       compare.x = (compare_x1 + compare_x2) / 2;
2651       compare.y = old_allocation.y + old_allocation.height / 2;
2652     }
2653   else
2654     {
2655       /* No old focus widget, need to figure out starting x,y some other way
2656        */
2657       GtkAllocation allocation;
2658       GtkWidget *widget = GTK_WIDGET (container);
2659       GdkRectangle old_focus_rect;
2660
2661       gtk_widget_get_allocation (widget, &allocation);
2662
2663       if (old_focus_coords (container, &old_focus_rect))
2664         {
2665           compare.x = old_focus_rect.x + old_focus_rect.width / 2;
2666         }
2667       else
2668         {
2669           if (!gtk_widget_get_has_window (widget))
2670             compare.x = allocation.x + allocation.width / 2;
2671           else
2672             compare.x = allocation.width / 2;
2673         }
2674
2675       if (!gtk_widget_get_has_window (widget))
2676         compare.y = (direction == GTK_DIR_DOWN) ? allocation.y : allocation.y + allocation.height;
2677       else
2678         compare.y = (direction == GTK_DIR_DOWN) ? 0 : + allocation.height;
2679     }
2680
2681   children = g_list_sort_with_data (children, up_down_compare, &compare);
2682
2683   if (compare.reverse)
2684     children = g_list_reverse (children);
2685
2686   return children;
2687 }
2688
2689 static gint
2690 left_right_compare (gconstpointer a,
2691                     gconstpointer b,
2692                     gpointer      data)
2693 {
2694   GdkRectangle allocation1;
2695   GdkRectangle allocation2;
2696   CompareInfo *compare = data;
2697   gint x1, x2;
2698
2699   get_allocation_coords (compare->container, (GtkWidget *)a, &allocation1);
2700   get_allocation_coords (compare->container, (GtkWidget *)b, &allocation2);
2701
2702   x1 = allocation1.x + allocation1.width / 2;
2703   x2 = allocation2.x + allocation2.width / 2;
2704
2705   if (x1 == x2)
2706     {
2707       gint y1 = abs (allocation1.y + allocation1.height / 2 - compare->y);
2708       gint y2 = abs (allocation2.y + allocation2.height / 2 - compare->y);
2709
2710       if (compare->reverse)
2711         return (y1 < y2) ? 1 : ((y1 == y2) ? 0 : -1);
2712       else
2713         return (y1 < y2) ? -1 : ((y1 == y2) ? 0 : 1);
2714     }
2715   else
2716     return (x1 < x2) ? -1 : 1;
2717 }
2718
2719 static GList *
2720 gtk_container_focus_sort_left_right (GtkContainer     *container,
2721                                      GList            *children,
2722                                      GtkDirectionType  direction,
2723                                      GtkWidget        *old_focus)
2724 {
2725   CompareInfo compare;
2726   GList *tmp_list;
2727   GdkRectangle old_allocation;
2728
2729   compare.container = container;
2730   compare.reverse = (direction == GTK_DIR_LEFT);
2731
2732   if (!old_focus)
2733     old_focus = find_old_focus (container, children);
2734
2735   if (old_focus && get_allocation_coords (container, old_focus, &old_allocation))
2736     {
2737       gint compare_y1;
2738       gint compare_y2;
2739       gint compare_x;
2740
2741       /* Delete widgets from list that don't match minimum criteria */
2742
2743       compare_y1 = old_allocation.y;
2744       compare_y2 = old_allocation.y + old_allocation.height;
2745
2746       if (direction == GTK_DIR_LEFT)
2747         compare_x = old_allocation.x;
2748       else
2749         compare_x = old_allocation.x + old_allocation.width;
2750
2751       tmp_list = children;
2752       while (tmp_list)
2753         {
2754           GtkWidget *child = tmp_list->data;
2755           GList *next = tmp_list->next;
2756           gint child_y1, child_y2;
2757           GdkRectangle child_allocation;
2758
2759           if (child != old_focus)
2760             {
2761               if (get_allocation_coords (container, child, &child_allocation))
2762                 {
2763                   child_y1 = child_allocation.y;
2764                   child_y2 = child_allocation.y + child_allocation.height;
2765
2766                   if ((child_y2 <= compare_y1 || child_y1 >= compare_y2) /* No vertical overlap */ ||
2767                       (direction == GTK_DIR_RIGHT && child_allocation.x + child_allocation.width < compare_x) || /* Not to left */
2768                       (direction == GTK_DIR_LEFT && child_allocation.x > compare_x)) /* Not to right */
2769                     {
2770                       children = g_list_delete_link (children, tmp_list);
2771                     }
2772                 }
2773               else
2774                 children = g_list_delete_link (children, tmp_list);
2775             }
2776
2777           tmp_list = next;
2778         }
2779
2780       compare.y = (compare_y1 + compare_y2) / 2;
2781       compare.x = old_allocation.x + old_allocation.width / 2;
2782     }
2783   else
2784     {
2785       /* No old focus widget, need to figure out starting x,y some other way
2786        */
2787       GtkAllocation allocation;
2788       GtkWidget *widget = GTK_WIDGET (container);
2789       GdkRectangle old_focus_rect;
2790
2791       gtk_widget_get_allocation (widget, &allocation);
2792
2793       if (old_focus_coords (container, &old_focus_rect))
2794         {
2795           compare.y = old_focus_rect.y + old_focus_rect.height / 2;
2796         }
2797       else
2798         {
2799           if (!gtk_widget_get_has_window (widget))
2800             compare.y = allocation.y + allocation.height / 2;
2801           else
2802             compare.y = allocation.height / 2;
2803         }
2804
2805       if (!gtk_widget_get_has_window (widget))
2806         compare.x = (direction == GTK_DIR_RIGHT) ? allocation.x : allocation.x + allocation.width;
2807       else
2808         compare.x = (direction == GTK_DIR_RIGHT) ? 0 : allocation.width;
2809     }
2810
2811   children = g_list_sort_with_data (children, left_right_compare, &compare);
2812
2813   if (compare.reverse)
2814     children = g_list_reverse (children);
2815
2816   return children;
2817 }
2818
2819 /**
2820  * gtk_container_focus_sort:
2821  * @container: a #GtkContainer
2822  * @children:  a list of descendents of @container (they don't
2823  *             have to be direct children)
2824  * @direction: focus direction
2825  * @old_focus: (allow-none): widget to use for the starting position, or %NULL
2826  *             to determine this automatically.
2827  *             (Note, this argument isn't used for GTK_DIR_TAB_*,
2828  *              which is the only @direction we use currently,
2829  *              so perhaps this argument should be removed)
2830  *
2831  * Sorts @children in the correct order for focusing with
2832  * direction type @direction.
2833  *
2834  * Return value: a copy of @children, sorted in correct focusing order,
2835  *   with children that aren't suitable for focusing in this direction
2836  *   removed.
2837  **/
2838 GList *
2839 _gtk_container_focus_sort (GtkContainer     *container,
2840                            GList            *children,
2841                            GtkDirectionType  direction,
2842                            GtkWidget        *old_focus)
2843 {
2844   GList *visible_children = NULL;
2845
2846   while (children)
2847     {
2848       if (gtk_widget_get_realized (children->data))
2849         visible_children = g_list_prepend (visible_children, children->data);
2850       children = children->next;
2851     }
2852
2853   switch (direction)
2854     {
2855     case GTK_DIR_TAB_FORWARD:
2856     case GTK_DIR_TAB_BACKWARD:
2857       return gtk_container_focus_sort_tab (container, visible_children, direction, old_focus);
2858     case GTK_DIR_UP:
2859     case GTK_DIR_DOWN:
2860       return gtk_container_focus_sort_up_down (container, visible_children, direction, old_focus);
2861     case GTK_DIR_LEFT:
2862     case GTK_DIR_RIGHT:
2863       return gtk_container_focus_sort_left_right (container, visible_children, direction, old_focus);
2864     }
2865
2866   g_assert_not_reached ();
2867
2868   return NULL;
2869 }
2870
2871 static gboolean
2872 gtk_container_focus_move (GtkContainer     *container,
2873                           GList            *children,
2874                           GtkDirectionType  direction)
2875 {
2876   GtkContainerPrivate *priv = container->priv;
2877   GtkWidget *focus_child;
2878   GtkWidget *child;
2879
2880   focus_child = priv->focus_child;
2881
2882   while (children)
2883     {
2884       child = children->data;
2885       children = children->next;
2886
2887       if (!child)
2888         continue;
2889
2890       if (focus_child)
2891         {
2892           if (focus_child == child)
2893             {
2894               focus_child = NULL;
2895
2896                 if (gtk_widget_child_focus (child, direction))
2897                   return TRUE;
2898             }
2899         }
2900       else if (gtk_widget_is_drawable (child) &&
2901                gtk_widget_is_ancestor (child, GTK_WIDGET (container)))
2902         {
2903           if (gtk_widget_child_focus (child, direction))
2904             return TRUE;
2905         }
2906     }
2907
2908   return FALSE;
2909 }
2910
2911
2912 static void
2913 gtk_container_children_callback (GtkWidget *widget,
2914                                  gpointer   client_data)
2915 {
2916   GList **children;
2917
2918   children = (GList**) client_data;
2919   *children = g_list_prepend (*children, widget);
2920 }
2921
2922 static void
2923 chain_widget_destroyed (GtkWidget *widget,
2924                         gpointer   user_data)
2925 {
2926   GtkContainer *container;
2927   GList *chain;
2928
2929   container = GTK_CONTAINER (user_data);
2930
2931   chain = g_object_get_data (G_OBJECT (container),
2932                              "gtk-container-focus-chain");
2933
2934   chain = g_list_remove (chain, widget);
2935
2936   g_signal_handlers_disconnect_by_func (widget,
2937                                         chain_widget_destroyed,
2938                                         user_data);
2939
2940   g_object_set_data (G_OBJECT (container),
2941                      I_("gtk-container-focus-chain"),
2942                      chain);
2943 }
2944
2945 /**
2946  * gtk_container_set_focus_chain:
2947  * @container: a #GtkContainer
2948  * @focusable_widgets: (transfer none) (element-type GtkWidget):
2949  *     the new focus chain
2950  *
2951  * Sets a focus chain, overriding the one computed automatically by GTK+.
2952  *
2953  * In principle each widget in the chain should be a descendant of the
2954  * container, but this is not enforced by this method, since it's allowed
2955  * to set the focus chain before you pack the widgets, or have a widget
2956  * in the chain that isn't always packed. The necessary checks are done
2957  * when the focus chain is actually traversed.
2958  **/
2959 void
2960 gtk_container_set_focus_chain (GtkContainer *container,
2961                                GList        *focusable_widgets)
2962 {
2963   GList *chain;
2964   GList *tmp_list;
2965   GtkContainerPrivate *priv;
2966
2967   g_return_if_fail (GTK_IS_CONTAINER (container));
2968
2969   priv = container->priv;
2970
2971   if (priv->has_focus_chain)
2972     gtk_container_unset_focus_chain (container);
2973
2974   priv->has_focus_chain = TRUE;
2975
2976   chain = NULL;
2977   tmp_list = focusable_widgets;
2978   while (tmp_list != NULL)
2979     {
2980       g_return_if_fail (GTK_IS_WIDGET (tmp_list->data));
2981
2982       /* In principle each widget in the chain should be a descendant
2983        * of the container, but we don't want to check that here. It's
2984        * expensive and also it's allowed to set the focus chain before
2985        * you pack the widgets, or have a widget in the chain that isn't
2986        * always packed. So we check for ancestor during actual traversal.
2987        */
2988
2989       chain = g_list_prepend (chain, tmp_list->data);
2990
2991       g_signal_connect (tmp_list->data,
2992                         "destroy",
2993                         G_CALLBACK (chain_widget_destroyed),
2994                         container);
2995
2996       tmp_list = g_list_next (tmp_list);
2997     }
2998
2999   chain = g_list_reverse (chain);
3000
3001   g_object_set_data (G_OBJECT (container),
3002                      I_("gtk-container-focus-chain"),
3003                      chain);
3004 }
3005
3006 /**
3007  * gtk_container_get_focus_chain:
3008  * @container:         a #GtkContainer
3009  * @focusable_widgets: (element-type GtkWidget) (out) (transfer container): location
3010  *                     to store the focus chain of the
3011  *                     container, or %NULL. You should free this list
3012  *                     using g_list_free() when you are done with it, however
3013  *                     no additional reference count is added to the
3014  *                     individual widgets in the focus chain.
3015  *
3016  * Retrieves the focus chain of the container, if one has been
3017  * set explicitly. If no focus chain has been explicitly
3018  * set, GTK+ computes the focus chain based on the positions
3019  * of the children. In that case, GTK+ stores %NULL in
3020  * @focusable_widgets and returns %FALSE.
3021  *
3022  * Return value: %TRUE if the focus chain of the container
3023  * has been set explicitly.
3024  **/
3025 gboolean
3026 gtk_container_get_focus_chain (GtkContainer *container,
3027                                GList       **focus_chain)
3028 {
3029   GtkContainerPrivate *priv;
3030
3031   g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
3032
3033   priv = container->priv;
3034
3035   if (focus_chain)
3036     {
3037       if (priv->has_focus_chain)
3038         *focus_chain = g_list_copy (get_focus_chain (container));
3039       else
3040         *focus_chain = NULL;
3041     }
3042
3043   return priv->has_focus_chain;
3044 }
3045
3046 /**
3047  * gtk_container_unset_focus_chain:
3048  * @container: a #GtkContainer
3049  *
3050  * Removes a focus chain explicitly set with gtk_container_set_focus_chain().
3051  **/
3052 void
3053 gtk_container_unset_focus_chain (GtkContainer  *container)
3054 {
3055   GtkContainerPrivate *priv;
3056
3057   g_return_if_fail (GTK_IS_CONTAINER (container));
3058
3059   priv = container->priv;
3060
3061   if (priv->has_focus_chain)
3062     {
3063       GList *chain;
3064       GList *tmp_list;
3065
3066       chain = get_focus_chain (container);
3067
3068       priv->has_focus_chain = FALSE;
3069
3070       g_object_set_data (G_OBJECT (container),
3071                          I_("gtk-container-focus-chain"),
3072                          NULL);
3073
3074       tmp_list = chain;
3075       while (tmp_list != NULL)
3076         {
3077           g_signal_handlers_disconnect_by_func (tmp_list->data,
3078                                                 chain_widget_destroyed,
3079                                                 container);
3080
3081           tmp_list = g_list_next (tmp_list);
3082         }
3083
3084       g_list_free (chain);
3085     }
3086 }
3087
3088 /**
3089  * gtk_container_set_focus_vadjustment:
3090  * @container: a #GtkContainer
3091  * @adjustment: an adjustment which should be adjusted when the focus
3092  *   is moved among the descendents of @container
3093  *
3094  * Hooks up an adjustment to focus handling in a container, so when a
3095  * child of the container is focused, the adjustment is scrolled to
3096  * show that widget. This function sets the vertical alignment. See
3097  * gtk_scrolled_window_get_vadjustment() for a typical way of obtaining
3098  * the adjustment and gtk_container_set_focus_hadjustment() for setting
3099  * the horizontal adjustment.
3100  *
3101  * The adjustments have to be in pixel units and in the same coordinate
3102  * system as the allocation for immediate children of the container.
3103  */
3104 void
3105 gtk_container_set_focus_vadjustment (GtkContainer  *container,
3106                                      GtkAdjustment *adjustment)
3107 {
3108   g_return_if_fail (GTK_IS_CONTAINER (container));
3109   if (adjustment)
3110     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
3111
3112   if (adjustment)
3113     g_object_ref (adjustment);
3114
3115   g_object_set_qdata_full (G_OBJECT (container),
3116                            vadjustment_key_id,
3117                            adjustment,
3118                            g_object_unref);
3119 }
3120
3121 /**
3122  * gtk_container_get_focus_vadjustment:
3123  * @container: a #GtkContainer
3124  *
3125  * Retrieves the vertical focus adjustment for the container. See
3126  * gtk_container_set_focus_vadjustment().
3127  *
3128  * Return value: (transfer none): the vertical focus adjustment, or %NULL if
3129  *   none has been set.
3130  **/
3131 GtkAdjustment *
3132 gtk_container_get_focus_vadjustment (GtkContainer *container)
3133 {
3134   GtkAdjustment *vadjustment;
3135
3136   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
3137
3138   vadjustment = g_object_get_qdata (G_OBJECT (container), vadjustment_key_id);
3139
3140   return vadjustment;
3141 }
3142
3143 /**
3144  * gtk_container_set_focus_hadjustment:
3145  * @container: a #GtkContainer
3146  * @adjustment: an adjustment which should be adjusted when the focus is
3147  *   moved among the descendents of @container
3148  *
3149  * Hooks up an adjustment to focus handling in a container, so when a child
3150  * of the container is focused, the adjustment is scrolled to show that
3151  * widget. This function sets the horizontal alignment.
3152  * See gtk_scrolled_window_get_hadjustment() for a typical way of obtaining
3153  * the adjustment and gtk_container_set_focus_vadjustment() for setting
3154  * the vertical adjustment.
3155  *
3156  * The adjustments have to be in pixel units and in the same coordinate
3157  * system as the allocation for immediate children of the container.
3158  */
3159 void
3160 gtk_container_set_focus_hadjustment (GtkContainer  *container,
3161                                      GtkAdjustment *adjustment)
3162 {
3163   g_return_if_fail (GTK_IS_CONTAINER (container));
3164   if (adjustment)
3165     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
3166
3167   if (adjustment)
3168     g_object_ref (adjustment);
3169
3170   g_object_set_qdata_full (G_OBJECT (container),
3171                            hadjustment_key_id,
3172                            adjustment,
3173                            g_object_unref);
3174 }
3175
3176 /**
3177  * gtk_container_get_focus_hadjustment:
3178  * @container: a #GtkContainer
3179  *
3180  * Retrieves the horizontal focus adjustment for the container. See
3181  * gtk_container_set_focus_hadjustment ().
3182  *
3183  * Return value: (transfer none): the horizontal focus adjustment, or %NULL if
3184  *   none has been set.
3185  **/
3186 GtkAdjustment *
3187 gtk_container_get_focus_hadjustment (GtkContainer *container)
3188 {
3189   GtkAdjustment *hadjustment;
3190
3191   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
3192
3193   hadjustment = g_object_get_qdata (G_OBJECT (container), hadjustment_key_id);
3194
3195   return hadjustment;
3196 }
3197
3198
3199 static void
3200 gtk_container_show_all (GtkWidget *widget)
3201 {
3202   g_return_if_fail (GTK_IS_CONTAINER (widget));
3203
3204   gtk_container_foreach (GTK_CONTAINER (widget),
3205                          (GtkCallback) gtk_widget_show_all,
3206                          NULL);
3207   gtk_widget_show (widget);
3208 }
3209
3210 static void
3211 gtk_container_draw_child (GtkWidget *child,
3212                           gpointer   client_data)
3213 {
3214   struct {
3215     GtkWidget *container;
3216     cairo_t *cr;
3217   } *data = client_data;
3218
3219   gtk_container_propagate_draw (GTK_CONTAINER (data->container),
3220                                 child,
3221                                 data->cr);
3222 }
3223
3224 static gint
3225 gtk_container_draw (GtkWidget *widget,
3226                     cairo_t   *cr)
3227 {
3228   struct {
3229     GtkWidget *container;
3230     cairo_t *cr;
3231   } data;
3232
3233   data.container = widget;
3234   data.cr = cr;
3235
3236   gtk_container_forall (GTK_CONTAINER (widget),
3237                         gtk_container_draw_child,
3238                         &data);
3239
3240   return FALSE;
3241 }
3242
3243 static void
3244 gtk_container_map_child (GtkWidget *child,
3245                          gpointer   client_data)
3246 {
3247   if (gtk_widget_get_visible (child) &&
3248       gtk_widget_get_child_visible (child) &&
3249       !gtk_widget_get_mapped (child))
3250     gtk_widget_map (child);
3251 }
3252
3253 static void
3254 gtk_container_map (GtkWidget *widget)
3255 {
3256   gtk_widget_set_mapped (widget, TRUE);
3257
3258   gtk_container_forall (GTK_CONTAINER (widget),
3259                         gtk_container_map_child,
3260                         NULL);
3261
3262   if (gtk_widget_get_has_window (widget))
3263     gdk_window_show (gtk_widget_get_window (widget));
3264 }
3265
3266 static void
3267 gtk_container_unmap (GtkWidget *widget)
3268 {
3269   gtk_widget_set_mapped (widget, FALSE);
3270
3271   /* hide our window first so user doesn't see all the child windows
3272    * vanishing one by one.  (only matters these days if one of the
3273    * children has an actual native window instead of client-side
3274    * window, e.g. a GtkSocket would)
3275    */
3276   if (gtk_widget_get_has_window (widget))
3277     gdk_window_hide (gtk_widget_get_window (widget));
3278
3279   gtk_container_forall (GTK_CONTAINER (widget),
3280                         (GtkCallback)gtk_widget_unmap,
3281                         NULL);
3282 }
3283
3284 /**
3285  * gtk_container_propagate_draw:
3286  * @container: a #GtkContainer
3287  * @child: a child of @container
3288  * @cr: Cairo context as passed to the container. If you want to use @cr
3289  *   in container's draw function, consider using cairo_save() and
3290  *   cairo_restore() before calling this function.
3291  *
3292  * When a container receives a call to the draw function, it must send
3293  * synthetic #GtkWidget::draw calls to all children that don't have their
3294  * own #GdkWindows. This function provides a convenient way of doing this.
3295  * A container, when it receives a call to its #GtkWidget::draw function,
3296  * calls gtk_container_propagate_draw() once for each child, passing in
3297  * the @cr the container received.
3298  *
3299  * gtk_container_propagate_draw() takes care of translating the origin of @cr,
3300  * and deciding whether the draw needs to be sent to the child. It is a
3301  * convenient and optimized way of getting the same effect as calling
3302  * gtk_widget_draw() on the child directly.
3303  *
3304  * In most cases, a container can simply either inherit the
3305  * #GtkWidget::draw implementation from #GtkContainer, or do some drawing
3306  * and then chain to the ::draw implementation from #GtkContainer.
3307  **/
3308 void
3309 gtk_container_propagate_draw (GtkContainer   *container,
3310                               GtkWidget      *child,
3311                               cairo_t        *cr)
3312 {
3313   GdkEventExpose *event;
3314   GtkAllocation allocation;
3315   GdkWindow *window, *w;
3316   int x, y;
3317
3318   g_return_if_fail (GTK_IS_CONTAINER (container));
3319   g_return_if_fail (GTK_IS_WIDGET (child));
3320   g_return_if_fail (cr != NULL);
3321
3322   g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (container));
3323
3324   event = _gtk_cairo_get_event (cr);
3325   if (event)
3326     {
3327       if (gtk_widget_get_has_window (child) ||
3328           gtk_widget_get_window (child) != event->window)
3329         return;
3330     }
3331
3332   cairo_save (cr);
3333
3334   /* translate coordinates. Ugly business, that. */
3335   if (!gtk_widget_get_has_window (GTK_WIDGET (container)))
3336     {
3337       gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
3338       x = -allocation.x;
3339       y = -allocation.y;
3340     }
3341   else
3342     {
3343       x = 0;
3344       y = 0;
3345     }
3346
3347   window = gtk_widget_get_window (GTK_WIDGET (container));
3348
3349   for (w = gtk_widget_get_window (child); w && w != window; w = gdk_window_get_parent (w))
3350     {
3351       int wx, wy;
3352       gdk_window_get_position (w, &wx, &wy);
3353       x += wx;
3354       y += wy;
3355     }
3356
3357   if (w == NULL)
3358     {
3359       x = 0;
3360       y = 0;
3361     }
3362
3363   if (!gtk_widget_get_has_window (child))
3364     {
3365       gtk_widget_get_allocation (child, &allocation);
3366       x += allocation.x;
3367       y += allocation.y;
3368     }
3369
3370   cairo_translate (cr, x, y);
3371
3372   _gtk_widget_draw_internal (child, cr, TRUE);
3373
3374   cairo_restore (cr);
3375 }
3376
3377 gboolean
3378 _gtk_container_get_reallocate_redraws (GtkContainer *container)
3379 {
3380   return container->priv->reallocate_redraws;
3381 }
3382
3383 /**
3384  * gtk_container_get_path_for_child:
3385  * @container: a #GtkContainer
3386  * @child: a child of @container
3387  *
3388  * Returns a newly created widget path representing all the widget hierarchy
3389  * from the toplevel down to and including @child.
3390  *
3391  * Returns: A newly created #GtkWidgetPath
3392  **/
3393 GtkWidgetPath *
3394 gtk_container_get_path_for_child (GtkContainer *container,
3395                                   GtkWidget    *child)
3396 {
3397   GtkWidgetPath *path;
3398
3399   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
3400   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
3401   g_return_val_if_fail (container == (GtkContainer *) gtk_widget_get_parent (child), NULL);
3402
3403   path = GTK_CONTAINER_GET_CLASS (container)->get_path_for_child (container, child);
3404   if (gtk_widget_path_get_object_type (path) != G_OBJECT_TYPE (child))
3405     {
3406       g_critical ("%s %p returned a widget path for type %s, but child is %s",
3407                   G_OBJECT_TYPE_NAME (container),
3408                   container,
3409                   g_type_name (gtk_widget_path_get_object_type (path)),
3410                   G_OBJECT_TYPE_NAME (child));
3411     }
3412
3413   return path;
3414 }