app: s/sprintf/g_snprintf/ in xcf_save_image()
[gimp.git] / libgimpconfig / gimpconfig-utils.c
blob7cef2195099d6c9255540062f65199f078d3256a
1 /* LIBGIMP - The GIMP Library
2 * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
4 * Utility functions for GimpConfig.
5 * Copyright (C) 2001-2003 Sven Neumann <sven@gimp.org>
7 * This library is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 3 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see
19 * <https://www.gnu.org/licenses/>.
22 #include "config.h"
24 #include <gio/gio.h>
26 #include "libgimpbase/gimpbase.h"
28 #include "gimpconfigtypes.h"
30 #include "gimpconfigwriter.h"
31 #include "gimpconfig-iface.h"
32 #include "gimpconfig-params.h"
33 #include "gimpconfig-utils.h"
36 /**
37 * SECTION: gimpconfig-utils
38 * @title: GimpConfig-utils
39 * @short_description: Miscellaneous utility functions for libgimpconfig.
41 * Miscellaneous utility functions for libgimpconfig.
42 **/
45 static gboolean
46 gimp_config_diff_property (GObject *a,
47 GObject *b,
48 GParamSpec *prop_spec)
50 GValue a_value = G_VALUE_INIT;
51 GValue b_value = G_VALUE_INIT;
52 gboolean retval = FALSE;
54 g_value_init (&a_value, prop_spec->value_type);
55 g_value_init (&b_value, prop_spec->value_type);
57 g_object_get_property (a, prop_spec->name, &a_value);
58 g_object_get_property (b, prop_spec->name, &b_value);
60 if (g_param_values_cmp (prop_spec, &a_value, &b_value))
62 if ((prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE) &&
63 G_IS_PARAM_SPEC_OBJECT (prop_spec) &&
64 g_type_interface_peek (g_type_class_peek (prop_spec->value_type),
65 GIMP_TYPE_CONFIG))
67 if (! gimp_config_is_equal_to (g_value_get_object (&a_value),
68 g_value_get_object (&b_value)))
70 retval = TRUE;
73 else
75 retval = TRUE;
79 g_value_unset (&a_value);
80 g_value_unset (&b_value);
82 return retval;
85 static GList *
86 gimp_config_diff_same (GObject *a,
87 GObject *b,
88 GParamFlags flags)
90 GParamSpec **param_specs;
91 guint n_param_specs;
92 gint i;
93 GList *list = NULL;
95 param_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a),
96 &n_param_specs);
98 for (i = 0; i < n_param_specs; i++)
100 GParamSpec *prop_spec = param_specs[i];
102 if (! flags || ((prop_spec->flags & flags) == flags))
104 if (gimp_config_diff_property (a, b, prop_spec))
105 list = g_list_prepend (list, prop_spec);
109 g_free (param_specs);
111 return list;
114 static GList *
115 gimp_config_diff_other (GObject *a,
116 GObject *b,
117 GParamFlags flags)
119 GParamSpec **param_specs;
120 guint n_param_specs;
121 gint i;
122 GList *list = NULL;
124 param_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (a),
125 &n_param_specs);
127 for (i = 0; i < n_param_specs; i++)
129 GParamSpec *a_spec = param_specs[i];
130 GParamSpec *b_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (b),
131 a_spec->name);
133 if (b_spec &&
134 (a_spec->value_type == b_spec->value_type) &&
135 (! flags || (a_spec->flags & b_spec->flags & flags) == flags))
137 if (gimp_config_diff_property (a, b, b_spec))
138 list = g_list_prepend (list, b_spec);
142 g_free (param_specs);
144 return list;
149 * gimp_config_diff:
150 * @a: a #GObject
151 * @b: another #GObject object
152 * @flags: a mask of GParamFlags
154 * Compares all properties of @a and @b that have all @flags set. If
155 * @flags is 0, all properties are compared.
157 * If the two objects are not of the same type, only properties that
158 * exist in both object classes and are of the same value_type are
159 * compared.
161 * Return value: a GList of differing GParamSpecs.
163 * Since: 2.4
165 GList *
166 gimp_config_diff (GObject *a,
167 GObject *b,
168 GParamFlags flags)
170 GList *diff;
172 g_return_val_if_fail (G_IS_OBJECT (a), NULL);
173 g_return_val_if_fail (G_IS_OBJECT (b), NULL);
175 if (G_TYPE_FROM_INSTANCE (a) == G_TYPE_FROM_INSTANCE (b))
176 diff = gimp_config_diff_same (a, b, flags);
177 else
178 diff = gimp_config_diff_other (a, b, flags);
180 return g_list_reverse (diff);
184 * gimp_config_sync:
185 * @src: a #GObject
186 * @dest: another #GObject
187 * @flags: a mask of GParamFlags
189 * Compares all read- and write-able properties from @src and @dest
190 * that have all @flags set. Differing values are then copied from
191 * @src to @dest. If @flags is 0, all differing read/write properties.
193 * Properties marked as "construct-only" are not touched.
195 * If the two objects are not of the same type, only properties that
196 * exist in both object classes and are of the same value_type are
197 * synchronized
199 * Return value: %TRUE if @dest was modified, %FALSE otherwise
201 * Since: 2.4
203 gboolean
204 gimp_config_sync (GObject *src,
205 GObject *dest,
206 GParamFlags flags)
208 GList *diff;
209 GList *list;
211 g_return_val_if_fail (G_IS_OBJECT (src), FALSE);
212 g_return_val_if_fail (G_IS_OBJECT (dest), FALSE);
214 /* we use the internal versions here for a number of reasons:
215 * - it saves a g_list_reverse()
216 * - it avoids duplicated parameter checks
218 if (G_TYPE_FROM_INSTANCE (src) == G_TYPE_FROM_INSTANCE (dest))
219 diff = gimp_config_diff_same (src, dest, (flags | G_PARAM_READWRITE));
220 else
221 diff = gimp_config_diff_other (src, dest, flags);
223 if (!diff)
224 return FALSE;
226 g_object_freeze_notify (G_OBJECT (dest));
228 for (list = diff; list; list = list->next)
230 GParamSpec *prop_spec = list->data;
232 if (! (prop_spec->flags & G_PARAM_CONSTRUCT_ONLY))
234 GValue value = G_VALUE_INIT;
236 g_value_init (&value, prop_spec->value_type);
238 g_object_get_property (src, prop_spec->name, &value);
239 g_object_set_property (dest, prop_spec->name, &value);
241 g_value_unset (&value);
245 g_object_thaw_notify (G_OBJECT (dest));
247 g_list_free (diff);
249 return TRUE;
253 * gimp_config_reset_properties:
254 * @object: a #GObject
256 * Resets all writable properties of @object to the default values as
257 * defined in their #GParamSpec. Properties marked as "construct-only"
258 * are not touched.
260 * If you want to reset a #GimpConfig object, please use gimp_config_reset().
262 * Since: 2.4
264 void
265 gimp_config_reset_properties (GObject *object)
267 GObjectClass *klass;
268 GParamSpec **property_specs;
269 guint n_property_specs;
270 guint i;
272 g_return_if_fail (G_IS_OBJECT (object));
274 klass = G_OBJECT_GET_CLASS (object);
276 property_specs = g_object_class_list_properties (klass, &n_property_specs);
277 if (!property_specs)
278 return;
280 g_object_freeze_notify (object);
282 for (i = 0; i < n_property_specs; i++)
284 GParamSpec *prop_spec;
285 GValue value = G_VALUE_INIT;
287 prop_spec = property_specs[i];
289 if ((prop_spec->flags & G_PARAM_WRITABLE) &&
290 ! (prop_spec->flags & G_PARAM_CONSTRUCT_ONLY))
292 if (G_IS_PARAM_SPEC_OBJECT (prop_spec))
294 if ((prop_spec->flags & GIMP_CONFIG_PARAM_SERIALIZE) &&
295 (prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE) &&
296 g_type_interface_peek (g_type_class_peek (prop_spec->value_type),
297 GIMP_TYPE_CONFIG))
299 g_value_init (&value, prop_spec->value_type);
301 g_object_get_property (object, prop_spec->name, &value);
303 gimp_config_reset (g_value_get_object (&value));
305 g_value_unset (&value);
308 else
310 GValue default_value = G_VALUE_INIT;
312 g_value_init (&default_value, prop_spec->value_type);
313 g_value_init (&value, prop_spec->value_type);
315 g_param_value_set_default (prop_spec, &default_value);
316 g_object_get_property (object, prop_spec->name, &value);
318 if (g_param_values_cmp (prop_spec, &default_value, &value))
320 g_object_set_property (object, prop_spec->name,
321 &default_value);
324 g_value_unset (&value);
325 g_value_unset (&default_value);
330 g_object_thaw_notify (object);
332 g_free (property_specs);
337 * gimp_config_reset_property:
338 * @object: a #GObject
339 * @property_name: name of the property to reset
341 * Resets the property named @property_name to its default value. The
342 * property must be writable and must not be marked as "construct-only".
344 * Since: 2.4
346 void
347 gimp_config_reset_property (GObject *object,
348 const gchar *property_name)
350 GObjectClass *klass;
351 GParamSpec *prop_spec;
353 g_return_if_fail (G_IS_OBJECT (object));
354 g_return_if_fail (property_name != NULL);
356 klass = G_OBJECT_GET_CLASS (object);
358 prop_spec = g_object_class_find_property (klass, property_name);
360 if (!prop_spec)
361 return;
363 if ((prop_spec->flags & G_PARAM_WRITABLE) &&
364 ! (prop_spec->flags & G_PARAM_CONSTRUCT_ONLY))
366 GValue value = G_VALUE_INIT;
368 if (G_IS_PARAM_SPEC_OBJECT (prop_spec))
370 if ((prop_spec->flags & GIMP_CONFIG_PARAM_SERIALIZE) &&
371 (prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE) &&
372 g_type_interface_peek (g_type_class_peek (prop_spec->value_type),
373 GIMP_TYPE_CONFIG))
375 g_value_init (&value, prop_spec->value_type);
377 g_object_get_property (object, prop_spec->name, &value);
379 gimp_config_reset (g_value_get_object (&value));
381 g_value_unset (&value);
384 else
386 g_value_init (&value, prop_spec->value_type);
387 g_param_value_set_default (prop_spec, &value);
389 g_object_set_property (object, prop_spec->name, &value);
391 g_value_unset (&value);
398 * GimpConfig string utilities
402 * gimp_config_string_append_escaped:
403 * @string: pointer to a #GString
404 * @val: a string to append or %NULL
406 * Escapes and quotes @val and appends it to @string. The escape
407 * algorithm is different from the one used by g_strescape() since it
408 * leaves non-ASCII characters intact and thus preserves UTF-8
409 * strings. Only control characters and quotes are being escaped.
411 * Since: 2.4
413 void
414 gimp_config_string_append_escaped (GString *string,
415 const gchar *val)
417 g_return_if_fail (string != NULL);
419 if (val)
421 const guchar *p;
422 gchar buf[4] = { '\\', 0, 0, 0 };
423 gint len;
425 g_string_append_c (string, '\"');
427 for (p = (const guchar *) val, len = 0; *p; p++)
429 if (*p < ' ' || *p == '\\' || *p == '\"')
431 g_string_append_len (string, val, len);
433 len = 2;
434 switch (*p)
436 case '\b':
437 buf[1] = 'b';
438 break;
439 case '\f':
440 buf[1] = 'f';
441 break;
442 case '\n':
443 buf[1] = 'n';
444 break;
445 case '\r':
446 buf[1] = 'r';
447 break;
448 case '\t':
449 buf[1] = 't';
450 break;
451 case '\\':
452 case '"':
453 buf[1] = *p;
454 break;
456 default:
457 len = 4;
458 buf[1] = '0' + (((*p) >> 6) & 07);
459 buf[2] = '0' + (((*p) >> 3) & 07);
460 buf[3] = '0' + ((*p) & 07);
461 break;
464 g_string_append_len (string, buf, len);
466 val = (const gchar *) p + 1;
467 len = 0;
469 else
471 len++;
475 g_string_append_len (string, val, len);
476 g_string_append_c (string, '\"');
478 else
480 g_string_append_len (string, "\"\"", 2);