]> Pileus Git - ~andy/gtk/blob - gtk/gtkcontainer.c
Fix many instances of "the the" in docs and comments. (#165815, Masao
[~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 "gtkalias.h"
33 #include "gtkcontainer.h"
34 #include "gtkprivate.h"
35 #include "gtkmain.h"
36 #include "gtkmarshalers.h"
37 #include "gtkwindow.h"
38 #include "gtkintl.h"
39 #include "gtktoolbar.h"
40 #include <gobject/gobjectnotifyqueue.c>
41 #include <gobject/gvaluecollector.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       static 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, "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                                                       G_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                                                       G_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                                                       G_PARAM_WRITABLE));
226   container_signals[ADD] =
227     g_signal_new ("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 ("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 ("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 ("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   GObject *object;
501   GObjectNotifyQueue *nqueue;
502   const gchar *name;
503
504   g_return_if_fail (GTK_IS_CONTAINER (container));
505   g_return_if_fail (GTK_IS_WIDGET (child));
506   g_return_if_fail (child->parent == GTK_WIDGET (container));
507
508   g_object_ref (container);
509   g_object_ref (child);
510
511   object = G_OBJECT (container);
512   nqueue = g_object_notify_queue_freeze (G_OBJECT (child), _gtk_widget_child_property_notify_context);
513   name = first_property_name;
514   while (name)
515     {
516       GValue value = { 0, };
517       gchar *error = NULL;
518       GParamSpec *pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool,
519                                                     name,
520                                                     G_OBJECT_TYPE (container),
521                                                     TRUE);
522       if (!pspec)
523         {
524           g_warning ("%s: container class `%s' has no child property named `%s'",
525                      G_STRLOC,
526                      G_OBJECT_TYPE_NAME (container),
527                      name);
528           break;
529         }
530       if (!(pspec->flags & G_PARAM_WRITABLE))
531         {
532           g_warning ("%s: child property `%s' of container class `%s' is not writable",
533                      G_STRLOC,
534                      pspec->name,
535                      G_OBJECT_TYPE_NAME (container));
536           break;
537         }
538       g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
539       G_VALUE_COLLECT (&value, var_args, 0, &error);
540       if (error)
541         {
542           g_warning ("%s: %s", G_STRLOC, error);
543           g_free (error);
544
545           /* we purposely leak the value here, it might not be
546            * in a sane state if an error condition occoured
547            */
548           break;
549         }
550       container_set_child_property (container, child, pspec, &value, nqueue);
551       g_value_unset (&value);
552       name = va_arg (var_args, gchar*);
553     }
554   g_object_notify_queue_thaw (G_OBJECT (child), nqueue);
555
556   g_object_unref (container);
557   g_object_unref (child);
558 }
559
560 /**
561  * gtk_container_child_set_property:
562  * @container: a #GtkContainer
563  * @child: a widget which is a child of @container
564  * @property_name: the name of the property to set
565  * @value: the value to set the property to
566  * 
567  * Sets a child property for @child and @container.
568  **/
569 void
570 gtk_container_child_set_property (GtkContainer *container,
571                                   GtkWidget    *child,
572                                   const gchar  *property_name,
573                                   const GValue *value)
574 {
575   GObject *object;
576   GObjectNotifyQueue *nqueue;
577   GParamSpec *pspec;
578
579   g_return_if_fail (GTK_IS_CONTAINER (container));
580   g_return_if_fail (GTK_IS_WIDGET (child));
581   g_return_if_fail (child->parent == GTK_WIDGET (container));
582   g_return_if_fail (property_name != NULL);
583   g_return_if_fail (G_IS_VALUE (value));
584   
585   g_object_ref (container);
586   g_object_ref (child);
587
588   object = G_OBJECT (container);
589   nqueue = g_object_notify_queue_freeze (G_OBJECT (child), _gtk_widget_child_property_notify_context);
590   pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool, property_name,
591                                     G_OBJECT_TYPE (container), TRUE);
592   if (!pspec)
593     g_warning ("%s: container class `%s' has no child property named `%s'",
594                G_STRLOC,
595                G_OBJECT_TYPE_NAME (container),
596                property_name);
597   else if (!(pspec->flags & G_PARAM_WRITABLE))
598     g_warning ("%s: child property `%s' of container class `%s' is not writable",
599                G_STRLOC,
600                pspec->name,
601                G_OBJECT_TYPE_NAME (container));
602   else
603     {
604       container_set_child_property (container, child, pspec, value, nqueue);
605     }
606   g_object_notify_queue_thaw (G_OBJECT (child), nqueue);
607   g_object_unref (container);
608   g_object_unref (child);
609 }
610
611 /**
612  * gtk_container_add_with_properties:
613  * @container: a #GtkContainer 
614  * @widget: a widget to be placed inside @container 
615  * @first_prop_name: the name of the first child property to set 
616  * @Varargs: a %NULL-terminated list of property names and values, starting
617  *           with @first_prop_name.
618  * 
619  * Adds @widget to @container, setting child properties at the same time.
620  * See gtk_container_add() and gtk_container_child_set() for more details.
621  **/
622 void
623 gtk_container_add_with_properties (GtkContainer *container,
624                                    GtkWidget    *widget,
625                                    const gchar  *first_prop_name,
626                                    ...)
627 {
628   g_return_if_fail (GTK_IS_CONTAINER (container));
629   g_return_if_fail (GTK_IS_WIDGET (widget));
630   g_return_if_fail (widget->parent == NULL);
631
632   g_object_ref (container);
633   g_object_ref (widget);
634   gtk_widget_freeze_child_notify (widget);
635
636   g_signal_emit (container, container_signals[ADD], 0, widget);
637   if (widget->parent)
638     {
639       va_list var_args;
640
641       va_start (var_args, first_prop_name);
642       gtk_container_child_set_valist (container, widget, first_prop_name, var_args);
643       va_end (var_args);
644     }
645
646   gtk_widget_thaw_child_notify (widget);
647   g_object_unref (widget);
648   g_object_unref (container);
649 }
650
651 /**
652  * gtk_container_child_set:
653  * @container: a #GtkContainer
654  * @child: a widget which is a child of @container
655  * @first_prop_name: the name of the first property to set
656  * @Varargs: a %NULL-terminated list of property names and values, starting
657  *           with @first_prop_name.
658  * 
659  * Sets one or more child properties for @child and @container.
660  **/
661 void
662 gtk_container_child_set (GtkContainer      *container,
663                          GtkWidget         *child,
664                          const gchar       *first_prop_name,
665                          ...)
666 {
667   va_list var_args;
668   
669   g_return_if_fail (GTK_IS_CONTAINER (container));
670   g_return_if_fail (GTK_IS_WIDGET (child));
671   g_return_if_fail (child->parent == GTK_WIDGET (container));
672
673   va_start (var_args, first_prop_name);
674   gtk_container_child_set_valist (container, child, first_prop_name, var_args);
675   va_end (var_args);
676 }
677
678 /**
679  * gtk_container_child_get:
680  * @container: a #GtkContainer
681  * @child: a widget which is a child of @container
682  * @first_prop_name: the name of the first property to get
683  * @Varargs: a %NULL-terminated list of property names and #GValue*, 
684  *           starting with @first_prop_name.
685  * 
686  * Gets the values of one or more child properties for @child and @container.
687  **/
688 void
689 gtk_container_child_get (GtkContainer      *container,
690                          GtkWidget         *child,
691                          const gchar       *first_prop_name,
692                          ...)
693 {
694   va_list var_args;
695   
696   g_return_if_fail (GTK_IS_CONTAINER (container));
697   g_return_if_fail (GTK_IS_WIDGET (child));
698   g_return_if_fail (child->parent == GTK_WIDGET (container));
699
700   va_start (var_args, first_prop_name);
701   gtk_container_child_get_valist (container, child, first_prop_name, var_args);
702   va_end (var_args);
703 }
704
705 /**
706  * gtk_container_class_install_child_property:
707  * @cclass: a #GtkContainerClass
708  * @property_id: the id for the property
709  * @pspec: the #GParamSpec for the property
710  * 
711  * Installs a child property on a container class. 
712  **/
713 void
714 gtk_container_class_install_child_property (GtkContainerClass *cclass,
715                                             guint              property_id,
716                                             GParamSpec        *pspec)
717 {
718   g_return_if_fail (GTK_IS_CONTAINER_CLASS (cclass));
719   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
720   if (pspec->flags & G_PARAM_WRITABLE)
721     g_return_if_fail (cclass->set_child_property != NULL);
722   if (pspec->flags & G_PARAM_READABLE)
723     g_return_if_fail (cclass->get_child_property != NULL);
724   g_return_if_fail (property_id > 0);
725   g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0);  /* paranoid */
726   if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))
727     g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
728
729   if (g_param_spec_pool_lookup (_gtk_widget_child_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (cclass), FALSE))
730     {
731       g_warning (G_STRLOC ": class `%s' already contains a child property named `%s'",
732                  G_OBJECT_CLASS_NAME (cclass),
733                  pspec->name);
734       return;
735     }
736   g_param_spec_ref (pspec);
737   g_param_spec_sink (pspec);
738   PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
739   g_param_spec_pool_insert (_gtk_widget_child_property_pool, pspec, G_OBJECT_CLASS_TYPE (cclass));
740 }
741
742 /**
743  * gtk_container_class_find_child_property:
744  * @cclass: a #GtkContainerClass
745  * @property_name: the name of the child property to find
746  * @returns: the #GParamSpec of the child property or %NULL if @class has no
747  *   child property with that name.
748  *
749  * Finds a child property of a container class by name.
750  */
751 GParamSpec*
752 gtk_container_class_find_child_property (GObjectClass *cclass,
753                                          const gchar  *property_name)
754 {
755   g_return_val_if_fail (GTK_IS_CONTAINER_CLASS (cclass), NULL);
756   g_return_val_if_fail (property_name != NULL, NULL);
757
758   return g_param_spec_pool_lookup (_gtk_widget_child_property_pool,
759                                    property_name,
760                                    G_OBJECT_CLASS_TYPE (cclass),
761                                    TRUE);
762 }
763
764 /**
765  * gtk_container_class_list_child_properties:
766  * @cclass: a #GtkContainerClass
767  * @n_properties: location to return the number of child properties found
768  * @returns: a newly allocated array of #GParamSpec*. The array must be 
769  *           freed with g_free().
770  *
771  * Returns all child properties of a container class.
772  */
773 GParamSpec**
774 gtk_container_class_list_child_properties (GObjectClass *cclass,
775                                            guint        *n_properties)
776 {
777   GParamSpec **pspecs;
778   guint n;
779
780   g_return_val_if_fail (GTK_IS_CONTAINER_CLASS (cclass), NULL);
781
782   pspecs = g_param_spec_pool_list (_gtk_widget_child_property_pool,
783                                    G_OBJECT_CLASS_TYPE (cclass),
784                                    &n);
785   if (n_properties)
786     *n_properties = n;
787
788   return pspecs;
789 }
790
791 static void
792 gtk_container_add_unimplemented (GtkContainer     *container,
793                                  GtkWidget        *widget)
794 {
795   g_warning ("GtkContainerClass::add not implemented for `%s'", g_type_name (G_TYPE_FROM_INSTANCE (container)));
796 }
797
798 static void
799 gtk_container_remove_unimplemented (GtkContainer     *container,
800                                     GtkWidget        *widget)
801 {
802   g_warning ("GtkContainerClass::remove not implemented for `%s'", g_type_name (G_TYPE_FROM_INSTANCE (container)));
803 }
804
805 static void
806 gtk_container_init (GtkContainer *container)
807 {
808   container->focus_child = NULL;
809   container->border_width = 0;
810   container->need_resize = FALSE;
811   container->resize_mode = GTK_RESIZE_PARENT;
812   container->reallocate_redraws = FALSE;
813 }
814
815 static void
816 gtk_container_destroy (GtkObject *object)
817 {
818   GtkContainer *container = GTK_CONTAINER (object);
819   
820   if (GTK_CONTAINER_RESIZE_PENDING (container))
821     _gtk_container_dequeue_resize_handler (container);
822
823   /* do this before walking child widgets, to avoid
824    * removing children from focus chain one by one.
825    */
826   if (container->has_focus_chain)
827     gtk_container_unset_focus_chain (container);
828   
829   gtk_container_foreach (container, (GtkCallback) gtk_widget_destroy, NULL);
830   
831   if (GTK_OBJECT_CLASS (parent_class)->destroy)
832     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
833 }
834
835 static void
836 gtk_container_set_property (GObject         *object,
837                             guint            prop_id,
838                             const GValue    *value,
839                             GParamSpec      *pspec)
840 {
841   GtkContainer *container = GTK_CONTAINER (object);
842
843   switch (prop_id)
844     {
845     case PROP_BORDER_WIDTH:
846       gtk_container_set_border_width (container, g_value_get_uint (value));
847       break;
848     case PROP_RESIZE_MODE:
849       gtk_container_set_resize_mode (container, g_value_get_enum (value));
850       break;
851     case PROP_CHILD:
852       gtk_container_add (container, GTK_WIDGET (g_value_get_object (value)));
853       break;
854     default:
855       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
856       break;
857     }
858 }
859
860 static void
861 gtk_container_get_property (GObject         *object,
862                             guint            prop_id,
863                             GValue          *value,
864                             GParamSpec      *pspec)
865 {
866   GtkContainer *container = GTK_CONTAINER (object);
867   
868   switch (prop_id)
869     {
870     case PROP_BORDER_WIDTH:
871       g_value_set_uint (value, container->border_width);
872       break;
873     case PROP_RESIZE_MODE:
874       g_value_set_enum (value, container->resize_mode);
875       break;
876     default:
877       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
878       break;
879     }
880 }
881
882 /**
883  * gtk_container_set_border_width:
884  * @container: a #GtkContainer
885  * @border_width: amount of blank space to leave <emphasis>outside</emphasis> the container.
886  *   Valid values are in the range 0-65535 pixels.
887  *
888  * Sets the border width of the container.
889  *
890  * The border width of a container is the amount of space to leave
891  * around the outside of the container. The only exception to this is
892  * #GtkWindow; because toplevel windows can't leave space outside,
893  * they leave the space inside. The border is added on all sides of
894  * the container. To add space to only one side, one approach is to
895  * create a #GtkAlignment widget, call gtk_widget_set_usize() to give
896  * it a size, and place it on the side of the container as a spacer.
897  **/
898 void
899 gtk_container_set_border_width (GtkContainer *container,
900                                 guint         border_width)
901 {
902   g_return_if_fail (GTK_IS_CONTAINER (container));
903
904   if (container->border_width != border_width)
905     {
906       container->border_width = border_width;
907       g_object_notify (G_OBJECT (container), "border_width");
908       
909       if (GTK_WIDGET_REALIZED (container))
910         gtk_widget_queue_resize (GTK_WIDGET (container));
911     }
912 }
913
914 /**
915  * gtk_container_get_border_width:
916  * @container: a #GtkContainer
917  * 
918  * Retrieves the border width of the container. See
919  * gtk_container_set_border_width().
920  *
921  * Return value: the current border width
922  **/
923 guint
924 gtk_container_get_border_width (GtkContainer *container)
925 {
926   g_return_val_if_fail (GTK_IS_CONTAINER (container), 0);
927
928   return container->border_width;
929 }
930
931 /**
932  * gtk_container_add:
933  * @container: a #GtkContainer
934  * @widget: a widget to be placed inside @container
935  * 
936  * Adds @widget to @container. Typically used for simple containers
937  * such as #GtkWindow, #GtkFrame, or #GtkButton; for more complicated
938  * layout containers such as #GtkBox or #GtkTable, this function will
939  * pick default packing parameters that may not be correct.  So
940  * consider functions such as gtk_box_pack_start() and
941  * gtk_table_attach() as an alternative to gtk_container_add() in
942  * those cases. A widget may be added to only one container at a time;
943  * you can't place the same widget inside two different containers.
944  **/
945 void
946 gtk_container_add (GtkContainer *container,
947                    GtkWidget    *widget)
948 {
949   g_return_if_fail (GTK_IS_CONTAINER (container));
950   g_return_if_fail (GTK_IS_WIDGET (widget));
951
952   if (widget->parent != NULL)
953     {
954       g_warning ("Attempting to add a widget with type %s to a container of "
955                  "type %s, but the widget is already inside a container of type %s, "
956                  "the GTK+ FAQ at http://www.gtk.org/faq/ explains how to reparent a widget.",
957                  g_type_name (G_OBJECT_TYPE (widget)),
958                  g_type_name (G_OBJECT_TYPE (container)),
959                  g_type_name (G_OBJECT_TYPE (widget->parent)));
960       return;
961     }
962
963   g_signal_emit (container, container_signals[ADD], 0, widget);
964 }
965
966 /**
967  * gtk_container_remove:
968  * @container: a #GtkContainer
969  * @widget: a current child of @container
970  * 
971  * Removes @widget from @container. @widget must be inside @container.
972  * Note that @container will own a reference to @widget, and that this
973  * may be the last reference held; so removing a widget from its
974  * container can destroy that widget. If you want to use @widget
975  * again, you need to add a reference to it while it's not inside
976  * a container, using g_object_ref(). If you don't want to use @widget
977  * again it's usually more efficient to simply destroy it directly
978  * using gtk_widget_destroy() since this will remove it from the
979  * container and help break any circular reference count cycles.
980  **/
981 void
982 gtk_container_remove (GtkContainer *container,
983                       GtkWidget    *widget)
984 {
985   g_return_if_fail (GTK_IS_CONTAINER (container));
986   g_return_if_fail (GTK_IS_WIDGET (widget));
987
988   /* When using the deprecated API of the toolbar, it is possible
989    * to legitimately call this function with a widget that is not
990    * a direct child of the container.
991    */
992   g_return_if_fail (GTK_IS_TOOLBAR (container) ||
993                     widget->parent == GTK_WIDGET (container));
994   
995   g_signal_emit (container, container_signals[REMOVE], 0, widget);
996 }
997
998 void
999 _gtk_container_dequeue_resize_handler (GtkContainer *container)
1000 {
1001   g_return_if_fail (GTK_IS_CONTAINER (container));
1002   g_return_if_fail (GTK_CONTAINER_RESIZE_PENDING (container));
1003
1004   container_resize_queue = g_slist_remove (container_resize_queue, container);
1005   GTK_PRIVATE_UNSET_FLAG (container, GTK_RESIZE_PENDING);
1006 }
1007
1008 /**
1009  * gtk_container_set_resize_mode:
1010  * @container: a #GtkContainer.
1011  * @resize_mode: the new resize mode.
1012  * 
1013  * Sets the resize mode for the container.
1014  *
1015  * The resize mode of a container determines whether a resize request 
1016  * will be passed to the container's parent, queued for later execution
1017  * or executed immediately.
1018  **/
1019 void
1020 gtk_container_set_resize_mode (GtkContainer  *container,
1021                                GtkResizeMode  resize_mode)
1022 {
1023   g_return_if_fail (GTK_IS_CONTAINER (container));
1024   g_return_if_fail (resize_mode <= GTK_RESIZE_IMMEDIATE);
1025   
1026   if (GTK_WIDGET_TOPLEVEL (container) &&
1027       resize_mode == GTK_RESIZE_PARENT)
1028     {
1029       resize_mode = GTK_RESIZE_QUEUE;
1030     }
1031   
1032   if (container->resize_mode != resize_mode)
1033     {
1034       container->resize_mode = resize_mode;
1035       
1036       gtk_widget_queue_resize (GTK_WIDGET (container));
1037       g_object_notify (G_OBJECT (container), "resize_mode");
1038     }
1039 }
1040
1041 /**
1042  * gtk_container_get_resize_mode:
1043  * @container: a #GtkContainer
1044  * 
1045  * Returns the resize mode for the container. See
1046  * gtk_container_set_resize_mode ().
1047  *
1048  * Return value: the current resize mode
1049  **/
1050 GtkResizeMode
1051 gtk_container_get_resize_mode (GtkContainer *container)
1052 {
1053   g_return_val_if_fail (GTK_IS_CONTAINER (container), GTK_RESIZE_PARENT);
1054
1055   return container->resize_mode;
1056 }
1057
1058 /**
1059  * gtk_container_set_reallocate_redraws:
1060  * @container: a #GtkContainer.
1061  * @needs_redraws: the new value for the container's @reallocate_redraws flag.
1062  *
1063  * Sets the @reallocate_redraws flag of the container to the given value.
1064  * 
1065  * Containers requesting reallocation redraws get automatically
1066  * redrawn if any of their children changed allocation. 
1067  **/ 
1068 void
1069 gtk_container_set_reallocate_redraws (GtkContainer *container,
1070                                       gboolean      needs_redraws)
1071 {
1072   g_return_if_fail (GTK_IS_CONTAINER (container));
1073
1074   container->reallocate_redraws = needs_redraws ? TRUE : FALSE;
1075 }
1076
1077 static GtkContainer*
1078 gtk_container_get_resize_container (GtkContainer *container)
1079 {
1080   GtkWidget *widget = GTK_WIDGET (container);
1081
1082   while (widget->parent)
1083     {
1084       widget = widget->parent;
1085       if (GTK_IS_RESIZE_CONTAINER (widget))
1086         break;
1087     }
1088
1089   return GTK_IS_RESIZE_CONTAINER (widget) ? (GtkContainer*) widget : NULL;
1090 }
1091
1092 static gboolean
1093 gtk_container_idle_sizer (gpointer data)
1094 {
1095   GDK_THREADS_ENTER ();
1096
1097   /* we may be invoked with a container_resize_queue of NULL, because
1098    * queue_resize could have been adding an extra idle function while
1099    * the queue still got processed. we better just ignore such case
1100    * than trying to explicitely work around them with some extra flags,
1101    * since it doesn't cause any actual harm.
1102    */
1103   while (container_resize_queue)
1104     {
1105       GSList *slist;
1106       GtkWidget *widget;
1107
1108       slist = container_resize_queue;
1109       container_resize_queue = slist->next;
1110       widget = slist->data;
1111       g_slist_free_1 (slist);
1112
1113       GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_PENDING);
1114       gtk_container_check_resize (GTK_CONTAINER (widget));
1115     }
1116
1117   gdk_window_process_all_updates ();
1118
1119   GDK_THREADS_LEAVE ();
1120
1121   return FALSE;
1122 }
1123
1124 void
1125 _gtk_container_queue_resize (GtkContainer *container)
1126 {
1127   GtkContainer *resize_container;
1128   GtkWidget *widget;
1129   
1130   g_return_if_fail (GTK_IS_CONTAINER (container));
1131
1132   widget = GTK_WIDGET (container);
1133   resize_container = gtk_container_get_resize_container (container);
1134   
1135   while (TRUE)
1136     {
1137       GTK_PRIVATE_SET_FLAG (widget, GTK_ALLOC_NEEDED);
1138       GTK_PRIVATE_SET_FLAG (widget, GTK_REQUEST_NEEDED);
1139       if ((resize_container && widget == GTK_WIDGET (resize_container)) ||
1140           !widget->parent)
1141         break;
1142       
1143       widget = widget->parent;
1144     }
1145       
1146   if (resize_container)
1147     {
1148       if (GTK_WIDGET_VISIBLE (resize_container) &&
1149           (GTK_WIDGET_TOPLEVEL (resize_container) || GTK_WIDGET_REALIZED (resize_container)))
1150         {
1151           switch (resize_container->resize_mode)
1152             {
1153             case GTK_RESIZE_QUEUE:
1154               if (!GTK_CONTAINER_RESIZE_PENDING (resize_container))
1155                 {
1156                   GTK_PRIVATE_SET_FLAG (resize_container, GTK_RESIZE_PENDING);
1157                   if (container_resize_queue == NULL)
1158                     g_idle_add_full (GTK_PRIORITY_RESIZE,
1159                                      gtk_container_idle_sizer,
1160                                      NULL, NULL);
1161                   container_resize_queue = g_slist_prepend (container_resize_queue, resize_container);
1162                 }
1163               break;
1164
1165             case GTK_RESIZE_IMMEDIATE:
1166               gtk_container_check_resize (resize_container);
1167               break;
1168
1169             case GTK_RESIZE_PARENT:
1170               g_assert_not_reached ();
1171               break;
1172             }
1173         }
1174       else
1175         {
1176           /* we need to let hidden resize containers know that something
1177            * changed while they where hidden (currently only evaluated by
1178            * toplevels).
1179            */
1180           resize_container->need_resize = TRUE;
1181         }
1182     }
1183 }
1184
1185 void
1186 gtk_container_check_resize (GtkContainer *container)
1187 {
1188   g_return_if_fail (GTK_IS_CONTAINER (container));
1189   
1190   g_signal_emit (container, container_signals[CHECK_RESIZE], 0);
1191 }
1192
1193 static void
1194 gtk_container_real_check_resize (GtkContainer *container)
1195 {
1196   GtkWidget *widget = GTK_WIDGET (container);
1197   GtkRequisition requisition;
1198   
1199   gtk_widget_size_request (widget, &requisition);
1200   
1201   if (requisition.width > widget->allocation.width ||
1202       requisition.height > widget->allocation.height)
1203     {
1204       if (GTK_IS_RESIZE_CONTAINER (container))
1205         gtk_widget_size_allocate (GTK_WIDGET (container),
1206                                   &GTK_WIDGET (container)->allocation);
1207       else
1208         gtk_widget_queue_resize (widget);
1209     }
1210   else
1211     {
1212       gtk_container_resize_children (container);
1213     }
1214 }
1215
1216 /* The container hasn't changed size but one of its children
1217  *  queued a resize request. Which means that the allocation
1218  *  is not sufficient for the requisition of some child.
1219  *  We've already performed a size request at this point,
1220  *  so we simply need to reallocate and let the allocation
1221  *  trickle down via GTK_WIDGET_ALLOC_NEEDED flags. 
1222  */
1223 void
1224 gtk_container_resize_children (GtkContainer *container)
1225 {
1226   GtkWidget *widget;
1227   
1228   /* resizing invariants:
1229    * toplevels have *always* resize_mode != GTK_RESIZE_PARENT set.
1230    * containers that have an idle sizer pending must be flagged with
1231    * RESIZE_PENDING.
1232    */
1233   g_return_if_fail (GTK_IS_CONTAINER (container));
1234
1235   widget = GTK_WIDGET (container);
1236   gtk_widget_size_allocate (widget, &widget->allocation);
1237 }
1238
1239 /**
1240  * gtk_container_forall:
1241  * @container: a #GtkContainer
1242  * @callback: a callback
1243  * @callback_data: callback user data
1244  * 
1245  * Invokes @callback on each child of @container, including children
1246  * that are considered "internal" (implementation details of the
1247  * container). "Internal" children generally weren't added by the user
1248  * of the container, but were added by the container implementation
1249  * itself.  Most applications should use gtk_container_foreach(),
1250  * rather than gtk_container_forall().
1251  **/
1252 void
1253 gtk_container_forall (GtkContainer *container,
1254                       GtkCallback   callback,
1255                       gpointer      callback_data)
1256 {
1257   GtkContainerClass *class;
1258
1259   g_return_if_fail (GTK_IS_CONTAINER (container));
1260   g_return_if_fail (callback != NULL);
1261
1262   class = GTK_CONTAINER_GET_CLASS (container);
1263
1264   if (class->forall)
1265     class->forall (container, TRUE, callback, callback_data);
1266 }
1267
1268 /**
1269  * gtk_container_foreach:
1270  * @container: a #GtkContainer
1271  * @callback: a callback
1272  * @callback_data: callback user data
1273  * 
1274  * Invokes @callback on each non-internal child of @container.  See
1275  * gtk_container_forall() for details on what constitutes an
1276  * "internal" child.  Most applications should use
1277  * gtk_container_foreach(), rather than gtk_container_forall().
1278  **/
1279 void
1280 gtk_container_foreach (GtkContainer *container,
1281                        GtkCallback   callback,
1282                        gpointer      callback_data)
1283 {
1284   GtkContainerClass *class;
1285   
1286   g_return_if_fail (GTK_IS_CONTAINER (container));
1287   g_return_if_fail (callback != NULL);
1288
1289   class = GTK_CONTAINER_GET_CLASS (container);
1290
1291   if (class->forall)
1292     class->forall (container, FALSE, callback, callback_data);
1293 }
1294
1295 typedef struct _GtkForeachData  GtkForeachData;
1296 struct _GtkForeachData
1297 {
1298   GtkObject         *container;
1299   GtkCallbackMarshal callback;
1300   gpointer           callback_data;
1301 };
1302
1303 static void
1304 gtk_container_foreach_unmarshal (GtkWidget *child,
1305                                  gpointer data)
1306 {
1307   GtkForeachData *fdata = (GtkForeachData*) data;
1308   GtkArg args[2];
1309   
1310   /* first argument */
1311   args[0].name = NULL;
1312   args[0].type = G_TYPE_FROM_INSTANCE (child);
1313   GTK_VALUE_OBJECT (args[0]) = GTK_OBJECT (child);
1314   
1315   /* location for return value */
1316   args[1].name = NULL;
1317   args[1].type = G_TYPE_NONE;
1318   
1319   fdata->callback (fdata->container, fdata->callback_data, 1, args);
1320 }
1321
1322 void
1323 gtk_container_foreach_full (GtkContainer       *container,
1324                             GtkCallback         callback,
1325                             GtkCallbackMarshal  marshal,
1326                             gpointer            callback_data,
1327                             GtkDestroyNotify    notify)
1328 {
1329   g_return_if_fail (GTK_IS_CONTAINER (container));
1330
1331   if (marshal)
1332     {
1333       GtkForeachData fdata;
1334   
1335       fdata.container     = GTK_OBJECT (container);
1336       fdata.callback      = marshal;
1337       fdata.callback_data = callback_data;
1338
1339       gtk_container_foreach (container, gtk_container_foreach_unmarshal, &fdata);
1340     }
1341   else
1342     {
1343       g_return_if_fail (callback != NULL);
1344
1345       gtk_container_foreach (container, callback, &callback_data);
1346     }
1347
1348   if (notify)
1349     notify (callback_data);
1350 }
1351
1352 void
1353 gtk_container_set_focus_child (GtkContainer *container,
1354                                GtkWidget    *widget)
1355 {
1356   g_return_if_fail (GTK_IS_CONTAINER (container));
1357   if (widget)
1358     g_return_if_fail (GTK_IS_WIDGET (widget));
1359
1360   g_signal_emit (container, container_signals[SET_FOCUS_CHILD], 0, widget);
1361 }
1362
1363 /**
1364  * gtk_container_get_children:
1365  * @container: a #GtkContainer.
1366  * 
1367  * Returns the container's non-internal children. See
1368  * gtk_container_forall() for details on what constitutes an "internal" child. 
1369  *
1370  * Return value: a newly-allocated list of the container's non-internal children.
1371  **/
1372 GList*
1373 gtk_container_get_children (GtkContainer *container)
1374 {
1375   GList *children = NULL;
1376
1377   gtk_container_foreach (container,
1378                          gtk_container_children_callback,
1379                          &children);
1380
1381   return g_list_reverse (children);
1382 }
1383
1384 static void
1385 gtk_container_child_position_callback (GtkWidget *widget,
1386                                        gpointer   client_data)
1387 {
1388   struct {
1389     GtkWidget *child;
1390     guint i;
1391     guint index;
1392   } *data = client_data;
1393
1394   data->i++;
1395   if (data->child == widget)
1396     data->index = data->i;
1397 }
1398
1399 static gchar*
1400 gtk_container_child_default_composite_name (GtkContainer *container,
1401                                             GtkWidget    *child)
1402 {
1403   struct {
1404     GtkWidget *child;
1405     guint i;
1406     guint index;
1407   } data;
1408   gchar *name;
1409
1410   /* fallback implementation */
1411   data.child = child;
1412   data.i = 0;
1413   data.index = 0;
1414   gtk_container_forall (container,
1415                         gtk_container_child_position_callback,
1416                         &data);
1417   
1418   name = g_strdup_printf ("%s-%u",
1419                           g_type_name (G_TYPE_FROM_INSTANCE (child)),
1420                           data.index);
1421
1422   return name;
1423 }
1424
1425 gchar*
1426 _gtk_container_child_composite_name (GtkContainer *container,
1427                                     GtkWidget    *child)
1428 {
1429   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
1430   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
1431   g_return_val_if_fail (child->parent == GTK_WIDGET (container), NULL);
1432
1433   if (GTK_WIDGET_COMPOSITE_CHILD (child))
1434     {
1435       static GQuark quark_composite_name = 0;
1436       gchar *name;
1437
1438       if (!quark_composite_name)
1439         quark_composite_name = g_quark_from_static_string ("gtk-composite-name");
1440
1441       name = g_object_get_qdata (G_OBJECT (child), quark_composite_name);
1442       if (!name)
1443         {
1444           GtkContainerClass *class;
1445
1446           class = GTK_CONTAINER_GET_CLASS (container);
1447           if (class->composite_name)
1448             name = class->composite_name (container, child);
1449         }
1450       else
1451         name = g_strdup (name);
1452
1453       return name;
1454     }
1455   
1456   return NULL;
1457 }
1458
1459 static void
1460 gtk_container_real_set_focus_child (GtkContainer     *container,
1461                                     GtkWidget        *child)
1462 {
1463   g_return_if_fail (GTK_IS_CONTAINER (container));
1464   g_return_if_fail (child == NULL || GTK_IS_WIDGET (child));
1465
1466   if (child != container->focus_child)
1467     {
1468       if (container->focus_child)
1469         g_object_unref (container->focus_child);
1470       container->focus_child = child;
1471       if (container->focus_child)
1472         g_object_ref (container->focus_child);
1473     }
1474
1475
1476   /* check for h/v adjustments
1477    */
1478   if (container->focus_child)
1479     {
1480       GtkAdjustment *hadj;
1481       GtkAdjustment *vadj;
1482       GtkWidget *focus_child;
1483       gint x, y;
1484
1485       hadj = g_object_get_qdata (G_OBJECT (container), hadjustment_key_id);   
1486       vadj = g_object_get_qdata (G_OBJECT (container), vadjustment_key_id);
1487       if (hadj || vadj) 
1488         {
1489
1490           focus_child = container->focus_child;
1491           while (GTK_IS_CONTAINER (focus_child) && 
1492                  GTK_CONTAINER (focus_child)->focus_child)
1493             {
1494               focus_child = GTK_CONTAINER (focus_child)->focus_child;
1495             }
1496           
1497           gtk_widget_translate_coordinates (focus_child, container->focus_child, 
1498                                             0, 0, &x, &y);
1499
1500            x += container->focus_child->allocation.x;
1501            y += container->focus_child->allocation.y;
1502           
1503           if (vadj)
1504             gtk_adjustment_clamp_page (vadj, y, y + focus_child->allocation.height);
1505           
1506           if (hadj)
1507             gtk_adjustment_clamp_page (hadj, x, x + focus_child->allocation.width);
1508         }
1509     }
1510 }
1511
1512 static GList*
1513 get_focus_chain (GtkContainer *container)
1514 {
1515   return g_object_get_data (G_OBJECT (container), "gtk-container-focus-chain");
1516 }
1517
1518 /* same as gtk_container_get_children, except it includes internals
1519  */
1520 static GList *
1521 gtk_container_get_all_children (GtkContainer *container)
1522 {
1523   GList *children = NULL;
1524
1525   gtk_container_forall (container,
1526                          gtk_container_children_callback,
1527                          &children);
1528
1529   return children;
1530 }
1531
1532 static gboolean
1533 gtk_container_focus (GtkWidget        *widget,
1534                      GtkDirectionType  direction)
1535 {
1536   GList *children;
1537   GList *sorted_children;
1538   gint return_val;
1539   GtkContainer *container;
1540
1541   g_return_val_if_fail (GTK_IS_CONTAINER (widget), FALSE);
1542
1543   container = GTK_CONTAINER (widget);
1544
1545   return_val = FALSE;
1546
1547   if (GTK_WIDGET_CAN_FOCUS (container))
1548     {
1549       if (!GTK_WIDGET_HAS_FOCUS (container))
1550         {
1551           gtk_widget_grab_focus (GTK_WIDGET (container));
1552           return_val = TRUE;
1553         }
1554     }
1555   else
1556     {
1557       /* Get a list of the containers children, allowing focus
1558        * chain to override.
1559        */
1560       if (container->has_focus_chain)
1561         children = g_list_copy (get_focus_chain (container));
1562       else
1563         children = gtk_container_get_all_children (container);
1564
1565       if (container->has_focus_chain &&
1566           (direction == GTK_DIR_TAB_FORWARD ||
1567            direction == GTK_DIR_TAB_BACKWARD))
1568         {
1569           sorted_children = g_list_copy (children);
1570           
1571           if (direction == GTK_DIR_TAB_BACKWARD)
1572             sorted_children = g_list_reverse (sorted_children);
1573         }
1574       else
1575         sorted_children = _gtk_container_focus_sort (container, children, direction, NULL);
1576       
1577       return_val = gtk_container_focus_move (container, sorted_children, direction);
1578
1579       g_list_free (sorted_children);
1580       g_list_free (children);
1581     }
1582
1583   return return_val;
1584 }
1585
1586 static gint
1587 tab_compare (gconstpointer a,
1588              gconstpointer b,
1589              gpointer      data)
1590 {
1591   const GtkWidget *child1 = a;
1592   const GtkWidget *child2 = b;
1593   GtkTextDirection text_direction = GPOINTER_TO_INT (data);
1594
1595   gint y1 = child1->allocation.y + child1->allocation.height / 2;
1596   gint y2 = child2->allocation.y + child2->allocation.height / 2;
1597
1598   if (y1 == y2)
1599     {
1600       gint x1 = child1->allocation.x + child1->allocation.width / 2;
1601       gint x2 = child2->allocation.x + child2->allocation.width / 2;
1602       
1603       if (text_direction == GTK_TEXT_DIR_RTL) 
1604         return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1);
1605       else
1606         return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1);
1607     }
1608   else
1609     return (y1 < y2) ? -1 : 1;
1610 }
1611
1612 static GList *
1613 gtk_container_focus_sort_tab (GtkContainer     *container,
1614                               GList            *children,
1615                               GtkDirectionType  direction,
1616                               GtkWidget        *old_focus)
1617 {
1618   GtkTextDirection text_direction = gtk_widget_get_direction (GTK_WIDGET (container));
1619   children = g_list_sort_with_data (children, tab_compare, GINT_TO_POINTER (text_direction));
1620
1621   /* if we are going backwards then reverse the order
1622    *  of the children.
1623    */
1624   if (direction == GTK_DIR_TAB_BACKWARD)
1625     children = g_list_reverse (children);
1626
1627   return children;
1628 }
1629
1630 /* Get coordinates of @widget's allocation with respect to
1631  * allocation of @container.
1632  */
1633 static gboolean
1634 get_allocation_coords (GtkContainer  *container,
1635                        GtkWidget     *widget,
1636                        GdkRectangle  *allocation)
1637 {
1638   *allocation = widget->allocation;
1639
1640   return gtk_widget_translate_coordinates (widget, GTK_WIDGET (container),
1641                                            0, 0, &allocation->x, &allocation->y);
1642 }
1643
1644 /* Look for a child in @children that is intermediate between
1645  * the focus widget and container. This widget, if it exists,
1646  * acts as the starting widget for focus navigation.
1647  */
1648 static GtkWidget *
1649 find_old_focus (GtkContainer *container,
1650                 GList        *children)
1651 {
1652   GList *tmp_list = children;
1653   while (tmp_list)
1654     {
1655       GtkWidget *child = tmp_list->data;
1656       GtkWidget *widget = child;
1657
1658       while (widget && widget != (GtkWidget *)container)
1659         {
1660           GtkWidget *parent = widget->parent;
1661           if (parent && ((GtkContainer *)parent)->focus_child != widget)
1662             goto next;
1663
1664           widget = parent;
1665         }
1666
1667       return child;
1668
1669     next:
1670       tmp_list = tmp_list->next;
1671     }
1672
1673   return NULL;
1674 }
1675
1676 static gboolean
1677 old_focus_coords (GtkContainer *container,
1678                   GdkRectangle *old_focus_rect)
1679 {
1680   GtkWidget *widget = GTK_WIDGET (container);
1681   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1682   
1683   if (toplevel && GTK_IS_WINDOW (toplevel) && GTK_WINDOW (toplevel)->focus_widget)
1684     {
1685       GtkWidget *old_focus = GTK_WINDOW (toplevel)->focus_widget;
1686       
1687       return get_allocation_coords (container, old_focus, old_focus_rect);
1688     }
1689   else
1690     return FALSE;
1691 }
1692
1693 typedef struct _CompareInfo CompareInfo;
1694
1695 struct _CompareInfo
1696 {
1697   GtkContainer *container;
1698   gint x;
1699   gint y;
1700   gboolean reverse;
1701 };
1702
1703 static gint
1704 up_down_compare (gconstpointer a,
1705                  gconstpointer b,
1706                  gpointer      data)
1707 {
1708   GdkRectangle allocation1;
1709   GdkRectangle allocation2;
1710   CompareInfo *compare = data;
1711   gint y1, y2;
1712
1713   if (!get_allocation_coords (compare->container, (GtkWidget *)a, &allocation1))
1714     return 0;
1715   if (!get_allocation_coords (compare->container, (GtkWidget *)b, &allocation2))
1716     return 0;
1717
1718   y1 = allocation1.y + allocation1.height / 2;
1719   y2 = allocation2.y + allocation2.height / 2;
1720
1721   if (y1 == y2)
1722     {
1723       gint x1 = abs (allocation1.x + allocation1.width / 2 - compare->x);
1724       gint x2 = abs (allocation2.x + allocation2.width / 2 - compare->x);
1725
1726       if (compare->reverse)
1727         return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1);
1728       else
1729         return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1);
1730     }
1731   else
1732     return (y1 < y2) ? -1 : 1;
1733 }
1734
1735 static GList *
1736 gtk_container_focus_sort_up_down (GtkContainer     *container,
1737                                   GList            *children,
1738                                   GtkDirectionType  direction,
1739                                   GtkWidget        *old_focus)
1740 {
1741   CompareInfo compare;
1742   GList *tmp_list;
1743   GdkRectangle old_allocation;
1744
1745   compare.container = container;
1746   compare.reverse = (direction == GTK_DIR_UP);
1747
1748   if (!old_focus)
1749       old_focus = find_old_focus (container, children);
1750   
1751   if (old_focus && get_allocation_coords (container, old_focus, &old_allocation))
1752     {
1753       gint compare_x1;
1754       gint compare_x2;
1755       gint compare_y;
1756
1757       /* Delete widgets from list that don't match minimum criteria */
1758
1759       compare_x1 = old_allocation.x;
1760       compare_x2 = old_allocation.x + old_allocation.width;
1761
1762       if (direction == GTK_DIR_UP)
1763         compare_y = old_allocation.y;
1764       else
1765         compare_y = old_allocation.y + old_allocation.height;
1766       
1767       tmp_list = children;
1768       while (tmp_list)
1769         {
1770           GtkWidget *child = tmp_list->data;
1771           GList *next = tmp_list->next;
1772           gint child_x1, child_x2;
1773           GdkRectangle child_allocation;
1774           
1775           if (child != old_focus)
1776             {
1777               if (get_allocation_coords (container, child, &child_allocation))
1778                 {
1779                   child_x1 = child_allocation.x;
1780                   child_x2 = child_allocation.x + child_allocation.width;
1781                   
1782                   if ((child_x2 <= compare_x1 || child_x1 >= compare_x2) /* No horizontal overlap */ ||
1783                       (direction == GTK_DIR_DOWN && child_allocation.y + child_allocation.height < compare_y) || /* Not below */
1784                       (direction == GTK_DIR_UP && child_allocation.y > compare_y)) /* Not above */
1785                     {
1786                       children = g_list_delete_link (children, tmp_list);
1787                     }
1788                 }
1789               else
1790                 children = g_list_delete_link (children, tmp_list);
1791             }
1792           
1793           tmp_list = next;
1794         }
1795
1796       compare.x = (compare_x1 + compare_x2) / 2;
1797       compare.y = old_allocation.y + old_allocation.height / 2;
1798     }
1799   else
1800     {
1801       /* No old focus widget, need to figure out starting x,y some other way
1802        */
1803       GtkWidget *widget = GTK_WIDGET (container);
1804       GdkRectangle old_focus_rect;
1805
1806       if (old_focus_coords (container, &old_focus_rect))
1807         {
1808           compare.x = old_focus_rect.x + old_focus_rect.width / 2;
1809         }
1810       else
1811         {
1812           if (GTK_WIDGET_NO_WINDOW (widget))
1813             compare.x = widget->allocation.x + widget->allocation.width / 2;
1814           else
1815             compare.x = widget->allocation.width / 2;
1816         }
1817       
1818       if (GTK_WIDGET_NO_WINDOW (widget))
1819         compare.y = (direction == GTK_DIR_DOWN) ? widget->allocation.y : widget->allocation.y + widget->allocation.height;
1820       else
1821         compare.y = (direction == GTK_DIR_DOWN) ? 0 : + widget->allocation.height;
1822     }
1823
1824   children = g_list_sort_with_data (children, up_down_compare, &compare);
1825
1826   if (compare.reverse)
1827     children = g_list_reverse (children);
1828
1829   return children;
1830 }
1831
1832 static gint
1833 left_right_compare (gconstpointer a,
1834                     gconstpointer b,
1835                     gpointer      data)
1836 {
1837   GdkRectangle allocation1;
1838   GdkRectangle allocation2;
1839   CompareInfo *compare = data;
1840   gint x1, x2;
1841
1842   if (!get_allocation_coords (compare->container, (GtkWidget *)a, &allocation1))
1843     return 0;
1844   if (!get_allocation_coords (compare->container, (GtkWidget *)b, &allocation2))
1845     return 0;
1846
1847   x1 = allocation1.x + allocation1.width / 2;
1848   x2 = allocation2.x + allocation2.width / 2;
1849
1850   if (x1 == x2)
1851     {
1852       gint y1 = abs (allocation1.y + allocation1.height / 2 - compare->y);
1853       gint y2 = abs (allocation2.y + allocation2.height / 2 - compare->y);
1854
1855       if (compare->reverse)
1856         return (y1 < y2) ? 1 : ((y1 == y2) ? 0 : -1);
1857       else
1858         return (y1 < y2) ? -1 : ((y1 == y2) ? 0 : 1);
1859     }
1860   else
1861     return (x1 < x2) ? -1 : 1;
1862 }
1863
1864 static GList *
1865 gtk_container_focus_sort_left_right (GtkContainer     *container,
1866                                      GList            *children,
1867                                      GtkDirectionType  direction,
1868                                      GtkWidget        *old_focus)
1869 {
1870   CompareInfo compare;
1871   GList *tmp_list;
1872   GdkRectangle old_allocation;
1873
1874   compare.container = container;
1875   compare.reverse = (direction == GTK_DIR_LEFT);
1876
1877   if (!old_focus)
1878     old_focus = find_old_focus (container, children);
1879   
1880   if (old_focus && get_allocation_coords (container, old_focus, &old_allocation))
1881     {
1882       gint compare_y1;
1883       gint compare_y2;
1884       gint compare_x;
1885       
1886       /* Delete widgets from list that don't match minimum criteria */
1887
1888       compare_y1 = old_allocation.y;
1889       compare_y2 = old_allocation.y + old_allocation.height;
1890
1891       if (direction == GTK_DIR_LEFT)
1892         compare_x = old_allocation.x;
1893       else
1894         compare_x = old_allocation.x + old_allocation.width;
1895       
1896       tmp_list = children;
1897       while (tmp_list)
1898         {
1899           GtkWidget *child = tmp_list->data;
1900           GList *next = tmp_list->next;
1901           gint child_y1, child_y2;
1902           GdkRectangle child_allocation;
1903           
1904           if (child != old_focus)
1905             {
1906               if (get_allocation_coords (container, child, &child_allocation))
1907                 {
1908                   child_y1 = child_allocation.y;
1909                   child_y2 = child_allocation.y + child_allocation.height;
1910                   
1911                   if ((child_y2 <= compare_y1 || child_y1 >= compare_y2) /* No vertical overlap */ ||
1912                       (direction == GTK_DIR_RIGHT && child_allocation.x + child_allocation.width < compare_x) || /* Not to left */
1913                       (direction == GTK_DIR_LEFT && child_allocation.x > compare_x)) /* Not to right */
1914                     {
1915                       children = g_list_delete_link (children, tmp_list);
1916                     }
1917                 }
1918               else
1919                 children = g_list_delete_link (children, tmp_list);
1920             }
1921           
1922           tmp_list = next;
1923         }
1924
1925       compare.y = (compare_y1 + compare_y2) / 2;
1926       compare.x = old_allocation.x + old_allocation.width / 2;
1927     }
1928   else
1929     {
1930       /* No old focus widget, need to figure out starting x,y some other way
1931        */
1932       GtkWidget *widget = GTK_WIDGET (container);
1933       GdkRectangle old_focus_rect;
1934
1935       if (old_focus_coords (container, &old_focus_rect))
1936         {
1937           compare.y = old_focus_rect.y + old_focus_rect.height / 2;
1938         }
1939       else
1940         {
1941           if (GTK_WIDGET_NO_WINDOW (widget))
1942             compare.y = widget->allocation.y + widget->allocation.height / 2;
1943           else
1944             compare.y = widget->allocation.height / 2;
1945         }
1946       
1947       if (GTK_WIDGET_NO_WINDOW (widget))
1948         compare.x = (direction == GTK_DIR_RIGHT) ? widget->allocation.x : widget->allocation.x + widget->allocation.width;
1949       else
1950         compare.x = (direction == GTK_DIR_RIGHT) ? 0 : widget->allocation.width;
1951     }
1952
1953   children = g_list_sort_with_data (children, left_right_compare, &compare);
1954
1955   if (compare.reverse)
1956     children = g_list_reverse (children);
1957
1958   return children;
1959 }
1960
1961 /**
1962  * gtk_container_focus_sort:
1963  * @container: a #GtkContainer
1964  * @children:  a list of descendents of @container (they don't
1965  *             have to be direct children.
1966  * @direction: focus direction
1967  * @old_focus: widget to use for the starting position, or %NULL
1968  *             to determine this automatically.
1969  *             [ Note, this argument isn't used for GTK_DIR_TAB_*,
1970  *               which is the only @direction we use currently,
1971  *               so perhaps this argument should be removed ]
1972  * 
1973  * Sorts @children in the correct order for focusing with
1974  * direction type @direction.
1975  * 
1976  * Return value: a copy of @children, sorted in correct focusing order,
1977  *   with children that aren't suitable for focusing in this direction
1978  *   removed.
1979  **/
1980 GList *
1981 _gtk_container_focus_sort (GtkContainer     *container,
1982                            GList            *children,
1983                            GtkDirectionType  direction,
1984                            GtkWidget        *old_focus)
1985 {
1986   children = g_list_copy (children);
1987   
1988   switch (direction)
1989     {
1990     case GTK_DIR_TAB_FORWARD:
1991     case GTK_DIR_TAB_BACKWARD:
1992       return gtk_container_focus_sort_tab (container, children, direction, old_focus);
1993     case GTK_DIR_UP:
1994     case GTK_DIR_DOWN:
1995       return gtk_container_focus_sort_up_down (container, children, direction, old_focus);
1996     case GTK_DIR_LEFT:
1997     case GTK_DIR_RIGHT:
1998       return gtk_container_focus_sort_left_right (container, children, direction, old_focus);
1999     }
2000
2001   g_assert_not_reached ();
2002
2003   return NULL;
2004 }
2005
2006 static gboolean
2007 gtk_container_focus_move (GtkContainer     *container,
2008                           GList            *children,
2009                           GtkDirectionType  direction)
2010 {
2011   GtkWidget *focus_child;
2012   GtkWidget *child;
2013
2014   focus_child = container->focus_child;
2015
2016   while (children)
2017     {
2018       child = children->data;
2019       children = children->next;
2020
2021       if (!child)
2022         continue;
2023       
2024       if (focus_child)
2025         {
2026           if (focus_child == child)
2027             {
2028               focus_child = NULL;
2029
2030                 if (gtk_widget_child_focus (child, direction))
2031                   return TRUE;
2032             }
2033         }
2034       else if (GTK_WIDGET_DRAWABLE (child) &&
2035                gtk_widget_is_ancestor (child, GTK_WIDGET (container)))
2036         {
2037           if (gtk_widget_child_focus (child, direction))
2038             return TRUE;
2039         }
2040     }
2041
2042   return FALSE;
2043 }
2044
2045
2046 static void
2047 gtk_container_children_callback (GtkWidget *widget,
2048                                  gpointer   client_data)
2049 {
2050   GList **children;
2051
2052   children = (GList**) client_data;
2053   *children = g_list_prepend (*children, widget);
2054 }
2055
2056 static void
2057 chain_widget_destroyed (GtkWidget *widget,
2058                         gpointer   user_data)
2059 {
2060   GtkContainer *container;
2061   GList *chain;
2062   
2063   container = GTK_CONTAINER (user_data);
2064
2065   chain = g_object_get_data (G_OBJECT (container),
2066                              "gtk-container-focus-chain");
2067
2068   chain = g_list_remove (chain, widget);
2069
2070   g_signal_handlers_disconnect_by_func (widget,
2071                                         chain_widget_destroyed,
2072                                         user_data);
2073   
2074   g_object_set_data (G_OBJECT (container),
2075                      "gtk-container-focus-chain",
2076                      chain);  
2077 }
2078
2079 /**
2080  * gtk_container_set_focus_chain: 
2081  * @container: a #GtkContainer.
2082  * @focusable_widgets: the new focus chain.
2083  *
2084  * Sets a focus chain, overriding the one computed automatically by GTK+.
2085  * 
2086  * In principle each widget in the chain should be a descendant of the 
2087  * container, but this is not enforced by this method, since it's allowed 
2088  * to set the focus chain before you pack the widgets, or have a widget 
2089  * in the chain that isn't always packed. The necessary checks are done 
2090  * when the focus chain is actually traversed.
2091  **/
2092 void
2093 gtk_container_set_focus_chain (GtkContainer *container,
2094                                GList        *focusable_widgets)
2095 {
2096   GList *chain;
2097   GList *tmp_list;
2098   
2099   g_return_if_fail (GTK_IS_CONTAINER (container));
2100   
2101   if (container->has_focus_chain)
2102     gtk_container_unset_focus_chain (container);
2103
2104   container->has_focus_chain = TRUE;
2105   
2106   chain = NULL;
2107   tmp_list = focusable_widgets;
2108   while (tmp_list != NULL)
2109     {
2110       g_return_if_fail (GTK_IS_WIDGET (tmp_list->data));
2111       
2112       /* In principle each widget in the chain should be a descendant
2113        * of the container, but we don't want to check that here, it's
2114        * expensive and also it's allowed to set the focus chain before
2115        * you pack the widgets, or have a widget in the chain that isn't
2116        * always packed. So we check for ancestor during actual traversal.
2117        */
2118
2119       chain = g_list_prepend (chain, tmp_list->data);
2120
2121       g_signal_connect (tmp_list->data,
2122                         "destroy",
2123                         G_CALLBACK (chain_widget_destroyed),
2124                         container);
2125       
2126       tmp_list = g_list_next (tmp_list);
2127     }
2128
2129   chain = g_list_reverse (chain);
2130   
2131   g_object_set_data (G_OBJECT (container),
2132                      "gtk-container-focus-chain",
2133                      chain);
2134 }
2135
2136 /**
2137  * gtk_container_get_focus_chain:
2138  * @container:         a #GtkContainer
2139  * @focusable_widgets: location to store the focus chain of the
2140  *                     container, or %NULL. You should free this list
2141  *                     using g_list_free() when you are done with it, however
2142  *                     no additional reference count is added to the
2143  *                     individual widgets in the focus chain.
2144  * 
2145  * Retrieves the focus chain of the container, if one has been
2146  * set explicitly. If no focus chain has been explicitly
2147  * set, GTK+ computes the focus chain based on the positions
2148  * of the children. In that case, GTK+ stores %NULL in
2149  * @focusable_widgets and returns %FALSE.
2150  *
2151  * Return value: %TRUE if the focus chain of the container 
2152  * has been set explicitly.
2153  **/
2154 gboolean
2155 gtk_container_get_focus_chain (GtkContainer *container,
2156                                GList       **focus_chain)
2157 {
2158   g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
2159
2160   if (focus_chain)
2161     {
2162       if (container->has_focus_chain)
2163         *focus_chain = g_list_copy (get_focus_chain (container));
2164       else
2165         *focus_chain = NULL;
2166     }
2167
2168   return container->has_focus_chain;
2169 }
2170
2171 /**
2172  * gtk_container_unset_focus_chain:
2173  * @container: a #GtkContainer.
2174  * 
2175  * Removes a focus chain explicitly set with gtk_container_set_focus_chain().
2176  **/
2177 void
2178 gtk_container_unset_focus_chain (GtkContainer  *container)
2179 {  
2180   g_return_if_fail (GTK_IS_CONTAINER (container));
2181
2182   if (container->has_focus_chain)
2183     {
2184       GList *chain;
2185       GList *tmp_list;
2186       
2187       chain = get_focus_chain (container);
2188       
2189       container->has_focus_chain = FALSE;
2190       
2191       g_object_set_data (G_OBJECT (container), "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 }