]> Pileus Git - ~andy/gtk/blob - gtk/gtkcontainer.c
stylecontext: Do invalidation on first resize container
[~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->focus_child)
1366     {
1367       g_object_unref (priv->focus_child);
1368       priv->focus_child = NULL;
1369     }
1370
1371   /* do this before walking child widgets, to avoid
1372    * removing children from focus chain one by one.
1373    */
1374   if (priv->has_focus_chain)
1375     gtk_container_unset_focus_chain (container);
1376
1377   gtk_container_foreach (container, (GtkCallback) gtk_widget_destroy, NULL);
1378
1379   GTK_WIDGET_CLASS (parent_class)->destroy (widget);
1380 }
1381
1382 static void
1383 gtk_container_set_property (GObject         *object,
1384                             guint            prop_id,
1385                             const GValue    *value,
1386                             GParamSpec      *pspec)
1387 {
1388   GtkContainer *container = GTK_CONTAINER (object);
1389
1390   switch (prop_id)
1391     {
1392     case PROP_BORDER_WIDTH:
1393       gtk_container_set_border_width (container, g_value_get_uint (value));
1394       break;
1395     case PROP_RESIZE_MODE:
1396       gtk_container_set_resize_mode (container, g_value_get_enum (value));
1397       break;
1398     case PROP_CHILD:
1399       gtk_container_add (container, GTK_WIDGET (g_value_get_object (value)));
1400       break;
1401     default:
1402       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1403       break;
1404     }
1405 }
1406
1407 static void
1408 gtk_container_get_property (GObject         *object,
1409                             guint            prop_id,
1410                             GValue          *value,
1411                             GParamSpec      *pspec)
1412 {
1413   GtkContainer *container = GTK_CONTAINER (object);
1414   GtkContainerPrivate *priv = container->priv;
1415
1416   switch (prop_id)
1417     {
1418     case PROP_BORDER_WIDTH:
1419       g_value_set_uint (value, priv->border_width);
1420       break;
1421     case PROP_RESIZE_MODE:
1422       g_value_set_enum (value, priv->resize_mode);
1423       break;
1424     default:
1425       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1426       break;
1427     }
1428 }
1429
1430 /**
1431  * gtk_container_set_border_width:
1432  * @container: a #GtkContainer
1433  * @border_width: amount of blank space to leave <emphasis>outside</emphasis>
1434  *   the container. Valid values are in the range 0-65535 pixels.
1435  *
1436  * Sets the border width of the container.
1437  *
1438  * The border width of a container is the amount of space to leave
1439  * around the outside of the container. The only exception to this is
1440  * #GtkWindow; because toplevel windows can't leave space outside,
1441  * they leave the space inside. The border is added on all sides of
1442  * the container. To add space to only one side, one approach is to
1443  * create a #GtkAlignment widget, call gtk_widget_set_size_request()
1444  * to give it a size, and place it on the side of the container as
1445  * a spacer.
1446  **/
1447 void
1448 gtk_container_set_border_width (GtkContainer *container,
1449                                 guint         border_width)
1450 {
1451   GtkContainerPrivate *priv;
1452
1453   g_return_if_fail (GTK_IS_CONTAINER (container));
1454
1455   priv = container->priv;
1456
1457   if (priv->border_width != border_width)
1458     {
1459       priv->border_width = border_width;
1460       g_object_notify (G_OBJECT (container), "border-width");
1461
1462       if (gtk_widget_get_realized (GTK_WIDGET (container)))
1463         gtk_widget_queue_resize (GTK_WIDGET (container));
1464     }
1465 }
1466
1467 /**
1468  * gtk_container_get_border_width:
1469  * @container: a #GtkContainer
1470  *
1471  * Retrieves the border width of the container. See
1472  * gtk_container_set_border_width().
1473  *
1474  * Return value: the current border width
1475  **/
1476 guint
1477 gtk_container_get_border_width (GtkContainer *container)
1478 {
1479   g_return_val_if_fail (GTK_IS_CONTAINER (container), 0);
1480
1481   return container->priv->border_width;
1482 }
1483
1484 /**
1485  * gtk_container_add:
1486  * @container: a #GtkContainer
1487  * @widget: a widget to be placed inside @container
1488  *
1489  * Adds @widget to @container. Typically used for simple containers
1490  * such as #GtkWindow, #GtkFrame, or #GtkButton; for more complicated
1491  * layout containers such as #GtkBox or #GtkGrid, this function will
1492  * pick default packing parameters that may not be correct.  So
1493  * consider functions such as gtk_box_pack_start() and
1494  * gtk_grid_attach() as an alternative to gtk_container_add() in
1495  * those cases. A widget may be added to only one container at a time;
1496  * you can't place the same widget inside two different containers.
1497  **/
1498 void
1499 gtk_container_add (GtkContainer *container,
1500                    GtkWidget    *widget)
1501 {
1502   GtkWidget *parent;
1503
1504   g_return_if_fail (GTK_IS_CONTAINER (container));
1505   g_return_if_fail (GTK_IS_WIDGET (widget));
1506
1507   parent = gtk_widget_get_parent (widget);
1508
1509   if (parent != NULL)
1510     {
1511       g_warning ("Attempting to add a widget with type %s to a container of "
1512                  "type %s, but the widget is already inside a container of type %s, "
1513                  "please use gtk_widget_reparent()" ,
1514                  g_type_name (G_OBJECT_TYPE (widget)),
1515                  g_type_name (G_OBJECT_TYPE (container)),
1516                  g_type_name (G_OBJECT_TYPE (parent)));
1517       return;
1518     }
1519
1520   g_signal_emit (container, container_signals[ADD], 0, widget);
1521 }
1522
1523 /**
1524  * gtk_container_remove:
1525  * @container: a #GtkContainer
1526  * @widget: a current child of @container
1527  *
1528  * Removes @widget from @container. @widget must be inside @container.
1529  * Note that @container will own a reference to @widget, and that this
1530  * may be the last reference held; so removing a widget from its
1531  * container can destroy that widget. If you want to use @widget
1532  * again, you need to add a reference to it while it's not inside
1533  * a container, using g_object_ref(). If you don't want to use @widget
1534  * again it's usually more efficient to simply destroy it directly
1535  * using gtk_widget_destroy() since this will remove it from the
1536  * container and help break any circular reference count cycles.
1537  **/
1538 void
1539 gtk_container_remove (GtkContainer *container,
1540                       GtkWidget    *widget)
1541 {
1542   g_return_if_fail (GTK_IS_CONTAINER (container));
1543   g_return_if_fail (GTK_IS_WIDGET (widget));
1544   g_return_if_fail (gtk_widget_get_parent (widget) == GTK_WIDGET (container) || GTK_IS_ASSISTANT (container));
1545
1546   g_signal_emit (container, container_signals[REMOVE], 0, widget);
1547 }
1548
1549 void
1550 _gtk_container_dequeue_resize_handler (GtkContainer *container)
1551 {
1552   g_return_if_fail (GTK_IS_CONTAINER (container));
1553   g_return_if_fail (container->priv->resize_pending);
1554
1555   container->priv->resize_pending = FALSE;
1556 }
1557
1558 /**
1559  * gtk_container_set_resize_mode:
1560  * @container: a #GtkContainer
1561  * @resize_mode: the new resize mode
1562  *
1563  * Sets the resize mode for the container.
1564  *
1565  * The resize mode of a container determines whether a resize request
1566  * will be passed to the container's parent, queued for later execution
1567  * or executed immediately.
1568  **/
1569 void
1570 gtk_container_set_resize_mode (GtkContainer  *container,
1571                                GtkResizeMode  resize_mode)
1572 {
1573   GtkContainerPrivate *priv;
1574
1575   g_return_if_fail (GTK_IS_CONTAINER (container));
1576   g_return_if_fail (resize_mode <= GTK_RESIZE_IMMEDIATE);
1577
1578   priv = container->priv;
1579
1580   if (gtk_widget_is_toplevel (GTK_WIDGET (container)) &&
1581       resize_mode == GTK_RESIZE_PARENT)
1582     {
1583       resize_mode = GTK_RESIZE_QUEUE;
1584     }
1585
1586   if (priv->resize_mode != resize_mode)
1587     {
1588       priv->resize_mode = resize_mode;
1589
1590       gtk_widget_queue_resize (GTK_WIDGET (container));
1591       g_object_notify (G_OBJECT (container), "resize-mode");
1592     }
1593 }
1594
1595 /**
1596  * gtk_container_get_resize_mode:
1597  * @container: a #GtkContainer
1598  *
1599  * Returns the resize mode for the container. See
1600  * gtk_container_set_resize_mode ().
1601  *
1602  * Return value: the current resize mode
1603  **/
1604 GtkResizeMode
1605 gtk_container_get_resize_mode (GtkContainer *container)
1606 {
1607   g_return_val_if_fail (GTK_IS_CONTAINER (container), GTK_RESIZE_PARENT);
1608
1609   return container->priv->resize_mode;
1610 }
1611
1612 /**
1613  * gtk_container_set_reallocate_redraws:
1614  * @container: a #GtkContainer
1615  * @needs_redraws: the new value for the container's @reallocate_redraws flag
1616  *
1617  * Sets the @reallocate_redraws flag of the container to the given value.
1618  *
1619  * Containers requesting reallocation redraws get automatically
1620  * redrawn if any of their children changed allocation.
1621  **/
1622 void
1623 gtk_container_set_reallocate_redraws (GtkContainer *container,
1624                                       gboolean      needs_redraws)
1625 {
1626   g_return_if_fail (GTK_IS_CONTAINER (container));
1627
1628   container->priv->reallocate_redraws = needs_redraws ? TRUE : FALSE;
1629 }
1630
1631 static void
1632 gtk_container_idle_sizer (GdkFrameClock *clock,
1633                           GtkContainer  *container)
1634 {
1635   /* We validate the style contexts in a single loop before even trying
1636    * to handle resizes instead of doing validations inline.
1637    * This is mostly necessary for compatibility reasons with old code,
1638    * because both style_updated and size_allocate functions often change
1639    * styles and so could cause infinite loops in this function.
1640    *
1641    * It's important to note that even an invalid style context returns
1642    * sane values. So the result of an invalid style context will never be
1643    * a program crash, but only a wrong layout or rendering.
1644    */
1645   if (container->priv->restyle_pending)
1646     {
1647       GtkBitmask *empty;
1648       gint64 current_time;
1649
1650       empty = _gtk_bitmask_new ();
1651       current_time = g_get_monotonic_time ();
1652
1653       container->priv->restyle_pending = FALSE;
1654       _gtk_style_context_validate (gtk_widget_get_style_context (GTK_WIDGET (container)),
1655                                    current_time,
1656                                    0,
1657                                    empty);
1658
1659       _gtk_bitmask_free (empty);
1660     }
1661
1662   /* we may be invoked with a container_resize_queue of NULL, because
1663    * queue_resize could have been adding an extra idle function while
1664    * the queue still got processed. we better just ignore such case
1665    * than trying to explicitely work around them with some extra flags,
1666    * since it doesn't cause any actual harm.
1667    */
1668   if (container->priv->resize_pending)
1669     {
1670       container->priv->resize_pending = FALSE;
1671       gtk_container_check_resize (container);
1672     }
1673
1674   if (!container->priv->restyle_pending && !container->priv->resize_pending)
1675     {
1676       _gtk_container_stop_idle_sizer (container);
1677     }
1678   else
1679     {
1680       gdk_frame_clock_request_phase (clock,
1681                                      GDK_FRAME_CLOCK_PHASE_LAYOUT);
1682     }
1683 }
1684
1685 static void
1686 gtk_container_start_idle_sizer (GtkContainer *container)
1687 {
1688   GdkFrameClock *clock;
1689
1690   if (container->priv->resize_handler != 0)
1691     return;
1692
1693   clock = gtk_widget_get_frame_clock (GTK_WIDGET (container));
1694   if (clock == NULL)
1695     return;
1696
1697   container->priv->resize_clock = clock;
1698   container->priv->resize_handler = g_signal_connect (clock, "layout",
1699                                                       G_CALLBACK (gtk_container_idle_sizer), container);
1700   gdk_frame_clock_request_phase (clock,
1701                                  GDK_FRAME_CLOCK_PHASE_LAYOUT);
1702 }
1703
1704 void
1705 _gtk_container_stop_idle_sizer (GtkContainer *container)
1706 {
1707   if (container->priv->resize_handler == 0)
1708     return;
1709
1710   g_signal_handler_disconnect (container->priv->resize_clock,
1711                                container->priv->resize_handler);
1712   container->priv->resize_handler = 0;
1713   container->priv->resize_clock = NULL;
1714 }
1715
1716 static void
1717 gtk_container_queue_resize_handler (GtkContainer *container)
1718 {
1719   GtkWidget *widget;
1720
1721   g_return_if_fail (GTK_IS_RESIZE_CONTAINER (container));
1722
1723   widget = GTK_WIDGET (container);
1724
1725   if (gtk_widget_get_visible (widget) &&
1726       (gtk_widget_is_toplevel (widget) ||
1727        gtk_widget_get_realized (widget)))
1728     {
1729       switch (container->priv->resize_mode)
1730         {
1731         case GTK_RESIZE_QUEUE:
1732           if (!container->priv->resize_pending)
1733             {
1734               container->priv->resize_pending = TRUE;
1735               gtk_container_start_idle_sizer (container);
1736             }
1737           break;
1738
1739         case GTK_RESIZE_IMMEDIATE:
1740           gtk_container_check_resize (container);
1741           break;
1742
1743         case GTK_RESIZE_PARENT:
1744         default:
1745           g_assert_not_reached ();
1746           break;
1747         }
1748     }
1749 }
1750
1751 static void
1752 _gtk_container_queue_resize_internal (GtkContainer *container,
1753                                       gboolean      invalidate_only)
1754 {
1755   GtkWidget *widget;
1756
1757   g_return_if_fail (GTK_IS_CONTAINER (container));
1758
1759   widget = GTK_WIDGET (container);
1760
1761   do
1762     {
1763       _gtk_widget_set_alloc_needed (widget, TRUE);
1764       _gtk_size_request_cache_clear (_gtk_widget_peek_request_cache (widget));
1765
1766       if (GTK_IS_RESIZE_CONTAINER (widget))
1767         break;
1768
1769       widget = gtk_widget_get_parent (widget);
1770     }
1771   while (widget);
1772
1773   if (widget && !invalidate_only)
1774     gtk_container_queue_resize_handler (GTK_CONTAINER (widget));
1775 }
1776
1777 void
1778 _gtk_container_queue_restyle (GtkContainer *container)
1779 {
1780   GtkContainerPrivate *priv;
1781
1782   g_return_if_fail (GTK_CONTAINER (container));
1783
1784   priv = container->priv;
1785
1786   if (priv->restyle_pending)
1787     return;
1788
1789   gtk_container_start_idle_sizer (container);
1790   priv->restyle_pending = TRUE;
1791 }
1792
1793 /**
1794  * _gtk_container_queue_resize:
1795  * @container: a #GtkContainer
1796  *
1797  * Determines the "resize container" in the hierarchy above this container
1798  * (typically the toplevel, but other containers can be set as resize
1799  * containers with gtk_container_set_resize_mode()), marks the container
1800  * and all parents up to and including the resize container as needing
1801  * to have sizes recompted, and if necessary adds the resize container
1802  * to the queue of containers that will be resized out at idle.
1803  */
1804 void
1805 _gtk_container_queue_resize (GtkContainer *container)
1806 {
1807   _gtk_container_queue_resize_internal (container, FALSE);
1808 }
1809
1810 /**
1811  * _gtk_container_resize_invalidate:
1812  * @container: a #GtkContainer
1813  *
1814  * Invalidates cached sizes like _gtk_container_queue_resize() but doesn't
1815  * actually queue the resize container for resize.
1816  */
1817 void
1818 _gtk_container_resize_invalidate (GtkContainer *container)
1819 {
1820   _gtk_container_queue_resize_internal (container, TRUE);
1821 }
1822
1823 void
1824 _gtk_container_maybe_start_idle_sizer (GtkContainer *container)
1825 {
1826   if (container->priv->restyle_pending || container->priv->resize_pending)
1827     gtk_container_start_idle_sizer (container);
1828 }
1829
1830 void
1831 gtk_container_check_resize (GtkContainer *container)
1832 {
1833   g_return_if_fail (GTK_IS_CONTAINER (container));
1834
1835   g_signal_emit (container, container_signals[CHECK_RESIZE], 0);
1836 }
1837
1838 static void
1839 gtk_container_real_check_resize (GtkContainer *container)
1840 {
1841   GtkWidget *widget = GTK_WIDGET (container);
1842   GtkAllocation allocation;
1843   GtkRequisition requisition;
1844
1845   gtk_widget_get_preferred_size (widget,
1846                                  &requisition, NULL);
1847   gtk_widget_get_allocation (widget, &allocation);
1848
1849   if (requisition.width > allocation.width ||
1850       requisition.height > allocation.height)
1851     {
1852       if (GTK_IS_RESIZE_CONTAINER (container))
1853         {
1854           gtk_widget_size_allocate (widget, &allocation);
1855           gtk_widget_set_allocation (widget, &allocation);
1856         }
1857       else
1858         gtk_widget_queue_resize (widget);
1859     }
1860   else
1861     {
1862       gtk_container_resize_children (container);
1863     }
1864 }
1865
1866 /* The container hasn't changed size but one of its children
1867  *  queued a resize request. Which means that the allocation
1868  *  is not sufficient for the requisition of some child.
1869  *  We've already performed a size request at this point,
1870  *  so we simply need to reallocate and let the allocation
1871  *  trickle down via GTK_WIDGET_ALLOC_NEEDED flags.
1872  */
1873 void
1874 gtk_container_resize_children (GtkContainer *container)
1875 {
1876   GtkAllocation allocation;
1877   GtkWidget *widget;
1878
1879   /* resizing invariants:
1880    * toplevels have *always* resize_mode != GTK_RESIZE_PARENT set.
1881    * containers that have an idle sizer pending must be flagged with
1882    * RESIZE_PENDING.
1883    */
1884   g_return_if_fail (GTK_IS_CONTAINER (container));
1885
1886   widget = GTK_WIDGET (container);
1887   gtk_widget_get_allocation (widget, &allocation);
1888
1889   gtk_widget_size_allocate (widget, &allocation);
1890   gtk_widget_set_allocation (widget, &allocation);
1891 }
1892
1893 static void
1894 gtk_container_adjust_size_request (GtkWidget         *widget,
1895                                    GtkOrientation     orientation,
1896                                    gint              *minimum_size,
1897                                    gint              *natural_size)
1898 {
1899   GtkContainer *container;
1900
1901   container = GTK_CONTAINER (widget);
1902
1903   if (GTK_CONTAINER_GET_CLASS (widget)->_handle_border_width)
1904     {
1905       int border_width;
1906
1907       border_width = container->priv->border_width;
1908
1909       *minimum_size += border_width * 2;
1910       *natural_size += border_width * 2;
1911     }
1912
1913   /* chain up last so gtk_widget_set_size_request() values
1914    * will have a chance to overwrite our border width.
1915    */
1916   parent_class->adjust_size_request (widget, orientation,
1917                                      minimum_size, natural_size);
1918 }
1919
1920 static void
1921 gtk_container_adjust_size_allocation (GtkWidget         *widget,
1922                                       GtkOrientation     orientation,
1923                                       gint              *minimum_size,
1924                                       gint              *natural_size,
1925                                       gint              *allocated_pos,
1926                                       gint              *allocated_size)
1927 {
1928   GtkContainer *container;
1929   int border_width;
1930
1931   container = GTK_CONTAINER (widget);
1932
1933   if (GTK_CONTAINER_GET_CLASS (widget)->_handle_border_width)
1934     {
1935       border_width = container->priv->border_width;
1936
1937       *allocated_size -= border_width * 2;
1938       *allocated_pos += border_width;
1939       *minimum_size -= border_width * 2;
1940       *natural_size -= border_width * 2;
1941     }
1942
1943   /* Chain up to GtkWidgetClass *after* removing our border width from
1944    * the proposed allocation size. This is because it's possible that the
1945    * widget was allocated more space than it needs in a said orientation,
1946    * if GtkWidgetClass does any alignments and thus limits the size to the
1947    * natural size... then we need that to be done *after* removing any margins
1948    * and padding values.
1949    */
1950   parent_class->adjust_size_allocation (widget, orientation,
1951                                         minimum_size, natural_size, allocated_pos,
1952                                         allocated_size);
1953 }
1954
1955 typedef struct {
1956   gint hfw;
1957   gint wfh;
1958 } RequestModeCount;
1959
1960 static void
1961 count_request_modes (GtkWidget        *widget,
1962                      RequestModeCount *count)
1963 {
1964   GtkSizeRequestMode mode = gtk_widget_get_request_mode (widget);
1965
1966   switch (mode)
1967     {
1968     case GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH:
1969       count->hfw++;
1970       break;
1971     case GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT:
1972       count->wfh++;
1973       break;
1974     case GTK_SIZE_REQUEST_CONSTANT_SIZE:
1975     default:
1976       break;
1977     }
1978 }
1979
1980 static GtkSizeRequestMode 
1981 gtk_container_get_request_mode (GtkWidget *widget)
1982 {
1983   GtkContainer *container = GTK_CONTAINER (widget);
1984   RequestModeCount count = { 0, 0 };
1985
1986   gtk_container_forall (container, (GtkCallback)count_request_modes, &count);
1987
1988   if (!count.hfw && !count.wfh)
1989     return GTK_SIZE_REQUEST_CONSTANT_SIZE;
1990   else
1991     return count.wfh > count.hfw ? 
1992         GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT :
1993         GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
1994 }
1995
1996 /**
1997  * gtk_container_class_handle_border_width:
1998  * @klass: the class struct of a #GtkContainer subclass
1999  *
2000  * Modifies a subclass of #GtkContainerClass to automatically add and
2001  * remove the border-width setting on GtkContainer.  This allows the
2002  * subclass to ignore the border width in its size request and
2003  * allocate methods. The intent is for a subclass to invoke this
2004  * in its class_init function.
2005  *
2006  * gtk_container_class_handle_border_width() is necessary because it
2007  * would break API too badly to make this behavior the default. So
2008  * subclasses must "opt in" to the parent class handling border_width
2009  * for them.
2010  */
2011 void
2012 gtk_container_class_handle_border_width (GtkContainerClass *klass)
2013 {
2014   g_return_if_fail (GTK_IS_CONTAINER_CLASS (klass));
2015
2016   klass->_handle_border_width = TRUE;
2017 }
2018
2019 /**
2020  * gtk_container_forall:
2021  * @container: a #GtkContainer
2022  * @callback: (scope call) (closure callback_data): a callback
2023  * @callback_data: callback user data
2024  *
2025  * Invokes @callback on each child of @container, including children
2026  * that are considered "internal" (implementation details of the
2027  * container). "Internal" children generally weren't added by the user
2028  * of the container, but were added by the container implementation
2029  * itself.  Most applications should use gtk_container_foreach(),
2030  * rather than gtk_container_forall().
2031  *
2032  * Virtual: forall
2033  **/
2034 void
2035 gtk_container_forall (GtkContainer *container,
2036                       GtkCallback   callback,
2037                       gpointer      callback_data)
2038 {
2039   GtkContainerClass *class;
2040
2041   g_return_if_fail (GTK_IS_CONTAINER (container));
2042   g_return_if_fail (callback != NULL);
2043
2044   class = GTK_CONTAINER_GET_CLASS (container);
2045
2046   if (class->forall)
2047     class->forall (container, TRUE, callback, callback_data);
2048 }
2049
2050 /**
2051  * gtk_container_foreach:
2052  * @container: a #GtkContainer
2053  * @callback: (scope call):  a callback
2054  * @callback_data: callback user data
2055  *
2056  * Invokes @callback on each non-internal child of @container. See
2057  * gtk_container_forall() for details on what constitutes an
2058  * "internal" child.  Most applications should use
2059  * gtk_container_foreach(), rather than gtk_container_forall().
2060  **/
2061 void
2062 gtk_container_foreach (GtkContainer *container,
2063                        GtkCallback   callback,
2064                        gpointer      callback_data)
2065 {
2066   GtkContainerClass *class;
2067
2068   g_return_if_fail (GTK_IS_CONTAINER (container));
2069   g_return_if_fail (callback != NULL);
2070
2071   class = GTK_CONTAINER_GET_CLASS (container);
2072
2073   if (class->forall)
2074     class->forall (container, FALSE, callback, callback_data);
2075 }
2076
2077 /**
2078  * gtk_container_set_focus_child:
2079  * @container: a #GtkContainer
2080  * @child: (allow-none): a #GtkWidget, or %NULL
2081  *
2082  * Sets, or unsets if @child is %NULL, the focused child of @container.
2083  *
2084  * This function emits the GtkContainer::set_focus_child signal of
2085  * @container. Implementations of #GtkContainer can override the
2086  * default behaviour by overriding the class closure of this signal.
2087  *
2088  * This is function is mostly meant to be used by widgets. Applications can use
2089  * gtk_widget_grab_focus() to manualy set the focus to a specific widget.
2090  */
2091 void
2092 gtk_container_set_focus_child (GtkContainer *container,
2093                                GtkWidget    *child)
2094 {
2095   g_return_if_fail (GTK_IS_CONTAINER (container));
2096   if (child)
2097     g_return_if_fail (GTK_IS_WIDGET (child));
2098
2099   g_signal_emit (container, container_signals[SET_FOCUS_CHILD], 0, child);
2100 }
2101
2102 /**
2103  * gtk_container_get_focus_child:
2104  * @container: a #GtkContainer
2105  *
2106  * Returns the current focus child widget inside @container. This is not the
2107  * currently focused widget. That can be obtained by calling
2108  * gtk_window_get_focus().
2109  *
2110  * Returns: (transfer none): The child widget which will receive the
2111  *          focus inside @container when the @conatiner is focussed,
2112  *          or %NULL if none is set.
2113  *
2114  * Since: 2.14
2115  **/
2116 GtkWidget *
2117 gtk_container_get_focus_child (GtkContainer *container)
2118 {
2119   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
2120
2121   return container->priv->focus_child;
2122 }
2123
2124 /**
2125  * gtk_container_get_children:
2126  * @container: a #GtkContainer
2127  *
2128  * Returns the container's non-internal children. See
2129  * gtk_container_forall() for details on what constitutes an "internal" child.
2130  *
2131  * Return value: (element-type GtkWidget) (transfer container): a newly-allocated list of the container's non-internal children.
2132  **/
2133 GList*
2134 gtk_container_get_children (GtkContainer *container)
2135 {
2136   GList *children = NULL;
2137
2138   gtk_container_foreach (container,
2139                          gtk_container_children_callback,
2140                          &children);
2141
2142   return g_list_reverse (children);
2143 }
2144
2145 static void
2146 gtk_container_child_position_callback (GtkWidget *widget,
2147                                        gpointer   client_data)
2148 {
2149   struct {
2150     GtkWidget *child;
2151     guint i;
2152     guint index;
2153   } *data = client_data;
2154
2155   data->i++;
2156   if (data->child == widget)
2157     data->index = data->i;
2158 }
2159
2160 static gchar*
2161 gtk_container_child_default_composite_name (GtkContainer *container,
2162                                             GtkWidget    *child)
2163 {
2164   struct {
2165     GtkWidget *child;
2166     guint i;
2167     guint index;
2168   } data;
2169   gchar *name;
2170
2171   /* fallback implementation */
2172   data.child = child;
2173   data.i = 0;
2174   data.index = 0;
2175   gtk_container_forall (container,
2176                         gtk_container_child_position_callback,
2177                         &data);
2178
2179   name = g_strdup_printf ("%s-%u",
2180                           g_type_name (G_TYPE_FROM_INSTANCE (child)),
2181                           data.index);
2182
2183   return name;
2184 }
2185
2186 gchar*
2187 _gtk_container_child_composite_name (GtkContainer *container,
2188                                     GtkWidget    *child)
2189 {
2190   gboolean composite_child;
2191
2192   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
2193   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
2194   g_return_val_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (container), NULL);
2195
2196   g_object_get (child, "composite-child", &composite_child, NULL);
2197   if (composite_child)
2198     {
2199       static GQuark quark_composite_name = 0;
2200       gchar *name;
2201
2202       if (!quark_composite_name)
2203         quark_composite_name = g_quark_from_static_string ("gtk-composite-name");
2204
2205       name = g_object_get_qdata (G_OBJECT (child), quark_composite_name);
2206       if (!name)
2207         {
2208           GtkContainerClass *class;
2209
2210           class = GTK_CONTAINER_GET_CLASS (container);
2211           if (class->composite_name)
2212             name = class->composite_name (container, child);
2213         }
2214       else
2215         name = g_strdup (name);
2216
2217       return name;
2218     }
2219
2220   return NULL;
2221 }
2222
2223 typedef struct {
2224   gboolean hexpand;
2225   gboolean vexpand;
2226 } ComputeExpandData;
2227
2228 static void
2229 gtk_container_compute_expand_callback (GtkWidget *widget,
2230                                        gpointer   client_data)
2231 {
2232   ComputeExpandData *data = client_data;
2233
2234   /* note that we don't get_expand on the child if we already know we
2235    * have to expand, so we only recurse into children until we find
2236    * one that expands and then we basically don't do any more
2237    * work. This means that we can leave some children in a
2238    * need_compute_expand state, which is fine, as long as GtkWidget
2239    * doesn't rely on an invariant that "if a child has
2240    * need_compute_expand, its parents also do"
2241    *
2242    * gtk_widget_compute_expand() always returns FALSE if the
2243    * child is !visible so that's taken care of.
2244    */
2245   data->hexpand = data->hexpand ||
2246     gtk_widget_compute_expand (widget, GTK_ORIENTATION_HORIZONTAL);
2247
2248   data->vexpand = data->vexpand ||
2249     gtk_widget_compute_expand (widget, GTK_ORIENTATION_VERTICAL);
2250 }
2251
2252 static void
2253 gtk_container_compute_expand (GtkWidget         *widget,
2254                               gboolean          *hexpand_p,
2255                               gboolean          *vexpand_p)
2256 {
2257   ComputeExpandData data;
2258
2259   data.hexpand = FALSE;
2260   data.vexpand = FALSE;
2261
2262   gtk_container_forall (GTK_CONTAINER (widget),
2263                         gtk_container_compute_expand_callback,
2264                         &data);
2265
2266   *hexpand_p = data.hexpand;
2267   *vexpand_p = data.vexpand;
2268 }
2269
2270 static void
2271 gtk_container_real_set_focus_child (GtkContainer     *container,
2272                                     GtkWidget        *child)
2273 {
2274   GtkContainerPrivate *priv;
2275
2276   g_return_if_fail (GTK_IS_CONTAINER (container));
2277   g_return_if_fail (child == NULL || GTK_IS_WIDGET (child));
2278
2279   priv = container->priv;
2280
2281   if (child != priv->focus_child)
2282     {
2283       if (priv->focus_child)
2284         g_object_unref (priv->focus_child);
2285       priv->focus_child = child;
2286       if (priv->focus_child)
2287         g_object_ref (priv->focus_child);
2288     }
2289
2290
2291   /* check for h/v adjustments
2292    */
2293   if (priv->focus_child)
2294     {
2295       GtkAdjustment *hadj;
2296       GtkAdjustment *vadj;
2297       GtkAllocation allocation;
2298       GtkWidget *focus_child;
2299       gint x, y;
2300
2301       hadj = g_object_get_qdata (G_OBJECT (container), hadjustment_key_id);
2302       vadj = g_object_get_qdata (G_OBJECT (container), vadjustment_key_id);
2303       if (hadj || vadj)
2304         {
2305
2306           focus_child = priv->focus_child;
2307           while (GTK_IS_CONTAINER (focus_child) && gtk_container_get_focus_child (GTK_CONTAINER (focus_child)))
2308             {
2309               focus_child = gtk_container_get_focus_child (GTK_CONTAINER (focus_child));
2310             }
2311
2312           gtk_widget_translate_coordinates (focus_child, priv->focus_child,
2313                                             0, 0, &x, &y);
2314
2315           gtk_widget_get_allocation (priv->focus_child, &allocation);
2316           x += allocation.x;
2317           y += allocation.y;
2318
2319           gtk_widget_get_allocation (focus_child, &allocation);
2320
2321           if (vadj)
2322             gtk_adjustment_clamp_page (vadj, y, y + allocation.height);
2323
2324           if (hadj)
2325             gtk_adjustment_clamp_page (hadj, x, x + allocation.width);
2326         }
2327     }
2328 }
2329
2330 static GList*
2331 get_focus_chain (GtkContainer *container)
2332 {
2333   return g_object_get_data (G_OBJECT (container), "gtk-container-focus-chain");
2334 }
2335
2336 /* same as gtk_container_get_children, except it includes internals
2337  */
2338 GList *
2339 _gtk_container_get_all_children (GtkContainer *container)
2340 {
2341   GList *children = NULL;
2342
2343   gtk_container_forall (container,
2344                          gtk_container_children_callback,
2345                          &children);
2346
2347   return children;
2348 }
2349
2350 static GtkWidgetPath *
2351 gtk_container_real_get_path_for_child (GtkContainer *container,
2352                                        GtkWidget    *child)
2353 {
2354   GtkStyleContext *context;
2355   GtkWidgetPath *path;
2356   GList *classes;
2357
2358   context = gtk_widget_get_style_context (GTK_WIDGET (container));
2359   path = _gtk_widget_create_path (GTK_WIDGET (container));
2360
2361   /* Copy any permanent classes to the path */
2362   classes = gtk_style_context_list_classes (context);
2363
2364   while (classes)
2365     {
2366       GList *cur;
2367
2368       cur = classes;
2369       classes = classes->next;
2370
2371       gtk_widget_path_iter_add_class (path, -1, cur->data);
2372       g_list_free_1 (cur);
2373     }
2374
2375   gtk_widget_path_append_for_widget (path, child);
2376
2377   return path;
2378 }
2379
2380 static gboolean
2381 gtk_container_focus (GtkWidget        *widget,
2382                      GtkDirectionType  direction)
2383 {
2384   GList *children;
2385   GList *sorted_children;
2386   gint return_val;
2387   GtkContainer *container;
2388   GtkContainerPrivate *priv;
2389
2390   g_return_val_if_fail (GTK_IS_CONTAINER (widget), FALSE);
2391
2392   container = GTK_CONTAINER (widget);
2393   priv = container->priv;
2394
2395   return_val = FALSE;
2396
2397   if (gtk_widget_get_can_focus (widget))
2398     {
2399       if (!gtk_widget_has_focus (widget))
2400         {
2401           gtk_widget_grab_focus (widget);
2402           return_val = TRUE;
2403         }
2404     }
2405   else
2406     {
2407       /* Get a list of the containers children, allowing focus
2408        * chain to override.
2409        */
2410       if (priv->has_focus_chain)
2411         children = g_list_copy (get_focus_chain (container));
2412       else
2413         children = _gtk_container_get_all_children (container);
2414
2415       if (priv->has_focus_chain &&
2416           (direction == GTK_DIR_TAB_FORWARD ||
2417            direction == GTK_DIR_TAB_BACKWARD))
2418         {
2419           sorted_children = g_list_copy (children);
2420
2421           if (direction == GTK_DIR_TAB_BACKWARD)
2422             sorted_children = g_list_reverse (sorted_children);
2423         }
2424       else
2425         sorted_children = _gtk_container_focus_sort (container, children, direction, NULL);
2426
2427       return_val = gtk_container_focus_move (container, sorted_children, direction);
2428
2429       g_list_free (sorted_children);
2430       g_list_free (children);
2431     }
2432
2433   return return_val;
2434 }
2435
2436 static gint
2437 tab_compare (gconstpointer a,
2438              gconstpointer b,
2439              gpointer      data)
2440 {
2441   GtkAllocation child1_allocation, child2_allocation;
2442   const GtkWidget *child1 = a;
2443   const GtkWidget *child2 = b;
2444   GtkTextDirection text_direction = GPOINTER_TO_INT (data);
2445   gint y1, y2;
2446
2447   gtk_widget_get_allocation ((GtkWidget *) child1, &child1_allocation);
2448   gtk_widget_get_allocation ((GtkWidget *) child2, &child2_allocation);
2449
2450   y1 = child1_allocation.y + child1_allocation.height / 2;
2451   y2 = child2_allocation.y + child2_allocation.height / 2;
2452
2453   if (y1 == y2)
2454     {
2455       gint x1 = child1_allocation.x + child1_allocation.width / 2;
2456       gint x2 = child2_allocation.x + child2_allocation.width / 2;
2457
2458       if (text_direction == GTK_TEXT_DIR_RTL)
2459         return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1);
2460       else
2461         return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1);
2462     }
2463   else
2464     return (y1 < y2) ? -1 : 1;
2465 }
2466
2467 static GList *
2468 gtk_container_focus_sort_tab (GtkContainer     *container,
2469                               GList            *children,
2470                               GtkDirectionType  direction,
2471                               GtkWidget        *old_focus)
2472 {
2473   GtkTextDirection text_direction = gtk_widget_get_direction (GTK_WIDGET (container));
2474   children = g_list_sort_with_data (children, tab_compare, GINT_TO_POINTER (text_direction));
2475
2476   /* if we are going backwards then reverse the order
2477    *  of the children.
2478    */
2479   if (direction == GTK_DIR_TAB_BACKWARD)
2480     children = g_list_reverse (children);
2481
2482   return children;
2483 }
2484
2485 /* Get coordinates of @widget's allocation with respect to
2486  * allocation of @container.
2487  */
2488 static gboolean
2489 get_allocation_coords (GtkContainer  *container,
2490                        GtkWidget     *widget,
2491                        GdkRectangle  *allocation)
2492 {
2493   gtk_widget_get_allocation (widget, allocation);
2494
2495   return gtk_widget_translate_coordinates (widget, GTK_WIDGET (container),
2496                                            0, 0, &allocation->x, &allocation->y);
2497 }
2498
2499 /* Look for a child in @children that is intermediate between
2500  * the focus widget and container. This widget, if it exists,
2501  * acts as the starting widget for focus navigation.
2502  */
2503 static GtkWidget *
2504 find_old_focus (GtkContainer *container,
2505                 GList        *children)
2506 {
2507   GList *tmp_list = children;
2508   while (tmp_list)
2509     {
2510       GtkWidget *child = tmp_list->data;
2511       GtkWidget *widget = child;
2512
2513       while (widget && widget != (GtkWidget *)container)
2514         {
2515           GtkWidget *parent;
2516
2517           parent = gtk_widget_get_parent (widget);
2518
2519           if (parent && (gtk_container_get_focus_child (GTK_CONTAINER (parent)) != widget))
2520             goto next;
2521
2522           widget = parent;
2523         }
2524
2525       return child;
2526
2527     next:
2528       tmp_list = tmp_list->next;
2529     }
2530
2531   return NULL;
2532 }
2533
2534 static gboolean
2535 old_focus_coords (GtkContainer *container,
2536                   GdkRectangle *old_focus_rect)
2537 {
2538   GtkWidget *widget = GTK_WIDGET (container);
2539   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
2540   GtkWidget *old_focus;
2541
2542   if (GTK_IS_WINDOW (toplevel))
2543     {
2544       old_focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
2545       if (old_focus)
2546         return get_allocation_coords (container, old_focus, old_focus_rect);
2547     }
2548
2549   return FALSE;
2550 }
2551
2552 typedef struct _CompareInfo CompareInfo;
2553
2554 struct _CompareInfo
2555 {
2556   GtkContainer *container;
2557   gint x;
2558   gint y;
2559   gboolean reverse;
2560 };
2561
2562 static gint
2563 up_down_compare (gconstpointer a,
2564                  gconstpointer b,
2565                  gpointer      data)
2566 {
2567   GdkRectangle allocation1;
2568   GdkRectangle allocation2;
2569   CompareInfo *compare = data;
2570   gint y1, y2;
2571
2572   get_allocation_coords (compare->container, (GtkWidget *)a, &allocation1);
2573   get_allocation_coords (compare->container, (GtkWidget *)b, &allocation2);
2574
2575   y1 = allocation1.y + allocation1.height / 2;
2576   y2 = allocation2.y + allocation2.height / 2;
2577
2578   if (y1 == y2)
2579     {
2580       gint x1 = abs (allocation1.x + allocation1.width / 2 - compare->x);
2581       gint x2 = abs (allocation2.x + allocation2.width / 2 - compare->x);
2582
2583       if (compare->reverse)
2584         return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1);
2585       else
2586         return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1);
2587     }
2588   else
2589     return (y1 < y2) ? -1 : 1;
2590 }
2591
2592 static GList *
2593 gtk_container_focus_sort_up_down (GtkContainer     *container,
2594                                   GList            *children,
2595                                   GtkDirectionType  direction,
2596                                   GtkWidget        *old_focus)
2597 {
2598   CompareInfo compare;
2599   GList *tmp_list;
2600   GdkRectangle old_allocation;
2601
2602   compare.container = container;
2603   compare.reverse = (direction == GTK_DIR_UP);
2604
2605   if (!old_focus)
2606       old_focus = find_old_focus (container, children);
2607
2608   if (old_focus && get_allocation_coords (container, old_focus, &old_allocation))
2609     {
2610       gint compare_x1;
2611       gint compare_x2;
2612       gint compare_y;
2613
2614       /* Delete widgets from list that don't match minimum criteria */
2615
2616       compare_x1 = old_allocation.x;
2617       compare_x2 = old_allocation.x + old_allocation.width;
2618
2619       if (direction == GTK_DIR_UP)
2620         compare_y = old_allocation.y;
2621       else
2622         compare_y = old_allocation.y + old_allocation.height;
2623
2624       tmp_list = children;
2625       while (tmp_list)
2626         {
2627           GtkWidget *child = tmp_list->data;
2628           GList *next = tmp_list->next;
2629           gint child_x1, child_x2;
2630           GdkRectangle child_allocation;
2631
2632           if (child != old_focus)
2633             {
2634               if (get_allocation_coords (container, child, &child_allocation))
2635                 {
2636                   child_x1 = child_allocation.x;
2637                   child_x2 = child_allocation.x + child_allocation.width;
2638
2639                   if ((child_x2 <= compare_x1 || child_x1 >= compare_x2) /* No horizontal overlap */ ||
2640                       (direction == GTK_DIR_DOWN && child_allocation.y + child_allocation.height < compare_y) || /* Not below */
2641                       (direction == GTK_DIR_UP && child_allocation.y > compare_y)) /* Not above */
2642                     {
2643                       children = g_list_delete_link (children, tmp_list);
2644                     }
2645                 }
2646               else
2647                 children = g_list_delete_link (children, tmp_list);
2648             }
2649
2650           tmp_list = next;
2651         }
2652
2653       compare.x = (compare_x1 + compare_x2) / 2;
2654       compare.y = old_allocation.y + old_allocation.height / 2;
2655     }
2656   else
2657     {
2658       /* No old focus widget, need to figure out starting x,y some other way
2659        */
2660       GtkAllocation allocation;
2661       GtkWidget *widget = GTK_WIDGET (container);
2662       GdkRectangle old_focus_rect;
2663
2664       gtk_widget_get_allocation (widget, &allocation);
2665
2666       if (old_focus_coords (container, &old_focus_rect))
2667         {
2668           compare.x = old_focus_rect.x + old_focus_rect.width / 2;
2669         }
2670       else
2671         {
2672           if (!gtk_widget_get_has_window (widget))
2673             compare.x = allocation.x + allocation.width / 2;
2674           else
2675             compare.x = allocation.width / 2;
2676         }
2677
2678       if (!gtk_widget_get_has_window (widget))
2679         compare.y = (direction == GTK_DIR_DOWN) ? allocation.y : allocation.y + allocation.height;
2680       else
2681         compare.y = (direction == GTK_DIR_DOWN) ? 0 : + allocation.height;
2682     }
2683
2684   children = g_list_sort_with_data (children, up_down_compare, &compare);
2685
2686   if (compare.reverse)
2687     children = g_list_reverse (children);
2688
2689   return children;
2690 }
2691
2692 static gint
2693 left_right_compare (gconstpointer a,
2694                     gconstpointer b,
2695                     gpointer      data)
2696 {
2697   GdkRectangle allocation1;
2698   GdkRectangle allocation2;
2699   CompareInfo *compare = data;
2700   gint x1, x2;
2701
2702   get_allocation_coords (compare->container, (GtkWidget *)a, &allocation1);
2703   get_allocation_coords (compare->container, (GtkWidget *)b, &allocation2);
2704
2705   x1 = allocation1.x + allocation1.width / 2;
2706   x2 = allocation2.x + allocation2.width / 2;
2707
2708   if (x1 == x2)
2709     {
2710       gint y1 = abs (allocation1.y + allocation1.height / 2 - compare->y);
2711       gint y2 = abs (allocation2.y + allocation2.height / 2 - compare->y);
2712
2713       if (compare->reverse)
2714         return (y1 < y2) ? 1 : ((y1 == y2) ? 0 : -1);
2715       else
2716         return (y1 < y2) ? -1 : ((y1 == y2) ? 0 : 1);
2717     }
2718   else
2719     return (x1 < x2) ? -1 : 1;
2720 }
2721
2722 static GList *
2723 gtk_container_focus_sort_left_right (GtkContainer     *container,
2724                                      GList            *children,
2725                                      GtkDirectionType  direction,
2726                                      GtkWidget        *old_focus)
2727 {
2728   CompareInfo compare;
2729   GList *tmp_list;
2730   GdkRectangle old_allocation;
2731
2732   compare.container = container;
2733   compare.reverse = (direction == GTK_DIR_LEFT);
2734
2735   if (!old_focus)
2736     old_focus = find_old_focus (container, children);
2737
2738   if (old_focus && get_allocation_coords (container, old_focus, &old_allocation))
2739     {
2740       gint compare_y1;
2741       gint compare_y2;
2742       gint compare_x;
2743
2744       /* Delete widgets from list that don't match minimum criteria */
2745
2746       compare_y1 = old_allocation.y;
2747       compare_y2 = old_allocation.y + old_allocation.height;
2748
2749       if (direction == GTK_DIR_LEFT)
2750         compare_x = old_allocation.x;
2751       else
2752         compare_x = old_allocation.x + old_allocation.width;
2753
2754       tmp_list = children;
2755       while (tmp_list)
2756         {
2757           GtkWidget *child = tmp_list->data;
2758           GList *next = tmp_list->next;
2759           gint child_y1, child_y2;
2760           GdkRectangle child_allocation;
2761
2762           if (child != old_focus)
2763             {
2764               if (get_allocation_coords (container, child, &child_allocation))
2765                 {
2766                   child_y1 = child_allocation.y;
2767                   child_y2 = child_allocation.y + child_allocation.height;
2768
2769                   if ((child_y2 <= compare_y1 || child_y1 >= compare_y2) /* No vertical overlap */ ||
2770                       (direction == GTK_DIR_RIGHT && child_allocation.x + child_allocation.width < compare_x) || /* Not to left */
2771                       (direction == GTK_DIR_LEFT && child_allocation.x > compare_x)) /* Not to right */
2772                     {
2773                       children = g_list_delete_link (children, tmp_list);
2774                     }
2775                 }
2776               else
2777                 children = g_list_delete_link (children, tmp_list);
2778             }
2779
2780           tmp_list = next;
2781         }
2782
2783       compare.y = (compare_y1 + compare_y2) / 2;
2784       compare.x = old_allocation.x + old_allocation.width / 2;
2785     }
2786   else
2787     {
2788       /* No old focus widget, need to figure out starting x,y some other way
2789        */
2790       GtkAllocation allocation;
2791       GtkWidget *widget = GTK_WIDGET (container);
2792       GdkRectangle old_focus_rect;
2793
2794       gtk_widget_get_allocation (widget, &allocation);
2795
2796       if (old_focus_coords (container, &old_focus_rect))
2797         {
2798           compare.y = old_focus_rect.y + old_focus_rect.height / 2;
2799         }
2800       else
2801         {
2802           if (!gtk_widget_get_has_window (widget))
2803             compare.y = allocation.y + allocation.height / 2;
2804           else
2805             compare.y = allocation.height / 2;
2806         }
2807
2808       if (!gtk_widget_get_has_window (widget))
2809         compare.x = (direction == GTK_DIR_RIGHT) ? allocation.x : allocation.x + allocation.width;
2810       else
2811         compare.x = (direction == GTK_DIR_RIGHT) ? 0 : allocation.width;
2812     }
2813
2814   children = g_list_sort_with_data (children, left_right_compare, &compare);
2815
2816   if (compare.reverse)
2817     children = g_list_reverse (children);
2818
2819   return children;
2820 }
2821
2822 /**
2823  * gtk_container_focus_sort:
2824  * @container: a #GtkContainer
2825  * @children:  a list of descendents of @container (they don't
2826  *             have to be direct children)
2827  * @direction: focus direction
2828  * @old_focus: (allow-none): widget to use for the starting position, or %NULL
2829  *             to determine this automatically.
2830  *             (Note, this argument isn't used for GTK_DIR_TAB_*,
2831  *              which is the only @direction we use currently,
2832  *              so perhaps this argument should be removed)
2833  *
2834  * Sorts @children in the correct order for focusing with
2835  * direction type @direction.
2836  *
2837  * Return value: a copy of @children, sorted in correct focusing order,
2838  *   with children that aren't suitable for focusing in this direction
2839  *   removed.
2840  **/
2841 GList *
2842 _gtk_container_focus_sort (GtkContainer     *container,
2843                            GList            *children,
2844                            GtkDirectionType  direction,
2845                            GtkWidget        *old_focus)
2846 {
2847   GList *visible_children = NULL;
2848
2849   while (children)
2850     {
2851       if (gtk_widget_get_realized (children->data))
2852         visible_children = g_list_prepend (visible_children, children->data);
2853       children = children->next;
2854     }
2855
2856   switch (direction)
2857     {
2858     case GTK_DIR_TAB_FORWARD:
2859     case GTK_DIR_TAB_BACKWARD:
2860       return gtk_container_focus_sort_tab (container, visible_children, direction, old_focus);
2861     case GTK_DIR_UP:
2862     case GTK_DIR_DOWN:
2863       return gtk_container_focus_sort_up_down (container, visible_children, direction, old_focus);
2864     case GTK_DIR_LEFT:
2865     case GTK_DIR_RIGHT:
2866       return gtk_container_focus_sort_left_right (container, visible_children, direction, old_focus);
2867     }
2868
2869   g_assert_not_reached ();
2870
2871   return NULL;
2872 }
2873
2874 static gboolean
2875 gtk_container_focus_move (GtkContainer     *container,
2876                           GList            *children,
2877                           GtkDirectionType  direction)
2878 {
2879   GtkContainerPrivate *priv = container->priv;
2880   GtkWidget *focus_child;
2881   GtkWidget *child;
2882
2883   focus_child = priv->focus_child;
2884
2885   while (children)
2886     {
2887       child = children->data;
2888       children = children->next;
2889
2890       if (!child)
2891         continue;
2892
2893       if (focus_child)
2894         {
2895           if (focus_child == child)
2896             {
2897               focus_child = NULL;
2898
2899                 if (gtk_widget_child_focus (child, direction))
2900                   return TRUE;
2901             }
2902         }
2903       else if (gtk_widget_is_drawable (child) &&
2904                gtk_widget_is_ancestor (child, GTK_WIDGET (container)))
2905         {
2906           if (gtk_widget_child_focus (child, direction))
2907             return TRUE;
2908         }
2909     }
2910
2911   return FALSE;
2912 }
2913
2914
2915 static void
2916 gtk_container_children_callback (GtkWidget *widget,
2917                                  gpointer   client_data)
2918 {
2919   GList **children;
2920
2921   children = (GList**) client_data;
2922   *children = g_list_prepend (*children, widget);
2923 }
2924
2925 static void
2926 chain_widget_destroyed (GtkWidget *widget,
2927                         gpointer   user_data)
2928 {
2929   GtkContainer *container;
2930   GList *chain;
2931
2932   container = GTK_CONTAINER (user_data);
2933
2934   chain = g_object_get_data (G_OBJECT (container),
2935                              "gtk-container-focus-chain");
2936
2937   chain = g_list_remove (chain, widget);
2938
2939   g_signal_handlers_disconnect_by_func (widget,
2940                                         chain_widget_destroyed,
2941                                         user_data);
2942
2943   g_object_set_data (G_OBJECT (container),
2944                      I_("gtk-container-focus-chain"),
2945                      chain);
2946 }
2947
2948 /**
2949  * gtk_container_set_focus_chain:
2950  * @container: a #GtkContainer
2951  * @focusable_widgets: (transfer none) (element-type GtkWidget):
2952  *     the new focus chain
2953  *
2954  * Sets a focus chain, overriding the one computed automatically by GTK+.
2955  *
2956  * In principle each widget in the chain should be a descendant of the
2957  * container, but this is not enforced by this method, since it's allowed
2958  * to set the focus chain before you pack the widgets, or have a widget
2959  * in the chain that isn't always packed. The necessary checks are done
2960  * when the focus chain is actually traversed.
2961  **/
2962 void
2963 gtk_container_set_focus_chain (GtkContainer *container,
2964                                GList        *focusable_widgets)
2965 {
2966   GList *chain;
2967   GList *tmp_list;
2968   GtkContainerPrivate *priv;
2969
2970   g_return_if_fail (GTK_IS_CONTAINER (container));
2971
2972   priv = container->priv;
2973
2974   if (priv->has_focus_chain)
2975     gtk_container_unset_focus_chain (container);
2976
2977   priv->has_focus_chain = TRUE;
2978
2979   chain = NULL;
2980   tmp_list = focusable_widgets;
2981   while (tmp_list != NULL)
2982     {
2983       g_return_if_fail (GTK_IS_WIDGET (tmp_list->data));
2984
2985       /* In principle each widget in the chain should be a descendant
2986        * of the container, but we don't want to check that here. It's
2987        * expensive and also it's allowed to set the focus chain before
2988        * you pack the widgets, or have a widget in the chain that isn't
2989        * always packed. So we check for ancestor during actual traversal.
2990        */
2991
2992       chain = g_list_prepend (chain, tmp_list->data);
2993
2994       g_signal_connect (tmp_list->data,
2995                         "destroy",
2996                         G_CALLBACK (chain_widget_destroyed),
2997                         container);
2998
2999       tmp_list = g_list_next (tmp_list);
3000     }
3001
3002   chain = g_list_reverse (chain);
3003
3004   g_object_set_data (G_OBJECT (container),
3005                      I_("gtk-container-focus-chain"),
3006                      chain);
3007 }
3008
3009 /**
3010  * gtk_container_get_focus_chain:
3011  * @container:         a #GtkContainer
3012  * @focusable_widgets: (element-type GtkWidget) (out) (transfer container): location
3013  *                     to store the focus chain of the
3014  *                     container, or %NULL. You should free this list
3015  *                     using g_list_free() when you are done with it, however
3016  *                     no additional reference count is added to the
3017  *                     individual widgets in the focus chain.
3018  *
3019  * Retrieves the focus chain of the container, if one has been
3020  * set explicitly. If no focus chain has been explicitly
3021  * set, GTK+ computes the focus chain based on the positions
3022  * of the children. In that case, GTK+ stores %NULL in
3023  * @focusable_widgets and returns %FALSE.
3024  *
3025  * Return value: %TRUE if the focus chain of the container
3026  * has been set explicitly.
3027  **/
3028 gboolean
3029 gtk_container_get_focus_chain (GtkContainer *container,
3030                                GList       **focus_chain)
3031 {
3032   GtkContainerPrivate *priv;
3033
3034   g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
3035
3036   priv = container->priv;
3037
3038   if (focus_chain)
3039     {
3040       if (priv->has_focus_chain)
3041         *focus_chain = g_list_copy (get_focus_chain (container));
3042       else
3043         *focus_chain = NULL;
3044     }
3045
3046   return priv->has_focus_chain;
3047 }
3048
3049 /**
3050  * gtk_container_unset_focus_chain:
3051  * @container: a #GtkContainer
3052  *
3053  * Removes a focus chain explicitly set with gtk_container_set_focus_chain().
3054  **/
3055 void
3056 gtk_container_unset_focus_chain (GtkContainer  *container)
3057 {
3058   GtkContainerPrivate *priv;
3059
3060   g_return_if_fail (GTK_IS_CONTAINER (container));
3061
3062   priv = container->priv;
3063
3064   if (priv->has_focus_chain)
3065     {
3066       GList *chain;
3067       GList *tmp_list;
3068
3069       chain = get_focus_chain (container);
3070
3071       priv->has_focus_chain = FALSE;
3072
3073       g_object_set_data (G_OBJECT (container),
3074                          I_("gtk-container-focus-chain"),
3075                          NULL);
3076
3077       tmp_list = chain;
3078       while (tmp_list != NULL)
3079         {
3080           g_signal_handlers_disconnect_by_func (tmp_list->data,
3081                                                 chain_widget_destroyed,
3082                                                 container);
3083
3084           tmp_list = g_list_next (tmp_list);
3085         }
3086
3087       g_list_free (chain);
3088     }
3089 }
3090
3091 /**
3092  * gtk_container_set_focus_vadjustment:
3093  * @container: a #GtkContainer
3094  * @adjustment: an adjustment which should be adjusted when the focus
3095  *   is moved among the descendents of @container
3096  *
3097  * Hooks up an adjustment to focus handling in a container, so when a
3098  * child of the container is focused, the adjustment is scrolled to
3099  * show that widget. This function sets the vertical alignment. See
3100  * gtk_scrolled_window_get_vadjustment() for a typical way of obtaining
3101  * the adjustment and gtk_container_set_focus_hadjustment() for setting
3102  * the horizontal adjustment.
3103  *
3104  * The adjustments have to be in pixel units and in the same coordinate
3105  * system as the allocation for immediate children of the container.
3106  */
3107 void
3108 gtk_container_set_focus_vadjustment (GtkContainer  *container,
3109                                      GtkAdjustment *adjustment)
3110 {
3111   g_return_if_fail (GTK_IS_CONTAINER (container));
3112   if (adjustment)
3113     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
3114
3115   if (adjustment)
3116     g_object_ref (adjustment);
3117
3118   g_object_set_qdata_full (G_OBJECT (container),
3119                            vadjustment_key_id,
3120                            adjustment,
3121                            g_object_unref);
3122 }
3123
3124 /**
3125  * gtk_container_get_focus_vadjustment:
3126  * @container: a #GtkContainer
3127  *
3128  * Retrieves the vertical focus adjustment for the container. See
3129  * gtk_container_set_focus_vadjustment().
3130  *
3131  * Return value: (transfer none): the vertical focus adjustment, or %NULL if
3132  *   none has been set.
3133  **/
3134 GtkAdjustment *
3135 gtk_container_get_focus_vadjustment (GtkContainer *container)
3136 {
3137   GtkAdjustment *vadjustment;
3138
3139   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
3140
3141   vadjustment = g_object_get_qdata (G_OBJECT (container), vadjustment_key_id);
3142
3143   return vadjustment;
3144 }
3145
3146 /**
3147  * gtk_container_set_focus_hadjustment:
3148  * @container: a #GtkContainer
3149  * @adjustment: an adjustment which should be adjusted when the focus is
3150  *   moved among the descendents of @container
3151  *
3152  * Hooks up an adjustment to focus handling in a container, so when a child
3153  * of the container is focused, the adjustment is scrolled to show that
3154  * widget. This function sets the horizontal alignment.
3155  * See gtk_scrolled_window_get_hadjustment() for a typical way of obtaining
3156  * the adjustment and gtk_container_set_focus_vadjustment() for setting
3157  * the vertical adjustment.
3158  *
3159  * The adjustments have to be in pixel units and in the same coordinate
3160  * system as the allocation for immediate children of the container.
3161  */
3162 void
3163 gtk_container_set_focus_hadjustment (GtkContainer  *container,
3164                                      GtkAdjustment *adjustment)
3165 {
3166   g_return_if_fail (GTK_IS_CONTAINER (container));
3167   if (adjustment)
3168     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
3169
3170   if (adjustment)
3171     g_object_ref (adjustment);
3172
3173   g_object_set_qdata_full (G_OBJECT (container),
3174                            hadjustment_key_id,
3175                            adjustment,
3176                            g_object_unref);
3177 }
3178
3179 /**
3180  * gtk_container_get_focus_hadjustment:
3181  * @container: a #GtkContainer
3182  *
3183  * Retrieves the horizontal focus adjustment for the container. See
3184  * gtk_container_set_focus_hadjustment ().
3185  *
3186  * Return value: (transfer none): the horizontal focus adjustment, or %NULL if
3187  *   none has been set.
3188  **/
3189 GtkAdjustment *
3190 gtk_container_get_focus_hadjustment (GtkContainer *container)
3191 {
3192   GtkAdjustment *hadjustment;
3193
3194   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
3195
3196   hadjustment = g_object_get_qdata (G_OBJECT (container), hadjustment_key_id);
3197
3198   return hadjustment;
3199 }
3200
3201
3202 static void
3203 gtk_container_show_all (GtkWidget *widget)
3204 {
3205   g_return_if_fail (GTK_IS_CONTAINER (widget));
3206
3207   gtk_container_foreach (GTK_CONTAINER (widget),
3208                          (GtkCallback) gtk_widget_show_all,
3209                          NULL);
3210   gtk_widget_show (widget);
3211 }
3212
3213 static void
3214 gtk_container_draw_child (GtkWidget *child,
3215                           gpointer   client_data)
3216 {
3217   struct {
3218     GtkWidget *container;
3219     cairo_t *cr;
3220   } *data = client_data;
3221
3222   gtk_container_propagate_draw (GTK_CONTAINER (data->container),
3223                                 child,
3224                                 data->cr);
3225 }
3226
3227 static gint
3228 gtk_container_draw (GtkWidget *widget,
3229                     cairo_t   *cr)
3230 {
3231   struct {
3232     GtkWidget *container;
3233     cairo_t *cr;
3234   } data;
3235
3236   data.container = widget;
3237   data.cr = cr;
3238
3239   gtk_container_forall (GTK_CONTAINER (widget),
3240                         gtk_container_draw_child,
3241                         &data);
3242
3243   return FALSE;
3244 }
3245
3246 static void
3247 gtk_container_map_child (GtkWidget *child,
3248                          gpointer   client_data)
3249 {
3250   if (gtk_widget_get_visible (child) &&
3251       gtk_widget_get_child_visible (child) &&
3252       !gtk_widget_get_mapped (child))
3253     gtk_widget_map (child);
3254 }
3255
3256 static void
3257 gtk_container_map (GtkWidget *widget)
3258 {
3259   gtk_widget_set_mapped (widget, TRUE);
3260
3261   gtk_container_forall (GTK_CONTAINER (widget),
3262                         gtk_container_map_child,
3263                         NULL);
3264
3265   if (gtk_widget_get_has_window (widget))
3266     gdk_window_show (gtk_widget_get_window (widget));
3267 }
3268
3269 static void
3270 gtk_container_unmap (GtkWidget *widget)
3271 {
3272   gtk_widget_set_mapped (widget, FALSE);
3273
3274   /* hide our window first so user doesn't see all the child windows
3275    * vanishing one by one.  (only matters these days if one of the
3276    * children has an actual native window instead of client-side
3277    * window, e.g. a GtkSocket would)
3278    */
3279   if (gtk_widget_get_has_window (widget))
3280     gdk_window_hide (gtk_widget_get_window (widget));
3281
3282   gtk_container_forall (GTK_CONTAINER (widget),
3283                         (GtkCallback)gtk_widget_unmap,
3284                         NULL);
3285 }
3286
3287 /**
3288  * gtk_container_propagate_draw:
3289  * @container: a #GtkContainer
3290  * @child: a child of @container
3291  * @cr: Cairo context as passed to the container. If you want to use @cr
3292  *   in container's draw function, consider using cairo_save() and
3293  *   cairo_restore() before calling this function.
3294  *
3295  * When a container receives a call to the draw function, it must send
3296  * synthetic #GtkWidget::draw calls to all children that don't have their
3297  * own #GdkWindows. This function provides a convenient way of doing this.
3298  * A container, when it receives a call to its #GtkWidget::draw function,
3299  * calls gtk_container_propagate_draw() once for each child, passing in
3300  * the @cr the container received.
3301  *
3302  * gtk_container_propagate_draw() takes care of translating the origin of @cr,
3303  * and deciding whether the draw needs to be sent to the child. It is a
3304  * convenient and optimized way of getting the same effect as calling
3305  * gtk_widget_draw() on the child directly.
3306  *
3307  * In most cases, a container can simply either inherit the
3308  * #GtkWidget::draw implementation from #GtkContainer, or do some drawing
3309  * and then chain to the ::draw implementation from #GtkContainer.
3310  **/
3311 void
3312 gtk_container_propagate_draw (GtkContainer   *container,
3313                               GtkWidget      *child,
3314                               cairo_t        *cr)
3315 {
3316   GdkEventExpose *event;
3317   GtkAllocation allocation;
3318   GdkWindow *window, *w;
3319   int x, y;
3320
3321   g_return_if_fail (GTK_IS_CONTAINER (container));
3322   g_return_if_fail (GTK_IS_WIDGET (child));
3323   g_return_if_fail (cr != NULL);
3324
3325   g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (container));
3326
3327   event = _gtk_cairo_get_event (cr);
3328   if (event)
3329     {
3330       if (gtk_widget_get_has_window (child) ||
3331           gtk_widget_get_window (child) != event->window)
3332         return;
3333     }
3334
3335   cairo_save (cr);
3336
3337   /* translate coordinates. Ugly business, that. */
3338   if (!gtk_widget_get_has_window (GTK_WIDGET (container)))
3339     {
3340       gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
3341       x = -allocation.x;
3342       y = -allocation.y;
3343     }
3344   else
3345     {
3346       x = 0;
3347       y = 0;
3348     }
3349
3350   window = gtk_widget_get_window (GTK_WIDGET (container));
3351
3352   for (w = gtk_widget_get_window (child); w && w != window; w = gdk_window_get_parent (w))
3353     {
3354       int wx, wy;
3355       gdk_window_get_position (w, &wx, &wy);
3356       x += wx;
3357       y += wy;
3358     }
3359
3360   if (w == NULL)
3361     {
3362       x = 0;
3363       y = 0;
3364     }
3365
3366   if (!gtk_widget_get_has_window (child))
3367     {
3368       gtk_widget_get_allocation (child, &allocation);
3369       x += allocation.x;
3370       y += allocation.y;
3371     }
3372
3373   cairo_translate (cr, x, y);
3374
3375   _gtk_widget_draw_internal (child, cr, TRUE);
3376
3377   cairo_restore (cr);
3378 }
3379
3380 gboolean
3381 _gtk_container_get_reallocate_redraws (GtkContainer *container)
3382 {
3383   return container->priv->reallocate_redraws;
3384 }
3385
3386 /**
3387  * gtk_container_get_path_for_child:
3388  * @container: a #GtkContainer
3389  * @child: a child of @container
3390  *
3391  * Returns a newly created widget path representing all the widget hierarchy
3392  * from the toplevel down to and including @child.
3393  *
3394  * Returns: A newly created #GtkWidgetPath
3395  **/
3396 GtkWidgetPath *
3397 gtk_container_get_path_for_child (GtkContainer *container,
3398                                   GtkWidget    *child)
3399 {
3400   GtkWidgetPath *path;
3401
3402   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
3403   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
3404   g_return_val_if_fail (container == (GtkContainer *) gtk_widget_get_parent (child), NULL);
3405
3406   path = GTK_CONTAINER_GET_CLASS (container)->get_path_for_child (container, child);
3407   if (gtk_widget_path_get_object_type (path) != G_OBJECT_TYPE (child))
3408     {
3409       g_critical ("%s %p returned a widget path for type %s, but child is %s",
3410                   G_OBJECT_TYPE_NAME (container),
3411                   container,
3412                   g_type_name (gtk_widget_path_get_object_type (path)),
3413                   G_OBJECT_TYPE_NAME (child));
3414     }
3415
3416   return path;
3417 }