Merge branch 'issue-737' into 'master'

Allow calling get_property() with an uninitialized GValue

Closes #737

See merge request GNOME/glib!892
This commit is contained in:
Philip Withnall 2019-06-04 19:35:53 +00:00
commit 2ac3cf8222
2 changed files with 84 additions and 27 deletions

View File

@ -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);

View File

@ -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);