]> Pileus Git - ~andy/gtk/blob - gtk/gtkcontainer.c
Try to figure out if this is Digital Unix and we need -std1 to get the
[~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
24
25 enum {
26   ADD,
27   REMOVE,
28   NEED_RESIZE,
29   FOREACH,
30   FOCUS,
31   LAST_SIGNAL
32 };
33 enum {
34   ARG_0,
35   ARG_BORDER_WIDTH,
36   ARG_AUTO_RESIZE,
37   ARG_BLOCK_RESIZE,
38   ARG_CHILD
39 };
40
41
42 typedef void (*GtkContainerSignal1) (GtkObject *object,
43                                      gpointer   arg1,
44                                      gpointer   data);
45 typedef void (*GtkContainerSignal2) (GtkObject *object,
46                                      GtkFunction arg1,
47                                      gpointer   arg2,
48                                      gpointer   data);
49 typedef gint (*GtkContainerSignal3) (GtkObject *object,
50                                      gint       arg1,
51                                      gpointer   data);
52 typedef gint (*GtkContainerSignal4) (GtkObject *object,
53                                      gpointer   data);
54
55
56 static void gtk_container_marshal_signal_1 (GtkObject      *object,
57                                             GtkSignalFunc   func,
58                                             gpointer        func_data,
59                                             GtkArg         *args);
60 static void gtk_container_marshal_signal_2 (GtkObject      *object,
61                                             GtkSignalFunc   func,
62                                             gpointer        func_data,
63                                             GtkArg         *args);
64 static void gtk_container_marshal_signal_3 (GtkObject      *object,
65                                             GtkSignalFunc   func,
66                                             gpointer        func_data,
67                                             GtkArg         *args);
68 static void gtk_container_marshal_signal_4 (GtkObject      *object,
69                                             GtkSignalFunc   func,
70                                             gpointer        func_data,
71                                             GtkArg         *args);
72
73
74 static void gtk_container_class_init        (GtkContainerClass *klass);
75 static void gtk_container_init              (GtkContainer      *container);
76 static void gtk_container_destroy           (GtkObject         *object);
77 static void gtk_container_get_arg           (GtkContainer      *container,
78                                              GtkArg            *arg,
79                                              guint              arg_id);
80 static void gtk_container_set_arg           (GtkContainer      *container,
81                                              GtkArg            *arg,
82                                              guint              arg_id);
83 static void gtk_container_add_unimplemented (GtkContainer      *container,
84                                              GtkWidget         *widget);
85 static void gtk_container_remove_unimplemented (GtkContainer   *container,
86                                                 GtkWidget      *widget);
87 static gint gtk_real_container_need_resize  (GtkContainer      *container);
88 static gint gtk_real_container_focus        (GtkContainer      *container,
89                                              GtkDirectionType   direction);
90 static gint gtk_container_focus_tab         (GtkContainer      *container,
91                                              GList             *children,
92                                              GtkDirectionType   direction);
93 static gint gtk_container_focus_up_down     (GtkContainer      *container,
94                                              GList             *children,
95                                              GtkDirectionType   direction);
96 static gint gtk_container_focus_left_right  (GtkContainer      *container,
97                                              GList             *children,
98                                              GtkDirectionType   direction);
99 static gint gtk_container_focus_move        (GtkContainer      *container,
100                                              GList             *children,
101                                              GtkDirectionType   direction);
102 static void gtk_container_children_callback (GtkWidget         *widget,
103                                              gpointer           client_data);
104 static void gtk_container_show_all          (GtkWidget         *widget);
105 static void gtk_container_hide_all          (GtkWidget         *widget);
106
107
108
109 static guint container_signals[LAST_SIGNAL] = { 0 };
110
111 static GtkWidgetClass *parent_class = NULL;
112
113 static const gchar *vadjustment_key = "gtk-vadjustment";
114 static guint        vadjustment_key_id = 0;
115 static const gchar *hadjustment_key = "gtk-hadjustment";
116 static guint        hadjustment_key_id = 0;
117
118 GtkType
119 gtk_container_get_type (void)
120 {
121   static GtkType container_type = 0;
122
123   if (!container_type)
124     {
125       GtkTypeInfo container_info =
126       {
127         "GtkContainer",
128         sizeof (GtkContainer),
129         sizeof (GtkContainerClass),
130         (GtkClassInitFunc) gtk_container_class_init,
131         (GtkObjectInitFunc) gtk_container_init,
132         (GtkArgSetFunc) gtk_container_set_arg,
133         (GtkArgGetFunc) gtk_container_get_arg,
134       };
135
136       container_type = gtk_type_unique (gtk_widget_get_type (), &container_info);
137     }
138
139   return container_type;
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   vadjustment_key_id = gtk_object_data_force_id (vadjustment_key);
154   hadjustment_key_id = gtk_object_data_force_id (hadjustment_key);
155   
156   gtk_object_add_arg_type ("GtkContainer::border_width", GTK_TYPE_LONG, GTK_ARG_READWRITE, ARG_BORDER_WIDTH);
157   gtk_object_add_arg_type ("GtkContainer::auto_resize", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_AUTO_RESIZE);
158   gtk_object_add_arg_type ("GtkContainer::block_resize", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_BLOCK_RESIZE);
159   gtk_object_add_arg_type ("GtkContainer::child", GTK_TYPE_WIDGET, GTK_ARG_WRITABLE, ARG_CHILD);
160
161   container_signals[ADD] =
162     gtk_signal_new ("add",
163                     GTK_RUN_FIRST,
164                     object_class->type,
165                     GTK_SIGNAL_OFFSET (GtkContainerClass, add),
166                     gtk_container_marshal_signal_1,
167                     GTK_TYPE_NONE, 1,
168                     GTK_TYPE_WIDGET);
169   container_signals[REMOVE] =
170     gtk_signal_new ("remove",
171                     GTK_RUN_FIRST,
172                     object_class->type,
173                     GTK_SIGNAL_OFFSET (GtkContainerClass, remove),
174                     gtk_container_marshal_signal_1,
175                     GTK_TYPE_NONE, 1,
176                     GTK_TYPE_WIDGET);
177   container_signals[NEED_RESIZE] =
178     gtk_signal_new ("need_resize",
179                     GTK_RUN_FIRST,
180                     object_class->type,
181                     GTK_SIGNAL_OFFSET (GtkContainerClass, need_resize),
182                     gtk_container_marshal_signal_4,
183                     GTK_TYPE_BOOL, 0);
184   container_signals[FOREACH] =
185     gtk_signal_new ("foreach",
186                     GTK_RUN_FIRST,
187                     object_class->type,
188                     GTK_SIGNAL_OFFSET (GtkContainerClass, foreach),
189                     gtk_container_marshal_signal_2,
190                     GTK_TYPE_NONE, 1,
191                     GTK_TYPE_C_CALLBACK);
192   container_signals[FOCUS] =
193     gtk_signal_new ("focus",
194                     GTK_RUN_LAST,
195                     object_class->type,
196                     GTK_SIGNAL_OFFSET (GtkContainerClass, focus),
197                     gtk_container_marshal_signal_3,
198                     GTK_TYPE_DIRECTION_TYPE, 1,
199                     GTK_TYPE_DIRECTION_TYPE);
200
201   gtk_object_class_add_signals (object_class, container_signals, LAST_SIGNAL);
202   
203   object_class->destroy = gtk_container_destroy;
204   
205   /* Other container classes should overwrite show_all and hide_all,
206    * for the purpose of showing internal children also, which are not
207    * accessable through gtk_container_foreach.
208   */
209   widget_class->show_all = gtk_container_show_all;
210   widget_class->hide_all = gtk_container_hide_all;
211
212   class->add = gtk_container_add_unimplemented;
213   class->remove = gtk_container_remove_unimplemented;
214   class->need_resize = gtk_real_container_need_resize;
215   class->foreach = NULL;
216   class->focus = gtk_real_container_focus;
217 }
218
219 static void
220 gtk_container_add_unimplemented (GtkContainer     *container,
221                                  GtkWidget        *widget)
222 {
223   g_warning ("GtkContainerClass::add not implemented for `%s'", gtk_type_name (GTK_OBJECT_TYPE (container)));
224 }
225
226 static void
227 gtk_container_remove_unimplemented (GtkContainer     *container,
228                                     GtkWidget        *widget)
229 {
230   g_warning ("GtkContainerClass::remove not implemented for `%s'", gtk_type_name (GTK_OBJECT_TYPE (container)));
231 }
232
233 static void
234 gtk_container_init (GtkContainer *container)
235 {
236   container->focus_child = NULL;
237   container->border_width = 0;
238   container->auto_resize = TRUE;
239   container->need_resize = FALSE;
240   container->block_resize = FALSE;
241   container->resize_widgets = NULL;
242 }
243
244 static void
245 gtk_container_destroy (GtkObject *object)
246 {
247   GSList *node;
248   
249   g_return_if_fail (object != NULL);
250   g_return_if_fail (GTK_IS_CONTAINER (object));
251
252   for (node = GTK_CONTAINER (object)->resize_widgets; node; node = node->next)
253     {
254       GtkWidget *child;
255       
256       child = (GtkWidget*) node->data;
257       GTK_PRIVATE_UNSET_FLAG (child, GTK_RESIZE_NEEDED);
258     }
259   g_slist_free (GTK_CONTAINER (object)->resize_widgets);
260   GTK_CONTAINER (object)->resize_widgets = NULL;
261   
262   gtk_container_foreach (GTK_CONTAINER (object),
263                          (GtkCallback) gtk_widget_destroy, NULL);
264   
265   if (GTK_OBJECT_CLASS (parent_class)->destroy)
266     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
267 }
268
269 static void
270 gtk_container_set_arg (GtkContainer *container,
271                        GtkArg       *arg,
272                        guint         arg_id)
273 {
274   switch (arg_id)
275     {
276     case ARG_BORDER_WIDTH:
277       gtk_container_border_width (container, GTK_VALUE_LONG (*arg));
278       break;
279     case ARG_AUTO_RESIZE:
280       if (GTK_VALUE_BOOL (*arg))
281         gtk_container_enable_resize (container);
282       else
283         gtk_container_disable_resize (container);
284       break;
285     case ARG_BLOCK_RESIZE:
286       if (GTK_VALUE_BOOL (*arg))
287         gtk_container_block_resize (container);
288       else
289         gtk_container_unblock_resize (container);
290       break;
291     case ARG_CHILD:
292       gtk_container_add (container, GTK_WIDGET (GTK_VALUE_OBJECT (*arg)));
293       break;
294     default:
295       arg->type = GTK_TYPE_INVALID;
296       break;
297     }
298 }
299
300 static void
301 gtk_container_get_arg (GtkContainer *container,
302                        GtkArg       *arg,
303                        guint         arg_id)
304 {
305   switch (arg_id)
306     {
307     case ARG_BORDER_WIDTH:
308       GTK_VALUE_LONG (*arg) = container->border_width;
309       break;
310     case ARG_AUTO_RESIZE:
311       GTK_VALUE_BOOL (*arg) = container->auto_resize;
312       break;
313     case ARG_BLOCK_RESIZE:
314       GTK_VALUE_BOOL (*arg) = container->block_resize;
315       break;
316     default:
317       arg->type = GTK_TYPE_INVALID;
318       break;
319     }
320 }
321
322 void
323 gtk_container_border_width (GtkContainer *container,
324                             gint          border_width)
325 {
326   g_return_if_fail (container != NULL);
327   g_return_if_fail (GTK_IS_CONTAINER (container));
328
329   if (container->border_width != border_width)
330     {
331       container->border_width = border_width;
332
333       if (GTK_WIDGET_REALIZED (container))
334         gtk_widget_queue_resize (GTK_WIDGET (container));
335     }
336 }
337
338 void
339 gtk_container_add (GtkContainer *container,
340                    GtkWidget    *widget)
341 {
342   g_return_if_fail (container != NULL);
343   g_return_if_fail (GTK_IS_CONTAINER (container));
344   g_return_if_fail (widget != NULL);
345   g_return_if_fail (GTK_IS_WIDGET (widget));
346   g_return_if_fail (widget->parent == NULL);
347
348   gtk_signal_emit (GTK_OBJECT (container), container_signals[ADD], widget);
349 }
350
351 void
352 gtk_container_remove (GtkContainer *container,
353                       GtkWidget    *widget)
354 {
355   g_return_if_fail (container != NULL);
356   g_return_if_fail (GTK_IS_CONTAINER (container));
357   g_return_if_fail (widget != NULL);
358   g_return_if_fail (GTK_IS_WIDGET (widget));
359   g_return_if_fail (widget->parent == GTK_WIDGET (container));
360   
361   gtk_signal_emit (GTK_OBJECT (container), container_signals[REMOVE], widget);
362 }
363
364 void
365 gtk_container_disable_resize (GtkContainer *container)
366 {
367   g_return_if_fail (container != NULL);
368   g_return_if_fail (GTK_IS_CONTAINER (container));
369
370   container->auto_resize = FALSE;
371 }
372
373 void
374 gtk_container_enable_resize (GtkContainer *container)
375 {
376   g_return_if_fail (container != NULL);
377   g_return_if_fail (GTK_IS_CONTAINER (container));
378
379   container->auto_resize = TRUE;
380   if (container->need_resize)
381     {
382       container->need_resize = FALSE;
383       gtk_widget_queue_resize (GTK_WIDGET (container));
384     }
385 }
386
387 void
388 gtk_container_block_resize (GtkContainer *container)
389 {
390   g_return_if_fail (container != NULL);
391   g_return_if_fail (GTK_IS_CONTAINER (container));
392
393   container->block_resize = TRUE;
394 }
395
396 void
397 gtk_container_unblock_resize (GtkContainer *container)
398 {
399   g_return_if_fail (container != NULL);
400   g_return_if_fail (GTK_IS_CONTAINER (container));
401   
402   container->block_resize = FALSE;
403 }
404
405 gint
406 gtk_container_need_resize (GtkContainer *container)
407 {
408   gint return_val;
409   
410   g_return_val_if_fail (container != NULL, FALSE);
411   g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
412   
413   return_val = FALSE;
414   
415   if (!container->block_resize)
416     {
417       if (container->auto_resize)
418         gtk_signal_emit (GTK_OBJECT (container),
419                          container_signals[NEED_RESIZE],
420                          &return_val);
421       else
422         container->need_resize = TRUE;
423     }
424   
425   return return_val;
426 }
427
428 void
429 gtk_container_foreach (GtkContainer *container,
430                        GtkCallback   callback,
431                        gpointer      callback_data)
432 {
433   gtk_signal_emit (GTK_OBJECT (container),
434                    container_signals[FOREACH],
435                    callback, callback_data);
436 }
437
438 typedef struct _GtkForeachData  GtkForeachData;
439 struct _GtkForeachData
440 {
441   GtkObject         *container;
442   GtkCallbackMarshal callback;
443   gpointer           callback_data;
444 };
445
446 static void
447 gtk_container_foreach_unmarshal (GtkWidget *child,
448                                  gpointer data)
449 {
450   GtkForeachData *fdata = (GtkForeachData*) data;
451   GtkArg args[2];
452   
453   /* first argument */
454   args[0].name = NULL;
455   args[0].type = GTK_OBJECT(child)->klass->type;
456   GTK_VALUE_OBJECT(args[0]) = GTK_OBJECT (child);
457   
458   /* location for return value */
459   args[1].name = NULL;
460   args[1].type = GTK_TYPE_NONE;
461   
462   fdata->callback (fdata->container, fdata->callback_data, 1, args);
463 }
464
465 void
466 gtk_container_foreach_interp (GtkContainer       *container,
467                               GtkCallbackMarshal  marshal,
468                               gpointer            callback_data,
469                               GtkDestroyNotify    notify)
470 {
471   gtk_container_foreach_full (container, NULL, marshal, 
472                               callback_data, notify);
473 }
474
475 void
476 gtk_container_foreach_full (GtkContainer       *container,
477                             GtkCallback         callback,
478                             GtkCallbackMarshal  marshal,
479                             gpointer            callback_data,
480                             GtkDestroyNotify    notify)
481 {
482   if (marshal)
483     {
484       GtkForeachData fdata;
485   
486       fdata.container     = GTK_OBJECT (container);
487       fdata.callback      = marshal;
488       fdata.callback_data = callback_data;
489
490       gtk_container_foreach (container, gtk_container_foreach_unmarshal, &fdata);
491     }
492   else
493     gtk_container_foreach (container, callback, &callback_data);
494   
495   notify (callback_data);
496 }
497
498 gint
499 gtk_container_focus (GtkContainer     *container,
500                      GtkDirectionType  direction)
501 {
502   gint return_val;
503   
504   gtk_signal_emit (GTK_OBJECT (container),
505                    container_signals[FOCUS],
506                    direction, &return_val);
507
508   return return_val;
509 }
510
511 GList*
512 gtk_container_children (GtkContainer *container)
513 {
514   GList *children;
515
516   children = NULL;
517
518   gtk_container_foreach (container,
519                          gtk_container_children_callback,
520                          &children);
521
522   return g_list_reverse (children);
523 }
524
525 void
526 gtk_container_register_toplevel (GtkContainer *container)
527 {
528   gtk_widget_ref (GTK_WIDGET (container));
529   gtk_object_sink (GTK_OBJECT (container));
530 }
531
532 void
533 gtk_container_unregister_toplevel (GtkContainer *container)
534 {
535   gtk_widget_unref (GTK_WIDGET (container));
536 }
537
538 void
539 gtk_container_set_focus_child (GtkContainer     *container,
540                                GtkWidget        *child)
541 {
542   g_return_if_fail (container != NULL);
543   g_return_if_fail (GTK_IS_CONTAINER (container));
544   if (child)
545     g_return_if_fail (GTK_IS_WIDGET (child));
546
547   if (child != container->focus_child)
548     {
549       if (container->focus_child)
550         gtk_widget_unref (container->focus_child);
551       container->focus_child = child;
552       if (container->focus_child)
553         gtk_widget_ref (container->focus_child);
554     }
555
556
557   /* check for h/v adjustments
558    */
559   if (container->focus_child)
560     {
561       GtkAdjustment *adjustment;
562       
563       adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container), vadjustment_key_id);
564       if (adjustment)
565         gtk_adjustment_clamp_page (adjustment,
566                                    container->focus_child->allocation.y,
567                                    (container->focus_child->allocation.y +
568                                     container->focus_child->allocation.height));
569
570       adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container), hadjustment_key_id);
571       if (adjustment)
572         gtk_adjustment_clamp_page (adjustment,
573                                    container->focus_child->allocation.x,
574                                    (container->focus_child->allocation.x +
575                                     container->focus_child->allocation.width));
576     }
577 }
578
579 static void
580 gtk_container_marshal_signal_1 (GtkObject      *object,
581                                 GtkSignalFunc   func,
582                                 gpointer        func_data,
583                                 GtkArg         *args)
584 {
585   GtkContainerSignal1 rfunc;
586
587   rfunc = (GtkContainerSignal1) func;
588
589   (* rfunc) (object, GTK_VALUE_OBJECT (args[0]), func_data);
590 }
591
592 static void
593 gtk_container_marshal_signal_2 (GtkObject      *object,
594                                 GtkSignalFunc   func,
595                                 gpointer        func_data,
596                                 GtkArg         *args)
597 {
598   GtkContainerSignal2 rfunc;
599
600   rfunc = (GtkContainerSignal2) func;
601
602   (* rfunc) (object,
603              GTK_VALUE_C_CALLBACK(args[0]).func,
604              GTK_VALUE_C_CALLBACK(args[0]).func_data,
605              func_data);
606 }
607
608 static void
609 gtk_container_marshal_signal_3 (GtkObject      *object,
610                                 GtkSignalFunc   func,
611                                 gpointer        func_data,
612                                 GtkArg         *args)
613 {
614   GtkContainerSignal3 rfunc;
615   gint *return_val;
616
617   rfunc = (GtkContainerSignal3) func;
618   return_val = GTK_RETLOC_ENUM (args[1]);
619
620   *return_val = (* rfunc) (object, GTK_VALUE_ENUM(args[0]), func_data);
621 }
622
623 static void
624 gtk_container_marshal_signal_4 (GtkObject      *object,
625                                 GtkSignalFunc   func,
626                                 gpointer        func_data,
627                                 GtkArg         *args)
628 {
629   GtkContainerSignal4 rfunc;
630   gint *return_val;
631
632   rfunc = (GtkContainerSignal4) func;
633   return_val = GTK_RETLOC_BOOL (args[0]);
634
635   *return_val = (* rfunc) (object, func_data);
636 }
637
638 static gint
639 gtk_real_container_need_resize (GtkContainer *container)
640 {
641   g_return_val_if_fail (container != NULL, FALSE);
642   g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
643
644   if (GTK_WIDGET_VISIBLE (container) && container->widget.parent)
645     return gtk_container_need_resize (GTK_CONTAINER (container->widget.parent));
646
647   return FALSE;
648 }
649
650 static gint
651 gtk_real_container_focus (GtkContainer     *container,
652                           GtkDirectionType  direction)
653 {
654   GList *children;
655   GList *tmp_list;
656   GList *tmp_list2;
657   gint return_val;
658
659   g_return_val_if_fail (container != NULL, FALSE);
660   g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
661
662   /* Fail if the container is insensitive
663    */
664   if (!GTK_WIDGET_SENSITIVE (container))
665     return FALSE;
666
667   return_val = FALSE;
668
669   if (GTK_WIDGET_CAN_FOCUS (container))
670     {
671       gtk_widget_grab_focus (GTK_WIDGET (container));
672       return_val = TRUE;
673     }
674   else
675     {
676       /* Get a list of the containers children
677        */
678       children = gtk_container_children (container);
679
680       if (children)
681         {
682           /* Remove any children which are insensitive
683            */
684           tmp_list = children;
685           while (tmp_list)
686             {
687               if (!GTK_WIDGET_SENSITIVE (tmp_list->data))
688                 {
689                   tmp_list2 = tmp_list;
690                   tmp_list = tmp_list->next;
691
692                   children = g_list_remove_link (children, tmp_list2);
693                   g_list_free_1 (tmp_list2);
694                 }
695               else
696                 tmp_list = tmp_list->next;
697             }
698
699           switch (direction)
700             {
701             case GTK_DIR_TAB_FORWARD:
702             case GTK_DIR_TAB_BACKWARD:
703               return_val = gtk_container_focus_tab (container, children, direction);
704               break;
705             case GTK_DIR_UP:
706             case GTK_DIR_DOWN:
707               return_val = gtk_container_focus_up_down (container, children, direction);
708               break;
709             case GTK_DIR_LEFT:
710             case GTK_DIR_RIGHT:
711               return_val = gtk_container_focus_left_right (container, children, direction);
712               break;
713             }
714
715           g_list_free (children);
716         }
717     }
718
719   return return_val;
720 }
721
722 static gint
723 gtk_container_focus_tab (GtkContainer     *container,
724                          GList            *children,
725                          GtkDirectionType  direction)
726 {
727   GtkWidget *child;
728   GtkWidget *child2;
729   GList *tmp_list;
730   guint length;
731   guint i, j;
732
733   length = g_list_length (children);
734
735   /* sort the children in the y direction */
736   for (i = 1; i < length; i++)
737     {
738       j = i;
739       tmp_list = g_list_nth (children, j);
740       child = tmp_list->data;
741
742       while (j > 0)
743         {
744           child2 = tmp_list->prev->data;
745           if (child->allocation.y < child2->allocation.y)
746             {
747               tmp_list->data = tmp_list->prev->data;
748               tmp_list = tmp_list->prev;
749               j--;
750             }
751           else
752             break;
753         }
754
755       tmp_list->data = child;
756     }
757
758   /* sort the children in the x direction while
759    *  maintaining the y direction sort.
760    */
761   for (i = 1; i < length; i++)
762     {
763       j = i;
764       tmp_list = g_list_nth (children, j);
765       child = tmp_list->data;
766
767       while (j > 0)
768         {
769           child2 = tmp_list->prev->data;
770           if ((child->allocation.x < child2->allocation.x) &&
771               (child->allocation.y == child2->allocation.y))
772             {
773               tmp_list->data = tmp_list->prev->data;
774               tmp_list = tmp_list->prev;
775               j--;
776             }
777           else
778             break;
779         }
780
781       tmp_list->data = child;
782     }
783
784   /* if we are going backwards then reverse the order
785    *  of the children.
786    */
787   if (direction == GTK_DIR_TAB_BACKWARD)
788     children = g_list_reverse (children);
789
790   return gtk_container_focus_move (container, children, direction);
791 }
792
793 static gint
794 gtk_container_focus_up_down (GtkContainer     *container,
795                              GList            *children,
796                              GtkDirectionType  direction)
797 {
798   GtkWidget *child;
799   GtkWidget *child2;
800   GList *tmp_list;
801   gint dist1, dist2;
802   gint focus_x;
803   gint focus_width;
804   guint length;
805   guint i, j;
806
807   /* return failure if there isn't a focus child */
808   if (container->focus_child)
809     {
810       focus_width = container->focus_child->allocation.width / 2;
811       focus_x = container->focus_child->allocation.x + focus_width;
812     }
813   else
814     {
815       focus_width = GTK_WIDGET (container)->allocation.width;
816       if (GTK_WIDGET_NO_WINDOW (container))
817         focus_x = GTK_WIDGET (container)->allocation.x;
818       else
819         focus_x = 0;
820     }
821
822   length = g_list_length (children);
823
824   /* sort the children in the y direction */
825   for (i = 1; i < length; i++)
826     {
827       j = i;
828       tmp_list = g_list_nth (children, j);
829       child = tmp_list->data;
830
831       while (j > 0)
832         {
833           child2 = tmp_list->prev->data;
834           if (child->allocation.y < child2->allocation.y)
835             {
836               tmp_list->data = tmp_list->prev->data;
837               tmp_list = tmp_list->prev;
838               j--;
839             }
840           else
841             break;
842         }
843
844       tmp_list->data = child;
845     }
846
847   /* sort the children in distance in the x direction
848    *  in distance from the current focus child while maintaining the
849    *  sort in the y direction
850    */
851   for (i = 1; i < length; i++)
852     {
853       j = i;
854       tmp_list = g_list_nth (children, j);
855       child = tmp_list->data;
856       dist1 = (child->allocation.x + child->allocation.width / 2) - focus_x;
857
858       while (j > 0)
859         {
860           child2 = tmp_list->prev->data;
861           dist2 = (child2->allocation.x + child2->allocation.width / 2) - focus_x;
862
863           if ((dist1 < dist2) &&
864               (child->allocation.y >= child2->allocation.y))
865             {
866               tmp_list->data = tmp_list->prev->data;
867               tmp_list = tmp_list->prev;
868               j--;
869             }
870           else
871             break;
872         }
873
874       tmp_list->data = child;
875     }
876
877   /* go and invalidate any widget which is too
878    *  far from the focus widget.
879    */
880   if (!container->focus_child &&
881       (direction == GTK_DIR_UP))
882     focus_x += focus_width;
883
884   tmp_list = children;
885   while (tmp_list)
886     {
887       child = tmp_list->data;
888
889       dist1 = (child->allocation.x + child->allocation.width / 2) - focus_x;
890       if (((direction == GTK_DIR_DOWN) && (dist1 < 0)) ||
891           ((direction == GTK_DIR_UP) && (dist1 > 0)))
892         tmp_list->data = NULL;
893
894       tmp_list = tmp_list->next;
895     }
896
897   if (direction == GTK_DIR_UP)
898     children = g_list_reverse (children);
899
900   return gtk_container_focus_move (container, children, direction);
901 }
902
903 static gint
904 gtk_container_focus_left_right (GtkContainer     *container,
905                                 GList            *children,
906                                 GtkDirectionType  direction)
907 {
908   GtkWidget *child;
909   GtkWidget *child2;
910   GList *tmp_list;
911   gint dist1, dist2;
912   gint focus_y;
913   gint focus_height;
914   guint length;
915   guint i, j;
916
917   /* return failure if there isn't a focus child */
918   if (container->focus_child)
919     {
920       focus_height = container->focus_child->allocation.height / 2;
921       focus_y = container->focus_child->allocation.y + focus_height;
922     }
923   else
924     {
925       focus_height = GTK_WIDGET (container)->allocation.height;
926       if (GTK_WIDGET_NO_WINDOW (container))
927         focus_y = GTK_WIDGET (container)->allocation.y;
928       else
929         focus_y = 0;
930     }
931
932   length = g_list_length (children);
933
934   /* sort the children in the x direction */
935   for (i = 1; i < length; i++)
936     {
937       j = i;
938       tmp_list = g_list_nth (children, j);
939       child = tmp_list->data;
940
941       while (j > 0)
942         {
943           child2 = tmp_list->prev->data;
944           if (child->allocation.x < child2->allocation.x)
945             {
946               tmp_list->data = tmp_list->prev->data;
947               tmp_list = tmp_list->prev;
948               j--;
949             }
950           else
951             break;
952         }
953
954       tmp_list->data = child;
955     }
956
957   /* sort the children in distance in the y direction
958    *  in distance from the current focus child while maintaining the
959    *  sort in the x direction
960    */
961   for (i = 1; i < length; i++)
962     {
963       j = i;
964       tmp_list = g_list_nth (children, j);
965       child = tmp_list->data;
966       dist1 = (child->allocation.y + child->allocation.height / 2) - focus_y;
967
968       while (j > 0)
969         {
970           child2 = tmp_list->prev->data;
971           dist2 = (child2->allocation.y + child2->allocation.height / 2) - focus_y;
972
973           if ((dist1 < dist2) &&
974               (child->allocation.x >= child2->allocation.x))
975             {
976               tmp_list->data = tmp_list->prev->data;
977               tmp_list = tmp_list->prev;
978               j--;
979             }
980           else
981             break;
982         }
983
984       tmp_list->data = child;
985     }
986
987   /* go and invalidate any widget which is too
988    *  far from the focus widget.
989    */
990   if (!container->focus_child &&
991       (direction == GTK_DIR_LEFT))
992     focus_y += focus_height;
993
994   tmp_list = children;
995   while (tmp_list)
996     {
997       child = tmp_list->data;
998
999       dist1 = (child->allocation.y + child->allocation.height / 2) - focus_y;
1000       if (((direction == GTK_DIR_RIGHT) && (dist1 < 0)) ||
1001           ((direction == GTK_DIR_LEFT) && (dist1 > 0)))
1002         tmp_list->data = NULL;
1003
1004       tmp_list = tmp_list->next;
1005     }
1006
1007   if (direction == GTK_DIR_LEFT)
1008     children = g_list_reverse (children);
1009
1010   return gtk_container_focus_move (container, children, direction);
1011 }
1012
1013 static gint
1014 gtk_container_focus_move (GtkContainer     *container,
1015                           GList            *children,
1016                           GtkDirectionType  direction)
1017 {
1018   GtkWidget *focus_child;
1019   GtkWidget *child;
1020
1021   focus_child = container->focus_child;
1022   gtk_container_set_focus_child (container, NULL);
1023
1024   while (children)
1025     {
1026       child = children->data;
1027       children = children->next;
1028
1029       if (!child)
1030         continue;
1031
1032       if (focus_child)
1033         {
1034           if (focus_child == child)
1035             {
1036               focus_child = NULL;
1037
1038               if (GTK_WIDGET_VISIBLE (child) &&
1039                   GTK_IS_CONTAINER (child) &&
1040                   !GTK_WIDGET_HAS_FOCUS (child))
1041                 if (gtk_container_focus (GTK_CONTAINER (child), direction))
1042                   return TRUE;
1043             }
1044         }
1045       else if (GTK_WIDGET_VISIBLE (child))
1046         {
1047           if (GTK_WIDGET_CAN_FOCUS (child))
1048             {
1049               gtk_widget_grab_focus (child);
1050               return TRUE;
1051             }
1052           else if (GTK_IS_CONTAINER (child))
1053             {
1054               if (gtk_container_focus (GTK_CONTAINER (child), direction))
1055                 return TRUE;
1056             }
1057         }
1058     }
1059
1060   return FALSE;
1061 }
1062
1063
1064 static void
1065 gtk_container_children_callback (GtkWidget *widget,
1066                                  gpointer   client_data)
1067 {
1068   GList **children;
1069
1070   children = (GList**) client_data;
1071   *children = g_list_prepend (*children, widget);
1072 }
1073
1074 static void
1075 gtk_container_show_all (GtkWidget *widget)
1076 {
1077   GtkContainer *container;
1078
1079   g_return_if_fail (widget != NULL);
1080   g_return_if_fail (GTK_IS_CONTAINER (widget));
1081   container = GTK_CONTAINER (widget);
1082
1083   /* First show children, then self.
1084      This makes sure that toplevel windows get shown as last widget.
1085      Otherwise the user would see the widgets get
1086      visible one after another.
1087   */
1088   gtk_container_foreach (container, (GtkCallback) gtk_widget_show_all, NULL);
1089   gtk_widget_show (widget);
1090 }
1091
1092
1093 static void
1094 gtk_container_hide_all (GtkWidget *widget)
1095 {
1096   GtkContainer *container;
1097
1098   g_return_if_fail (widget != NULL);
1099   g_return_if_fail (GTK_IS_CONTAINER (widget));
1100   container = GTK_CONTAINER (widget);
1101
1102   /* First hide self, then children.
1103      This is the reverse order of gtk_container_show_all.
1104   */
1105   gtk_widget_hide (widget);  
1106   gtk_container_foreach (container, (GtkCallback) gtk_widget_hide_all, NULL);
1107 }
1108
1109 void
1110 gtk_container_set_focus_vadjustment (GtkContainer  *container,
1111                                      GtkAdjustment *adjustment)
1112 {
1113   g_return_if_fail (container != NULL);
1114   g_return_if_fail (GTK_IS_CONTAINER (container));
1115   if (adjustment)
1116     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
1117
1118   if (adjustment)
1119     gtk_object_ref (GTK_OBJECT(adjustment));
1120
1121   gtk_object_set_data_by_id_full (GTK_OBJECT (container),
1122                                   vadjustment_key_id,
1123                                   adjustment,
1124                                   (GtkDestroyNotify) gtk_object_unref);
1125 }
1126
1127 void
1128 gtk_container_set_focus_hadjustment (GtkContainer  *container,
1129                                      GtkAdjustment *adjustment)
1130 {
1131   g_return_if_fail (container != NULL);
1132   g_return_if_fail (GTK_IS_CONTAINER (container));
1133   if (adjustment)
1134     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
1135
1136   if (adjustment)
1137     gtk_object_ref (GTK_OBJECT (adjustment));
1138
1139   gtk_object_set_data_by_id_full (GTK_OBJECT (container),
1140                                   hadjustment_key_id,
1141                                   adjustment,
1142                                   (GtkDestroyNotify) gtk_object_unref);
1143 }