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