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