diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c index 0394a998d3..11fbdc29ad 100644 --- a/gtk/gtkcontainer.c +++ b/gtk/gtkcontainer.c @@ -221,21 +221,33 @@ * a element for children, which can contain multiple * elements that specify child properties for the child. * - * An example of child properties in UI definitions: + * Since 2.16, child properties can also be marked as translatable using + * the same “translatable”, “comments” and “context” attributes that are used + * for regular properties. + * + * Since 3.16, containers can have a element containing multiple + * elements, one for each child that should be added to the focus + * chain. The ”name” attribute gives the id of the widget. + * + * An example of these properties in UI definitions: * |[ - * + * * - * + * * * start * * + * + * + * + * + * + * + * * * ]| * - * Since 2.16, child properties can also be marked as translatable using - * the same “translatable”, “comments” and “context” attributes that are used - * for regular properties. */ @@ -353,6 +365,11 @@ static void gtk_container_buildable_custom_tag_end (GtkBuildable *buildable, GObject *child, const gchar *tagname, gpointer *data); +static void gtk_container_buildable_custom_finished (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *tagname, + gpointer data); static gboolean gtk_container_should_propagate_draw (GtkContainer *container, GtkWidget *child, @@ -557,6 +574,7 @@ gtk_container_buildable_init (GtkBuildableIface *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; + iface->custom_finished = gtk_container_buildable_custom_finished; } static void @@ -727,6 +745,46 @@ static const GMarkupParser attributes_parser = attributes_text_element, }; +typedef struct + { + GSList *items; + GObject *object; + } FocusChainData; + +static void +focus_chain_start_element (GMarkupParseContext *context, + const gchar *element_name, + const gchar **names, + const gchar **values, + gpointer user_data, + GError **error) +{ + guint i; + FocusChainData *data = (FocusChainData*)user_data; + + if (strcmp (element_name, "widget") == 0) + { + for (i = 0; names[i]; i++) + { + if (strcmp (names[i], "name") == 0) + data->items = g_slist_prepend (data->items, g_strdup (values[i])); + } + } + else if (strcmp (element_name, "focus-chain") == 0) + { + return; + } + else + { + g_warning ("Unsupported type tag for GtkContainer %s\n", element_name); + } +} + +static const GMarkupParser focus_chain_parser = + { + focus_chain_start_element + }; + static gboolean gtk_container_buildable_custom_tag_start (GtkBuildable *buildable, GtkBuilder *builder, @@ -735,14 +793,14 @@ gtk_container_buildable_custom_tag_start (GtkBuildable *buildable, 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) { + PackingPropertiesData *parser_data; + parser_data = g_slice_new0 (PackingPropertiesData); parser_data->string = g_string_new (""); parser_data->builder = builder; @@ -754,6 +812,17 @@ gtk_container_buildable_custom_tag_start (GtkBuildable *buildable, *data = parser_data; return TRUE; } + else if (!child && strcmp (tagname, "focus-chain") == 0) + { + FocusChainData *parser_data; + parser_data = g_slice_new0 (FocusChainData); + parser_data->items = NULL; + parser_data->object = G_OBJECT (buildable); + + *parser = focus_chain_parser; + *data = parser_data; + return TRUE; + } return FALSE; } @@ -778,6 +847,48 @@ gtk_container_buildable_custom_tag_end (GtkBuildable *buildable, child, tagname, data); } +static void +gtk_container_buildable_custom_finished (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *tagname, + gpointer data) +{ + if (strcmp (tagname, "focus-chain") == 0) + { + FocusChainData *parser_data = (FocusChainData*)data; + GSList *l; + GList *chain; + GObject *object; + + chain = NULL; + for (l = parser_data->items; l; l = l->next) + { + object = gtk_builder_get_object (builder, l->data); + if (!object) + { + g_warning ("Unknown object %s specified in focus-chain for %s", + (const gchar*)l->data, + gtk_buildable_get_name (GTK_BUILDABLE (parser_data->object))); + continue; + } + chain = g_list_prepend (chain, object); + } + + gtk_container_set_focus_chain (GTK_CONTAINER (parser_data->object), chain); + g_list_free (chain); + + g_slist_free_full (parser_data->items, g_free); + g_slice_free (FocusChainData, parser_data); + + return; + } + + if (parent_buildable_iface->custom_finished) + parent_buildable_iface->custom_finished (buildable, builder, + child, tagname, data); +} + /** * gtk_container_child_type: * @container: a #GtkContainer