]> Pileus Git - ~andy/gtk/blob - gtk/gtkcontainer.c
Remove reallocate-redraws property. This is something that only a widget
[~andy/gtk] / gtk / gtkcontainer.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <stdarg.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #include "gtkcontainer.h"
32 #include "gtkprivate.h"
33 #include "gtksignal.h"
34 #include "gtkmain.h"
35 #include "gtkwindow.h"
36 #include "gtkintl.h"
37
38 enum {
39   ADD,
40   REMOVE,
41   CHECK_RESIZE,
42   FOCUS,
43   SET_FOCUS_CHILD,
44   LAST_SIGNAL
45 };
46
47 enum {
48   PROP_0,
49   PROP_BORDER_WIDTH,
50   PROP_RESIZE_MODE,
51   PROP_CHILD,
52 };
53
54 typedef struct _GtkChildArgInfo GtkChildArgInfo;
55 struct _GtkChildArgInfo
56 {
57   gchar *name;
58   GtkType type;
59   GtkType class_type;
60   guint arg_flags;
61   guint arg_id;
62   guint seq_id;
63 };
64
65 static void     gtk_container_base_class_init      (GtkContainerClass *klass);
66 static void     gtk_container_class_init           (GtkContainerClass *klass);
67 static void     gtk_container_init                 (GtkContainer      *container);
68 static void     gtk_container_destroy              (GtkObject         *object);
69 static void     gtk_container_set_property         (GObject         *object,
70                                                     guint            prop_id,
71                                                     const GValue    *value,
72                                                     GParamSpec      *pspec);
73 static void     gtk_container_get_property         (GObject         *object,
74                                                     guint            prop_id,
75                                                     GValue          *value,
76                                                     GParamSpec      *pspec);
77 static void     gtk_container_add_unimplemented    (GtkContainer      *container,
78                                                     GtkWidget         *widget);
79 static void     gtk_container_remove_unimplemented (GtkContainer      *container,
80                                                     GtkWidget         *widget);
81 static void     gtk_container_real_check_resize    (GtkContainer      *container);
82 static gboolean gtk_container_real_focus           (GtkContainer      *container,
83                                                     GtkDirectionType   direction);
84 static void     gtk_container_real_set_focus_child (GtkContainer      *container,
85                                                     GtkWidget         *widget);
86 static gboolean gtk_container_focus_tab            (GtkContainer      *container,
87                                                     GList             *children,
88                                                     GtkDirectionType   direction);
89 static gboolean gtk_container_focus_up_down        (GtkContainer      *container,
90                                                     GList            **children,
91                                                     GtkDirectionType   direction);
92 static gboolean gtk_container_focus_left_right     (GtkContainer      *container,
93                                                     GList            **children,
94                                                     GtkDirectionType   direction);
95 static gboolean gtk_container_focus_move           (GtkContainer      *container,
96                                                     GList             *children,
97                                                     GtkDirectionType   direction);
98 static void     gtk_container_children_callback    (GtkWidget         *widget,
99                                                     gpointer           client_data);
100 static void     gtk_container_show_all             (GtkWidget         *widget);
101 static void     gtk_container_hide_all             (GtkWidget         *widget);
102 static gint     gtk_container_expose               (GtkWidget         *widget,
103                                                     GdkEventExpose    *event);
104
105
106 static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
107                                                           GtkWidget    *child);
108
109
110
111 static guint container_signals[LAST_SIGNAL] = { 0 };
112 static GHashTable *container_child_arg_info_ht = NULL;
113
114 static GtkWidgetClass *parent_class = NULL;
115
116 static const gchar *vadjustment_key = "gtk-vadjustment";
117 static guint        vadjustment_key_id = 0;
118 static const gchar *hadjustment_key = "gtk-hadjustment";
119 static guint        hadjustment_key_id = 0;
120 static GSList      *container_resize_queue = NULL;
121
122 GtkType
123 gtk_container_get_type (void)
124 {
125   static GtkType container_type = 0;
126
127   if (!container_type)
128     {
129       static const GtkTypeInfo container_info =
130       {
131         "GtkContainer",
132         sizeof (GtkContainer),
133         sizeof (GtkContainerClass),
134         (GtkClassInitFunc) gtk_container_class_init,
135         (GtkObjectInitFunc) gtk_container_init,
136         /* reserved_1 */ NULL,
137         /* reserved_2 */ NULL,
138         (GtkClassInitFunc) gtk_container_base_class_init,
139       };
140
141       container_type = gtk_type_unique (gtk_widget_get_type (), &container_info);
142     }
143
144   return container_type;
145 }
146
147 static void
148 gtk_container_base_class_init (GtkContainerClass *class)
149 {
150   /* reset instance specifc class fields that don't get inherited */
151   class->n_child_args = 0;
152   class->set_child_arg = NULL;
153   class->get_child_arg = NULL;
154 }
155
156 static void
157 gtk_container_class_init (GtkContainerClass *class)
158 {
159   GObjectClass *gobject_class;
160   GtkObjectClass *object_class;
161   GtkWidgetClass *widget_class;
162
163   gobject_class = G_OBJECT_CLASS (class);
164   object_class = (GtkObjectClass*) class;
165   widget_class = (GtkWidgetClass*) class;
166
167   parent_class = gtk_type_class (gtk_widget_get_type ());
168
169   container_child_arg_info_ht = g_hash_table_new (gtk_arg_info_hash,
170                                                   gtk_arg_info_equal);
171
172   vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
173   hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
174   
175   gobject_class->set_property = gtk_container_set_property;
176   gobject_class->get_property = gtk_container_get_property;
177
178   g_object_class_install_property (gobject_class,
179                                    PROP_RESIZE_MODE,
180                                    g_param_spec_enum ("resize_mode",
181                                                       _("Resize mode"),
182                                                       _("Specify how resize events are handled"),
183                                                       GTK_TYPE_RESIZE_MODE,
184                                                       GTK_RESIZE_PARENT,
185                                                       G_PARAM_READWRITE));
186   g_object_class_install_property (gobject_class,
187                                    PROP_BORDER_WIDTH,
188                                    g_param_spec_uint ("border_width",
189                                                       _("Border width"),
190                                                       _("The width of the empty border outside the containers children."),
191                                                       0,
192                                                       G_MAXINT,
193                                                       0,
194                                                       G_PARAM_READWRITE));
195   g_object_class_install_property (gobject_class,
196                                    PROP_CHILD,
197                                    g_param_spec_object ("child",
198                                                       _("Child"),
199                                                       _("Can be used to add a new child to the container."),
200                                                       GTK_TYPE_WIDGET,
201                                                       G_PARAM_WRITABLE));
202
203   object_class->destroy = gtk_container_destroy;
204
205   widget_class->show_all = gtk_container_show_all;
206   widget_class->hide_all = gtk_container_hide_all;
207   widget_class->expose_event = gtk_container_expose;
208   
209   class->add = gtk_container_add_unimplemented;
210   class->remove = gtk_container_remove_unimplemented;
211   class->check_resize = gtk_container_real_check_resize;
212   class->forall = NULL;
213   class->focus = gtk_container_real_focus;
214   class->set_focus_child = gtk_container_real_set_focus_child;
215   class->child_type = NULL;
216   class->composite_name = gtk_container_child_default_composite_name;
217
218   container_signals[ADD] =
219     gtk_signal_new ("add",
220                     GTK_RUN_FIRST,
221                     GTK_CLASS_TYPE (object_class),
222                     GTK_SIGNAL_OFFSET (GtkContainerClass, add),
223                     gtk_marshal_VOID__OBJECT,
224                     GTK_TYPE_NONE, 1,
225                     GTK_TYPE_WIDGET);
226   container_signals[REMOVE] =
227     gtk_signal_new ("remove",
228                     GTK_RUN_FIRST,
229                     GTK_CLASS_TYPE (object_class),
230                     GTK_SIGNAL_OFFSET (GtkContainerClass, remove),
231                     gtk_marshal_VOID__OBJECT,
232                     GTK_TYPE_NONE, 1,
233                     GTK_TYPE_WIDGET);
234   container_signals[CHECK_RESIZE] =
235     gtk_signal_new ("check_resize",
236                     GTK_RUN_LAST,
237                     GTK_CLASS_TYPE (object_class),
238                     GTK_SIGNAL_OFFSET (GtkContainerClass, check_resize),
239                     gtk_marshal_VOID__VOID,
240                     GTK_TYPE_NONE, 0);
241   container_signals[FOCUS] =
242     gtk_signal_new ("focus",
243                     GTK_RUN_LAST,
244                     GTK_CLASS_TYPE (object_class),
245                     GTK_SIGNAL_OFFSET (GtkContainerClass, focus),
246                     gtk_marshal_ENUM__ENUM,
247                     GTK_TYPE_DIRECTION_TYPE, 1,
248                     GTK_TYPE_DIRECTION_TYPE);
249   container_signals[SET_FOCUS_CHILD] =
250     gtk_signal_new ("set-focus-child",
251                     GTK_RUN_FIRST,
252                     GTK_CLASS_TYPE (object_class),
253                     GTK_SIGNAL_OFFSET (GtkContainerClass, set_focus_child),
254                     gtk_marshal_VOID__OBJECT,
255                     GTK_TYPE_NONE, 1,
256                     GTK_TYPE_WIDGET);
257 }
258
259 GtkType
260 gtk_container_child_type (GtkContainer      *container)
261 {
262   GtkType slot;
263   GtkContainerClass *class;
264
265   g_return_val_if_fail (container != NULL, 0);
266   g_return_val_if_fail (GTK_IS_CONTAINER (container), 0);
267
268   class = GTK_CONTAINER_GET_CLASS (container);
269   if (class->child_type)
270     slot = class->child_type (container);
271   else
272     slot = GTK_TYPE_NONE;
273
274   return slot;
275 }
276
277 /****************************************************
278  * GtkContainer child argument mechanism
279  *
280  ****************************************************/
281
282 void
283 gtk_container_add_with_args (GtkContainer      *container,
284                              GtkWidget         *widget,
285                              const gchar       *first_arg_name,
286                              ...)
287 {
288   g_return_if_fail (container != NULL);
289   g_return_if_fail (GTK_IS_CONTAINER (container));
290   g_return_if_fail (widget != NULL);
291   g_return_if_fail (GTK_IS_WIDGET (widget));
292   g_return_if_fail (widget->parent == NULL);
293
294   gtk_widget_ref (GTK_WIDGET (container));
295   gtk_widget_ref (widget);
296
297   gtk_signal_emit (GTK_OBJECT (container), container_signals[ADD], widget);
298   
299   if (widget->parent)
300     {
301       va_list var_args;
302       GSList *arg_list = NULL;
303       GSList *info_list = NULL;
304       gchar *error;
305       
306       va_start (var_args, first_arg_name);
307       error = gtk_container_child_args_collect (GTK_OBJECT_TYPE (container),
308                                                 &arg_list,
309                                                 &info_list,
310                                                 first_arg_name,
311                                                 var_args);
312       va_end (var_args);
313
314       if (error)
315         {
316           g_warning ("gtk_container_add_with_args(): %s", error);
317           g_free (error);
318         }
319       else
320         {
321           GSList *slist_arg;
322           GSList *slist_info;
323
324           slist_arg = arg_list;
325           slist_info = info_list;
326           while (slist_arg)
327             {
328               gtk_container_arg_set (container, widget, slist_arg->data, slist_info->data);
329               slist_arg = slist_arg->next;
330               slist_info = slist_info->next;
331             }
332           gtk_args_collect_cleanup (arg_list, info_list);
333         }
334     }
335
336   gtk_widget_unref (widget);
337   gtk_widget_unref (GTK_WIDGET (container));
338 }
339
340 void
341 gtk_container_addv (GtkContainer      *container,
342                     GtkWidget         *widget,
343                     guint              n_args,
344                     GtkArg            *args)
345 {
346   g_return_if_fail (container != NULL);
347   g_return_if_fail (GTK_IS_CONTAINER (container));
348   g_return_if_fail (widget != NULL);
349   g_return_if_fail (GTK_IS_WIDGET (widget));
350   g_return_if_fail (widget->parent == NULL);
351
352   gtk_widget_ref (GTK_WIDGET (container));
353   gtk_widget_ref (widget);
354
355   gtk_signal_emit (GTK_OBJECT (container), container_signals[ADD], widget);
356   
357   if (widget->parent)
358     {
359       GtkArg *max_args;
360
361       for (max_args = args + n_args; args < max_args; args++)
362         gtk_container_arg_set (container, widget, args, NULL);
363     }
364
365   gtk_widget_unref (widget);
366   gtk_widget_unref (GTK_WIDGET (container));
367 }
368
369 void
370 gtk_container_child_setv (GtkContainer      *container,
371                           GtkWidget         *child,
372                           guint              n_args,
373                           GtkArg            *args)
374 {
375   GtkArg *max_args;
376
377   g_return_if_fail (container != NULL);
378   g_return_if_fail (GTK_IS_CONTAINER (container));
379   g_return_if_fail (child != NULL);
380   g_return_if_fail (GTK_IS_WIDGET (child));
381   g_return_if_fail (child->parent != NULL);
382   if (n_args)
383     g_return_if_fail (args != NULL);
384
385   for (max_args = args + n_args; args < max_args; args++)
386     gtk_container_arg_set (container, child, args, NULL);
387 }
388
389 void
390 gtk_container_child_getv (GtkContainer      *container,
391                           GtkWidget         *child,
392                           guint              n_args,
393                           GtkArg            *args)
394 {
395   GtkArg *max_args;
396
397   g_return_if_fail (container != NULL);
398   g_return_if_fail (GTK_IS_CONTAINER (container));
399   g_return_if_fail (child != NULL);
400   g_return_if_fail (GTK_IS_WIDGET (child));
401   g_return_if_fail (child->parent != NULL);
402   if (n_args)
403     g_return_if_fail (args != NULL);
404
405   for (max_args = args + n_args; args < max_args; args++)
406     gtk_container_arg_get (container, child, args, NULL);
407 }
408
409 void
410 gtk_container_child_set (GtkContainer      *container,
411                          GtkWidget         *child,
412                          const gchar       *first_arg_name,
413                          ...)
414 {
415   va_list var_args;
416   GSList *arg_list = NULL;
417   GSList *info_list = NULL;
418   gchar *error;
419   
420   g_return_if_fail (container != NULL);
421   g_return_if_fail (GTK_IS_CONTAINER (container));
422   g_return_if_fail (child != NULL);
423   g_return_if_fail (GTK_IS_WIDGET (child));
424   g_return_if_fail (child->parent != NULL);
425
426   va_start (var_args, first_arg_name);
427   error = gtk_container_child_args_collect (GTK_OBJECT_TYPE (container),
428                                             &arg_list,
429                                             &info_list,
430                                             first_arg_name,
431                                             var_args);
432   va_end (var_args);
433
434   if (error)
435     {
436       g_warning ("gtk_container_child_set(): %s", error);
437       g_free (error);
438     }
439   else
440     {
441       GSList *slist_arg;
442       GSList *slist_info;
443
444       slist_arg = arg_list;
445       slist_info = info_list;
446       while (slist_arg)
447         {
448           gtk_container_arg_set (container, child, slist_arg->data, slist_info->data);
449           slist_arg = slist_arg->next;
450           slist_info = slist_info->next;
451         }
452       gtk_args_collect_cleanup (arg_list, info_list);
453     }
454 }
455
456 void
457 gtk_container_arg_set (GtkContainer *container,
458                        GtkWidget    *child,
459                        GtkArg       *arg,
460                        GtkArgInfo   *info)
461 {
462   GtkContainerClass *class;
463   
464   g_return_if_fail (container != NULL);
465   g_return_if_fail (GTK_IS_CONTAINER (container));
466   g_return_if_fail (child != NULL);
467   g_return_if_fail (GTK_IS_WIDGET (child));
468   g_return_if_fail (arg != NULL);
469   
470   if (!info)
471     {
472       gchar *error;
473       
474       error = gtk_arg_get_info (GTK_OBJECT_TYPE (container),
475                                 container_child_arg_info_ht,
476                                 arg->name,
477                                 &info);
478       if (error)
479         {
480           g_warning ("gtk_container_arg_set(): %s", error);
481           g_free (error);
482           return;
483         }
484     }
485   g_return_if_fail (info->arg_flags & GTK_ARG_CHILD_ARG);
486   
487   if (! (info->arg_flags & GTK_ARG_WRITABLE))
488     {
489       g_warning ("gtk_container_arg_set(): argument \"%s\" is not writable",
490                  info->full_name);
491       return;
492     }
493   if (info->type != arg->type)
494     {
495       g_warning ("gtk_container_arg_set(): argument \"%s\" has invalid type `%s'",
496                  info->full_name,
497                  gtk_type_name (arg->type));
498       return;
499     }
500   
501   class = gtk_type_class (info->class_type);
502   g_assert (class->set_child_arg != NULL);
503   class->set_child_arg (container, child, arg, info->arg_id);
504 }
505
506 void
507 gtk_container_arg_get (GtkContainer *container,
508                        GtkWidget    *child,
509                        GtkArg       *arg,
510                        GtkArgInfo   *info)
511 {
512   GtkContainerClass *class;
513   
514   g_return_if_fail (container != NULL);
515   g_return_if_fail (GTK_IS_CONTAINER (container));
516   g_return_if_fail (child != NULL);
517   g_return_if_fail (GTK_IS_WIDGET (child));
518   g_return_if_fail (arg != NULL);
519   
520   if (!info)
521     {
522       gchar *error;
523       
524       error = gtk_arg_get_info (GTK_OBJECT_TYPE (container),
525                                 container_child_arg_info_ht,
526                                 arg->name,
527                                 &info);
528       if (error)
529         {
530           g_warning ("gtk_container_arg_get(): %s", error);
531           g_free (error);
532           arg->type = GTK_TYPE_INVALID;
533           return;
534         }
535     }
536   g_return_if_fail (info->arg_flags & GTK_ARG_CHILD_ARG);
537   
538   if (! (info->arg_flags & GTK_ARG_READABLE))
539     {
540       g_warning ("gtk_container_arg_get(): argument \"%s\" is not readable",
541                  info->full_name);
542       arg->type = GTK_TYPE_INVALID;
543       return;
544     }
545   
546   class = gtk_type_class (info->class_type);
547   g_assert (class->get_child_arg != NULL);
548   arg->type = info->type;
549   class->get_child_arg (container, child, arg, info->arg_id);
550 }
551
552 void
553 gtk_container_add_child_arg_type (const gchar       *arg_name,
554                                   GtkType            arg_type,
555                                   guint              arg_flags,
556                                   guint              arg_id)
557 {
558   g_return_if_fail (arg_name != NULL);
559   g_return_if_fail (arg_type > GTK_TYPE_NONE);
560   g_return_if_fail (arg_id > 0);
561   g_return_if_fail ((arg_flags & GTK_ARG_READWRITE) == GTK_ARG_READWRITE);
562   /* g_return_if_fail ((arg_flags & GTK_ARG_CHILD_ARG) != 0); */
563
564   arg_flags |= GTK_ARG_CHILD_ARG;
565   arg_flags &= GTK_ARG_MASK;
566
567   gtk_arg_type_new_static (GTK_TYPE_CONTAINER,
568                            arg_name,
569                            GTK_STRUCT_OFFSET (GtkContainerClass, n_child_args),
570                            container_child_arg_info_ht,
571                            arg_type,
572                            arg_flags,
573                            arg_id);
574 }
575
576 gchar*
577 gtk_container_child_args_collect (GtkType       object_type,
578                                   GSList      **arg_list_p,
579                                   GSList      **info_list_p,
580                                   const gchar  *first_arg_name,
581                                   va_list       var_args)
582 {
583   return gtk_args_collect (object_type,
584                            container_child_arg_info_ht,
585                            arg_list_p,
586                            info_list_p,
587                            first_arg_name,
588                            var_args);
589 }
590
591 gchar*
592 gtk_container_child_arg_get_info (GtkType       object_type,
593                                   const gchar  *arg_name,
594                                   GtkArgInfo  **info_p)
595 {
596   return gtk_arg_get_info (object_type,
597                            container_child_arg_info_ht,
598                            arg_name,
599                            info_p);
600 }
601
602 GtkArg*
603 gtk_container_query_child_args (GtkType            class_type,
604                                 guint32          **arg_flags,
605                                 guint             *n_args)
606 {
607   g_return_val_if_fail (n_args != NULL, NULL);
608   *n_args = 0;
609   g_return_val_if_fail (gtk_type_is_a (class_type, GTK_TYPE_CONTAINER), NULL);
610
611   return gtk_args_query (class_type, container_child_arg_info_ht, arg_flags, n_args);
612 }
613
614
615 static void
616 gtk_container_add_unimplemented (GtkContainer     *container,
617                                  GtkWidget        *widget)
618 {
619   g_warning ("GtkContainerClass::add not implemented for `%s'", gtk_type_name (GTK_OBJECT_TYPE (container)));
620 }
621
622 static void
623 gtk_container_remove_unimplemented (GtkContainer     *container,
624                                     GtkWidget        *widget)
625 {
626   g_warning ("GtkContainerClass::remove not implemented for `%s'", gtk_type_name (GTK_OBJECT_TYPE (container)));
627 }
628
629 static void
630 gtk_container_init (GtkContainer *container)
631 {
632   container->focus_child = NULL;
633   container->border_width = 0;
634   container->need_resize = FALSE;
635   container->resize_mode = GTK_RESIZE_PARENT;
636   container->reallocate_redraws = FALSE;
637   container->resize_widgets = NULL;
638 }
639
640 static void
641 gtk_container_destroy (GtkObject *object)
642 {
643   GtkContainer *container;
644
645   g_return_if_fail (object != NULL);
646   g_return_if_fail (GTK_IS_CONTAINER (object));
647
648   container = GTK_CONTAINER (object);
649   
650   if (GTK_CONTAINER_RESIZE_PENDING (container))
651     gtk_container_dequeue_resize_handler (container);
652   if (container->resize_widgets)
653     gtk_container_clear_resize_widgets (container);
654
655   /* do this before walking child widgets, to avoid
656    * removing children from focus chain one by one.
657    */
658   if (container->has_focus_chain)
659     gtk_container_unset_focus_chain (container);
660   
661   gtk_container_foreach (container, (GtkCallback) gtk_widget_destroy, NULL);
662   
663   if (GTK_OBJECT_CLASS (parent_class)->destroy)
664     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
665 }
666
667 static void
668 gtk_container_set_property (GObject         *object,
669                             guint            prop_id,
670                             const GValue    *value,
671                             GParamSpec      *pspec)
672 {
673   GtkContainer *container;
674
675   container = GTK_CONTAINER (object);
676
677   switch (prop_id)
678     {
679     case PROP_BORDER_WIDTH:
680       gtk_container_set_border_width (container, g_value_get_uint (value));
681       break;
682     case PROP_RESIZE_MODE:
683       gtk_container_set_resize_mode (container, g_value_get_enum (value));
684       break;
685     case PROP_CHILD:
686       gtk_container_add (container, GTK_WIDGET (g_value_get_object (value)));
687       break;
688     default:
689       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
690       break;
691     }
692 }
693
694 static void
695 gtk_container_get_property (GObject         *object,
696                             guint            prop_id,
697                             GValue          *value,
698                             GParamSpec      *pspec)
699 {
700   GtkContainer *container;
701
702   container = GTK_CONTAINER (object);
703   
704   switch (prop_id)
705     {
706     case PROP_BORDER_WIDTH:
707       g_value_set_uint (value, container->border_width);
708       break;
709     case PROP_RESIZE_MODE:
710       g_value_set_enum (value, container->resize_mode);
711       break;
712     default:
713       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
714       break;
715     }
716 }
717
718 /**
719  * gtk_container_set_border_width:
720  * @container: a #GtkContainer
721  * @border_width: amount of blank space to leave <emphasis>outside</emphasis> the container
722  *
723  * The border width of a container is the amount of space to leave
724  * around the outside of the container. The only exception to this is
725  * #GtkWindow; because toplevel windows can't leave space outside,
726  * they leave the space inside. The border is added on all sides of
727  * the container. To add space to only one side, one approach is to
728  * create a #GtkAlignment widget, call gtk_widget_set_usize() to give
729  * it a size, and place it on the side of the container as a spacer.
730  * 
731  **/
732 void
733 gtk_container_set_border_width (GtkContainer *container,
734                                 guint         border_width)
735 {
736   g_return_if_fail (container != NULL);
737   g_return_if_fail (GTK_IS_CONTAINER (container));
738
739   if (container->border_width != border_width)
740     {
741       container->border_width = border_width;
742       g_object_notify (G_OBJECT (container), "border_width");
743       
744       if (GTK_WIDGET_REALIZED (container))
745         gtk_widget_queue_resize (GTK_WIDGET (container));
746     }
747 }
748
749 /**
750  * gtk_container_add:
751  * @container: a #GtkContainer
752  * @widget: a widget to be placed inside @container
753  * 
754  * Adds @widget to @container. Typically used for simple containers
755  * such as #GtkWindow, #GtkFrame, or #GtkButton; for more complicated
756  * layout containers such as #GtkBox or #GtkTable, this function will
757  * pick default packing parameters that may not be correct.  So
758  * consider functions such as gtk_box_pack_start() and
759  * gtk_table_attach() as an alternative to gtk_container_add() in
760  * those cases. A widget may be added to only one container at a time;
761  * you can't place the same widget inside two different containers.
762  **/
763 void
764 gtk_container_add (GtkContainer *container,
765                    GtkWidget    *widget)
766 {
767   g_return_if_fail (container != NULL);
768   g_return_if_fail (GTK_IS_CONTAINER (container));
769   g_return_if_fail (widget != NULL);
770   g_return_if_fail (GTK_IS_WIDGET (widget));
771
772   if (widget->parent != NULL)
773     {
774       g_warning ("Attempting to add a widget with type %s to a container of "
775                  "type %s, but the widget is already inside a container of type %s",
776                  g_type_name (G_OBJECT_TYPE (widget)),
777                  g_type_name (G_OBJECT_TYPE (container)),
778                  g_type_name (G_OBJECT_TYPE (widget->parent)));
779       return;
780     }
781
782   gtk_signal_emit (GTK_OBJECT (container), container_signals[ADD], widget);
783 }
784
785 /**
786  * gtk_container_remove:
787  * @container: a #GtkContainer
788  * @widget: a current child of @container
789  * 
790  * Removes @widget from @container. @widget must be inside @container.
791  * Note that @container will own a reference to @widget, and that this
792  * may be the last reference held; so removing a widget from its
793  * container can destroy that widget. If you want to use @widget
794  * again, you need to add a reference to it while it's not inside
795  * a container, using g_object_ref().
796  **/
797 void
798 gtk_container_remove (GtkContainer *container,
799                       GtkWidget    *widget)
800 {
801   g_return_if_fail (container != NULL);
802   g_return_if_fail (GTK_IS_CONTAINER (container));
803   g_return_if_fail (widget != NULL);
804   g_return_if_fail (GTK_IS_WIDGET (widget));
805   g_return_if_fail (widget->parent == GTK_WIDGET (container));
806   
807   gtk_signal_emit (GTK_OBJECT (container), container_signals[REMOVE], widget);
808 }
809
810 void
811 gtk_container_dequeue_resize_handler (GtkContainer *container)
812 {
813   g_return_if_fail (GTK_IS_CONTAINER (container));
814   g_return_if_fail (GTK_CONTAINER_RESIZE_PENDING (container));
815
816   container_resize_queue = g_slist_remove (container_resize_queue, container);
817   GTK_PRIVATE_UNSET_FLAG (container, GTK_RESIZE_PENDING);
818 }
819
820 void
821 gtk_container_clear_resize_widgets (GtkContainer *container)
822 {
823   GSList *node;
824
825   g_return_if_fail (container != NULL);
826   g_return_if_fail (GTK_IS_CONTAINER (container));
827
828   node = container->resize_widgets;
829
830   while (node)
831     {
832       GtkWidget *widget = node->data;
833
834       GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
835       node = node->next;
836     }
837   
838   g_slist_free (container->resize_widgets);
839   container->resize_widgets = NULL;
840 }
841
842 void
843 gtk_container_set_resize_mode (GtkContainer  *container,
844                                GtkResizeMode  resize_mode)
845 {
846   g_return_if_fail (container != NULL);
847   g_return_if_fail (GTK_IS_CONTAINER (container));
848   g_return_if_fail (resize_mode <= GTK_RESIZE_IMMEDIATE);
849   
850   if (GTK_WIDGET_TOPLEVEL (container) &&
851       resize_mode == GTK_RESIZE_PARENT)
852     {
853       resize_mode = GTK_RESIZE_QUEUE;
854       g_object_notify (G_OBJECT (container), "resize_mode");
855     }
856   
857   if (container->resize_mode != resize_mode)
858     {
859       container->resize_mode = resize_mode;
860       
861       if (resize_mode == GTK_RESIZE_IMMEDIATE)
862         gtk_container_check_resize (container);
863       else
864         {
865           gtk_container_clear_resize_widgets (container);
866           gtk_widget_queue_resize (GTK_WIDGET (container));
867         }
868        g_object_notify (G_OBJECT (container), "resize_mode");
869     }
870 }
871
872 void
873 gtk_container_set_reallocate_redraws (GtkContainer *container,
874                                       gboolean      needs_redraws)
875 {
876   g_return_if_fail (GTK_IS_CONTAINER (container));
877
878   container->reallocate_redraws = needs_redraws ? TRUE : FALSE;
879 }
880
881 static GtkContainer*
882 gtk_container_get_resize_container (GtkContainer *container)
883 {
884   GtkWidget *widget;
885
886   widget = GTK_WIDGET (container);
887
888   while (widget->parent)
889     {
890       widget = widget->parent;
891       if (GTK_IS_RESIZE_CONTAINER (widget) && !GTK_WIDGET_RESIZE_NEEDED (widget))
892         break;
893     }
894
895   return GTK_IS_RESIZE_CONTAINER (widget) ? (GtkContainer*) widget : NULL;
896 }
897
898 static gboolean
899 gtk_container_idle_sizer (gpointer data)
900 {
901   GDK_THREADS_ENTER ();
902
903   /* we may be invoked with a container_resize_queue of NULL, because
904    * queue_resize could have been adding an extra idle function while
905    * the queue still got processed. we better just ignore such case
906    * than trying to explicitely work around them with some extra flags,
907    * since it doesn't cause any actual harm.
908    */
909   while (container_resize_queue)
910     {
911       GSList *slist;
912       GtkWidget *widget;
913
914       slist = container_resize_queue;
915       container_resize_queue = slist->next;
916       widget = slist->data;
917       g_slist_free_1 (slist);
918
919       GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_PENDING);
920       gtk_container_check_resize (GTK_CONTAINER (widget));
921     }
922
923   gdk_window_process_all_updates ();
924
925   GDK_THREADS_LEAVE ();
926
927   return FALSE;
928 }
929
930 void
931 gtk_container_queue_resize (GtkContainer *container)
932 {
933   GtkContainer *resize_container;
934   
935   g_return_if_fail (container != NULL);
936   g_return_if_fail (GTK_IS_CONTAINER (container));
937
938   /* clear resize widgets for resize containers
939    * before aborting prematurely. this is especially
940    * important for toplevels which may need imemdiate
941    * processing or their resize handler to be queued.
942    */
943   if (GTK_IS_RESIZE_CONTAINER (container))
944     gtk_container_clear_resize_widgets (container);
945   if (GTK_OBJECT_DESTROYED (container) ||
946       GTK_WIDGET_RESIZE_NEEDED (container))
947     return;
948   
949   resize_container = gtk_container_get_resize_container (container);
950   
951   if (resize_container)
952     {
953       if (GTK_WIDGET_VISIBLE (resize_container) &&
954           (GTK_WIDGET_TOPLEVEL (resize_container) || GTK_WIDGET_DRAWABLE (resize_container)))
955         {
956           switch (resize_container->resize_mode)
957             {
958             case GTK_RESIZE_QUEUE:
959               if (!GTK_CONTAINER_RESIZE_PENDING (resize_container))
960                 {
961                   GTK_PRIVATE_SET_FLAG (resize_container, GTK_RESIZE_PENDING);
962                   if (container_resize_queue == NULL)
963                     gtk_idle_add_priority (GTK_PRIORITY_RESIZE,
964                                            gtk_container_idle_sizer,
965                                            NULL);
966                   container_resize_queue = g_slist_prepend (container_resize_queue, resize_container);
967                 }
968               
969               GTK_PRIVATE_SET_FLAG (container, GTK_RESIZE_NEEDED);
970               resize_container->resize_widgets =
971                 g_slist_prepend (resize_container->resize_widgets, container);
972               break;
973
974             case GTK_RESIZE_IMMEDIATE:
975               GTK_PRIVATE_SET_FLAG (container, GTK_RESIZE_NEEDED);
976               resize_container->resize_widgets =
977                 g_slist_prepend (resize_container->resize_widgets, container);
978               gtk_container_check_resize (resize_container);
979               break;
980
981             case GTK_RESIZE_PARENT:
982               /* Ignore, should not be reached */
983               break;
984             }
985         }
986       else
987         {
988           /* we need to let hidden resize containers know that something
989            * changed while they where hidden (currently only evaluated by
990            * toplevels).
991            */
992           resize_container->need_resize = TRUE;
993         }
994     }
995 }
996
997 void
998 gtk_container_check_resize (GtkContainer *container)
999 {
1000   g_return_if_fail (container != NULL);
1001   g_return_if_fail (GTK_IS_CONTAINER (container));
1002   
1003   gtk_signal_emit (GTK_OBJECT (container), container_signals[CHECK_RESIZE]);
1004 }
1005
1006 static void
1007 gtk_container_real_check_resize (GtkContainer *container)
1008 {
1009   GtkWidget *widget;
1010   GtkRequisition requisition;
1011   
1012   g_return_if_fail (container != NULL);
1013   g_return_if_fail (GTK_IS_CONTAINER (container));
1014   
1015   widget = GTK_WIDGET (container);
1016   
1017   gtk_widget_size_request (widget, &requisition);
1018   
1019   if (requisition.width > widget->allocation.width ||
1020       requisition.height > widget->allocation.height)
1021     {
1022       if (GTK_IS_RESIZE_CONTAINER (container))
1023         gtk_widget_size_allocate (GTK_WIDGET (container),
1024                                   &GTK_WIDGET (container)->allocation);
1025       else
1026         gtk_widget_queue_resize (widget);
1027     }
1028   else
1029     {
1030       gtk_container_resize_children (container);
1031     }
1032 }
1033
1034 /* The container hasn't changed size but one of its children
1035  *  queued a resize request. Which means that the allocation
1036  *  is not sufficient for the requisition of some child.
1037  *  We've already performed a size request at this point,
1038  *  so we simply need to run through the list of resize
1039  *  widgets and reallocate their sizes appropriately. We
1040  *  make the optimization of not performing reallocation
1041  *  for a widget who also has a parent in the resize widgets
1042  *  list. GTK_RESIZE_NEEDED is used for flagging those
1043  *  parents inside this function.
1044  */
1045 void
1046 gtk_container_resize_children (GtkContainer *container)
1047 {
1048   GtkWidget *widget;
1049   GtkWidget *resize_container;
1050   GSList *resize_widgets;
1051   GSList *resize_containers;
1052   GSList *node;
1053   
1054   /* resizing invariants:
1055    * toplevels have *always* resize_mode != GTK_RESIZE_PARENT set.
1056    * containers with resize_mode==GTK_RESIZE_PARENT have to have resize_widgets
1057    * set to NULL.
1058    * containers that are flagged RESIZE_NEEDED must have resize_widgets set to
1059    * NULL, or are toplevels (thus have ->parent set to NULL).
1060    * widgets that are in some container->resize_widgets list must be flagged with
1061    * RESIZE_NEEDED.
1062    * widgets that have RESIZE_NEEDED set must be referenced in some
1063    * GTK_IS_RESIZE_CONTAINER (container)->resize_widgets list.
1064    * containers that have an idle sizer pending must be flagged with
1065    * RESIZE_PENDING.
1066    */
1067   
1068   g_return_if_fail (container != NULL);
1069   g_return_if_fail (GTK_IS_CONTAINER (container));
1070
1071   /* we first check out if we actually need to perform a resize,
1072    * which is not the case if we got another container queued for
1073    * a resize in our ancestry. also we can skip the whole
1074    * resize_widgets checks if we are a toplevel and NEED_RESIZE.
1075    * this code assumes that our allocation is sufficient for our
1076    * requisition, since otherwise we would NEED_RESIZE.
1077    */
1078   resize_container = GTK_WIDGET (container);
1079   while (resize_container)
1080     {
1081       if (GTK_WIDGET_RESIZE_NEEDED (resize_container))
1082         break;
1083       resize_container = resize_container->parent;
1084     }
1085   if (resize_container)
1086     {
1087       /* queue_resize and size_allocate both clear our
1088        * resize_widgets list.
1089        */
1090       if (resize_container->parent)
1091         gtk_container_queue_resize (container);
1092       else
1093         gtk_widget_size_allocate (GTK_WIDGET (container),
1094                                   &GTK_WIDGET (container)->allocation);
1095       return;
1096     }
1097
1098   resize_container = GTK_WIDGET (container);
1099
1100   /* we now walk the ancestry for all resize widgets as long
1101    * as they are our children and as long as their allocation
1102    * is insufficient, since we don't need to reallocate below that.
1103    */
1104   resize_widgets = container->resize_widgets;
1105   container->resize_widgets = NULL;
1106   for (node = resize_widgets; node; node = node->next)
1107     {
1108       widget = node->data;
1109
1110       GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
1111
1112       while (widget->parent != resize_container &&
1113              ((widget->allocation.width < widget->requisition.width) ||
1114               (widget->allocation.height < widget->requisition.height)))
1115         widget = widget->parent;
1116       
1117       GTK_PRIVATE_SET_FLAG (widget, GTK_RESIZE_NEEDED);
1118       node->data = widget;
1119     }
1120
1121   /* for the newly setup resize_widgets list, we now walk each widget's
1122    * ancestry to sort those widgets out that have RESIZE_NEEDED parents.
1123    * we can safely stop the walk if we are the parent, since we checked
1124    * our own ancestry already.
1125    */
1126   resize_containers = NULL;
1127   for (node = resize_widgets; node; node = node->next)
1128     {
1129       GtkWidget *parent;
1130
1131       widget = node->data;
1132       
1133       if (!GTK_WIDGET_RESIZE_NEEDED (widget))
1134         continue;
1135       
1136       parent = widget->parent;
1137       
1138       while (parent != resize_container)
1139         {
1140           if (GTK_WIDGET_RESIZE_NEEDED (parent))
1141             {
1142               GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
1143               widget = parent;
1144             }
1145           parent = parent->parent;
1146         }
1147       
1148       if (!g_slist_find (resize_containers, widget))
1149         {
1150           resize_containers = g_slist_prepend (resize_containers, widget);
1151           gtk_widget_ref (widget);
1152         }
1153     }
1154   g_slist_free (resize_widgets);
1155   
1156   for (node = resize_containers; node; node = node->next)
1157     {
1158       widget = node->data;
1159       
1160       GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
1161
1162       gtk_widget_size_allocate (widget, &widget->allocation);
1163
1164       gtk_widget_unref (widget);
1165     }
1166   g_slist_free (resize_containers);
1167 }
1168
1169 /**
1170  * gtk_container_forall:
1171  * @container: a #GtkContainer
1172  * @callback: a callback
1173  * @callback_data: callback user data
1174  * 
1175  * Invokes @callback on each child of @container, including children
1176  * that are considered "internal" (implementation details of the
1177  * container). "Internal" children generally weren't added by the user
1178  * of the container, but were added by the container implementation
1179  * itself.  Most applications should use gtk_container_foreach(),
1180  * rather than gtk_container_forall().
1181  **/
1182 void
1183 gtk_container_forall (GtkContainer *container,
1184                       GtkCallback   callback,
1185                       gpointer      callback_data)
1186 {
1187   GtkContainerClass *class;
1188
1189   g_return_if_fail (container != NULL);
1190   g_return_if_fail (GTK_IS_CONTAINER (container));
1191   g_return_if_fail (callback != NULL);
1192
1193   class = GTK_CONTAINER_GET_CLASS (container);
1194
1195   if (class->forall)
1196     class->forall (container, TRUE, callback, callback_data);
1197 }
1198
1199 /**
1200  * gtk_container_foreach:
1201  * @container: a #GtkContainer
1202  * @callback: a callback
1203  * @callback_data: callback user data
1204  * 
1205  * Invokes @callback on each non-internal child of @container.  See
1206  * gtk_container_forall() for details on what constitutes an
1207  * "internal" child.  Most applications should use
1208  * gtk_container_foreach(), rather than gtk_container_forall().
1209  **/
1210 void
1211 gtk_container_foreach (GtkContainer *container,
1212                        GtkCallback   callback,
1213                        gpointer      callback_data)
1214 {
1215   GtkContainerClass *class;
1216   
1217   g_return_if_fail (container != NULL);
1218   g_return_if_fail (GTK_IS_CONTAINER (container));
1219   g_return_if_fail (callback != NULL);
1220
1221   class = GTK_CONTAINER_GET_CLASS (container);
1222
1223   if (class->forall)
1224     class->forall (container, FALSE, callback, callback_data);
1225 }
1226
1227 typedef struct _GtkForeachData  GtkForeachData;
1228 struct _GtkForeachData
1229 {
1230   GtkObject         *container;
1231   GtkCallbackMarshal callback;
1232   gpointer           callback_data;
1233 };
1234
1235 static void
1236 gtk_container_foreach_unmarshal (GtkWidget *child,
1237                                  gpointer data)
1238 {
1239   GtkForeachData *fdata = (GtkForeachData*) data;
1240   GtkArg args[2];
1241   
1242   /* first argument */
1243   args[0].name = NULL;
1244   args[0].type = GTK_OBJECT_TYPE (child);
1245   GTK_VALUE_OBJECT (args[0]) = GTK_OBJECT (child);
1246   
1247   /* location for return value */
1248   args[1].name = NULL;
1249   args[1].type = GTK_TYPE_NONE;
1250   
1251   fdata->callback (fdata->container, fdata->callback_data, 1, args);
1252 }
1253
1254 void
1255 gtk_container_foreach_full (GtkContainer       *container,
1256                             GtkCallback         callback,
1257                             GtkCallbackMarshal  marshal,
1258                             gpointer            callback_data,
1259                             GtkDestroyNotify    notify)
1260 {
1261   g_return_if_fail (container != NULL);
1262   g_return_if_fail (GTK_IS_CONTAINER (container));
1263
1264   if (marshal)
1265     {
1266       GtkForeachData fdata;
1267   
1268       fdata.container     = GTK_OBJECT (container);
1269       fdata.callback      = marshal;
1270       fdata.callback_data = callback_data;
1271
1272       gtk_container_foreach (container, gtk_container_foreach_unmarshal, &fdata);
1273     }
1274   else
1275     {
1276       g_return_if_fail (callback != NULL);
1277
1278       gtk_container_foreach (container, callback, &callback_data);
1279     }
1280
1281   if (notify)
1282     notify (callback_data);
1283 }
1284
1285 gboolean
1286 gtk_container_focus (GtkContainer     *container,
1287                      GtkDirectionType  direction)
1288 {
1289   gint return_val;
1290
1291   g_return_val_if_fail (container != NULL, FALSE);
1292   g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
1293   
1294   gtk_signal_emit (GTK_OBJECT (container),
1295                    container_signals[FOCUS],
1296                    direction, &return_val);
1297
1298   return return_val;
1299 }
1300
1301 void
1302 gtk_container_set_focus_child (GtkContainer *container,
1303                                GtkWidget    *widget)
1304 {
1305   g_return_if_fail (container != NULL);
1306   g_return_if_fail (GTK_IS_CONTAINER (container));
1307   if (widget)
1308     g_return_if_fail (GTK_IS_WIDGET (widget));
1309
1310   gtk_signal_emit (GTK_OBJECT (container), container_signals[SET_FOCUS_CHILD], widget);
1311 }
1312
1313 GList*
1314 gtk_container_children (GtkContainer *container)
1315 {
1316   GList *children;
1317
1318   children = NULL;
1319
1320   gtk_container_foreach (container,
1321                          gtk_container_children_callback,
1322                          &children);
1323
1324   return g_list_reverse (children);
1325 }
1326
1327 static void
1328 gtk_container_child_position_callback (GtkWidget *widget,
1329                                        gpointer   client_data)
1330 {
1331   struct {
1332     GtkWidget *child;
1333     guint i;
1334     guint index;
1335   } *data = client_data;
1336
1337   data->i++;
1338   if (data->child == widget)
1339     data->index = data->i;
1340 }
1341
1342 static gchar*
1343 gtk_container_child_default_composite_name (GtkContainer *container,
1344                                             GtkWidget    *child)
1345 {
1346   struct {
1347     GtkWidget *child;
1348     guint i;
1349     guint index;
1350   } data;
1351   gchar *name;
1352
1353   /* fallback implementation */
1354   data.child = child;
1355   data.i = 0;
1356   data.index = 0;
1357   gtk_container_forall (container,
1358                         gtk_container_child_position_callback,
1359                         &data);
1360   
1361   name = g_strdup_printf ("%s-%u",
1362                           gtk_type_name (GTK_OBJECT_TYPE (child)),
1363                           data.index);
1364
1365   return name;
1366 }
1367
1368 gchar*
1369 gtk_container_child_composite_name (GtkContainer *container,
1370                                     GtkWidget    *child)
1371 {
1372   g_return_val_if_fail (container != NULL, NULL);
1373   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
1374   g_return_val_if_fail (child != NULL, NULL);
1375   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
1376   g_return_val_if_fail (child->parent == GTK_WIDGET (container), NULL);
1377
1378   if (GTK_WIDGET_COMPOSITE_CHILD (child))
1379     {
1380       static GQuark quark_composite_name = 0;
1381       gchar *name;
1382
1383       if (!quark_composite_name)
1384         quark_composite_name = g_quark_from_static_string ("gtk-composite-name");
1385
1386       name = gtk_object_get_data_by_id (GTK_OBJECT (child), quark_composite_name);
1387       if (!name)
1388         {
1389           GtkContainerClass *class;
1390
1391           class = GTK_CONTAINER_GET_CLASS (container);
1392           if (class->composite_name)
1393             name = class->composite_name (container, child);
1394         }
1395       else
1396         name = g_strdup (name);
1397
1398       return name;
1399     }
1400   
1401   return NULL;
1402 }
1403
1404 void
1405 gtk_container_real_set_focus_child (GtkContainer     *container,
1406                                     GtkWidget        *child)
1407 {
1408   g_return_if_fail (container != NULL);
1409   g_return_if_fail (GTK_IS_CONTAINER (container));
1410   if (child)
1411     g_return_if_fail (GTK_IS_WIDGET (child));
1412
1413   if (child != container->focus_child)
1414     {
1415       if (container->focus_child)
1416         gtk_widget_unref (container->focus_child);
1417       container->focus_child = child;
1418       if (container->focus_child)
1419         gtk_widget_ref (container->focus_child);
1420     }
1421
1422
1423   /* check for h/v adjustments
1424    */
1425   if (container->focus_child)
1426     {
1427       GtkAdjustment *adjustment;
1428       
1429       adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container), vadjustment_key_id);
1430       if (adjustment)
1431         gtk_adjustment_clamp_page (adjustment,
1432                                    container->focus_child->allocation.y,
1433                                    (container->focus_child->allocation.y +
1434                                     container->focus_child->allocation.height));
1435
1436       adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container), hadjustment_key_id);
1437       if (adjustment)
1438         gtk_adjustment_clamp_page (adjustment,
1439                                    container->focus_child->allocation.x,
1440                                    (container->focus_child->allocation.x +
1441                                     container->focus_child->allocation.width));
1442     }
1443 }
1444
1445 static GList*
1446 get_focus_chain (GtkContainer *container)
1447 {
1448   GList *chain;
1449   
1450   chain = g_object_get_data (G_OBJECT (container), "gtk-container-focus-chain");
1451
1452   return chain;
1453 }
1454
1455 static GList*
1456 filter_unfocusable (GtkContainer *container,
1457                     GList        *list)
1458 {
1459   GList *tmp_list;
1460   GList *tmp_list2;
1461   
1462   tmp_list = list;
1463   while (tmp_list)
1464     {
1465       if (GTK_WIDGET_IS_SENSITIVE (tmp_list->data) &&
1466           GTK_WIDGET_DRAWABLE (tmp_list->data) &&
1467           (GTK_IS_CONTAINER (tmp_list->data) || GTK_WIDGET_CAN_FOCUS (tmp_list->data)))
1468         tmp_list = tmp_list->next;
1469       else
1470         {
1471           tmp_list2 = tmp_list;
1472           tmp_list = tmp_list->next;
1473           
1474           list = g_list_remove_link (list, tmp_list2);
1475           g_list_free_1 (tmp_list2);
1476         }
1477     }
1478
1479   return list;
1480 }
1481
1482 static gboolean
1483 gtk_container_real_focus (GtkContainer     *container,
1484                           GtkDirectionType  direction)
1485 {
1486   GList *children;
1487   gint return_val;
1488
1489   g_return_val_if_fail (container != NULL, FALSE);
1490   g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
1491
1492   /* Fail if the container is inappropriate for focus movement
1493    */
1494   if (!GTK_WIDGET_DRAWABLE (container) ||
1495       !GTK_WIDGET_IS_SENSITIVE (container))
1496     return FALSE;
1497
1498   return_val = FALSE;
1499
1500   if (GTK_WIDGET_CAN_FOCUS (container))
1501     {
1502       if (!GTK_WIDGET_HAS_FOCUS (container))
1503         {
1504           gtk_widget_grab_focus (GTK_WIDGET (container));
1505           return_val = TRUE;
1506         }
1507     }
1508   else
1509     {
1510       /* Get a list of the containers children, allowing focus
1511        * chain to override.
1512        */
1513       if (container->has_focus_chain)
1514         {
1515           GList *chain;
1516
1517           chain = get_focus_chain (container);
1518
1519           children = g_list_copy (chain);
1520         }
1521       else
1522         {
1523           children = NULL;
1524           gtk_container_forall (container,
1525                                 gtk_container_children_callback,
1526                                 &children);
1527           children = g_list_reverse (children);
1528         }
1529
1530       if (children)
1531         {
1532           /* Remove any children which are inappropriate for focus movement
1533            */
1534           children = filter_unfocusable (container, children);
1535           
1536           switch (direction)
1537             {
1538             case GTK_DIR_TAB_FORWARD:
1539             case GTK_DIR_TAB_BACKWARD:
1540               if (container->has_focus_chain)
1541                 {
1542                   if (direction == GTK_DIR_TAB_BACKWARD)
1543                     children = g_list_reverse (children);
1544                   return_val = gtk_container_focus_move (container, children, direction);
1545                 }
1546               else
1547                 return_val = gtk_container_focus_tab (container, children, direction);
1548               break;
1549             case GTK_DIR_UP:
1550             case GTK_DIR_DOWN:
1551               return_val = gtk_container_focus_up_down (container, &children, direction);
1552               break;
1553             case GTK_DIR_LEFT:
1554             case GTK_DIR_RIGHT:
1555               return_val = gtk_container_focus_left_right (container, &children, direction);
1556               break;
1557             }
1558
1559           g_list_free (children);
1560         }
1561     }
1562
1563   return return_val;
1564 }
1565
1566 static gboolean
1567 gtk_container_focus_tab (GtkContainer     *container,
1568                          GList            *children,
1569                          GtkDirectionType  direction)
1570 {
1571   GtkWidget *child;
1572   GtkWidget *child2;
1573   GList *tmp_list;
1574   guint length;
1575   guint i, j;
1576
1577   length = g_list_length (children);
1578
1579   /* sort the children in the y direction */
1580   for (i = 1; i < length; i++)
1581     {
1582       j = i;
1583       tmp_list = g_list_nth (children, j);
1584       child = tmp_list->data;
1585
1586       while (j > 0)
1587         {
1588           child2 = tmp_list->prev->data;
1589           if (child->allocation.y < child2->allocation.y)
1590             {
1591               tmp_list->data = tmp_list->prev->data;
1592               tmp_list = tmp_list->prev;
1593               j--;
1594             }
1595           else
1596             break;
1597         }
1598
1599       tmp_list->data = child;
1600     }
1601
1602   /* sort the children in the x direction while
1603    *  maintaining the y direction sort.
1604    */
1605   for (i = 1; i < length; i++)
1606     {
1607       j = i;
1608       tmp_list = g_list_nth (children, j);
1609       child = tmp_list->data;
1610
1611       while (j > 0)
1612         {
1613           child2 = tmp_list->prev->data;
1614           if ((child->allocation.x < child2->allocation.x) &&
1615               (child->allocation.y == child2->allocation.y))
1616             {
1617               tmp_list->data = tmp_list->prev->data;
1618               tmp_list = tmp_list->prev;
1619               j--;
1620             }
1621           else
1622             break;
1623         }
1624
1625       tmp_list->data = child;
1626     }
1627
1628   /* if we are going backwards then reverse the order
1629    *  of the children.
1630    */
1631   if (direction == GTK_DIR_TAB_BACKWARD)
1632     children = g_list_reverse (children);
1633
1634   return gtk_container_focus_move (container, children, direction);
1635 }
1636
1637 static gboolean
1638 old_focus_coords (GtkContainer *container, GdkRectangle *old_focus_rect)
1639 {
1640   GtkWidget *widget = GTK_WIDGET (container);
1641   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
1642   
1643   if (toplevel &&
1644       GTK_IS_WINDOW (toplevel) && GTK_WINDOW (toplevel)->focus_widget &&
1645       GTK_WIDGET_REALIZED (container) &&
1646       GTK_WIDGET_REALIZED (GTK_WINDOW (toplevel)->focus_widget))
1647     {
1648       GtkWidget *old_focus = GTK_WINDOW (toplevel)->focus_widget;
1649       GdkWindow *old_parent_window = old_focus->parent ? old_focus->parent->window : old_focus->window;
1650       GdkWindow *new_parent_window = widget->window;
1651       GdkWindow *toplevel_window = toplevel->window;
1652       
1653       *old_focus_rect = old_focus->allocation;
1654       
1655       /* Translate coordinates to the toplevel */
1656       
1657       while (old_parent_window != toplevel_window)
1658         {
1659           gint dx, dy;
1660           
1661           gdk_window_get_position (old_parent_window, &dx, &dy);
1662           
1663           old_focus_rect->x += dx;
1664           old_focus_rect->y += dy;
1665           
1666           old_parent_window = gdk_window_get_parent (old_parent_window);
1667         }
1668       
1669       /* Translate coordinates back to the new container */
1670       
1671       while (new_parent_window != toplevel_window)
1672         {
1673           gint dx, dy;
1674           
1675           gdk_window_get_position (new_parent_window, &dx, &dy);
1676           
1677           old_focus_rect->x -= dx;
1678           old_focus_rect->y -= dy;
1679           
1680           new_parent_window = gdk_window_get_parent (new_parent_window);
1681         }
1682
1683       return TRUE;
1684     }
1685
1686   return FALSE;
1687 }
1688
1689 typedef struct _CompareInfo CompareInfo;
1690
1691 struct _CompareInfo
1692 {
1693   gint x;
1694   gint y;
1695 };
1696
1697 static gint
1698 up_down_compare (gconstpointer a,
1699                  gconstpointer b,
1700                  gpointer      data)
1701 {
1702   const GtkWidget *child1 = a;
1703   const GtkWidget *child2 = b;
1704   CompareInfo *compare = data;
1705
1706   gint y1 = child1->allocation.y + child1->allocation.height / 2;
1707   gint y2 = child2->allocation.y + child2->allocation.height / 2;
1708
1709   if (y1 == y2)
1710     {
1711       gint x1 = abs (child1->allocation.x + child1->allocation.width / 2 - compare->x);
1712       gint x2 = abs (child2->allocation.x + child2->allocation.width / 2 - compare->x);
1713
1714       if (compare->y < y1)
1715         return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1);
1716       else
1717         return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1);
1718     }
1719   else
1720     return (y1 < y2) ? -1 : 1;
1721 }
1722
1723 static gboolean
1724 gtk_container_focus_up_down (GtkContainer     *container,
1725                              GList           **children,
1726                              GtkDirectionType  direction)
1727 {
1728   CompareInfo compare;
1729   GList *tmp_list;
1730
1731   if (container->focus_child)
1732     {
1733       gint compare_x1;
1734       gint compare_x2;
1735       gint compare_y;
1736       
1737       /* Delete widgets from list that don't match minimum criteria */
1738
1739       compare_x1 = container->focus_child->allocation.x;
1740       compare_x2 = container->focus_child->allocation.x + container->focus_child->allocation.width;
1741
1742       if (direction == GTK_DIR_UP)
1743         compare_y = container->focus_child->allocation.y;
1744       else
1745         compare_y = container->focus_child->allocation.y + container->focus_child->allocation.height;
1746       
1747       tmp_list = *children;
1748       while (tmp_list)
1749         {
1750           GtkWidget *child = tmp_list->data;
1751           GList *next = tmp_list->next;
1752           gint child_x1, child_x2;
1753           
1754           if (child != container->focus_child)
1755             {
1756               child_x1 = child->allocation.x;
1757               child_x2 = child->allocation.x + child->allocation.width;
1758               
1759               if ((child_x2 <= compare_x1 || child_x1 >= compare_x2) /* No horizontal overlap */ ||
1760                   (direction == GTK_DIR_DOWN && child->allocation.y + child->allocation.height < compare_y) || /* Not below */
1761                   (direction == GTK_DIR_UP && child->allocation.y > compare_y)) /* Not above */
1762                 {
1763                   *children = g_list_delete_link (*children, tmp_list);
1764                 }
1765             }
1766           
1767           tmp_list = next;
1768         }
1769
1770       compare.x = (compare_x1 + compare_x2) / 2;
1771       compare.y = container->focus_child->allocation.y + container->focus_child->allocation.height / 2;
1772     }
1773   else
1774     {
1775       /* No old focus widget, need to figure out starting x,y some other way
1776        */
1777       GtkWidget *widget = GTK_WIDGET (container);
1778       GdkRectangle old_focus_rect;
1779
1780       if (old_focus_coords (container, &old_focus_rect))
1781         {
1782           compare.x = old_focus_rect.x + old_focus_rect.width / 2;
1783         }
1784       else
1785         {
1786           if (GTK_WIDGET_NO_WINDOW (widget))
1787             compare.x = widget->allocation.x + widget->allocation.width / 2;
1788           else
1789             compare.x = widget->allocation.width / 2;
1790         }
1791       
1792       if (GTK_WIDGET_NO_WINDOW (widget))
1793         compare.y = (direction == GTK_DIR_DOWN) ? widget->allocation.y : widget->allocation.y + widget->allocation.height;
1794       else
1795         compare.y = (direction == GTK_DIR_DOWN) ? 0 : + widget->allocation.height;
1796     }
1797
1798   *children = g_list_sort_with_data (*children, up_down_compare, &compare);
1799
1800   if (direction == GTK_DIR_UP)
1801     *children = g_list_reverse (*children);
1802
1803   return gtk_container_focus_move (container, *children, direction);
1804 }
1805
1806 static gint
1807 left_right_compare (gconstpointer a,
1808                     gconstpointer b,
1809                     gpointer      data)
1810 {
1811   const GtkWidget *child1 = a;
1812   const GtkWidget *child2 = b;
1813   CompareInfo *compare = data;
1814
1815   gint x1 = child1->allocation.x + child1->allocation.width / 2;
1816   gint x2 = child2->allocation.x + child2->allocation.width / 2;
1817
1818   if (x1 == x2)
1819     {
1820       gint y1 = abs (child1->allocation.y + child1->allocation.height / 2 - compare->y);
1821       gint y2 = abs (child2->allocation.y + child2->allocation.height / 2 - compare->y);
1822
1823       if (compare->x < x1)
1824         return (y1 < y2) ? -1 : ((y1 == y2) ? 0 : 1);
1825       else
1826         return (y1 < y2) ? 1 : ((y1 == y2) ? 0 : -1);
1827     }
1828   else
1829     return (x1 < x2) ? -1 : 1;
1830 }
1831
1832 static gboolean
1833 gtk_container_focus_left_right (GtkContainer     *container,
1834                                 GList           **children,
1835                                 GtkDirectionType  direction)
1836 {
1837   CompareInfo compare;
1838   GList *tmp_list;
1839
1840   if (container->focus_child)
1841     {
1842       gint compare_y1;
1843       gint compare_y2;
1844       gint compare_x;
1845       
1846       /* Delete widgets from list that don't match minimum criteria */
1847
1848       compare_y1 = container->focus_child->allocation.y;
1849       compare_y2 = container->focus_child->allocation.y + container->focus_child->allocation.height;
1850
1851       if (direction == GTK_DIR_LEFT)
1852         compare_x = container->focus_child->allocation.x;
1853       else
1854         compare_x = container->focus_child->allocation.x + container->focus_child->allocation.width;
1855       
1856       tmp_list = *children;
1857       while (tmp_list)
1858         {
1859           GtkWidget *child = tmp_list->data;
1860           GList *next = tmp_list->next;
1861           gint child_y1, child_y2;
1862           
1863           if (child != container->focus_child)
1864             {
1865               child_y1 = child->allocation.y;
1866               child_y2 = child->allocation.y + child->allocation.height;
1867               
1868               if ((child_y2 <= compare_y1 || child_y1 >= compare_y2) /* No vertical overlap */ ||
1869                   (direction == GTK_DIR_RIGHT && child->allocation.x + child->allocation.width < compare_x) || /* Not to left */
1870                   (direction == GTK_DIR_LEFT && child->allocation.x > compare_x)) /* Not to right */
1871                 {
1872                   *children = g_list_delete_link (*children, tmp_list);
1873                 }
1874             }
1875           
1876           tmp_list = next;
1877         }
1878
1879       compare.y = (compare_y1 + compare_y2) / 2;
1880       compare.x = container->focus_child->allocation.x + container->focus_child->allocation.width / 2;
1881     }
1882   else
1883     {
1884       /* No old focus widget, need to figure out starting x,y some other way
1885        */
1886       GtkWidget *widget = GTK_WIDGET (container);
1887       GdkRectangle old_focus_rect;
1888
1889       if (old_focus_coords (container, &old_focus_rect))
1890         {
1891           compare.y = old_focus_rect.y + old_focus_rect.height / 2;
1892         }
1893       else
1894         {
1895           if (GTK_WIDGET_NO_WINDOW (widget))
1896             compare.y = widget->allocation.y + widget->allocation.height / 2;
1897           else
1898             compare.y = widget->allocation.height / 2;
1899         }
1900       
1901       if (GTK_WIDGET_NO_WINDOW (widget))
1902         compare.x = (direction == GTK_DIR_RIGHT) ? widget->allocation.x : widget->allocation.x + widget->allocation.width;
1903       else
1904         compare.x = (direction == GTK_DIR_RIGHT) ? 0 : widget->allocation.width;
1905     }
1906
1907   *children = g_list_sort_with_data (*children, left_right_compare, &compare);
1908
1909   if (direction == GTK_DIR_LEFT)
1910     *children = g_list_reverse (*children);
1911
1912   return gtk_container_focus_move (container, *children, direction);
1913 }
1914
1915 static gboolean
1916 gtk_container_focus_move (GtkContainer     *container,
1917                           GList            *children,
1918                           GtkDirectionType  direction)
1919 {
1920   GtkWidget *focus_child;
1921   GtkWidget *child;
1922
1923   focus_child = container->focus_child;
1924
1925   while (children)
1926     {
1927       child = children->data;
1928       children = children->next;
1929
1930       if (!child)
1931         continue;
1932       
1933       if (focus_child)
1934         {
1935           if (focus_child == child)
1936             {
1937               focus_child = NULL;
1938
1939               if (GTK_WIDGET_DRAWABLE (child) &&
1940                   GTK_IS_CONTAINER (child))
1941                 if (gtk_container_focus (GTK_CONTAINER (child), direction))
1942                   return TRUE;
1943             }
1944         }
1945       else if (GTK_WIDGET_DRAWABLE (child) &&
1946                gtk_widget_is_ancestor (child, GTK_WIDGET (container)))
1947         {
1948           if (GTK_IS_CONTAINER (child))
1949             {
1950               if (gtk_container_focus (GTK_CONTAINER (child), direction))
1951                 return TRUE;
1952             }
1953           else if (GTK_WIDGET_CAN_FOCUS (child))
1954             {
1955               gtk_widget_grab_focus (child);
1956               return TRUE;
1957             }
1958         }
1959     }
1960
1961   return FALSE;
1962 }
1963
1964
1965 static void
1966 gtk_container_children_callback (GtkWidget *widget,
1967                                  gpointer   client_data)
1968 {
1969   GList **children;
1970
1971   children = (GList**) client_data;
1972   *children = g_list_prepend (*children, widget);
1973 }
1974
1975
1976 /* Hack-around */
1977 #define g_signal_handlers_disconnect_by_func(obj, func, data) g_signal_handlers_disconnect_matched (obj, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, 0, 0, NULL, func, data)
1978
1979 static void
1980 chain_widget_destroyed (GtkWidget *widget,
1981                         gpointer   user_data)
1982 {
1983   GtkContainer *container;
1984   GList *chain;
1985   
1986   container = GTK_CONTAINER (user_data);
1987
1988   chain = g_object_get_data (G_OBJECT (container),
1989                              "gtk-container-focus-chain");
1990
1991   chain = g_list_remove (chain, widget);
1992
1993   g_signal_handlers_disconnect_by_func (G_OBJECT (widget),
1994                                         chain_widget_destroyed,
1995                                         user_data);
1996   
1997   g_object_set_data (G_OBJECT (container),
1998                      "gtk-container-focus-chain",
1999                      chain);  
2000 }
2001
2002 void
2003 gtk_container_set_focus_chain (GtkContainer *container,
2004                                GList        *focusable_widgets)
2005 {
2006   GList *chain;
2007   GList *tmp_list;
2008   
2009   g_return_if_fail (GTK_IS_CONTAINER (container));
2010   
2011   if (container->has_focus_chain)
2012     gtk_container_unset_focus_chain (container);
2013
2014   container->has_focus_chain = TRUE;
2015   
2016   chain = NULL;
2017   tmp_list = focusable_widgets;
2018   while (tmp_list != NULL)
2019     {
2020       g_return_if_fail (GTK_IS_WIDGET (tmp_list->data));
2021       
2022       /* In principle each widget in the chain should be a descendant
2023        * of the container, but we don't want to check that here, it's
2024        * expensive and also it's allowed to set the focus chain before
2025        * you pack the widgets, or have a widget in the chain that isn't
2026        * always packed. So we check for ancestor during actual traversal.
2027        */
2028
2029       chain = g_list_prepend (chain, tmp_list->data);
2030
2031       gtk_signal_connect (GTK_OBJECT (tmp_list->data),
2032                           "destroy",
2033                           GTK_SIGNAL_FUNC (chain_widget_destroyed),
2034                           container);
2035       
2036       tmp_list = g_list_next (tmp_list);
2037     }
2038
2039   chain = g_list_reverse (chain);
2040   
2041   g_object_set_data (G_OBJECT (container),
2042                      "gtk-container-focus-chain",
2043                      chain);
2044 }
2045
2046 void
2047 gtk_container_unset_focus_chain (GtkContainer  *container)
2048 {  
2049   g_return_if_fail (GTK_IS_CONTAINER (container));
2050
2051   if (container->has_focus_chain)
2052     {
2053       GList *chain;
2054       GList *tmp_list;
2055       
2056       chain = get_focus_chain (container);
2057       
2058       container->has_focus_chain = FALSE;
2059       
2060       g_object_set_data (G_OBJECT (container), "gtk-container-focus-chain",
2061                          NULL);
2062
2063       tmp_list = chain;
2064       while (tmp_list != NULL)
2065         {
2066           g_signal_handlers_disconnect_by_func (G_OBJECT (tmp_list->data),
2067                                                 chain_widget_destroyed,
2068                                                 container);
2069           
2070           tmp_list = g_list_next (tmp_list);
2071         }
2072
2073       g_list_free (chain);
2074     }
2075 }
2076
2077 void
2078 gtk_container_set_focus_vadjustment (GtkContainer  *container,
2079                                      GtkAdjustment *adjustment)
2080 {
2081   g_return_if_fail (container != NULL);
2082   g_return_if_fail (GTK_IS_CONTAINER (container));
2083   if (adjustment)
2084     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2085
2086   if (adjustment)
2087     gtk_object_ref (GTK_OBJECT(adjustment));
2088
2089   gtk_object_set_data_by_id_full (GTK_OBJECT (container),
2090                                   vadjustment_key_id,
2091                                   adjustment,
2092                                   (GtkDestroyNotify) gtk_object_unref);
2093 }
2094
2095 void
2096 gtk_container_set_focus_hadjustment (GtkContainer  *container,
2097                                      GtkAdjustment *adjustment)
2098 {
2099   g_return_if_fail (container != NULL);
2100   g_return_if_fail (GTK_IS_CONTAINER (container));
2101   if (adjustment)
2102     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
2103
2104   if (adjustment)
2105     gtk_object_ref (GTK_OBJECT (adjustment));
2106
2107   gtk_object_set_data_by_id_full (GTK_OBJECT (container),
2108                                   hadjustment_key_id,
2109                                   adjustment,
2110                                   (GtkDestroyNotify) gtk_object_unref);
2111 }
2112
2113
2114 static void
2115 gtk_container_show_all (GtkWidget *widget)
2116 {
2117   g_return_if_fail (widget != NULL);
2118   g_return_if_fail (GTK_IS_CONTAINER (widget));
2119
2120   gtk_container_foreach (GTK_CONTAINER (widget),
2121                          (GtkCallback) gtk_widget_show_all,
2122                          NULL);
2123   gtk_widget_show (widget);
2124 }
2125
2126 static void
2127 gtk_container_hide_all (GtkWidget *widget)
2128 {
2129   g_return_if_fail (widget != NULL);
2130   g_return_if_fail (GTK_IS_CONTAINER (widget));
2131
2132   gtk_widget_hide (widget);
2133   gtk_container_foreach (GTK_CONTAINER (widget),
2134                          (GtkCallback) gtk_widget_hide_all,
2135                          NULL);
2136 }
2137
2138
2139 static void
2140 gtk_container_expose_child (GtkWidget *child,
2141                             gpointer   client_data)
2142 {
2143   struct {
2144     GtkWidget *container;
2145     GdkEventExpose *event;
2146   } *data = client_data;
2147   
2148   gtk_container_propagate_expose (GTK_CONTAINER (data->container),
2149                                   child,
2150                                   data->event);
2151 }
2152
2153 static gint 
2154 gtk_container_expose (GtkWidget      *widget,
2155                       GdkEventExpose *event)
2156 {
2157   struct {
2158     GtkWidget *container;
2159     GdkEventExpose *event;
2160   } data;
2161
2162   g_return_val_if_fail (widget != NULL, FALSE);
2163   g_return_val_if_fail (GTK_IS_CONTAINER (widget), FALSE);
2164   g_return_val_if_fail (event != NULL, FALSE);
2165
2166   
2167   if (GTK_WIDGET_DRAWABLE (widget)) 
2168     {
2169       data.container = widget;
2170       data.event = event;
2171       
2172       gtk_container_foreach (GTK_CONTAINER (widget),
2173                              gtk_container_expose_child,
2174                              &data);
2175     }   
2176   
2177   return TRUE;
2178 }
2179
2180
2181 /**
2182  * gtk_container_propagate_expose:
2183  * @container: a #GtkContainer
2184  * @child: a child of @container
2185  * @event: a expose event sent to container
2186  *
2187  *  When a container receives an expose event, it must send synthetic
2188  * expose events to all children that don't have their own GdkWindows.
2189  * This function provides a convenient way of doing this. A container,
2190  * when it receives an expose event, gtk_container_propagate_expose() 
2191  * once for each child, passing in the event the container received.
2192  *
2193  * gtk_container_propagate expose() takes care of deciding whether
2194  * an expose event needs to be sent to the child, intersecting
2195  * the event's area with the child area, and sending the event.
2196  * 
2197  * In most cases, a container can simply either simply inherit the
2198  * ::expose implementation from GtkContainer, or, do some drawing 
2199  * and then chain to the ::expose implementation from GtkContainer.
2200  **/
2201 void
2202 gtk_container_propagate_expose (GtkContainer   *container,
2203                                 GtkWidget      *child,
2204                                 GdkEventExpose *event)
2205 {
2206   GdkEventExpose child_event;
2207
2208   g_return_if_fail (GTK_IS_CONTAINER (container));
2209   g_return_if_fail (GTK_IS_WIDGET (child));
2210   g_return_if_fail (event != NULL);
2211
2212   g_assert (child->parent == GTK_WIDGET (container));
2213   
2214   if (GTK_WIDGET_DRAWABLE (child) &&
2215       GTK_WIDGET_NO_WINDOW (child) &&
2216       (child->window == event->window))
2217     {
2218       child_event = *event;
2219
2220       child_event.region = gtk_widget_region_intersect (child, event->region);
2221       if (!gdk_region_empty (child_event.region))
2222         {
2223           gdk_region_get_clipbox (child_event.region, &child_event.area);
2224           gtk_widget_send_expose (child, (GdkEvent *)&child_event);
2225         }
2226       gdk_region_destroy (child_event.region);
2227     }
2228 }