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