diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 03:13:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 03:13:10 +0000 |
commit | 3c57dd931145d43f2b0aef96c4d178135956bf91 (patch) | |
tree | 3de698981e9f0cc2c4f9569b19a5f3595e741f6b /libgimpconfig/gimpconfig-serialize.c | |
parent | Initial commit. (diff) | |
download | gimp-3c57dd931145d43f2b0aef96c4d178135956bf91.tar.xz gimp-3c57dd931145d43f2b0aef96c4d178135956bf91.zip |
Adding upstream version 2.10.36.upstream/2.10.36
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libgimpconfig/gimpconfig-serialize.c')
-rw-r--r-- | libgimpconfig/gimpconfig-serialize.c | 576 |
1 files changed, 576 insertions, 0 deletions
diff --git a/libgimpconfig/gimpconfig-serialize.c b/libgimpconfig/gimpconfig-serialize.c new file mode 100644 index 0000000..0df5bbc --- /dev/null +++ b/libgimpconfig/gimpconfig-serialize.c @@ -0,0 +1,576 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis + * + * Object properties serialization routines + * Copyright (C) 2001-2002 Sven Neumann <sven@gimp.org> + * + * This library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpmath/gimpmath.h" +#include "libgimpcolor/gimpcolor.h" + +#include "gimpconfigtypes.h" + +#include "gimpconfigwriter.h" +#include "gimpconfig-iface.h" +#include "gimpconfig-params.h" +#include "gimpconfig-path.h" +#include "gimpconfig-serialize.h" +#include "gimpconfig-utils.h" + + +/** + * SECTION: gimpconfig-serialize + * @title: GimpConfig-serialize + * @short_description: Serializing for libgimpconfig. + * + * Serializing interface for libgimpconfig. + **/ + + +static gboolean gimp_config_serialize_rgb (const GValue *value, + GString *str, + gboolean has_alpha); + + +/** + * gimp_config_serialize_properties: + * @config: a #GimpConfig. + * @writer: a #GimpConfigWriter. + * + * This function writes all object properties to the @writer. + * + * Returns: %TRUE if serialization succeeded, %FALSE otherwise + * + * Since: 2.4 + **/ +gboolean +gimp_config_serialize_properties (GimpConfig *config, + GimpConfigWriter *writer) +{ + GObjectClass *klass; + GParamSpec **property_specs; + guint n_property_specs; + guint i; + + g_return_val_if_fail (G_IS_OBJECT (config), FALSE); + + klass = G_OBJECT_GET_CLASS (config); + + property_specs = g_object_class_list_properties (klass, &n_property_specs); + + if (! property_specs) + return TRUE; + + for (i = 0; i < n_property_specs; i++) + { + GParamSpec *prop_spec = property_specs[i]; + + if (! (prop_spec->flags & GIMP_CONFIG_PARAM_SERIALIZE)) + continue; + + if (! gimp_config_serialize_property (config, prop_spec, writer)) + return FALSE; + } + + g_free (property_specs); + + return TRUE; +} + +/** + * gimp_config_serialize_changed_properties: + * @config: a #GimpConfig. + * @writer: a #GimpConfigWriter. + * + * This function writes all object properties that have been changed from + * their default values to the @writer. + * + * Returns: %TRUE if serialization succeeded, %FALSE otherwise + * + * Since: 2.4 + **/ +gboolean +gimp_config_serialize_changed_properties (GimpConfig *config, + GimpConfigWriter *writer) +{ + GObjectClass *klass; + GParamSpec **property_specs; + guint n_property_specs; + guint i; + GValue value = G_VALUE_INIT; + + g_return_val_if_fail (G_IS_OBJECT (config), FALSE); + + klass = G_OBJECT_GET_CLASS (config); + + property_specs = g_object_class_list_properties (klass, &n_property_specs); + + if (! property_specs) + return TRUE; + + for (i = 0; i < n_property_specs; i++) + { + GParamSpec *prop_spec = property_specs[i]; + + if (! (prop_spec->flags & GIMP_CONFIG_PARAM_SERIALIZE)) + continue; + + g_value_init (&value, prop_spec->value_type); + g_object_get_property (G_OBJECT (config), prop_spec->name, &value); + + if (! g_param_value_defaults (prop_spec, &value)) + { + if (! gimp_config_serialize_property (config, prop_spec, writer)) + return FALSE; + } + + g_value_unset (&value); + } + + g_free (property_specs); + + return TRUE; +} + +/** + * gimp_config_serialize_property: + * @config: a #GimpConfig. + * @param_spec: a #GParamSpec. + * @writer: a #GimpConfigWriter. + * + * This function serializes a single object property to the @writer. + * + * Returns: %TRUE if serialization succeeded, %FALSE otherwise + * + * Since: 2.4 + **/ +gboolean +gimp_config_serialize_property (GimpConfig *config, + GParamSpec *param_spec, + GimpConfigWriter *writer) +{ + GimpConfigInterface *config_iface = NULL; + GimpConfigInterface *parent_iface = NULL; + GValue value = G_VALUE_INIT; + gboolean success = FALSE; + + if (! (param_spec->flags & GIMP_CONFIG_PARAM_SERIALIZE)) + return FALSE; + + if (param_spec->flags & GIMP_CONFIG_PARAM_IGNORE) + return TRUE; + + g_value_init (&value, param_spec->value_type); + g_object_get_property (G_OBJECT (config), param_spec->name, &value); + + if (param_spec->flags & GIMP_CONFIG_PARAM_DEFAULTS && + g_param_value_defaults (param_spec, &value)) + { + g_value_unset (&value); + return TRUE; + } + + if (G_TYPE_IS_OBJECT (param_spec->owner_type)) + { + GTypeClass *owner_class = g_type_class_peek (param_spec->owner_type); + + config_iface = g_type_interface_peek (owner_class, GIMP_TYPE_CONFIG); + + /* We must call serialize_property() *only* if the *exact* class + * which implements it is param_spec->owner_type's class. + * + * Therefore, we ask param_spec->owner_type's immediate parent class + * for it's GimpConfigInterface and check if we get a different + * pointer. + * + * (if the pointers are the same, param_spec->owner_type's + * GimpConfigInterface is inherited from one of it's parent classes + * and thus not able to handle param_spec->owner_type's properties). + */ + if (config_iface) + { + GTypeClass *owner_parent_class; + + owner_parent_class = g_type_class_peek_parent (owner_class); + + parent_iface = g_type_interface_peek (owner_parent_class, + GIMP_TYPE_CONFIG); + } + } + + if (config_iface && + config_iface != parent_iface && /* see comment above */ + config_iface->serialize_property && + config_iface->serialize_property (config, + param_spec->param_id, + (const GValue *) &value, + param_spec, + writer)) + { + success = TRUE; + } + + /* If there is no serialize_property() method *or* if it returned + * FALSE, continue with the default implementation + */ + + if (! success) + { + if (G_VALUE_HOLDS_OBJECT (&value) && + G_VALUE_TYPE (&value) != G_TYPE_FILE) + { + GimpConfigInterface *config_iface = NULL; + GimpConfig *prop_object; + + prop_object = g_value_get_object (&value); + + if (prop_object) + config_iface = GIMP_CONFIG_GET_INTERFACE (prop_object); + else + success = TRUE; + + if (config_iface) + { + gimp_config_writer_open (writer, param_spec->name); + + /* if the object property is not GIMP_CONFIG_PARAM_AGGREGATE, + * deserializing will need to know the exact type + * in order to create the object + */ + if (! (param_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE)) + { + GType object_type = G_TYPE_FROM_INSTANCE (prop_object); + + gimp_config_writer_string (writer, g_type_name (object_type)); + } + + success = config_iface->serialize (prop_object, writer, NULL); + + if (success) + gimp_config_writer_close (writer); + else + gimp_config_writer_revert (writer); + } + } + else + { + GString *str = g_string_new (NULL); + + if (GIMP_VALUE_HOLDS_RGB (&value)) + { + gboolean has_alpha = gimp_param_spec_rgb_has_alpha (param_spec); + + success = gimp_config_serialize_rgb (&value, str, has_alpha); + } + else + { + success = gimp_config_serialize_value (&value, str, TRUE); + } + + if (success) + { + gimp_config_writer_open (writer, param_spec->name); + gimp_config_writer_print (writer, str->str, str->len); + gimp_config_writer_close (writer); + } + + g_string_free (str, TRUE); + } + + if (! success) + { + /* don't warn for empty string properties */ + if (G_VALUE_HOLDS_STRING (&value)) + { + success = TRUE; + } + else + { + g_warning ("couldn't serialize property %s::%s of type %s", + g_type_name (G_TYPE_FROM_INSTANCE (config)), + param_spec->name, + g_type_name (param_spec->value_type)); + } + } + } + + g_value_unset (&value); + + return success; +} + +/** + * gimp_config_serialize_property_by_name: + * @config: a #GimpConfig. + * @prop_name: the property's name. + * @writer: a #GimpConfigWriter. + * + * This function serializes a single object property to the @writer. + * + * Returns: %TRUE if serialization succeeded, %FALSE otherwise + * + * Since: 2.6 + **/ +gboolean +gimp_config_serialize_property_by_name (GimpConfig *config, + const gchar *prop_name, + GimpConfigWriter *writer) +{ + GParamSpec *pspec; + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), + prop_name); + + if (! pspec) + return FALSE; + + return gimp_config_serialize_property (config, pspec, writer); +} + +/** + * gimp_config_serialize_value: + * @value: a #GValue. + * @str: a #GString. + * @escaped: whether to escape string values. + * + * This utility function appends a string representation of #GValue to @str. + * + * Return value: %TRUE if serialization succeeded, %FALSE otherwise. + * + * Since: 2.4 + **/ +gboolean +gimp_config_serialize_value (const GValue *value, + GString *str, + gboolean escaped) +{ + if (G_VALUE_HOLDS_BOOLEAN (value)) + { + gboolean bool; + + bool = g_value_get_boolean (value); + g_string_append (str, bool ? "yes" : "no"); + return TRUE; + } + + if (G_VALUE_HOLDS_ENUM (value)) + { + GEnumClass *enum_class = g_type_class_peek (G_VALUE_TYPE (value)); + GEnumValue *enum_value = g_enum_get_value (enum_class, + g_value_get_enum (value)); + + if (enum_value && enum_value->value_nick) + { + g_string_append (str, enum_value->value_nick); + return TRUE; + } + else + { + g_warning ("Couldn't get nick for enum_value of %s", + G_ENUM_CLASS_TYPE_NAME (enum_class)); + return FALSE; + } + } + + if (G_VALUE_HOLDS_STRING (value)) + { + const gchar *cstr = g_value_get_string (value); + + if (!cstr) + return FALSE; + + if (escaped) + gimp_config_string_append_escaped (str, cstr); + else + g_string_append (str, cstr); + + return TRUE; + } + + if (G_VALUE_HOLDS_DOUBLE (value) || G_VALUE_HOLDS_FLOAT (value)) + { + gdouble v_double; + gchar buf[G_ASCII_DTOSTR_BUF_SIZE]; + + if (G_VALUE_HOLDS_DOUBLE (value)) + v_double = g_value_get_double (value); + else + v_double = (gdouble) g_value_get_float (value); + + g_ascii_dtostr (buf, sizeof (buf), v_double); + g_string_append (str, buf); + return TRUE; + } + + if (GIMP_VALUE_HOLDS_RGB (value)) + { + return gimp_config_serialize_rgb (value, str, TRUE); + } + + if (GIMP_VALUE_HOLDS_MATRIX2 (value)) + { + GimpMatrix2 *trafo; + + trafo = g_value_get_boxed (value); + + if (trafo) + { + gchar buf[4][G_ASCII_DTOSTR_BUF_SIZE]; + gint i, j, k; + + for (i = 0, k = 0; i < 2; i++) + for (j = 0; j < 2; j++, k++) + g_ascii_dtostr (buf[k], G_ASCII_DTOSTR_BUF_SIZE, + trafo->coeff[i][j]); + + g_string_append_printf (str, "(matrix %s %s %s %s)", + buf[0], buf[1], buf[2], buf[3]); + } + else + { + g_string_append (str, "(matrix 1.0 1.0 1.0 1.0)"); + } + + return TRUE; + } + + if (G_VALUE_TYPE (value) == GIMP_TYPE_VALUE_ARRAY) + { + GimpValueArray *array; + + array = g_value_get_boxed (value); + + if (array) + { + gint length = gimp_value_array_length (array); + gint i; + + g_string_append_printf (str, "%d", length); + + for (i = 0; i < length; i++) + { + g_string_append (str, " "); + + if (! gimp_config_serialize_value (gimp_value_array_index (array, + i), + str, TRUE)) + return FALSE; + } + } + else + { + g_string_append (str, "0"); + } + + return TRUE; + } + + if (G_VALUE_TYPE (value) == G_TYPE_FILE) + { + GFile *file = g_value_get_object (value); + + if (file) + { + gchar *path = g_file_get_path (file); + gchar *unexpand = NULL; + + if (path) + { + unexpand = gimp_config_path_unexpand (path, TRUE, NULL); + g_free (path); + } + + if (unexpand) + { + if (escaped) + gimp_config_string_append_escaped (str, unexpand); + else + g_string_append (str, unexpand); + + g_free (unexpand); + } + else + { + g_string_append (str, "NULL"); + } + } + else + { + g_string_append (str, "NULL"); + } + + return TRUE; + } + + if (g_value_type_transformable (G_VALUE_TYPE (value), G_TYPE_STRING)) + { + GValue tmp_value = G_VALUE_INIT; + + g_value_init (&tmp_value, G_TYPE_STRING); + g_value_transform (value, &tmp_value); + + g_string_append (str, g_value_get_string (&tmp_value)); + + g_value_unset (&tmp_value); + return TRUE; + } + + return FALSE; +} + +static gboolean +gimp_config_serialize_rgb (const GValue *value, + GString *str, + gboolean has_alpha) +{ + GimpRGB *rgb; + + rgb = g_value_get_boxed (value); + + if (rgb) + { + gchar buf[4][G_ASCII_DTOSTR_BUF_SIZE]; + + g_ascii_dtostr (buf[0], G_ASCII_DTOSTR_BUF_SIZE, rgb->r); + g_ascii_dtostr (buf[1], G_ASCII_DTOSTR_BUF_SIZE, rgb->g); + g_ascii_dtostr (buf[2], G_ASCII_DTOSTR_BUF_SIZE, rgb->b); + + if (has_alpha) + { + g_ascii_dtostr (buf[3], G_ASCII_DTOSTR_BUF_SIZE, rgb->a); + + g_string_append_printf (str, "(color-rgba %s %s %s %s)", + buf[0], buf[1], buf[2], buf[3]); + } + else + { + g_string_append_printf (str, "(color-rgb %s %s %s)", + buf[0], buf[1], buf[2]); + } + + return TRUE; + } + + return FALSE; +} |