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