]> Pileus Git - ~andy/gtk/blob - gtk/gtkcontainer.c
1d9181626f1874b369a3ad718539339332834b41
[~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 #include <stdarg.h>
29 #include <string.h>
30 #include <stdlib.h>
31
32 #include "gtkcontainer.h"
33 #include "gtkprivate.h"
34 #include "gtkmain.h"
35 #include "gtkmarshalers.h"
36 #include "gtkwindow.h"
37 #include "gtkintl.h"
38 #include "gtktoolbar.h"
39 #include <gobject/gobjectnotifyqueue.c>
40 #include <gobject/gvaluecollector.h>
41 #include "gtkalias.h"
42
43
44 enum {
45   ADD,
46   REMOVE,
47   CHECK_RESIZE,
48   SET_FOCUS_CHILD,
49   LAST_SIGNAL
50 };
51
52 enum {
53   PROP_0,
54   PROP_BORDER_WIDTH,
55   PROP_RESIZE_MODE,
56   PROP_CHILD
57 };
58
59 #define PARAM_SPEC_PARAM_ID(pspec)              ((pspec)->param_id)
60 #define PARAM_SPEC_SET_PARAM_ID(pspec, id)      ((pspec)->param_id = (id))
61
62
63 /* --- prototypes --- */
64 static void     gtk_container_base_class_init      (GtkContainerClass *klass);
65 static void     gtk_container_base_class_finalize  (GtkContainerClass *klass);
66 static void     gtk_container_class_init           (GtkContainerClass *klass);
67 static void     gtk_container_init                 (GtkContainer      *container);
68 static void     gtk_container_destroy              (GtkObject         *object);
69 static void     gtk_container_set_property         (GObject         *object,
70                                                     guint            prop_id,
71                                                     const GValue    *value,
72                                                     GParamSpec      *pspec);
73 static void     gtk_container_get_property         (GObject         *object,
74                                                     guint            prop_id,
75                                                     GValue          *value,
76                                                     GParamSpec      *pspec);
77 static void     gtk_container_add_unimplemented    (GtkContainer      *container,
78                                                     GtkWidget         *widget);
79 static void     gtk_container_remove_unimplemented (GtkContainer      *container,
80                                                     GtkWidget         *widget);
81 static void     gtk_container_real_check_resize    (GtkContainer      *container);
82 static gboolean gtk_container_focus                (GtkWidget         *widget,
83                                                     GtkDirectionType   direction);
84 static void     gtk_container_real_set_focus_child (GtkContainer      *container,
85                                                     GtkWidget         *widget);
86
87 static gboolean gtk_container_focus_move           (GtkContainer      *container,
88                                                     GList             *children,
89                                                     GtkDirectionType   direction);
90 static void     gtk_container_children_callback    (GtkWidget         *widget,
91                                                     gpointer           client_data);
92 static void     gtk_container_show_all             (GtkWidget         *widget);
93 static void     gtk_container_hide_all             (GtkWidget         *widget);
94 static gint     gtk_container_expose               (GtkWidget         *widget,
95                                                     GdkEventExpose    *event);
96 static void     gtk_container_map                  (GtkWidget         *widget);
97 static void     gtk_container_unmap                (GtkWidget         *widget);
98
99 static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
100                                                           GtkWidget    *child);
101
102
103 /* --- variables --- */
104 static const gchar           vadjustment_key[] = "gtk-vadjustment";
105 static guint                 vadjustment_key_id = 0;
106 static const gchar           hadjustment_key[] = "gtk-hadjustment";
107 static guint                 hadjustment_key_id = 0;
108 static GSList               *container_resize_queue = NULL;
109 static guint                 container_signals[LAST_SIGNAL] = { 0 };
110 static GtkWidgetClass       *parent_class = NULL;
111 extern GParamSpecPool       *_gtk_widget_child_property_pool;
112 extern GObjectNotifyContext *_gtk_widget_child_property_notify_context;
113
114
115 /* --- functions --- */
116 GType
117 gtk_container_get_type (void)
118 {
119   static GType container_type = 0;
120
121   if (!container_type)
122     {
123       const GTypeInfo container_info =
124       {
125         sizeof (GtkContainerClass),
126         (GBaseInitFunc) gtk_container_base_class_init,
127         (GBaseFinalizeFunc) gtk_container_base_class_finalize,
128         (GClassInitFunc) gtk_container_class_init,
129         NULL        /* class_finalize */,
130         NULL        /* class_data */,
131         sizeof (GtkContainer),
132         0           /* n_preallocs */,
133         (GInstanceInitFunc) gtk_container_init,
134         NULL,       /* value_table */
135       };
136
137       container_type =
138         g_type_register_static (GTK_TYPE_WIDGET, I_("GtkContainer"), 
139                                 &container_info, G_TYPE_FLAG_ABSTRACT);
140     }
141
142   return container_type;
143 }
144
145 static void
146 gtk_container_base_class_init (GtkContainerClass *class)
147 {
148   /* reset instance specifc class fields that don't get inherited */
149   class->set_child_property = NULL;
150   class->get_child_property = NULL;
151 }
152
153 static void
154 gtk_container_base_class_finalize (GtkContainerClass *class)
155 {
156   GList *list, *node;
157
158   list = g_param_spec_pool_list_owned (_gtk_widget_child_property_pool, G_OBJECT_CLASS_TYPE (class));
159   for (node = list; node; node = node->next)
160     {
161       GParamSpec *pspec = node->data;
162
163       g_param_spec_pool_remove (_gtk_widget_child_property_pool, pspec);
164       PARAM_SPEC_SET_PARAM_ID (pspec, 0);
165       g_param_spec_unref (pspec);
166     }
167   g_list_free (list);
168 }
169
170 static void
171 gtk_container_class_init (GtkContainerClass *class)
172 {
173   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
174   GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
175   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
176
177   parent_class = g_type_class_peek_parent (class);
178
179   vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
180   hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
181   
182   gobject_class->set_property = gtk_container_set_property;
183   gobject_class->get_property = gtk_container_get_property;
184
185   object_class->destroy = gtk_container_destroy;
186
187   widget_class->show_all = gtk_container_show_all;
188   widget_class->hide_all = gtk_container_hide_all;
189   widget_class->expose_event = gtk_container_expose;
190   widget_class->map = gtk_container_map;
191   widget_class->unmap = gtk_container_unmap;
192   widget_class->focus = gtk_container_focus;
193   
194   class->add = gtk_container_add_unimplemented;
195   class->remove = gtk_container_remove_unimplemented;
196   class->check_resize = gtk_container_real_check_resize;
197   class->forall = NULL;
198   class->set_focus_child = gtk_container_real_set_focus_child;
199   class->child_type = NULL;
200   class->composite_name = gtk_container_child_default_composite_name;
201
202   g_object_class_install_property (gobject_class,
203                                    PROP_RESIZE_MODE,
204                                    g_param_spec_enum ("resize-mode",
205                                                       P_("Resize mode"),
206                                                       P_("Specify how resize events are handled"),
207                                                       GTK_TYPE_RESIZE_MODE,
208                                                       GTK_RESIZE_PARENT,
209                                                       GTK_PARAM_READWRITE));
210   g_object_class_install_property (gobject_class,
211                                    PROP_BORDER_WIDTH,
212                                    g_param_spec_uint ("border-width",
213                                                       P_("Border width"),
214                                                       P_("The width of the empty border outside the containers children"),
215                                                       0,
216                                                       G_MAXINT,
217                                                       0,
218                                                       GTK_PARAM_READWRITE));
219   g_object_class_install_property (gobject_class,
220                                    PROP_CHILD,
221                                    g_param_spec_object ("child",
222                                                       P_("Child"),
223                                                       P_("Can be used to add a new child to the container"),
224                                                       GTK_TYPE_WIDGET,
225                                                       GTK_PARAM_WRITABLE));
226   container_signals[ADD] =
227     g_signal_new (I_("add"),
228                   G_OBJECT_CLASS_TYPE (object_class),
229                   G_SIGNAL_RUN_FIRST,
230                   G_STRUCT_OFFSET (GtkContainerClass, add),
231                   NULL, NULL,
232                   _gtk_marshal_VOID__OBJECT,
233                   G_TYPE_NONE, 1,
234                   GTK_TYPE_WIDGET);
235   container_signals[REMOVE] =
236     g_signal_new (I_("remove"),
237                   G_OBJECT_CLASS_TYPE (object_class),
238                   G_SIGNAL_RUN_FIRST,
239                   G_STRUCT_OFFSET (GtkContainerClass, remove),
240                   NULL, NULL,
241                   _gtk_marshal_VOID__OBJECT,
242                   G_TYPE_NONE, 1,
243                   GTK_TYPE_WIDGET);
244   container_signals[CHECK_RESIZE] =
245     g_signal_new (I_("check_resize"),
246                   G_OBJECT_CLASS_TYPE (object_class),
247                   G_SIGNAL_RUN_LAST,
248                   G_STRUCT_OFFSET (GtkContainerClass, check_resize),
249                   NULL, NULL,
250                   _gtk_marshal_VOID__VOID,
251                   G_TYPE_NONE, 0);
252   container_signals[SET_FOCUS_CHILD] =
253     g_signal_new (I_("set-focus-child"),
254                   G_OBJECT_CLASS_TYPE (object_class),
255                   G_SIGNAL_RUN_FIRST,
256                   G_STRUCT_OFFSET (GtkContainerClass, set_focus_child),
257                   NULL, NULL,
258                   _gtk_marshal_VOID__OBJECT,
259                   G_TYPE_NONE, 1,
260                   GTK_TYPE_WIDGET);
261 }
262
263 /**
264  * gtk_container_child_type: 
265  * @container: a #GtkContainer.
266  *
267  * Returns the type of the children supported by the container.
268  *
269  * Note that this may return %G_TYPE_NONE to indicate that no more
270  * children can be added, e.g. for a #GtkPaned which already has two 
271  * children.
272  *
273  * Return value: a #GType.
274  **/
275 GType
276 gtk_container_child_type (GtkContainer *container)
277 {
278   GType slot;
279   GtkContainerClass *class;
280
281   g_return_val_if_fail (GTK_IS_CONTAINER (container), 0);
282
283   class = GTK_CONTAINER_GET_CLASS (container);
284   if (class->child_type)
285     slot = class->child_type (container);
286   else
287     slot = G_TYPE_NONE;
288
289   return slot;
290 }
291
292 /* --- GtkContainer child property mechanism --- */
293 static inline void
294 container_get_child_property (GtkContainer *container,
295                               GtkWidget    *child,
296                               GParamSpec   *pspec,
297                               GValue       *value)
298 {
299   GtkContainerClass *class = g_type_class_peek (pspec->owner_type);
300   
301   class->get_child_property (container, child, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
302 }
303
304 static inline void
305 container_set_child_property (GtkContainer       *container,
306                               GtkWidget          *child,
307                               GParamSpec         *pspec,
308                               const GValue       *value,
309                               GObjectNotifyQueue *nqueue)
310 {
311   GValue tmp_value = { 0, };
312   GtkContainerClass *class = g_type_class_peek (pspec->owner_type);
313
314   /* provide a copy to work from, convert (if necessary) and validate */
315   g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
316   if (!g_value_transform (value, &tmp_value))
317     g_warning ("unable to set child property `%s' of type `%s' from value of type `%s'",
318                pspec->name,
319                g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
320                G_VALUE_TYPE_NAME (value));
321   else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
322     {
323       gchar *contents = g_strdup_value_contents (value);
324
325       g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
326                  contents,
327                  G_VALUE_TYPE_NAME (value),
328                  pspec->name,
329                  g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
330       g_free (contents);
331     }
332   else
333     {
334       class->set_child_property (container, child, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
335       g_object_notify_queue_add (G_OBJECT (child), nqueue, pspec);
336     }
337   g_value_unset (&tmp_value);
338 }
339
340 /**
341  * gtk_container_child_get_valist:
342  * @container: a #GtkContainer
343  * @child: a widget which is a child of @container
344  * @first_property_name: the name of the first property to get
345  * @var_args: a %NULL-terminated list of property names and #GValue*, 
346  *           starting with @first_prop_name.
347  * 
348  * Gets the values of one or more child properties for @child and @container.
349  **/
350 void
351 gtk_container_child_get_valist (GtkContainer *container,
352                                 GtkWidget    *child,
353                                 const gchar  *first_property_name,
354                                 va_list       var_args)
355 {
356   const gchar *name;
357
358   g_return_if_fail (GTK_IS_CONTAINER (container));
359   g_return_if_fail (GTK_IS_WIDGET (child));
360   g_return_if_fail (child->parent == GTK_WIDGET (container));
361
362   g_object_ref (container);
363   g_object_ref (child);
364
365   name = first_property_name;
366   while (name)
367     {
368       GValue value = { 0, };
369       GParamSpec *pspec;
370       gchar *error;
371
372       pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool,
373                                         name,
374                                         G_OBJECT_TYPE (container),
375                                         TRUE);
376       if (!pspec)
377         {
378           g_warning ("%s: container class `%s' has no child property named `%s'",
379                      G_STRLOC,
380                      G_OBJECT_TYPE_NAME (container),
381                      name);
382           break;
383         }
384       if (!(pspec->flags & G_PARAM_READABLE))
385         {
386           g_warning ("%s: child property `%s' of container class `%s' is not readable",
387                      G_STRLOC,
388                      pspec->name,
389                      G_OBJECT_TYPE_NAME (container));
390           break;
391         }
392       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
393       container_get_child_property (container, child, pspec, &value);
394       G_VALUE_LCOPY (&value, var_args, 0, &error);
395       if (error)
396         {
397           g_warning ("%s: %s", G_STRLOC, error);
398           g_free (error);
399           g_value_unset (&value);
400           break;
401         }
402       g_value_unset (&value);
403       name = va_arg (var_args, gchar*);
404     }
405
406   g_object_unref (child);
407   g_object_unref (container);
408 }
409
410 /**
411  * gtk_container_child_get_property:
412  * @container: a #GtkContainer
413  * @child: a widget which is a child of @container
414  * @property_name: the name of the property to get
415  * @value: a location to return the value
416  * 
417  * Gets the value of a child property for @child and @container.
418  **/
419 void
420 gtk_container_child_get_property (GtkContainer *container,
421                                   GtkWidget    *child,
422                                   const gchar  *property_name,
423                                   GValue       *value)
424 {
425   GParamSpec *pspec;
426
427   g_return_if_fail (GTK_IS_CONTAINER (container));
428   g_return_if_fail (GTK_IS_WIDGET (child));
429   g_return_if_fail (child->parent == GTK_WIDGET (container));
430   g_return_if_fail (property_name != NULL);
431   g_return_if_fail (G_IS_VALUE (value));
432   
433   g_object_ref (container);
434   g_object_ref (child);
435   pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool, property_name,
436                                     G_OBJECT_TYPE (container), TRUE);
437   if (!pspec)
438     g_warning ("%s: container class `%s' has no child property named `%s'",
439                G_STRLOC,
440                G_OBJECT_TYPE_NAME (container),
441                property_name);
442   else if (!(pspec->flags & G_PARAM_READABLE))
443     g_warning ("%s: child property `%s' of container class `%s' is not readable",
444                G_STRLOC,
445                pspec->name,
446                G_OBJECT_TYPE_NAME (container));
447   else
448     {
449       GValue *prop_value, tmp_value = { 0, };
450
451       /* auto-conversion of the callers value type
452        */
453       if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
454         {
455           g_value_reset (value);
456           prop_value = value;
457         }
458       else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
459         {
460           g_warning ("can't retrieve child property `%s' of type `%s' as value of type `%s'",
461                      pspec->name,
462                      g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
463                      G_VALUE_TYPE_NAME (value));
464           g_object_unref (child);
465           g_object_unref (container);
466           return;
467         }
468       else
469         {
470           g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
471           prop_value = &tmp_value;
472         }
473       container_get_child_property (container, child, pspec, prop_value);
474       if (prop_value != value)
475         {
476           g_value_transform (prop_value, value);
477           g_value_unset (&tmp_value);
478         }
479     }
480   g_object_unref (child);
481   g_object_unref (container);
482 }
483
484 /**
485  * gtk_container_child_set_valist:
486  * @container: a #GtkContainer
487  * @child: a widget which is a child of @container
488  * @first_property_name: the name of the first property to set
489  * @var_args: a %NULL-terminated list of property names and values, starting
490  *           with @first_prop_name.
491  * 
492  * Sets one or more child properties for @child and @container.
493  **/
494 void
495 gtk_container_child_set_valist (GtkContainer *container,
496                                 GtkWidget    *child,
497                                 const gchar  *first_property_name,
498                                 va_list       var_args)
499 {
500   GObjectNotifyQueue *nqueue;
501   const gchar *name;
502
503   g_return_if_fail (GTK_IS_CONTAINER (container));
504   g_return_if_fail (GTK_IS_WIDGET (child));
505   g_return_if_fail (child->parent == GTK_WIDGET (container));
506
507   g_object_ref (container);
508   g_object_ref (child);
509
510   nqueue = g_object_notify_queue_freeze (G_OBJECT (child), _gtk_widget_child_property_notify_context);
511   name = first_property_name;
512   while (name)
513     {
514       GValue value = { 0, };
515       gchar *error = NULL;
516       GParamSpec *pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool,
517                                                     name,
518                                                     G_OBJECT_TYPE (container),
519                                                     TRUE);
520       if (!pspec)
521         {
522           g_warning ("%s: container class `%s' has no child property named `%s'",
523                      G_STRLOC,
524                      G_OBJECT_TYPE_NAME (container),
525                      name);
526           break;
527         }
528       if (!(pspec->flags & G_PARAM_WRITABLE))
529         {
530           g_warning ("%s: child property `%s' of container class `%s' is not writable",
531                      G_STRLOC,
532                      pspec->name,
533                      G_OBJECT_TYPE_NAME (container));
534           break;
535         }
536       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
537       G_VALUE_COLLECT (&value, var_args, 0, &error);
538       if (error)
539         {
540           g_warning ("%s: %s", G_STRLOC, error);
541           g_free (error);
542
543           /* we purposely leak the value here, it might not be
544            * in a sane state if an error condition occoured
545            */
546           break;
547         }
548       container_set_child_property (container, child, pspec, &value, nqueue);
549       g_value_unset (&value);
550       name = va_arg (var_args, gchar*);
551     }
552   g_object_notify_queue_thaw (G_OBJECT (child), nqueue);
553
554   g_object_unref (container);
555   g_object_unref (child);
556 }
557
558 /**
559  * gtk_container_child_set_property:
560  * @container: a #GtkContainer
561  * @child: a widget which is a child of @container
562  * @property_name: the name of the property to set
563  * @value: the value to set the property to
564  * 
565  * Sets a child property for @child and @container.
566  **/
567 void
568 gtk_container_child_set_property (GtkContainer *container,
569                                   GtkWidget    *child,
570                                   const gchar  *property_name,
571                                   const GValue *value)
572 {
573   GObjectNotifyQueue *nqueue;
574   GParamSpec *pspec;
575
576   g_return_if_fail (GTK_IS_CONTAINER (container));
577   g_return_if_fail (GTK_IS_WIDGET (child));
578   g_return_if_fail (child->parent == GTK_WIDGET (container));
579   g_return_if_fail (property_name != NULL);
580   g_return_if_fail (G_IS_VALUE (value));
581   
582   g_object_ref (container);
583   g_object_ref (child);
584
585   nqueue = g_object_notify_queue_freeze (G_OBJECT (child), _gtk_widget_child_property_notify_context);
586   pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool, property_name,
587                                     G_OBJECT_TYPE (container), TRUE);
588   if (!pspec)
589     g_warning ("%s: container class `%s' has no child property named `%s'",
590                G_STRLOC,
591                G_OBJECT_TYPE_NAME (container),
592                property_name);
593   else if (!(pspec->flags & G_PARAM_WRITABLE))
594     g_warning ("%s: child property `%s' of container class `%s' is not writable",
595                G_STRLOC,
596                pspec->name,
597                G_OBJECT_TYPE_NAME (container));
598   else
599     {
600       container_set_child_property (container, child, pspec, value, nqueue);
601     }
602   g_object_notify_queue_thaw (G_OBJECT (child), nqueue);
603   g_object_unref (container);
604   g_object_unref (child);
605 }
606
607 /**
608  * gtk_container_add_with_properties:
609  * @container: a #GtkContainer 
610  * @widget: a widget to be placed inside @container 
611  * @first_prop_name: the name of the first child property to set 
612  * @Varargs: a %NULL-terminated list of property names and values, starting
613  *           with @first_prop_name.
614  * 
615  * Adds @widget to @container, setting child properties at the same time.
616  * See gtk_container_add() and gtk_container_child_set() for more details.
617  **/
618 void
619 gtk_container_add_with_properties (GtkContainer *container,
620                                    GtkWidget    *widget,
621                                    const gchar  *first_prop_name,
622                                    ...)
623 {
624   g_return_if_fail (GTK_IS_CONTAINER (container));
625   g_return_if_fail (GTK_IS_WIDGET (widget));
626   g_return_if_fail (widget->parent == NULL);
627
628   g_object_ref (container);
629   g_object_ref (widget);
630   gtk_widget_freeze_child_notify (widget);
631
632   g_signal_emit (container, container_signals[ADD], 0, widget);
633   if (widget->parent)
634     {
635       va_list var_args;
636
637       va_start (var_args, first_prop_name);
638       gtk_container_child_set_valist (container, widget, first_prop_name, var_args);
639       va_end (var_args);
640     }
641
642   gtk_widget_thaw_child_notify (widget);
643   g_object_unref (widget);
644   g_object_unref (container);
645 }
646
647 /**
648  * gtk_container_child_set:
649  * @container: a #GtkContainer
650  * @child: a widget which is a child of @container
651  * @first_prop_name: the name of the first property to set
652  * @Varargs: a %NULL-terminated list of property names and values, starting
653  *           with @first_prop_name.
654  * 
655  * Sets one or more child properties for @child and @container.
656  **/
657 void
658 gtk_container_child_set (GtkContainer      *container,
659                          GtkWidget         *child,
660                          const gchar       *first_prop_name,
661                          ...)
662 {
663   va_list var_args;
664   
665   g_return_if_fail (GTK_IS_CONTAINER (container));
666   g_return_if_fail (GTK_IS_WIDGET (child));
667   g_return_if_fail (child->parent == GTK_WIDGET (container));
668
669   va_start (var_args, first_prop_name);
670   gtk_container_child_set_valist (container, child, first_prop_name, var_args);
671   va_end (var_args);
672 }
673
674 /**
675  * gtk_container_child_get:
676  * @container: a #GtkContainer
677  * @child: a widget which is a child of @container
678  * @first_prop_name: the name of the first property to get
679  * @Varargs: a %NULL-terminated list of property names and #GValue*, 
680  *           starting with @first_prop_name.
681  * 
682  * Gets the values of one or more child properties for @child and @container.
683  **/
684 void
685 gtk_container_child_get (GtkContainer      *container,
686                          GtkWidget         *child,
687                          const gchar       *first_prop_name,
688                          ...)
689 {
690   va_list var_args;
691   
692   g_return_if_fail (GTK_IS_CONTAINER (container));
693   g_return_if_fail (GTK_IS_WIDGET (child));
694   g_return_if_fail (child->parent == GTK_WIDGET (container));
695
696   va_start (var_args, first_prop_name);
697   gtk_container_child_get_valist (container, child, first_prop_name, var_args);
698   va_end (var_args);
699 }
700
701 /**
702  * gtk_container_class_install_child_property:
703  * @cclass: a #GtkContainerClass
704  * @property_id: the id for the property
705  * @pspec: the #GParamSpec for the property
706  * 
707  * Installs a child property on a container class. 
708  **/
709 void
710 gtk_container_class_install_child_property (GtkContainerClass *cclass,
711                                             guint              property_id,
712                                             GParamSpec        *pspec)
713 {
714   g_return_if_fail (GTK_IS_CONTAINER_CLASS (cclass));
715   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
716   if (pspec->flags & G_PARAM_WRITABLE)
717     g_return_if_fail (cclass->set_child_property != NULL);
718   if (pspec->flags & G_PARAM_READABLE)
719     g_return_if_fail (cclass->get_child_property != NULL);
720   g_return_if_fail (property_id > 0);
721   g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0);  /* paranoid */
722   if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))
723     g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
724
725   if (g_param_spec_pool_lookup (_gtk_widget_child_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (cclass), FALSE))
726     {
727       g_warning (G_STRLOC ": class `%s' already contains a child property named `%s'",
728                  G_OBJECT_CLASS_NAME (cclass),
729                  pspec->name);
730       return;
731     }
732   g_param_spec_ref (pspec);
733   g_param_spec_sink (pspec);
734   PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
735   g_param_spec_pool_insert (_gtk_widget_child_property_pool, pspec, G_OBJECT_CLASS_TYPE (cclass));
736 }
737
738 /**
739  * gtk_container_class_find_child_property:
740  * @cclass: a #GtkContainerClass
741  * @property_name: the name of the child property to find
742  * @returns: the #GParamSpec of the child property or %NULL if @class has no
743  *   child property with that name.
744  *
745  * Finds a child property of a container class by name.
746  */
747 GParamSpec*
748 gtk_container_class_find_child_property (GObjectClass *cclass,
749                                          const gchar  *property_name)
750 {
751   g_return_val_if_fail (GTK_IS_CONTAINER_CLASS (cclass), NULL);
752   g_return_val_if_fail (property_name != NULL, NULL);
753
754   return g_param_spec_pool_lookup (_gtk_widget_child_property_pool,
755                                    property_name,
756                                    G_OBJECT_CLASS_TYPE (cclass),
757                                    TRUE);
758 }
759
760 /**
761  * gtk_container_class_list_child_properties:
762  * @cclass: a #GtkContainerClass
763  * @n_properties: location to return the number of child properties found
764  * @returns: a newly allocated array of #GParamSpec*. The array must be 
765  *           freed with g_free().
766  *
767  * Returns all child properties of a container class.
768  */
769 GParamSpec**
770 gtk_container_class_list_child_properties (GObjectClass *cclass,
771                                            guint        *n_properties)
772 {
773   GParamSpec **pspecs;
774   guint n;
775
776   g_return_val_if_fail (GTK_IS_CONTAINER_CLASS (cclass), NULL);
777
778   pspecs = g_param_spec_pool_list (_gtk_widget_child_property_pool,
779                                    G_OBJECT_CLASS_TYPE (cclass),
780                                    &n);
781   if (n_properties)
782     *n_properties = n;
783
784   return pspecs;
785 }
786
787 static void
788 gtk_container_add_unimplemented (GtkContainer     *container,
789                                  GtkWidget        *widget)
790 {
791   g_warning ("GtkContainerClass::add not implemented for `%s'", g_type_name (G_TYPE_FROM_INSTANCE (container)));
792 }
793
794 static void
795 gtk_container_remove_unimplemented (GtkContainer     *container,
796                                     GtkWidget        *widget)
797 {
798   g_warning ("GtkContainerClass::remove not implemented for `%s'", g_type_name (G_TYPE_FROM_INSTANCE (container)));
799 }
800
801 static void
802 gtk_container_init (GtkContainer *container)
803 {
804   container->focus_child = NULL;
805   container->border_width = 0;
806   container->need_resize = FALSE;
807   container->resize_mode = GTK_RESIZE_PARENT;
808   container->reallocate_redraws = FALSE;
809 }
810
811 static void
812 gtk_container_destroy (GtkObject *object)
813 {
814   GtkContainer *container = GTK_CONTAINER (object);
815   
816   if (GTK_CONTAINER_RESIZE_PENDING (container))
817     _gtk_container_dequeue_resize_handler (container);
818
819   /* do this before walking child widgets, to avoid
820    * removing children from focus chain one by one.
821    */
822   if (container->has_focus_chain)
823     gtk_container_unset_focus_chain (container);
824   
825   gtk_container_foreach (container, (GtkCallback) gtk_widget_destroy, NULL);
826   
827   if (GTK_OBJECT_CLASS (parent_class)->destroy)
828     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
829 }
830
831 static void
832 gtk_container_set_property (GObject         *object,
833                             guint            prop_id,
834                             const GValue    *value,
835                             GParamSpec      *pspec)
836 {
837   GtkContainer *container = GTK_CONTAINER (object);
838
839   switch (prop_id)
840     {
841     case PROP_BORDER_WIDTH:
842       gtk_container_set_border_width (container, g_value_get_uint (value));
843       break;
844     case PROP_RESIZE_MODE:
845       gtk_container_set_resize_mode (container, g_value_get_enum (value));
846       break;
847     case PROP_CHILD:
848       gtk_container_add (container, GTK_WIDGET (g_value_get_object (value)));
849       break;
850     default:
851       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
852       break;
853     }
854 }
855
856 static void
857 gtk_container_get_property (GObject         *object,
858                             guint            prop_id,
859                             GValue          *value,
860                             GParamSpec      *pspec)
861 {
862   GtkContainer *container = GTK_CONTAINER (object);
863   
864   switch (prop_id)
865     {
866     case PROP_BORDER_WIDTH:
867       g_value_set_uint (value, container->border_width);
868       break;
869     case PROP_RESIZE_MODE:
870       g_value_set_enum (value, container->resize_mode);
871       break;
872     default:
873       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
874       break;
875     }
876 }
877
878 /**
879  * gtk_container_set_border_width:
880  * @container: a #GtkContainer
881  * @border_width: amount of blank space to leave <emphasis>outside</emphasis> the container.
882  *   Valid values are in the range 0-65535 pixels.
883  *
884  * Sets the border width of the container.
885  *
886  * The border width of a container is the amount of space to leave
887  * around the outside of the container. The only exception to this is
888  * #GtkWindow; because toplevel windows can't leave space outside,
889  * they leave the space inside. The border is added on all sides of
890  * the container. To add space to only one side, one approach is to
891  * create a #GtkAlignment widget, call gtk_widget_set_usize() to give
892  * it a size, and place it on the side of the container as a spacer.
893  **/
894 void
895 gtk_container_set_border_width (GtkContainer *container,
896                                 guint         border_width)
897 {
898   g_return_if_fail (GTK_IS_CONTAINER (container));
899
900   if (container->border_width != border_width)
901     {
902       container->border_width = border_width;
903       g_object_notify (G_OBJECT (container), "border-width");
904       
905       if (GTK_WIDGET_REALIZED (container))
906         gtk_widget_queue_resize (GTK_WIDGET (container));
907     }
908 }
909
910 /**
911  * gtk_container_get_border_width:
912  * @container: a #GtkContainer
913  * 
914  * Retrieves the border width of the container. See
915  * gtk_container_set_border_width().
916  *
917  * Return value: the current border width
918  **/
919 guint
920 gtk_container_get_border_width (GtkContainer *container)
921 {
922   g_return_val_if_fail (GTK_IS_CONTAINER (container), 0);
923
924   return container->border_width;
925 }
926
927 /**
928  * gtk_container_add:
929  * @container: a #GtkContainer
930  * @widget: a widget to be placed inside @container
931  * 
932  * Adds @widget to @container. Typically used for simple containers
933  * such as #GtkWindow, #GtkFrame, or #GtkButton; for more complicated
934  * layout containers such as #GtkBox or #GtkTable, this function will
935  * pick default packing parameters that may not be correct.  So
936  * consider functions such as gtk_box_pack_start() and
937  * gtk_table_attach() as an alternative to gtk_container_add() in
938  * those cases. A widget may be added to only one container at a time;
939  * you can't place the same widget inside two different containers.
940  **/
941 void
942 gtk_container_add (GtkContainer *container,
943                    GtkWidget    *widget)
944 {
945   g_return_if_fail (GTK_IS_CONTAINER (container));
946   g_return_if_fail (GTK_IS_WIDGET (widget));
947
948   if (widget->parent != NULL)
949     {
950       g_warning ("Attempting to add a widget with type %s to a container of "
951                  "type %s, but the widget is already inside a container of type %s, "
952                  "the GTK+ FAQ at http://www.gtk.org/faq/ explains how to reparent a widget.",
953                  g_type_name (G_OBJECT_TYPE (widget)),
954                  g_type_name (G_OBJECT_TYPE (container)),
955                  g_type_name (G_OBJECT_TYPE (widget->parent)));
956       return;
957     }
958
959   g_signal_emit (container, container_signals[ADD], 0, widget);
960 }
961
962 /**
963  * gtk_container_remove:
964  * @container: a #GtkContainer
965  * @widget: a current child of @container
966  * 
967  * Removes @widget from @container. @widget must be inside @container.
968  * Note that @container will own a reference to @widget, and that this
969  * may be the last reference held; so removing a widget from its
970  * container can destroy that widget. If you want to use @widget
971  * again, you need to add a reference to it while it's not inside
972  * a container, using g_object_ref(). If you don't want to use @widget
973  * again it's usually more efficient to simply destroy it directly
974  * using gtk_widget_destroy() since this will remove it from the
975  * container and help break any circular reference count cycles.
976  **/
977 void
978 gtk_container_remove (GtkContainer *container,
979                       GtkWidget    *widget)
980 {
981   g_return_if_fail (GTK_IS_CONTAINER (container));
982   g_return_if_fail (GTK_IS_WIDGET (widget));
983
984   /* When using the deprecated API of the toolbar, it is possible
985    * to legitimately call this function with a widget that is not
986    * a direct child of the container.
987    */
988   g_return_if_fail (GTK_IS_TOOLBAR (container) ||
989                     widget->parent == GTK_WIDGET (container));
990   
991   g_signal_emit (container, container_signals[REMOVE], 0, widget);
992 }
993
994 void
995 _gtk_container_dequeue_resize_handler (GtkContainer *container)
996 {
997   g_return_if_fail (GTK_IS_CONTAINER (container));
998   g_return_if_fail (GTK_CONTAINER_RESIZE_PENDING (container));
999
1000   container_resize_queue = g_slist_remove (container_resize_queue, container);
1001   GTK_PRIVATE_UNSET_FLAG (container, GTK_RESIZE_PENDING);
1002 }
1003
1004 /**
1005  * gtk_container_set_resize_mode:
1006  * @container: a #GtkContainer.
1007  * @resize_mode: the new resize mode.
1008  * 
1009  * Sets the resize mode for the container.
1010  *
1011  * The resize mode of a container determines whether a resize request 
1012  * will be passed to the container's parent, queued for later execution
1013  * or executed immediately.
1014  **/
1015 void
1016 gtk_container_set_resize_mode (GtkContainer  *container,
1017                                GtkResizeMode  resize_mode)
1018 {
1019   g_return_if_fail (GTK_IS_CONTAINER (container));
1020   g_return_if_fail (resize_mode <= GTK_RESIZE_IMMEDIATE);
1021   
1022   if (GTK_WIDGET_TOPLEVEL (container) &&
1023       resize_mode == GTK_RESIZE_PARENT)
1024     {
1025       resize_mode = GTK_RESIZE_QUEUE;
1026     }
1027   
1028   if (container->resize_mode != resize_mode)
1029     {
1030       container->resize_mode = resize_mode;
1031       
1032       gtk_widget_queue_resize (GTK_WIDGET (container));
1033       g_object_notify (G_OBJECT (container), "resize-mode");
1034     }
1035 }
1036
1037 /**
1038  * gtk_container_get_resize_mode:
1039  * @container: a #GtkContainer
1040  * 
1041  * Returns the resize mode for the container. See
1042  * gtk_container_set_resize_mode ().
1043  *
1044  * Return value: the current resize mode
1045  **/
1046 GtkResizeMode
1047 gtk_container_get_resize_mode (GtkContainer *container)
1048 {
1049   g_return_val_if_fail (GTK_IS_CONTAINER (container), GTK_RESIZE_PARENT);
1050
1051   return container->resize_mode;
1052 }
1053
1054 /**
1055  * gtk_container_set_reallocate_redraws:
1056  * @container: a #GtkContainer.
1057  * @needs_redraws: the new value for the container's @reallocate_redraws flag.
1058  *
1059  * Sets the @reallocate_redraws flag of the container to the given value.
1060  * 
1061  * Containers requesting reallocation redraws get automatically
1062  * redrawn if any of their children changed allocation. 
1063  **/ 
1064 void
1065 gtk_container_set_reallocate_redraws (GtkContainer *container,
1066                                       gboolean      needs_redraws)
1067 {
1068   g_return_if_fail (GTK_IS_CONTAINER (container));
1069
1070   container->reallocate_redraws = needs_redraws ? TRUE : FALSE;
1071 }
1072
1073 static GtkContainer*
1074 gtk_container_get_resize_container (GtkContainer *container)
1075 {
1076   GtkWidget *widget = GTK_WIDGET (container);
1077
1078   while (widget->parent)
1079     {
1080       widget = widget->parent;
1081       if (GTK_IS_RESIZE_CONTAINER (widget))
1082         break;
1083     }
1084
1085   return GTK_IS_RESIZE_CONTAINER (widget) ? (GtkContainer*) widget : NULL;
1086 }
1087
1088 static gboolean
1089 gtk_container_idle_sizer (gpointer data)
1090 {
1091   GDK_THREADS_ENTER ();
1092
1093   /* we may be invoked with a container_resize_queue of NULL, because
1094    * queue_resize could have been adding an extra idle function while
1095    * the queue still got processed. we better just ignore such case
1096    * than trying to explicitely work around them with some extra flags,
1097    * since it doesn't cause any actual harm.
1098    */
1099   while (container_resize_queue)
1100     {
1101       GSList *slist;
1102       GtkWidget *widget;
1103
1104       slist = container_resize_queue;
1105       container_resize_queue = slist->next;
1106       widget = slist->data;
1107       g_slist_free_1 (slist);
1108
1109       GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_PENDING);
1110       gtk_container_check_resize (GTK_CONTAINER (widget));
1111     }
1112
1113   gdk_window_process_all_updates ();
1114
1115   GDK_THREADS_LEAVE ();
1116
1117   return FALSE;
1118 }
1119
1120 void
1121 _gtk_container_queue_resize (GtkContainer *container)
1122 {
1123   GtkContainer *resize_container;
1124   GtkWidget *widget;
1125   
1126   g_return_if_fail (GTK_IS_CONTAINER (container));
1127
1128   widget = GTK_WIDGET (container);
1129   resize_container = gtk_container_get_resize_container (container);
1130   
1131   while (TRUE)
1132     {
1133       GTK_PRIVATE_SET_FLAG (widget, GTK_ALLOC_NEEDED);
1134       GTK_PRIVATE_SET_FLAG (widget, GTK_REQUEST_NEEDED);
1135       if ((resize_container && widget == GTK_WIDGET (resize_container)) ||
1136           !widget->parent)
1137         break;
1138       
1139       widget = widget->parent;
1140     }
1141       
1142   if (resize_container)
1143     {
1144       if (GTK_WIDGET_VISIBLE (resize_container) &&
1145           (GTK_WIDGET_TOPLEVEL (resize_container) || GTK_WIDGET_REALIZED (resize_container)))
1146         {
1147           switch (resize_container->resize_mode)
1148             {
1149             case GTK_RESIZE_QUEUE:
1150               if (!GTK_CONTAINER_RESIZE_PENDING (resize_container))
1151                 {
1152                   GTK_PRIVATE_SET_FLAG (resize_container, GTK_RESIZE_PENDING);
1153                   if (container_resize_queue == NULL)
1154                     g_idle_add_full (GTK_PRIORITY_RESIZE,
1155                                      gtk_container_idle_sizer,
1156                                      NULL, NULL);
1157                   container_resize_queue = g_slist_prepend (container_resize_queue, resize_container);
1158                 }
1159               break;
1160
1161             case GTK_RESIZE_IMMEDIATE:
1162               gtk_container_check_resize (resize_container);
1163               break;
1164
1165             case GTK_RESIZE_PARENT:
1166               g_assert_not_reached ();
1167               break;
1168             }
1169         }
1170       else
1171         {
1172           /* we need to let hidden resize containers know that something
1173            * changed while they where hidden (currently only evaluated by
1174            * toplevels).
1175            */
1176           resize_container->need_resize = TRUE;
1177         }
1178     }
1179 }
1180
1181 void
1182 gtk_container_check_resize (GtkContainer *container)
1183 {
1184   g_return_if_fail (GTK_IS_CONTAINER (container));
1185   
1186   g_signal_emit (container, container_signals[CHECK_RESIZE], 0);
1187 }
1188
1189 static void
1190 gtk_container_real_check_resize (GtkContainer *container)
1191 {
1192   GtkWidget *widget = GTK_WIDGET (container);
1193   GtkRequisition requisition;
1194   
1195   gtk_widget_size_request (widget, &requisition);
1196   
1197   if (requisition.width > widget->allocation.width ||
1198       requisition.height > widget->allocation.height)
1199     {
1200       if (GTK_IS_RESIZE_CONTAINER (container))
1201         gtk_widget_size_allocate (GTK_WIDGET (container),
1202                                   &GTK_WIDGET (container)->allocation);
1203       else
1204         gtk_widget_queue_resize (widget);
1205     }
1206   else
1207     {
1208       gtk_container_resize_children (container);
1209     }
1210 }
1211
1212 /* The container hasn't changed size but one of its children
1213  *  queued a resize request. Which means that the allocation
1214  *  is not sufficient for the requisition of some child.
1215  *  We've already performed a size request at this point,
1216  *  so we simply need to reallocate and let the allocation
1217  *  trickle down via GTK_WIDGET_ALLOC_NEEDED flags. 
1218  */
1219 void
1220 gtk_container_resize_children (GtkContainer *container)
1221 {
1222   GtkWidget *widget;
1223   
1224   /* resizing invariants:
1225    * toplevels have *always* resize_mode != GTK_RESIZE_PARENT set.
1226    * containers that have an idle sizer pending must be flagged with
1227    * RESIZE_PENDING.
1228    */
1229   g_return_if_fail (GTK_IS_CONTAINER (container));
1230
1231   widget = GTK_WIDGET (container);
1232   gtk_widget_size_allocate (widget, &widget->allocation);
1233 }
1234
1235 /**
1236  * gtk_container_forall:
1237  * @container: a #GtkContainer
1238  * @callback: a callback
1239  * @callback_data: callback user data
1240  * 
1241  * Invokes @callback on each child of @container, including children
1242  * that are considered "internal" (implementation details of the
1243  * container). "Internal" children generally weren't added by the user
1244  * of the container, but were added by the container implementation
1245  * itself.  Most applications should use gtk_container_foreach(),
1246  * rather than gtk_container_forall().
1247  **/
1248 void
1249 gtk_container_forall (GtkContainer *container,
1250                       GtkCallback   callback,
1251                       gpointer      callback_data)
1252 {
1253   GtkContainerClass *class;
1254
1255   g_return_if_fail (GTK_IS_CONTAINER (container));
1256   g_return_if_fail (callback != NULL);
1257
1258   class = GTK_CONTAINER_GET_CLASS (container);
1259
1260   if (class->forall)
1261     class->forall (container, TRUE, callback, callback_data);
1262 }
1263
1264 /**
1265  * gtk_container_foreach:
1266  * @container: a #GtkContainer
1267  * @callback: a callback
1268  * @callback_data: callback user data
1269  * 
1270  * Invokes @callback on each non-internal child of @container.  See
1271  * gtk_container_forall() for details on what constitutes an
1272  * "internal" child.  Most applications should use
1273  * gtk_container_foreach(), rather than gtk_container_forall().
1274  **/
1275 void
1276 gtk_container_foreach (GtkContainer *container,
1277                        GtkCallback   callback,
1278                        gpointer      callback_data)
1279 {
1280   GtkContainerClass *class;
1281   
1282   g_return_if_fail (GTK_IS_CONTAINER (container));
1283   g_return_if_fail (callback != NULL);
1284
1285   class = GTK_CONTAINER_GET_CLASS (container);
1286
1287   if (class->forall)
1288     class->forall (container, FALSE, callback, callback_data);
1289 }
1290
1291 typedef struct _GtkForeachData  GtkForeachData;
1292 struct _GtkForeachData
1293 {
1294   GtkObject         *container;
1295   GtkCallbackMarshal callback;
1296   gpointer           callback_data;
1297 };
1298
1299 static void
1300 gtk_container_foreach_unmarshal (GtkWidget *child,
1301                                  gpointer data)
1302 {
1303   GtkForeachData *fdata = (GtkForeachData*) data;
1304   GtkArg args[2];
1305   
1306   /* first argument */
1307   args[0].name = NULL;
1308   args[0].type = G_TYPE_FROM_INSTANCE (child);
1309   GTK_VALUE_OBJECT (args[0]) = GTK_OBJECT (child);
1310   
1311   /* location for return value */
1312   args[1].name = NULL;
1313   args[1].type = G_TYPE_NONE;
1314   
1315   fdata->callback (fdata->container, fdata->callback_data, 1, args);
1316 }
1317
1318 void
1319 gtk_container_foreach_full (GtkContainer       *container,
1320                             GtkCallback         callback,
1321                             GtkCallbackMarshal  marshal,
1322                             gpointer            callback_data,
1323                             GtkDestroyNotify    notify)
1324 {
1325   g_return_if_fail (GTK_IS_CONTAINER (container));
1326
1327   if (marshal)
1328     {
1329       GtkForeachData fdata;
1330   
1331       fdata.container     = GTK_OBJECT (container);
1332       fdata.callback      = marshal;
1333       fdata.callback_data = callback_data;
1334
1335       gtk_container_foreach (container, gtk_container_foreach_unmarshal, &fdata);
1336     }
1337   else
1338     {
1339       g_return_if_fail (callback != NULL);
1340
1341       gtk_container_foreach (container, callback, &callback_data);
1342     }
1343
1344   if (notify)
1345     notify (callback_data);
1346 }
1347
1348 void
1349 gtk_container_set_focus_child (GtkContainer *container,
1350                                GtkWidget    *widget)
1351 {
1352   g_return_if_fail (GTK_IS_CONTAINER (container));
1353   if (widget)
1354     g_return_if_fail (GTK_IS_WIDGET (widget));
1355
1356   g_signal_emit (container, container_signals[SET_FOCUS_CHILD], 0, widget);
1357 }
1358
1359 /**
1360  * gtk_container_get_children:
1361  * @container: a #GtkContainer.
1362  * 
1363  * Returns the container's non-internal children. See
1364  * gtk_container_forall() for details on what constitutes an "internal" child. 
1365  *
1366  * Return value: a newly-allocated list of the container's non-internal children.
1367  **/
1368 GList*
1369 gtk_container_get_children (GtkContainer *container)
1370 {
1371   GList *children = NULL;
1372
1373   gtk_container_foreach (container,
1374                          gtk_container_children_callback,
1375                          &children);
1376
1377   return g_list_reverse (children);
1378 }
1379
1380 static void
1381 gtk_container_child_position_callback (GtkWidget *widget,
1382                                        gpointer   client_data)
1383 {
1384   struct {
1385     GtkWidget *child;
1386     guint i;
1387     guint index;
1388   } *data = client_data;
1389
1390   data->i++;
1391   if (data->child == widget)
1392     data->index = data->i;
1393 }
1394
1395 static gchar*
1396 gtk_container_child_default_composite_name (GtkContainer *container,
1397                                             GtkWidget    *child)
1398 {
1399   struct {
1400     GtkWidget *child;
1401     guint i;
1402     guint index;
1403   } data;
1404   gchar *name;
1405
1406   /* fallback implementation */
1407   data.child = child;
1408   data.i = 0;
1409   data.index = 0;
1410   gtk_container_forall (container,
1411                         gtk_container_child_position_callback,
1412                         &data);
1413   
1414   name = g_strdup_printf ("%s-%u",
1415                           g_type_name (G_TYPE_FROM_INSTANCE (child)),
1416                           data.index);
1417
1418   return name;
1419 }
1420
1421 gchar*
1422 _gtk_container_child_composite_name (GtkContainer *container,
1423                                     GtkWidget    *child)
1424 {
1425   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
1426   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
1427   g_return_val_if_fail (child->parent == GTK_WIDGET (container), NULL);
1428
1429   if (GTK_WIDGET_COMPOSITE_CHILD (child))
1430     {
1431       static GQuark quark_composite_name = 0;
1432       gchar *name;
1433
1434       if (!quark_composite_name)
1435         quark_composite_name = g_quark_from_static_string ("gtk-composite-name");
1436
1437       name = g_object_get_qdata (G_OBJECT (child), quark_composite_name);
1438       if (!name)
1439         {
1440           GtkContainerClass *class;
1441
1442           class = GTK_CONTAINER_GET_CLASS (container);
1443           if (class->composite_name)
1444             name = class->composite_name (container, child);
1445         }
1446       else
1447         name = g_strdup (name);
1448
1449       return name;
1450     }
1451   
1452   return NULL;
1453 }
1454
1455 static void
1456 gtk_container_real_set_focus_child (GtkContainer     *container,
1457                                     GtkWidget        *child)
1458 {
1459   g_return_if_fail (GTK_IS_CONTAINER (container));
1460   g_return_if_fail (child == NULL || GTK_IS_WIDGET (child));
1461
1462   if (child != container->focus_child)
1463     {
1464       if (container->focus_child)
1465         g_object_unref (container->focus_child);
1466       container->focus_child = child;
1467       if (container->focus_child)
1468         g_object_ref (container->focus_child);
1469     }
1470
1471
1472   /* check for h/v adjustments
1473    */
1474   if (container->focus_child)
1475     {
1476       GtkAdjustment *hadj;
1477       GtkAdjustment *vadj;
1478       GtkWidget *focus_child;
1479       gint x, y;
1480
1481       hadj = g_object_get_qdata (G_OBJECT (container), hadjustment_key_id);   
1482       vadj = g_object_get_qdata (G_OBJECT (container), vadjustment_key_id);
1483       if (hadj || vadj) 
1484         {
1485
1486           focus_child = container->focus_child;
1487           while (GTK_IS_CONTAINER (focus_child) && 
1488                  GTK_CONTAINER (focus_child)->focus_child)
1489             {
1490               focus_child = GTK_CONTAINER (focus_child)->focus_child;
1491             }
1492           
1493           gtk_widget_translate_coordinates (focus_child, container->focus_child, 
1494                                             0, 0, &x, &y);
1495
1496            x += container->focus_child->allocation.x;
1497            y += container->focus_child->allocation.y;
1498           
1499           if (vadj)
1500             gtk_adjustment_clamp_page (vadj, y, y + focus_child->allocation.height);
1501           
1502           if (hadj)
1503             gtk_adjustment_clamp_page (hadj, x, x + focus_child->allocation.width);
1504         }
1505     }
1506 }
1507
1508 static GList*
1509 get_focus_chain (GtkContainer *container)
1510 {
1511   return g_object_get_data (G_OBJECT (container), "gtk-container-focus-chain");
1512 }
1513
1514 /* same as gtk_container_get_children, except it includes internals
1515  */
1516 static GList *
1517 gtk_container_get_all_children (GtkContainer *container)
1518 {
1519   GList *children = NULL;
1520
1521   gtk_container_forall (container,
1522                          gtk_container_children_callback,
1523                          &children);
1524
1525   return children;
1526 }
1527
1528 static gboolean
1529 gtk_container_focus (GtkWidget        *widget,
1530                      GtkDirectionType  direction)
1531 {
1532   GList *children;
1533   GList *sorted_children;
1534   gint return_val;
1535   GtkContainer *container;
1536
1537   g_return_val_if_fail (GTK_IS_CONTAINER (widget), FALSE);
1538
1539   container = GTK_CONTAINER (widget);
1540
1541   return_val = FALSE;
1542
1543   if (GTK_WIDGET_CAN_FOCUS (container))
1544     {
1545       if (!GTK_WIDGET_HAS_FOCUS (container))
1546         {
1547           gtk_widget_grab_focus (GTK_WIDGET (container));
1548           return_val = TRUE;
1549         }
1550     }
1551   else
1552     {
1553       /* Get a list of the containers children, allowing focus
1554        * chain to override.
1555        */
1556       if (container->has_focus_chain)
1557         children = g_list_copy (get_focus_chain (container));
1558       else
1559         children = gtk_container_get_all_children (container);
1560
1561       if (container->has_focus_chain &&
1562           (direction == GTK_DIR_TAB_FORWARD ||
1563            direction == GTK_DIR_TAB_BACKWARD))
1564         {
1565           sorted_children = g_list_copy (children);
1566           
1567           if (direction == GTK_DIR_TAB_BACKWARD)
1568             sorted_children = g_list_reverse (sorted_children);
1569         }
1570       else
1571         sorted_children = _gtk_container_focus_sort (container, children, direction, NULL);
1572       
1573       return_val = gtk_container_focus_move (container, sorted_children, direction);
1574
1575       g_list_free (sorted_children);
1576       g_list_free (children);
1577     }
1578
1579   return return_val;
1580 }
1581
1582 static gint
1583 tab_compare (gconstpointer a,
1584              gconstpointer b,
1585              gpointer      data)
1586 {
1587   const GtkWidget *child1 = a;
1588   const GtkWidget *child2 = b;
1589   GtkTextDirection text_direction = GPOINTER_TO_INT (data);
1590
1591   gint y1 = child1->allocation.y + child1->allocation.height / 2;
1592   gint y2 = child2->allocation.y + child2->allocation.height / 2;
1593
1594   if (y1 == y2)
1595     {
1596       gint x1 = child1->allocation.x + child1->allocation.width / 2;
1597       gint x2 = child2->allocation.x + child2->allocation.width / 2;
1598       
1599       if (text_direction == GTK_TEXT_DIR_RTL) 
1600         return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1);
1601       else
1602         return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1);
1603     }
1604   else
1605     return (y1 < y2) ? -1 : 1;
1606 }
1607
1608 static GList *
1609 gtk_container_focus_sort_tab (GtkContainer     *container,
1610                               GList            *children,
1611                               GtkDirectionType  direction,
1612                               GtkWidget        *old_focus)
1613 {
1614   GtkTextDirection text_direction = gtk_widget_get_direction (GTK_WIDGET (container));
1615   children = g_list_sort_with_data (children, tab_compare, GINT_TO_POINTER (text_direction));
1616
1617   /* if we are going backwards then reverse the order
1618    *  of the children.
1619    */
1620   if (direction == GTK_DIR_TAB_BACKWARD)
1621     children = g_list_reverse (children);
1622
1623   return children;
1624 }
1625
1626 /* Get coordinates of @widget's allocation with respect to
1627  * allocation of @container.
1628  */
1629 static gboolean
1630 get_allocation_coords (GtkContainer  *container,
1631                        GtkWidget     *widget,
1632                        GdkRectangle  *allocation)
1633 {
1634   *allocation = widget->allocation;
1635
1636   return gtk_widget_translate_coordinates (widget, GTK_WIDGET (container),
1637                                            0, 0, &allocation->x, &allocation->y);
1638 }
1639
1640 /* Look for a child in @children that is intermediate between
1641  * the focus widget and container. This widget, if it exists,
1642  * acts as the starting widget for focus navigation.
1643  */
1644 static GtkWidget *
1645 find_old_focus (GtkContainer *container,
1646                 GList        *children)
1647 {
1648   GList *tmp_list = children;
1649   while (tmp_list)
1650     {
1651       GtkWidget *child = tmp_list->data;
1652       GtkWidget *widget = child;
1653
1654       while (widget && widget != (GtkWidget *)container)
1655         {
1656           GtkWidget *parent = widget->parent;
1657           if (parent && ((GtkContainer *)parent)->focus_child != widget)
1658             goto next;
1659
1660           widget = parent;
1661         }
1662
1663       return child;
1664
1665     next:
1666       tmp_list = tmp_list->next;
1667     }
1668
1669   return NULL;
1670 }
1671
1672 static gboolean
1673 old_focus_coords (GtkContainer *container,
1674                   GdkRectangle *old_focus_rect)
1675 {
1676   GtkWidget *widget = GTK_WIDGET (container);
1677   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1678   
1679   if (toplevel && GTK_IS_WINDOW (toplevel) && GTK_WINDOW (toplevel)->focus_widget)
1680     {
1681       GtkWidget *old_focus = GTK_WINDOW (toplevel)->focus_widget;
1682       
1683       return get_allocation_coords (container, old_focus, old_focus_rect);
1684     }
1685   else
1686     return FALSE;
1687 }
1688
1689 typedef struct _CompareInfo CompareInfo;
1690
1691 struct _CompareInfo
1692 {
1693   GtkContainer *container;
1694   gint x;
1695   gint y;
1696   gboolean reverse;
1697 };
1698
1699 static gint
1700 up_down_compare (gconstpointer a,
1701                  gconstpointer b,
1702                  gpointer      data)
1703 {
1704   GdkRectangle allocation1;
1705   GdkRectangle allocation2;
1706   CompareInfo *compare = data;
1707   gint y1, y2;
1708
1709   get_allocation_coords (compare->container, (GtkWidget *)a, &allocation1);
1710   get_allocation_coords (compare->container, (GtkWidget *)b, &allocation2);
1711
1712   y1 = allocation1.y + allocation1.height / 2;
1713   y2 = allocation2.y + allocation2.height / 2;
1714
1715   if (y1 == y2)
1716     {
1717       gint x1 = abs (allocation1.x + allocation1.width / 2 - compare->x);
1718       gint x2 = abs (allocation2.x + allocation2.width / 2 - compare->x);
1719
1720       if (compare->reverse)
1721         return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1);
1722       else
1723         return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1);
1724     }
1725   else
1726     return (y1 < y2) ? -1 : 1;
1727 }
1728
1729 static GList *
1730 gtk_container_focus_sort_up_down (GtkContainer     *container,
1731                                   GList            *children,
1732                                   GtkDirectionType  direction,
1733                                   GtkWidget        *old_focus)
1734 {
1735   CompareInfo compare;
1736   GList *tmp_list;
1737   GdkRectangle old_allocation;
1738
1739   compare.container = container;
1740   compare.reverse = (direction == GTK_DIR_UP);
1741
1742   if (!old_focus)
1743       old_focus = find_old_focus (container, children);
1744   
1745   if (old_focus && get_allocation_coords (container, old_focus, &old_allocation))
1746     {
1747       gint compare_x1;
1748       gint compare_x2;
1749       gint compare_y;
1750
1751       /* Delete widgets from list that don't match minimum criteria */
1752
1753       compare_x1 = old_allocation.x;
1754       compare_x2 = old_allocation.x + old_allocation.width;
1755
1756       if (direction == GTK_DIR_UP)
1757         compare_y = old_allocation.y;
1758       else
1759         compare_y = old_allocation.y + old_allocation.height;
1760       
1761       tmp_list = children;
1762       while (tmp_list)
1763         {
1764           GtkWidget *child = tmp_list->data;
1765           GList *next = tmp_list->next;
1766           gint child_x1, child_x2;
1767           GdkRectangle child_allocation;
1768           
1769           if (child != old_focus)
1770             {
1771               if (get_allocation_coords (container, child, &child_allocation))
1772                 {
1773                   child_x1 = child_allocation.x;
1774                   child_x2 = child_allocation.x + child_allocation.width;
1775                   
1776                   if ((child_x2 <= compare_x1 || child_x1 >= compare_x2) /* No horizontal overlap */ ||
1777                       (direction == GTK_DIR_DOWN && child_allocation.y + child_allocation.height < compare_y) || /* Not below */
1778                       (direction == GTK_DIR_UP && child_allocation.y > compare_y)) /* Not above */
1779                     {
1780                       children = g_list_delete_link (children, tmp_list);
1781                     }
1782                 }
1783               else
1784                 children = g_list_delete_link (children, tmp_list);
1785             }
1786           
1787           tmp_list = next;
1788         }
1789
1790       compare.x = (compare_x1 + compare_x2) / 2;
1791       compare.y = old_allocation.y + old_allocation.height / 2;
1792     }
1793   else
1794     {
1795       /* No old focus widget, need to figure out starting x,y some other way
1796        */
1797       GtkWidget *widget = GTK_WIDGET (container);
1798       GdkRectangle old_focus_rect;
1799
1800       if (old_focus_coords (container, &old_focus_rect))
1801         {
1802           compare.x = old_focus_rect.x + old_focus_rect.width / 2;
1803         }
1804       else
1805         {
1806           if (GTK_WIDGET_NO_WINDOW (widget))
1807             compare.x = widget->allocation.x + widget->allocation.width / 2;
1808           else
1809             compare.x = widget->allocation.width / 2;
1810         }
1811       
1812       if (GTK_WIDGET_NO_WINDOW (widget))
1813         compare.y = (direction == GTK_DIR_DOWN) ? widget->allocation.y : widget->allocation.y + widget->allocation.height;
1814       else
1815         compare.y = (direction == GTK_DIR_DOWN) ? 0 : + widget->allocation.height;
1816     }
1817
1818   children = g_list_sort_with_data (children, up_down_compare, &compare);
1819
1820   if (compare.reverse)
1821     children = g_list_reverse (children);
1822
1823   return children;
1824 }
1825
1826 static gint
1827 left_right_compare (gconstpointer a,
1828                     gconstpointer b,
1829                     gpointer      data)
1830 {
1831   GdkRectangle allocation1;
1832   GdkRectangle allocation2;
1833   CompareInfo *compare = data;
1834   gint x1, x2;
1835
1836   get_allocation_coords (compare->container, (GtkWidget *)a, &allocation1);
1837   get_allocation_coords (compare->container, (GtkWidget *)b, &allocation2);
1838
1839   x1 = allocation1.x + allocation1.width / 2;
1840   x2 = allocation2.x + allocation2.width / 2;
1841
1842   if (x1 == x2)
1843     {
1844       gint y1 = abs (allocation1.y + allocation1.height / 2 - compare->y);
1845       gint y2 = abs (allocation2.y + allocation2.height / 2 - compare->y);
1846
1847       if (compare->reverse)
1848         return (y1 < y2) ? 1 : ((y1 == y2) ? 0 : -1);
1849       else
1850         return (y1 < y2) ? -1 : ((y1 == y2) ? 0 : 1);
1851     }
1852   else
1853     return (x1 < x2) ? -1 : 1;
1854 }
1855
1856 static GList *
1857 gtk_container_focus_sort_left_right (GtkContainer     *container,
1858                                      GList            *children,
1859                                      GtkDirectionType  direction,
1860                                      GtkWidget        *old_focus)
1861 {
1862   CompareInfo compare;
1863   GList *tmp_list;
1864   GdkRectangle old_allocation;
1865
1866   compare.container = container;
1867   compare.reverse = (direction == GTK_DIR_LEFT);
1868
1869   if (!old_focus)
1870     old_focus = find_old_focus (container, children);
1871   
1872   if (old_focus && get_allocation_coords (container, old_focus, &old_allocation))
1873     {
1874       gint compare_y1;
1875       gint compare_y2;
1876       gint compare_x;
1877       
1878       /* Delete widgets from list that don't match minimum criteria */
1879
1880       compare_y1 = old_allocation.y;
1881       compare_y2 = old_allocation.y + old_allocation.height;
1882
1883       if (direction == GTK_DIR_LEFT)
1884         compare_x = old_allocation.x;
1885       else
1886         compare_x = old_allocation.x + old_allocation.width;
1887       
1888       tmp_list = children;
1889       while (tmp_list)
1890         {
1891           GtkWidget *child = tmp_list->data;
1892           GList *next = tmp_list->next;
1893           gint child_y1, child_y2;
1894           GdkRectangle child_allocation;
1895           
1896           if (child != old_focus)
1897             {
1898               if (get_allocation_coords (container, child, &child_allocation))
1899                 {
1900                   child_y1 = child_allocation.y;
1901                   child_y2 = child_allocation.y + child_allocation.height;
1902                   
1903                   if ((child_y2 <= compare_y1 || child_y1 >= compare_y2) /* No vertical overlap */ ||
1904                       (direction == GTK_DIR_RIGHT && child_allocation.x + child_allocation.width < compare_x) || /* Not to left */
1905                       (direction == GTK_DIR_LEFT && child_allocation.x > compare_x)) /* Not to right */
1906                     {
1907                       children = g_list_delete_link (children, tmp_list);
1908                     }
1909                 }
1910               else
1911                 children = g_list_delete_link (children, tmp_list);
1912             }
1913           
1914           tmp_list = next;
1915         }
1916
1917       compare.y = (compare_y1 + compare_y2) / 2;
1918       compare.x = old_allocation.x + old_allocation.width / 2;
1919     }
1920   else
1921     {
1922       /* No old focus widget, need to figure out starting x,y some other way
1923        */
1924       GtkWidget *widget = GTK_WIDGET (container);
1925       GdkRectangle old_focus_rect;
1926
1927       if (old_focus_coords (container, &old_focus_rect))
1928         {
1929           compare.y = old_focus_rect.y + old_focus_rect.height / 2;
1930         }
1931       else
1932         {
1933           if (GTK_WIDGET_NO_WINDOW (widget))
1934             compare.y = widget->allocation.y + widget->allocation.height / 2;
1935           else
1936             compare.y = widget->allocation.height / 2;
1937         }
1938       
1939       if (GTK_WIDGET_NO_WINDOW (widget))
1940         compare.x = (direction == GTK_DIR_RIGHT) ? widget->allocation.x : widget->allocation.x + widget->allocation.width;
1941       else
1942         compare.x = (direction == GTK_DIR_RIGHT) ? 0 : widget->allocation.width;
1943     }
1944
1945   children = g_list_sort_with_data (children, left_right_compare, &compare);
1946
1947   if (compare.reverse)
1948     children = g_list_reverse (children);
1949
1950   return children;
1951 }
1952
1953 /**
1954  * gtk_container_focus_sort:
1955  * @container: a #GtkContainer
1956  * @children:  a list of descendents of @container (they don't
1957  *             have to be direct children.
1958  * @direction: focus direction
1959  * @old_focus: widget to use for the starting position, or %NULL
1960  *             to determine this automatically.
1961  *             [ Note, this argument isn't used for GTK_DIR_TAB_*,
1962  *               which is the only @direction we use currently,
1963  *               so perhaps this argument should be removed ]
1964  * 
1965  * Sorts @children in the correct order for focusing with
1966  * direction type @direction.
1967  * 
1968  * Return value: a copy of @children, sorted in correct focusing order,
1969  *   with children that aren't suitable for focusing in this direction
1970  *   removed.
1971  **/
1972 GList *
1973 _gtk_container_focus_sort (GtkContainer     *container,
1974                            GList            *children,
1975                            GtkDirectionType  direction,
1976                            GtkWidget        *old_focus)
1977 {
1978   GList *visible_children = NULL;
1979
1980   while (children)
1981     {
1982       if (GTK_WIDGET_REALIZED (children->data))
1983         visible_children = g_list_prepend (visible_children, children->data);
1984       children = children->next;
1985     }
1986   
1987   switch (direction)
1988     {
1989     case GTK_DIR_TAB_FORWARD:
1990     case GTK_DIR_TAB_BACKWARD:
1991       return gtk_container_focus_sort_tab (container, visible_children, direction, old_focus);
1992     case GTK_DIR_UP:
1993     case GTK_DIR_DOWN:
1994       return gtk_container_focus_sort_up_down (container, visible_children, direction, old_focus);
1995     case GTK_DIR_LEFT:
1996     case GTK_DIR_RIGHT:
1997       return gtk_container_focus_sort_left_right (container, visible_children, direction, old_focus);
1998     }
1999
2000   g_assert_not_reached ();
2001
2002   return NULL;
2003 }
2004
2005 static gboolean
2006 gtk_container_focus_move (GtkContainer     *container,
2007                           GList            *children,
2008                           GtkDirectionType  direction)
2009 {
2010   GtkWidget *focus_child;
2011   GtkWidget *child;
2012
2013   focus_child = container->focus_child;
2014
2015   while (children)
2016     {
2017       child = children->data;
2018       children = children->next;
2019
2020       if (!child)
2021         continue;
2022       
2023       if (focus_child)
2024         {
2025           if (focus_child == child)
2026             {
2027               focus_child = NULL;
2028
2029                 if (gtk_widget_child_focus (child, direction))
2030                   return TRUE;
2031             }
2032         }
2033       else if (GTK_WIDGET_DRAWABLE (child) &&
2034                gtk_widget_is_ancestor (child, GTK_WIDGET (container)))
2035         {
2036           if (gtk_widget_child_focus (child, direction))
2037             return TRUE;
2038         }
2039     }
2040
2041   return FALSE;
2042 }
2043
2044
2045 static void
2046 gtk_container_children_callback (GtkWidget *widget,
2047                                  gpointer   client_data)
2048 {
2049   GList **children;
2050
2051   children = (GList**) client_data;
2052   *children = g_list_prepend (*children, widget);
2053 }
2054
2055 static void
2056 chain_widget_destroyed (GtkWidget *widget,
2057                         gpointer   user_data)
2058 {
2059   GtkContainer *container;
2060   GList *chain;
2061   
2062   container = GTK_CONTAINER (user_data);
2063
2064   chain = g_object_get_data (G_OBJECT (container),
2065                              "gtk-container-focus-chain");
2066
2067   chain = g_list_remove (chain, widget);
2068
2069   g_signal_handlers_disconnect_by_func (widget,
2070                                         chain_widget_destroyed,
2071                                         user_data);
2072   
2073   g_object_set_data (G_OBJECT (container),
2074                      I_("gtk-container-focus-chain"),
2075                      chain);  
2076 }
2077
2078 /**
2079  * gtk_container_set_focus_chain: 
2080  * @container: a #GtkContainer.
2081  * @focusable_widgets: the new focus chain.
2082  *
2083  * Sets a focus chain, overriding the one computed automatically by GTK+.
2084  * 
2085  * In principle each widget in the chain should be a descendant of the 
2086  * container, but this is not enforced by this method, since it's allowed 
2087  * to set the focus chain before you pack the widgets, or have a widget 
2088  * in the chain that isn't always packed. The necessary checks are done 
2089  * when the focus chain is actually traversed.
2090  **/
2091 void
2092 gtk_container_set_focus_chain (GtkContainer *container,
2093                                GList        *focusable_widgets)
2094 {
2095   GList *chain;
2096   GList *tmp_list;
2097   
2098   g_return_if_fail (GTK_IS_CONTAINER (container));
2099   
2100   if (container->has_focus_chain)
2101     gtk_container_unset_focus_chain (container);
2102
2103   container->has_focus_chain = TRUE;
2104   
2105   chain = NULL;
2106   tmp_list = focusable_widgets;
2107   while (tmp_list != NULL)
2108     {
2109       g_return_if_fail (GTK_IS_WIDGET (tmp_list->data));
2110       
2111       /* In principle each widget in the chain should be a descendant
2112        * of the container, but we don't want to check that here, it's
2113        * expensive and also it's allowed to set the focus chain before
2114        * you pack the widgets, or have a widget in the chain that isn't
2115        * always packed. So we check for ancestor during actual traversal.
2116        */
2117
2118       chain = g_list_prepend (chain, tmp_list->data);
2119
2120       g_signal_connect (tmp_list->data,
2121                         "destroy",
2122                         G_CALLBACK (chain_widget_destroyed),
2123                         container);
2124       
2125       tmp_list = g_list_next (tmp_list);
2126     }
2127
2128   chain = g_list_reverse (chain);
2129   
2130   g_object_set_data (G_OBJECT (container),
2131                      I_("gtk-container-focus-chain"),
2132                      chain);
2133 }
2134
2135 /**
2136  * gtk_container_get_focus_chain:
2137  * @container:         a #GtkContainer
2138  * @focusable_widgets: location to store the focus chain of the
2139  *                     container, or %NULL. You should free this list
2140  *                     using g_list_free() when you are done with it, however
2141  *                     no additional reference count is added to the
2142  *                     individual widgets in the focus chain.
2143  * 
2144  * Retrieves the focus chain of the container, if one has been
2145  * set explicitly. If no focus chain has been explicitly
2146  * set, GTK+ computes the focus chain based on the positions
2147  * of the children. In that case, GTK+ stores %NULL in
2148  * @focusable_widgets and returns %FALSE.
2149  *
2150  * Return value: %TRUE if the focus chain of the container 
2151  * has been set explicitly.
2152  **/
2153 gboolean
2154 gtk_container_get_focus_chain (GtkContainer *container,
2155                                GList       **focus_chain)
2156 {
2157   g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
2158
2159   if (focus_chain)
2160     {
2161       if (container->has_focus_chain)
2162         *focus_chain = g_list_copy (get_focus_chain (container));
2163       else
2164         *focus_chain = NULL;
2165     }
2166
2167   return container->has_focus_chain;
2168 }
2169
2170 /**
2171  * gtk_container_unset_focus_chain:
2172  * @container: a #GtkContainer.
2173  * 
2174  * Removes a focus chain explicitly set with gtk_container_set_focus_chain().
2175  **/
2176 void
2177 gtk_container_unset_focus_chain (GtkContainer  *container)
2178 {  
2179   g_return_if_fail (GTK_IS_CONTAINER (container));
2180
2181   if (container->has_focus_chain)
2182     {
2183       GList *chain;
2184       GList *tmp_list;
2185       
2186       chain = get_focus_chain (container);
2187       
2188       container->has_focus_chain = FALSE;
2189       
2190       g_object_set_data (G_OBJECT (container), 
2191                          I_("gtk-container-focus-chain"),
2192                          NULL);
2193
2194       tmp_list = chain;
2195       while (tmp_list != NULL)
2196         {
2197           g_signal_handlers_disconnect_by_func (tmp_list->data,
2198                                                 chain_widget_destroyed,
2199                                                 container);
2200           
2201           tmp_list = g_list_next (tmp_list);
2202         }
2203
2204       g_list_free (chain);
2205     }
2206 }
2207
2208 /**
2209  * gtk_container_set_focus_vadjustment:
2210  * @container: a #GtkContainer
2211  * @adjustment: an adjustment which should be adjusted when the focus is moved among the
2212  *   descendents of @container
2213  * 
2214  * Hooks up an adjustment to focus handling in a container, so when a child of the 
2215  * container is focused, the adjustment is scrolled to show that widget. This function
2216  * sets the vertical alignment. See gtk_scrolled_window_get_vadjustment() for a typical
2217  * way of obtaining the adjustment and gtk_container_set_focus_hadjustment() for setting
2218  * the horizontal adjustment.
2219  *
2220  * The adjustments have to be in pixel units and in the same coordinate system as the 
2221  * allocation for immediate children of the container. 
2222  */
2223 void
2224 gtk_container_set_focus_vadjustment (GtkContainer  *container,
2225                                      GtkAdjustment *adjustment)
2226 {
2227   g_return_if_fail (GTK_IS_CONTAINER (container));
2228   if (adjustment)
2229     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2230
2231   if (adjustment)
2232     g_object_ref (adjustment);
2233
2234   g_object_set_qdata_full (G_OBJECT (container),
2235                            vadjustment_key_id,
2236                            adjustment,
2237                            g_object_unref);
2238 }
2239
2240 /**
2241  * gtk_container_get_focus_vadjustment:
2242  * @container: a #GtkContainer
2243  *
2244  * Retrieves the vertical focus adjustment for the container. See
2245  * gtk_container_set_focus_vadjustment ().
2246  *
2247  * Return value: the vertical focus adjustment, or %NULL if
2248  *   none has been set.
2249  **/
2250 GtkAdjustment *
2251 gtk_container_get_focus_vadjustment (GtkContainer *container)
2252 {
2253   GtkAdjustment *vadjustment;
2254     
2255   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
2256
2257   vadjustment = g_object_get_qdata (G_OBJECT (container), vadjustment_key_id);
2258
2259   return vadjustment;
2260 }
2261
2262 /**
2263  * gtk_container_set_focus_hadjustment:
2264  * @container: a #GtkContainer
2265  * @adjustment: an adjustment which should be adjusted when the focus is moved among the
2266  *   descendents of @container
2267  * 
2268  * Hooks up an adjustment to focus handling in a container, so when a child of the 
2269  * container is focused, the adjustment is scrolled to show that widget. This function
2270  * sets the horizontal alignment. See gtk_scrolled_window_get_hadjustment() for a typical
2271  * way of obtaining the adjustment and gtk_container_set_focus_vadjustment() for setting
2272  * the vertical adjustment.
2273  *
2274  * The adjustments have to be in pixel units and in the same coordinate system as the 
2275  * allocation for immediate children of the container. 
2276  */
2277 void
2278 gtk_container_set_focus_hadjustment (GtkContainer  *container,
2279                                      GtkAdjustment *adjustment)
2280 {
2281   g_return_if_fail (GTK_IS_CONTAINER (container));
2282   if (adjustment)
2283     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2284
2285   if (adjustment)
2286     g_object_ref (adjustment);
2287
2288   g_object_set_qdata_full (G_OBJECT (container),
2289                            hadjustment_key_id,
2290                            adjustment,
2291                            g_object_unref);
2292 }
2293
2294 /**
2295  * gtk_container_get_focus_hadjustment:
2296  * @container: a #GtkContainer
2297  *
2298  * Retrieves the horizontal focus adjustment for the container. See
2299  * gtk_container_set_focus_hadjustment ().
2300  *
2301  * Return value: the horizontal focus adjustment, or %NULL if
2302  *   none has been set.
2303  **/
2304 GtkAdjustment *
2305 gtk_container_get_focus_hadjustment (GtkContainer *container)
2306 {
2307   GtkAdjustment *hadjustment;
2308
2309   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
2310
2311   hadjustment = g_object_get_qdata (G_OBJECT (container), hadjustment_key_id);
2312
2313   return hadjustment;
2314 }
2315
2316
2317 static void
2318 gtk_container_show_all (GtkWidget *widget)
2319 {
2320   g_return_if_fail (GTK_IS_CONTAINER (widget));
2321
2322   gtk_container_foreach (GTK_CONTAINER (widget),
2323                          (GtkCallback) gtk_widget_show_all,
2324                          NULL);
2325   gtk_widget_show (widget);
2326 }
2327
2328 static void
2329 gtk_container_hide_all (GtkWidget *widget)
2330 {
2331   g_return_if_fail (GTK_IS_CONTAINER (widget));
2332
2333   gtk_widget_hide (widget);
2334   gtk_container_foreach (GTK_CONTAINER (widget),
2335                          (GtkCallback) gtk_widget_hide_all,
2336                          NULL);
2337 }
2338
2339
2340 static void
2341 gtk_container_expose_child (GtkWidget *child,
2342                             gpointer   client_data)
2343 {
2344   struct {
2345     GtkWidget *container;
2346     GdkEventExpose *event;
2347   } *data = client_data;
2348   
2349   gtk_container_propagate_expose (GTK_CONTAINER (data->container),
2350                                   child,
2351                                   data->event);
2352 }
2353
2354 static gint 
2355 gtk_container_expose (GtkWidget      *widget,
2356                       GdkEventExpose *event)
2357 {
2358   struct {
2359     GtkWidget *container;
2360     GdkEventExpose *event;
2361   } data;
2362
2363   g_return_val_if_fail (GTK_IS_CONTAINER (widget), FALSE);
2364   g_return_val_if_fail (event != NULL, FALSE);
2365
2366   
2367   if (GTK_WIDGET_DRAWABLE (widget)) 
2368     {
2369       data.container = widget;
2370       data.event = event;
2371       
2372       gtk_container_forall (GTK_CONTAINER (widget),
2373                             gtk_container_expose_child,
2374                             &data);
2375     }   
2376   
2377   return FALSE;
2378 }
2379
2380 static void
2381 gtk_container_map_child (GtkWidget *child,
2382                          gpointer   client_data)
2383 {
2384   if (GTK_WIDGET_VISIBLE (child) &&
2385       GTK_WIDGET_CHILD_VISIBLE (child) &&
2386       !GTK_WIDGET_MAPPED (child))
2387     gtk_widget_map (child);
2388 }
2389
2390 static void
2391 gtk_container_map (GtkWidget *widget)
2392 {
2393   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2394
2395   gtk_container_forall (GTK_CONTAINER (widget),
2396                         gtk_container_map_child,
2397                         NULL);
2398
2399   if (!GTK_WIDGET_NO_WINDOW (widget))
2400     gdk_window_show (widget->window);
2401 }
2402
2403 static void
2404 gtk_container_unmap (GtkWidget *widget)
2405 {
2406   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2407
2408   if (!GTK_WIDGET_NO_WINDOW (widget))
2409     gdk_window_hide (widget->window);
2410   else
2411     gtk_container_forall (GTK_CONTAINER (widget),
2412                           (GtkCallback)gtk_widget_unmap,
2413                           NULL);
2414 }
2415
2416 /**
2417  * gtk_container_propagate_expose:
2418  * @container: a #GtkContainer
2419  * @child: a child of @container
2420  * @event: a expose event sent to container
2421  *
2422  * When a container receives an expose event, it must send synthetic
2423  * expose events to all children that don't have their own #GdkWindows.
2424  * This function provides a convenient way of doing this. A container,
2425  * when it receives an expose event, calls gtk_container_propagate_expose() 
2426  * once for each child, passing in the event the container received.
2427  *
2428  * gtk_container_propagate_expose() takes care of deciding whether
2429  * an expose event needs to be sent to the child, intersecting
2430  * the event's area with the child area, and sending the event.
2431  * 
2432  * In most cases, a container can simply either simply inherit the
2433  * ::expose implementation from #GtkContainer, or, do some drawing 
2434  * and then chain to the ::expose implementation from #GtkContainer.
2435  **/
2436 void
2437 gtk_container_propagate_expose (GtkContainer   *container,
2438                                 GtkWidget      *child,
2439                                 GdkEventExpose *event)
2440 {
2441   GdkEvent *child_event;
2442
2443   g_return_if_fail (GTK_IS_CONTAINER (container));
2444   g_return_if_fail (GTK_IS_WIDGET (child));
2445   g_return_if_fail (event != NULL);
2446
2447   g_assert (child->parent == GTK_WIDGET (container));
2448   
2449   if (GTK_WIDGET_DRAWABLE (child) &&
2450       GTK_WIDGET_NO_WINDOW (child) &&
2451       (child->window == event->window))
2452     {
2453       child_event = gdk_event_new (GDK_EXPOSE);
2454       child_event->expose = *event;
2455       g_object_ref (child_event->expose.window);
2456
2457       child_event->expose.region = gtk_widget_region_intersect (child, event->region);
2458       if (!gdk_region_empty (child_event->expose.region))
2459         {
2460           gdk_region_get_clipbox (child_event->expose.region, &child_event->expose.area);
2461           gtk_widget_send_expose (child, child_event);
2462         }
2463       gdk_event_free (child_event);
2464     }
2465 }
2466
2467 #define __GTK_CONTAINER_C__
2468 #include "gtkaliasdef.c"