2005-01-29 12:54:48 +00:00
|
|
|
/* LIBGIMP - The GIMP Library
|
|
|
|
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
|
2001-11-27 03:52:11 +00:00
|
|
|
*
|
|
|
|
* Object properties deserialization routines
|
2002-03-23 17:58:57 +00:00
|
|
|
* Copyright (C) 2001-2002 Sven Neumann <sven@gimp.org>
|
2001-11-27 03:52:11 +00:00
|
|
|
*
|
2009-01-17 22:28:01 +00:00
|
|
|
* This library is free software: you can redistribute it and/or
|
2007-03-02 08:38:13 +00:00
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
2009-01-17 22:28:01 +00:00
|
|
|
* version 3 of the License, or (at your option) any later version.
|
2001-11-27 03:52:11 +00:00
|
|
|
*
|
2007-03-02 08:38:13 +00:00
|
|
|
* This library is distributed in the hope that it will be useful,
|
2001-11-27 03:52:11 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2007-03-02 08:38:13 +00:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
2001-11-27 03:52:11 +00:00
|
|
|
*
|
2007-03-02 08:38:13 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2009-01-17 22:28:01 +00:00
|
|
|
* License along with this library. If not, see
|
2018-07-11 23:27:07 +02:00
|
|
|
* <https://www.gnu.org/licenses/>.
|
2001-11-27 03:52:11 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2011-04-28 15:50:39 +02:00
|
|
|
#include <cairo.h>
|
2012-05-03 03:36:22 +02:00
|
|
|
#include <gegl.h>
|
|
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
2001-11-27 03:52:11 +00:00
|
|
|
|
2002-05-21 17:33:04 +00:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2002-05-21 15:01:57 +00:00
|
|
|
#include "libgimpcolor/gimpcolor.h"
|
2003-07-07 16:22:45 +00:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
2002-05-21 15:01:57 +00:00
|
|
|
|
2005-01-25 20:30:20 +00:00
|
|
|
#include "gimpconfigtypes.h"
|
|
|
|
|
2005-01-25 19:11:26 +00:00
|
|
|
#include "gimpconfigwriter.h"
|
|
|
|
#include "gimpconfig-iface.h"
|
2001-11-27 03:52:11 +00:00
|
|
|
#include "gimpconfig-deserialize.h"
|
2002-05-21 17:33:04 +00:00
|
|
|
#include "gimpconfig-params.h"
|
2002-12-29 18:58:24 +00:00
|
|
|
#include "gimpconfig-path.h"
|
2002-06-06 19:31:52 +00:00
|
|
|
#include "gimpscanner.h"
|
2001-11-27 03:52:11 +00:00
|
|
|
|
2005-01-25 19:11:26 +00:00
|
|
|
#include "libgimp/libgimp-intl.h"
|
2001-12-13 01:55:37 +00:00
|
|
|
|
2001-11-27 03:52:11 +00:00
|
|
|
|
2010-06-29 20:57:52 +02:00
|
|
|
/**
|
|
|
|
* SECTION: gimpconfig-deserialize
|
|
|
|
* @title: GimpConfig-deserialize
|
|
|
|
* @short_description: Deserializing code for libgimpconfig.
|
|
|
|
*
|
|
|
|
* Deserializing code for libgimpconfig.
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
2003-09-16 13:12:50 +00:00
|
|
|
/*
|
2001-12-09 03:00:32 +00:00
|
|
|
* All functions return G_TOKEN_RIGHT_PAREN on success,
|
|
|
|
* the GTokenType they would have expected but didn't get
|
|
|
|
* or G_TOKEN_NONE if they got the expected token but
|
|
|
|
* couldn't parse it.
|
|
|
|
*/
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2021-04-05 21:49:41 +02:00
|
|
|
static GTokenType gimp_config_deserialize_value (GValue *value,
|
|
|
|
GimpConfig *config,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner);
|
|
|
|
static GTokenType gimp_config_deserialize_fundamental (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner);
|
|
|
|
static GTokenType gimp_config_deserialize_enum (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner);
|
|
|
|
static GTokenType gimp_config_deserialize_memsize (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner);
|
|
|
|
static GTokenType gimp_config_deserialize_path (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner);
|
|
|
|
static GTokenType gimp_config_deserialize_matrix2 (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner);
|
|
|
|
static GTokenType gimp_config_deserialize_object (GValue *value,
|
|
|
|
GimpConfig *config,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner,
|
|
|
|
gint nest_level);
|
|
|
|
static GTokenType gimp_config_deserialize_value_array (GValue *value,
|
|
|
|
GimpConfig *config,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner);
|
2024-10-24 17:43:09 +02:00
|
|
|
static GTokenType gimp_config_deserialize_array (GValue *value,
|
|
|
|
GScanner *scanner);
|
2024-10-17 22:08:16 +02:00
|
|
|
static GTokenType gimp_config_deserialize_strv (GValue *value,
|
|
|
|
GScanner *scanner);
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-25 20:55:21 +02:00
|
|
|
static GimpUnit * gimp_config_get_unit_from_identifier (const gchar *identifier);
|
2021-04-05 21:49:41 +02:00
|
|
|
static GTokenType gimp_config_deserialize_unit (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner);
|
|
|
|
static GTokenType gimp_config_deserialize_file_value (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner);
|
|
|
|
static GTokenType gimp_config_deserialize_parasite_value (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner);
|
2023-07-23 17:32:25 +02:00
|
|
|
static GTokenType gimp_config_deserialize_bytes (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner);
|
2023-11-15 02:28:34 +01:00
|
|
|
static GTokenType gimp_config_deserialize_color (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner);
|
2021-04-05 21:49:41 +02:00
|
|
|
static GTokenType gimp_config_deserialize_any (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner);
|
|
|
|
static GTokenType gimp_config_skip_unknown_property (GScanner *scanner);
|
2001-11-27 03:52:11 +00:00
|
|
|
|
2003-09-16 13:12:50 +00:00
|
|
|
static inline gboolean scanner_string_utf8_valid (GScanner *scanner,
|
2001-12-13 01:55:37 +00:00
|
|
|
const gchar *token_name);
|
2001-12-10 18:31:35 +00:00
|
|
|
|
2004-11-14 02:50:33 +00:00
|
|
|
static inline gboolean
|
|
|
|
scanner_string_utf8_valid (GScanner *scanner,
|
|
|
|
const gchar *token_name)
|
|
|
|
{
|
|
|
|
if (g_utf8_validate (scanner->value.v_string, -1, NULL))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
g_scanner_error (scanner,
|
|
|
|
_("value for token %s is not a valid UTF-8 string"),
|
|
|
|
token_name);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
2001-11-27 03:52:11 +00:00
|
|
|
|
2002-03-23 17:58:57 +00:00
|
|
|
/**
|
|
|
|
* gimp_config_deserialize_properties:
|
2003-10-11 15:02:03 +00:00
|
|
|
* @config: a #GimpConfig.
|
2002-03-23 17:58:57 +00:00
|
|
|
* @scanner: a #GScanner.
|
2010-06-29 22:19:11 +02:00
|
|
|
* @nest_level: the nest level
|
2003-09-16 13:12:50 +00:00
|
|
|
*
|
2003-10-11 15:02:03 +00:00
|
|
|
* This function uses the @scanner to configure the properties of @config.
|
2002-03-23 17:58:57 +00:00
|
|
|
*
|
2019-08-03 00:10:14 +02:00
|
|
|
* Returns: %TRUE on success, %FALSE otherwise.
|
2005-01-29 12:54:48 +00:00
|
|
|
*
|
2015-05-31 21:18:09 +02:00
|
|
|
* Since: 2.4
|
2002-03-23 17:58:57 +00:00
|
|
|
**/
|
2001-11-27 03:52:11 +00:00
|
|
|
gboolean
|
2003-10-11 14:30:18 +00:00
|
|
|
gimp_config_deserialize_properties (GimpConfig *config,
|
|
|
|
GScanner *scanner,
|
2005-01-24 22:07:52 +00:00
|
|
|
gint nest_level)
|
2001-11-27 03:52:11 +00:00
|
|
|
{
|
2001-12-07 16:10:53 +00:00
|
|
|
GObjectClass *klass;
|
|
|
|
GParamSpec **property_specs;
|
|
|
|
guint n_property_specs;
|
|
|
|
guint i;
|
|
|
|
guint scope_id;
|
|
|
|
guint old_scope_id;
|
2007-06-04 10:38:25 +00:00
|
|
|
GTokenType token;
|
2001-12-07 16:10:53 +00:00
|
|
|
|
2003-10-11 14:30:18 +00:00
|
|
|
g_return_val_if_fail (GIMP_IS_CONFIG (config), FALSE);
|
2001-11-27 03:52:11 +00:00
|
|
|
|
2003-10-11 14:30:18 +00:00
|
|
|
klass = G_OBJECT_GET_CLASS (config);
|
2001-12-07 16:10:53 +00:00
|
|
|
property_specs = g_object_class_list_properties (klass, &n_property_specs);
|
2001-11-27 03:52:11 +00:00
|
|
|
|
2007-06-04 10:38:25 +00:00
|
|
|
if (! property_specs)
|
2001-12-10 20:43:51 +00:00
|
|
|
return TRUE;
|
2001-11-27 03:52:11 +00:00
|
|
|
|
2003-10-11 14:30:18 +00:00
|
|
|
scope_id = g_type_qname (G_TYPE_FROM_INSTANCE (config));
|
2001-11-27 03:52:11 +00:00
|
|
|
old_scope_id = g_scanner_set_scope (scanner, scope_id);
|
|
|
|
|
|
|
|
for (i = 0; i < n_property_specs; i++)
|
|
|
|
{
|
|
|
|
GParamSpec *prop_spec = property_specs[i];
|
|
|
|
|
2005-02-05 14:52:58 +00:00
|
|
|
if (prop_spec->flags & GIMP_CONFIG_PARAM_SERIALIZE)
|
2001-11-27 03:52:11 +00:00
|
|
|
{
|
2003-09-16 13:12:50 +00:00
|
|
|
g_scanner_scope_add_symbol (scanner, scope_id,
|
2001-11-27 03:52:11 +00:00
|
|
|
prop_spec->name, prop_spec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-12-13 01:55:37 +00:00
|
|
|
g_free (property_specs);
|
|
|
|
|
2003-10-11 14:30:18 +00:00
|
|
|
g_object_freeze_notify (G_OBJECT (config));
|
2003-02-28 17:01:13 +00:00
|
|
|
|
2001-11-27 03:52:11 +00:00
|
|
|
token = G_TOKEN_LEFT_PAREN;
|
2002-05-27 14:04:21 +00:00
|
|
|
|
|
|
|
while (TRUE)
|
2001-11-27 03:52:11 +00:00
|
|
|
{
|
2016-09-28 18:32:25 +02:00
|
|
|
GTokenType next = g_scanner_peek_next_token (scanner);
|
|
|
|
|
|
|
|
if (next == G_TOKEN_EOF)
|
|
|
|
break;
|
2001-12-09 03:00:32 +00:00
|
|
|
|
2007-06-04 10:38:25 +00:00
|
|
|
if (G_UNLIKELY (next != token &&
|
|
|
|
! (token == G_TOKEN_SYMBOL &&
|
|
|
|
next == G_TOKEN_IDENTIFIER)))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2001-11-27 03:52:11 +00:00
|
|
|
|
|
|
|
token = g_scanner_get_next_token (scanner);
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2001-11-27 03:52:11 +00:00
|
|
|
switch (token)
|
|
|
|
{
|
|
|
|
case G_TOKEN_LEFT_PAREN:
|
|
|
|
token = G_TOKEN_SYMBOL;
|
|
|
|
break;
|
2002-05-27 14:04:21 +00:00
|
|
|
|
2007-06-04 10:38:25 +00:00
|
|
|
case G_TOKEN_IDENTIFIER:
|
|
|
|
token = gimp_config_skip_unknown_property (scanner);
|
|
|
|
break;
|
|
|
|
|
2001-11-27 03:52:11 +00:00
|
|
|
case G_TOKEN_SYMBOL:
|
2003-10-11 14:30:18 +00:00
|
|
|
token = gimp_config_deserialize_property (config,
|
2003-02-28 17:01:13 +00:00
|
|
|
scanner, nest_level);
|
2001-11-27 03:52:11 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case G_TOKEN_RIGHT_PAREN:
|
|
|
|
token = G_TOKEN_LEFT_PAREN;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: /* do nothing */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-12-07 16:10:53 +00:00
|
|
|
g_scanner_set_scope (scanner, old_scope_id);
|
|
|
|
|
2003-10-11 14:30:18 +00:00
|
|
|
g_object_thaw_notify (G_OBJECT (config));
|
2003-02-28 17:01:13 +00:00
|
|
|
|
2003-10-21 18:14:58 +00:00
|
|
|
if (token == G_TOKEN_NONE)
|
|
|
|
return FALSE;
|
|
|
|
|
2002-06-17 19:36:33 +00:00
|
|
|
return gimp_config_deserialize_return (scanner, token, nest_level);
|
2001-11-27 03:52:11 +00:00
|
|
|
}
|
|
|
|
|
2005-01-29 12:54:48 +00:00
|
|
|
/**
|
|
|
|
* gimp_config_deserialize_property:
|
|
|
|
* @config: a #GimpConfig.
|
|
|
|
* @scanner: a #GScanner.
|
2010-06-29 22:19:11 +02:00
|
|
|
* @nest_level: the nest level
|
2005-01-29 12:54:48 +00:00
|
|
|
*
|
|
|
|
* This function deserializes a single property of @config. You
|
|
|
|
* shouldn't need to call this function directly. If possible, use
|
|
|
|
* gimp_config_deserialize_properties() instead.
|
|
|
|
*
|
2019-08-03 00:10:14 +02:00
|
|
|
* Returns: %G_TOKEN_RIGHT_PAREN on success, otherwise the
|
2005-01-29 12:54:48 +00:00
|
|
|
* expected #GTokenType or %G_TOKEN_NONE if the expected token was
|
|
|
|
* found but couldn't be parsed.
|
|
|
|
*
|
2015-05-31 21:18:09 +02:00
|
|
|
* Since: 2.4
|
2005-01-29 12:54:48 +00:00
|
|
|
**/
|
2005-01-24 22:05:02 +00:00
|
|
|
GTokenType
|
2003-10-11 14:30:18 +00:00
|
|
|
gimp_config_deserialize_property (GimpConfig *config,
|
2003-02-28 17:01:13 +00:00
|
|
|
GScanner *scanner,
|
|
|
|
gint nest_level)
|
2001-11-27 03:52:11 +00:00
|
|
|
{
|
2006-08-08 12:29:48 +00:00
|
|
|
GimpConfigInterface *config_iface = NULL;
|
2005-12-30 18:35:49 +00:00
|
|
|
GimpConfigInterface *parent_iface = NULL;
|
2002-05-22 13:19:19 +00:00
|
|
|
GParamSpec *prop_spec;
|
2016-03-26 15:59:26 +01:00
|
|
|
GTokenType token = G_TOKEN_RIGHT_PAREN;
|
|
|
|
GValue value = G_VALUE_INIT;
|
2003-11-13 17:09:23 +00:00
|
|
|
guint old_scope_id;
|
|
|
|
|
|
|
|
old_scope_id = g_scanner_set_scope (scanner, 0);
|
2001-11-27 03:52:11 +00:00
|
|
|
|
2002-05-22 13:19:19 +00:00
|
|
|
prop_spec = G_PARAM_SPEC (scanner->value.v_symbol);
|
2001-12-07 16:10:53 +00:00
|
|
|
|
2001-12-08 15:56:40 +00:00
|
|
|
g_value_init (&value, prop_spec->value_type);
|
|
|
|
|
2006-08-08 12:29:48 +00:00
|
|
|
if (G_TYPE_IS_OBJECT (prop_spec->owner_type))
|
2004-02-19 12:30:18 +00:00
|
|
|
{
|
2006-08-08 12:29:48 +00:00
|
|
|
GTypeClass *owner_class = g_type_class_peek (prop_spec->owner_type);
|
|
|
|
|
|
|
|
config_iface = g_type_interface_peek (owner_class, GIMP_TYPE_CONFIG);
|
|
|
|
|
|
|
|
/* We must call deserialize_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;
|
2004-02-19 12:30:18 +00:00
|
|
|
|
2006-08-08 12:29:48 +00:00
|
|
|
owner_parent_class = g_type_class_peek_parent (owner_class);
|
2004-02-19 12:30:18 +00:00
|
|
|
|
2006-08-08 12:29:48 +00:00
|
|
|
parent_iface = g_type_interface_peek (owner_parent_class,
|
|
|
|
GIMP_TYPE_CONFIG);
|
|
|
|
}
|
2004-02-19 12:30:18 +00:00
|
|
|
}
|
|
|
|
|
2003-10-11 14:30:18 +00:00
|
|
|
if (config_iface &&
|
2004-02-19 12:30:18 +00:00
|
|
|
config_iface != parent_iface && /* see comment above */
|
2003-10-11 14:30:18 +00:00
|
|
|
config_iface->deserialize_property &&
|
|
|
|
config_iface->deserialize_property (config,
|
|
|
|
prop_spec->param_id,
|
|
|
|
&value,
|
|
|
|
prop_spec,
|
|
|
|
scanner,
|
|
|
|
&token))
|
2002-05-22 13:19:19 +00:00
|
|
|
{
|
|
|
|
/* nop */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-25 20:55:21 +02:00
|
|
|
if (G_VALUE_HOLDS_OBJECT (&value) &&
|
|
|
|
G_VALUE_TYPE (&value) != G_TYPE_FILE &&
|
|
|
|
G_VALUE_TYPE (&value) != GEGL_TYPE_COLOR &&
|
|
|
|
G_VALUE_TYPE (&value) != GIMP_TYPE_UNIT)
|
2016-05-08 22:21:15 +02:00
|
|
|
{
|
|
|
|
token = gimp_config_deserialize_object (&value,
|
|
|
|
config, prop_spec,
|
|
|
|
scanner, nest_level);
|
|
|
|
}
|
2003-02-28 17:01:13 +00:00
|
|
|
else
|
2016-05-08 22:21:15 +02:00
|
|
|
{
|
|
|
|
token = gimp_config_deserialize_value (&value,
|
|
|
|
config, prop_spec, scanner);
|
|
|
|
}
|
2001-12-08 15:56:40 +00:00
|
|
|
}
|
2001-12-08 03:35:38 +00:00
|
|
|
|
2001-12-10 12:32:28 +00:00
|
|
|
if (token == G_TOKEN_RIGHT_PAREN &&
|
|
|
|
g_scanner_peek_next_token (scanner) == token)
|
|
|
|
{
|
2024-08-31 01:37:14 +02:00
|
|
|
if (! (prop_spec->flags & GIMP_PARAM_DONT_SERIALIZE) &&
|
|
|
|
(GIMP_VALUE_HOLDS_COLOR (&value) ||
|
|
|
|
! (G_VALUE_HOLDS_OBJECT (&value) &&
|
|
|
|
(prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE))))
|
2003-10-11 14:30:18 +00:00
|
|
|
g_object_set_property (G_OBJECT (config), prop_spec->name, &value);
|
2001-12-10 12:32:28 +00:00
|
|
|
}
|
2003-09-16 13:12:50 +00:00
|
|
|
#ifdef CONFIG_DEBUG
|
2001-12-09 03:00:32 +00:00
|
|
|
else
|
2001-12-10 12:32:28 +00:00
|
|
|
{
|
2004-05-12 08:13:33 +00:00
|
|
|
g_warning ("%s: couldn't deserialize property %s::%s of type %s",
|
|
|
|
G_STRFUNC,
|
2003-10-11 14:30:18 +00:00
|
|
|
g_type_name (G_TYPE_FROM_INSTANCE (config)),
|
2003-09-16 13:12:50 +00:00
|
|
|
prop_spec->name,
|
2001-12-10 12:32:28 +00:00
|
|
|
g_type_name (prop_spec->value_type));
|
|
|
|
}
|
2002-03-23 17:58:57 +00:00
|
|
|
#endif
|
2001-12-08 03:35:38 +00:00
|
|
|
|
2001-12-08 15:56:40 +00:00
|
|
|
g_value_unset (&value);
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2003-11-13 17:09:23 +00:00
|
|
|
g_scanner_set_scope (scanner, old_scope_id);
|
|
|
|
|
2001-12-09 03:00:32 +00:00
|
|
|
return token;
|
2001-12-08 15:56:40 +00:00
|
|
|
}
|
|
|
|
|
2002-05-24 17:42:21 +00:00
|
|
|
static GTokenType
|
|
|
|
gimp_config_deserialize_value (GValue *value,
|
2003-10-11 15:02:03 +00:00
|
|
|
GimpConfig *config,
|
2002-05-24 17:42:21 +00:00
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner)
|
|
|
|
{
|
|
|
|
if (G_TYPE_FUNDAMENTAL (prop_spec->value_type) == G_TYPE_ENUM)
|
|
|
|
{
|
|
|
|
return gimp_config_deserialize_enum (value, prop_spec, scanner);
|
|
|
|
}
|
|
|
|
else if (G_TYPE_IS_FUNDAMENTAL (prop_spec->value_type))
|
|
|
|
{
|
|
|
|
return gimp_config_deserialize_fundamental (value, prop_spec, scanner);
|
|
|
|
}
|
|
|
|
else if (prop_spec->value_type == GIMP_TYPE_MEMSIZE)
|
|
|
|
{
|
|
|
|
return gimp_config_deserialize_memsize (value, prop_spec, scanner);
|
|
|
|
}
|
2005-01-25 23:44:05 +00:00
|
|
|
else if (prop_spec->value_type == GIMP_TYPE_CONFIG_PATH)
|
2002-05-24 17:42:21 +00:00
|
|
|
{
|
2002-12-29 18:58:24 +00:00
|
|
|
return gimp_config_deserialize_path (value, prop_spec, scanner);
|
2002-05-24 17:42:21 +00:00
|
|
|
}
|
2003-07-07 16:22:45 +00:00
|
|
|
else if (prop_spec->value_type == GIMP_TYPE_MATRIX2)
|
|
|
|
{
|
|
|
|
return gimp_config_deserialize_matrix2 (value, prop_spec, scanner);
|
|
|
|
}
|
2012-05-04 00:50:23 +02:00
|
|
|
else if (prop_spec->value_type == GIMP_TYPE_VALUE_ARRAY)
|
2002-05-24 17:42:21 +00:00
|
|
|
{
|
|
|
|
return gimp_config_deserialize_value_array (value,
|
2003-10-11 15:02:03 +00:00
|
|
|
config, prop_spec, scanner);
|
2002-05-24 17:42:21 +00:00
|
|
|
}
|
2023-06-15 17:12:44 +00:00
|
|
|
else if (prop_spec->value_type == G_TYPE_STRV)
|
|
|
|
{
|
|
|
|
return gimp_config_deserialize_strv (value, scanner);
|
|
|
|
}
|
2024-10-24 22:18:20 +02:00
|
|
|
else if (prop_spec->value_type == GIMP_TYPE_INT32_ARRAY ||
|
app, libgimp*, pdb, plug-ins: rename various public API name s/float/double/.
Several types functions were using the wording "float" historically to
mean double-precision, e.g. the float array type (which was in fact a
double array). Or the scanner function gimp_scanner_parse_float() was in
fact returning a double value. What if we wanted someday to actually add
float (usually this naming means in C the single-precision IEEE 754
floating point representation) support? How would we name this?
Now technically it's not entirely wrong (a double is still a floating
point). So I've been wondering if that is because maybe we never planned
to have float and double precision may be good enough for all usage in a
plug-in API (which doesn't have to be as generic so the higher precision
is enough)? But how can we be sure? Also we already had some functions
using the wording double (e.g. gimp_procedure_add_double_argument()), so
let's just go the safe route and use the accurate wording.
The additional change in PDB is internal, but there too, I was also
finding very confusing that we were naming double-precision float as
'float' type. So I took the opportunity to update this. It doesn't
change any signature.
In fact the whole commit doesn't change any type or code logic, only
naming, except for one bug fix in the middle which I encountered while
renaming: in gimp_scanner_parse_deprecated_color(), I discovered a
hidden bug in scanning (color-hsv*) values, which was mistakenly using a
double type for an array of float.
2024-11-02 14:03:37 +01:00
|
|
|
prop_spec->value_type == GIMP_TYPE_DOUBLE_ARRAY)
|
2024-10-24 17:43:09 +02:00
|
|
|
{
|
|
|
|
return gimp_config_deserialize_array (value, scanner);
|
|
|
|
}
|
2012-10-04 23:54:27 +02:00
|
|
|
else if (prop_spec->value_type == GIMP_TYPE_UNIT)
|
|
|
|
{
|
|
|
|
return gimp_config_deserialize_unit (value, prop_spec, scanner);
|
|
|
|
}
|
2016-05-08 22:21:15 +02:00
|
|
|
else if (prop_spec->value_type == G_TYPE_FILE)
|
|
|
|
{
|
|
|
|
return gimp_config_deserialize_file_value (value, prop_spec, scanner);
|
|
|
|
}
|
2021-04-05 21:49:41 +02:00
|
|
|
else if (prop_spec->value_type == GIMP_TYPE_PARASITE)
|
|
|
|
{
|
|
|
|
return gimp_config_deserialize_parasite_value (value, prop_spec, scanner);
|
|
|
|
}
|
2023-07-23 17:32:25 +02:00
|
|
|
else if (prop_spec->value_type == G_TYPE_BYTES)
|
|
|
|
{
|
|
|
|
return gimp_config_deserialize_bytes (value, prop_spec, scanner);
|
|
|
|
}
|
2023-11-15 02:28:34 +01:00
|
|
|
else if (prop_spec->value_type == GEGL_TYPE_COLOR)
|
|
|
|
{
|
|
|
|
return gimp_config_deserialize_color (value, prop_spec, scanner);
|
|
|
|
}
|
2002-05-24 17:42:21 +00:00
|
|
|
|
|
|
|
/* This fallback will only work for value_types that
|
|
|
|
* can be transformed from a string value.
|
|
|
|
*/
|
|
|
|
return gimp_config_deserialize_any (value, prop_spec, scanner);
|
|
|
|
}
|
|
|
|
|
2001-12-09 03:00:32 +00:00
|
|
|
static GTokenType
|
2001-12-08 15:56:40 +00:00
|
|
|
gimp_config_deserialize_fundamental (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
2001-12-09 03:00:32 +00:00
|
|
|
GScanner *scanner)
|
2001-12-08 15:56:40 +00:00
|
|
|
{
|
2001-12-09 03:00:32 +00:00
|
|
|
GTokenType token;
|
2019-07-30 18:36:20 +02:00
|
|
|
GTokenType next_token;
|
2003-02-03 14:37:59 +00:00
|
|
|
GType value_type;
|
|
|
|
gboolean negate = FALSE;
|
2001-12-09 03:00:32 +00:00
|
|
|
|
2003-02-03 14:37:59 +00:00
|
|
|
value_type = G_TYPE_FUNDAMENTAL (prop_spec->value_type);
|
|
|
|
|
|
|
|
switch (value_type)
|
2001-12-08 15:56:40 +00:00
|
|
|
{
|
|
|
|
case G_TYPE_STRING:
|
2001-12-09 03:00:32 +00:00
|
|
|
token = G_TOKEN_STRING;
|
2001-12-08 15:56:40 +00:00
|
|
|
break;
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2001-12-08 15:56:40 +00:00
|
|
|
case G_TYPE_BOOLEAN:
|
2001-12-09 03:00:32 +00:00
|
|
|
token = G_TOKEN_IDENTIFIER;
|
2001-12-08 15:56:40 +00:00
|
|
|
break;
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2001-12-08 15:56:40 +00:00
|
|
|
case G_TYPE_INT:
|
|
|
|
case G_TYPE_LONG:
|
2003-11-14 13:41:16 +00:00
|
|
|
case G_TYPE_INT64:
|
2003-02-03 14:37:59 +00:00
|
|
|
if (g_scanner_peek_next_token (scanner) == '-')
|
|
|
|
{
|
|
|
|
negate = TRUE;
|
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
}
|
|
|
|
/* fallthrough */
|
|
|
|
case G_TYPE_UINT:
|
2001-12-08 15:56:40 +00:00
|
|
|
case G_TYPE_ULONG:
|
2003-11-14 13:41:16 +00:00
|
|
|
case G_TYPE_UINT64:
|
2001-12-09 03:00:32 +00:00
|
|
|
token = G_TOKEN_INT;
|
2001-12-08 15:56:40 +00:00
|
|
|
break;
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2001-12-08 15:56:40 +00:00
|
|
|
case G_TYPE_FLOAT:
|
|
|
|
case G_TYPE_DOUBLE:
|
2003-10-26 00:03:16 +00:00
|
|
|
if (g_scanner_peek_next_token (scanner) == '-')
|
|
|
|
{
|
|
|
|
negate = TRUE;
|
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
}
|
2001-12-09 03:00:32 +00:00
|
|
|
token = G_TOKEN_FLOAT;
|
2001-12-08 15:56:40 +00:00
|
|
|
break;
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2001-12-08 15:56:40 +00:00
|
|
|
default:
|
|
|
|
g_assert_not_reached ();
|
2001-12-09 03:00:32 +00:00
|
|
|
break;
|
2001-11-27 03:52:11 +00:00
|
|
|
}
|
|
|
|
|
2019-07-30 18:36:20 +02:00
|
|
|
next_token = g_scanner_peek_next_token (scanner);
|
|
|
|
|
|
|
|
/* we parse integers into floats too, because g_ascii_dtostr()
|
|
|
|
* serialized whole number without decimal point
|
|
|
|
*/
|
|
|
|
if (next_token != token &&
|
|
|
|
! (token == G_TOKEN_FLOAT && next_token == G_TOKEN_INT))
|
2003-02-03 14:37:59 +00:00
|
|
|
{
|
|
|
|
return token;
|
|
|
|
}
|
2001-11-27 03:52:11 +00:00
|
|
|
|
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
|
2003-02-03 14:37:59 +00:00
|
|
|
switch (value_type)
|
2001-11-27 03:52:11 +00:00
|
|
|
{
|
2001-12-08 15:56:40 +00:00
|
|
|
case G_TYPE_STRING:
|
2001-12-10 18:31:35 +00:00
|
|
|
if (scanner_string_utf8_valid (scanner, prop_spec->name))
|
2020-06-08 22:30:30 +02:00
|
|
|
g_value_set_string (value, scanner->value.v_string);
|
2001-12-10 18:31:35 +00:00
|
|
|
else
|
|
|
|
return G_TOKEN_NONE;
|
2001-12-08 15:56:40 +00:00
|
|
|
break;
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2001-12-08 15:56:40 +00:00
|
|
|
case G_TYPE_BOOLEAN:
|
|
|
|
if (! g_ascii_strcasecmp (scanner->value.v_identifier, "yes") ||
|
|
|
|
! g_ascii_strcasecmp (scanner->value.v_identifier, "true"))
|
|
|
|
g_value_set_boolean (value, TRUE);
|
|
|
|
else if (! g_ascii_strcasecmp (scanner->value.v_identifier, "no") ||
|
|
|
|
! g_ascii_strcasecmp (scanner->value.v_identifier, "false"))
|
|
|
|
g_value_set_boolean (value, FALSE);
|
2001-11-27 03:52:11 +00:00
|
|
|
else
|
2001-12-08 15:56:40 +00:00
|
|
|
{
|
2003-09-16 13:12:50 +00:00
|
|
|
g_scanner_error
|
|
|
|
(scanner,
|
2002-06-09 12:53:42 +00:00
|
|
|
/* please don't translate 'yes' and 'no' */
|
2003-09-16 13:12:50 +00:00
|
|
|
_("expected 'yes' or 'no' for boolean token %s, got '%s'"),
|
2001-12-08 15:56:40 +00:00
|
|
|
prop_spec->name, scanner->value.v_identifier);
|
2001-12-09 03:00:32 +00:00
|
|
|
return G_TOKEN_NONE;
|
2001-12-08 15:56:40 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case G_TYPE_INT:
|
2003-02-03 14:37:59 +00:00
|
|
|
g_value_set_int (value, (negate ?
|
2019-11-03 13:38:24 +02:00
|
|
|
- (gint) scanner->value.v_int64 :
|
|
|
|
(gint) scanner->value.v_int64));
|
2001-12-08 15:56:40 +00:00
|
|
|
break;
|
|
|
|
case G_TYPE_UINT:
|
2003-11-14 13:41:16 +00:00
|
|
|
g_value_set_uint (value, scanner->value.v_int64);
|
2001-12-08 15:56:40 +00:00
|
|
|
break;
|
2003-11-14 13:41:16 +00:00
|
|
|
|
2001-12-08 15:56:40 +00:00
|
|
|
case G_TYPE_LONG:
|
2003-02-03 14:37:59 +00:00
|
|
|
g_value_set_long (value, (negate ?
|
2019-11-03 13:38:24 +02:00
|
|
|
- (glong) scanner->value.v_int64 :
|
|
|
|
(glong) scanner->value.v_int64));
|
2001-12-08 15:56:40 +00:00
|
|
|
break;
|
|
|
|
case G_TYPE_ULONG:
|
2003-11-14 13:41:16 +00:00
|
|
|
g_value_set_ulong (value, scanner->value.v_int64);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case G_TYPE_INT64:
|
|
|
|
g_value_set_int64 (value, (negate ?
|
2019-11-03 13:38:24 +02:00
|
|
|
- (gint64) scanner->value.v_int64 :
|
|
|
|
(gint64) scanner->value.v_int64));
|
2002-05-27 14:04:21 +00:00
|
|
|
break;
|
2003-11-14 13:41:16 +00:00
|
|
|
case G_TYPE_UINT64:
|
|
|
|
g_value_set_uint64 (value, scanner->value.v_int64);
|
|
|
|
break;
|
|
|
|
|
2001-12-08 15:56:40 +00:00
|
|
|
case G_TYPE_FLOAT:
|
2019-07-30 18:36:20 +02:00
|
|
|
if (next_token == G_TOKEN_FLOAT)
|
|
|
|
g_value_set_float (value, negate ?
|
app, libgimp*, pdb, plug-ins: rename various public API name s/float/double/.
Several types functions were using the wording "float" historically to
mean double-precision, e.g. the float array type (which was in fact a
double array). Or the scanner function gimp_scanner_parse_float() was in
fact returning a double value. What if we wanted someday to actually add
float (usually this naming means in C the single-precision IEEE 754
floating point representation) support? How would we name this?
Now technically it's not entirely wrong (a double is still a floating
point). So I've been wondering if that is because maybe we never planned
to have float and double precision may be good enough for all usage in a
plug-in API (which doesn't have to be as generic so the higher precision
is enough)? But how can we be sure? Also we already had some functions
using the wording double (e.g. gimp_procedure_add_double_argument()), so
let's just go the safe route and use the accurate wording.
The additional change in PDB is internal, but there too, I was also
finding very confusing that we were naming double-precision float as
'float' type. So I took the opportunity to update this. It doesn't
change any signature.
In fact the whole commit doesn't change any type or code logic, only
naming, except for one bug fix in the middle which I encountered while
renaming: in gimp_scanner_parse_deprecated_color(), I discovered a
hidden bug in scanning (color-hsv*) values, which was mistakenly using a
double type for an array of float.
2024-11-02 14:03:37 +01:00
|
|
|
- (gfloat) scanner->value.v_float :
|
|
|
|
(gfloat) scanner->value.v_float);
|
2019-07-30 18:36:20 +02:00
|
|
|
else
|
|
|
|
g_value_set_float (value, negate ?
|
2019-11-03 13:38:24 +02:00
|
|
|
- (gfloat) scanner->value.v_int :
|
|
|
|
(gfloat) scanner->value.v_int);
|
2001-12-08 15:56:40 +00:00
|
|
|
break;
|
2019-07-30 18:36:20 +02:00
|
|
|
|
2001-12-08 15:56:40 +00:00
|
|
|
case G_TYPE_DOUBLE:
|
2019-07-30 18:36:20 +02:00
|
|
|
if (next_token == G_TOKEN_FLOAT)
|
|
|
|
g_value_set_double (value, negate ?
|
2019-11-03 13:38:24 +02:00
|
|
|
- scanner->value.v_float:
|
|
|
|
scanner->value.v_float);
|
2019-07-30 18:36:20 +02:00
|
|
|
else
|
|
|
|
g_value_set_double (value, negate ?
|
2019-11-03 13:38:24 +02:00
|
|
|
- (gdouble) scanner->value.v_int:
|
|
|
|
(gdouble) scanner->value.v_int);
|
2001-12-08 15:56:40 +00:00
|
|
|
break;
|
2002-05-27 14:04:21 +00:00
|
|
|
|
2001-12-08 15:56:40 +00:00
|
|
|
default:
|
2001-12-09 03:00:32 +00:00
|
|
|
g_assert_not_reached ();
|
|
|
|
break;
|
2001-11-27 03:52:11 +00:00
|
|
|
}
|
2001-12-08 15:56:40 +00:00
|
|
|
|
2001-12-09 03:00:32 +00:00
|
|
|
return G_TOKEN_RIGHT_PAREN;
|
2001-12-08 15:56:40 +00:00
|
|
|
}
|
|
|
|
|
2001-12-09 03:00:32 +00:00
|
|
|
static GTokenType
|
2001-12-08 15:56:40 +00:00
|
|
|
gimp_config_deserialize_enum (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
2001-12-09 03:00:32 +00:00
|
|
|
GScanner *scanner)
|
2001-12-08 15:56:40 +00:00
|
|
|
{
|
|
|
|
GEnumClass *enum_class;
|
|
|
|
GEnumValue *enum_value;
|
|
|
|
|
|
|
|
enum_class = g_type_class_peek (G_VALUE_TYPE (value));
|
2002-11-18 18:31:49 +00:00
|
|
|
|
|
|
|
switch (g_scanner_peek_next_token (scanner))
|
2001-12-08 03:35:38 +00:00
|
|
|
{
|
2002-11-18 18:31:49 +00:00
|
|
|
case G_TOKEN_IDENTIFIER:
|
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
|
2004-07-08 00:09:41 +00:00
|
|
|
enum_value = g_enum_get_value_by_nick (enum_class,
|
2006-04-12 10:53:28 +00:00
|
|
|
scanner->value.v_identifier);
|
2017-01-06 23:09:39 +01:00
|
|
|
if (! enum_value)
|
2006-04-12 10:53:28 +00:00
|
|
|
enum_value = g_enum_get_value_by_name (enum_class,
|
|
|
|
scanner->value.v_identifier);
|
2017-01-06 23:09:39 +01:00
|
|
|
if (! enum_value)
|
|
|
|
{
|
|
|
|
/* if the value was not found, check if we have a compat
|
|
|
|
* enum to find the ideitifier
|
|
|
|
*/
|
|
|
|
GQuark quark = g_quark_from_static_string ("gimp-compat-enum");
|
2017-01-08 20:16:47 +01:00
|
|
|
GType compat_type = (GType) g_type_get_qdata (G_VALUE_TYPE (value),
|
|
|
|
quark);
|
2017-01-06 23:09:39 +01:00
|
|
|
|
|
|
|
if (compat_type)
|
|
|
|
{
|
|
|
|
GEnumClass *compat_class = g_type_class_ref (compat_type);
|
|
|
|
|
|
|
|
enum_value = g_enum_get_value_by_nick (compat_class,
|
|
|
|
scanner->value.v_identifier);
|
|
|
|
if (! enum_value)
|
|
|
|
enum_value = g_enum_get_value_by_name (compat_class,
|
|
|
|
scanner->value.v_identifier);
|
|
|
|
|
|
|
|
/* finally, if we found a compat value, make sure the
|
|
|
|
* same value exists in the original enum
|
|
|
|
*/
|
|
|
|
if (enum_value)
|
|
|
|
enum_value = g_enum_get_value (enum_class, enum_value->value);
|
|
|
|
|
|
|
|
g_type_class_unref (compat_class);
|
|
|
|
}
|
|
|
|
}
|
2002-11-18 18:31:49 +00:00
|
|
|
|
2017-01-06 23:09:39 +01:00
|
|
|
if (! enum_value)
|
2006-04-12 10:53:28 +00:00
|
|
|
{
|
|
|
|
g_scanner_error (scanner,
|
|
|
|
_("invalid value '%s' for token %s"),
|
|
|
|
scanner->value.v_identifier, prop_spec->name);
|
|
|
|
return G_TOKEN_NONE;
|
|
|
|
}
|
2002-11-18 18:31:49 +00:00
|
|
|
break;
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2002-11-18 18:31:49 +00:00
|
|
|
case G_TOKEN_INT:
|
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
|
2003-11-14 13:41:16 +00:00
|
|
|
enum_value = g_enum_get_value (enum_class,
|
|
|
|
(gint) scanner->value.v_int64);
|
2002-11-18 18:31:49 +00:00
|
|
|
|
2017-01-06 23:09:39 +01:00
|
|
|
if (! enum_value)
|
2006-04-12 10:53:28 +00:00
|
|
|
{
|
|
|
|
g_scanner_error (scanner,
|
|
|
|
_("invalid value '%ld' for token %s"),
|
|
|
|
(glong) scanner->value.v_int64, prop_spec->name);
|
|
|
|
return G_TOKEN_NONE;
|
|
|
|
}
|
2002-11-18 18:31:49 +00:00
|
|
|
break;
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2002-11-18 18:31:49 +00:00
|
|
|
default:
|
|
|
|
return G_TOKEN_IDENTIFIER;
|
2001-12-08 15:56:40 +00:00
|
|
|
}
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2001-12-08 15:56:40 +00:00
|
|
|
g_value_set_enum (value, enum_value->value);
|
|
|
|
|
2001-12-09 03:00:32 +00:00
|
|
|
return G_TOKEN_RIGHT_PAREN;
|
2001-12-08 15:56:40 +00:00
|
|
|
}
|
|
|
|
|
2001-12-09 03:00:32 +00:00
|
|
|
static GTokenType
|
|
|
|
gimp_config_deserialize_memsize (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner)
|
|
|
|
{
|
2004-07-27 16:39:00 +00:00
|
|
|
gchar *orig_cset_first = scanner->config->cset_identifier_first;
|
|
|
|
gchar *orig_cset_nth = scanner->config->cset_identifier_nth;
|
|
|
|
guint64 memsize;
|
2001-12-09 03:00:32 +00:00
|
|
|
|
|
|
|
scanner->config->cset_identifier_first = G_CSET_DIGITS;
|
|
|
|
scanner->config->cset_identifier_nth = G_CSET_DIGITS "gGmMkKbB";
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2002-05-29 09:20:56 +00:00
|
|
|
if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
|
|
|
|
return G_TOKEN_IDENTIFIER;
|
2001-12-09 03:00:32 +00:00
|
|
|
|
2002-05-29 09:20:56 +00:00
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
|
|
|
|
scanner->config->cset_identifier_first = orig_cset_first;
|
|
|
|
scanner->config->cset_identifier_nth = orig_cset_nth;
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2004-07-27 16:39:00 +00:00
|
|
|
if (! gimp_memsize_deserialize (scanner->value.v_identifier, &memsize))
|
2002-05-29 09:20:56 +00:00
|
|
|
return G_TOKEN_NONE;
|
2004-07-27 16:39:00 +00:00
|
|
|
|
|
|
|
g_value_set_uint64 (value, memsize);
|
|
|
|
|
|
|
|
return G_TOKEN_RIGHT_PAREN;
|
2001-12-09 03:00:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static GTokenType
|
|
|
|
gimp_config_deserialize_path (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner)
|
|
|
|
{
|
2003-02-28 17:01:13 +00:00
|
|
|
GError *error = NULL;
|
2001-12-10 18:31:35 +00:00
|
|
|
|
2001-12-09 03:00:32 +00:00
|
|
|
if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
|
|
|
|
return G_TOKEN_STRING;
|
|
|
|
|
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
|
2001-12-10 18:31:35 +00:00
|
|
|
if (!scanner_string_utf8_valid (scanner, prop_spec->name))
|
|
|
|
return G_TOKEN_NONE;
|
|
|
|
|
2002-12-29 18:58:24 +00:00
|
|
|
if (scanner->value.v_string)
|
|
|
|
{
|
|
|
|
/* Check if the string can be expanded
|
2003-01-26 01:20:20 +00:00
|
|
|
* and converted to the filesystem encoding.
|
2002-12-29 18:58:24 +00:00
|
|
|
*/
|
|
|
|
gchar *expand = gimp_config_path_expand (scanner->value.v_string,
|
|
|
|
TRUE, &error);
|
2001-12-09 03:00:32 +00:00
|
|
|
|
2002-12-29 18:58:24 +00:00
|
|
|
if (!expand)
|
|
|
|
{
|
|
|
|
g_scanner_error (scanner,
|
2003-11-14 15:33:40 +00:00
|
|
|
_("while parsing token '%s': %s"),
|
2002-12-29 18:58:24 +00:00
|
|
|
prop_spec->name, error->message);
|
|
|
|
g_error_free (error);
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2002-12-29 18:58:24 +00:00
|
|
|
return G_TOKEN_NONE;
|
|
|
|
}
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2002-12-29 18:58:24 +00:00
|
|
|
g_free (expand);
|
2001-12-10 18:31:35 +00:00
|
|
|
|
2002-12-29 18:58:24 +00:00
|
|
|
g_value_set_static_string (value, scanner->value.v_string);
|
|
|
|
}
|
2001-12-09 03:00:32 +00:00
|
|
|
|
|
|
|
return G_TOKEN_RIGHT_PAREN;
|
|
|
|
}
|
|
|
|
|
2003-07-07 16:22:45 +00:00
|
|
|
static GTokenType
|
|
|
|
gimp_config_deserialize_matrix2 (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner)
|
|
|
|
{
|
|
|
|
GimpMatrix2 matrix;
|
|
|
|
|
|
|
|
if (! gimp_scanner_parse_matrix2 (scanner, &matrix))
|
|
|
|
return G_TOKEN_NONE;
|
|
|
|
|
|
|
|
g_value_set_boxed (value, &matrix);
|
|
|
|
|
|
|
|
return G_TOKEN_RIGHT_PAREN;
|
|
|
|
}
|
|
|
|
|
2003-02-28 17:01:13 +00:00
|
|
|
static GTokenType
|
|
|
|
gimp_config_deserialize_object (GValue *value,
|
2003-10-11 14:30:18 +00:00
|
|
|
GimpConfig *config,
|
2003-02-28 17:01:13 +00:00
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner,
|
|
|
|
gint nest_level)
|
|
|
|
{
|
2003-10-11 14:30:18 +00:00
|
|
|
GimpConfigInterface *config_iface;
|
|
|
|
GimpConfig *prop_object;
|
2023-09-11 18:08:04 +02:00
|
|
|
GType type;
|
2003-02-28 17:01:13 +00:00
|
|
|
|
2003-10-11 14:30:18 +00:00
|
|
|
g_object_get_property (G_OBJECT (config), prop_spec->name, value);
|
2003-02-28 17:01:13 +00:00
|
|
|
|
|
|
|
prop_object = g_value_get_object (value);
|
|
|
|
|
2023-09-11 18:08:04 +02:00
|
|
|
/* if the object property is not GIMP_CONFIG_PARAM_AGGREGATE, read
|
|
|
|
* the type of the object.
|
|
|
|
*/
|
|
|
|
if (! (prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE))
|
2004-06-16 18:14:44 +00:00
|
|
|
{
|
2023-09-11 18:08:04 +02:00
|
|
|
gchar *type_name;
|
2004-06-16 18:14:44 +00:00
|
|
|
|
2023-09-11 18:08:04 +02:00
|
|
|
if (! gimp_scanner_parse_string (scanner, &type_name))
|
|
|
|
return G_TOKEN_STRING;
|
2019-06-20 15:01:29 +02:00
|
|
|
|
2023-09-11 18:08:04 +02:00
|
|
|
if (! (type_name && *type_name))
|
|
|
|
{
|
|
|
|
g_scanner_error (scanner, "Type name is empty");
|
2004-06-16 18:14:44 +00:00
|
|
|
g_free (type_name);
|
2023-09-11 18:08:04 +02:00
|
|
|
return G_TOKEN_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = g_type_from_name (type_name);
|
|
|
|
g_free (type_name);
|
2004-06-16 18:14:44 +00:00
|
|
|
|
2023-09-11 18:08:04 +02:00
|
|
|
if (! g_type_is_a (type, prop_spec->value_type))
|
|
|
|
return G_TOKEN_STRING;
|
|
|
|
}
|
2004-06-16 18:14:44 +00:00
|
|
|
|
2023-09-11 18:08:04 +02:00
|
|
|
if (! prop_object)
|
|
|
|
{
|
|
|
|
/* if the object property is not GIMP_CONFIG_PARAM_AGGREGATE,
|
|
|
|
* create the object.
|
|
|
|
*/
|
|
|
|
if (! (prop_spec->flags & GIMP_CONFIG_PARAM_AGGREGATE))
|
|
|
|
{
|
2004-06-16 18:14:44 +00:00
|
|
|
prop_object = g_object_new (type, NULL);
|
|
|
|
|
|
|
|
g_value_take_object (value, prop_object);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return G_TOKEN_RIGHT_PAREN;
|
|
|
|
}
|
|
|
|
}
|
2003-02-28 17:01:13 +00:00
|
|
|
|
2020-05-10 15:23:55 +02:00
|
|
|
config_iface = GIMP_CONFIG_GET_IFACE (prop_object);
|
2003-02-28 17:01:13 +00:00
|
|
|
|
2003-10-11 14:30:18 +00:00
|
|
|
if (! config_iface)
|
2003-02-28 17:01:13 +00:00
|
|
|
return gimp_config_deserialize_any (value, prop_spec, scanner);
|
2003-09-16 13:12:50 +00:00
|
|
|
|
2023-07-20 01:48:59 +02:00
|
|
|
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;
|
|
|
|
}
|
2003-02-28 17:01:13 +00:00
|
|
|
|
|
|
|
return G_TOKEN_RIGHT_PAREN;
|
|
|
|
}
|
|
|
|
|
2002-05-24 17:42:21 +00:00
|
|
|
static GTokenType
|
|
|
|
gimp_config_deserialize_value_array (GValue *value,
|
2003-10-11 14:30:18 +00:00
|
|
|
GimpConfig *config,
|
2002-05-24 17:42:21 +00:00
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner)
|
|
|
|
{
|
2012-05-04 00:50:23 +02:00
|
|
|
GimpParamSpecValueArray *array_spec;
|
|
|
|
GimpValueArray *array;
|
2016-03-26 15:59:26 +01:00
|
|
|
GValue array_value = G_VALUE_INIT;
|
2012-05-04 00:50:23 +02:00
|
|
|
gint n_values;
|
|
|
|
GTokenType token;
|
|
|
|
gint i;
|
2002-05-24 17:42:21 +00:00
|
|
|
|
2012-05-04 00:50:23 +02:00
|
|
|
array_spec = GIMP_PARAM_SPEC_VALUE_ARRAY (prop_spec);
|
2002-05-24 17:42:21 +00:00
|
|
|
|
2002-05-31 13:58:18 +00:00
|
|
|
if (! gimp_scanner_parse_int (scanner, &n_values))
|
2002-05-24 17:42:21 +00:00
|
|
|
return G_TOKEN_INT;
|
|
|
|
|
2012-05-04 00:50:23 +02:00
|
|
|
array = gimp_value_array_new (n_values);
|
2002-05-24 17:42:21 +00:00
|
|
|
|
|
|
|
for (i = 0; i < n_values; i++)
|
|
|
|
{
|
|
|
|
g_value_init (&array_value, array_spec->element_spec->value_type);
|
|
|
|
|
|
|
|
token = gimp_config_deserialize_value (&array_value,
|
2003-10-11 14:30:18 +00:00
|
|
|
config,
|
2002-05-24 17:42:21 +00:00
|
|
|
array_spec->element_spec,
|
|
|
|
scanner);
|
|
|
|
|
|
|
|
if (token == G_TOKEN_RIGHT_PAREN)
|
2012-05-04 00:50:23 +02:00
|
|
|
gimp_value_array_append (array, &array_value);
|
2002-05-24 17:42:21 +00:00
|
|
|
|
|
|
|
g_value_unset (&array_value);
|
|
|
|
|
|
|
|
if (token != G_TOKEN_RIGHT_PAREN)
|
2021-08-21 19:19:23 +02:00
|
|
|
{
|
|
|
|
gimp_value_array_unref (array);
|
|
|
|
return token;
|
|
|
|
}
|
2002-05-24 17:42:21 +00:00
|
|
|
}
|
|
|
|
|
2004-05-11 17:19:24 +00:00
|
|
|
g_value_take_boxed (value, array);
|
2002-05-28 16:41:56 +00:00
|
|
|
|
2002-05-24 17:42:21 +00:00
|
|
|
return G_TOKEN_RIGHT_PAREN;
|
|
|
|
}
|
|
|
|
|
2024-10-17 22:08:16 +02:00
|
|
|
/**
|
|
|
|
* gimp_config_deserialize_strv:
|
|
|
|
* @value: destination #GValue to hold a #GStrv
|
|
|
|
* @scanner: #GScanner positioned in serialization stream
|
|
|
|
*
|
|
|
|
* Sets @value to new #GStrv.
|
|
|
|
* Scans i.e. consumes serialization to fill the GStrv.
|
|
|
|
*
|
|
|
|
* Requires @value to be initialized to hold type #G_TYPE_BOXED.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* G_TOKEN_RIGHT_PAREN on success.
|
|
|
|
* G_TOKEN_INT on failure to scan length.
|
|
|
|
* G_TOKEN_STRING on failure to scan enough quoted strings.
|
|
|
|
*
|
|
|
|
* On failure, the value in @value is not touched and could be NULL.
|
|
|
|
*
|
|
|
|
* Since: 3.0
|
|
|
|
**/
|
|
|
|
static GTokenType
|
|
|
|
gimp_config_deserialize_strv (GValue *value,
|
|
|
|
GScanner *scanner)
|
|
|
|
{
|
|
|
|
gint n_values;
|
|
|
|
GTokenType result_token = G_TOKEN_RIGHT_PAREN;
|
|
|
|
GStrvBuilder *builder;
|
|
|
|
|
|
|
|
/* Scan length of array. */
|
|
|
|
if (! gimp_scanner_parse_int (scanner, &n_values))
|
|
|
|
return G_TOKEN_INT;
|
|
|
|
|
|
|
|
builder = g_strv_builder_new ();
|
|
|
|
|
|
|
|
for (gint i = 0; i < n_values; i++)
|
|
|
|
{
|
|
|
|
gchar *scanned_string;
|
|
|
|
|
|
|
|
if (! gimp_scanner_parse_string (scanner, &scanned_string))
|
|
|
|
{
|
|
|
|
/* Error, missing a string. */
|
|
|
|
result_token = G_TOKEN_STRING;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_strv_builder_add (builder, scanned_string ? scanned_string : "");
|
|
|
|
g_free (scanned_string);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* assert result_token is G_TOKEN_RIGHT_PAREN OR G_TOKEN_STRING */
|
|
|
|
if (result_token == G_TOKEN_RIGHT_PAREN)
|
|
|
|
{
|
|
|
|
GStrv gstrv;
|
|
|
|
|
|
|
|
/* Allocate new GStrv. */
|
|
|
|
gstrv = g_strv_builder_end (builder);
|
|
|
|
/* Transfer ownership of the array and all strings it points to. */
|
|
|
|
g_value_take_boxed (value, gstrv);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* No GStrv to unref. */
|
|
|
|
g_scanner_error (scanner, "Missing string.");
|
|
|
|
}
|
|
|
|
|
|
|
|
g_strv_builder_unref (builder);
|
|
|
|
|
|
|
|
return result_token;
|
|
|
|
}
|
|
|
|
|
2024-10-24 17:43:09 +02:00
|
|
|
static GTokenType
|
|
|
|
gimp_config_deserialize_array (GValue *value,
|
|
|
|
GScanner *scanner)
|
|
|
|
{
|
|
|
|
gint32 *values;
|
|
|
|
gint n_values;
|
|
|
|
GTokenType result_token = G_TOKEN_RIGHT_PAREN;
|
|
|
|
|
|
|
|
if (! gimp_scanner_parse_int (scanner, &n_values))
|
|
|
|
return G_TOKEN_INT;
|
|
|
|
|
2024-10-24 22:18:20 +02:00
|
|
|
if (GIMP_VALUE_HOLDS_INT32_ARRAY (value))
|
|
|
|
values = g_new0 (gint32, n_values);
|
app, libgimp*, pdb, plug-ins: rename various public API name s/float/double/.
Several types functions were using the wording "float" historically to
mean double-precision, e.g. the float array type (which was in fact a
double array). Or the scanner function gimp_scanner_parse_float() was in
fact returning a double value. What if we wanted someday to actually add
float (usually this naming means in C the single-precision IEEE 754
floating point representation) support? How would we name this?
Now technically it's not entirely wrong (a double is still a floating
point). So I've been wondering if that is because maybe we never planned
to have float and double precision may be good enough for all usage in a
plug-in API (which doesn't have to be as generic so the higher precision
is enough)? But how can we be sure? Also we already had some functions
using the wording double (e.g. gimp_procedure_add_double_argument()), so
let's just go the safe route and use the accurate wording.
The additional change in PDB is internal, but there too, I was also
finding very confusing that we were naming double-precision float as
'float' type. So I took the opportunity to update this. It doesn't
change any signature.
In fact the whole commit doesn't change any type or code logic, only
naming, except for one bug fix in the middle which I encountered while
renaming: in gimp_scanner_parse_deprecated_color(), I discovered a
hidden bug in scanning (color-hsv*) values, which was mistakenly using a
double type for an array of float.
2024-11-02 14:03:37 +01:00
|
|
|
else /* GIMP_VALUE_HOLDS_DOUBLE_ARRAY (value) */
|
2024-10-24 22:18:20 +02:00
|
|
|
values = (gint32 *) g_new0 (gdouble, n_values);
|
2024-10-24 17:43:09 +02:00
|
|
|
|
|
|
|
for (gint i = 0; i < n_values; i++)
|
|
|
|
{
|
2024-10-24 22:18:20 +02:00
|
|
|
if (GIMP_VALUE_HOLDS_INT32_ARRAY (value))
|
2024-10-24 17:43:09 +02:00
|
|
|
{
|
2024-10-24 22:18:20 +02:00
|
|
|
gint value;
|
|
|
|
|
|
|
|
if (! gimp_scanner_parse_int (scanner, &value))
|
|
|
|
{
|
|
|
|
result_token = G_TOKEN_INT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
values[i] = value;
|
2024-10-24 17:43:09 +02:00
|
|
|
}
|
2024-10-24 22:18:20 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
gdouble value;
|
|
|
|
|
app, libgimp*, pdb, plug-ins: rename various public API name s/float/double/.
Several types functions were using the wording "float" historically to
mean double-precision, e.g. the float array type (which was in fact a
double array). Or the scanner function gimp_scanner_parse_float() was in
fact returning a double value. What if we wanted someday to actually add
float (usually this naming means in C the single-precision IEEE 754
floating point representation) support? How would we name this?
Now technically it's not entirely wrong (a double is still a floating
point). So I've been wondering if that is because maybe we never planned
to have float and double precision may be good enough for all usage in a
plug-in API (which doesn't have to be as generic so the higher precision
is enough)? But how can we be sure? Also we already had some functions
using the wording double (e.g. gimp_procedure_add_double_argument()), so
let's just go the safe route and use the accurate wording.
The additional change in PDB is internal, but there too, I was also
finding very confusing that we were naming double-precision float as
'float' type. So I took the opportunity to update this. It doesn't
change any signature.
In fact the whole commit doesn't change any type or code logic, only
naming, except for one bug fix in the middle which I encountered while
renaming: in gimp_scanner_parse_deprecated_color(), I discovered a
hidden bug in scanning (color-hsv*) values, which was mistakenly using a
double type for an array of float.
2024-11-02 14:03:37 +01:00
|
|
|
if (! gimp_scanner_parse_double (scanner, &value))
|
2024-10-24 22:18:20 +02:00
|
|
|
{
|
|
|
|
result_token = G_TOKEN_FLOAT;
|
|
|
|
break;
|
|
|
|
}
|
2024-10-24 17:43:09 +02:00
|
|
|
|
2024-10-24 22:18:20 +02:00
|
|
|
((gdouble *) values)[i] = value;
|
|
|
|
}
|
2024-10-24 17:43:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (result_token == G_TOKEN_RIGHT_PAREN)
|
|
|
|
{
|
2024-10-24 22:18:20 +02:00
|
|
|
if (GIMP_VALUE_HOLDS_INT32_ARRAY (value))
|
|
|
|
gimp_value_take_int32_array (value, values, n_values);
|
|
|
|
else
|
app, libgimp*, pdb, plug-ins: rename various public API name s/float/double/.
Several types functions were using the wording "float" historically to
mean double-precision, e.g. the float array type (which was in fact a
double array). Or the scanner function gimp_scanner_parse_float() was in
fact returning a double value. What if we wanted someday to actually add
float (usually this naming means in C the single-precision IEEE 754
floating point representation) support? How would we name this?
Now technically it's not entirely wrong (a double is still a floating
point). So I've been wondering if that is because maybe we never planned
to have float and double precision may be good enough for all usage in a
plug-in API (which doesn't have to be as generic so the higher precision
is enough)? But how can we be sure? Also we already had some functions
using the wording double (e.g. gimp_procedure_add_double_argument()), so
let's just go the safe route and use the accurate wording.
The additional change in PDB is internal, but there too, I was also
finding very confusing that we were naming double-precision float as
'float' type. So I took the opportunity to update this. It doesn't
change any signature.
In fact the whole commit doesn't change any type or code logic, only
naming, except for one bug fix in the middle which I encountered while
renaming: in gimp_scanner_parse_deprecated_color(), I discovered a
hidden bug in scanning (color-hsv*) values, which was mistakenly using a
double type for an array of float.
2024-11-02 14:03:37 +01:00
|
|
|
gimp_value_take_double_array (value, (gdouble *) values, n_values);
|
2024-10-24 17:43:09 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_scanner_error (scanner, "Missing value.");
|
|
|
|
}
|
|
|
|
|
|
|
|
return result_token;
|
|
|
|
}
|
|
|
|
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-25 20:55:21 +02:00
|
|
|
static GimpUnit *
|
|
|
|
gimp_config_get_unit_from_identifier (const gchar *identifier)
|
|
|
|
{
|
|
|
|
GimpUnit *unit;
|
|
|
|
|
|
|
|
unit = gimp_unit_get_by_id (GIMP_UNIT_PIXEL);
|
|
|
|
for (gint i = GIMP_UNIT_PIXEL; unit; i++)
|
|
|
|
{
|
Issue #434: remove broken plural support for GimpUnit.
Rather than trying to implement full i18n plural support, we just remove
this failed attempt from the past. The fact is that to get proper
support, we'd basically need to reimplement a Gettext-like plural
definition syntax within our API, then ask people to write down this
plural definition for their language, then to write every plural form…
all this for custom units which only them will ever see!
Moreover code investigation shows that the singular form was simply
never used, and the plural form was always used (whatever the actual
unit value displayed).
As for the "identifier", this was a text which was never shown anywhere
(except in the unit editor) and for all built-in units, as well as
default unitrc units, it was equivalent to the English plural value.
So we now just have a unique name which is the "long label" to be used
everywhere in the GUI, and abbreviation will be basically the "short
label". That's it. No useless (or worse, not actually usable because it
was not generic internationalization) values anymore!
2024-08-05 16:02:47 +02:00
|
|
|
if (g_strcmp0 (identifier, gimp_unit_get_name (unit)) == 0)
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-25 20:55:21 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
unit = gimp_unit_get_by_id (i);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unit == NULL && g_strcmp0 (identifier, "percent") == 0)
|
|
|
|
unit = gimp_unit_percent ();
|
|
|
|
|
|
|
|
/* XXX This may return NULL, especially for user-defined units which
|
|
|
|
* may have disappeared from one session to another. Should we return
|
|
|
|
* some default unit then?
|
|
|
|
*/
|
|
|
|
|
|
|
|
return unit;
|
|
|
|
}
|
|
|
|
|
2012-10-04 23:54:27 +02:00
|
|
|
/* This function is entirely sick, so is our method of serializing
|
|
|
|
* units, which we write out as (unit foo bar) instead of
|
|
|
|
* (unit "foo bar"). The assumption that caused this shit was that a
|
|
|
|
* unit's "identifier" is really an identifier in the C-ish sense,
|
|
|
|
* when in fact it's just a random user entered string.
|
|
|
|
*
|
|
|
|
* Here, we try to parse at least the default units shipped with gimp,
|
|
|
|
* and we add code to parse (unit "foo bar") in order to be compatible
|
|
|
|
* with future correct unit serializing.
|
|
|
|
*/
|
|
|
|
static GTokenType
|
|
|
|
gimp_config_deserialize_unit (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner)
|
|
|
|
{
|
|
|
|
gchar *old_cset_skip_characters;
|
|
|
|
gchar *old_cset_identifier_first;
|
|
|
|
gchar *old_cset_identifier_nth;
|
|
|
|
GString *buffer;
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-25 20:55:21 +02:00
|
|
|
GimpUnit *unit;
|
2012-10-04 23:54:27 +02:00
|
|
|
GTokenType token;
|
|
|
|
|
|
|
|
/* parse the next token *before* reconfiguring the scanner, so it
|
|
|
|
* skips whitespace first
|
|
|
|
*/
|
|
|
|
token = g_scanner_peek_next_token (scanner);
|
|
|
|
|
|
|
|
if (token == G_TOKEN_STRING)
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-25 20:55:21 +02:00
|
|
|
{
|
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
unit = gimp_config_get_unit_from_identifier (scanner->value.v_string);
|
|
|
|
g_value_set_object (value, unit);
|
|
|
|
|
|
|
|
return G_TOKEN_RIGHT_PAREN;
|
|
|
|
}
|
2012-10-04 23:54:27 +02:00
|
|
|
|
|
|
|
old_cset_skip_characters = scanner->config->cset_skip_characters;
|
|
|
|
old_cset_identifier_first = scanner->config->cset_identifier_first;
|
|
|
|
old_cset_identifier_nth = scanner->config->cset_identifier_nth;
|
|
|
|
|
|
|
|
scanner->config->cset_skip_characters = "";
|
|
|
|
scanner->config->cset_identifier_first = ( G_CSET_a_2_z G_CSET_A_2_Z "." );
|
|
|
|
scanner->config->cset_identifier_nth = ( G_CSET_a_2_z G_CSET_A_2_Z
|
|
|
|
G_CSET_DIGITS "-_." );
|
|
|
|
|
|
|
|
buffer = g_string_new ("");
|
|
|
|
|
|
|
|
while (g_scanner_peek_next_token (scanner) != G_TOKEN_RIGHT_PAREN)
|
|
|
|
{
|
|
|
|
token = g_scanner_peek_next_token (scanner);
|
|
|
|
|
|
|
|
if (token == G_TOKEN_IDENTIFIER)
|
|
|
|
{
|
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
g_string_append (buffer, scanner->value.v_identifier);
|
|
|
|
}
|
|
|
|
else if (token == G_TOKEN_CHAR)
|
|
|
|
{
|
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
g_string_append_c (buffer, scanner->value.v_char);
|
|
|
|
}
|
|
|
|
else if (token == ' ')
|
|
|
|
{
|
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
g_string_append_c (buffer, token);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
token = G_TOKEN_IDENTIFIER;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-25 20:55:21 +02:00
|
|
|
unit = gimp_config_get_unit_from_identifier (buffer->str);
|
|
|
|
g_value_set_object (value, unit);
|
2012-10-04 23:54:27 +02:00
|
|
|
|
|
|
|
token = G_TOKEN_RIGHT_PAREN;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
|
|
|
g_string_free (buffer, TRUE);
|
|
|
|
|
|
|
|
scanner->config->cset_skip_characters = old_cset_skip_characters;
|
|
|
|
scanner->config->cset_identifier_first = old_cset_identifier_first;
|
|
|
|
scanner->config->cset_identifier_nth = old_cset_identifier_nth;
|
|
|
|
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
2016-05-08 22:21:15 +02:00
|
|
|
static GTokenType
|
|
|
|
gimp_config_deserialize_file_value (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner)
|
|
|
|
{
|
|
|
|
GTokenType token;
|
|
|
|
|
|
|
|
token = g_scanner_peek_next_token (scanner);
|
|
|
|
|
|
|
|
if (token != G_TOKEN_IDENTIFIER &&
|
|
|
|
token != G_TOKEN_STRING)
|
|
|
|
{
|
|
|
|
return G_TOKEN_STRING;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
|
|
|
|
if (token == G_TOKEN_IDENTIFIER)
|
|
|
|
{
|
|
|
|
/* this is supposed to parse a literal "NULL" only, but so what... */
|
|
|
|
g_value_set_object (value, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-10-17 18:55:50 +02:00
|
|
|
gchar *path = gimp_config_path_expand (scanner->value.v_string, TRUE,
|
|
|
|
NULL);
|
2016-05-08 22:21:15 +02:00
|
|
|
|
2016-10-17 18:55:50 +02:00
|
|
|
if (path)
|
|
|
|
{
|
|
|
|
GFile *file = g_file_new_for_path (path);
|
|
|
|
|
|
|
|
g_value_take_object (value, file);
|
|
|
|
g_free (path);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_value_set_object (value, NULL);
|
|
|
|
}
|
2016-05-08 22:21:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return G_TOKEN_RIGHT_PAREN;
|
|
|
|
}
|
|
|
|
|
2021-04-05 21:49:41 +02:00
|
|
|
/*
|
|
|
|
* Note: this is different from gimp_config_deserialize_parasite()
|
|
|
|
* which is a public API to deserialize random properties into a config
|
|
|
|
* object from a parasite. Here we are deserializing the contents of a
|
|
|
|
* parasite itself in @scanner.
|
|
|
|
*/
|
|
|
|
static GTokenType
|
|
|
|
gimp_config_deserialize_parasite_value (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner)
|
|
|
|
{
|
|
|
|
GimpParasite *parasite;
|
|
|
|
gchar *name;
|
|
|
|
guint8 *data;
|
|
|
|
gint data_length;
|
|
|
|
gint64 flags;
|
|
|
|
|
|
|
|
if (! gimp_scanner_parse_string (scanner, &name))
|
|
|
|
return G_TOKEN_STRING;
|
|
|
|
|
|
|
|
if (! (name && *name))
|
|
|
|
{
|
|
|
|
g_scanner_error (scanner, "Parasite name is empty");
|
|
|
|
g_free (name);
|
|
|
|
return G_TOKEN_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! gimp_scanner_parse_int64 (scanner, &flags))
|
|
|
|
return G_TOKEN_INT;
|
|
|
|
|
|
|
|
if (! gimp_scanner_parse_int (scanner, &data_length))
|
|
|
|
return G_TOKEN_INT;
|
|
|
|
|
|
|
|
if (! gimp_scanner_parse_data (scanner, data_length, &data))
|
|
|
|
return G_TOKEN_STRING;
|
|
|
|
|
|
|
|
parasite = gimp_parasite_new (name, flags, data_length, data);
|
2023-11-15 02:26:23 +01:00
|
|
|
g_free (data);
|
2021-04-05 21:49:41 +02:00
|
|
|
|
|
|
|
g_value_take_boxed (value, parasite);
|
|
|
|
|
|
|
|
return G_TOKEN_RIGHT_PAREN;
|
|
|
|
}
|
|
|
|
|
2023-07-23 17:32:25 +02:00
|
|
|
static GTokenType
|
|
|
|
gimp_config_deserialize_bytes (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner)
|
|
|
|
{
|
2023-08-30 18:30:13 +02:00
|
|
|
GTokenType token;
|
|
|
|
GBytes *bytes;
|
|
|
|
guint8 *data;
|
|
|
|
gint data_length;
|
2023-07-23 17:32:25 +02:00
|
|
|
|
2023-08-30 18:30:13 +02:00
|
|
|
token = g_scanner_peek_next_token (scanner);
|
2023-07-23 17:32:25 +02:00
|
|
|
|
2023-08-30 18:30:13 +02:00
|
|
|
if (token == G_TOKEN_IDENTIFIER)
|
|
|
|
{
|
|
|
|
g_scanner_get_next_token (scanner);
|
2023-07-23 17:32:25 +02:00
|
|
|
|
2023-08-30 18:30:13 +02:00
|
|
|
if (g_ascii_strcasecmp (scanner->value.v_identifier, "null") != 0)
|
|
|
|
/* Do not fail the whole file parsing. Just output to stderr and assume
|
|
|
|
* a NULL bytes property.
|
|
|
|
*/
|
|
|
|
g_printerr ("%s: expected NULL identifier for bytes token '%s', got '%s'. "
|
|
|
|
"Assuming NULL instead.\n",
|
|
|
|
G_STRFUNC, prop_spec->name, scanner->value.v_identifier);
|
2023-07-23 17:32:25 +02:00
|
|
|
|
2023-08-30 18:30:13 +02:00
|
|
|
g_value_set_boxed (value, NULL);
|
|
|
|
}
|
|
|
|
else if (token == G_TOKEN_INT)
|
|
|
|
{
|
|
|
|
if (! gimp_scanner_parse_int (scanner, &data_length))
|
|
|
|
return G_TOKEN_INT;
|
|
|
|
|
|
|
|
if (! gimp_scanner_parse_data (scanner, data_length, &data))
|
|
|
|
return G_TOKEN_STRING;
|
|
|
|
|
2023-11-15 02:26:23 +01:00
|
|
|
bytes = g_bytes_new_take (data, data_length);
|
2023-08-30 18:30:13 +02:00
|
|
|
|
|
|
|
g_value_take_boxed (value, bytes);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return G_TOKEN_INT;
|
|
|
|
}
|
2023-07-23 17:32:25 +02:00
|
|
|
|
|
|
|
return G_TOKEN_RIGHT_PAREN;
|
|
|
|
}
|
|
|
|
|
2023-11-15 02:28:34 +01:00
|
|
|
static GTokenType
|
|
|
|
gimp_config_deserialize_color (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
|
|
|
GScanner *scanner)
|
|
|
|
{
|
2023-12-12 00:34:24 +09:00
|
|
|
GeglColor *color = NULL;
|
2023-11-15 02:44:12 +01:00
|
|
|
|
2023-12-12 00:34:24 +09:00
|
|
|
if (! gimp_scanner_parse_color (scanner, &color))
|
|
|
|
return G_TOKEN_NONE;
|
2023-11-15 02:28:34 +01:00
|
|
|
|
2023-12-12 00:34:24 +09:00
|
|
|
g_value_take_object (value, color);
|
2023-11-15 02:28:34 +01:00
|
|
|
|
|
|
|
return G_TOKEN_RIGHT_PAREN;
|
|
|
|
}
|
|
|
|
|
2001-12-09 03:00:32 +00:00
|
|
|
static GTokenType
|
2001-12-08 15:56:40 +00:00
|
|
|
gimp_config_deserialize_any (GValue *value,
|
|
|
|
GParamSpec *prop_spec,
|
2001-12-09 03:00:32 +00:00
|
|
|
GScanner *scanner)
|
2001-12-08 15:56:40 +00:00
|
|
|
{
|
2012-10-04 23:54:27 +02:00
|
|
|
GValue src = G_VALUE_INIT;
|
|
|
|
GTokenType token;
|
2001-12-08 15:56:40 +00:00
|
|
|
|
|
|
|
if (!g_value_type_transformable (G_TYPE_STRING, prop_spec->value_type))
|
|
|
|
{
|
2022-02-10 22:09:43 +01:00
|
|
|
g_scanner_error (scanner,
|
|
|
|
"%s can not be transformed from a string",
|
|
|
|
g_type_name (prop_spec->value_type));
|
2001-12-09 03:00:32 +00:00
|
|
|
return G_TOKEN_NONE;
|
2001-12-08 03:35:38 +00:00
|
|
|
}
|
2001-12-08 15:56:40 +00:00
|
|
|
|
2012-10-04 23:54:27 +02:00
|
|
|
token = g_scanner_peek_next_token (scanner);
|
|
|
|
|
|
|
|
if (token != G_TOKEN_IDENTIFIER &&
|
|
|
|
token != G_TOKEN_STRING)
|
|
|
|
{
|
|
|
|
return G_TOKEN_IDENTIFIER;
|
|
|
|
}
|
2001-12-08 15:56:40 +00:00
|
|
|
|
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
|
|
|
|
g_value_init (&src, G_TYPE_STRING);
|
2012-10-04 23:54:27 +02:00
|
|
|
|
|
|
|
if (token == G_TOKEN_IDENTIFIER)
|
|
|
|
g_value_set_static_string (&src, scanner->value.v_identifier);
|
|
|
|
else
|
|
|
|
g_value_set_static_string (&src, scanner->value.v_string);
|
|
|
|
|
2001-12-08 15:56:40 +00:00
|
|
|
g_value_transform (&src, value);
|
2001-12-11 23:10:59 +00:00
|
|
|
g_value_unset (&src);
|
2001-12-08 15:56:40 +00:00
|
|
|
|
2001-12-09 03:00:32 +00:00
|
|
|
return G_TOKEN_RIGHT_PAREN;
|
2001-11-27 03:52:11 +00:00
|
|
|
}
|
2007-06-04 10:38:25 +00:00
|
|
|
|
|
|
|
static GTokenType
|
|
|
|
gimp_config_skip_unknown_property (GScanner *scanner)
|
|
|
|
{
|
|
|
|
gint open_paren = 0;
|
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
GTokenType token = g_scanner_peek_next_token (scanner);
|
|
|
|
|
|
|
|
switch (token)
|
|
|
|
{
|
|
|
|
case G_TOKEN_LEFT_PAREN:
|
|
|
|
open_paren++;
|
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case G_TOKEN_RIGHT_PAREN:
|
|
|
|
if (open_paren == 0)
|
|
|
|
return token;
|
|
|
|
|
|
|
|
open_paren--;
|
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case G_TOKEN_EOF:
|
|
|
|
return token;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_scanner_get_next_token (scanner);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|