From 5f4dba9cb7461e9fee3f83d72e4680cf8e60767a Mon Sep 17 00:00:00 2001 From: Tristan Van Berkom Date: Sat, 8 Jun 2013 10:12:14 -0400 Subject: [PATCH] Bug 701838 - Work around a semantic API break in GObject Recent versions of GObject fire critical messages if properties are installed outside of class initializers (causing all of EDS tests to fail). This patch adds some class data and initializes the class in the dynamic subclass initializer. Note that the class data which should normally be freed in the class finalizer is not freed, since it is a static type the finalizer will never run (and GLib also takes the liberty of firing critical messages for specifying a class finalizer). --- libedataserver/e-source-camel.c | 112 ++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/libedataserver/e-source-camel.c b/libedataserver/e-source-camel.c index 2672636..8f7b96d 100644 --- a/libedataserver/e-source-camel.c +++ b/libedataserver/e-source-camel.c @@ -70,6 +70,11 @@ typedef struct { GBindingTransformFunc settings_to_extension; } BindingData; +typedef struct { + GType settings_type; + const gchar *extension_name; +} SubclassData; + static gboolean transform_none_to_null (GBinding *binding, const GValue *source_value, @@ -244,15 +249,55 @@ static void subclass_class_init (gpointer g_class, gpointer class_data) { + ESourceCamelClass *class; + GObjectClass *settings_class; GObjectClass *object_class; + SubclassData *data = class_data; + GParamSpec **properties; + guint ii, n_properties; + guint prop_id = 1; - /* e_source_camel_generate_subtype() does all the - * dynamic class initialization. We just do what static - * initialization we can here. */ + class = E_SOURCE_CAMEL_CLASS (g_class); + settings_class = g_type_class_ref (data->settings_type); object_class = G_OBJECT_CLASS (g_class); object_class->set_property = subclass_set_property; object_class->get_property = subclass_get_property; + + /* For each property in the CamelSettings class, register + * an equivalent GObject property in this class and add an + * E_SOURCE_PARAM_SETTING flag so the value gets written to + * the ESource's key file. */ + properties = g_object_class_list_properties ( + settings_class, &n_properties); + + for (ii = 0; ii < n_properties; ii++) { + GParamSpec *pspec; + + /* Some properties in CamelSettings may be covered + * by other ESourceExtensions. Skip them here. */ + if (subclass_get_binding_index (properties[ii]) >= 0) + continue; + + pspec = param_spec_clone (properties[ii]); + pspec->flags |= E_SOURCE_PARAM_SETTING; + + /* Clear the G_PARAM_CONSTRUCT flag. We apply default + * property values to our GValue array during instance + * initialization. */ + pspec->flags &= ~G_PARAM_CONSTRUCT; + + g_object_class_install_property ( + G_OBJECT_CLASS (class), prop_id++, pspec); + } + + g_free (properties); + + /* Initialize more class members. */ + class->settings_type = G_OBJECT_CLASS_TYPE (settings_class); + class->parent_class.name = data->extension_name; + + g_type_class_unref (settings_class); } static void @@ -543,14 +588,9 @@ GType e_source_camel_generate_subtype (const gchar *protocol, GType settings_type) { - ESourceCamelClass *class; - GObjectClass *settings_class; - GParamSpec **properties; - guint ii, n_properties; - guint prop_id = 1; GTypeInfo type_info; - GType parent_type; GType type; + SubclassData *subclass_data; const gchar *type_name; const gchar *extension_name; @@ -572,59 +612,19 @@ e_source_camel_generate_subtype (const gchar *protocol, return G_TYPE_INVALID; } + subclass_data = g_slice_new0 (SubclassData); + subclass_data->settings_type = settings_type; + subclass_data->extension_name = g_intern_string (extension_name); + memset (&type_info, 0, sizeof (GTypeInfo)); type_info.class_size = sizeof (ESourceCamelClass); type_info.class_init = subclass_class_init; + type_info.class_data = subclass_data; type_info.instance_size = sizeof (ESourceCamel); type_info.instance_init = subclass_instance_init; - parent_type = E_TYPE_SOURCE_CAMEL; - type = g_type_register_static (parent_type, type_name, &type_info, 0); - - /* Since we have first access to the newly registered GType, and - * because initializing its class structure requires some of the - * arguments we were passed, we'll complete class initialization - * here rather than trying to do it all in subclass_init(). */ - - class = g_type_class_ref (type); - settings_class = g_type_class_ref (settings_type); - - /* Initialize more class members. */ - class->settings_type = G_OBJECT_CLASS_TYPE (settings_class); - class->parent_class.name = g_intern_string (extension_name); - - /* For each property in the CamelSettings class, register - * an equivalent GObject property in this class and add an - * E_SOURCE_PARAM_SETTING flag so the value gets written to - * the ESource's key file. */ - - properties = g_object_class_list_properties ( - settings_class, &n_properties); - - for (ii = 0; ii < n_properties; ii++) { - GParamSpec *pspec; - - /* Some properties in CamelSettings may be covered - * by other ESourceExtensions. Skip them here. */ - if (subclass_get_binding_index (properties[ii]) >= 0) - continue; - - pspec = param_spec_clone (properties[ii]); - pspec->flags |= E_SOURCE_PARAM_SETTING; - - /* Clear the G_PARAM_CONSTRUCT flag. We apply default - * property values to our GValue array during instance - * initialization. */ - pspec->flags &= ~G_PARAM_CONSTRUCT; - - g_object_class_install_property ( - G_OBJECT_CLASS (class), prop_id++, pspec); - } - - g_free (properties); - - g_type_class_unref (class); - g_type_class_unref (settings_class); + type = g_type_register_static ( + E_TYPE_SOURCE_CAMEL, type_name, &type_info, 0); return type; } -- 2.7.4