X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcontainer.c;h=6563af965fdd509920b0d7541e8e959a6af725e3;hb=becb5057fc26e721e49d16b2cd1edc4834d65ce3;hp=dac0433e92283d21ec8159d33dcb1fd0d806980b;hpb=540f15dcce27b7089a0dbcb76c746bd9aeda6c6e;p=~andy%2Fgtk diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c index dac0433e9..6563af965 100644 --- a/gtk/gtkcontainer.c +++ b/gtk/gtkcontainer.c @@ -24,18 +24,23 @@ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ +#include "config.h" #include #include #include #include "gtkcontainer.h" +#include "gtkbuildable.h" +#include "gtkbuilderprivate.h" #include "gtkprivate.h" -#include "gtksignal.h" #include "gtkmain.h" +#include "gtkmarshalers.h" #include "gtkwindow.h" #include "gtkintl.h" +#include "gtktoolbar.h" #include #include +#include "gtkalias.h" enum { @@ -50,7 +55,7 @@ enum { PROP_0, PROP_BORDER_WIDTH, PROP_RESIZE_MODE, - PROP_CHILD, + PROP_CHILD }; #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id) @@ -80,15 +85,7 @@ static gboolean gtk_container_focus (GtkWidget *widget, GtkDirectionType direction); static void gtk_container_real_set_focus_child (GtkContainer *container, GtkWidget *widget); -static gboolean gtk_container_focus_tab (GtkContainer *container, - GList *children, - GtkDirectionType direction); -static gboolean gtk_container_focus_up_down (GtkContainer *container, - GList **children, - GtkDirectionType direction); -static gboolean gtk_container_focus_left_right (GtkContainer *container, - GList **children, - GtkDirectionType direction); + static gboolean gtk_container_focus_move (GtkContainer *container, GList *children, GtkDirectionType direction); @@ -104,33 +101,53 @@ static void gtk_container_unmap (GtkWidget *widget); static gchar* gtk_container_child_default_composite_name (GtkContainer *container, GtkWidget *child); +/* GtkBuildable */ +static void gtk_container_buildable_init (GtkBuildableIface *iface); +static void gtk_container_buildable_add_child (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *type); +static gboolean gtk_container_buildable_custom_tag_start (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *tagname, + GMarkupParser *parser, + gpointer *data); +static void gtk_container_buildable_custom_tag_end (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *tagname, + gpointer *data); + /* --- variables --- */ -static const gchar *vadjustment_key = "gtk-vadjustment"; +static const gchar vadjustment_key[] = "gtk-vadjustment"; static guint vadjustment_key_id = 0; -static const gchar *hadjustment_key = "gtk-hadjustment"; +static const gchar hadjustment_key[] = "gtk-hadjustment"; static guint hadjustment_key_id = 0; static GSList *container_resize_queue = NULL; static guint container_signals[LAST_SIGNAL] = { 0 }; static GtkWidgetClass *parent_class = NULL; extern GParamSpecPool *_gtk_widget_child_property_pool; extern GObjectNotifyContext *_gtk_widget_child_property_notify_context; +static GtkBuildableIface *parent_buildable_iface; /* --- functions --- */ -GtkType +GType gtk_container_get_type (void) { - static GtkType container_type = 0; + static GType container_type = 0; if (!container_type) { - static GTypeInfo container_info = { + const GTypeInfo container_info = + { sizeof (GtkContainerClass), (GBaseInitFunc) gtk_container_base_class_init, (GBaseFinalizeFunc) gtk_container_base_class_finalize, (GClassInitFunc) gtk_container_class_init, - NULL /* class_destroy */, + NULL /* class_finalize */, NULL /* class_data */, sizeof (GtkContainer), 0 /* n_preallocs */, @@ -138,7 +155,21 @@ gtk_container_get_type (void) NULL, /* value_table */ }; - container_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkContainer", &container_info, 0); + static const GInterfaceInfo buildable_info = + { + (GInterfaceInitFunc) gtk_container_buildable_init, + NULL, + NULL + }; + + container_type = + g_type_register_static (GTK_TYPE_WIDGET, I_("GtkContainer"), + &container_info, G_TYPE_FLAG_ABSTRACT); + + g_type_add_interface_static (container_type, + GTK_TYPE_BUILDABLE, + &buildable_info); + } return container_type; @@ -203,65 +234,289 @@ gtk_container_class_init (GtkContainerClass *class) g_object_class_install_property (gobject_class, PROP_RESIZE_MODE, - g_param_spec_enum ("resize_mode", - _("Resize mode"), - _("Specify how resize events are handled"), + g_param_spec_enum ("resize-mode", + P_("Resize mode"), + P_("Specify how resize events are handled"), GTK_TYPE_RESIZE_MODE, GTK_RESIZE_PARENT, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_BORDER_WIDTH, - g_param_spec_uint ("border_width", - _("Border width"), - _("The width of the empty border outside the containers children."), + g_param_spec_uint ("border-width", + P_("Border width"), + P_("The width of the empty border outside the containers children"), 0, G_MAXINT, 0, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_CHILD, g_param_spec_object ("child", - _("Child"), - _("Can be used to add a new child to the container."), + P_("Child"), + P_("Can be used to add a new child to the container"), GTK_TYPE_WIDGET, - G_PARAM_WRITABLE)); + GTK_PARAM_WRITABLE)); container_signals[ADD] = - gtk_signal_new ("add", - GTK_RUN_FIRST, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkContainerClass, add), - gtk_marshal_VOID__OBJECT, - GTK_TYPE_NONE, 1, - GTK_TYPE_WIDGET); + g_signal_new (I_("add"), + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkContainerClass, add), + NULL, NULL, + _gtk_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + GTK_TYPE_WIDGET); container_signals[REMOVE] = - gtk_signal_new ("remove", - GTK_RUN_FIRST, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkContainerClass, remove), - gtk_marshal_VOID__OBJECT, - GTK_TYPE_NONE, 1, - GTK_TYPE_WIDGET); + g_signal_new (I_("remove"), + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkContainerClass, remove), + NULL, NULL, + _gtk_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + GTK_TYPE_WIDGET); container_signals[CHECK_RESIZE] = - gtk_signal_new ("check_resize", - GTK_RUN_LAST, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkContainerClass, check_resize), - gtk_marshal_VOID__VOID, - GTK_TYPE_NONE, 0); + g_signal_new (I_("check-resize"), + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkContainerClass, check_resize), + NULL, NULL, + _gtk_marshal_VOID__VOID, + G_TYPE_NONE, 0); container_signals[SET_FOCUS_CHILD] = - gtk_signal_new ("set-focus-child", - GTK_RUN_FIRST, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkContainerClass, set_focus_child), - gtk_marshal_VOID__OBJECT, - GTK_TYPE_NONE, 1, - GTK_TYPE_WIDGET); + g_signal_new (I_("set-focus-child"), + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkContainerClass, set_focus_child), + NULL, NULL, + _gtk_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + GTK_TYPE_WIDGET); +} + +static void +gtk_container_buildable_init (GtkBuildableIface *iface) +{ + parent_buildable_iface = g_type_interface_peek_parent (iface); + iface->add_child = gtk_container_buildable_add_child; + iface->custom_tag_start = gtk_container_buildable_custom_tag_start; + iface->custom_tag_end = gtk_container_buildable_custom_tag_end; +} + +static void +gtk_container_buildable_add_child (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *type) +{ + if (type) + { + GTK_BUILDER_WARN_INVALID_CHILD_TYPE (buildable, type); + } + else if (GTK_IS_WIDGET (child) && GTK_WIDGET (child)->parent == NULL) + { + gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child)); + } + else + g_warning ("Cannot add an object of type %s to a container of type %s", + g_type_name (G_OBJECT_TYPE (child)), g_type_name (G_OBJECT_TYPE (buildable))); +} + +static void +gtk_container_buildable_set_child_property (GtkContainer *container, + GtkBuilder *builder, + GtkWidget *child, + gchar *name, + const gchar *value) +{ + GParamSpec *pspec; + GValue gvalue = { 0, }; + GError *error = NULL; + + pspec = gtk_container_class_find_child_property + (G_OBJECT_GET_CLASS (container), name); + if (!pspec) + { + g_warning ("%s does not have a property called %s", + g_type_name (G_OBJECT_TYPE (container)), name); + return; + } + + if (!gtk_builder_value_from_string (builder, pspec, value, &gvalue, &error)) + { + g_warning ("Could not read property %s:%s with value %s of type %s: %s", + g_type_name (G_OBJECT_TYPE (container)), + name, + value, + g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)), + error->message); + g_error_free (error); + return; + } + + gtk_container_child_set_property (container, child, name, &gvalue); + g_value_unset (&gvalue); +} + +typedef struct { + GtkBuilder *builder; + GtkContainer *container; + GtkWidget *child; + gchar *child_prop_name; + gchar *context; + gboolean translatable; +} PackingPropertiesData; + +static void +attributes_start_element (GMarkupParseContext *context, + const gchar *element_name, + const gchar **names, + const gchar **values, + gpointer user_data, + GError **error) +{ + PackingPropertiesData *parser_data = (PackingPropertiesData*)user_data; + guint i; + + if (strcmp (element_name, "property") == 0) + { + for (i = 0; names[i]; i++) + if (strcmp (names[i], "name") == 0) + parser_data->child_prop_name = g_strdup (values[i]); + else if (strcmp (names[i], "translatable") == 0) + { + if (!_gtk_builder_boolean_from_string (values[1], + &parser_data->translatable, + error)) + return; + } + else if (strcmp (names[i], "comments") == 0) + ; /* for translators */ + else if (strcmp (names[i], "context") == 0) + parser_data->context = g_strdup (values[1]); + else + g_warning ("Unsupported attribute for GtkContainer Child " + "property: %s\n", names[i]); + } + else if (strcmp (element_name, "packing") == 0) + return; + else + g_warning ("Unsupported tag for GtkContainer: %s\n", element_name); +} + +static void +attributes_text_element (GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error) +{ + PackingPropertiesData *parser_data = (PackingPropertiesData*)user_data; + gchar* value; + + if (!parser_data->child_prop_name) + return; + + if (parser_data->translatable && text_len) + { + const gchar* domain; + domain = gtk_builder_get_translation_domain (parser_data->builder); + + value = _gtk_builder_parser_translate (domain, + parser_data->context, + text); + } + else + { + value = g_strdup (text); + } + + gtk_container_buildable_set_child_property (parser_data->container, + parser_data->builder, + parser_data->child, + parser_data->child_prop_name, + value); + + g_free (parser_data->child_prop_name); + g_free (parser_data->context); + g_free (value); + parser_data->child_prop_name = NULL; + parser_data->context = NULL; + parser_data->translatable = FALSE; +} + +static const GMarkupParser attributes_parser = + { + attributes_start_element, + NULL, + attributes_text_element, + }; + +static gboolean +gtk_container_buildable_custom_tag_start (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *tagname, + GMarkupParser *parser, + gpointer *data) +{ + PackingPropertiesData *parser_data; + + if (parent_buildable_iface->custom_tag_start (buildable, builder, child, + tagname, parser, data)) + return TRUE; + + if (child && strcmp (tagname, "packing") == 0) + { + parser_data = g_slice_new0 (PackingPropertiesData); + parser_data->builder = builder; + parser_data->container = GTK_CONTAINER (buildable); + parser_data->child = GTK_WIDGET (child); + parser_data->child_prop_name = NULL; + + *parser = attributes_parser; + *data = parser_data; + return TRUE; + } + + return FALSE; +} + +static void +gtk_container_buildable_custom_tag_end (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *tagname, + gpointer *data) +{ + if (strcmp (tagname, "packing") == 0) + { + g_slice_free (PackingPropertiesData, (gpointer)data); + return; + + } + + if (parent_buildable_iface->custom_tag_end) + parent_buildable_iface->custom_tag_end (buildable, builder, + child, tagname, data); + } -GtkType +/** + * gtk_container_child_type: + * @container: a #GtkContainer + * + * Returns the type of the children supported by the container. + * + * Note that this may return %G_TYPE_NONE to indicate that no more + * children can be added, e.g. for a #GtkPaned which already has two + * children. + * + * Return value: a #GType. + **/ +GType gtk_container_child_type (GtkContainer *container) { - GtkType slot; + GType slot; GtkContainerClass *class; g_return_val_if_fail (GTK_IS_CONTAINER (container), 0); @@ -270,7 +525,7 @@ gtk_container_child_type (GtkContainer *container) if (class->child_type) slot = class->child_type (container); else - slot = GTK_TYPE_NONE; + slot = G_TYPE_NONE; return slot; } @@ -323,6 +578,16 @@ container_set_child_property (GtkContainer *container, g_value_unset (&tmp_value); } +/** + * gtk_container_child_get_valist: + * @container: a #GtkContainer + * @child: a widget which is a child of @container + * @first_property_name: the name of the first property to get + * @var_args: return location for the first property, followed + * optionally by more name/return location pairs, followed by %NULL + * + * Gets the values of one or more child properties for @child and @container. + **/ void gtk_container_child_get_valist (GtkContainer *container, GtkWidget *child, @@ -383,6 +648,15 @@ gtk_container_child_get_valist (GtkContainer *container, g_object_unref (container); } +/** + * gtk_container_child_get_property: + * @container: a #GtkContainer + * @child: a widget which is a child of @container + * @property_name: the name of the property to get + * @value: a location to return the value + * + * Gets the value of a child property for @child and @container. + **/ void gtk_container_child_get_property (GtkContainer *container, GtkWidget *child, @@ -424,7 +698,7 @@ gtk_container_child_get_property (GtkContainer *container, } else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value))) { - g_warning ("can't retrive child property `%s' of type `%s' as value of type `%s'", + g_warning ("can't retrieve child property `%s' of type `%s' as value of type `%s'", pspec->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)), G_VALUE_TYPE_NAME (value)); @@ -448,13 +722,22 @@ gtk_container_child_get_property (GtkContainer *container, g_object_unref (container); } +/** + * gtk_container_child_set_valist: + * @container: a #GtkContainer + * @child: a widget which is a child of @container + * @first_property_name: the name of the first property to set + * @var_args: a %NULL-terminated list of property names and values, starting + * with @first_prop_name + * + * Sets one or more child properties for @child and @container. + **/ void gtk_container_child_set_valist (GtkContainer *container, GtkWidget *child, const gchar *first_property_name, va_list var_args) { - GObject *object; GObjectNotifyQueue *nqueue; const gchar *name; @@ -465,7 +748,6 @@ gtk_container_child_set_valist (GtkContainer *container, g_object_ref (container); g_object_ref (child); - object = G_OBJECT (container); nqueue = g_object_notify_queue_freeze (G_OBJECT (child), _gtk_widget_child_property_notify_context); name = first_property_name; while (name) @@ -514,13 +796,21 @@ gtk_container_child_set_valist (GtkContainer *container, g_object_unref (child); } +/** + * gtk_container_child_set_property: + * @container: a #GtkContainer + * @child: a widget which is a child of @container + * @property_name: the name of the property to set + * @value: the value to set the property to + * + * Sets a child property for @child and @container. + **/ void gtk_container_child_set_property (GtkContainer *container, GtkWidget *child, const gchar *property_name, const GValue *value) { - GObject *object; GObjectNotifyQueue *nqueue; GParamSpec *pspec; @@ -533,7 +823,6 @@ gtk_container_child_set_property (GtkContainer *container, g_object_ref (container); g_object_ref (child); - object = G_OBJECT (container); nqueue = g_object_notify_queue_freeze (G_OBJECT (child), _gtk_widget_child_property_notify_context); pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool, property_name, G_OBJECT_TYPE (container), TRUE); @@ -556,6 +845,17 @@ gtk_container_child_set_property (GtkContainer *container, g_object_unref (child); } +/** + * gtk_container_add_with_properties: + * @container: a #GtkContainer + * @widget: a widget to be placed inside @container + * @first_prop_name: the name of the first child property to set + * @Varargs: a %NULL-terminated list of property names and values, starting + * with @first_prop_name + * + * Adds @widget to @container, setting child properties at the same time. + * See gtk_container_add() and gtk_container_child_set() for more details. + **/ void gtk_container_add_with_properties (GtkContainer *container, GtkWidget *widget, @@ -566,11 +866,11 @@ gtk_container_add_with_properties (GtkContainer *container, g_return_if_fail (GTK_IS_WIDGET (widget)); g_return_if_fail (widget->parent == NULL); - gtk_widget_ref (GTK_WIDGET (container)); - gtk_widget_ref (widget); + g_object_ref (container); + g_object_ref (widget); gtk_widget_freeze_child_notify (widget); - gtk_signal_emit (GTK_OBJECT (container), container_signals[ADD], widget); + g_signal_emit (container, container_signals[ADD], 0, widget); if (widget->parent) { va_list var_args; @@ -581,10 +881,20 @@ gtk_container_add_with_properties (GtkContainer *container, } gtk_widget_thaw_child_notify (widget); - gtk_widget_unref (widget); - gtk_widget_unref (GTK_WIDGET (container)); + g_object_unref (widget); + g_object_unref (container); } +/** + * gtk_container_child_set: + * @container: a #GtkContainer + * @child: a widget which is a child of @container + * @first_prop_name: the name of the first property to set + * @Varargs: a %NULL-terminated list of property names and values, starting + * with @first_prop_name + * + * Sets one or more child properties for @child and @container. + **/ void gtk_container_child_set (GtkContainer *container, GtkWidget *child, @@ -602,6 +912,16 @@ gtk_container_child_set (GtkContainer *container, va_end (var_args); } +/** + * gtk_container_child_get: + * @container: a #GtkContainer + * @child: a widget which is a child of @container + * @first_prop_name: the name of the first property to get + * @Varargs: return location for the first property, followed + * optionally by more name/return location pairs, followed by %NULL + * + * Gets the values of one or more child properties for @child and @container. + **/ void gtk_container_child_get (GtkContainer *container, GtkWidget *child, @@ -610,9 +930,7 @@ gtk_container_child_get (GtkContainer *container, { va_list var_args; - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); - g_return_if_fail (child != NULL); g_return_if_fail (GTK_IS_WIDGET (child)); g_return_if_fail (child->parent == GTK_WIDGET (container)); @@ -621,59 +939,85 @@ gtk_container_child_get (GtkContainer *container, va_end (var_args); } +/** + * gtk_container_class_install_child_property: + * @cclass: a #GtkContainerClass + * @property_id: the id for the property + * @pspec: the #GParamSpec for the property + * + * Installs a child property on a container class. + **/ void -gtk_container_class_install_child_property (GtkContainerClass *class, +gtk_container_class_install_child_property (GtkContainerClass *cclass, guint property_id, GParamSpec *pspec) { - g_return_if_fail (GTK_IS_CONTAINER_CLASS (class)); + g_return_if_fail (GTK_IS_CONTAINER_CLASS (cclass)); g_return_if_fail (G_IS_PARAM_SPEC (pspec)); if (pspec->flags & G_PARAM_WRITABLE) - g_return_if_fail (class->set_child_property != NULL); + g_return_if_fail (cclass->set_child_property != NULL); if (pspec->flags & G_PARAM_READABLE) - g_return_if_fail (class->get_child_property != NULL); + g_return_if_fail (cclass->get_child_property != NULL); g_return_if_fail (property_id > 0); g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */ if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0); - if (g_param_spec_pool_lookup (_gtk_widget_child_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (class), FALSE)) + if (g_param_spec_pool_lookup (_gtk_widget_child_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (cclass), FALSE)) { - g_warning (G_STRLOC ": class `%s' already contains a property named `%s'", - G_OBJECT_CLASS_NAME (class), + g_warning (G_STRLOC ": class `%s' already contains a child property named `%s'", + G_OBJECT_CLASS_NAME (cclass), pspec->name); return; } g_param_spec_ref (pspec); g_param_spec_sink (pspec); PARAM_SPEC_SET_PARAM_ID (pspec, property_id); - g_param_spec_pool_insert (_gtk_widget_child_property_pool, pspec, G_OBJECT_CLASS_TYPE (class)); + g_param_spec_pool_insert (_gtk_widget_child_property_pool, pspec, G_OBJECT_CLASS_TYPE (cclass)); } +/** + * gtk_container_class_find_child_property: + * @cclass: a #GtkContainerClass + * @property_name: the name of the child property to find + * @returns: the #GParamSpec of the child property or %NULL if @class has no + * child property with that name. + * + * Finds a child property of a container class by name. + */ GParamSpec* -gtk_container_class_find_child_property (GObjectClass *class, +gtk_container_class_find_child_property (GObjectClass *cclass, const gchar *property_name) { - g_return_val_if_fail (GTK_IS_CONTAINER_CLASS (class), NULL); + g_return_val_if_fail (GTK_IS_CONTAINER_CLASS (cclass), NULL); g_return_val_if_fail (property_name != NULL, NULL); return g_param_spec_pool_lookup (_gtk_widget_child_property_pool, property_name, - G_OBJECT_CLASS_TYPE (class), + G_OBJECT_CLASS_TYPE (cclass), TRUE); } -GParamSpec** /* free result */ -gtk_container_class_list_child_properties (GObjectClass *class, +/** + * gtk_container_class_list_child_properties: + * @cclass: a #GtkContainerClass + * @n_properties: location to return the number of child properties found + * @returns: a newly allocated %NULL-terminated array of #GParamSpec*. + * The array must be freed with g_free(). + * + * Returns all child properties of a container class. + */ +GParamSpec** +gtk_container_class_list_child_properties (GObjectClass *cclass, guint *n_properties) { GParamSpec **pspecs; guint n; - g_return_val_if_fail (GTK_IS_CONTAINER_CLASS (class), NULL); + g_return_val_if_fail (GTK_IS_CONTAINER_CLASS (cclass), NULL); pspecs = g_param_spec_pool_list (_gtk_widget_child_property_pool, - G_OBJECT_CLASS_TYPE (class), + G_OBJECT_CLASS_TYPE (cclass), &n); if (n_properties) *n_properties = n; @@ -685,14 +1029,14 @@ static void gtk_container_add_unimplemented (GtkContainer *container, GtkWidget *widget) { - g_warning ("GtkContainerClass::add not implemented for `%s'", gtk_type_name (GTK_OBJECT_TYPE (container))); + g_warning ("GtkContainerClass::add not implemented for `%s'", g_type_name (G_TYPE_FROM_INSTANCE (container))); } static void gtk_container_remove_unimplemented (GtkContainer *container, GtkWidget *widget) { - g_warning ("GtkContainerClass::remove not implemented for `%s'", gtk_type_name (GTK_OBJECT_TYPE (container))); + g_warning ("GtkContainerClass::remove not implemented for `%s'", g_type_name (G_TYPE_FROM_INSTANCE (container))); } static void @@ -703,34 +1047,25 @@ gtk_container_init (GtkContainer *container) container->need_resize = FALSE; container->resize_mode = GTK_RESIZE_PARENT; container->reallocate_redraws = FALSE; - container->resize_widgets = NULL; } static void gtk_container_destroy (GtkObject *object) { - GtkContainer *container; - - g_return_if_fail (object != NULL); - g_return_if_fail (GTK_IS_CONTAINER (object)); + GtkContainer *container = GTK_CONTAINER (object); - container = GTK_CONTAINER (object); - if (GTK_CONTAINER_RESIZE_PENDING (container)) _gtk_container_dequeue_resize_handler (container); - if (container->resize_widgets) - _gtk_container_clear_resize_widgets (container); /* do this before walking child widgets, to avoid * removing children from focus chain one by one. */ if (container->has_focus_chain) gtk_container_unset_focus_chain (container); - + gtk_container_foreach (container, (GtkCallback) gtk_widget_destroy, NULL); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); + + GTK_OBJECT_CLASS (parent_class)->destroy (object); } static void @@ -739,9 +1074,7 @@ gtk_container_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - GtkContainer *container; - - container = GTK_CONTAINER (object); + GtkContainer *container = GTK_CONTAINER (object); switch (prop_id) { @@ -766,9 +1099,7 @@ gtk_container_get_property (GObject *object, GValue *value, GParamSpec *pspec) { - GtkContainer *container; - - container = GTK_CONTAINER (object); + GtkContainer *container = GTK_CONTAINER (object); switch (prop_id) { @@ -787,28 +1118,30 @@ gtk_container_get_property (GObject *object, /** * gtk_container_set_border_width: * @container: a #GtkContainer - * @border_width: amount of blank space to leave outside the container + * @border_width: amount of blank space to leave outside + * the container. Valid values are in the range 0-65535 pixels. + * + * Sets the border width of the container. * * The border width of a container is the amount of space to leave * around the outside of the container. The only exception to this is * #GtkWindow; because toplevel windows can't leave space outside, * they leave the space inside. The border is added on all sides of * the container. To add space to only one side, one approach is to - * create a #GtkAlignment widget, call gtk_widget_set_usize() to give - * it a size, and place it on the side of the container as a spacer. - * + * create a #GtkAlignment widget, call gtk_widget_set_size_request() + * to give it a size, and place it on the side of the container as + * a spacer. **/ void gtk_container_set_border_width (GtkContainer *container, guint border_width) { - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); if (container->border_width != border_width) { container->border_width = border_width; - g_object_notify (G_OBJECT (container), "border_width"); + g_object_notify (G_OBJECT (container), "border-width"); if (GTK_WIDGET_REALIZED (container)) gtk_widget_queue_resize (GTK_WIDGET (container)); @@ -850,23 +1183,22 @@ void gtk_container_add (GtkContainer *container, GtkWidget *widget) { - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); - g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_WIDGET (widget)); if (widget->parent != NULL) { g_warning ("Attempting to add a widget with type %s to a container of " "type %s, but the widget is already inside a container of type %s, " - "the GTK+ FAQ at http://www.gtk.org/faq/ explains how to reparent a widget.", + "the GTK+ FAQ at http://library.gnome.org/devel/gtk-faq/stable/ " + "explains how to reparent a widget.", g_type_name (G_OBJECT_TYPE (widget)), g_type_name (G_OBJECT_TYPE (container)), g_type_name (G_OBJECT_TYPE (widget->parent))); return; } - gtk_signal_emit (GTK_OBJECT (container), container_signals[ADD], widget); + g_signal_emit (container, container_signals[ADD], 0, widget); } /** @@ -879,19 +1211,26 @@ gtk_container_add (GtkContainer *container, * may be the last reference held; so removing a widget from its * container can destroy that widget. If you want to use @widget * again, you need to add a reference to it while it's not inside - * a container, using g_object_ref(). + * a container, using g_object_ref(). If you don't want to use @widget + * again it's usually more efficient to simply destroy it directly + * using gtk_widget_destroy() since this will remove it from the + * container and help break any circular reference count cycles. **/ void gtk_container_remove (GtkContainer *container, GtkWidget *widget) { - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); - g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_WIDGET (widget)); - g_return_if_fail (widget->parent == GTK_WIDGET (container)); + + /* When using the deprecated API of the toolbar, it is possible + * to legitimately call this function with a widget that is not + * a direct child of the container. + */ + g_return_if_fail (GTK_IS_TOOLBAR (container) || + widget->parent == GTK_WIDGET (container)); - gtk_signal_emit (GTK_OBJECT (container), container_signals[REMOVE], widget); + g_signal_emit (container, container_signals[REMOVE], 0, widget); } void @@ -904,33 +1243,21 @@ _gtk_container_dequeue_resize_handler (GtkContainer *container) GTK_PRIVATE_UNSET_FLAG (container, GTK_RESIZE_PENDING); } -void -_gtk_container_clear_resize_widgets (GtkContainer *container) -{ - GSList *node; - - g_return_if_fail (container != NULL); - g_return_if_fail (GTK_IS_CONTAINER (container)); - - node = container->resize_widgets; - - while (node) - { - GtkWidget *widget = node->data; - - GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED); - node = node->next; - } - - g_slist_free (container->resize_widgets); - container->resize_widgets = NULL; -} - +/** + * gtk_container_set_resize_mode: + * @container: a #GtkContainer + * @resize_mode: the new resize mode + * + * Sets the resize mode for the container. + * + * The resize mode of a container determines whether a resize request + * will be passed to the container's parent, queued for later execution + * or executed immediately. + **/ void gtk_container_set_resize_mode (GtkContainer *container, GtkResizeMode resize_mode) { - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); g_return_if_fail (resize_mode <= GTK_RESIZE_IMMEDIATE); @@ -938,21 +1265,14 @@ gtk_container_set_resize_mode (GtkContainer *container, resize_mode == GTK_RESIZE_PARENT) { resize_mode = GTK_RESIZE_QUEUE; - g_object_notify (G_OBJECT (container), "resize_mode"); } if (container->resize_mode != resize_mode) { container->resize_mode = resize_mode; - if (resize_mode == GTK_RESIZE_IMMEDIATE) - gtk_container_check_resize (container); - else - { - _gtk_container_clear_resize_widgets (container); - gtk_widget_queue_resize (GTK_WIDGET (container)); - } - g_object_notify (G_OBJECT (container), "resize_mode"); + gtk_widget_queue_resize (GTK_WIDGET (container)); + g_object_notify (G_OBJECT (container), "resize-mode"); } } @@ -973,6 +1293,16 @@ gtk_container_get_resize_mode (GtkContainer *container) return container->resize_mode; } +/** + * gtk_container_set_reallocate_redraws: + * @container: a #GtkContainer + * @needs_redraws: the new value for the container's @reallocate_redraws flag + * + * Sets the @reallocate_redraws flag of the container to the given value. + * + * Containers requesting reallocation redraws get automatically + * redrawn if any of their children changed allocation. + **/ void gtk_container_set_reallocate_redraws (GtkContainer *container, gboolean needs_redraws) @@ -985,14 +1315,12 @@ gtk_container_set_reallocate_redraws (GtkContainer *container, static GtkContainer* gtk_container_get_resize_container (GtkContainer *container) { - GtkWidget *widget; - - widget = GTK_WIDGET (container); + GtkWidget *widget = GTK_WIDGET (container); while (widget->parent) { widget = widget->parent; - if (GTK_IS_RESIZE_CONTAINER (widget) && !GTK_WIDGET_RESIZE_NEEDED (widget)) + if (GTK_IS_RESIZE_CONTAINER (widget)) break; } @@ -1002,8 +1330,6 @@ gtk_container_get_resize_container (GtkContainer *container) static gboolean gtk_container_idle_sizer (gpointer data) { - GDK_THREADS_ENTER (); - /* we may be invoked with a container_resize_queue of NULL, because * queue_resize could have been adding an extra idle function while * the queue still got processed. we better just ignore such case @@ -1026,8 +1352,6 @@ gtk_container_idle_sizer (gpointer data) gdk_window_process_all_updates (); - GDK_THREADS_LEAVE (); - return FALSE; } @@ -1035,27 +1359,28 @@ void _gtk_container_queue_resize (GtkContainer *container) { GtkContainer *resize_container; + GtkWidget *widget; - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); - /* clear resize widgets for resize containers - * before aborting prematurely. this is especially - * important for toplevels which may need imemdiate - * processing or their resize handler to be queued. - */ - if (GTK_IS_RESIZE_CONTAINER (container)) - _gtk_container_clear_resize_widgets (container); - if (GTK_OBJECT_DESTROYED (container) || - GTK_WIDGET_RESIZE_NEEDED (container)) - return; - + widget = GTK_WIDGET (container); resize_container = gtk_container_get_resize_container (container); + while (TRUE) + { + GTK_PRIVATE_SET_FLAG (widget, GTK_ALLOC_NEEDED); + GTK_PRIVATE_SET_FLAG (widget, GTK_REQUEST_NEEDED); + if ((resize_container && widget == GTK_WIDGET (resize_container)) || + !widget->parent) + break; + + widget = widget->parent; + } + if (resize_container) { if (GTK_WIDGET_VISIBLE (resize_container) && - (GTK_WIDGET_TOPLEVEL (resize_container) || GTK_WIDGET_DRAWABLE (resize_container))) + (GTK_WIDGET_TOPLEVEL (resize_container) || GTK_WIDGET_REALIZED (resize_container))) { switch (resize_container->resize_mode) { @@ -1064,26 +1389,19 @@ _gtk_container_queue_resize (GtkContainer *container) { GTK_PRIVATE_SET_FLAG (resize_container, GTK_RESIZE_PENDING); if (container_resize_queue == NULL) - gtk_idle_add_priority (GTK_PRIORITY_RESIZE, - gtk_container_idle_sizer, - NULL); + gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE, + gtk_container_idle_sizer, + NULL, NULL); container_resize_queue = g_slist_prepend (container_resize_queue, resize_container); } - - GTK_PRIVATE_SET_FLAG (container, GTK_RESIZE_NEEDED); - resize_container->resize_widgets = - g_slist_prepend (resize_container->resize_widgets, container); break; case GTK_RESIZE_IMMEDIATE: - GTK_PRIVATE_SET_FLAG (container, GTK_RESIZE_NEEDED); - resize_container->resize_widgets = - g_slist_prepend (resize_container->resize_widgets, container); gtk_container_check_resize (resize_container); break; case GTK_RESIZE_PARENT: - /* Ignore, should not be reached */ + g_assert_not_reached (); break; } } @@ -1101,23 +1419,17 @@ _gtk_container_queue_resize (GtkContainer *container) void gtk_container_check_resize (GtkContainer *container) { - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); - gtk_signal_emit (GTK_OBJECT (container), container_signals[CHECK_RESIZE]); + g_signal_emit (container, container_signals[CHECK_RESIZE], 0); } static void gtk_container_real_check_resize (GtkContainer *container) { - GtkWidget *widget; + GtkWidget *widget = GTK_WIDGET (container); GtkRequisition requisition; - g_return_if_fail (container != NULL); - g_return_if_fail (GTK_IS_CONTAINER (container)); - - widget = GTK_WIDGET (container); - gtk_widget_size_request (widget, &requisition); if (requisition.width > widget->allocation.width || @@ -1139,135 +1451,23 @@ gtk_container_real_check_resize (GtkContainer *container) * queued a resize request. Which means that the allocation * is not sufficient for the requisition of some child. * We've already performed a size request at this point, - * so we simply need to run through the list of resize - * widgets and reallocate their sizes appropriately. We - * make the optimization of not performing reallocation - * for a widget who also has a parent in the resize widgets - * list. GTK_RESIZE_NEEDED is used for flagging those - * parents inside this function. + * so we simply need to reallocate and let the allocation + * trickle down via GTK_WIDGET_ALLOC_NEEDED flags. */ void gtk_container_resize_children (GtkContainer *container) { GtkWidget *widget; - GtkWidget *resize_container; - GSList *resize_widgets; - GSList *resize_containers; - GSList *node; /* resizing invariants: * toplevels have *always* resize_mode != GTK_RESIZE_PARENT set. - * containers with resize_mode==GTK_RESIZE_PARENT have to have resize_widgets - * set to NULL. - * containers that are flagged RESIZE_NEEDED must have resize_widgets set to - * NULL, or are toplevels (thus have ->parent set to NULL). - * widgets that are in some container->resize_widgets list must be flagged with - * RESIZE_NEEDED. - * widgets that have RESIZE_NEEDED set must be referenced in some - * GTK_IS_RESIZE_CONTAINER (container)->resize_widgets list. * containers that have an idle sizer pending must be flagged with * RESIZE_PENDING. */ - - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); - /* we first check out if we actually need to perform a resize, - * which is not the case if we got another container queued for - * a resize in our ancestry. also we can skip the whole - * resize_widgets checks if we are a toplevel and NEED_RESIZE. - * this code assumes that our allocation is sufficient for our - * requisition, since otherwise we would NEED_RESIZE. - */ - resize_container = GTK_WIDGET (container); - while (resize_container) - { - if (GTK_WIDGET_RESIZE_NEEDED (resize_container)) - break; - resize_container = resize_container->parent; - } - if (resize_container) - { - /* queue_resize and size_allocate both clear our - * resize_widgets list. - */ - if (resize_container->parent) - _gtk_container_queue_resize (container); - else - gtk_widget_size_allocate (GTK_WIDGET (container), - >K_WIDGET (container)->allocation); - return; - } - - resize_container = GTK_WIDGET (container); - - /* we now walk the ancestry for all resize widgets as long - * as they are our children and as long as their allocation - * is insufficient, since we don't need to reallocate below that. - */ - resize_widgets = container->resize_widgets; - container->resize_widgets = NULL; - for (node = resize_widgets; node; node = node->next) - { - widget = node->data; - - GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED); - - while (widget->parent != resize_container && - ((widget->allocation.width < widget->requisition.width) || - (widget->allocation.height < widget->requisition.height))) - widget = widget->parent; - - GTK_PRIVATE_SET_FLAG (widget, GTK_RESIZE_NEEDED); - node->data = widget; - } - - /* for the newly setup resize_widgets list, we now walk each widget's - * ancestry to sort those widgets out that have RESIZE_NEEDED parents. - * we can safely stop the walk if we are the parent, since we checked - * our own ancestry already. - */ - resize_containers = NULL; - for (node = resize_widgets; node; node = node->next) - { - GtkWidget *parent; - - widget = node->data; - - if (!GTK_WIDGET_RESIZE_NEEDED (widget)) - continue; - - parent = widget->parent; - - while (parent != resize_container) - { - if (GTK_WIDGET_RESIZE_NEEDED (parent)) - { - GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED); - widget = parent; - } - parent = parent->parent; - } - - if (!g_slist_find (resize_containers, widget)) - { - resize_containers = g_slist_prepend (resize_containers, widget); - gtk_widget_ref (widget); - } - } - g_slist_free (resize_widgets); - - for (node = resize_containers; node; node = node->next) - { - widget = node->data; - - GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_NEEDED); - - gtk_widget_size_allocate (widget, &widget->allocation); - - gtk_widget_unref (widget); - } - g_slist_free (resize_containers); + widget = GTK_WIDGET (container); + gtk_widget_size_allocate (widget, &widget->allocation); } /** @@ -1290,7 +1490,6 @@ gtk_container_forall (GtkContainer *container, { GtkContainerClass *class; - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); g_return_if_fail (callback != NULL); @@ -1306,7 +1505,7 @@ gtk_container_forall (GtkContainer *container, * @callback: a callback * @callback_data: callback user data * - * Invokes @callback on each non-internal child of @container. See + * Invokes @callback on each non-internal child of @container. See * gtk_container_forall() for details on what constitutes an * "internal" child. Most applications should use * gtk_container_foreach(), rather than gtk_container_forall(). @@ -1318,7 +1517,6 @@ gtk_container_foreach (GtkContainer *container, { GtkContainerClass *class; - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); g_return_if_fail (callback != NULL); @@ -1345,12 +1543,12 @@ gtk_container_foreach_unmarshal (GtkWidget *child, /* first argument */ args[0].name = NULL; - args[0].type = GTK_OBJECT_TYPE (child); + args[0].type = G_TYPE_FROM_INSTANCE (child); GTK_VALUE_OBJECT (args[0]) = GTK_OBJECT (child); /* location for return value */ args[1].name = NULL; - args[1].type = GTK_TYPE_NONE; + args[1].type = G_TYPE_NONE; fdata->callback (fdata->container, fdata->callback_data, 1, args); } @@ -1360,9 +1558,8 @@ gtk_container_foreach_full (GtkContainer *container, GtkCallback callback, GtkCallbackMarshal marshal, gpointer callback_data, - GtkDestroyNotify notify) + GDestroyNotify notify) { - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); if (marshal) @@ -1386,24 +1583,60 @@ gtk_container_foreach_full (GtkContainer *container, notify (callback_data); } +/** + * gtk_container_set_focus_child: + * @container: a #GtkContainer + * @child: a #GtkWidget, or %NULL + * + * Sets, or unsets if @child is %NULL, the focused child of @container. + * + * This function emits the GtkContainer::set_focus_child signal of + * @container. Implementations of #GtkContainer can override the + * default behaviour by overriding the class closure of this signal. + */ void gtk_container_set_focus_child (GtkContainer *container, - GtkWidget *widget) + GtkWidget *child) { - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); - if (widget) - g_return_if_fail (GTK_IS_WIDGET (widget)); + if (child) + g_return_if_fail (GTK_IS_WIDGET (child)); + + g_signal_emit (container, container_signals[SET_FOCUS_CHILD], 0, child); +} + +/** + * gtk_container_get_focus_child: + * @container: a #GtkContainer + * + * Returns the current focus child widget inside @container. + * + * Returns: The child widget which has the focus + * inside @container, or %NULL if none is set. + * + * Since: 2.14 + **/ +GtkWidget * +gtk_container_get_focus_child (GtkContainer *container) +{ + g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL); - gtk_signal_emit (GTK_OBJECT (container), container_signals[SET_FOCUS_CHILD], widget); + return container->focus_child; } +/** + * gtk_container_get_children: + * @container: a #GtkContainer + * + * Returns the container's non-internal children. See + * gtk_container_forall() for details on what constitutes an "internal" child. + * + * Return value: a newly-allocated list of the container's non-internal children. + **/ GList* gtk_container_get_children (GtkContainer *container) { - GList *children; - - children = NULL; + GList *children = NULL; gtk_container_foreach (container, gtk_container_children_callback, @@ -1447,7 +1680,7 @@ gtk_container_child_default_composite_name (GtkContainer *container, &data); name = g_strdup_printf ("%s-%u", - gtk_type_name (GTK_OBJECT_TYPE (child)), + g_type_name (G_TYPE_FROM_INSTANCE (child)), data.index); return name; @@ -1457,9 +1690,7 @@ gchar* _gtk_container_child_composite_name (GtkContainer *container, GtkWidget *child) { - g_return_val_if_fail (container != NULL, NULL); g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL); - g_return_val_if_fail (child != NULL, NULL); g_return_val_if_fail (GTK_IS_WIDGET (child), NULL); g_return_val_if_fail (child->parent == GTK_WIDGET (container), NULL); @@ -1471,7 +1702,7 @@ _gtk_container_child_composite_name (GtkContainer *container, if (!quark_composite_name) quark_composite_name = g_quark_from_static_string ("gtk-composite-name"); - name = gtk_object_get_data_by_id (GTK_OBJECT (child), quark_composite_name); + name = g_object_get_qdata (G_OBJECT (child), quark_composite_name); if (!name) { GtkContainerClass *class; @@ -1493,18 +1724,16 @@ static void gtk_container_real_set_focus_child (GtkContainer *container, GtkWidget *child) { - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); - if (child) - g_return_if_fail (GTK_IS_WIDGET (child)); + g_return_if_fail (child == NULL || GTK_IS_WIDGET (child)); if (child != container->focus_child) { if (container->focus_child) - gtk_widget_unref (container->focus_child); + g_object_unref (container->focus_child); container->focus_child = child; if (container->focus_child) - gtk_widget_ref (container->focus_child); + g_object_ref (container->focus_child); } @@ -1512,21 +1741,35 @@ gtk_container_real_set_focus_child (GtkContainer *container, */ if (container->focus_child) { - GtkAdjustment *adjustment; - - adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container), vadjustment_key_id); - if (adjustment) - gtk_adjustment_clamp_page (adjustment, - container->focus_child->allocation.y, - (container->focus_child->allocation.y + - container->focus_child->allocation.height)); - - adjustment = gtk_object_get_data_by_id (GTK_OBJECT (container), hadjustment_key_id); - if (adjustment) - gtk_adjustment_clamp_page (adjustment, - container->focus_child->allocation.x, - (container->focus_child->allocation.x + - container->focus_child->allocation.width)); + GtkAdjustment *hadj; + GtkAdjustment *vadj; + GtkWidget *focus_child; + gint x, y; + + hadj = g_object_get_qdata (G_OBJECT (container), hadjustment_key_id); + vadj = g_object_get_qdata (G_OBJECT (container), vadjustment_key_id); + if (hadj || vadj) + { + + focus_child = container->focus_child; + while (GTK_IS_CONTAINER (focus_child) && + GTK_CONTAINER (focus_child)->focus_child) + { + focus_child = GTK_CONTAINER (focus_child)->focus_child; + } + + gtk_widget_translate_coordinates (focus_child, container->focus_child, + 0, 0, &x, &y); + + x += container->focus_child->allocation.x; + y += container->focus_child->allocation.y; + + if (vadj) + gtk_adjustment_clamp_page (vadj, y, y + focus_child->allocation.height); + + if (hadj) + gtk_adjustment_clamp_page (hadj, x, x + focus_child->allocation.width); + } } } @@ -1536,31 +1779,18 @@ get_focus_chain (GtkContainer *container) return g_object_get_data (G_OBJECT (container), "gtk-container-focus-chain"); } -static GList* -filter_unfocusable (GtkContainer *container, - GList *list) +/* same as gtk_container_get_children, except it includes internals + */ +static GList * +gtk_container_get_all_children (GtkContainer *container) { - GList *tmp_list; - GList *tmp_list2; - - tmp_list = list; - while (tmp_list) - { - if (GTK_WIDGET_IS_SENSITIVE (tmp_list->data) && - GTK_WIDGET_DRAWABLE (tmp_list->data) && - (GTK_IS_CONTAINER (tmp_list->data) || GTK_WIDGET_CAN_FOCUS (tmp_list->data))) - tmp_list = tmp_list->next; - else - { - tmp_list2 = tmp_list; - tmp_list = tmp_list->next; - - list = g_list_remove_link (list, tmp_list2); - g_list_free_1 (tmp_list2); - } - } + GList *children = NULL; + + gtk_container_forall (container, + gtk_container_children_callback, + &children); - return list; + return children; } static gboolean @@ -1568,6 +1798,7 @@ gtk_container_focus (GtkWidget *widget, GtkDirectionType direction) { GList *children; + GList *sorted_children; gint return_val; GtkContainer *container; @@ -1591,183 +1822,146 @@ gtk_container_focus (GtkWidget *widget, * chain to override. */ if (container->has_focus_chain) - { - children = g_list_copy (get_focus_chain (container)); - } + children = g_list_copy (get_focus_chain (container)); else - { - children = NULL; - gtk_container_forall (container, - gtk_container_children_callback, - &children); - children = g_list_reverse (children); - } + children = gtk_container_get_all_children (container); - if (children) + if (container->has_focus_chain && + (direction == GTK_DIR_TAB_FORWARD || + direction == GTK_DIR_TAB_BACKWARD)) { - /* Remove any children which are inappropriate for focus movement - */ - children = filter_unfocusable (container, children); - - switch (direction) - { - case GTK_DIR_TAB_FORWARD: - case GTK_DIR_TAB_BACKWARD: - if (container->has_focus_chain) - { - if (direction == GTK_DIR_TAB_BACKWARD) - children = g_list_reverse (children); - return_val = gtk_container_focus_move (container, children, direction); - } - else - return_val = gtk_container_focus_tab (container, children, direction); - break; - case GTK_DIR_UP: - case GTK_DIR_DOWN: - return_val = gtk_container_focus_up_down (container, &children, direction); - break; - case GTK_DIR_LEFT: - case GTK_DIR_RIGHT: - return_val = gtk_container_focus_left_right (container, &children, direction); - break; - } - - g_list_free (children); + sorted_children = g_list_copy (children); + + if (direction == GTK_DIR_TAB_BACKWARD) + sorted_children = g_list_reverse (sorted_children); } + else + sorted_children = _gtk_container_focus_sort (container, children, direction, NULL); + + return_val = gtk_container_focus_move (container, sorted_children, direction); + + g_list_free (sorted_children); + g_list_free (children); } return return_val; } -static gboolean -gtk_container_focus_tab (GtkContainer *container, - GList *children, - GtkDirectionType direction) +static gint +tab_compare (gconstpointer a, + gconstpointer b, + gpointer data) { - GtkWidget *child; - GtkWidget *child2; - GList *tmp_list; - guint length; - guint i, j; + const GtkWidget *child1 = a; + const GtkWidget *child2 = b; + GtkTextDirection text_direction = GPOINTER_TO_INT (data); - length = g_list_length (children); + gint y1 = child1->allocation.y + child1->allocation.height / 2; + gint y2 = child2->allocation.y + child2->allocation.height / 2; - /* sort the children in the y direction */ - for (i = 1; i < length; i++) + if (y1 == y2) { - j = i; - tmp_list = g_list_nth (children, j); - child = tmp_list->data; - - while (j > 0) - { - child2 = tmp_list->prev->data; - if (child->allocation.y < child2->allocation.y) - { - tmp_list->data = tmp_list->prev->data; - tmp_list = tmp_list->prev; - j--; - } - else - break; - } - - tmp_list->data = child; + gint x1 = child1->allocation.x + child1->allocation.width / 2; + gint x2 = child2->allocation.x + child2->allocation.width / 2; + + if (text_direction == GTK_TEXT_DIR_RTL) + return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1); + else + return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1); } + else + return (y1 < y2) ? -1 : 1; +} + +static GList * +gtk_container_focus_sort_tab (GtkContainer *container, + GList *children, + GtkDirectionType direction, + GtkWidget *old_focus) +{ + GtkTextDirection text_direction = gtk_widget_get_direction (GTK_WIDGET (container)); + children = g_list_sort_with_data (children, tab_compare, GINT_TO_POINTER (text_direction)); - /* sort the children in the x direction while - * maintaining the y direction sort. + /* if we are going backwards then reverse the order + * of the children. */ - for (i = 1; i < length; i++) + if (direction == GTK_DIR_TAB_BACKWARD) + children = g_list_reverse (children); + + return children; +} + +/* Get coordinates of @widget's allocation with respect to + * allocation of @container. + */ +static gboolean +get_allocation_coords (GtkContainer *container, + GtkWidget *widget, + GdkRectangle *allocation) +{ + *allocation = widget->allocation; + + return gtk_widget_translate_coordinates (widget, GTK_WIDGET (container), + 0, 0, &allocation->x, &allocation->y); +} + +/* Look for a child in @children that is intermediate between + * the focus widget and container. This widget, if it exists, + * acts as the starting widget for focus navigation. + */ +static GtkWidget * +find_old_focus (GtkContainer *container, + GList *children) +{ + GList *tmp_list = children; + while (tmp_list) { - j = i; - tmp_list = g_list_nth (children, j); - child = tmp_list->data; + GtkWidget *child = tmp_list->data; + GtkWidget *widget = child; - while (j > 0) + while (widget && widget != (GtkWidget *)container) { - child2 = tmp_list->prev->data; - if ((child->allocation.x < child2->allocation.x) && - (child->allocation.y == child2->allocation.y)) - { - tmp_list->data = tmp_list->prev->data; - tmp_list = tmp_list->prev; - j--; - } - else - break; + GtkWidget *parent = widget->parent; + if (parent && ((GtkContainer *)parent)->focus_child != widget) + goto next; + + widget = parent; } - tmp_list->data = child; - } + return child; - /* if we are going backwards then reverse the order - * of the children. - */ - if (direction == GTK_DIR_TAB_BACKWARD) - children = g_list_reverse (children); + next: + tmp_list = tmp_list->next; + } - return gtk_container_focus_move (container, children, direction); + return NULL; } static gboolean -old_focus_coords (GtkContainer *container, GdkRectangle *old_focus_rect) +old_focus_coords (GtkContainer *container, + GdkRectangle *old_focus_rect) { GtkWidget *widget = GTK_WIDGET (container); GtkWidget *toplevel = gtk_widget_get_toplevel (widget); - - if (toplevel && - GTK_IS_WINDOW (toplevel) && GTK_WINDOW (toplevel)->focus_widget && - GTK_WIDGET_REALIZED (container) && - GTK_WIDGET_REALIZED (GTK_WINDOW (toplevel)->focus_widget)) + + if (GTK_IS_WINDOW (toplevel) && GTK_WINDOW (toplevel)->focus_widget) { GtkWidget *old_focus = GTK_WINDOW (toplevel)->focus_widget; - GdkWindow *old_parent_window = old_focus->parent ? old_focus->parent->window : old_focus->window; - GdkWindow *new_parent_window = widget->window; - GdkWindow *toplevel_window = toplevel->window; - - *old_focus_rect = old_focus->allocation; - - /* Translate coordinates to the toplevel */ - - while (old_parent_window != toplevel_window) - { - gint dx, dy; - - gdk_window_get_position (old_parent_window, &dx, &dy); - - old_focus_rect->x += dx; - old_focus_rect->y += dy; - - old_parent_window = gdk_window_get_parent (old_parent_window); - } - - /* Translate coordinates back to the new container */ - while (new_parent_window != toplevel_window) - { - gint dx, dy; - - gdk_window_get_position (new_parent_window, &dx, &dy); - - old_focus_rect->x -= dx; - old_focus_rect->y -= dy; - - new_parent_window = gdk_window_get_parent (new_parent_window); - } - - return TRUE; + return get_allocation_coords (container, old_focus, old_focus_rect); } - - return FALSE; + else + return FALSE; } typedef struct _CompareInfo CompareInfo; struct _CompareInfo { + GtkContainer *container; gint x; gint y; + gboolean reverse; }; static gint @@ -1775,76 +1969,94 @@ up_down_compare (gconstpointer a, gconstpointer b, gpointer data) { - const GtkWidget *child1 = a; - const GtkWidget *child2 = b; + GdkRectangle allocation1; + GdkRectangle allocation2; CompareInfo *compare = data; + gint y1, y2; - gint y1 = child1->allocation.y + child1->allocation.height / 2; - gint y2 = child2->allocation.y + child2->allocation.height / 2; + get_allocation_coords (compare->container, (GtkWidget *)a, &allocation1); + get_allocation_coords (compare->container, (GtkWidget *)b, &allocation2); + + y1 = allocation1.y + allocation1.height / 2; + y2 = allocation2.y + allocation2.height / 2; if (y1 == y2) { - gint x1 = abs (child1->allocation.x + child1->allocation.width / 2 - compare->x); - gint x2 = abs (child2->allocation.x + child2->allocation.width / 2 - compare->x); + gint x1 = abs (allocation1.x + allocation1.width / 2 - compare->x); + gint x2 = abs (allocation2.x + allocation2.width / 2 - compare->x); - if (compare->y < y1) - return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1); - else + if (compare->reverse) return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1); + else + return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1); } else return (y1 < y2) ? -1 : 1; } -static gboolean -gtk_container_focus_up_down (GtkContainer *container, - GList **children, - GtkDirectionType direction) +static GList * +gtk_container_focus_sort_up_down (GtkContainer *container, + GList *children, + GtkDirectionType direction, + GtkWidget *old_focus) { CompareInfo compare; GList *tmp_list; + GdkRectangle old_allocation; - if (container->focus_child) + compare.container = container; + compare.reverse = (direction == GTK_DIR_UP); + + if (!old_focus) + old_focus = find_old_focus (container, children); + + if (old_focus && get_allocation_coords (container, old_focus, &old_allocation)) { gint compare_x1; gint compare_x2; gint compare_y; - + /* Delete widgets from list that don't match minimum criteria */ - compare_x1 = container->focus_child->allocation.x; - compare_x2 = container->focus_child->allocation.x + container->focus_child->allocation.width; + compare_x1 = old_allocation.x; + compare_x2 = old_allocation.x + old_allocation.width; if (direction == GTK_DIR_UP) - compare_y = container->focus_child->allocation.y; + compare_y = old_allocation.y; else - compare_y = container->focus_child->allocation.y + container->focus_child->allocation.height; + compare_y = old_allocation.y + old_allocation.height; - tmp_list = *children; + tmp_list = children; while (tmp_list) { GtkWidget *child = tmp_list->data; GList *next = tmp_list->next; gint child_x1, child_x2; + GdkRectangle child_allocation; - if (child != container->focus_child) + if (child != old_focus) { - child_x1 = child->allocation.x; - child_x2 = child->allocation.x + child->allocation.width; - - if ((child_x2 <= compare_x1 || child_x1 >= compare_x2) /* No horizontal overlap */ || - (direction == GTK_DIR_DOWN && child->allocation.y + child->allocation.height < compare_y) || /* Not below */ - (direction == GTK_DIR_UP && child->allocation.y > compare_y)) /* Not above */ + if (get_allocation_coords (container, child, &child_allocation)) { - *children = g_list_delete_link (*children, tmp_list); + child_x1 = child_allocation.x; + child_x2 = child_allocation.x + child_allocation.width; + + if ((child_x2 <= compare_x1 || child_x1 >= compare_x2) /* No horizontal overlap */ || + (direction == GTK_DIR_DOWN && child_allocation.y + child_allocation.height < compare_y) || /* Not below */ + (direction == GTK_DIR_UP && child_allocation.y > compare_y)) /* Not above */ + { + children = g_list_delete_link (children, tmp_list); + } } + else + children = g_list_delete_link (children, tmp_list); } tmp_list = next; } compare.x = (compare_x1 + compare_x2) / 2; - compare.y = container->focus_child->allocation.y + container->focus_child->allocation.height / 2; + compare.y = old_allocation.y + old_allocation.height / 2; } else { @@ -1871,12 +2083,12 @@ gtk_container_focus_up_down (GtkContainer *container, compare.y = (direction == GTK_DIR_DOWN) ? 0 : + widget->allocation.height; } - *children = g_list_sort_with_data (*children, up_down_compare, &compare); + children = g_list_sort_with_data (children, up_down_compare, &compare); - if (direction == GTK_DIR_UP) - *children = g_list_reverse (*children); + if (compare.reverse) + children = g_list_reverse (children); - return gtk_container_focus_move (container, *children, direction); + return children; } static gint @@ -1884,36 +2096,48 @@ left_right_compare (gconstpointer a, gconstpointer b, gpointer data) { - const GtkWidget *child1 = a; - const GtkWidget *child2 = b; + GdkRectangle allocation1; + GdkRectangle allocation2; CompareInfo *compare = data; + gint x1, x2; + + get_allocation_coords (compare->container, (GtkWidget *)a, &allocation1); + get_allocation_coords (compare->container, (GtkWidget *)b, &allocation2); - gint x1 = child1->allocation.x + child1->allocation.width / 2; - gint x2 = child2->allocation.x + child2->allocation.width / 2; + x1 = allocation1.x + allocation1.width / 2; + x2 = allocation2.x + allocation2.width / 2; if (x1 == x2) { - gint y1 = abs (child1->allocation.y + child1->allocation.height / 2 - compare->y); - gint y2 = abs (child2->allocation.y + child2->allocation.height / 2 - compare->y); + gint y1 = abs (allocation1.y + allocation1.height / 2 - compare->y); + gint y2 = abs (allocation2.y + allocation2.height / 2 - compare->y); - if (compare->x < x1) - return (y1 < y2) ? -1 : ((y1 == y2) ? 0 : 1); - else + if (compare->reverse) return (y1 < y2) ? 1 : ((y1 == y2) ? 0 : -1); + else + return (y1 < y2) ? -1 : ((y1 == y2) ? 0 : 1); } else return (x1 < x2) ? -1 : 1; } -static gboolean -gtk_container_focus_left_right (GtkContainer *container, - GList **children, - GtkDirectionType direction) +static GList * +gtk_container_focus_sort_left_right (GtkContainer *container, + GList *children, + GtkDirectionType direction, + GtkWidget *old_focus) { CompareInfo compare; GList *tmp_list; + GdkRectangle old_allocation; - if (container->focus_child) + compare.container = container; + compare.reverse = (direction == GTK_DIR_LEFT); + + if (!old_focus) + old_focus = find_old_focus (container, children); + + if (old_focus && get_allocation_coords (container, old_focus, &old_allocation)) { gint compare_y1; gint compare_y2; @@ -1921,39 +2145,45 @@ gtk_container_focus_left_right (GtkContainer *container, /* Delete widgets from list that don't match minimum criteria */ - compare_y1 = container->focus_child->allocation.y; - compare_y2 = container->focus_child->allocation.y + container->focus_child->allocation.height; + compare_y1 = old_allocation.y; + compare_y2 = old_allocation.y + old_allocation.height; if (direction == GTK_DIR_LEFT) - compare_x = container->focus_child->allocation.x; + compare_x = old_allocation.x; else - compare_x = container->focus_child->allocation.x + container->focus_child->allocation.width; + compare_x = old_allocation.x + old_allocation.width; - tmp_list = *children; + tmp_list = children; while (tmp_list) { GtkWidget *child = tmp_list->data; GList *next = tmp_list->next; gint child_y1, child_y2; + GdkRectangle child_allocation; - if (child != container->focus_child) + if (child != old_focus) { - child_y1 = child->allocation.y; - child_y2 = child->allocation.y + child->allocation.height; - - if ((child_y2 <= compare_y1 || child_y1 >= compare_y2) /* No vertical overlap */ || - (direction == GTK_DIR_RIGHT && child->allocation.x + child->allocation.width < compare_x) || /* Not to left */ - (direction == GTK_DIR_LEFT && child->allocation.x > compare_x)) /* Not to right */ + if (get_allocation_coords (container, child, &child_allocation)) { - *children = g_list_delete_link (*children, tmp_list); + child_y1 = child_allocation.y; + child_y2 = child_allocation.y + child_allocation.height; + + if ((child_y2 <= compare_y1 || child_y1 >= compare_y2) /* No vertical overlap */ || + (direction == GTK_DIR_RIGHT && child_allocation.x + child_allocation.width < compare_x) || /* Not to left */ + (direction == GTK_DIR_LEFT && child_allocation.x > compare_x)) /* Not to right */ + { + children = g_list_delete_link (children, tmp_list); + } } + else + children = g_list_delete_link (children, tmp_list); } tmp_list = next; } compare.y = (compare_y1 + compare_y2) / 2; - compare.x = container->focus_child->allocation.x + container->focus_child->allocation.width / 2; + compare.x = old_allocation.x + old_allocation.width / 2; } else { @@ -1980,12 +2210,64 @@ gtk_container_focus_left_right (GtkContainer *container, compare.x = (direction == GTK_DIR_RIGHT) ? 0 : widget->allocation.width; } - *children = g_list_sort_with_data (*children, left_right_compare, &compare); + children = g_list_sort_with_data (children, left_right_compare, &compare); - if (direction == GTK_DIR_LEFT) - *children = g_list_reverse (*children); + if (compare.reverse) + children = g_list_reverse (children); - return gtk_container_focus_move (container, *children, direction); + return children; +} + +/** + * gtk_container_focus_sort: + * @container: a #GtkContainer + * @children: a list of descendents of @container (they don't + * have to be direct children) + * @direction: focus direction + * @old_focus: widget to use for the starting position, or %NULL + * to determine this automatically. + * (Note, this argument isn't used for GTK_DIR_TAB_*, + * which is the only @direction we use currently, + * so perhaps this argument should be removed) + * + * Sorts @children in the correct order for focusing with + * direction type @direction. + * + * Return value: a copy of @children, sorted in correct focusing order, + * with children that aren't suitable for focusing in this direction + * removed. + **/ +GList * +_gtk_container_focus_sort (GtkContainer *container, + GList *children, + GtkDirectionType direction, + GtkWidget *old_focus) +{ + GList *visible_children = NULL; + + while (children) + { + if (GTK_WIDGET_REALIZED (children->data)) + visible_children = g_list_prepend (visible_children, children->data); + children = children->next; + } + + switch (direction) + { + case GTK_DIR_TAB_FORWARD: + case GTK_DIR_TAB_BACKWARD: + return gtk_container_focus_sort_tab (container, visible_children, direction, old_focus); + case GTK_DIR_UP: + case GTK_DIR_DOWN: + return gtk_container_focus_sort_up_down (container, visible_children, direction, old_focus); + case GTK_DIR_LEFT: + case GTK_DIR_RIGHT: + return gtk_container_focus_sort_left_right (container, visible_children, direction, old_focus); + } + + g_assert_not_reached (); + + return NULL; } static gboolean @@ -2052,15 +2334,28 @@ chain_widget_destroyed (GtkWidget *widget, chain = g_list_remove (chain, widget); - g_signal_handlers_disconnect_by_func (G_OBJECT (widget), + g_signal_handlers_disconnect_by_func (widget, chain_widget_destroyed, user_data); g_object_set_data (G_OBJECT (container), - "gtk-container-focus-chain", + I_("gtk-container-focus-chain"), chain); } +/** + * gtk_container_set_focus_chain: + * @container: a #GtkContainer + * @focusable_widgets: the new focus chain + * + * Sets a focus chain, overriding the one computed automatically by GTK+. + * + * In principle each widget in the chain should be a descendant of the + * container, but this is not enforced by this method, since it's allowed + * to set the focus chain before you pack the widgets, or have a widget + * in the chain that isn't always packed. The necessary checks are done + * when the focus chain is actually traversed. + **/ void gtk_container_set_focus_chain (GtkContainer *container, GList *focusable_widgets) @@ -2090,10 +2385,10 @@ gtk_container_set_focus_chain (GtkContainer *container, chain = g_list_prepend (chain, tmp_list->data); - gtk_signal_connect (GTK_OBJECT (tmp_list->data), - "destroy", - GTK_SIGNAL_FUNC (chain_widget_destroyed), - container); + g_signal_connect (tmp_list->data, + "destroy", + G_CALLBACK (chain_widget_destroyed), + container); tmp_list = g_list_next (tmp_list); } @@ -2101,7 +2396,7 @@ gtk_container_set_focus_chain (GtkContainer *container, chain = g_list_reverse (chain); g_object_set_data (G_OBJECT (container), - "gtk-container-focus-chain", + I_("gtk-container-focus-chain"), chain); } @@ -2114,14 +2409,14 @@ gtk_container_set_focus_chain (GtkContainer *container, * no additional reference count is added to the * individual widgets in the focus chain. * - * Retrieve the focus chain of the container, if one has been - * set explicitely. If no focus chain has been explicitely + * Retrieves the focus chain of the container, if one has been + * set explicitly. If no focus chain has been explicitly * set, GTK+ computes the focus chain based on the positions * of the children. In that case, GTK+ stores %NULL in * @focusable_widgets and returns %FALSE. * - * Return value: %TRUE if the focus chain of the container, - * has been set explicitely. + * Return value: %TRUE if the focus chain of the container + * has been set explicitly. **/ gboolean gtk_container_get_focus_chain (GtkContainer *container, @@ -2140,6 +2435,12 @@ gtk_container_get_focus_chain (GtkContainer *container, return container->has_focus_chain; } +/** + * gtk_container_unset_focus_chain: + * @container: a #GtkContainer + * + * Removes a focus chain explicitly set with gtk_container_set_focus_chain(). + **/ void gtk_container_unset_focus_chain (GtkContainer *container) { @@ -2154,13 +2455,14 @@ gtk_container_unset_focus_chain (GtkContainer *container) container->has_focus_chain = FALSE; - g_object_set_data (G_OBJECT (container), "gtk-container-focus-chain", + g_object_set_data (G_OBJECT (container), + I_("gtk-container-focus-chain"), NULL); tmp_list = chain; while (tmp_list != NULL) { - g_signal_handlers_disconnect_by_func (G_OBJECT (tmp_list->data), + g_signal_handlers_disconnect_by_func (tmp_list->data, chain_widget_destroyed, container); @@ -2171,22 +2473,37 @@ gtk_container_unset_focus_chain (GtkContainer *container) } } +/** + * gtk_container_set_focus_vadjustment: + * @container: a #GtkContainer + * @adjustment: an adjustment which should be adjusted when the focus + * is moved among the descendents of @container + * + * Hooks up an adjustment to focus handling in a container, so when a + * child of the container is focused, the adjustment is scrolled to + * show that widget. This function sets the vertical alignment. See + * gtk_scrolled_window_get_vadjustment() for a typical way of obtaining + * the adjustment and gtk_container_set_focus_hadjustment() for setting + * the horizontal adjustment. + * + * The adjustments have to be in pixel units and in the same coordinate + * system as the allocation for immediate children of the container. + */ void gtk_container_set_focus_vadjustment (GtkContainer *container, GtkAdjustment *adjustment) { - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); if (adjustment) g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); if (adjustment) - gtk_object_ref (GTK_OBJECT(adjustment)); + g_object_ref (adjustment); - gtk_object_set_data_by_id_full (GTK_OBJECT (container), - vadjustment_key_id, - adjustment, - (GtkDestroyNotify) gtk_object_unref); + g_object_set_qdata_full (G_OBJECT (container), + vadjustment_key_id, + adjustment, + g_object_unref); } /** @@ -2194,7 +2511,7 @@ gtk_container_set_focus_vadjustment (GtkContainer *container, * @container: a #GtkContainer * * Retrieves the vertical focus adjustment for the container. See - * gtk_container_set_focus_vadjustment (). + * gtk_container_set_focus_vadjustment(). * * Return value: the vertical focus adjustment, or %NULL if * none has been set. @@ -2206,28 +2523,42 @@ gtk_container_get_focus_vadjustment (GtkContainer *container) g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL); - vadjustment = gtk_object_get_data_by_id (GTK_OBJECT (container), - vadjustment_key_id); + vadjustment = g_object_get_qdata (G_OBJECT (container), vadjustment_key_id); return vadjustment; } +/** + * gtk_container_set_focus_hadjustment: + * @container: a #GtkContainer + * @adjustment: an adjustment which should be adjusted when the focus is + * moved among the descendents of @container + * + * Hooks up an adjustment to focus handling in a container, so when a child + * of the container is focused, the adjustment is scrolled to show that + * widget. This function sets the horizontal alignment. + * See gtk_scrolled_window_get_hadjustment() for a typical way of obtaining + * the adjustment and gtk_container_set_focus_vadjustment() for setting + * the vertical adjustment. + * + * The adjustments have to be in pixel units and in the same coordinate + * system as the allocation for immediate children of the container. + */ void gtk_container_set_focus_hadjustment (GtkContainer *container, GtkAdjustment *adjustment) { - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_CONTAINER (container)); if (adjustment) g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment)); if (adjustment) - gtk_object_ref (GTK_OBJECT (adjustment)); + g_object_ref (adjustment); - gtk_object_set_data_by_id_full (GTK_OBJECT (container), - hadjustment_key_id, - adjustment, - (GtkDestroyNotify) gtk_object_unref); + g_object_set_qdata_full (G_OBJECT (container), + hadjustment_key_id, + adjustment, + g_object_unref); } /** @@ -2237,7 +2568,7 @@ gtk_container_set_focus_hadjustment (GtkContainer *container, * Retrieves the horizontal focus adjustment for the container. See * gtk_container_set_focus_hadjustment (). * - * Return value: the horizontal focus adjustment, or %NULL if none + * Return value: the horizontal focus adjustment, or %NULL if * none has been set. **/ GtkAdjustment * @@ -2247,8 +2578,7 @@ gtk_container_get_focus_hadjustment (GtkContainer *container) g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL); - hadjustment = gtk_object_get_data_by_id (GTK_OBJECT (container), - hadjustment_key_id); + hadjustment = g_object_get_qdata (G_OBJECT (container), hadjustment_key_id); return hadjustment; } @@ -2257,7 +2587,6 @@ gtk_container_get_focus_hadjustment (GtkContainer *container) static void gtk_container_show_all (GtkWidget *widget) { - g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_CONTAINER (widget)); gtk_container_foreach (GTK_CONTAINER (widget), @@ -2269,7 +2598,6 @@ gtk_container_show_all (GtkWidget *widget) static void gtk_container_hide_all (GtkWidget *widget) { - g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_CONTAINER (widget)); gtk_widget_hide (widget); @@ -2302,7 +2630,6 @@ gtk_container_expose (GtkWidget *widget, GdkEventExpose *event; } data; - g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_CONTAINER (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); @@ -2312,12 +2639,12 @@ gtk_container_expose (GtkWidget *widget, data.container = widget; data.event = event; - gtk_container_foreach (GTK_CONTAINER (widget), - gtk_container_expose_child, - &data); + gtk_container_forall (GTK_CONTAINER (widget), + gtk_container_expose_child, + &data); } - return TRUE; + return FALSE; } static void @@ -2362,26 +2689,26 @@ gtk_container_unmap (GtkWidget *widget) * @child: a child of @container * @event: a expose event sent to container * - * When a container receives an expose event, it must send synthetic - * expose events to all children that don't have their own GdkWindows. + * When a container receives an expose event, it must send synthetic + * expose events to all children that don't have their own #GdkWindows. * This function provides a convenient way of doing this. A container, - * when it receives an expose event, gtk_container_propagate_expose() + * when it receives an expose event, calls gtk_container_propagate_expose() * once for each child, passing in the event the container received. * - * gtk_container_propagate expose() takes care of deciding whether + * gtk_container_propagate_expose() takes care of deciding whether * an expose event needs to be sent to the child, intersecting * the event's area with the child area, and sending the event. * * In most cases, a container can simply either simply inherit the - * ::expose implementation from GtkContainer, or, do some drawing - * and then chain to the ::expose implementation from GtkContainer. + * #GtkWidget::expose implementation from #GtkContainer, or, do some drawing + * and then chain to the ::expose implementation from #GtkContainer. **/ void gtk_container_propagate_expose (GtkContainer *container, GtkWidget *child, GdkEventExpose *event) { - GdkEventExpose child_event; + GdkEvent *child_event; g_return_if_fail (GTK_IS_CONTAINER (container)); g_return_if_fail (GTK_IS_WIDGET (child)); @@ -2393,14 +2720,19 @@ gtk_container_propagate_expose (GtkContainer *container, GTK_WIDGET_NO_WINDOW (child) && (child->window == event->window)) { - child_event = *event; + child_event = gdk_event_new (GDK_EXPOSE); + child_event->expose = *event; + g_object_ref (child_event->expose.window); - child_event.region = gtk_widget_region_intersect (child, event->region); - if (!gdk_region_empty (child_event.region)) + child_event->expose.region = gtk_widget_region_intersect (child, event->region); + if (!gdk_region_empty (child_event->expose.region)) { - gdk_region_get_clipbox (child_event.region, &child_event.area); - gtk_widget_send_expose (child, (GdkEvent *)&child_event); + gdk_region_get_clipbox (child_event->expose.region, &child_event->expose.area); + gtk_widget_send_expose (child, child_event); } - gdk_region_destroy (child_event.region); + gdk_event_free (child_event); } } + +#define __GTK_CONTAINER_C__ +#include "gtkaliasdef.c"