]> Pileus Git - ~andy/gtk/blob - gtk/gtkcontainer.c
Mention in the docs that the return value is NULL-terminated. (#383373,
[~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 %NULL-terminated array of #GParamSpec*. 
765  *           The array must be 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   /* we may be invoked with a container_resize_queue of NULL, because
1092    * queue_resize could have been adding an extra idle function while
1093    * the queue still got processed. we better just ignore such case
1094    * than trying to explicitely work around them with some extra flags,
1095    * since it doesn't cause any actual harm.
1096    */
1097   while (container_resize_queue)
1098     {
1099       GSList *slist;
1100       GtkWidget *widget;
1101
1102       slist = container_resize_queue;
1103       container_resize_queue = slist->next;
1104       widget = slist->data;
1105       g_slist_free_1 (slist);
1106
1107       GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_PENDING);
1108       gtk_container_check_resize (GTK_CONTAINER (widget));
1109     }
1110
1111   gdk_window_process_all_updates ();
1112
1113   return FALSE;
1114 }
1115
1116 void
1117 _gtk_container_queue_resize (GtkContainer *container)
1118 {
1119   GtkContainer *resize_container;
1120   GtkWidget *widget;
1121   
1122   g_return_if_fail (GTK_IS_CONTAINER (container));
1123
1124   widget = GTK_WIDGET (container);
1125   resize_container = gtk_container_get_resize_container (container);
1126   
1127   while (TRUE)
1128     {
1129       GTK_PRIVATE_SET_FLAG (widget, GTK_ALLOC_NEEDED);
1130       GTK_PRIVATE_SET_FLAG (widget, GTK_REQUEST_NEEDED);
1131       if ((resize_container && widget == GTK_WIDGET (resize_container)) ||
1132           !widget->parent)
1133         break;
1134       
1135       widget = widget->parent;
1136     }
1137       
1138   if (resize_container)
1139     {
1140       if (GTK_WIDGET_VISIBLE (resize_container) &&
1141           (GTK_WIDGET_TOPLEVEL (resize_container) || GTK_WIDGET_REALIZED (resize_container)))
1142         {
1143           switch (resize_container->resize_mode)
1144             {
1145             case GTK_RESIZE_QUEUE:
1146               if (!GTK_CONTAINER_RESIZE_PENDING (resize_container))
1147                 {
1148                   GTK_PRIVATE_SET_FLAG (resize_container, GTK_RESIZE_PENDING);
1149                   if (container_resize_queue == NULL)
1150                     gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE,
1151                                      gtk_container_idle_sizer,
1152                                      NULL, NULL);
1153                   container_resize_queue = g_slist_prepend (container_resize_queue, resize_container);
1154                 }
1155               break;
1156
1157             case GTK_RESIZE_IMMEDIATE:
1158               gtk_container_check_resize (resize_container);
1159               break;
1160
1161             case GTK_RESIZE_PARENT:
1162               g_assert_not_reached ();
1163               break;
1164             }
1165         }
1166       else
1167         {
1168           /* we need to let hidden resize containers know that something
1169            * changed while they where hidden (currently only evaluated by
1170            * toplevels).
1171            */
1172           resize_container->need_resize = TRUE;
1173         }
1174     }
1175 }
1176
1177 void
1178 gtk_container_check_resize (GtkContainer *container)
1179 {
1180   g_return_if_fail (GTK_IS_CONTAINER (container));
1181   
1182   g_signal_emit (container, container_signals[CHECK_RESIZE], 0);
1183 }
1184
1185 static void
1186 gtk_container_real_check_resize (GtkContainer *container)
1187 {
1188   GtkWidget *widget = GTK_WIDGET (container);
1189   GtkRequisition requisition;
1190   
1191   gtk_widget_size_request (widget, &requisition);
1192   
1193   if (requisition.width > widget->allocation.width ||
1194       requisition.height > widget->allocation.height)
1195     {
1196       if (GTK_IS_RESIZE_CONTAINER (container))
1197         gtk_widget_size_allocate (GTK_WIDGET (container),
1198                                   &GTK_WIDGET (container)->allocation);
1199       else
1200         gtk_widget_queue_resize (widget);
1201     }
1202   else
1203     {
1204       gtk_container_resize_children (container);
1205     }
1206 }
1207
1208 /* The container hasn't changed size but one of its children
1209  *  queued a resize request. Which means that the allocation
1210  *  is not sufficient for the requisition of some child.
1211  *  We've already performed a size request at this point,
1212  *  so we simply need to reallocate and let the allocation
1213  *  trickle down via GTK_WIDGET_ALLOC_NEEDED flags. 
1214  */
1215 void
1216 gtk_container_resize_children (GtkContainer *container)
1217 {
1218   GtkWidget *widget;
1219   
1220   /* resizing invariants:
1221    * toplevels have *always* resize_mode != GTK_RESIZE_PARENT set.
1222    * containers that have an idle sizer pending must be flagged with
1223    * RESIZE_PENDING.
1224    */
1225   g_return_if_fail (GTK_IS_CONTAINER (container));
1226
1227   widget = GTK_WIDGET (container);
1228   gtk_widget_size_allocate (widget, &widget->allocation);
1229 }
1230
1231 /**
1232  * gtk_container_forall:
1233  * @container: a #GtkContainer
1234  * @callback: a callback
1235  * @callback_data: callback user data
1236  * 
1237  * Invokes @callback on each child of @container, including children
1238  * that are considered "internal" (implementation details of the
1239  * container). "Internal" children generally weren't added by the user
1240  * of the container, but were added by the container implementation
1241  * itself.  Most applications should use gtk_container_foreach(),
1242  * rather than gtk_container_forall().
1243  **/
1244 void
1245 gtk_container_forall (GtkContainer *container,
1246                       GtkCallback   callback,
1247                       gpointer      callback_data)
1248 {
1249   GtkContainerClass *class;
1250
1251   g_return_if_fail (GTK_IS_CONTAINER (container));
1252   g_return_if_fail (callback != NULL);
1253
1254   class = GTK_CONTAINER_GET_CLASS (container);
1255
1256   if (class->forall)
1257     class->forall (container, TRUE, callback, callback_data);
1258 }
1259
1260 /**
1261  * gtk_container_foreach:
1262  * @container: a #GtkContainer
1263  * @callback: a callback
1264  * @callback_data: callback user data
1265  * 
1266  * Invokes @callback on each non-internal child of @container.  See
1267  * gtk_container_forall() for details on what constitutes an
1268  * "internal" child.  Most applications should use
1269  * gtk_container_foreach(), rather than gtk_container_forall().
1270  **/
1271 void
1272 gtk_container_foreach (GtkContainer *container,
1273                        GtkCallback   callback,
1274                        gpointer      callback_data)
1275 {
1276   GtkContainerClass *class;
1277   
1278   g_return_if_fail (GTK_IS_CONTAINER (container));
1279   g_return_if_fail (callback != NULL);
1280
1281   class = GTK_CONTAINER_GET_CLASS (container);
1282
1283   if (class->forall)
1284     class->forall (container, FALSE, callback, callback_data);
1285 }
1286
1287 typedef struct _GtkForeachData  GtkForeachData;
1288 struct _GtkForeachData
1289 {
1290   GtkObject         *container;
1291   GtkCallbackMarshal callback;
1292   gpointer           callback_data;
1293 };
1294
1295 static void
1296 gtk_container_foreach_unmarshal (GtkWidget *child,
1297                                  gpointer data)
1298 {
1299   GtkForeachData *fdata = (GtkForeachData*) data;
1300   GtkArg args[2];
1301   
1302   /* first argument */
1303   args[0].name = NULL;
1304   args[0].type = G_TYPE_FROM_INSTANCE (child);
1305   GTK_VALUE_OBJECT (args[0]) = GTK_OBJECT (child);
1306   
1307   /* location for return value */
1308   args[1].name = NULL;
1309   args[1].type = G_TYPE_NONE;
1310   
1311   fdata->callback (fdata->container, fdata->callback_data, 1, args);
1312 }
1313
1314 void
1315 gtk_container_foreach_full (GtkContainer       *container,
1316                             GtkCallback         callback,
1317                             GtkCallbackMarshal  marshal,
1318                             gpointer            callback_data,
1319                             GtkDestroyNotify    notify)
1320 {
1321   g_return_if_fail (GTK_IS_CONTAINER (container));
1322
1323   if (marshal)
1324     {
1325       GtkForeachData fdata;
1326   
1327       fdata.container     = GTK_OBJECT (container);
1328       fdata.callback      = marshal;
1329       fdata.callback_data = callback_data;
1330
1331       gtk_container_foreach (container, gtk_container_foreach_unmarshal, &fdata);
1332     }
1333   else
1334     {
1335       g_return_if_fail (callback != NULL);
1336
1337       gtk_container_foreach (container, callback, &callback_data);
1338     }
1339
1340   if (notify)
1341     notify (callback_data);
1342 }
1343
1344 void
1345 gtk_container_set_focus_child (GtkContainer *container,
1346                                GtkWidget    *widget)
1347 {
1348   g_return_if_fail (GTK_IS_CONTAINER (container));
1349   if (widget)
1350     g_return_if_fail (GTK_IS_WIDGET (widget));
1351
1352   g_signal_emit (container, container_signals[SET_FOCUS_CHILD], 0, widget);
1353 }
1354
1355 /**
1356  * gtk_container_get_children:
1357  * @container: a #GtkContainer.
1358  * 
1359  * Returns the container's non-internal children. See
1360  * gtk_container_forall() for details on what constitutes an "internal" child. 
1361  *
1362  * Return value: a newly-allocated list of the container's non-internal children.
1363  **/
1364 GList*
1365 gtk_container_get_children (GtkContainer *container)
1366 {
1367   GList *children = NULL;
1368
1369   gtk_container_foreach (container,
1370                          gtk_container_children_callback,
1371                          &children);
1372
1373   return g_list_reverse (children);
1374 }
1375
1376 static void
1377 gtk_container_child_position_callback (GtkWidget *widget,
1378                                        gpointer   client_data)
1379 {
1380   struct {
1381     GtkWidget *child;
1382     guint i;
1383     guint index;
1384   } *data = client_data;
1385
1386   data->i++;
1387   if (data->child == widget)
1388     data->index = data->i;
1389 }
1390
1391 static gchar*
1392 gtk_container_child_default_composite_name (GtkContainer *container,
1393                                             GtkWidget    *child)
1394 {
1395   struct {
1396     GtkWidget *child;
1397     guint i;
1398     guint index;
1399   } data;
1400   gchar *name;
1401
1402   /* fallback implementation */
1403   data.child = child;
1404   data.i = 0;
1405   data.index = 0;
1406   gtk_container_forall (container,
1407                         gtk_container_child_position_callback,
1408                         &data);
1409   
1410   name = g_strdup_printf ("%s-%u",
1411                           g_type_name (G_TYPE_FROM_INSTANCE (child)),
1412                           data.index);
1413
1414   return name;
1415 }
1416
1417 gchar*
1418 _gtk_container_child_composite_name (GtkContainer *container,
1419                                     GtkWidget    *child)
1420 {
1421   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
1422   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
1423   g_return_val_if_fail (child->parent == GTK_WIDGET (container), NULL);
1424
1425   if (GTK_WIDGET_COMPOSITE_CHILD (child))
1426     {
1427       static GQuark quark_composite_name = 0;
1428       gchar *name;
1429
1430       if (!quark_composite_name)
1431         quark_composite_name = g_quark_from_static_string ("gtk-composite-name");
1432
1433       name = g_object_get_qdata (G_OBJECT (child), quark_composite_name);
1434       if (!name)
1435         {
1436           GtkContainerClass *class;
1437
1438           class = GTK_CONTAINER_GET_CLASS (container);
1439           if (class->composite_name)
1440             name = class->composite_name (container, child);
1441         }
1442       else
1443         name = g_strdup (name);
1444
1445       return name;
1446     }
1447   
1448   return NULL;
1449 }
1450
1451 static void
1452 gtk_container_real_set_focus_child (GtkContainer     *container,
1453                                     GtkWidget        *child)
1454 {
1455   g_return_if_fail (GTK_IS_CONTAINER (container));
1456   g_return_if_fail (child == NULL || GTK_IS_WIDGET (child));
1457
1458   if (child != container->focus_child)
1459     {
1460       if (container->focus_child)
1461         g_object_unref (container->focus_child);
1462       container->focus_child = child;
1463       if (container->focus_child)
1464         g_object_ref (container->focus_child);
1465     }
1466
1467
1468   /* check for h/v adjustments
1469    */
1470   if (container->focus_child)
1471     {
1472       GtkAdjustment *hadj;
1473       GtkAdjustment *vadj;
1474       GtkWidget *focus_child;
1475       gint x, y;
1476
1477       hadj = g_object_get_qdata (G_OBJECT (container), hadjustment_key_id);   
1478       vadj = g_object_get_qdata (G_OBJECT (container), vadjustment_key_id);
1479       if (hadj || vadj) 
1480         {
1481
1482           focus_child = container->focus_child;
1483           while (GTK_IS_CONTAINER (focus_child) && 
1484                  GTK_CONTAINER (focus_child)->focus_child)
1485             {
1486               focus_child = GTK_CONTAINER (focus_child)->focus_child;
1487             }
1488           
1489           gtk_widget_translate_coordinates (focus_child, container->focus_child, 
1490                                             0, 0, &x, &y);
1491
1492            x += container->focus_child->allocation.x;
1493            y += container->focus_child->allocation.y;
1494           
1495           if (vadj)
1496             gtk_adjustment_clamp_page (vadj, y, y + focus_child->allocation.height);
1497           
1498           if (hadj)
1499             gtk_adjustment_clamp_page (hadj, x, x + focus_child->allocation.width);
1500         }
1501     }
1502 }
1503
1504 static GList*
1505 get_focus_chain (GtkContainer *container)
1506 {
1507   return g_object_get_data (G_OBJECT (container), "gtk-container-focus-chain");
1508 }
1509
1510 /* same as gtk_container_get_children, except it includes internals
1511  */
1512 static GList *
1513 gtk_container_get_all_children (GtkContainer *container)
1514 {
1515   GList *children = NULL;
1516
1517   gtk_container_forall (container,
1518                          gtk_container_children_callback,
1519                          &children);
1520
1521   return children;
1522 }
1523
1524 static gboolean
1525 gtk_container_focus (GtkWidget        *widget,
1526                      GtkDirectionType  direction)
1527 {
1528   GList *children;
1529   GList *sorted_children;
1530   gint return_val;
1531   GtkContainer *container;
1532
1533   g_return_val_if_fail (GTK_IS_CONTAINER (widget), FALSE);
1534
1535   container = GTK_CONTAINER (widget);
1536
1537   return_val = FALSE;
1538
1539   if (GTK_WIDGET_CAN_FOCUS (container))
1540     {
1541       if (!GTK_WIDGET_HAS_FOCUS (container))
1542         {
1543           gtk_widget_grab_focus (GTK_WIDGET (container));
1544           return_val = TRUE;
1545         }
1546     }
1547   else
1548     {
1549       /* Get a list of the containers children, allowing focus
1550        * chain to override.
1551        */
1552       if (container->has_focus_chain)
1553         children = g_list_copy (get_focus_chain (container));
1554       else
1555         children = gtk_container_get_all_children (container);
1556
1557       if (container->has_focus_chain &&
1558           (direction == GTK_DIR_TAB_FORWARD ||
1559            direction == GTK_DIR_TAB_BACKWARD))
1560         {
1561           sorted_children = g_list_copy (children);
1562           
1563           if (direction == GTK_DIR_TAB_BACKWARD)
1564             sorted_children = g_list_reverse (sorted_children);
1565         }
1566       else
1567         sorted_children = _gtk_container_focus_sort (container, children, direction, NULL);
1568       
1569       return_val = gtk_container_focus_move (container, sorted_children, direction);
1570
1571       g_list_free (sorted_children);
1572       g_list_free (children);
1573     }
1574
1575   return return_val;
1576 }
1577
1578 static gint
1579 tab_compare (gconstpointer a,
1580              gconstpointer b,
1581              gpointer      data)
1582 {
1583   const GtkWidget *child1 = a;
1584   const GtkWidget *child2 = b;
1585   GtkTextDirection text_direction = GPOINTER_TO_INT (data);
1586
1587   gint y1 = child1->allocation.y + child1->allocation.height / 2;
1588   gint y2 = child2->allocation.y + child2->allocation.height / 2;
1589
1590   if (y1 == y2)
1591     {
1592       gint x1 = child1->allocation.x + child1->allocation.width / 2;
1593       gint x2 = child2->allocation.x + child2->allocation.width / 2;
1594       
1595       if (text_direction == GTK_TEXT_DIR_RTL) 
1596         return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1);
1597       else
1598         return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1);
1599     }
1600   else
1601     return (y1 < y2) ? -1 : 1;
1602 }
1603
1604 static GList *
1605 gtk_container_focus_sort_tab (GtkContainer     *container,
1606                               GList            *children,
1607                               GtkDirectionType  direction,
1608                               GtkWidget        *old_focus)
1609 {
1610   GtkTextDirection text_direction = gtk_widget_get_direction (GTK_WIDGET (container));
1611   children = g_list_sort_with_data (children, tab_compare, GINT_TO_POINTER (text_direction));
1612
1613   /* if we are going backwards then reverse the order
1614    *  of the children.
1615    */
1616   if (direction == GTK_DIR_TAB_BACKWARD)
1617     children = g_list_reverse (children);
1618
1619   return children;
1620 }
1621
1622 /* Get coordinates of @widget's allocation with respect to
1623  * allocation of @container.
1624  */
1625 static gboolean
1626 get_allocation_coords (GtkContainer  *container,
1627                        GtkWidget     *widget,
1628                        GdkRectangle  *allocation)
1629 {
1630   *allocation = widget->allocation;
1631
1632   return gtk_widget_translate_coordinates (widget, GTK_WIDGET (container),
1633                                            0, 0, &allocation->x, &allocation->y);
1634 }
1635
1636 /* Look for a child in @children that is intermediate between
1637  * the focus widget and container. This widget, if it exists,
1638  * acts as the starting widget for focus navigation.
1639  */
1640 static GtkWidget *
1641 find_old_focus (GtkContainer *container,
1642                 GList        *children)
1643 {
1644   GList *tmp_list = children;
1645   while (tmp_list)
1646     {
1647       GtkWidget *child = tmp_list->data;
1648       GtkWidget *widget = child;
1649
1650       while (widget && widget != (GtkWidget *)container)
1651         {
1652           GtkWidget *parent = widget->parent;
1653           if (parent && ((GtkContainer *)parent)->focus_child != widget)
1654             goto next;
1655
1656           widget = parent;
1657         }
1658
1659       return child;
1660
1661     next:
1662       tmp_list = tmp_list->next;
1663     }
1664
1665   return NULL;
1666 }
1667
1668 static gboolean
1669 old_focus_coords (GtkContainer *container,
1670                   GdkRectangle *old_focus_rect)
1671 {
1672   GtkWidget *widget = GTK_WIDGET (container);
1673   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1674   
1675   if (toplevel && GTK_IS_WINDOW (toplevel) && GTK_WINDOW (toplevel)->focus_widget)
1676     {
1677       GtkWidget *old_focus = GTK_WINDOW (toplevel)->focus_widget;
1678       
1679       return get_allocation_coords (container, old_focus, old_focus_rect);
1680     }
1681   else
1682     return FALSE;
1683 }
1684
1685 typedef struct _CompareInfo CompareInfo;
1686
1687 struct _CompareInfo
1688 {
1689   GtkContainer *container;
1690   gint x;
1691   gint y;
1692   gboolean reverse;
1693 };
1694
1695 static gint
1696 up_down_compare (gconstpointer a,
1697                  gconstpointer b,
1698                  gpointer      data)
1699 {
1700   GdkRectangle allocation1;
1701   GdkRectangle allocation2;
1702   CompareInfo *compare = data;
1703   gint y1, y2;
1704
1705   get_allocation_coords (compare->container, (GtkWidget *)a, &allocation1);
1706   get_allocation_coords (compare->container, (GtkWidget *)b, &allocation2);
1707
1708   y1 = allocation1.y + allocation1.height / 2;
1709   y2 = allocation2.y + allocation2.height / 2;
1710
1711   if (y1 == y2)
1712     {
1713       gint x1 = abs (allocation1.x + allocation1.width / 2 - compare->x);
1714       gint x2 = abs (allocation2.x + allocation2.width / 2 - compare->x);
1715
1716       if (compare->reverse)
1717         return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1);
1718       else
1719         return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1);
1720     }
1721   else
1722     return (y1 < y2) ? -1 : 1;
1723 }
1724
1725 static GList *
1726 gtk_container_focus_sort_up_down (GtkContainer     *container,
1727                                   GList            *children,
1728                                   GtkDirectionType  direction,
1729                                   GtkWidget        *old_focus)
1730 {
1731   CompareInfo compare;
1732   GList *tmp_list;
1733   GdkRectangle old_allocation;
1734
1735   compare.container = container;
1736   compare.reverse = (direction == GTK_DIR_UP);
1737
1738   if (!old_focus)
1739       old_focus = find_old_focus (container, children);
1740   
1741   if (old_focus && get_allocation_coords (container, old_focus, &old_allocation))
1742     {
1743       gint compare_x1;
1744       gint compare_x2;
1745       gint compare_y;
1746
1747       /* Delete widgets from list that don't match minimum criteria */
1748
1749       compare_x1 = old_allocation.x;
1750       compare_x2 = old_allocation.x + old_allocation.width;
1751
1752       if (direction == GTK_DIR_UP)
1753         compare_y = old_allocation.y;
1754       else
1755         compare_y = old_allocation.y + old_allocation.height;
1756       
1757       tmp_list = children;
1758       while (tmp_list)
1759         {
1760           GtkWidget *child = tmp_list->data;
1761           GList *next = tmp_list->next;
1762           gint child_x1, child_x2;
1763           GdkRectangle child_allocation;
1764           
1765           if (child != old_focus)
1766             {
1767               if (get_allocation_coords (container, child, &child_allocation))
1768                 {
1769                   child_x1 = child_allocation.x;
1770                   child_x2 = child_allocation.x + child_allocation.width;
1771                   
1772                   if ((child_x2 <= compare_x1 || child_x1 >= compare_x2) /* No horizontal overlap */ ||
1773                       (direction == GTK_DIR_DOWN && child_allocation.y + child_allocation.height < compare_y) || /* Not below */
1774                       (direction == GTK_DIR_UP && child_allocation.y > compare_y)) /* Not above */
1775                     {
1776                       children = g_list_delete_link (children, tmp_list);
1777                     }
1778                 }
1779               else
1780                 children = g_list_delete_link (children, tmp_list);
1781             }
1782           
1783           tmp_list = next;
1784         }
1785
1786       compare.x = (compare_x1 + compare_x2) / 2;
1787       compare.y = old_allocation.y + old_allocation.height / 2;
1788     }
1789   else
1790     {
1791       /* No old focus widget, need to figure out starting x,y some other way
1792        */
1793       GtkWidget *widget = GTK_WIDGET (container);
1794       GdkRectangle old_focus_rect;
1795
1796       if (old_focus_coords (container, &old_focus_rect))
1797         {
1798           compare.x = old_focus_rect.x + old_focus_rect.width / 2;
1799         }
1800       else
1801         {
1802           if (GTK_WIDGET_NO_WINDOW (widget))
1803             compare.x = widget->allocation.x + widget->allocation.width / 2;
1804           else
1805             compare.x = widget->allocation.width / 2;
1806         }
1807       
1808       if (GTK_WIDGET_NO_WINDOW (widget))
1809         compare.y = (direction == GTK_DIR_DOWN) ? widget->allocation.y : widget->allocation.y + widget->allocation.height;
1810       else
1811         compare.y = (direction == GTK_DIR_DOWN) ? 0 : + widget->allocation.height;
1812     }
1813
1814   children = g_list_sort_with_data (children, up_down_compare, &compare);
1815
1816   if (compare.reverse)
1817     children = g_list_reverse (children);
1818
1819   return children;
1820 }
1821
1822 static gint
1823 left_right_compare (gconstpointer a,
1824                     gconstpointer b,
1825                     gpointer      data)
1826 {
1827   GdkRectangle allocation1;
1828   GdkRectangle allocation2;
1829   CompareInfo *compare = data;
1830   gint x1, x2;
1831
1832   get_allocation_coords (compare->container, (GtkWidget *)a, &allocation1);
1833   get_allocation_coords (compare->container, (GtkWidget *)b, &allocation2);
1834
1835   x1 = allocation1.x + allocation1.width / 2;
1836   x2 = allocation2.x + allocation2.width / 2;
1837
1838   if (x1 == x2)
1839     {
1840       gint y1 = abs (allocation1.y + allocation1.height / 2 - compare->y);
1841       gint y2 = abs (allocation2.y + allocation2.height / 2 - compare->y);
1842
1843       if (compare->reverse)
1844         return (y1 < y2) ? 1 : ((y1 == y2) ? 0 : -1);
1845       else
1846         return (y1 < y2) ? -1 : ((y1 == y2) ? 0 : 1);
1847     }
1848   else
1849     return (x1 < x2) ? -1 : 1;
1850 }
1851
1852 static GList *
1853 gtk_container_focus_sort_left_right (GtkContainer     *container,
1854                                      GList            *children,
1855                                      GtkDirectionType  direction,
1856                                      GtkWidget        *old_focus)
1857 {
1858   CompareInfo compare;
1859   GList *tmp_list;
1860   GdkRectangle old_allocation;
1861
1862   compare.container = container;
1863   compare.reverse = (direction == GTK_DIR_LEFT);
1864
1865   if (!old_focus)
1866     old_focus = find_old_focus (container, children);
1867   
1868   if (old_focus && get_allocation_coords (container, old_focus, &old_allocation))
1869     {
1870       gint compare_y1;
1871       gint compare_y2;
1872       gint compare_x;
1873       
1874       /* Delete widgets from list that don't match minimum criteria */
1875
1876       compare_y1 = old_allocation.y;
1877       compare_y2 = old_allocation.y + old_allocation.height;
1878
1879       if (direction == GTK_DIR_LEFT)
1880         compare_x = old_allocation.x;
1881       else
1882         compare_x = old_allocation.x + old_allocation.width;
1883       
1884       tmp_list = children;
1885       while (tmp_list)
1886         {
1887           GtkWidget *child = tmp_list->data;
1888           GList *next = tmp_list->next;
1889           gint child_y1, child_y2;
1890           GdkRectangle child_allocation;
1891           
1892           if (child != old_focus)
1893             {
1894               if (get_allocation_coords (container, child, &child_allocation))
1895                 {
1896                   child_y1 = child_allocation.y;
1897                   child_y2 = child_allocation.y + child_allocation.height;
1898                   
1899                   if ((child_y2 <= compare_y1 || child_y1 >= compare_y2) /* No vertical overlap */ ||
1900                       (direction == GTK_DIR_RIGHT && child_allocation.x + child_allocation.width < compare_x) || /* Not to left */
1901                       (direction == GTK_DIR_LEFT && child_allocation.x > compare_x)) /* Not to right */
1902                     {
1903                       children = g_list_delete_link (children, tmp_list);
1904                     }
1905                 }
1906               else
1907                 children = g_list_delete_link (children, tmp_list);
1908             }
1909           
1910           tmp_list = next;
1911         }
1912
1913       compare.y = (compare_y1 + compare_y2) / 2;
1914       compare.x = old_allocation.x + old_allocation.width / 2;
1915     }
1916   else
1917     {
1918       /* No old focus widget, need to figure out starting x,y some other way
1919        */
1920       GtkWidget *widget = GTK_WIDGET (container);
1921       GdkRectangle old_focus_rect;
1922
1923       if (old_focus_coords (container, &old_focus_rect))
1924         {
1925           compare.y = old_focus_rect.y + old_focus_rect.height / 2;
1926         }
1927       else
1928         {
1929           if (GTK_WIDGET_NO_WINDOW (widget))
1930             compare.y = widget->allocation.y + widget->allocation.height / 2;
1931           else
1932             compare.y = widget->allocation.height / 2;
1933         }
1934       
1935       if (GTK_WIDGET_NO_WINDOW (widget))
1936         compare.x = (direction == GTK_DIR_RIGHT) ? widget->allocation.x : widget->allocation.x + widget->allocation.width;
1937       else
1938         compare.x = (direction == GTK_DIR_RIGHT) ? 0 : widget->allocation.width;
1939     }
1940
1941   children = g_list_sort_with_data (children, left_right_compare, &compare);
1942
1943   if (compare.reverse)
1944     children = g_list_reverse (children);
1945
1946   return children;
1947 }
1948
1949 /**
1950  * gtk_container_focus_sort:
1951  * @container: a #GtkContainer
1952  * @children:  a list of descendents of @container (they don't
1953  *             have to be direct children.
1954  * @direction: focus direction
1955  * @old_focus: widget to use for the starting position, or %NULL
1956  *             to determine this automatically.
1957  *             [ Note, this argument isn't used for GTK_DIR_TAB_*,
1958  *               which is the only @direction we use currently,
1959  *               so perhaps this argument should be removed ]
1960  * 
1961  * Sorts @children in the correct order for focusing with
1962  * direction type @direction.
1963  * 
1964  * Return value: a copy of @children, sorted in correct focusing order,
1965  *   with children that aren't suitable for focusing in this direction
1966  *   removed.
1967  **/
1968 GList *
1969 _gtk_container_focus_sort (GtkContainer     *container,
1970                            GList            *children,
1971                            GtkDirectionType  direction,
1972                            GtkWidget        *old_focus)
1973 {
1974   GList *visible_children = NULL;
1975
1976   while (children)
1977     {
1978       if (GTK_WIDGET_REALIZED (children->data))
1979         visible_children = g_list_prepend (visible_children, children->data);
1980       children = children->next;
1981     }
1982   
1983   switch (direction)
1984     {
1985     case GTK_DIR_TAB_FORWARD:
1986     case GTK_DIR_TAB_BACKWARD:
1987       return gtk_container_focus_sort_tab (container, visible_children, direction, old_focus);
1988     case GTK_DIR_UP:
1989     case GTK_DIR_DOWN:
1990       return gtk_container_focus_sort_up_down (container, visible_children, direction, old_focus);
1991     case GTK_DIR_LEFT:
1992     case GTK_DIR_RIGHT:
1993       return gtk_container_focus_sort_left_right (container, visible_children, direction, old_focus);
1994     }
1995
1996   g_assert_not_reached ();
1997
1998   return NULL;
1999 }
2000
2001 static gboolean
2002 gtk_container_focus_move (GtkContainer     *container,
2003                           GList            *children,
2004                           GtkDirectionType  direction)
2005 {
2006   GtkWidget *focus_child;
2007   GtkWidget *child;
2008
2009   focus_child = container->focus_child;
2010
2011   while (children)
2012     {
2013       child = children->data;
2014       children = children->next;
2015
2016       if (!child)
2017         continue;
2018       
2019       if (focus_child)
2020         {
2021           if (focus_child == child)
2022             {
2023               focus_child = NULL;
2024
2025                 if (gtk_widget_child_focus (child, direction))
2026                   return TRUE;
2027             }
2028         }
2029       else if (GTK_WIDGET_DRAWABLE (child) &&
2030                gtk_widget_is_ancestor (child, GTK_WIDGET (container)))
2031         {
2032           if (gtk_widget_child_focus (child, direction))
2033             return TRUE;
2034         }
2035     }
2036
2037   return FALSE;
2038 }
2039
2040
2041 static void
2042 gtk_container_children_callback (GtkWidget *widget,
2043                                  gpointer   client_data)
2044 {
2045   GList **children;
2046
2047   children = (GList**) client_data;
2048   *children = g_list_prepend (*children, widget);
2049 }
2050
2051 static void
2052 chain_widget_destroyed (GtkWidget *widget,
2053                         gpointer   user_data)
2054 {
2055   GtkContainer *container;
2056   GList *chain;
2057   
2058   container = GTK_CONTAINER (user_data);
2059
2060   chain = g_object_get_data (G_OBJECT (container),
2061                              "gtk-container-focus-chain");
2062
2063   chain = g_list_remove (chain, widget);
2064
2065   g_signal_handlers_disconnect_by_func (widget,
2066                                         chain_widget_destroyed,
2067                                         user_data);
2068   
2069   g_object_set_data (G_OBJECT (container),
2070                      I_("gtk-container-focus-chain"),
2071                      chain);  
2072 }
2073
2074 /**
2075  * gtk_container_set_focus_chain: 
2076  * @container: a #GtkContainer.
2077  * @focusable_widgets: the new focus chain.
2078  *
2079  * Sets a focus chain, overriding the one computed automatically by GTK+.
2080  * 
2081  * In principle each widget in the chain should be a descendant of the 
2082  * container, but this is not enforced by this method, since it's allowed 
2083  * to set the focus chain before you pack the widgets, or have a widget 
2084  * in the chain that isn't always packed. The necessary checks are done 
2085  * when the focus chain is actually traversed.
2086  **/
2087 void
2088 gtk_container_set_focus_chain (GtkContainer *container,
2089                                GList        *focusable_widgets)
2090 {
2091   GList *chain;
2092   GList *tmp_list;
2093   
2094   g_return_if_fail (GTK_IS_CONTAINER (container));
2095   
2096   if (container->has_focus_chain)
2097     gtk_container_unset_focus_chain (container);
2098
2099   container->has_focus_chain = TRUE;
2100   
2101   chain = NULL;
2102   tmp_list = focusable_widgets;
2103   while (tmp_list != NULL)
2104     {
2105       g_return_if_fail (GTK_IS_WIDGET (tmp_list->data));
2106       
2107       /* In principle each widget in the chain should be a descendant
2108        * of the container, but we don't want to check that here, it's
2109        * expensive and also it's allowed to set the focus chain before
2110        * you pack the widgets, or have a widget in the chain that isn't
2111        * always packed. So we check for ancestor during actual traversal.
2112        */
2113
2114       chain = g_list_prepend (chain, tmp_list->data);
2115
2116       g_signal_connect (tmp_list->data,
2117                         "destroy",
2118                         G_CALLBACK (chain_widget_destroyed),
2119                         container);
2120       
2121       tmp_list = g_list_next (tmp_list);
2122     }
2123
2124   chain = g_list_reverse (chain);
2125   
2126   g_object_set_data (G_OBJECT (container),
2127                      I_("gtk-container-focus-chain"),
2128                      chain);
2129 }
2130
2131 /**
2132  * gtk_container_get_focus_chain:
2133  * @container:         a #GtkContainer
2134  * @focusable_widgets: location to store the focus chain of the
2135  *                     container, or %NULL. You should free this list
2136  *                     using g_list_free() when you are done with it, however
2137  *                     no additional reference count is added to the
2138  *                     individual widgets in the focus chain.
2139  * 
2140  * Retrieves the focus chain of the container, if one has been
2141  * set explicitly. If no focus chain has been explicitly
2142  * set, GTK+ computes the focus chain based on the positions
2143  * of the children. In that case, GTK+ stores %NULL in
2144  * @focusable_widgets and returns %FALSE.
2145  *
2146  * Return value: %TRUE if the focus chain of the container 
2147  * has been set explicitly.
2148  **/
2149 gboolean
2150 gtk_container_get_focus_chain (GtkContainer *container,
2151                                GList       **focus_chain)
2152 {
2153   g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
2154
2155   if (focus_chain)
2156     {
2157       if (container->has_focus_chain)
2158         *focus_chain = g_list_copy (get_focus_chain (container));
2159       else
2160         *focus_chain = NULL;
2161     }
2162
2163   return container->has_focus_chain;
2164 }
2165
2166 /**
2167  * gtk_container_unset_focus_chain:
2168  * @container: a #GtkContainer.
2169  * 
2170  * Removes a focus chain explicitly set with gtk_container_set_focus_chain().
2171  **/
2172 void
2173 gtk_container_unset_focus_chain (GtkContainer  *container)
2174 {  
2175   g_return_if_fail (GTK_IS_CONTAINER (container));
2176
2177   if (container->has_focus_chain)
2178     {
2179       GList *chain;
2180       GList *tmp_list;
2181       
2182       chain = get_focus_chain (container);
2183       
2184       container->has_focus_chain = FALSE;
2185       
2186       g_object_set_data (G_OBJECT (container), 
2187                          I_("gtk-container-focus-chain"),
2188                          NULL);
2189
2190       tmp_list = chain;
2191       while (tmp_list != NULL)
2192         {
2193           g_signal_handlers_disconnect_by_func (tmp_list->data,
2194                                                 chain_widget_destroyed,
2195                                                 container);
2196           
2197           tmp_list = g_list_next (tmp_list);
2198         }
2199
2200       g_list_free (chain);
2201     }
2202 }
2203
2204 /**
2205  * gtk_container_set_focus_vadjustment:
2206  * @container: a #GtkContainer
2207  * @adjustment: an adjustment which should be adjusted when the focus is moved among the
2208  *   descendents of @container
2209  * 
2210  * Hooks up an adjustment to focus handling in a container, so when a child of the 
2211  * container is focused, the adjustment is scrolled to show that widget. This function
2212  * sets the vertical alignment. See gtk_scrolled_window_get_vadjustment() for a typical
2213  * way of obtaining the adjustment and gtk_container_set_focus_hadjustment() for setting
2214  * the horizontal adjustment.
2215  *
2216  * The adjustments have to be in pixel units and in the same coordinate system as the 
2217  * allocation for immediate children of the container. 
2218  */
2219 void
2220 gtk_container_set_focus_vadjustment (GtkContainer  *container,
2221                                      GtkAdjustment *adjustment)
2222 {
2223   g_return_if_fail (GTK_IS_CONTAINER (container));
2224   if (adjustment)
2225     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2226
2227   if (adjustment)
2228     g_object_ref (adjustment);
2229
2230   g_object_set_qdata_full (G_OBJECT (container),
2231                            vadjustment_key_id,
2232                            adjustment,
2233                            g_object_unref);
2234 }
2235
2236 /**
2237  * gtk_container_get_focus_vadjustment:
2238  * @container: a #GtkContainer
2239  *
2240  * Retrieves the vertical focus adjustment for the container. See
2241  * gtk_container_set_focus_vadjustment ().
2242  *
2243  * Return value: the vertical focus adjustment, or %NULL if
2244  *   none has been set.
2245  **/
2246 GtkAdjustment *
2247 gtk_container_get_focus_vadjustment (GtkContainer *container)
2248 {
2249   GtkAdjustment *vadjustment;
2250     
2251   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
2252
2253   vadjustment = g_object_get_qdata (G_OBJECT (container), vadjustment_key_id);
2254
2255   return vadjustment;
2256 }
2257
2258 /**
2259  * gtk_container_set_focus_hadjustment:
2260  * @container: a #GtkContainer
2261  * @adjustment: an adjustment which should be adjusted when the focus is moved among the
2262  *   descendents of @container
2263  * 
2264  * Hooks up an adjustment to focus handling in a container, so when a child of the 
2265  * container is focused, the adjustment is scrolled to show that widget. This function
2266  * sets the horizontal alignment. See gtk_scrolled_window_get_hadjustment() for a typical
2267  * way of obtaining the adjustment and gtk_container_set_focus_vadjustment() for setting
2268  * the vertical adjustment.
2269  *
2270  * The adjustments have to be in pixel units and in the same coordinate system as the 
2271  * allocation for immediate children of the container. 
2272  */
2273 void
2274 gtk_container_set_focus_hadjustment (GtkContainer  *container,
2275                                      GtkAdjustment *adjustment)
2276 {
2277   g_return_if_fail (GTK_IS_CONTAINER (container));
2278   if (adjustment)
2279     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2280
2281   if (adjustment)
2282     g_object_ref (adjustment);
2283
2284   g_object_set_qdata_full (G_OBJECT (container),
2285                            hadjustment_key_id,
2286                            adjustment,
2287                            g_object_unref);
2288 }
2289
2290 /**
2291  * gtk_container_get_focus_hadjustment:
2292  * @container: a #GtkContainer
2293  *
2294  * Retrieves the horizontal focus adjustment for the container. See
2295  * gtk_container_set_focus_hadjustment ().
2296  *
2297  * Return value: the horizontal focus adjustment, or %NULL if
2298  *   none has been set.
2299  **/
2300 GtkAdjustment *
2301 gtk_container_get_focus_hadjustment (GtkContainer *container)
2302 {
2303   GtkAdjustment *hadjustment;
2304
2305   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
2306
2307   hadjustment = g_object_get_qdata (G_OBJECT (container), hadjustment_key_id);
2308
2309   return hadjustment;
2310 }
2311
2312
2313 static void
2314 gtk_container_show_all (GtkWidget *widget)
2315 {
2316   g_return_if_fail (GTK_IS_CONTAINER (widget));
2317
2318   gtk_container_foreach (GTK_CONTAINER (widget),
2319                          (GtkCallback) gtk_widget_show_all,
2320                          NULL);
2321   gtk_widget_show (widget);
2322 }
2323
2324 static void
2325 gtk_container_hide_all (GtkWidget *widget)
2326 {
2327   g_return_if_fail (GTK_IS_CONTAINER (widget));
2328
2329   gtk_widget_hide (widget);
2330   gtk_container_foreach (GTK_CONTAINER (widget),
2331                          (GtkCallback) gtk_widget_hide_all,
2332                          NULL);
2333 }
2334
2335
2336 static void
2337 gtk_container_expose_child (GtkWidget *child,
2338                             gpointer   client_data)
2339 {
2340   struct {
2341     GtkWidget *container;
2342     GdkEventExpose *event;
2343   } *data = client_data;
2344   
2345   gtk_container_propagate_expose (GTK_CONTAINER (data->container),
2346                                   child,
2347                                   data->event);
2348 }
2349
2350 static gint 
2351 gtk_container_expose (GtkWidget      *widget,
2352                       GdkEventExpose *event)
2353 {
2354   struct {
2355     GtkWidget *container;
2356     GdkEventExpose *event;
2357   } data;
2358
2359   g_return_val_if_fail (GTK_IS_CONTAINER (widget), FALSE);
2360   g_return_val_if_fail (event != NULL, FALSE);
2361
2362   
2363   if (GTK_WIDGET_DRAWABLE (widget)) 
2364     {
2365       data.container = widget;
2366       data.event = event;
2367       
2368       gtk_container_forall (GTK_CONTAINER (widget),
2369                             gtk_container_expose_child,
2370                             &data);
2371     }   
2372   
2373   return FALSE;
2374 }
2375
2376 static void
2377 gtk_container_map_child (GtkWidget *child,
2378                          gpointer   client_data)
2379 {
2380   if (GTK_WIDGET_VISIBLE (child) &&
2381       GTK_WIDGET_CHILD_VISIBLE (child) &&
2382       !GTK_WIDGET_MAPPED (child))
2383     gtk_widget_map (child);
2384 }
2385
2386 static void
2387 gtk_container_map (GtkWidget *widget)
2388 {
2389   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
2390
2391   gtk_container_forall (GTK_CONTAINER (widget),
2392                         gtk_container_map_child,
2393                         NULL);
2394
2395   if (!GTK_WIDGET_NO_WINDOW (widget))
2396     gdk_window_show (widget->window);
2397 }
2398
2399 static void
2400 gtk_container_unmap (GtkWidget *widget)
2401 {
2402   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
2403
2404   if (!GTK_WIDGET_NO_WINDOW (widget))
2405     gdk_window_hide (widget->window);
2406   else
2407     gtk_container_forall (GTK_CONTAINER (widget),
2408                           (GtkCallback)gtk_widget_unmap,
2409                           NULL);
2410 }
2411
2412 /**
2413  * gtk_container_propagate_expose:
2414  * @container: a #GtkContainer
2415  * @child: a child of @container
2416  * @event: a expose event sent to container
2417  *
2418  * When a container receives an expose event, it must send synthetic
2419  * expose events to all children that don't have their own #GdkWindows.
2420  * This function provides a convenient way of doing this. A container,
2421  * when it receives an expose event, calls gtk_container_propagate_expose() 
2422  * once for each child, passing in the event the container received.
2423  *
2424  * gtk_container_propagate_expose() takes care of deciding whether
2425  * an expose event needs to be sent to the child, intersecting
2426  * the event's area with the child area, and sending the event.
2427  * 
2428  * In most cases, a container can simply either simply inherit the
2429  * ::expose implementation from #GtkContainer, or, do some drawing 
2430  * and then chain to the ::expose implementation from #GtkContainer.
2431  **/
2432 void
2433 gtk_container_propagate_expose (GtkContainer   *container,
2434                                 GtkWidget      *child,
2435                                 GdkEventExpose *event)
2436 {
2437   GdkEvent *child_event;
2438
2439   g_return_if_fail (GTK_IS_CONTAINER (container));
2440   g_return_if_fail (GTK_IS_WIDGET (child));
2441   g_return_if_fail (event != NULL);
2442
2443   g_assert (child->parent == GTK_WIDGET (container));
2444   
2445   if (GTK_WIDGET_DRAWABLE (child) &&
2446       GTK_WIDGET_NO_WINDOW (child) &&
2447       (child->window == event->window))
2448     {
2449       child_event = gdk_event_new (GDK_EXPOSE);
2450       child_event->expose = *event;
2451       g_object_ref (child_event->expose.window);
2452
2453       child_event->expose.region = gtk_widget_region_intersect (child, event->region);
2454       if (!gdk_region_empty (child_event->expose.region))
2455         {
2456           gdk_region_get_clipbox (child_event->expose.region, &child_event->expose.area);
2457           gtk_widget_send_expose (child, child_event);
2458         }
2459       gdk_event_free (child_event);
2460     }
2461 }
2462
2463 #define __GTK_CONTAINER_C__
2464 #include "gtkaliasdef.c"