123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- /* LIBGIMP - The GIMP Library
- * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
- *
- * Utility functions for GimpConfig.
- * Copyright (C) 2001-2003 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 <gio/gio.h>
- #include "libgimpbase/gimpbase.h"
- #include "gimpconfigtypes.h"
- #include "gimpconfigwriter.h"
- #include "gimpconfig-iface.h"
- #include "gimpconfig-params.h"
- #include "gimpconfig-utils.h"
- /**
- * SECTION: gimpconfig-utils
- * @title: GimpConfig-utils
- * @short_description: Miscellaneous utility functions for libgimpconfig.
- *
- * Miscellaneous utility functions for libgimpconfig.
- **/
- static gboolean
- gimp_config_diff_property (GObject *a,
- GObject *b,
- GParamSpec *prop_spec)
- {
- GValue a_value = G_VALUE_INIT;
- GValue b_value = G_VALUE_INIT;
- gboolean retval = FALSE;
- g_value_init (&a_value, prop_spec->value_type);
- g_value_init (&b_value, prop_spec->value_type);
- g_object_get_property (a, prop_spec->name, &a_value);
- g_object_get_property (b, prop_spec->name, &b_value);
- /* TODO: temporary hack to handle case of NULL GeglColor in a param value.
- * This got fixed in commit c0477bcb0 which should be available for GEGL
- * 0.4.50. In the meantime, this will do.
- */
- if (GEGL_IS_PARAM_SPEC_COLOR (prop_spec) &&
- (! g_value_get_object (&a_value) ||
- ! g_value_get_object (&b_value)))
- {
- retval = (g_value_get_object (&a_value) != g_value_get_object (&b_value));
- }
- else if (g_param_values_cmp (prop_spec, &a_value, &b_value))
- {
- if ((prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE) &&
- G_IS_PARAM_SPEC_OBJECT (prop_spec) &&
- g_type_interface_peek (g_type_class_peek (prop_spec->value_type),
- GIMP_TYPE_CONFIG))
- {
- if (! gimp_config_is_equal_to (g_value_get_object (&a_value),
- g_value_get_object (&b_value)))
- {
- retval = TRUE;
- }
- }
- else
- {
- retval = TRUE;
- }
- }
- g_value_unset (&a_value);
- g_value_unset (&b_value);
- return retval;
- }
- static GList *
- gimp_config_diff_same (GObject *a,
- GObject *b,
- GParamFlags flags)
- {
- GParamSpec **param_specs;
- guint n_param_specs;
- guint i;
- GList *list = NULL;
- param_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a),
- &n_param_specs);
- for (i = 0; i < n_param_specs; i++)
- {
- GParamSpec *prop_spec = param_specs[i];
- if (! flags || ((prop_spec->flags & flags) == flags))
- {
- if (gimp_config_diff_property (a, b, prop_spec))
- list = g_list_prepend (list, prop_spec);
- }
- }
- g_free (param_specs);
- return list;
- }
- static GList *
- gimp_config_diff_other (GObject *a,
- GObject *b,
- GParamFlags flags)
- {
- GParamSpec **param_specs;
- guint n_param_specs;
- guint i;
- GList *list = NULL;
- param_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a),
- &n_param_specs);
- for (i = 0; i < n_param_specs; i++)
- {
- GParamSpec *a_spec = param_specs[i];
- GParamSpec *b_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (b),
- a_spec->name);
- if (b_spec &&
- (a_spec->value_type == b_spec->value_type) &&
- (! flags || (a_spec->flags & b_spec->flags & flags) == flags))
- {
- if (gimp_config_diff_property (a, b, b_spec))
- list = g_list_prepend (list, b_spec);
- }
- }
- g_free (param_specs);
- return list;
- }
- /**
- * gimp_config_diff:
- * @a: a #GObject
- * @b: another #GObject object
- * @flags: a mask of GParamFlags
- *
- * Compares all properties of @a and @b that have all @flags set. If
- * @flags is 0, all properties are compared.
- *
- * If the two objects are not of the same type, only properties that
- * exist in both object classes and are of the same value_type are
- * compared.
- *
- * Returns: (transfer container) (element-type GParamSpec): a GList of differing GParamSpecs.
- *
- * Since: 2.4
- **/
- GList *
- gimp_config_diff (GObject *a,
- GObject *b,
- GParamFlags flags)
- {
- GList *diff;
- g_return_val_if_fail (G_IS_OBJECT (a), NULL);
- g_return_val_if_fail (G_IS_OBJECT (b), NULL);
- if (G_TYPE_FROM_INSTANCE (a) == G_TYPE_FROM_INSTANCE (b))
- diff = gimp_config_diff_same (a, b, flags);
- else
- diff = gimp_config_diff_other (a, b, flags);
- return g_list_reverse (diff);
- }
- /**
- * gimp_config_sync:
- * @src: a #GObject
- * @dest: another #GObject
- * @flags: a mask of GParamFlags
- *
- * Compares all read- and write-able properties from @src and @dest
- * that have all @flags set. Differing values are then copied from
- * @src to @dest. If @flags is 0, all differing read/write properties.
- *
- * Properties marked as "construct-only" are not touched.
- *
- * If the two objects are not of the same type, only properties that
- * exist in both object classes and are of the same value_type are
- * synchronized
- *
- * Returns: %TRUE if @dest was modified, %FALSE otherwise
- *
- * Since: 2.4
- **/
- gboolean
- gimp_config_sync (GObject *src,
- GObject *dest,
- GParamFlags flags)
- {
- GList *diff;
- GList *list;
- g_return_val_if_fail (G_IS_OBJECT (src), FALSE);
- g_return_val_if_fail (G_IS_OBJECT (dest), FALSE);
- /* we use the internal versions here for a number of reasons:
- * - it saves a g_list_reverse()
- * - it avoids duplicated parameter checks
- */
- if (G_TYPE_FROM_INSTANCE (src) == G_TYPE_FROM_INSTANCE (dest))
- diff = gimp_config_diff_same (src, dest, (flags | G_PARAM_READWRITE));
- else
- diff = gimp_config_diff_other (src, dest, flags);
- if (!diff)
- return FALSE;
- g_object_freeze_notify (G_OBJECT (dest));
- for (list = diff; list; list = list->next)
- {
- GParamSpec *prop_spec = list->data;
- if (! (prop_spec->flags & G_PARAM_CONSTRUCT_ONLY))
- {
- GValue value = G_VALUE_INIT;
- g_value_init (&value, prop_spec->value_type);
- g_object_get_property (src, prop_spec->name, &value);
- g_object_set_property (dest, prop_spec->name, &value);
- g_value_unset (&value);
- }
- }
- g_object_thaw_notify (G_OBJECT (dest));
- g_list_free (diff);
- return TRUE;
- }
- /**
- * gimp_config_reset_properties:
- * @object: a #GObject
- *
- * Resets all writable properties of @object to the default values as
- * defined in their #GParamSpec. Properties marked as "construct-only"
- * are not touched.
- *
- * If you want to reset a #GimpConfig object, please use gimp_config_reset().
- *
- * Since: 2.4
- **/
- void
- gimp_config_reset_properties (GObject *object)
- {
- GObjectClass *klass;
- GParamSpec **property_specs;
- guint n_property_specs;
- guint i;
- g_return_if_fail (G_IS_OBJECT (object));
- klass = G_OBJECT_GET_CLASS (object);
- property_specs = g_object_class_list_properties (klass, &n_property_specs);
- if (!property_specs)
- return;
- g_object_freeze_notify (object);
- for (i = 0; i < n_property_specs; i++)
- {
- GParamSpec *prop_spec;
- GValue value = G_VALUE_INIT;
- prop_spec = property_specs[i];
- if ((prop_spec->flags & G_PARAM_WRITABLE) &&
- ! (prop_spec->flags & G_PARAM_CONSTRUCT_ONLY))
- {
- if (G_IS_PARAM_SPEC_OBJECT (prop_spec))
- {
- if ((prop_spec->flags & GIMP_CONFIG_PARAM_SERIALIZE) &&
- (prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE) &&
- g_type_interface_peek (g_type_class_peek (prop_spec->value_type),
- GIMP_TYPE_CONFIG))
- {
- g_value_init (&value, prop_spec->value_type);
- g_object_get_property (object, prop_spec->name, &value);
- gimp_config_reset (g_value_get_object (&value));
- g_value_unset (&value);
- }
- }
- else
- {
- GValue default_value = G_VALUE_INIT;
- g_value_init (&default_value, prop_spec->value_type);
- g_value_init (&value, prop_spec->value_type);
- g_param_value_set_default (prop_spec, &default_value);
- g_object_get_property (object, prop_spec->name, &value);
- if (g_param_values_cmp (prop_spec, &default_value, &value))
- {
- g_object_set_property (object, prop_spec->name,
- &default_value);
- }
- g_value_unset (&value);
- g_value_unset (&default_value);
- }
- }
- }
- g_object_thaw_notify (object);
- g_free (property_specs);
- }
- /**
- * gimp_config_reset_property:
- * @object: a #GObject
- * @property_name: name of the property to reset
- *
- * Resets the property named @property_name to its default value. The
- * property must be writable and must not be marked as "construct-only".
- *
- * Since: 2.4
- **/
- void
- gimp_config_reset_property (GObject *object,
- const gchar *property_name)
- {
- GObjectClass *klass;
- GParamSpec *prop_spec;
- g_return_if_fail (G_IS_OBJECT (object));
- g_return_if_fail (property_name != NULL);
- klass = G_OBJECT_GET_CLASS (object);
- prop_spec = g_object_class_find_property (klass, property_name);
- if (!prop_spec)
- return;
- if ((prop_spec->flags & G_PARAM_WRITABLE) &&
- ! (prop_spec->flags & G_PARAM_CONSTRUCT_ONLY))
- {
- GValue value = G_VALUE_INIT;
- if (G_IS_PARAM_SPEC_OBJECT (prop_spec))
- {
- if ((prop_spec->flags & GIMP_CONFIG_PARAM_SERIALIZE) &&
- (prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE) &&
- g_type_interface_peek (g_type_class_peek (prop_spec->value_type),
- GIMP_TYPE_CONFIG))
- {
- g_value_init (&value, prop_spec->value_type);
- g_object_get_property (object, prop_spec->name, &value);
- gimp_config_reset (g_value_get_object (&value));
- g_value_unset (&value);
- }
- }
- else
- {
- g_value_init (&value, prop_spec->value_type);
- g_param_value_set_default (prop_spec, &value);
- g_object_set_property (object, prop_spec->name, &value);
- g_value_unset (&value);
- }
- }
- }
- /*
- * GimpConfig string utilities
- */
- /**
- * gimp_config_string_append_escaped:
- * @string: pointer to a #GString
- * @val: a string to append or %NULL
- *
- * Escapes and quotes @val and appends it to @string. The escape
- * algorithm is different from the one used by g_strescape() since it
- * leaves non-ASCII characters intact and thus preserves UTF-8
- * strings. Only control characters and quotes are being escaped.
- *
- * Since: 2.4
- **/
- void
- gimp_config_string_append_escaped (GString *string,
- const gchar *val)
- {
- g_return_if_fail (string != NULL);
- if (val)
- {
- const guchar *p;
- gchar buf[4] = { '\\', 0, 0, 0 };
- gint len;
- g_string_append_c (string, '\"');
- for (p = (const guchar *) val, len = 0; *p; p++)
- {
- if (*p < ' ' || *p == '\\' || *p == '\"')
- {
- g_string_append_len (string, val, len);
- len = 2;
- switch (*p)
- {
- case '\b':
- buf[1] = 'b';
- break;
- case '\f':
- buf[1] = 'f';
- break;
- case '\n':
- buf[1] = 'n';
- break;
- case '\r':
- buf[1] = 'r';
- break;
- case '\t':
- buf[1] = 't';
- break;
- case '\\':
- case '"':
- buf[1] = *p;
- break;
- default:
- len = 4;
- buf[1] = '0' + (((*p) >> 6) & 07);
- buf[2] = '0' + (((*p) >> 3) & 07);
- buf[3] = '0' + ((*p) & 07);
- break;
- }
- g_string_append_len (string, buf, len);
- val = (const gchar *) p + 1;
- len = 0;
- }
- else
- {
- len++;
- }
- }
- g_string_append_len (string, val, len);
- g_string_append_c (string, '\"');
- }
- else
- {
- g_string_append_len (string, "\"\"", 2);
- }
- }
|