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