From ce0a84003cfc2aed95b68d4e20ab06d6ffd701e6 Mon Sep 17 00:00:00 2001 From: Jehan Date: Thu, 20 Jul 2023 01:48:59 +0200 Subject: [PATCH] libgimp, libgimpconfig: GimpResource can now be (de)serialized. I add a new class method deserialize_create() to GimpConfigInterface which returns the GimpConfig object per deserialization, instead of modifying an existing bare object. This matters for cases like our GimpResource (and later our GimpItem) classes which are fully managed by libgimp and should be unique objects per actual resource. It should even be possible to compare the pointer itself for identity. That's why we need to let GimpResource create the object (in reality request it to the infra and only ref it) through this new class method. With this commit and the previous ones, all GimpResource are now properly stored as plug-in settings (e.g. the "film" plug-in has a font setting which is now properly remembered). These identifiers are not portable (across various installations and therefore not for XCF either), but at least they are reasonably identifying data on a same installation (unlike GimpResource's int ID which is only valid within a single session) which makes them very fine for plug-in settings storage. When a data file disappears, we fallback to the context default data instead. --- libgimp/gimpresource.c | 81 +++++++++++++++++++++++++- libgimpconfig/gimpconfig-deserialize.c | 24 +++++++- libgimpconfig/gimpconfig-iface.c | 2 +- libgimpconfig/gimpconfig-iface.h | 4 ++ 4 files changed, 107 insertions(+), 4 deletions(-) diff --git a/libgimp/gimpresource.c b/libgimp/gimpresource.c index 202bed4f91..ff3b4ec7d9 100644 --- a/libgimp/gimpresource.c +++ b/libgimp/gimpresource.c @@ -112,6 +112,8 @@ typedef struct _GimpResourcePrivate } GimpResourcePrivate; +static void gimp_resource_config_iface_init (GimpConfigInterface *iface); + static void gimp_resource_set_property (GObject *object, guint property_id, const GValue *value, @@ -121,8 +123,21 @@ static void gimp_resource_get_property (GObject *object, GValue *value, GParamSpec *pspec); +static gboolean gimp_resource_serialize (GimpConfig *config, + GimpConfigWriter *writer, + gpointer data); +static GimpConfig * + gimp_resource_deserialize_create (GType type, + GScanner *scanner, + gint nest_level, + gpointer data); -G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GimpResource, gimp_resource, G_TYPE_OBJECT) + +G_DEFINE_TYPE_EXTENDED (GimpResource, gimp_resource, G_TYPE_OBJECT, + G_TYPE_FLAG_ABSTRACT, + G_ADD_PRIVATE (GimpResource) + G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, + gimp_resource_config_iface_init)) #define parent_class gimp_resource_parent_class @@ -148,6 +163,13 @@ gimp_resource_class_init (GimpResourceClass *klass) g_object_class_install_properties (object_class, N_PROPS, props); } +static void +gimp_resource_config_iface_init (GimpConfigInterface *iface) +{ + iface->serialize = gimp_resource_serialize; + iface->deserialize_create = gimp_resource_deserialize_create; +} + static void gimp_resource_init (GimpResource *resource) { @@ -195,6 +217,63 @@ gimp_resource_get_property (GObject *object, } } +static gboolean +gimp_resource_serialize (GimpConfig *config, + GimpConfigWriter *writer, + gpointer data) +{ + GimpResource *resource; + gchar *name; + gchar *collection; + gboolean is_internal; + + g_return_val_if_fail (GIMP_IS_RESOURCE (config), FALSE); + + resource = GIMP_RESOURCE (config); + is_internal = _gimp_resource_get_identifiers (resource, &name, &collection); + + if (is_internal) + gimp_config_writer_identifier (writer, "internal"); + gimp_config_writer_string (writer, name); + gimp_config_writer_string (writer, collection); + + g_free (name); + g_free (collection); + + return TRUE; +} + +static GimpConfig * +gimp_resource_deserialize_create (GType type, + GScanner *scanner, + gint nest_level, + gpointer data) +{ + GimpResource *resource = NULL; + gchar *name = NULL; + gchar *collection = NULL; + gboolean is_internal = FALSE; + + if (gimp_scanner_parse_identifier (scanner, "internal")) + is_internal = TRUE; + + if (gimp_scanner_parse_string (scanner, &name) && + gimp_scanner_parse_string (scanner, &collection)) + resource = _gimp_resource_get_by_identifiers (g_type_name (type), name, collection, is_internal); + + if (resource == NULL) + /* Default to context resource. */ + resource = _gimp_context_get_resource (g_type_name (type)); + + if (resource) + g_object_ref (resource); + + g_free (collection); + g_free (name);; + + return GIMP_CONFIG (resource);; +} + /** * gimp_resource_get_id: * @resource: The resource. diff --git a/libgimpconfig/gimpconfig-deserialize.c b/libgimpconfig/gimpconfig-deserialize.c index 8f90b58351..3dd99298dd 100644 --- a/libgimpconfig/gimpconfig-deserialize.c +++ b/libgimpconfig/gimpconfig-deserialize.c @@ -781,8 +781,28 @@ gimp_config_deserialize_object (GValue *value, if (! config_iface) return gimp_config_deserialize_any (value, prop_spec, scanner); - if (! config_iface->deserialize (prop_object, scanner, nest_level + 1, NULL)) - return G_TOKEN_NONE; + if (config_iface->deserialize_create != NULL) + { + /* Some class may prefer to create themselves their objects, for instance + * to maintain unicity of objects (in libgimp in particular, the various + * GimpItem or GimpResource are managed by the lib. A single item or + * resource must be represented for a single object across the whole + * processus. + */ + GimpConfig *created_object; + + created_object = config_iface->deserialize_create (G_TYPE_FROM_INSTANCE (prop_object), + scanner, nest_level + 1, NULL); + + if (created_object == NULL) + return G_TOKEN_NONE; + else + g_value_take_object (value, created_object); + } + else if (! config_iface->deserialize (prop_object, scanner, nest_level + 1, NULL)) + { + return G_TOKEN_NONE; + } return G_TOKEN_RIGHT_PAREN; } diff --git a/libgimpconfig/gimpconfig-iface.c b/libgimpconfig/gimpconfig-iface.c index a537220d94..131693e487 100644 --- a/libgimpconfig/gimpconfig-iface.c +++ b/libgimpconfig/gimpconfig-iface.c @@ -454,7 +454,7 @@ gimp_config_serialize_to_parasite (GimpConfig *config, /** * gimp_config_deserialize_file: - * @config: an oObject that implements the #GimpConfigInterface. + * @config: an object that implements the #GimpConfigInterface. * @file: the file to read configuration from. * @data: user data passed to the deserialize implementation. * @error: return location for a possible error diff --git a/libgimpconfig/gimpconfig-iface.h b/libgimpconfig/gimpconfig-iface.h index 605e999a1a..c142ee6c52 100644 --- a/libgimpconfig/gimpconfig-iface.h +++ b/libgimpconfig/gimpconfig-iface.h @@ -44,6 +44,10 @@ struct _GimpConfigInterface GScanner *scanner, gint nest_level, gpointer data); + GimpConfig * (* deserialize_create) (GType type, + GScanner *scanner, + gint nest_level, + gpointer data); gboolean (* serialize_property) (GimpConfig *config, guint property_id, const GValue *value,