gsettings: Add g_settings_bind_with_mapping_closures()

This is an introspection-friendly version of g_settings_bind_with_mapping.
Having two callbacks that share the same user data is not supported by
girepository, so the existing function is not introspectable.

Closes: #564
This commit is contained in:
Philip Chimento
2024-03-17 21:15:46 -07:00
committed by Philip Withnall
parent afcb839121
commit 685d3dfbdc
3 changed files with 292 additions and 0 deletions

View File

@@ -1714,6 +1714,146 @@ test_custom_binding (void)
g_object_unref (settings);
}
/* Same test as above, but with closures
*/
static void
test_bind_with_mapping_closures (void)
{
TestObject *obj;
GSettings *settings;
char *s;
gboolean b;
GClosure *get;
GClosure *set;
settings = g_settings_new ("org.gtk.test.binding");
obj = test_object_new ();
g_settings_set_string (settings, "string", "true");
get = g_cclosure_new (G_CALLBACK (string_to_bool), NULL, NULL);
set = g_cclosure_new (G_CALLBACK (bool_to_string), NULL, NULL);
g_settings_bind_with_mapping_closures (settings, "string",
G_OBJECT (obj), "bool",
G_SETTINGS_BIND_DEFAULT, get, set);
g_settings_set_string (settings, "string", "false");
g_object_get (obj, "bool", &b, NULL);
g_assert_cmpint (b, ==, FALSE);
g_settings_set_string (settings, "string", "not true");
g_object_get (obj, "bool", &b, NULL);
g_assert_cmpint (b, ==, FALSE);
g_object_set (obj, "bool", TRUE, NULL);
s = g_settings_get_string (settings, "string");
g_assert_cmpstr (s, ==, "true");
g_free (s);
set = g_cclosure_new (G_CALLBACK (bool_to_bool), NULL, NULL);
g_settings_bind_with_mapping_closures (settings, "string",
G_OBJECT (obj), "bool",
G_SETTINGS_BIND_DEFAULT, get, set);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
"*binding mapping function for key 'string' returned"
" GVariant of type 'b' when type 's' was requested*");
g_object_set (obj, "bool", FALSE, NULL);
g_test_assert_expected_messages ();
g_object_unref (obj);
g_object_unref (settings);
}
typedef struct
{
gboolean get_called;
gboolean set_called;
gboolean get_freed;
gboolean set_freed;
} BindWithMappingData;
static gboolean
get_callback (GValue *value,
GVariant *variant,
void *user_data)
{
BindWithMappingData *data = (BindWithMappingData *) user_data;
data->get_called = TRUE;
g_assert_true (G_VALUE_HOLDS_BOOLEAN (value));
g_assert_true (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING));
return string_to_bool (value, variant, NULL);
}
static GVariant *
set_callback (const GValue *value,
const GVariantType *expected_type,
void *user_data)
{
BindWithMappingData *data = (BindWithMappingData *) user_data;
data->set_called = TRUE;
g_assert_true (G_VALUE_HOLDS_BOOLEAN (value));
g_assert_true (g_variant_type_equal (expected_type, G_VARIANT_TYPE_STRING));
return bool_to_string (value, expected_type, NULL);
}
static void
teardown_get (void *user_data, GClosure *closure)
{
BindWithMappingData *data = (BindWithMappingData *) user_data;
data->get_freed = TRUE;
}
static void
teardown_set (void *user_data, GClosure *closure)
{
BindWithMappingData *data = (BindWithMappingData *) user_data;
data->set_freed = TRUE;
}
/* Tests the types of GValue and GVariant passed to the closures */
static void
test_bind_with_mapping_closures_parameters (void)
{
TestObject *obj;
GSettings *settings;
GClosure *get;
GClosure *set;
BindWithMappingData data = { FALSE, FALSE, FALSE, FALSE };
settings = g_settings_new ("org.gtk.test.binding");
obj = test_object_new ();
g_settings_set_string (settings, "string", "true");
get = g_cclosure_new (G_CALLBACK (get_callback), &data, teardown_get);
set = g_cclosure_new (G_CALLBACK (set_callback), &data, teardown_set);
g_settings_bind_with_mapping_closures (settings, "string",
G_OBJECT (obj), "bool",
G_SETTINGS_BIND_DEFAULT, get, set);
g_assert_true (data.get_called);
g_assert_false (data.set_called);
data.get_called = FALSE;
g_object_set (obj, "bool", FALSE, NULL);
g_assert_true (data.set_called);
g_assert_false (data.get_called);
g_object_unref (obj);
g_assert_true (data.get_freed);
g_assert_true (data.set_freed);
g_object_unref (settings);
}
/* Test that with G_SETTINGS_BIND_NO_CHANGES, the
* initial settings value is transported to the object
* side, but later settings changes do not affect the
@@ -3237,6 +3377,8 @@ main (int argc, char *argv[])
g_test_add_func ("/gsettings/simple-binding", test_simple_binding);
g_test_add_func ("/gsettings/directional-binding", test_directional_binding);
g_test_add_func ("/gsettings/custom-binding", test_custom_binding);
g_test_add_func ("/gsettings/bind-with-mapping-closures", test_bind_with_mapping_closures);
g_test_add_func ("/gsettings/bind-with-mapping-closures-parameters", test_bind_with_mapping_closures_parameters);
g_test_add_func ("/gsettings/no-change-binding", test_no_change_binding);
g_test_add_func ("/gsettings/unbinding", test_unbind);
g_test_add_func ("/gsettings/writable-binding", test_bind_writable);