diff --git a/gobject/gobject.c b/gobject/gobject.c index c95311b3e..5f613f230 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -2565,9 +2565,15 @@ g_object_set_property (GObject *object, * @property_name: the name of the property to get * @value: return location for the property value * - * Gets a property of an object. @value must have been initialized to the - * expected type of the property (or a type to which the expected type can be - * transformed) using g_value_init(). + * Gets a property of an object. + * + * The @value can be: + * + * - an empty #GValue initialized by %G_VALUE_INIT, which will be + * automatically initialized with the expected type of the property + * - a #GValue initialized with the expected type of the property + * - a #GValue initialized with a type to which the expected type + * of the property can be transformed * * In general, a copy is made of the property contents and the caller is * responsible for freeing the memory by calling g_value_unset(). @@ -2584,7 +2590,7 @@ g_object_get_property (GObject *object, g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (property_name != NULL); - g_return_if_fail (G_IS_VALUE (value)); + g_return_if_fail (value != NULL); g_object_ref (object); @@ -2597,33 +2603,38 @@ g_object_get_property (GObject *object, { GValue *prop_value, tmp_value = G_VALUE_INIT; - /* auto-conversion of the callers value type - */ - if (G_VALUE_TYPE (value) == pspec->value_type) - { - g_value_reset (value); - prop_value = value; - } + if (G_VALUE_TYPE (value) == G_TYPE_INVALID) + { + /* uninitialized value */ + g_value_init (value, pspec->value_type); + prop_value = value; + } + else if (G_VALUE_TYPE (value) == pspec->value_type) + { + /* auto-conversion of the callers value type */ + g_value_reset (value); + prop_value = value; + } else if (!g_value_type_transformable (pspec->value_type, G_VALUE_TYPE (value))) - { - g_warning ("%s: can't retrieve property '%s' of type '%s' as value of type '%s'", - G_STRFUNC, pspec->name, - g_type_name (pspec->value_type), - G_VALUE_TYPE_NAME (value)); - g_object_unref (object); - return; - } + { + g_warning ("%s: can't retrieve property '%s' of type '%s' as value of type '%s'", + G_STRFUNC, pspec->name, + g_type_name (pspec->value_type), + G_VALUE_TYPE_NAME (value)); + g_object_unref (object); + return; + } else - { - g_value_init (&tmp_value, pspec->value_type); - prop_value = &tmp_value; - } + { + g_value_init (&tmp_value, pspec->value_type); + prop_value = &tmp_value; + } object_get_property (object, pspec, prop_value); if (prop_value != value) - { - g_value_transform (prop_value, value); - g_value_unset (&tmp_value); - } + { + g_value_transform (prop_value, value); + g_value_unset (&tmp_value); + } } g_object_unref (object); diff --git a/gobject/tests/properties.c b/gobject/tests/properties.c index 0aa325a74..1e48e3389 100644 --- a/gobject/tests/properties.c +++ b/gobject/tests/properties.c @@ -541,6 +541,51 @@ properties_testv_getv (void) g_object_unref (test_obj); } +static void +properties_get_property (void) +{ + TestObject *test_obj; + struct { + const char *name; + GType gtype; + GValue value; + } test_props[] = { + { "foo", G_TYPE_INT, G_VALUE_INIT }, + { "bar", G_TYPE_INVALID, G_VALUE_INIT }, + { "bar", G_TYPE_STRING, G_VALUE_INIT }, + }; + int i; + + g_test_summary ("g_object_get_property() accepts uninitialized, " + "initialized, and transformable values"); + + for (i = 0; i < G_N_ELEMENTS (test_props); i++) + { + if (test_props[i].gtype != G_TYPE_INVALID) + g_value_init (&(test_props[i].value), test_props[i].gtype); + } + + test_obj = (TestObject *) g_object_new_with_properties (test_object_get_type (), 0, NULL, NULL); + + g_test_message ("Test g_object_get_property with an initialized value"); + g_object_get_property (G_OBJECT (test_obj), test_props[0].name, &(test_props[0].value)); + g_assert_cmpint (g_value_get_int (&(test_props[0].value)), ==, 42); + + g_test_message ("Test g_object_get_property with an uninitialized value"); + g_object_get_property (G_OBJECT (test_obj), test_props[1].name, &(test_props[1].value)); + g_assert_true (g_value_get_boolean (&(test_props[1].value))); + + g_test_message ("Test g_object_get_property with a transformable value"); + g_object_get_property (G_OBJECT (test_obj), test_props[2].name, &(test_props[2].value)); + g_assert_true (G_VALUE_HOLDS_STRING (&(test_props[2].value))); + g_assert_cmpstr (g_value_get_string (&(test_props[2].value)), ==, "TRUE"); + + for (i = 0; i < G_N_ELEMENTS (test_props); i++) + g_value_unset (&(test_props[i].value)); + + g_object_unref (test_obj); +} + static void properties_testv_notify_queue (void) { @@ -599,6 +644,7 @@ main (int argc, char *argv[]) g_test_add_func ("/properties/notify", properties_notify); g_test_add_func ("/properties/notify-queue", properties_notify_queue); g_test_add_func ("/properties/construct", properties_construct); + g_test_add_func ("/properties/get-property", properties_get_property); g_test_add_func ("/properties/testv_with_no_properties", properties_testv_with_no_properties);