diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c index c6b6b2577a..695b53e79f 100644 --- a/gtk/gtkbuilder.c +++ b/gtk/gtkbuilder.c @@ -100,17 +100,12 @@ * specifying the id of the #GtkUIManager in the "constructor" attribute and the * name of the object in the "id" attribute. * - * Objects must be given a name with the "id" attribute, which allows the + * Objects may be given a name with the "id" attribute, which allows the * application to retrieve them from the builder with gtk_builder_get_object(). * An id is also necessary to use the object as property value in other parts of - * the UI definition. + * the UI definition. GTK+ reserves ids starting and ending with ___ (3 underscores) + * for its own purposes. * - * - * Prior to 2.20, GtkBuilder was setting the "name" property of constructed widgets to the - * "id" attribute. In GTK+ 2.20 or newer, you have to use gtk_buildable_get_name() instead - * of gtk_widget_get_name() to obtain the "id", or set the "name" property in your UI - * definition. - * * * Setting properties of objects is pretty straightforward with the * <property> element: the "name" attribute specifies the name of the diff --git a/gtk/gtkbuilder.rnc b/gtk/gtkbuilder.rnc index 635fd4f289..6e3aea3469 100644 --- a/gtk/gtkbuilder.rnc +++ b/gtk/gtkbuilder.rnc @@ -9,7 +9,7 @@ requires = element requires { } object = element object { - attribute id { xsd:ID }, + attribute id { xsd:ID } ?, attribute class { text }, attribute type-func { text } ?, attribute constructor { text } ?, diff --git a/gtk/gtkbuilder.rng b/gtk/gtkbuilder.rng index eee698a607..341d19f3ea 100644 --- a/gtk/gtkbuilder.rng +++ b/gtk/gtkbuilder.rng @@ -29,9 +29,11 @@ - - - + + + + + diff --git a/gtk/gtkbuilderparser.c b/gtk/gtkbuilderparser.c index 11e04cb506..e2111d65c9 100644 --- a/gtk/gtkbuilderparser.c +++ b/gtk/gtkbuilderparser.c @@ -301,7 +301,7 @@ is_requested_object (const gchar *object, for (l = data->requested_objects; l; l = l->next) { - if (strcmp (l->data, object) == 0) + if (g_strcmp0 (l->data, object) == 0) return TRUE; } @@ -369,10 +369,11 @@ parse_object (GMarkupParseContext *context, return; } + data->object_counter++; + if (!object_id) { - error_missing_attribute (data, element_name, "id", error); - return; + object_id = g_strdup_printf ("___object_%d___", data->object_counter++); } ++data->cur_object_level; @@ -420,7 +421,6 @@ parse_object (GMarkupParseContext *context, return; } - g_hash_table_insert (data->object_ids, g_strdup (object_id), GINT_TO_POINTER (line)); } diff --git a/gtk/gtkbuilderprivate.h b/gtk/gtkbuilderprivate.h index 346459c678..b653373be7 100644 --- a/gtk/gtkbuilderprivate.h +++ b/gtk/gtkbuilderprivate.h @@ -107,6 +107,8 @@ typedef struct { gint requested_object_level; gint cur_object_level; + gint object_counter; + GHashTable *object_ids; } ParserData; diff --git a/testsuite/gtk/builder.c b/testsuite/gtk/builder.c index 08582623c5..d20fba6a61 100644 --- a/testsuite/gtk/builder.c +++ b/testsuite/gtk/builder.c @@ -2728,6 +2728,53 @@ test_expose_object (void) g_object_unref (image); } +static void +test_no_ids (void) +{ + GtkBuilder *builder; + GError *error = NULL; + GObject *obj; + const gchar buffer[] = + "" + " " + " " + " " + " " + " " + " Message" + " " + " " + " False" + " " + " " + " " + " " + " " + " " + " " + " " + " gtk-ok" + " yes" + " " + " " + " " + " " + " " + " button_ok" + " " + " " + ""; + + builder = gtk_builder_new (); + gtk_builder_add_from_string (builder, buffer, -1, &error); + g_assert (error == NULL); + + obj = gtk_builder_get_object (builder, "button_ok"); + g_assert (GTK_IS_BUTTON (obj)); + + g_object_unref (builder); +} + int main (int argc, char **argv) { @@ -2777,6 +2824,7 @@ main (int argc, char **argv) g_test_add_func ("/Builder/GMenu", test_gmenu); g_test_add_func ("/Builder/LevelBar", test_level_bar); g_test_add_func ("/Builder/Expose Object", test_expose_object); + g_test_add_func ("/Builder/No IDs", test_no_ids); return g_test_run(); }