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