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