1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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/.
28 #include "gtkcontainer.h"
29 #include "gtkprivate.h"
30 #include "gtksignal.h"
48 ARG_REALLOCATE_REDRAWS
51 typedef struct _GtkChildArgInfo GtkChildArgInfo;
52 struct _GtkChildArgInfo
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,
69 static void gtk_container_set_arg (GtkObject *object,
72 static void gtk_container_add_unimplemented (GtkContainer *container,
74 static void gtk_container_remove_unimplemented (GtkContainer *container,
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,
81 static gint gtk_container_focus_tab (GtkContainer *container,
83 GtkDirectionType direction);
84 static gint gtk_container_focus_up_down (GtkContainer *container,
86 GtkDirectionType direction);
87 static gint gtk_container_focus_left_right (GtkContainer *container,
89 GtkDirectionType direction);
90 static gint gtk_container_focus_move (GtkContainer *container,
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);
98 static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
103 static guint container_signals[LAST_SIGNAL] = { 0 };
104 static GHashTable *container_child_arg_info_ht = NULL;
106 static GtkWidgetClass *parent_class = NULL;
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;
115 gtk_container_get_type (void)
117 static GtkType container_type = 0;
121 static const GtkTypeInfo container_info =
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,
133 container_type = gtk_type_unique (gtk_widget_get_type (), &container_info);
136 return container_type;
140 gtk_container_base_class_init (GtkContainerClass *class)
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;
149 gtk_container_class_init (GtkContainerClass *class)
151 GtkObjectClass *object_class;
152 GtkWidgetClass *widget_class;
154 object_class = (GtkObjectClass*) class;
155 widget_class = (GtkWidgetClass*) class;
157 parent_class = gtk_type_class (gtk_widget_get_type ());
159 container_child_arg_info_ht = g_hash_table_new (gtk_arg_info_hash,
162 vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
163 hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
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);
170 container_signals[ADD] =
171 gtk_signal_new ("add",
173 GTK_CLASS_TYPE (object_class),
174 GTK_SIGNAL_OFFSET (GtkContainerClass, add),
175 gtk_marshal_NONE__POINTER,
178 container_signals[REMOVE] =
179 gtk_signal_new ("remove",
181 GTK_CLASS_TYPE (object_class),
182 GTK_SIGNAL_OFFSET (GtkContainerClass, remove),
183 gtk_marshal_NONE__POINTER,
186 container_signals[CHECK_RESIZE] =
187 gtk_signal_new ("check_resize",
189 GTK_CLASS_TYPE (object_class),
190 GTK_SIGNAL_OFFSET (GtkContainerClass, check_resize),
191 gtk_marshal_NONE__NONE,
193 container_signals[FOCUS] =
194 gtk_signal_new ("focus",
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",
204 GTK_CLASS_TYPE (object_class),
205 GTK_SIGNAL_OFFSET (GtkContainerClass, set_focus_child),
206 gtk_marshal_NONE__POINTER,
209 gtk_object_class_add_signals (object_class, container_signals, LAST_SIGNAL);
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;
215 widget_class->show_all = gtk_container_show_all;
216 widget_class->hide_all = gtk_container_hide_all;
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;
229 gtk_container_child_type (GtkContainer *container)
232 GtkContainerClass *class;
234 g_return_val_if_fail (container != NULL, 0);
235 g_return_val_if_fail (GTK_IS_CONTAINER (container), 0);
237 class = GTK_CONTAINER_GET_CLASS (container);
238 if (class->child_type)
239 slot = class->child_type (container);
241 slot = GTK_TYPE_NONE;
246 /****************************************************
247 * GtkContainer child argument mechanism
249 ****************************************************/
252 gtk_container_add_with_args (GtkContainer *container,
254 const gchar *first_arg_name,
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);
263 gtk_widget_ref (GTK_WIDGET (container));
264 gtk_widget_ref (widget);
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);
273 GSList *arg_list = NULL;
274 GSList *info_list = NULL;
277 va_start (var_args, first_arg_name);
278 error = gtk_container_child_args_collect (GTK_OBJECT_TYPE (container),
287 g_warning ("gtk_container_add_with_args(): %s", error);
295 slist_arg = arg_list;
296 slist_info = info_list;
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;
303 gtk_args_collect_cleanup (arg_list, info_list);
307 gtk_widget_unref (widget);
308 gtk_widget_unref (GTK_WIDGET (container));
312 gtk_container_addv (GtkContainer *container,
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);
323 gtk_widget_ref (GTK_WIDGET (container));
324 gtk_widget_ref (widget);
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);
334 for (max_args = args + n_args; args < max_args; args++)
335 gtk_container_arg_set (container, widget, args, NULL);
338 gtk_widget_unref (widget);
339 gtk_widget_unref (GTK_WIDGET (container));
343 gtk_container_child_setv (GtkContainer *container,
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);
356 g_return_if_fail (args != NULL);
358 for (max_args = args + n_args; args < max_args; args++)
359 gtk_container_arg_set (container, child, args, NULL);
363 gtk_container_child_getv (GtkContainer *container,
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);
376 g_return_if_fail (args != NULL);
378 for (max_args = args + n_args; args < max_args; args++)
379 gtk_container_arg_get (container, child, args, NULL);
383 gtk_container_child_set (GtkContainer *container,
385 const gchar *first_arg_name,
389 GSList *arg_list = NULL;
390 GSList *info_list = NULL;
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);
399 va_start (var_args, first_arg_name);
400 error = gtk_container_child_args_collect (GTK_OBJECT_TYPE (container),
409 g_warning ("gtk_container_child_set(): %s", error);
417 slist_arg = arg_list;
418 slist_info = info_list;
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;
425 gtk_args_collect_cleanup (arg_list, info_list);
430 gtk_container_arg_set (GtkContainer *container,
435 GtkContainerClass *class;
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);
447 error = gtk_arg_get_info (GTK_OBJECT_TYPE (container),
448 container_child_arg_info_ht,
453 g_warning ("gtk_container_arg_set(): %s", error);
458 g_return_if_fail (info->arg_flags & GTK_ARG_CHILD_ARG);
460 if (! (info->arg_flags & GTK_ARG_WRITABLE))
462 g_warning ("gtk_container_arg_set(): argument \"%s\" is not writable",
466 if (info->type != arg->type)
468 g_warning ("gtk_container_arg_set(): argument \"%s\" has invalid type `%s'",
470 gtk_type_name (arg->type));
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);
480 gtk_container_arg_get (GtkContainer *container,
485 GtkContainerClass *class;
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);
497 error = gtk_arg_get_info (GTK_OBJECT_TYPE (container),
498 container_child_arg_info_ht,
503 g_warning ("gtk_container_arg_get(): %s", error);
505 arg->type = GTK_TYPE_INVALID;
509 g_return_if_fail (info->arg_flags & GTK_ARG_CHILD_ARG);
511 if (! (info->arg_flags & GTK_ARG_READABLE))
513 g_warning ("gtk_container_arg_get(): argument \"%s\" is not readable",
515 arg->type = GTK_TYPE_INVALID;
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);
526 gtk_container_add_child_arg_type (const gchar *arg_name,
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); */
537 arg_flags |= GTK_ARG_CHILD_ARG;
538 arg_flags &= GTK_ARG_MASK;
540 gtk_arg_type_new_static (GTK_TYPE_CONTAINER,
542 GTK_STRUCT_OFFSET (GtkContainerClass, n_child_args),
543 container_child_arg_info_ht,
550 gtk_container_child_args_collect (GtkType object_type,
552 GSList **info_list_p,
553 const gchar *first_arg_name,
556 return gtk_args_collect (object_type,
557 container_child_arg_info_ht,
565 gtk_container_child_arg_get_info (GtkType object_type,
566 const gchar *arg_name,
569 return gtk_arg_get_info (object_type,
570 container_child_arg_info_ht,
576 gtk_container_query_child_args (GtkType class_type,
580 g_return_val_if_fail (n_args != NULL, NULL);
582 g_return_val_if_fail (gtk_type_is_a (class_type, GTK_TYPE_CONTAINER), NULL);
584 return gtk_args_query (class_type, container_child_arg_info_ht, arg_flags, n_args);
589 gtk_container_add_unimplemented (GtkContainer *container,
592 g_warning ("GtkContainerClass::add not implemented for `%s'", gtk_type_name (GTK_OBJECT_TYPE (container)));
596 gtk_container_remove_unimplemented (GtkContainer *container,
599 g_warning ("GtkContainerClass::remove not implemented for `%s'", gtk_type_name (GTK_OBJECT_TYPE (container)));
603 gtk_container_init (GtkContainer *container)
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;
614 gtk_container_destroy (GtkObject *object)
616 GtkContainer *container;
618 g_return_if_fail (object != NULL);
619 g_return_if_fail (GTK_IS_CONTAINER (object));
621 container = GTK_CONTAINER (object);
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);
628 gtk_container_foreach (container, (GtkCallback) gtk_widget_destroy, NULL);
630 if (GTK_OBJECT_CLASS (parent_class)->destroy)
631 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
635 gtk_container_set_arg (GtkObject *object,
639 GtkContainer *container;
641 container = GTK_CONTAINER (object);
645 case ARG_BORDER_WIDTH:
646 gtk_container_set_border_width (container, GTK_VALUE_ULONG (*arg));
648 case ARG_RESIZE_MODE:
649 gtk_container_set_resize_mode (container, GTK_VALUE_ENUM (*arg));
651 case ARG_REALLOCATE_REDRAWS:
652 gtk_container_set_reallocate_redraws (container, GTK_VALUE_BOOL (*arg));
655 gtk_container_add (container, GTK_WIDGET (GTK_VALUE_OBJECT (*arg)));
663 gtk_container_get_arg (GtkObject *object,
667 GtkContainer *container;
669 container = GTK_CONTAINER (object);
673 case ARG_BORDER_WIDTH:
674 GTK_VALUE_ULONG (*arg) = container->border_width;
676 case ARG_RESIZE_MODE:
677 GTK_VALUE_ENUM (*arg) = container->resize_mode;
679 case ARG_REALLOCATE_REDRAWS:
680 GTK_VALUE_BOOL (*arg) = container->reallocate_redraws;
683 arg->type = GTK_TYPE_INVALID;
689 gtk_container_set_border_width (GtkContainer *container,
692 g_return_if_fail (container != NULL);
693 g_return_if_fail (GTK_IS_CONTAINER (container));
695 if (container->border_width != border_width)
697 container->border_width = border_width;
699 if (GTK_WIDGET_REALIZED (container))
700 gtk_widget_queue_resize (GTK_WIDGET (container));
705 gtk_container_add (GtkContainer *container,
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);
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);
720 gtk_container_remove (GtkContainer *container,
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));
729 gtk_signal_emit (GTK_OBJECT (container), container_signals[REMOVE], widget);
733 gtk_container_dequeue_resize_handler (GtkContainer *container)
735 g_return_if_fail (GTK_IS_CONTAINER (container));
736 g_return_if_fail (GTK_CONTAINER_RESIZE_PENDING (container));
738 container_resize_queue = g_slist_remove (container_resize_queue, container);
739 GTK_PRIVATE_UNSET_FLAG (container, GTK_RESIZE_PENDING);
743 gtk_container_clear_resize_widgets (GtkContainer *container)
747 g_return_if_fail (container != NULL);
748 g_return_if_fail (GTK_IS_CONTAINER (container));
750 node = container->resize_widgets;
754 GtkWidget *widget = node->data;
756 GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
760 g_slist_free (container->resize_widgets);
761 container->resize_widgets = NULL;
765 gtk_container_set_resize_mode (GtkContainer *container,
766 GtkResizeMode resize_mode)
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);
772 if (GTK_WIDGET_TOPLEVEL (container) &&
773 resize_mode == GTK_RESIZE_PARENT)
774 resize_mode = GTK_RESIZE_QUEUE;
776 if (container->resize_mode != resize_mode)
778 container->resize_mode = resize_mode;
780 if (resize_mode == GTK_RESIZE_IMMEDIATE)
781 gtk_container_check_resize (container);
784 gtk_container_clear_resize_widgets (container);
785 gtk_widget_queue_resize (GTK_WIDGET (container));
791 gtk_container_set_reallocate_redraws (GtkContainer *container,
792 gboolean needs_redraws)
794 g_return_if_fail (GTK_IS_CONTAINER (container));
796 needs_redraws = needs_redraws ? TRUE : FALSE;
797 if (needs_redraws != container->reallocate_redraws)
799 container->reallocate_redraws = needs_redraws;
800 if (container->reallocate_redraws)
801 gtk_widget_queue_draw (GTK_WIDGET (container));
806 gtk_container_get_resize_container (GtkContainer *container)
810 widget = GTK_WIDGET (container);
812 while (widget->parent)
814 widget = widget->parent;
815 if (GTK_IS_RESIZE_CONTAINER (widget) && !GTK_WIDGET_RESIZE_NEEDED (widget))
819 return GTK_IS_RESIZE_CONTAINER (widget) ? (GtkContainer*) widget : NULL;
823 gtk_container_idle_sizer (gpointer data)
825 GDK_THREADS_ENTER ();
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.
833 while (container_resize_queue)
838 slist = container_resize_queue;
839 container_resize_queue = slist->next;
840 widget = slist->data;
841 g_slist_free_1 (slist);
843 GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_PENDING);
844 gtk_container_check_resize (GTK_CONTAINER (widget));
847 gdk_window_process_all_updates ();
849 GDK_THREADS_LEAVE ();
855 gtk_container_queue_resize (GtkContainer *container)
857 GtkContainer *resize_container;
859 g_return_if_fail (container != NULL);
860 g_return_if_fail (GTK_IS_CONTAINER (container));
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.
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))
873 resize_container = gtk_container_get_resize_container (container);
875 if (resize_container)
877 if (GTK_WIDGET_VISIBLE (resize_container) &&
878 (GTK_WIDGET_TOPLEVEL (resize_container) || GTK_WIDGET_DRAWABLE (resize_container)))
880 switch (resize_container->resize_mode)
882 case GTK_RESIZE_QUEUE:
883 if (!GTK_CONTAINER_RESIZE_PENDING (resize_container))
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,
890 container_resize_queue = g_slist_prepend (container_resize_queue, resize_container);
893 GTK_PRIVATE_SET_FLAG (container, GTK_RESIZE_NEEDED);
894 resize_container->resize_widgets =
895 g_slist_prepend (resize_container->resize_widgets, container);
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);
905 case GTK_RESIZE_PARENT:
906 /* Ignore, should not be reached */
912 /* we need to let hidden resize containers know that something
913 * changed while they where hidden (currently only evaluated by
916 resize_container->need_resize = TRUE;
922 gtk_container_check_resize (GtkContainer *container)
924 g_return_if_fail (container != NULL);
925 g_return_if_fail (GTK_IS_CONTAINER (container));
927 gtk_signal_emit (GTK_OBJECT (container), container_signals[CHECK_RESIZE]);
931 gtk_container_real_check_resize (GtkContainer *container)
934 GtkRequisition requisition;
936 g_return_if_fail (container != NULL);
937 g_return_if_fail (GTK_IS_CONTAINER (container));
939 widget = GTK_WIDGET (container);
941 gtk_widget_size_request (widget, &requisition);
943 if (requisition.width > widget->allocation.width ||
944 requisition.height > widget->allocation.height)
946 if (GTK_IS_RESIZE_CONTAINER (container))
947 gtk_widget_size_allocate (GTK_WIDGET (container),
948 >K_WIDGET (container)->allocation);
950 gtk_widget_queue_resize (widget);
954 gtk_container_resize_children (container);
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.
970 gtk_container_resize_children (GtkContainer *container)
973 GtkWidget *resize_container;
974 GSList *resize_widgets;
975 GSList *resize_containers;
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
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
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
992 g_return_if_fail (container != NULL);
993 g_return_if_fail (GTK_IS_CONTAINER (container));
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.
1002 resize_container = GTK_WIDGET (container);
1003 while (resize_container)
1005 if (GTK_WIDGET_RESIZE_NEEDED (resize_container))
1007 resize_container = resize_container->parent;
1009 if (resize_container)
1011 /* queue_resize and size_allocate both clear our
1012 * resize_widgets list.
1014 if (resize_container->parent)
1015 gtk_container_queue_resize (container);
1017 gtk_widget_size_allocate (GTK_WIDGET (container),
1018 >K_WIDGET (container)->allocation);
1022 resize_container = GTK_WIDGET (container);
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.
1028 resize_widgets = container->resize_widgets;
1029 container->resize_widgets = NULL;
1030 for (node = resize_widgets; node; node = node->next)
1032 widget = node->data;
1034 GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
1036 while (widget->parent != resize_container &&
1037 ((widget->allocation.width < widget->requisition.width) ||
1038 (widget->allocation.height < widget->requisition.height)))
1039 widget = widget->parent;
1041 GTK_PRIVATE_SET_FLAG (widget, GTK_RESIZE_NEEDED);
1042 node->data = widget;
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.
1050 resize_containers = NULL;
1051 for (node = resize_widgets; node; node = node->next)
1055 widget = node->data;
1057 if (!GTK_WIDGET_RESIZE_NEEDED (widget))
1060 parent = widget->parent;
1062 while (parent != resize_container)
1064 if (GTK_WIDGET_RESIZE_NEEDED (parent))
1066 GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
1069 parent = parent->parent;
1072 if (!g_slist_find (resize_containers, widget))
1074 resize_containers = g_slist_prepend (resize_containers, widget);
1075 gtk_widget_ref (widget);
1078 g_slist_free (resize_widgets);
1080 for (node = resize_containers; node; node = node->next)
1082 widget = node->data;
1084 GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED);
1086 gtk_widget_size_allocate (widget, &widget->allocation);
1088 gtk_widget_unref (widget);
1090 g_slist_free (resize_containers);
1094 gtk_container_forall (GtkContainer *container,
1095 GtkCallback callback,
1096 gpointer callback_data)
1098 GtkContainerClass *class;
1100 g_return_if_fail (container != NULL);
1101 g_return_if_fail (GTK_IS_CONTAINER (container));
1102 g_return_if_fail (callback != NULL);
1104 class = GTK_CONTAINER_GET_CLASS (container);
1107 class->forall (container, TRUE, callback, callback_data);
1111 gtk_container_foreach (GtkContainer *container,
1112 GtkCallback callback,
1113 gpointer callback_data)
1115 GtkContainerClass *class;
1117 g_return_if_fail (container != NULL);
1118 g_return_if_fail (GTK_IS_CONTAINER (container));
1119 g_return_if_fail (callback != NULL);
1121 class = GTK_CONTAINER_GET_CLASS (container);
1124 class->forall (container, FALSE, callback, callback_data);
1127 typedef struct _GtkForeachData GtkForeachData;
1128 struct _GtkForeachData
1130 GtkObject *container;
1131 GtkCallbackMarshal callback;
1132 gpointer callback_data;
1136 gtk_container_foreach_unmarshal (GtkWidget *child,
1139 GtkForeachData *fdata = (GtkForeachData*) data;
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);
1147 /* location for return value */
1148 args[1].name = NULL;
1149 args[1].type = GTK_TYPE_NONE;
1151 fdata->callback (fdata->container, fdata->callback_data, 1, args);
1155 gtk_container_foreach_full (GtkContainer *container,
1156 GtkCallback callback,
1157 GtkCallbackMarshal marshal,
1158 gpointer callback_data,
1159 GtkDestroyNotify notify)
1161 g_return_if_fail (container != NULL);
1162 g_return_if_fail (GTK_IS_CONTAINER (container));
1166 GtkForeachData fdata;
1168 fdata.container = GTK_OBJECT (container);
1169 fdata.callback = marshal;
1170 fdata.callback_data = callback_data;
1172 gtk_container_foreach (container, gtk_container_foreach_unmarshal, &fdata);
1176 g_return_if_fail (callback != NULL);
1178 gtk_container_foreach (container, callback, &callback_data);
1182 notify (callback_data);
1186 gtk_container_focus (GtkContainer *container,
1187 GtkDirectionType direction)
1191 g_return_val_if_fail (container != NULL, FALSE);
1192 g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
1194 gtk_signal_emit (GTK_OBJECT (container),
1195 container_signals[FOCUS],
1196 direction, &return_val);
1202 gtk_container_set_focus_child (GtkContainer *container,
1205 g_return_if_fail (container != NULL);
1206 g_return_if_fail (GTK_IS_CONTAINER (container));
1208 g_return_if_fail (GTK_IS_WIDGET (widget));
1210 gtk_signal_emit (GTK_OBJECT (container), container_signals[SET_FOCUS_CHILD], widget);
1214 gtk_container_children (GtkContainer *container)
1220 gtk_container_foreach (container,
1221 gtk_container_children_callback,
1224 return g_list_reverse (children);
1228 gtk_container_child_position_callback (GtkWidget *widget,
1229 gpointer client_data)
1235 } *data = client_data;
1238 if (data->child == widget)
1239 data->index = data->i;
1243 gtk_container_child_default_composite_name (GtkContainer *container,
1253 /* fallback implementation */
1257 gtk_container_forall (container,
1258 gtk_container_child_position_callback,
1261 name = g_strdup_printf ("%s-%u",
1262 gtk_type_name (GTK_OBJECT_TYPE (child)),
1269 gtk_container_child_composite_name (GtkContainer *container,
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);
1278 if (GTK_WIDGET_COMPOSITE_CHILD (child))
1280 static GQuark quark_composite_name = 0;
1283 if (!quark_composite_name)
1284 quark_composite_name = g_quark_from_static_string ("gtk-composite-name");
1286 name = gtk_object_get_data_by_id (GTK_OBJECT (child), quark_composite_name);
1289 GtkContainerClass *class;
1291 class = GTK_CONTAINER_GET_CLASS (container);
1292 if (class->composite_name)
1293 name = class->composite_name (container, child);
1296 name = g_strdup (name);
1305 gtk_container_real_set_focus_child (GtkContainer *container,
1308 g_return_if_fail (container != NULL);
1309 g_return_if_fail (GTK_IS_CONTAINER (container));
1311 g_return_if_fail (GTK_IS_WIDGET (child));
1313 if (child != container->focus_child)
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);
1323 /* check for h/v adjustments
1325 if (container->focus_child)
1327 GtkAdjustment *adjustment;
1329 adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container), vadjustment_key_id);
1331 gtk_adjustment_clamp_page (adjustment,
1332 container->focus_child->allocation.y,
1333 (container->focus_child->allocation.y +
1334 container->focus_child->allocation.height));
1336 adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container), hadjustment_key_id);
1338 gtk_adjustment_clamp_page (adjustment,
1339 container->focus_child->allocation.x,
1340 (container->focus_child->allocation.x +
1341 container->focus_child->allocation.width));
1346 gtk_container_real_focus (GtkContainer *container,
1347 GtkDirectionType direction)
1354 g_return_val_if_fail (container != NULL, FALSE);
1355 g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
1357 /* Fail if the container is inappropriate for focus movement
1359 if (!GTK_WIDGET_DRAWABLE (container) ||
1360 !GTK_WIDGET_IS_SENSITIVE (container))
1365 if (GTK_WIDGET_CAN_FOCUS (container))
1367 gtk_widget_grab_focus (GTK_WIDGET (container));
1372 /* Get a list of the containers children
1375 gtk_container_forall (container,
1376 gtk_container_children_callback,
1378 children = g_list_reverse (children);
1379 /* children = gtk_container_children (container); */
1383 /* Remove any children which are inappropriate for focus movement
1385 tmp_list = children;
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;
1394 tmp_list2 = tmp_list;
1395 tmp_list = tmp_list->next;
1397 children = g_list_remove_link (children, tmp_list2);
1398 g_list_free_1 (tmp_list2);
1404 case GTK_DIR_TAB_FORWARD:
1405 case GTK_DIR_TAB_BACKWARD:
1406 return_val = gtk_container_focus_tab (container, children, direction);
1410 return_val = gtk_container_focus_up_down (container, children, direction);
1414 return_val = gtk_container_focus_left_right (container, children, direction);
1418 g_list_free (children);
1426 gtk_container_focus_tab (GtkContainer *container,
1428 GtkDirectionType direction)
1436 length = g_list_length (children);
1438 /* sort the children in the y direction */
1439 for (i = 1; i < length; i++)
1442 tmp_list = g_list_nth (children, j);
1443 child = tmp_list->data;
1447 child2 = tmp_list->prev->data;
1448 if (child->allocation.y < child2->allocation.y)
1450 tmp_list->data = tmp_list->prev->data;
1451 tmp_list = tmp_list->prev;
1458 tmp_list->data = child;
1461 /* sort the children in the x direction while
1462 * maintaining the y direction sort.
1464 for (i = 1; i < length; i++)
1467 tmp_list = g_list_nth (children, j);
1468 child = tmp_list->data;
1472 child2 = tmp_list->prev->data;
1473 if ((child->allocation.x < child2->allocation.x) &&
1474 (child->allocation.y == child2->allocation.y))
1476 tmp_list->data = tmp_list->prev->data;
1477 tmp_list = tmp_list->prev;
1484 tmp_list->data = child;
1487 /* if we are going backwards then reverse the order
1490 if (direction == GTK_DIR_TAB_BACKWARD)
1491 children = g_list_reverse (children);
1493 return gtk_container_focus_move (container, children, direction);
1497 gtk_container_focus_up_down (GtkContainer *container,
1499 GtkDirectionType direction)
1510 /* return failure if there isn't a focus child */
1511 if (container->focus_child)
1513 focus_width = container->focus_child->allocation.width / 2;
1514 focus_x = container->focus_child->allocation.x + focus_width;
1518 focus_width = GTK_WIDGET (container)->allocation.width;
1519 if (GTK_WIDGET_NO_WINDOW (container))
1520 focus_x = GTK_WIDGET (container)->allocation.x;
1525 length = g_list_length (children);
1527 /* sort the children in the y direction */
1528 for (i = 1; i < length; i++)
1531 tmp_list = g_list_nth (children, j);
1532 child = tmp_list->data;
1536 child2 = tmp_list->prev->data;
1537 if (child->allocation.y < child2->allocation.y)
1539 tmp_list->data = tmp_list->prev->data;
1540 tmp_list = tmp_list->prev;
1547 tmp_list->data = child;
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
1554 for (i = 1; i < length; 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;
1563 child2 = tmp_list->prev->data;
1564 dist2 = (child2->allocation.x + child2->allocation.width / 2) - focus_x;
1566 if ((dist1 < dist2) &&
1567 (child->allocation.y >= child2->allocation.y))
1569 tmp_list->data = tmp_list->prev->data;
1570 tmp_list = tmp_list->prev;
1577 tmp_list->data = child;
1580 /* go and invalidate any widget which is too
1581 * far from the focus widget.
1583 if (!container->focus_child &&
1584 (direction == GTK_DIR_UP))
1585 focus_x += focus_width;
1587 tmp_list = children;
1590 child = tmp_list->data;
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;
1597 tmp_list = tmp_list->next;
1600 if (direction == GTK_DIR_UP)
1601 children = g_list_reverse (children);
1603 return gtk_container_focus_move (container, children, direction);
1607 gtk_container_focus_left_right (GtkContainer *container,
1609 GtkDirectionType direction)
1620 /* return failure if there isn't a focus child */
1621 if (container->focus_child)
1623 focus_height = container->focus_child->allocation.height / 2;
1624 focus_y = container->focus_child->allocation.y + focus_height;
1628 focus_height = GTK_WIDGET (container)->allocation.height;
1629 if (GTK_WIDGET_NO_WINDOW (container))
1630 focus_y = GTK_WIDGET (container)->allocation.y;
1635 length = g_list_length (children);
1637 /* sort the children in the x direction */
1638 for (i = 1; i < length; i++)
1641 tmp_list = g_list_nth (children, j);
1642 child = tmp_list->data;
1646 child2 = tmp_list->prev->data;
1647 if (child->allocation.x < child2->allocation.x)
1649 tmp_list->data = tmp_list->prev->data;
1650 tmp_list = tmp_list->prev;
1657 tmp_list->data = child;
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
1664 for (i = 1; i < length; 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;
1673 child2 = tmp_list->prev->data;
1674 dist2 = (child2->allocation.y + child2->allocation.height / 2) - focus_y;
1676 if ((dist1 < dist2) &&
1677 (child->allocation.x >= child2->allocation.x))
1679 tmp_list->data = tmp_list->prev->data;
1680 tmp_list = tmp_list->prev;
1687 tmp_list->data = child;
1690 /* go and invalidate any widget which is too
1691 * far from the focus widget.
1693 if (!container->focus_child &&
1694 (direction == GTK_DIR_LEFT))
1695 focus_y += focus_height;
1697 tmp_list = children;
1700 child = tmp_list->data;
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;
1707 tmp_list = tmp_list->next;
1710 if (direction == GTK_DIR_LEFT)
1711 children = g_list_reverse (children);
1713 return gtk_container_focus_move (container, children, direction);
1717 gtk_container_focus_move (GtkContainer *container,
1719 GtkDirectionType direction)
1721 GtkWidget *focus_child;
1724 focus_child = container->focus_child;
1725 gtk_container_set_focus_child (container, NULL);
1729 child = children->data;
1730 children = children->next;
1737 if (focus_child == child)
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))
1748 else if (GTK_WIDGET_DRAWABLE (child))
1750 if (GTK_IS_CONTAINER (child))
1752 if (gtk_container_focus (GTK_CONTAINER (child), direction))
1755 else if (GTK_WIDGET_CAN_FOCUS (child))
1757 gtk_widget_grab_focus (child);
1768 gtk_container_children_callback (GtkWidget *widget,
1769 gpointer client_data)
1773 children = (GList**) client_data;
1774 *children = g_list_prepend (*children, widget);
1778 gtk_container_set_focus_vadjustment (GtkContainer *container,
1779 GtkAdjustment *adjustment)
1781 g_return_if_fail (container != NULL);
1782 g_return_if_fail (GTK_IS_CONTAINER (container));
1784 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
1787 gtk_object_ref (GTK_OBJECT(adjustment));
1789 gtk_object_set_data_by_id_full (GTK_OBJECT (container),
1792 (GtkDestroyNotify) gtk_object_unref);
1796 gtk_container_set_focus_hadjustment (GtkContainer *container,
1797 GtkAdjustment *adjustment)
1799 g_return_if_fail (container != NULL);
1800 g_return_if_fail (GTK_IS_CONTAINER (container));
1802 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
1805 gtk_object_ref (GTK_OBJECT (adjustment));
1807 gtk_object_set_data_by_id_full (GTK_OBJECT (container),
1810 (GtkDestroyNotify) gtk_object_unref);
1815 gtk_container_show_all (GtkWidget *widget)
1817 g_return_if_fail (widget != NULL);
1818 g_return_if_fail (GTK_IS_CONTAINER (widget));
1820 gtk_container_foreach (GTK_CONTAINER (widget),
1821 (GtkCallback) gtk_widget_show_all,
1823 gtk_widget_show (widget);
1827 gtk_container_hide_all (GtkWidget *widget)
1829 g_return_if_fail (widget != NULL);
1830 g_return_if_fail (GTK_IS_CONTAINER (widget));
1832 gtk_widget_hide (widget);
1833 gtk_container_foreach (GTK_CONTAINER (widget),
1834 (GtkCallback) gtk_widget_hide_all,