]> Pileus Git - ~andy/gtk/blob - gtk/gtkcontainer.c
removed default initialization check, people must use gtk_type_init();
[~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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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 #include <string.h>
20 #include "gtkcontainer.h"
21 #include "gtkprivate.h"
22 #include "gtksignal.h"
23 #include "gtkmain.h"
24 #include <stdarg.h>
25
26
27 enum {
28   ADD,
29   REMOVE,
30   CHECK_RESIZE,
31   FOCUS,
32   SET_FOCUS_CHILD,
33   LAST_SIGNAL
34 };
35 enum {
36   ARG_0,
37   ARG_BORDER_WIDTH,
38   ARG_RESIZE_MODE,
39   ARG_CHILD
40 };
41
42 typedef struct _GtkChildArgInfo GtkChildArgInfo;
43 struct _GtkChildArgInfo
44 {
45   gchar *name;
46   GtkType type;
47   GtkType class_type;
48   guint arg_flags;
49   guint arg_id;
50   guint seq_id;
51 };
52
53 /* The global list of toplevel windows */
54 static GList *toplevel_list = NULL;
55
56 static void gtk_container_base_class_init   (GtkContainerClass *klass);
57 static void gtk_container_class_init        (GtkContainerClass *klass);
58 static void gtk_container_init              (GtkContainer      *container);
59 static void gtk_container_destroy           (GtkObject         *object);
60 static void gtk_container_get_arg           (GtkObject         *object,
61                                              GtkArg            *arg,
62                                              guint              arg_id);
63 static void gtk_container_set_arg           (GtkObject         *object,
64                                              GtkArg            *arg,
65                                              guint              arg_id);
66 static void gtk_container_add_unimplemented (GtkContainer      *container,
67                                              GtkWidget         *widget);
68 static void gtk_container_remove_unimplemented (GtkContainer   *container,
69                                                 GtkWidget      *widget);
70 static void gtk_container_real_check_resize (GtkContainer      *container);
71 static gint gtk_container_real_focus        (GtkContainer      *container,
72                                              GtkDirectionType   direction);
73 static void gtk_container_real_set_focus_child (GtkContainer      *container,
74                                              GtkWidget         *widget);
75 static gint gtk_container_focus_tab         (GtkContainer      *container,
76                                              GList             *children,
77                                              GtkDirectionType   direction);
78 static gint gtk_container_focus_up_down     (GtkContainer      *container,
79                                              GList             *children,
80                                              GtkDirectionType   direction);
81 static gint gtk_container_focus_left_right  (GtkContainer      *container,
82                                              GList             *children,
83                                              GtkDirectionType   direction);
84 static gint gtk_container_focus_move        (GtkContainer      *container,
85                                              GList             *children,
86                                              GtkDirectionType   direction);
87 static void gtk_container_children_callback (GtkWidget         *widget,
88                                              gpointer           client_data);
89 static void gtk_container_show_all          (GtkWidget         *widget);
90 static void gtk_container_hide_all          (GtkWidget         *widget);
91
92 static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
93                                                           GtkWidget    *child);
94
95
96
97 static guint container_signals[LAST_SIGNAL] = { 0 };
98 static GHashTable *container_child_arg_info_ht = NULL;
99
100 static GtkWidgetClass *parent_class = NULL;
101
102 static const gchar *vadjustment_key = "gtk-vadjustment";
103 static guint        vadjustment_key_id = 0;
104 static const gchar *hadjustment_key = "gtk-hadjustment";
105 static guint        hadjustment_key_id = 0;
106 static GSList      *container_resize_queue = NULL;
107
108 GtkType
109 gtk_container_get_type (void)
110 {
111   static GtkType container_type = 0;
112
113   if (!container_type)
114     {
115       GtkTypeInfo container_info =
116       {
117         "GtkContainer",
118         sizeof (GtkContainer),
119         sizeof (GtkContainerClass),
120         (GtkClassInitFunc) gtk_container_class_init,
121         (GtkObjectInitFunc) gtk_container_init,
122         /* reserved_1 */ NULL,
123         /* reserved_2 */ NULL,
124         (GtkClassInitFunc) gtk_container_base_class_init,
125       };
126
127       container_type = gtk_type_unique (gtk_widget_get_type (), &container_info);
128     }
129
130   return container_type;
131 }
132
133 static void
134 gtk_container_base_class_init (GtkContainerClass *class)
135 {
136   /* reset instance specifc class fields that don't get inherited */
137   class->n_child_args = 0;
138   class->set_child_arg = NULL;
139   class->get_child_arg = NULL;
140 }
141
142 static void
143 gtk_container_class_init (GtkContainerClass *class)
144 {
145   GtkObjectClass *object_class;
146   GtkWidgetClass *widget_class;
147
148   object_class = (GtkObjectClass*) class;
149   widget_class = (GtkWidgetClass*) class;
150
151   parent_class = gtk_type_class (gtk_widget_get_type ());
152
153   container_child_arg_info_ht = g_hash_table_new (gtk_arg_info_hash,
154                                                   gtk_arg_info_equal);
155
156   vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
157   hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
158   
159   gtk_object_add_arg_type ("GtkContainer::border_width", GTK_TYPE_ULONG, GTK_ARG_READWRITE, ARG_BORDER_WIDTH);
160   gtk_object_add_arg_type ("GtkContainer::resize_mode", GTK_TYPE_RESIZE_MODE, GTK_ARG_READWRITE, ARG_RESIZE_MODE);
161   gtk_object_add_arg_type ("GtkContainer::child", GTK_TYPE_WIDGET, GTK_ARG_WRITABLE, ARG_CHILD);
162
163   container_signals[ADD] =
164     gtk_signal_new ("add",
165                     GTK_RUN_FIRST,
166                     object_class->type,
167                     GTK_SIGNAL_OFFSET (GtkContainerClass, add),
168                     gtk_marshal_NONE__POINTER,
169                     GTK_TYPE_NONE, 1,
170                     GTK_TYPE_WIDGET);
171   container_signals[REMOVE] =
172     gtk_signal_new ("remove",
173                     GTK_RUN_FIRST,
174                     object_class->type,
175                     GTK_SIGNAL_OFFSET (GtkContainerClass, remove),
176                     gtk_marshal_NONE__POINTER,
177                     GTK_TYPE_NONE, 1,
178                     GTK_TYPE_WIDGET);
179   container_signals[CHECK_RESIZE] =
180     gtk_signal_new ("check_resize",
181                     GTK_RUN_LAST,
182                     object_class->type,
183                     GTK_SIGNAL_OFFSET (GtkContainerClass, check_resize),
184                     gtk_marshal_NONE__NONE,
185                     GTK_TYPE_NONE, 0);
186   container_signals[FOCUS] =
187     gtk_signal_new ("focus",
188                     GTK_RUN_LAST,
189                     object_class->type,
190                     GTK_SIGNAL_OFFSET (GtkContainerClass, focus),
191                     gtk_marshal_ENUM__ENUM,
192                     GTK_TYPE_DIRECTION_TYPE, 1,
193                     GTK_TYPE_DIRECTION_TYPE);
194   container_signals[SET_FOCUS_CHILD] =
195     gtk_signal_new ("set-focus-child",
196                     GTK_RUN_FIRST,
197                     object_class->type,
198                     GTK_SIGNAL_OFFSET (GtkContainerClass, set_focus_child),
199                     gtk_marshal_NONE__POINTER,
200                     GTK_TYPE_NONE, 1,
201                     GTK_TYPE_WIDGET);
202   gtk_object_class_add_signals (object_class, container_signals, LAST_SIGNAL);
203
204   object_class->get_arg = gtk_container_get_arg;
205   object_class->set_arg = gtk_container_set_arg;
206   object_class->destroy = gtk_container_destroy;
207
208   widget_class->show_all = gtk_container_show_all;
209   widget_class->hide_all = gtk_container_hide_all;
210   
211   class->add = gtk_container_add_unimplemented;
212   class->remove = gtk_container_remove_unimplemented;
213   class->check_resize = gtk_container_real_check_resize;
214   class->forall = NULL;
215   class->focus = gtk_container_real_focus;
216   class->set_focus_child = gtk_container_real_set_focus_child;
217   class->child_type = NULL;
218   class->composite_name = gtk_container_child_default_composite_name;
219 }
220
221 GtkType
222 gtk_container_child_type (GtkContainer      *container)
223 {
224   GtkType slot;
225   GtkContainerClass *class;
226
227   g_return_val_if_fail (container != NULL, 0);
228   g_return_val_if_fail (GTK_IS_CONTAINER (container), 0);
229
230   class = GTK_CONTAINER_CLASS (GTK_OBJECT (container)->klass);
231   if (class->child_type)
232     slot = class->child_type (container);
233   else
234     slot = GTK_TYPE_NONE;
235
236   return slot;
237 }
238
239 /****************************************************
240  * GtkContainer child argument mechanism
241  *
242  ****************************************************/
243
244 void
245 gtk_container_add_with_args (GtkContainer      *container,
246                              GtkWidget         *widget,
247                              const gchar       *first_arg_name,
248                              ...)
249 {
250   g_return_if_fail (container != NULL);
251   g_return_if_fail (GTK_IS_CONTAINER (container));
252   g_return_if_fail (widget != NULL);
253   g_return_if_fail (GTK_IS_WIDGET (widget));
254   g_return_if_fail (widget->parent == NULL);
255
256   gtk_widget_ref (GTK_WIDGET (container));
257   gtk_widget_ref (widget);
258
259   gtk_signal_emit (GTK_OBJECT (container), container_signals[ADD], widget);
260   
261   if (widget->parent)
262     {
263       va_list var_args;
264       GSList *arg_list = NULL;
265       GSList *info_list = NULL;
266       gchar *error;
267       
268       va_start (var_args, first_arg_name);
269       error = gtk_container_child_args_collect (GTK_OBJECT_TYPE (container),
270                                                 &arg_list,
271                                                 &info_list,
272                                                 first_arg_name,
273                                                 var_args);
274       va_end (var_args);
275
276       if (error)
277         {
278           g_warning ("gtk_container_add_with_args(): %s", error);
279           g_free (error);
280         }
281       else
282         {
283           GSList *slist_arg;
284           GSList *slist_info;
285
286           slist_arg = arg_list;
287           slist_info = info_list;
288           while (slist_arg)
289             {
290               gtk_container_arg_set (container, widget, slist_arg->data, slist_info->data);
291               slist_arg = slist_arg->next;
292               slist_info = slist_info->next;
293             }
294           gtk_args_collect_cleanup (arg_list, info_list);
295         }
296     }
297
298   gtk_widget_unref (widget);
299   gtk_widget_unref (GTK_WIDGET (container));
300 }
301
302 void
303 gtk_container_addv (GtkContainer      *container,
304                     GtkWidget         *widget,
305                     guint              n_args,
306                     GtkArg            *args)
307 {
308   g_return_if_fail (container != NULL);
309   g_return_if_fail (GTK_IS_CONTAINER (container));
310   g_return_if_fail (widget != NULL);
311   g_return_if_fail (GTK_IS_WIDGET (widget));
312   g_return_if_fail (widget->parent == NULL);
313
314   gtk_widget_ref (GTK_WIDGET (container));
315   gtk_widget_ref (widget);
316
317   gtk_signal_emit (GTK_OBJECT (container), container_signals[ADD], widget);
318   
319   if (widget->parent)
320     {
321       GtkArg *max_args;
322
323       for (max_args = args + n_args; args < max_args; args++)
324         gtk_container_arg_set (container, widget, args, NULL);
325     }
326
327   gtk_widget_unref (widget);
328   gtk_widget_unref (GTK_WIDGET (container));
329 }
330
331 void
332 gtk_container_child_setv (GtkContainer      *container,
333                           GtkWidget         *child,
334                           guint              n_args,
335                           GtkArg            *args)
336 {
337   GtkArg *max_args;
338
339   g_return_if_fail (container != NULL);
340   g_return_if_fail (GTK_IS_CONTAINER (container));
341   g_return_if_fail (child != NULL);
342   g_return_if_fail (GTK_IS_WIDGET (child));
343   g_return_if_fail (child->parent != NULL);
344   if (n_args)
345     g_return_if_fail (args != NULL);
346
347   for (max_args = args + n_args; args < max_args; args++)
348     gtk_container_arg_set (container, child, args, NULL);
349 }
350
351 void
352 gtk_container_child_getv (GtkContainer      *container,
353                           GtkWidget         *child,
354                           guint              n_args,
355                           GtkArg            *args)
356 {
357   GtkArg *max_args;
358
359   g_return_if_fail (container != NULL);
360   g_return_if_fail (GTK_IS_CONTAINER (container));
361   g_return_if_fail (child != NULL);
362   g_return_if_fail (GTK_IS_WIDGET (child));
363   g_return_if_fail (child->parent != NULL);
364   if (n_args)
365     g_return_if_fail (args != NULL);
366
367   for (max_args = args + n_args; args < max_args; args++)
368     gtk_container_arg_get (container, child, args, NULL);
369 }
370
371 void
372 gtk_container_child_set (GtkContainer      *container,
373                          GtkWidget         *child,
374                          const gchar       *first_arg_name,
375                          ...)
376 {
377   va_list var_args;
378   GSList *arg_list = NULL;
379   GSList *info_list = NULL;
380   gchar *error;
381   
382   g_return_if_fail (container != NULL);
383   g_return_if_fail (GTK_IS_CONTAINER (container));
384   g_return_if_fail (child != NULL);
385   g_return_if_fail (GTK_IS_WIDGET (child));
386   g_return_if_fail (child->parent != NULL);
387
388   va_start (var_args, first_arg_name);
389   error = gtk_container_child_args_collect (GTK_OBJECT_TYPE (container),
390                                             &arg_list,
391                                             &info_list,
392                                             first_arg_name,
393                                             var_args);
394   va_end (var_args);
395
396   if (error)
397     {
398       g_warning ("gtk_container_child_set(): %s", error);
399       g_free (error);
400     }
401   else
402     {
403       GSList *slist_arg;
404       GSList *slist_info;
405
406       slist_arg = arg_list;
407       slist_info = info_list;
408       while (slist_arg)
409         {
410           gtk_container_arg_set (container, child, slist_arg->data, slist_info->data);
411           slist_arg = slist_arg->next;
412           slist_info = slist_info->next;
413         }
414       gtk_args_collect_cleanup (arg_list, info_list);
415     }
416 }
417
418 void
419 gtk_container_arg_set (GtkContainer *container,
420                        GtkWidget    *child,
421                        GtkArg       *arg,
422                        GtkArgInfo   *info)
423 {
424   GtkContainerClass *class;
425   
426   g_return_if_fail (container != NULL);
427   g_return_if_fail (GTK_IS_CONTAINER (container));
428   g_return_if_fail (child != NULL);
429   g_return_if_fail (GTK_IS_WIDGET (child));
430   g_return_if_fail (arg != NULL);
431   
432   if (!info)
433     {
434       gchar *error;
435       
436       error = gtk_arg_get_info (GTK_OBJECT_TYPE (container),
437                                 container_child_arg_info_ht,
438                                 arg->name,
439                                 &info);
440       if (error)
441         {
442           g_warning ("gtk_container_arg_set(): %s", error);
443           g_free (error);
444           return;
445         }
446     }
447   g_return_if_fail (info->arg_flags & GTK_ARG_CHILD_ARG);
448   
449   if (! (info->arg_flags & GTK_ARG_WRITABLE))
450     {
451       g_warning ("gtk_container_arg_set(): argument \"%s\" is not writable",
452                  info->full_name);
453       return;
454     }
455   if (info->type != arg->type)
456     {
457       g_warning ("gtk_container_arg_set(): argument \"%s\" has invalid type `%s'",
458                  info->full_name,
459                  gtk_type_name (arg->type));
460       return;
461     }
462   
463   class = gtk_type_class (info->class_type);
464   g_assert (class->set_child_arg != NULL);
465   class->set_child_arg (container, child, arg, info->arg_id);
466 }
467
468 void
469 gtk_container_arg_get (GtkContainer *container,
470                        GtkWidget    *child,
471                        GtkArg       *arg,
472                        GtkArgInfo   *info)
473 {
474   GtkContainerClass *class;
475   
476   g_return_if_fail (container != NULL);
477   g_return_if_fail (GTK_IS_CONTAINER (container));
478   g_return_if_fail (child != NULL);
479   g_return_if_fail (GTK_IS_WIDGET (child));
480   g_return_if_fail (arg != NULL);
481   
482   if (!info)
483     {
484       gchar *error;
485       
486       error = gtk_arg_get_info (GTK_OBJECT_TYPE (container),
487                                 container_child_arg_info_ht,
488                                 arg->name,
489                                 &info);
490       if (error)
491         {
492           g_warning ("gtk_container_arg_get(): %s", error);
493           g_free (error);
494           arg->type = GTK_TYPE_INVALID;
495           return;
496         }
497     }
498   g_return_if_fail (info->arg_flags & GTK_ARG_CHILD_ARG);
499   
500   if (! (info->arg_flags & GTK_ARG_READABLE))
501     {
502       g_warning ("gtk_container_arg_get(): argument \"%s\" is not readable",
503                  info->full_name);
504       arg->type = GTK_TYPE_INVALID;
505       return;
506     }
507   
508   class = gtk_type_class (info->class_type);
509   g_assert (class->get_child_arg != NULL);
510   arg->type = info->type;
511   class->get_child_arg (container, child, arg, info->arg_id);
512 }
513
514 void
515 gtk_container_add_child_arg_type (const gchar       *arg_name,
516                                   GtkType            arg_type,
517                                   guint              arg_flags,
518                                   guint              arg_id)
519 {
520   g_return_if_fail (arg_name != NULL);
521   g_return_if_fail (arg_type > GTK_TYPE_NONE);
522   g_return_if_fail (arg_id > 0);
523   g_return_if_fail ((arg_flags & GTK_ARG_READWRITE) == GTK_ARG_READWRITE);
524   /* g_return_if_fail ((arg_flags & GTK_ARG_CHILD_ARG) != 0); */
525
526   arg_flags |= GTK_ARG_CHILD_ARG;
527   arg_flags &= GTK_ARG_MASK;
528
529   gtk_arg_type_new_static (GTK_TYPE_CONTAINER,
530                            arg_name,
531                            GTK_STRUCT_OFFSET (GtkContainerClass, n_child_args),
532                            container_child_arg_info_ht,
533                            arg_type,
534                            arg_flags,
535                            arg_id);
536 }
537
538 gchar*
539 gtk_container_child_args_collect (GtkType       object_type,
540                                   GSList      **arg_list_p,
541                                   GSList      **info_list_p,
542                                   const gchar  *first_arg_name,
543                                   va_list       var_args)
544 {
545   return gtk_args_collect (object_type,
546                            container_child_arg_info_ht,
547                            arg_list_p,
548                            info_list_p,
549                            first_arg_name,
550                            var_args);
551 }
552
553 gchar*
554 gtk_container_child_arg_get_info (GtkType       object_type,
555                                   const gchar  *arg_name,
556                                   GtkArgInfo  **info_p)
557 {
558   return gtk_arg_get_info (object_type,
559                            container_child_arg_info_ht,
560                            arg_name,
561                            info_p);
562 }
563
564 GtkArg*
565 gtk_container_query_child_args (GtkType            class_type,
566                                 guint32          **arg_flags,
567                                 guint             *n_args)
568 {
569   g_return_val_if_fail (n_args != NULL, NULL);
570   *n_args = 0;
571   g_return_val_if_fail (gtk_type_is_a (class_type, GTK_TYPE_CONTAINER), NULL);
572
573   return gtk_args_query (class_type, container_child_arg_info_ht, arg_flags, n_args);
574 }
575
576
577 static void
578 gtk_container_add_unimplemented (GtkContainer     *container,
579                                  GtkWidget        *widget)
580 {
581   g_warning ("GtkContainerClass::add not implemented for `%s'", gtk_type_name (GTK_OBJECT_TYPE (container)));
582 }
583
584 static void
585 gtk_container_remove_unimplemented (GtkContainer     *container,
586                                     GtkWidget        *widget)
587 {
588   g_warning ("GtkContainerClass::remove not implemented for `%s'", gtk_type_name (GTK_OBJECT_TYPE (container)));
589 }
590
591 static void
592 gtk_container_init (GtkContainer *container)
593 {
594   container->focus_child = NULL;
595   container->border_width = 0;
596   container->need_resize = FALSE;
597   container->resize_mode = GTK_RESIZE_PARENT;
598   container->resize_widgets = NULL;
599 }
600
601 static void
602 gtk_container_destroy (GtkObject *object)
603 {
604   GtkContainer *container;
605
606   g_return_if_fail (object != NULL);
607   g_return_if_fail (GTK_IS_CONTAINER (object));
608
609   container = GTK_CONTAINER (object);
610   
611   if (GTK_CONTAINER_RESIZE_PENDING (container))
612     {
613       container_resize_queue = g_slist_remove (container_resize_queue, container);
614       GTK_PRIVATE_UNSET_FLAG (container, GTK_RESIZE_PENDING);
615     }
616   gtk_container_clear_resize_widgets (container);
617   
618   gtk_container_foreach (container, (GtkCallback) gtk_widget_destroy, NULL);
619   
620   if (GTK_OBJECT_CLASS (parent_class)->destroy)
621     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
622 }
623
624 static void
625 gtk_container_set_arg (GtkObject    *object,
626                        GtkArg       *arg,
627                        guint         arg_id)
628 {
629   GtkContainer *container;
630
631   container = GTK_CONTAINER (object);
632
633   switch (arg_id)
634     {
635     case ARG_BORDER_WIDTH:
636       gtk_container_set_border_width (container, GTK_VALUE_ULONG (*arg));
637       break;
638     case ARG_RESIZE_MODE:
639       gtk_container_set_resize_mode (container, GTK_VALUE_ENUM (*arg));
640       break;
641     case ARG_CHILD:
642       gtk_container_add (container, GTK_WIDGET (GTK_VALUE_OBJECT (*arg)));
643       break;
644     default:
645       break;
646     }
647 }
648
649 static void
650 gtk_container_get_arg (GtkObject    *object,
651                        GtkArg       *arg,
652                        guint         arg_id)
653 {
654   GtkContainer *container;
655
656   container = GTK_CONTAINER (object);
657   
658   switch (arg_id)
659     {
660     case ARG_BORDER_WIDTH:
661       GTK_VALUE_ULONG (*arg) = container->border_width;
662       break;
663     case ARG_RESIZE_MODE:
664       GTK_VALUE_ENUM (*arg) = container->resize_mode;
665       break;
666     default:
667       arg->type = GTK_TYPE_INVALID;
668       break;
669     }
670 }
671
672 void
673 gtk_container_set_border_width (GtkContainer *container,
674                                 guint         border_width)
675 {
676   g_return_if_fail (container != NULL);
677   g_return_if_fail (GTK_IS_CONTAINER (container));
678
679   if (container->border_width != border_width)
680     {
681       container->border_width = border_width;
682
683       if (GTK_WIDGET_REALIZED (container))
684         gtk_widget_queue_resize (GTK_WIDGET (container));
685     }
686 }
687
688 void
689 gtk_container_add (GtkContainer *container,
690                    GtkWidget    *widget)
691 {
692   g_return_if_fail (container != NULL);
693   g_return_if_fail (GTK_IS_CONTAINER (container));
694   g_return_if_fail (widget != NULL);
695   g_return_if_fail (GTK_IS_WIDGET (widget));
696   g_return_if_fail (widget->parent == NULL);
697
698   gtk_signal_emit (GTK_OBJECT (container), container_signals[ADD], widget);
699 }
700
701 void
702 gtk_container_remove (GtkContainer *container,
703                       GtkWidget    *widget)
704 {
705   g_return_if_fail (container != NULL);
706   g_return_if_fail (GTK_IS_CONTAINER (container));
707   g_return_if_fail (widget != NULL);
708   g_return_if_fail (GTK_IS_WIDGET (widget));
709   g_return_if_fail (widget->parent == GTK_WIDGET (container));
710   
711   gtk_signal_emit (GTK_OBJECT (container), container_signals[REMOVE], widget);
712 }
713
714 void
715 gtk_container_block_resize (GtkContainer *container)
716 {
717   g_return_if_fail (container != NULL);
718   g_return_if_fail (GTK_IS_CONTAINER (container));
719
720   g_message ("gtk_container_block_resize() is deprecated");
721 }
722
723 void
724 gtk_container_unblock_resize (GtkContainer *container)
725 {
726   g_return_if_fail (container != NULL);
727   g_return_if_fail (GTK_IS_CONTAINER (container));
728   
729   g_message ("gtk_container_unblock_resize() is deprecated");
730 }
731
732 void
733 gtk_container_clear_resize_widgets (GtkContainer *container)
734 {
735   GSList *node;
736
737   g_return_if_fail (container != NULL);
738   g_return_if_fail (GTK_IS_CONTAINER (container));
739
740   node = container->resize_widgets;
741
742   if (node)
743     gtk_signal_disconnect_by_func (GTK_OBJECT (container),
744                                    GTK_SIGNAL_FUNC (gtk_container_clear_resize_widgets),
745                                    NULL);
746
747   while (node)
748     {
749       GtkWidget *widget = node->data;
750
751       GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
752       node = node->next;
753     }
754   
755   g_slist_free (container->resize_widgets);
756   container->resize_widgets = NULL;
757 }
758
759 void
760 gtk_container_set_resize_mode (GtkContainer  *container,
761                                GtkResizeMode  resize_mode)
762 {
763   g_return_if_fail (container != NULL);
764   g_return_if_fail (GTK_IS_CONTAINER (container));
765   g_return_if_fail (resize_mode <= GTK_RESIZE_IMMEDIATE);
766   
767   if (GTK_WIDGET_TOPLEVEL (container) &&
768       resize_mode == GTK_RESIZE_PARENT)
769     resize_mode = GTK_RESIZE_QUEUE;
770   
771   if (container->resize_mode != resize_mode)
772     {
773       container->resize_mode = resize_mode;
774       
775       if (resize_mode == GTK_RESIZE_IMMEDIATE)
776         gtk_container_check_resize (container);
777       else
778         {
779           gtk_container_clear_resize_widgets (container);
780           gtk_widget_queue_resize (GTK_WIDGET (container));
781         }
782     }
783 }
784
785 gint    
786 gtk_container_need_resize (GtkContainer     *container)
787 {
788   g_message ("gtk_container_need_resize() is deprecated");
789
790   gtk_container_check_resize (container);
791   return FALSE;
792 }
793
794 static GtkContainer*
795 gtk_container_get_resize_container (GtkContainer *container)
796 {
797   GtkWidget *widget;
798
799   widget = GTK_WIDGET (container);
800
801   while (widget->parent)
802     {
803       widget = widget->parent;
804       if (GTK_IS_RESIZE_CONTAINER (widget) && !GTK_WIDGET_RESIZE_NEEDED (widget))
805         break;
806     }
807
808   return GTK_IS_RESIZE_CONTAINER (widget) ? (GtkContainer*) widget : NULL;
809 }
810
811 static gboolean
812 gtk_container_idle_sizer (gpointer data)
813 {
814   /* we may be invoked with a container_resize_queue of NULL, because
815    * queue_resize could have been adding an extra idle function while
816    * the queue still got processed. we better just ignore such case
817    * than trying to explicitely work around them with some extra flags,
818    * sine it doesn't cause any actual harm.
819    */
820   while (container_resize_queue)
821     {
822       GSList *slist;
823       GtkWidget *widget;
824
825       slist = container_resize_queue;
826       container_resize_queue = slist->next;
827       widget = slist->data;
828       g_slist_free_1 (slist);
829
830       GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_PENDING);
831       gtk_container_check_resize (GTK_CONTAINER (widget));
832     }
833   
834   return FALSE;
835 }
836
837 void
838 gtk_container_queue_resize (GtkContainer *container)
839 {
840   GtkContainer *resize_container;
841   
842   g_return_if_fail (container != NULL);
843   g_return_if_fail (GTK_IS_CONTAINER (container));
844
845   if (GTK_OBJECT_DESTROYED (container) ||
846       GTK_WIDGET_RESIZE_NEEDED (container))
847     return;
848
849   if (GTK_IS_RESIZE_CONTAINER (container))
850     gtk_container_clear_resize_widgets (container);
851
852   resize_container = gtk_container_get_resize_container (container);
853
854   if (resize_container)
855     {
856       if (GTK_WIDGET_VISIBLE (resize_container))
857         {
858           switch (resize_container->resize_mode)
859             {
860             case GTK_RESIZE_QUEUE:
861               if (!GTK_CONTAINER_RESIZE_PENDING (resize_container))
862                 {
863                   GTK_PRIVATE_SET_FLAG (resize_container, GTK_RESIZE_PENDING);
864                   if (container_resize_queue == NULL)
865                     gtk_idle_add_priority (GTK_PRIORITY_INTERNAL - 1,
866                                            gtk_container_idle_sizer,
867                                            NULL);
868                   container_resize_queue = g_slist_prepend (container_resize_queue, resize_container);
869                 }
870               
871               GTK_PRIVATE_SET_FLAG (container, GTK_RESIZE_NEEDED);
872               if (!resize_container->resize_widgets)
873                 gtk_signal_connect (GTK_OBJECT (resize_container),
874                                     "size_allocate",
875                                     GTK_SIGNAL_FUNC (gtk_container_clear_resize_widgets),
876                                     NULL);
877               resize_container->resize_widgets =
878                 g_slist_prepend (resize_container->resize_widgets, container);
879               break;
880
881             case GTK_RESIZE_IMMEDIATE:
882               GTK_PRIVATE_SET_FLAG (container, GTK_RESIZE_NEEDED);
883               if (!resize_container->resize_widgets)
884                 gtk_signal_connect (GTK_OBJECT (resize_container),
885                                     "size_allocate",
886                                     GTK_SIGNAL_FUNC (gtk_container_clear_resize_widgets),
887                                     NULL);
888               resize_container->resize_widgets =
889                 g_slist_prepend (resize_container->resize_widgets, container);
890               gtk_container_check_resize (resize_container);
891               break;
892
893             case GTK_RESIZE_PARENT:
894               /* Ignore */
895               break;
896             }
897         }
898       else
899         {
900           /* We need to let hidden toplevels know that something
901            * changed while they where hidden. For other resize containers,
902            * they will get resized when they are shown.
903            */
904           if (GTK_WIDGET_TOPLEVEL (resize_container))
905             gtk_container_check_resize (resize_container);
906         }
907     }
908 }
909
910 void
911 gtk_container_check_resize (GtkContainer *container)
912 {
913   g_return_if_fail (container != NULL);
914   g_return_if_fail (GTK_IS_CONTAINER (container));
915
916   gtk_signal_emit (GTK_OBJECT (container), container_signals[CHECK_RESIZE]);
917 }
918
919 static void
920 gtk_container_real_check_resize (GtkContainer *container)
921 {
922   GtkWidget *widget;
923   
924   g_return_if_fail (container != NULL);
925   g_return_if_fail (GTK_IS_CONTAINER (container));
926   
927   widget = GTK_WIDGET (container);
928   
929   gtk_widget_size_request (widget, &widget->requisition);
930   
931   if (widget->requisition.width > widget->allocation.width ||
932       widget->requisition.height > widget->allocation.height)
933     {
934       if (GTK_IS_RESIZE_CONTAINER (container))
935         {
936           gtk_widget_size_allocate (GTK_WIDGET (container),
937                                     &GTK_WIDGET (container)->allocation);
938           gtk_widget_queue_draw (GTK_WIDGET (container));
939         }
940       else
941         gtk_widget_queue_resize (widget);
942     }
943   else
944     {
945       gtk_container_resize_children (container);
946     }
947 }
948
949 /* The container hasn't changed size but one of its children
950  *  queued a resize request. Which means that the allocation
951  *  is not sufficient for the requisition of some child.
952  *  We've already performed a size request at this point,
953  *  so we simply need to run through the list of resize
954  *  widgets and reallocate their sizes appropriately. We
955  *  make the optimization of not performing reallocation
956  *  for a widget who also has a parent in the resize widgets
957  *  list. GTK_RESIZE_NEEDED is used for flagging those
958  *  parents inside this function.
959  */
960 void
961 gtk_container_resize_children (GtkContainer *container)
962 {
963   GtkWidget *widget;
964   GtkWidget *resize_container;
965   GSList *resize_widgets;
966   GSList *resize_containers;
967   GSList *node;
968   
969   /* resizing invariants:
970    * toplevels have *always* resize_mode != GTK_RESIZE_PARENT set.
971    * containers with resize_mode==GTK_RESIZE_PARENT have to have resize_widgets
972    * set to NULL.
973    * containers that are flagged RESIZE_NEEDED must have resize_widgets set to
974    * NULL, or are toplevels (thus have ->parent set to NULL).
975    * widgets that are in some container->resize_widgets list must be flagged with
976    * RESIZE_NEEDED.
977    * widgets that have RESIZE_NEEDED set must be referenced in some
978    * GTK_IS_RESIZE_CONTAINER (container)->resize_widgets list.
979    * containers that have an idle sizer pending must be flagged with
980    * RESIZE_PENDING.
981    */
982   
983   g_return_if_fail (container != NULL);
984   g_return_if_fail (GTK_IS_CONTAINER (container));
985
986   /* we first check out if we actually need to perform a resize,
987    * which is not the case if we got another container queued for
988    * a resize in our anchestry. also we can skip the whole
989    * resize_widgets checks if we are a toplevel and NEED_RESIZE.
990    * this code implies that our allocation is sufficient for our
991    * requisition, since otherwise we would NEED_RESIZE.
992    */
993   resize_container = GTK_WIDGET (container);
994   while (resize_container)
995     {
996       if (GTK_WIDGET_RESIZE_NEEDED (resize_container))
997         break;
998       resize_container = resize_container->parent;
999     }
1000   if (resize_container)
1001     {
1002       /* queue_resize and size_allocate both clear our
1003        * resize_widgets list.
1004        */
1005       if (resize_container->parent)
1006         gtk_container_queue_resize (container);
1007       else
1008         {
1009           gtk_widget_size_allocate (GTK_WIDGET (container),
1010                                     &GTK_WIDGET (container)->allocation);
1011           gtk_widget_queue_draw (GTK_WIDGET (container));
1012         }
1013       return;
1014     }
1015
1016   resize_container = GTK_WIDGET (container);
1017
1018   /* we now walk the anchestry for all resize widgets as long
1019    * as they are our children and as long as their allocation
1020    * is insufficient, since we don't need to reallocate below that.
1021    */
1022   resize_widgets = container->resize_widgets;
1023   if (resize_widgets)
1024     gtk_signal_disconnect_by_func (GTK_OBJECT (container),
1025                                    GTK_SIGNAL_FUNC (gtk_container_clear_resize_widgets),
1026                                    NULL);
1027   container->resize_widgets = NULL;
1028   for (node = resize_widgets; node; node = node->next)
1029     {
1030       widget = node->data;
1031
1032       GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
1033
1034       while (widget->parent != resize_container &&
1035              ((widget->allocation.width < widget->requisition.width) ||
1036               (widget->allocation.height < widget->requisition.height)))
1037         widget = widget->parent;
1038       
1039       GTK_PRIVATE_SET_FLAG (widget, GTK_RESIZE_NEEDED);
1040       node->data = widget;
1041     }
1042
1043   /* for the newly setup resize_widgets list, we now walk each widget's
1044    * anchestry to sort those widgets out that have RESIZE_NEEDED parents.
1045    * we can safely stop the walk if we are the parent, since we checked
1046    * our own anchestry already.
1047    */
1048   resize_containers = NULL;
1049   for (node = resize_widgets; node; node = node->next)
1050     {
1051       GtkWidget *parent;
1052
1053       widget = node->data;
1054       
1055       if (!GTK_WIDGET_RESIZE_NEEDED (widget))
1056         continue;
1057       
1058       parent = widget->parent;
1059       
1060       while (parent != resize_container)
1061         {
1062           if (GTK_WIDGET_RESIZE_NEEDED (parent))
1063             {
1064               GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
1065               widget = parent;
1066             }
1067           parent = parent->parent;
1068         }
1069       
1070       if (!g_slist_find (resize_containers, widget))
1071         {
1072           resize_containers = g_slist_prepend (resize_containers, widget);
1073           gtk_widget_ref (widget);
1074         }
1075     }
1076   g_slist_free (resize_widgets);
1077   
1078   for (node = resize_containers; node; node = node->next)
1079     {
1080       widget = node->data;
1081       
1082       GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
1083       gtk_widget_size_allocate (widget, &widget->allocation);
1084       gtk_widget_queue_draw (widget);
1085       gtk_widget_unref (widget);
1086     }
1087   g_slist_free (resize_containers);
1088 }
1089
1090 void
1091 gtk_container_forall (GtkContainer *container,
1092                       GtkCallback   callback,
1093                       gpointer      callback_data)
1094 {
1095   GtkContainerClass *class;
1096
1097   g_return_if_fail (container != NULL);
1098   g_return_if_fail (GTK_IS_CONTAINER (container));
1099   g_return_if_fail (callback != NULL);
1100
1101   class = GTK_CONTAINER_CLASS (GTK_OBJECT (container)->klass);
1102
1103   if (class->forall)
1104     class->forall (container, TRUE, callback, callback_data);
1105 }
1106
1107 void
1108 gtk_container_foreach (GtkContainer *container,
1109                        GtkCallback   callback,
1110                        gpointer      callback_data)
1111 {
1112   GtkContainerClass *class;
1113   
1114   g_return_if_fail (container != NULL);
1115   g_return_if_fail (GTK_IS_CONTAINER (container));
1116   g_return_if_fail (callback != NULL);
1117
1118   class = GTK_CONTAINER_CLASS (GTK_OBJECT (container)->klass);
1119
1120   if (class->forall)
1121     class->forall (container, FALSE, callback, callback_data);
1122 }
1123
1124 typedef struct _GtkForeachData  GtkForeachData;
1125 struct _GtkForeachData
1126 {
1127   GtkObject         *container;
1128   GtkCallbackMarshal callback;
1129   gpointer           callback_data;
1130 };
1131
1132 static void
1133 gtk_container_foreach_unmarshal (GtkWidget *child,
1134                                  gpointer data)
1135 {
1136   GtkForeachData *fdata = (GtkForeachData*) data;
1137   GtkArg args[2];
1138   
1139   /* first argument */
1140   args[0].name = NULL;
1141   args[0].type = GTK_OBJECT(child)->klass->type;
1142   GTK_VALUE_OBJECT(args[0]) = GTK_OBJECT (child);
1143   
1144   /* location for return value */
1145   args[1].name = NULL;
1146   args[1].type = GTK_TYPE_NONE;
1147   
1148   fdata->callback (fdata->container, fdata->callback_data, 1, args);
1149 }
1150
1151 void
1152 gtk_container_foreach_interp (GtkContainer       *container,
1153                               GtkCallbackMarshal  marshal,
1154                               gpointer            callback_data,
1155                               GtkDestroyNotify    notify)
1156 {
1157   gtk_container_foreach_full (container, NULL, marshal, 
1158                               callback_data, notify);
1159 }
1160
1161 void
1162 gtk_container_foreach_full (GtkContainer       *container,
1163                             GtkCallback         callback,
1164                             GtkCallbackMarshal  marshal,
1165                             gpointer            callback_data,
1166                             GtkDestroyNotify    notify)
1167 {
1168   g_return_if_fail (container != NULL);
1169   g_return_if_fail (GTK_IS_CONTAINER (container));
1170
1171   if (marshal)
1172     {
1173       GtkForeachData fdata;
1174   
1175       fdata.container     = GTK_OBJECT (container);
1176       fdata.callback      = marshal;
1177       fdata.callback_data = callback_data;
1178
1179       gtk_container_foreach (container, gtk_container_foreach_unmarshal, &fdata);
1180     }
1181   else
1182     {
1183       g_return_if_fail (callback != NULL);
1184
1185       gtk_container_foreach (container, callback, &callback_data);
1186     }
1187
1188   if (notify)
1189     notify (callback_data);
1190 }
1191
1192 gint
1193 gtk_container_focus (GtkContainer     *container,
1194                      GtkDirectionType  direction)
1195 {
1196   gint return_val;
1197
1198   g_return_val_if_fail (container != NULL, FALSE);
1199   g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
1200   
1201   gtk_signal_emit (GTK_OBJECT (container),
1202                    container_signals[FOCUS],
1203                    direction, &return_val);
1204
1205   return return_val;
1206 }
1207
1208 void
1209 gtk_container_set_focus_child (GtkContainer     *container,
1210                                GtkWidget          *widget)
1211 {
1212   g_return_if_fail (container != NULL);
1213   g_return_if_fail (GTK_IS_CONTAINER (container));
1214   if (widget)
1215     g_return_if_fail (GTK_IS_WIDGET (container));
1216
1217   gtk_signal_emit (GTK_OBJECT (container), container_signals[SET_FOCUS_CHILD], widget);
1218 }
1219
1220 GList*
1221 gtk_container_children (GtkContainer *container)
1222 {
1223   GList *children;
1224
1225   children = NULL;
1226
1227   gtk_container_foreach (container,
1228                          gtk_container_children_callback,
1229                          &children);
1230
1231   return g_list_reverse (children);
1232 }
1233
1234 void
1235 gtk_container_register_toplevel (GtkContainer *container)
1236 {
1237   g_return_if_fail (container != NULL);
1238   
1239   toplevel_list = g_list_prepend (toplevel_list, container);
1240   
1241   gtk_widget_ref (GTK_WIDGET (container));
1242   gtk_object_sink (GTK_OBJECT (container));
1243 }
1244
1245 void
1246 gtk_container_unregister_toplevel (GtkContainer *container)
1247 {
1248   GList *node;
1249
1250   g_return_if_fail (container != NULL);
1251
1252   node = g_list_find (toplevel_list, container);
1253   g_return_if_fail (node != NULL);
1254
1255   toplevel_list = g_list_remove_link (toplevel_list, node);
1256   g_list_free_1 (node);
1257
1258   gtk_widget_unref (GTK_WIDGET (container));
1259 }
1260
1261 GList*
1262 gtk_container_get_toplevels (void)
1263 {
1264   /* XXX: fixme we should ref all these widgets and duplicate
1265    * the list.
1266    */
1267   return toplevel_list;
1268 }
1269
1270 static void
1271 gtk_container_child_position_callback (GtkWidget *widget,
1272                                        gpointer   client_data)
1273 {
1274   struct {
1275     GtkWidget *child;
1276     guint i;
1277     guint index;
1278   } *data = client_data;
1279
1280   data->i++;
1281   if (data->child == widget)
1282     data->index = data->i;
1283 }
1284
1285 static gchar*
1286 gtk_container_child_default_composite_name (GtkContainer *container,
1287                                             GtkWidget    *child)
1288 {
1289   struct {
1290     GtkWidget *child;
1291     guint i;
1292     guint index;
1293   } data;
1294   gchar *name;
1295
1296   /* fallback implementation */
1297   data.child = child;
1298   data.i = 0;
1299   data.index = 0;
1300   gtk_container_forall (container,
1301                         gtk_container_child_position_callback,
1302                         &data);
1303   
1304   name = g_strdup_printf ("%s-%u",
1305                           gtk_type_name (GTK_OBJECT_TYPE (child)),
1306                           data.index);
1307
1308   return name;
1309 }
1310
1311 gchar*
1312 gtk_container_child_composite_name (GtkContainer *container,
1313                                     GtkWidget    *child)
1314 {
1315   g_return_val_if_fail (container != NULL, NULL);
1316   g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
1317   g_return_val_if_fail (child != NULL, NULL);
1318   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
1319   g_return_val_if_fail (child->parent == GTK_WIDGET (container), NULL);
1320
1321   if (GTK_WIDGET_COMPOSITE_CHILD (child))
1322     {
1323       static GQuark quark_composite_name = 0;
1324       gchar *name;
1325
1326       if (!quark_composite_name)
1327         quark_composite_name = g_quark_from_static_string ("gtk-composite-name");
1328
1329       name = gtk_object_get_data_by_id (GTK_OBJECT (child), quark_composite_name);
1330       if (!name)
1331         {
1332           GtkContainerClass *class;
1333
1334           class = GTK_CONTAINER_CLASS (GTK_OBJECT (container)->klass);
1335           if (class->composite_name)
1336             name = class->composite_name (container, child);
1337         }
1338       else
1339         name = g_strdup (name);
1340
1341       return name;
1342     }
1343   
1344   return NULL;
1345 }
1346
1347 void
1348 gtk_container_real_set_focus_child (GtkContainer     *container,
1349                                     GtkWidget        *child)
1350 {
1351   g_return_if_fail (container != NULL);
1352   g_return_if_fail (GTK_IS_CONTAINER (container));
1353   if (child)
1354     g_return_if_fail (GTK_IS_WIDGET (child));
1355
1356   if (child != container->focus_child)
1357     {
1358       if (container->focus_child)
1359         gtk_widget_unref (container->focus_child);
1360       container->focus_child = child;
1361       if (container->focus_child)
1362         gtk_widget_ref (container->focus_child);
1363     }
1364
1365
1366   /* check for h/v adjustments
1367    */
1368   if (container->focus_child)
1369     {
1370       GtkAdjustment *adjustment;
1371       
1372       adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container), vadjustment_key_id);
1373       if (adjustment)
1374         gtk_adjustment_clamp_page (adjustment,
1375                                    container->focus_child->allocation.y,
1376                                    (container->focus_child->allocation.y +
1377                                     container->focus_child->allocation.height));
1378
1379       adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container), hadjustment_key_id);
1380       if (adjustment)
1381         gtk_adjustment_clamp_page (adjustment,
1382                                    container->focus_child->allocation.x,
1383                                    (container->focus_child->allocation.x +
1384                                     container->focus_child->allocation.width));
1385     }
1386 }
1387
1388 static gint
1389 gtk_container_real_focus (GtkContainer     *container,
1390                           GtkDirectionType  direction)
1391 {
1392   GList *children;
1393   GList *tmp_list;
1394   GList *tmp_list2;
1395   gint return_val;
1396
1397   g_return_val_if_fail (container != NULL, FALSE);
1398   g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
1399
1400   /* Fail if the container is inappropriate for focus movement
1401    */
1402   if (!GTK_WIDGET_DRAWABLE (container) ||
1403       !GTK_WIDGET_SENSITIVE (container))
1404     return FALSE;
1405
1406   return_val = FALSE;
1407
1408   if (GTK_WIDGET_CAN_FOCUS (container))
1409     {
1410       gtk_widget_grab_focus (GTK_WIDGET (container));
1411       return_val = TRUE;
1412     }
1413   else
1414     {
1415       /* Get a list of the containers children
1416        */
1417       children = NULL;
1418       gtk_container_forall (container,
1419                             gtk_container_children_callback,
1420                             &children);
1421       children = g_list_reverse (children);
1422       /* children = gtk_container_children (container); */
1423
1424       if (children)
1425         {
1426           /* Remove any children which are inappropriate for focus movement
1427            */
1428           tmp_list = children;
1429           while (tmp_list)
1430             {
1431               if (GTK_WIDGET_SENSITIVE (tmp_list->data) &&
1432                   GTK_WIDGET_DRAWABLE (tmp_list->data) &&
1433                   (GTK_IS_CONTAINER (tmp_list->data) || GTK_WIDGET_CAN_FOCUS (tmp_list->data)))
1434                 tmp_list = tmp_list->next;
1435               else
1436                 {
1437                   tmp_list2 = tmp_list;
1438                   tmp_list = tmp_list->next;
1439                   
1440                   children = g_list_remove_link (children, tmp_list2);
1441                   g_list_free_1 (tmp_list2);
1442                 }
1443             }
1444
1445           switch (direction)
1446             {
1447             case GTK_DIR_TAB_FORWARD:
1448             case GTK_DIR_TAB_BACKWARD:
1449               return_val = gtk_container_focus_tab (container, children, direction);
1450               break;
1451             case GTK_DIR_UP:
1452             case GTK_DIR_DOWN:
1453               return_val = gtk_container_focus_up_down (container, children, direction);
1454               break;
1455             case GTK_DIR_LEFT:
1456             case GTK_DIR_RIGHT:
1457               return_val = gtk_container_focus_left_right (container, children, direction);
1458               break;
1459             }
1460
1461           g_list_free (children);
1462         }
1463     }
1464
1465   return return_val;
1466 }
1467
1468 static gint
1469 gtk_container_focus_tab (GtkContainer     *container,
1470                          GList            *children,
1471                          GtkDirectionType  direction)
1472 {
1473   GtkWidget *child;
1474   GtkWidget *child2;
1475   GList *tmp_list;
1476   guint length;
1477   guint i, j;
1478
1479   length = g_list_length (children);
1480
1481   /* sort the children in the y direction */
1482   for (i = 1; i < length; i++)
1483     {
1484       j = i;
1485       tmp_list = g_list_nth (children, j);
1486       child = tmp_list->data;
1487
1488       while (j > 0)
1489         {
1490           child2 = tmp_list->prev->data;
1491           if (child->allocation.y < child2->allocation.y)
1492             {
1493               tmp_list->data = tmp_list->prev->data;
1494               tmp_list = tmp_list->prev;
1495               j--;
1496             }
1497           else
1498             break;
1499         }
1500
1501       tmp_list->data = child;
1502     }
1503
1504   /* sort the children in the x direction while
1505    *  maintaining the y direction sort.
1506    */
1507   for (i = 1; i < length; i++)
1508     {
1509       j = i;
1510       tmp_list = g_list_nth (children, j);
1511       child = tmp_list->data;
1512
1513       while (j > 0)
1514         {
1515           child2 = tmp_list->prev->data;
1516           if ((child->allocation.x < child2->allocation.x) &&
1517               (child->allocation.y == child2->allocation.y))
1518             {
1519               tmp_list->data = tmp_list->prev->data;
1520               tmp_list = tmp_list->prev;
1521               j--;
1522             }
1523           else
1524             break;
1525         }
1526
1527       tmp_list->data = child;
1528     }
1529
1530   /* if we are going backwards then reverse the order
1531    *  of the children.
1532    */
1533   if (direction == GTK_DIR_TAB_BACKWARD)
1534     children = g_list_reverse (children);
1535
1536   return gtk_container_focus_move (container, children, direction);
1537 }
1538
1539 static gint
1540 gtk_container_focus_up_down (GtkContainer     *container,
1541                              GList            *children,
1542                              GtkDirectionType  direction)
1543 {
1544   GtkWidget *child;
1545   GtkWidget *child2;
1546   GList *tmp_list;
1547   gint dist1, dist2;
1548   gint focus_x;
1549   gint focus_width;
1550   guint length;
1551   guint i, j;
1552
1553   /* return failure if there isn't a focus child */
1554   if (container->focus_child)
1555     {
1556       focus_width = container->focus_child->allocation.width / 2;
1557       focus_x = container->focus_child->allocation.x + focus_width;
1558     }
1559   else
1560     {
1561       focus_width = GTK_WIDGET (container)->allocation.width;
1562       if (GTK_WIDGET_NO_WINDOW (container))
1563         focus_x = GTK_WIDGET (container)->allocation.x;
1564       else
1565         focus_x = 0;
1566     }
1567
1568   length = g_list_length (children);
1569
1570   /* sort the children in the y direction */
1571   for (i = 1; i < length; i++)
1572     {
1573       j = i;
1574       tmp_list = g_list_nth (children, j);
1575       child = tmp_list->data;
1576
1577       while (j > 0)
1578         {
1579           child2 = tmp_list->prev->data;
1580           if (child->allocation.y < child2->allocation.y)
1581             {
1582               tmp_list->data = tmp_list->prev->data;
1583               tmp_list = tmp_list->prev;
1584               j--;
1585             }
1586           else
1587             break;
1588         }
1589
1590       tmp_list->data = child;
1591     }
1592
1593   /* sort the children in distance in the x direction
1594    *  in distance from the current focus child while maintaining the
1595    *  sort in the y direction
1596    */
1597   for (i = 1; i < length; i++)
1598     {
1599       j = i;
1600       tmp_list = g_list_nth (children, j);
1601       child = tmp_list->data;
1602       dist1 = (child->allocation.x + child->allocation.width / 2) - focus_x;
1603
1604       while (j > 0)
1605         {
1606           child2 = tmp_list->prev->data;
1607           dist2 = (child2->allocation.x + child2->allocation.width / 2) - focus_x;
1608
1609           if ((dist1 < dist2) &&
1610               (child->allocation.y >= child2->allocation.y))
1611             {
1612               tmp_list->data = tmp_list->prev->data;
1613               tmp_list = tmp_list->prev;
1614               j--;
1615             }
1616           else
1617             break;
1618         }
1619
1620       tmp_list->data = child;
1621     }
1622
1623   /* go and invalidate any widget which is too
1624    *  far from the focus widget.
1625    */
1626   if (!container->focus_child &&
1627       (direction == GTK_DIR_UP))
1628     focus_x += focus_width;
1629
1630   tmp_list = children;
1631   while (tmp_list)
1632     {
1633       child = tmp_list->data;
1634
1635       dist1 = (child->allocation.x + child->allocation.width / 2) - focus_x;
1636       if (((direction == GTK_DIR_DOWN) && (dist1 < 0)) ||
1637           ((direction == GTK_DIR_UP) && (dist1 > 0)))
1638         tmp_list->data = NULL;
1639
1640       tmp_list = tmp_list->next;
1641     }
1642
1643   if (direction == GTK_DIR_UP)
1644     children = g_list_reverse (children);
1645
1646   return gtk_container_focus_move (container, children, direction);
1647 }
1648
1649 static gint
1650 gtk_container_focus_left_right (GtkContainer     *container,
1651                                 GList            *children,
1652                                 GtkDirectionType  direction)
1653 {
1654   GtkWidget *child;
1655   GtkWidget *child2;
1656   GList *tmp_list;
1657   gint dist1, dist2;
1658   gint focus_y;
1659   gint focus_height;
1660   guint length;
1661   guint i, j;
1662
1663   /* return failure if there isn't a focus child */
1664   if (container->focus_child)
1665     {
1666       focus_height = container->focus_child->allocation.height / 2;
1667       focus_y = container->focus_child->allocation.y + focus_height;
1668     }
1669   else
1670     {
1671       focus_height = GTK_WIDGET (container)->allocation.height;
1672       if (GTK_WIDGET_NO_WINDOW (container))
1673         focus_y = GTK_WIDGET (container)->allocation.y;
1674       else
1675         focus_y = 0;
1676     }
1677
1678   length = g_list_length (children);
1679
1680   /* sort the children in the x direction */
1681   for (i = 1; i < length; i++)
1682     {
1683       j = i;
1684       tmp_list = g_list_nth (children, j);
1685       child = tmp_list->data;
1686
1687       while (j > 0)
1688         {
1689           child2 = tmp_list->prev->data;
1690           if (child->allocation.x < child2->allocation.x)
1691             {
1692               tmp_list->data = tmp_list->prev->data;
1693               tmp_list = tmp_list->prev;
1694               j--;
1695             }
1696           else
1697             break;
1698         }
1699
1700       tmp_list->data = child;
1701     }
1702
1703   /* sort the children in distance in the y direction
1704    *  in distance from the current focus child while maintaining the
1705    *  sort in the x direction
1706    */
1707   for (i = 1; i < length; i++)
1708     {
1709       j = i;
1710       tmp_list = g_list_nth (children, j);
1711       child = tmp_list->data;
1712       dist1 = (child->allocation.y + child->allocation.height / 2) - focus_y;
1713
1714       while (j > 0)
1715         {
1716           child2 = tmp_list->prev->data;
1717           dist2 = (child2->allocation.y + child2->allocation.height / 2) - focus_y;
1718
1719           if ((dist1 < dist2) &&
1720               (child->allocation.x >= child2->allocation.x))
1721             {
1722               tmp_list->data = tmp_list->prev->data;
1723               tmp_list = tmp_list->prev;
1724               j--;
1725             }
1726           else
1727             break;
1728         }
1729
1730       tmp_list->data = child;
1731     }
1732
1733   /* go and invalidate any widget which is too
1734    *  far from the focus widget.
1735    */
1736   if (!container->focus_child &&
1737       (direction == GTK_DIR_LEFT))
1738     focus_y += focus_height;
1739
1740   tmp_list = children;
1741   while (tmp_list)
1742     {
1743       child = tmp_list->data;
1744
1745       dist1 = (child->allocation.y + child->allocation.height / 2) - focus_y;
1746       if (((direction == GTK_DIR_RIGHT) && (dist1 < 0)) ||
1747           ((direction == GTK_DIR_LEFT) && (dist1 > 0)))
1748         tmp_list->data = NULL;
1749
1750       tmp_list = tmp_list->next;
1751     }
1752
1753   if (direction == GTK_DIR_LEFT)
1754     children = g_list_reverse (children);
1755
1756   return gtk_container_focus_move (container, children, direction);
1757 }
1758
1759 static gint
1760 gtk_container_focus_move (GtkContainer     *container,
1761                           GList            *children,
1762                           GtkDirectionType  direction)
1763 {
1764   GtkWidget *focus_child;
1765   GtkWidget *child;
1766
1767   focus_child = container->focus_child;
1768   gtk_container_set_focus_child (container, NULL);
1769
1770   while (children)
1771     {
1772       child = children->data;
1773       children = children->next;
1774
1775       if (!child)
1776         continue;
1777
1778       if (focus_child)
1779         {
1780           if (focus_child == child)
1781             {
1782               focus_child = NULL;
1783
1784               if (GTK_WIDGET_DRAWABLE (child) &&
1785                   GTK_IS_CONTAINER (child) &&
1786                   !GTK_WIDGET_HAS_FOCUS (child))
1787                 if (gtk_container_focus (GTK_CONTAINER (child), direction))
1788                   return TRUE;
1789             }
1790         }
1791       else if (GTK_WIDGET_DRAWABLE (child))
1792         {
1793           if (GTK_IS_CONTAINER (child))
1794             {
1795               if (gtk_container_focus (GTK_CONTAINER (child), direction))
1796                 return TRUE;
1797             }
1798           else if (GTK_WIDGET_CAN_FOCUS (child))
1799             {
1800               gtk_widget_grab_focus (child);
1801               return TRUE;
1802             }
1803         }
1804     }
1805
1806   return FALSE;
1807 }
1808
1809
1810 static void
1811 gtk_container_children_callback (GtkWidget *widget,
1812                                  gpointer   client_data)
1813 {
1814   GList **children;
1815
1816   children = (GList**) client_data;
1817   *children = g_list_prepend (*children, widget);
1818 }
1819
1820 void
1821 gtk_container_set_focus_vadjustment (GtkContainer  *container,
1822                                      GtkAdjustment *adjustment)
1823 {
1824   g_return_if_fail (container != NULL);
1825   g_return_if_fail (GTK_IS_CONTAINER (container));
1826   if (adjustment)
1827     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
1828
1829   if (adjustment)
1830     gtk_object_ref (GTK_OBJECT(adjustment));
1831
1832   gtk_object_set_data_by_id_full (GTK_OBJECT (container),
1833                                   vadjustment_key_id,
1834                                   adjustment,
1835                                   (GtkDestroyNotify) gtk_object_unref);
1836 }
1837
1838 void
1839 gtk_container_set_focus_hadjustment (GtkContainer  *container,
1840                                      GtkAdjustment *adjustment)
1841 {
1842   g_return_if_fail (container != NULL);
1843   g_return_if_fail (GTK_IS_CONTAINER (container));
1844   if (adjustment)
1845     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
1846
1847   if (adjustment)
1848     gtk_object_ref (GTK_OBJECT (adjustment));
1849
1850   gtk_object_set_data_by_id_full (GTK_OBJECT (container),
1851                                   hadjustment_key_id,
1852                                   adjustment,
1853                                   (GtkDestroyNotify) gtk_object_unref);
1854 }
1855
1856
1857 static void
1858 gtk_container_show_all (GtkWidget *widget)
1859 {
1860   g_return_if_fail (widget != NULL);
1861   g_return_if_fail (GTK_IS_CONTAINER (widget));
1862
1863   gtk_container_foreach (GTK_CONTAINER (widget),
1864                          (GtkCallback) gtk_widget_show_all,
1865                          NULL);
1866   gtk_widget_show (widget);
1867 }
1868
1869 static void
1870 gtk_container_hide_all (GtkWidget *widget)
1871 {
1872   g_return_if_fail (widget != NULL);
1873   g_return_if_fail (GTK_IS_CONTAINER (widget));
1874
1875   gtk_widget_hide (widget);
1876   gtk_container_foreach (GTK_CONTAINER (widget),
1877                          (GtkCallback) gtk_widget_hide_all,
1878                          NULL);
1879 }