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