added "gint nest_level" to the deserialization functions, so nested calls

2002-05-27  Michael Natterer  <mitch@gimp.org>

	* app/config/gimpconfig.[ch]: added "gint nest_level" to the
	deserialization functions, so nested calls to deserialize()
	don't error on the trailing ')'. Made the scanner config parse
	one-character identifiers and allow G_CSET_A_2_Z for all
	identifiers.
	Added gimp_config_deserialize_return() because returning the
	correct return value from a deserialize() function is not
	trivial any more with nested calls.

	* app/config/gimpconfig-deserialize.[ch]
	* app/config/gimprc.c
	* app/core/gimpdocumentlist.c
	* app/core/gimpparasitelist.c: use the new return value utility
	function and made the main parsing loops simpler.

	* app/core/gimpunits.c: made the main parsing loops consistent
	with the stuff that uses GimpConfig.

	* app/config/gimpconfig-deserialize.c
	* app/config/gimpconfig-serialize.c: call the
	(de)serialize_property() functions only if the property's class
	implements the method itself (does *not* inherit it from one of
	it's parents).

	* app/core/gimpcontainer.c: implemented deserialization of
	containers. For each child entry encountered in the input, check
	if it's already contained in the container and create it if not.
	If a "gimp" pointer is passed as user_data pass it as construct
	property to g_object_new() when creating the object.

	* app/core/gimpcontext.c: changed deserialization of brush,
	pattern etc. to honor "no_data".

	* app/widgets/gimpdeviceinfo.c: added a "gimp" construct_only
	property which overrides GimpContext's "gimp" property. Moved all
	initialisation code from gimp_device_info_new() to
	gimp_device_info_set_property(PROP_GIMP) so it is properly
	performed if the object is created by GimpContainer's
	deserialize() implementation.

	* app/widgets/gimpdevices.c: made gimp_devices_restore_test() work.
This commit is contained in:
Michael Natterer 2002-05-27 14:04:21 +00:00 committed by Michael Natterer
parent 9ccebbd48e
commit dbc8aeb49c
20 changed files with 572 additions and 215 deletions

View File

@ -1,3 +1,47 @@
2002-05-27 Michael Natterer <mitch@gimp.org>
* app/config/gimpconfig.[ch]: added "gint nest_level" to the
deserialization functions, so nested calls to deserialize()
don't error on the trailing ')'. Made the scanner config parse
one-character identifiers and allow G_CSET_A_2_Z for all
identifiers.
Added gimp_config_deserialize_return() because returning the
correct return value from a deserialize() function is not
trivial any more with nested calls.
* app/config/gimpconfig-deserialize.[ch]
* app/config/gimprc.c
* app/core/gimpdocumentlist.c
* app/core/gimpparasitelist.c: use the new return value utility
function and made the main parsing loops simpler.
* app/core/gimpunits.c: made the main parsing loops consistent
with the stuff that uses GimpConfig.
* app/config/gimpconfig-deserialize.c
* app/config/gimpconfig-serialize.c: call the
(de)serialize_property() functions only if the property's class
implements the method itself (does *not* inherit it from one of
it's parents).
* app/core/gimpcontainer.c: implemented deserialization of
containers. For each child entry encountered in the input, check
if it's already contained in the container and create it if not.
If a "gimp" pointer is passed as user_data pass it as construct
property to g_object_new() when creating the object.
* app/core/gimpcontext.c: changed deserialization of brush,
pattern etc. to honor "no_data".
* app/widgets/gimpdeviceinfo.c: added a "gimp" construct_only
property which overrides GimpContext's "gimp" property. Moved all
initialisation code from gimp_device_info_new() to
gimp_device_info_set_property(PROP_GIMP) so it is properly
performed if the object is created by GimpContainer's
deserialize() implementation.
* app/widgets/gimpdevices.c: made gimp_devices_restore_test() work.
2002-05-27 Sven Neumann <sven@gimp.org>
* configure.in: restructured, added lots of comments. Reenabled

View File

@ -90,6 +90,7 @@ static inline gboolean scanner_string_utf8_valid (GScanner *scanner,
* gimp_config_deserialize_properties:
* @object: a #GObject.
* @scanner: a #GScanner.
* @embedded_scope: %TRUE if a trailing ')' should not trigger a parse error.
* @store_unknown_tokens: %TRUE if you want to store unknown tokens.
*
* This function uses the @scanner to configure the properties of @object.
@ -105,6 +106,7 @@ static inline gboolean scanner_string_utf8_valid (GScanner *scanner,
gboolean
gimp_config_deserialize_properties (GObject *object,
GScanner *scanner,
gint nest_level,
gboolean store_unknown_tokens)
{
GObjectClass *klass;
@ -124,7 +126,7 @@ gimp_config_deserialize_properties (GObject *object,
if (!property_specs)
return TRUE;
scope_id = g_quark_from_static_string ("gimp_config_deserialize_properties");
scope_id = g_type_qname (G_TYPE_FROM_INSTANCE (object));
old_scope_id = g_scanner_set_scope (scanner, scope_id);
for (i = 0; i < n_property_specs; i++)
@ -141,8 +143,8 @@ gimp_config_deserialize_properties (GObject *object,
g_free (property_specs);
token = G_TOKEN_LEFT_PAREN;
do
while (TRUE)
{
next = g_scanner_peek_next_token (scanner);
@ -160,7 +162,7 @@ gimp_config_deserialize_properties (GObject *object,
case G_TOKEN_LEFT_PAREN:
token = G_TOKEN_SYMBOL;
break;
case G_TOKEN_IDENTIFIER:
token = gimp_config_deserialize_unknown (object, scanner);
break;
@ -177,17 +179,11 @@ gimp_config_deserialize_properties (GObject *object,
break;
}
}
while (token != G_TOKEN_EOF);
if (next != G_TOKEN_EOF && next != token && token != G_TOKEN_NONE)
{
g_scanner_get_next_token (scanner);
g_scanner_unexp_token (scanner, token, NULL, NULL, NULL, NULL, TRUE);
}
g_scanner_set_scope (scanner, old_scope_id);
return (next == G_TOKEN_EOF || next == token);
return gimp_config_deserialize_return (scanner, token,
nest_level, NULL);
}
static GTokenType
@ -219,7 +215,9 @@ static GTokenType
gimp_config_deserialize_property (GObject *object,
GScanner *scanner)
{
GTypeClass *owner_class;
GimpConfigInterface *gimp_config_iface;
GimpConfigInterface *parent_iface;
GParamSpec *prop_spec;
GTokenType token = G_TOKEN_RIGHT_PAREN;
GValue value = { 0, };
@ -228,11 +226,33 @@ gimp_config_deserialize_property (GObject *object,
g_value_init (&value, prop_spec->value_type);
gimp_config_iface =
g_type_interface_peek (g_type_class_peek (prop_spec->owner_type),
GIMP_TYPE_CONFIG_INTERFACE);
owner_class = g_type_class_peek (prop_spec->owner_type);
if (gimp_config_iface &&
gimp_config_iface = g_type_interface_peek (owner_class,
GIMP_TYPE_CONFIG_INTERFACE);
/* 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 (gimp_config_iface)
{
GTypeClass *owner_parent_class;
owner_parent_class = g_type_class_peek_parent (owner_class),
parent_iface = g_type_interface_peek (owner_parent_class,
GIMP_TYPE_CONFIG_INTERFACE);
}
if (gimp_config_iface &&
gimp_config_iface != parent_iface && /* see comment above */
gimp_config_iface->deserialize_property &&
gimp_config_iface->deserialize_property (object,
prop_spec->param_id,
@ -385,14 +405,14 @@ gimp_config_deserialize_fundamental (GValue *value,
break;
case G_TYPE_ULONG:
g_value_set_uint (value, scanner->value.v_int);
break;
break;
case G_TYPE_FLOAT:
g_value_set_float (value, scanner->value.v_float);
break;
case G_TYPE_DOUBLE:
g_value_set_double (value, scanner->value.v_float);
break;
default:
g_assert_not_reached ();
break;
@ -519,11 +539,8 @@ gimp_config_deserialize_color (GValue *value,
token = G_TOKEN_LEFT_PAREN;
do
while (g_scanner_peek_next_token (scanner) == token)
{
if (g_scanner_peek_next_token (scanner) != token)
break;
token = g_scanner_get_next_token (scanner);
switch (token)
@ -595,7 +612,6 @@ gimp_config_deserialize_color (GValue *value,
break;
}
}
while (token != G_TOKEN_EOF);
finish:

View File

@ -25,6 +25,7 @@
gboolean gimp_config_deserialize_properties (GObject *object,
GScanner *scanner,
gint nest_level,
gboolean store_unknown_tokens);

View File

@ -389,18 +389,42 @@ gimp_config_serialize_property (GObject *object,
GString *str,
gboolean escaped)
{
GTypeClass *owner_class;
GimpConfigInterface *gimp_config_iface;
GimpConfigInterface *parent_iface;
GValue value = { 0, };
gboolean retval;
g_value_init (&value, param_spec->value_type);
g_object_get_property (object, param_spec->name, &value);
gimp_config_iface =
g_type_interface_peek (g_type_class_peek (param_spec->owner_type),
GIMP_TYPE_CONFIG_INTERFACE);
owner_class = g_type_class_peek (param_spec->owner_type);
gimp_config_iface = g_type_interface_peek (owner_class,
GIMP_TYPE_CONFIG_INTERFACE);
/* 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 (gimp_config_iface)
{
GTypeClass *owner_parent_class;
owner_parent_class = g_type_class_peek_parent (owner_class),
parent_iface = g_type_interface_peek (owner_parent_class,
GIMP_TYPE_CONFIG_INTERFACE);
}
if (gimp_config_iface &&
gimp_config_iface != parent_iface && /* see comment above */
gimp_config_iface->serialize_property &&
gimp_config_iface->serialize_property (object,
param_spec->param_id,

View File

@ -53,6 +53,7 @@ static gboolean gimp_config_iface_serialize (GObject *object,
gpointer data);
static gboolean gimp_config_iface_deserialize (GObject *object,
GScanner *scanner,
gint nest_level,
gpointer data);
static GObject *gimp_config_iface_duplicate (GObject *object);
static gboolean gimp_config_iface_equal (GObject *a,
@ -111,9 +112,10 @@ gimp_config_iface_serialize (GObject *object,
static gboolean
gimp_config_iface_deserialize (GObject *object,
GScanner *scanner,
gint nest_level,
gpointer data)
{
return gimp_config_deserialize_properties (object, scanner, FALSE);
return gimp_config_deserialize_properties (object, scanner, nest_level, FALSE);
}
static GObject *
@ -227,7 +229,8 @@ gimp_config_serialize (GObject *object,
if (success && footer)
success = (write (fd, "\n", 1) != -1 &&
write (fd, footer, strlen (footer)) != -1);
write (fd, footer, strlen (footer)) != -1 &&
write (fd, "\n", 1) != -1);
if (! success)
{
@ -311,10 +314,12 @@ gimp_config_deserialize (GObject *object,
scanner->msg_handler = gimp_config_scanner_message;
scanner->input_name = filename;
scanner->config->cset_identifier_first = ( G_CSET_a_2_z );
scanner->config->cset_identifier_nth = ( G_CSET_a_2_z "-_" );
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 "-_" );
success = gimp_config_iface->deserialize (object, scanner, data);
scanner->config->scan_identifier_1char = TRUE;
success = gimp_config_iface->deserialize (object, scanner, 0, data);
g_scanner_destroy (scanner);
close (fd);
@ -325,6 +330,45 @@ gimp_config_deserialize (GObject *object,
return success;
}
gboolean
gimp_config_deserialize_return (GScanner *scanner,
GTokenType expected_token,
gint nest_level,
const gchar *symbol_name)
{
GTokenType next_token;
g_return_val_if_fail (scanner != NULL, FALSE);
next_token = g_scanner_peek_next_token (scanner);
if (expected_token != G_TOKEN_LEFT_PAREN)
{
g_scanner_get_next_token (scanner);
g_scanner_unexp_token (scanner, expected_token, NULL, NULL,
symbol_name,
_("fatal parse error"), TRUE);
return FALSE;
}
else
{
if (nest_level > 0 && next_token == G_TOKEN_RIGHT_PAREN)
{
return TRUE;
}
else if (next_token != G_TOKEN_EOF)
{
g_scanner_get_next_token (scanner);
g_scanner_unexp_token (scanner, expected_token, NULL, NULL,
symbol_name,
_("fatal parse error"), TRUE);
return FALSE;
}
}
return TRUE;
}
GQuark
gimp_config_error_quark (void)
{

View File

@ -46,6 +46,7 @@ struct _GimpConfigInterface
gpointer data);
gboolean (* deserialize) (GObject *object,
GScanner *scanner,
gint nest_level,
gpointer data);
gboolean (* serialize_property) (GObject *object,
guint property_id,
@ -81,6 +82,11 @@ gboolean gimp_config_deserialize (GObject *object,
gpointer data,
GError **error);
gboolean gimp_config_deserialize_return (GScanner *scanner,
GTokenType expected_token,
gint nest_level,
const gchar *symbol_name);
GObject * gimp_config_duplicate (GObject *object);
gboolean gimp_config_equal (GObject *a,
GObject *b);

View File

@ -48,6 +48,7 @@ static gboolean gimp_rc_serialize (GObject *object,
gpointer data);
static gboolean gimp_rc_deserialize (GObject *object,
GScanner *scanner,
gint nest_level,
gpointer data);
static GObject * gimp_rc_duplicate (GObject *object);
@ -129,9 +130,10 @@ gimp_rc_serialize (GObject *object,
static gboolean
gimp_rc_deserialize (GObject *object,
GScanner *scanner,
gint nest_level,
gpointer data)
{
return gimp_config_deserialize_properties (object, scanner, TRUE);
return gimp_config_deserialize_properties (object, scanner, nest_level, TRUE);
}
static void

View File

@ -120,11 +120,8 @@ gimp_unitrc_load (Gimp *gimp)
token = G_TOKEN_LEFT_PAREN;
do
while (g_scanner_peek_next_token (scanner) == token)
{
if (g_scanner_peek_next_token (scanner) != token)
break;
token = g_scanner_get_next_token (scanner);
switch (token)
@ -138,8 +135,8 @@ gimp_unitrc_load (Gimp *gimp)
{
g_scanner_set_scope (scanner, UNIT_INFO);
token = gimp_unitrc_unit_info_deserialize (scanner, gimp);
if (token == G_TOKEN_LEFT_PAREN)
if (token == G_TOKEN_RIGHT_PAREN)
g_scanner_set_scope (scanner, 0);
}
break;
@ -152,7 +149,6 @@ gimp_unitrc_load (Gimp *gimp)
break;
}
}
while (token != G_TOKEN_EOF);
if (token != G_TOKEN_LEFT_PAREN)
{
@ -240,19 +236,13 @@ gimp_unitrc_unit_info_deserialize (GScanner *scanner,
GTokenType token;
GimpUnit unit;
if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
return G_TOKEN_STRING;
if (! gimp_scanner_parse_string (scanner, &identifier))
return G_TOKEN_STRING;
token = G_TOKEN_LEFT_PAREN;
do
while (g_scanner_peek_next_token (scanner) == token)
{
if (g_scanner_peek_next_token (scanner) != token)
break;
token = g_scanner_get_next_token (scanner);
switch (token)
@ -262,42 +252,48 @@ gimp_unitrc_unit_info_deserialize (GScanner *scanner,
break;
case G_TOKEN_SYMBOL:
token = G_TOKEN_RIGHT_PAREN;
switch (GPOINTER_TO_INT (scanner->value.v_symbol))
{
case UNIT_FACTOR:
token = G_TOKEN_FLOAT;
if (! gimp_scanner_parse_float (scanner, &factor))
return G_TOKEN_FLOAT;
goto cleanup;
break;
case UNIT_DIGITS:
token = G_TOKEN_INT;
if (! gimp_scanner_parse_int (scanner, &digits))
return G_TOKEN_INT;
goto cleanup;
break;
case UNIT_SYMBOL:
token = G_TOKEN_STRING;
if (! gimp_scanner_parse_string (scanner, &symbol))
return G_TOKEN_STRING;
goto cleanup;
break;
case UNIT_ABBREV:
token = G_TOKEN_STRING;
if (! gimp_scanner_parse_string (scanner, &abbreviation))
return G_TOKEN_STRING;
goto cleanup;
break;
case UNIT_SINGULAR:
token = G_TOKEN_STRING;
if (! gimp_scanner_parse_string (scanner, &singular))
return G_TOKEN_STRING;
goto cleanup;
break;
case UNIT_PLURAL:
token = G_TOKEN_STRING;
if (! gimp_scanner_parse_string (scanner, &plural))
return G_TOKEN_STRING;
goto cleanup;
break;
default:
break;
}
token = G_TOKEN_RIGHT_PAREN;
break;
case G_TOKEN_RIGHT_PAREN:
@ -308,30 +304,23 @@ gimp_unitrc_unit_info_deserialize (GScanner *scanner,
break;
}
}
while (token != G_TOKEN_EOF);
if (token == G_TOKEN_LEFT_PAREN)
{
token = G_TOKEN_RIGHT_PAREN;
if (gimp_scanner_parse_token (scanner, token))
if (g_scanner_peek_next_token (scanner) == token)
{
unit = _gimp_unit_new (gimp, identifier, factor, digits,
symbol, abbreviation, singular, plural);
/* make the unit definition persistent */
gimp_unit_set_deletion_flag (unit, FALSE);
g_free (identifier);
g_free (symbol);
g_free (abbreviation);
g_free (singular);
g_free (plural);
return G_TOKEN_LEFT_PAREN;
}
}
cleanup:
g_free (identifier);
g_free (symbol);
g_free (abbreviation);

View File

@ -30,10 +30,15 @@
#include "core-types.h"
#include "gimp.h"
#include "gimpcontainer.h"
#include "gimpmarshal.h"
#include "config/gimpconfig.h"
#include "config/gimpconfig-deserialize.h"
#include "config/gimpscanner.h"
#include "libgimp/gimpintl.h"
/* #define DEBUG_CONTAINER */
@ -98,6 +103,7 @@ static gboolean gimp_container_serialize (GObject *object,
gpointer data);
static gboolean gimp_container_deserialize (GObject *object,
GScanner *scanner,
gint nest_level,
gpointer data);
static void gimp_container_disconnect_callback (GimpObject *object,
@ -434,7 +440,10 @@ gimp_container_serialize_foreach (GObject *object,
if (! serialize_data->success)
return;
g_string_assign (str, ")\n");
if (serialize_data->indent_level > 0)
g_string_assign (str, ")");
else
g_string_assign (str, ")\n");
if (write (serialize_data->fd, str->str, str->len) == -1)
serialize_data->success = FALSE;
@ -466,13 +475,123 @@ gimp_container_serialize (GObject *object,
static gboolean
gimp_container_deserialize (GObject *object,
GScanner *scanner,
gint nest_level,
gpointer data)
{
GimpContainer *container;
GTokenType token;
container = GIMP_CONTAINER (object);
return TRUE;
token = G_TOKEN_LEFT_PAREN;
while (g_scanner_peek_next_token (scanner) == token)
{
token = g_scanner_get_next_token (scanner);
switch (token)
{
case G_TOKEN_LEFT_PAREN:
token = G_TOKEN_IDENTIFIER;
break;
case G_TOKEN_IDENTIFIER:
{
GimpObject *child;
GType type;
gchar *name;
type = g_type_from_name (scanner->value.v_identifier);
if (! type)
{
g_scanner_error (scanner,
_("unable to determine type of '%s'"),
scanner->value.v_identifier);
return FALSE;
}
if (! g_type_is_a (type, container->children_type))
{
g_scanner_error (scanner,
_("'%s' is not a subclass of '%s'"),
scanner->value.v_identifier,
g_type_name (container->children_type));
return FALSE;
}
if (! g_type_is_a (type, GIMP_TYPE_CONFIG_INTERFACE))
{
g_scanner_error (scanner,
_("'%s' does not implement GimpConfigInterface"),
scanner->value.v_identifier);
return FALSE;
}
if (! gimp_scanner_parse_string (scanner, &name))
{
token = G_TOKEN_STRING;
break;
}
child = gimp_container_get_child_by_name (container, name);
if (child)
{
g_print ("found child \"%s\"\n", name);
}
else
{
g_print ("creating child \"%s\"\n", name);
if (GIMP_IS_GIMP (data))
{
child = g_object_new (type,
"name", name,
"gimp", data, NULL);
}
else
{
child = g_object_new (type,
"name", name, NULL);
}
gimp_container_add (container, child);
if (container->policy == GIMP_CONTAINER_POLICY_STRONG)
g_object_unref (G_OBJECT (child));
}
{
#if 0
GimpConfigInterface *config_iface;
config_iface = GIMP_GET_CONFIG_INTERFACE (child);
#endif
if (! gimp_config_deserialize_properties (G_OBJECT (child),
scanner,
nest_level + 1,
FALSE))
{
/* warning should be already set by child */
return FALSE;
}
}
}
token = G_TOKEN_RIGHT_PAREN;
break;
case G_TOKEN_RIGHT_PAREN:
token = G_TOKEN_LEFT_PAREN;
break;
default: /* do nothing */
break;
}
}
return gimp_config_deserialize_return (scanner, token,
nest_level, NULL);
}
static void

View File

@ -574,23 +574,20 @@ gimp_context_class_init (GimpContextClass *klass)
gimp_context_prop_types[GIMP_CONTEXT_PROP_BUFFER] = GIMP_TYPE_BUFFER;
gimp_context_prop_types[GIMP_CONTEXT_PROP_IMAGEFILE] = GIMP_TYPE_IMAGEFILE;
g_object_class_install_property (object_class,
PROP_GIMP,
g_object_class_install_property (object_class, PROP_GIMP,
g_param_spec_object ("gimp",
NULL, NULL,
GIMP_TYPE_GIMP,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_IMAGE,
g_object_class_install_property (object_class, PROP_IMAGE,
g_param_spec_object (gimp_context_prop_names[IMAGE_CHANGED],
NULL, NULL,
GIMP_TYPE_IMAGE,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_DISPLAY,
g_object_class_install_property (object_class, PROP_DISPLAY,
g_param_spec_object (gimp_context_prop_names[DISPLAY_CHANGED],
NULL, NULL,
GIMP_TYPE_OBJECT,
@ -635,15 +632,13 @@ gimp_context_class_init (GimpContextClass *klass)
gimp_context_prop_names[PALETTE_CHANGED],
GIMP_TYPE_PALETTE);
g_object_class_install_property (object_class,
PROP_BUFFER,
g_object_class_install_property (object_class, PROP_BUFFER,
g_param_spec_object (gimp_context_prop_names[BUFFER_CHANGED],
NULL, NULL,
GIMP_TYPE_BUFFER,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_IMAGEFILE,
g_object_class_install_property (object_class, PROP_IMAGEFILE,
g_param_spec_object (gimp_context_prop_names[IMAGEFILE_CHANGED],
NULL, NULL,
GIMP_TYPE_IMAGEFILE,
@ -995,7 +990,9 @@ gimp_context_deserialize_property (GObject *object,
{
GimpContext *context;
GimpContainer *container;
GimpObject *standard;
GimpObject *current;
gchar **name_loc;
gboolean no_data = FALSE;
gchar *object_name;
context = GIMP_CONTEXT (object);
@ -1004,33 +1001,42 @@ gimp_context_deserialize_property (GObject *object,
{
case PROP_TOOL:
container = context->gimp->tool_info_list;
standard = GIMP_OBJECT (gimp_tool_info_get_standard (context->gimp));
current = (GimpObject *) context->tool_info;
name_loc = &context->tool_name;
no_data = TRUE;
break;
case PROP_BRUSH:
container = context->gimp->brush_factory->container;
standard = GIMP_OBJECT (gimp_brush_get_standard ());
current = (GimpObject *) context->brush;
name_loc = &context->brush_name;
break;
case PROP_PATTERN:
container = context->gimp->pattern_factory->container;
standard = GIMP_OBJECT (gimp_pattern_get_standard ());
current = (GimpObject *) context->pattern;
name_loc = &context->pattern_name;
break;
case PROP_GRADIENT:
container = context->gimp->gradient_factory->container;
standard = GIMP_OBJECT (gimp_gradient_get_standard ());
current = (GimpObject *) context->gradient;
name_loc = &context->gradient_name;
break;
case PROP_PALETTE:
container = context->gimp->palette_factory->container;
standard = GIMP_OBJECT (gimp_palette_get_standard ());
current = (GimpObject *) context->palette;
name_loc = &context->palette_name;
break;
default:
return FALSE;
}
if (! no_data)
no_data = context->gimp->no_data;
if (gimp_scanner_parse_identifier (scanner, "NULL"))
{
g_value_set_object (value, NULL);
@ -1044,13 +1050,14 @@ gimp_context_deserialize_property (GObject *object,
if (! deserialize_obj)
{
if (gimp_container_num_children (container) > 0)
if (no_data)
{
deserialize_obj = gimp_container_get_child_by_index (container, 0);
g_free (*name_loc);
*name_loc = g_strdup (object_name);
}
else
{
deserialize_obj = standard;
deserialize_obj = current;
}
}

View File

@ -33,8 +33,6 @@
#include "gimpdocumentlist.h"
#include "gimpimagefile.h"
#include "libgimp/gimpintl.h"
static void gimp_document_list_config_iface_init (gpointer iface,
gpointer iface_data);
@ -44,6 +42,7 @@ static gboolean gimp_document_list_serialize (GObject *list,
gpointer data);
static gboolean gimp_document_list_deserialize (GObject *list,
GScanner *scanner,
gint nest_level,
gpointer data);
@ -129,6 +128,7 @@ gimp_document_list_serialize (GObject *document_list,
static gboolean
gimp_document_list_deserialize (GObject *document_list,
GScanner *scanner,
gint nest_level,
gpointer data)
{
GTokenType token;
@ -141,11 +141,8 @@ gimp_document_list_deserialize (GObject *document_list,
token = G_TOKEN_LEFT_PAREN;
do
while (g_scanner_peek_next_token (scanner) == token)
{
if (g_scanner_peek_next_token (scanner) != token)
break;
token = g_scanner_get_next_token (scanner);
switch (token)
@ -176,6 +173,8 @@ gimp_document_list_deserialize (GObject *document_list,
gimp_container_add (GIMP_CONTAINER (document_list),
GIMP_OBJECT (imagefile));
g_object_unref (G_OBJECT (imagefile));
}
break;
@ -187,20 +186,9 @@ gimp_document_list_deserialize (GObject *document_list,
break;
}
}
while (token != G_TOKEN_EOF);
GIMP_LIST (document_list)->list =
g_list_reverse (GIMP_LIST (document_list)->list);
if (token != G_TOKEN_LEFT_PAREN)
{
g_scanner_get_next_token (scanner);
g_scanner_unexp_token (scanner, token, NULL, NULL, document_symbol,
_("fatal parse error"), TRUE);
return FALSE;
}
return TRUE;
return gimp_config_deserialize_return (scanner, token,
nest_level, document_symbol);
}
GimpContainer *

View File

@ -34,8 +34,6 @@
#include "gimpmarshal.h"
#include "gimpparasitelist.h"
#include "libgimp/gimpintl.h"
enum
{
@ -58,6 +56,7 @@ static gboolean gimp_parasite_list_serialize (GObject *list,
gpointer data);
static gboolean gimp_parasite_list_deserialize (GObject *list,
GScanner *scanner,
gint nest_level,
gpointer data);
static void parasite_serialize (const gchar *key,
@ -245,6 +244,7 @@ gimp_parasite_list_serialize (GObject *list,
static gboolean
gimp_parasite_list_deserialize (GObject *list,
GScanner *scanner,
gint nest_level,
gpointer data)
{
GTokenType token;
@ -254,11 +254,8 @@ gimp_parasite_list_deserialize (GObject *list,
token = G_TOKEN_LEFT_PAREN;
do
while (g_scanner_peek_next_token (scanner) == token)
{
if (g_scanner_peek_next_token (scanner) != token)
break;
token = g_scanner_get_next_token (scanner);
switch (token)
@ -319,17 +316,9 @@ gimp_parasite_list_deserialize (GObject *list,
break;
}
}
while (token != G_TOKEN_EOF);
if (token != G_TOKEN_LEFT_PAREN)
{
g_scanner_get_next_token (scanner);
g_scanner_unexp_token (scanner, token, NULL, NULL, parasite_symbol,
_("fatal parse error"), TRUE);
return FALSE;
}
return TRUE;
return gimp_config_deserialize_return (scanner, token,
nest_level, parasite_symbol);
}
GimpParasiteList *

View File

@ -120,11 +120,8 @@ gimp_unitrc_load (Gimp *gimp)
token = G_TOKEN_LEFT_PAREN;
do
while (g_scanner_peek_next_token (scanner) == token)
{
if (g_scanner_peek_next_token (scanner) != token)
break;
token = g_scanner_get_next_token (scanner);
switch (token)
@ -138,8 +135,8 @@ gimp_unitrc_load (Gimp *gimp)
{
g_scanner_set_scope (scanner, UNIT_INFO);
token = gimp_unitrc_unit_info_deserialize (scanner, gimp);
if (token == G_TOKEN_LEFT_PAREN)
if (token == G_TOKEN_RIGHT_PAREN)
g_scanner_set_scope (scanner, 0);
}
break;
@ -152,7 +149,6 @@ gimp_unitrc_load (Gimp *gimp)
break;
}
}
while (token != G_TOKEN_EOF);
if (token != G_TOKEN_LEFT_PAREN)
{
@ -240,19 +236,13 @@ gimp_unitrc_unit_info_deserialize (GScanner *scanner,
GTokenType token;
GimpUnit unit;
if (g_scanner_peek_next_token (scanner) != G_TOKEN_STRING)
return G_TOKEN_STRING;
if (! gimp_scanner_parse_string (scanner, &identifier))
return G_TOKEN_STRING;
token = G_TOKEN_LEFT_PAREN;
do
while (g_scanner_peek_next_token (scanner) == token)
{
if (g_scanner_peek_next_token (scanner) != token)
break;
token = g_scanner_get_next_token (scanner);
switch (token)
@ -262,42 +252,48 @@ gimp_unitrc_unit_info_deserialize (GScanner *scanner,
break;
case G_TOKEN_SYMBOL:
token = G_TOKEN_RIGHT_PAREN;
switch (GPOINTER_TO_INT (scanner->value.v_symbol))
{
case UNIT_FACTOR:
token = G_TOKEN_FLOAT;
if (! gimp_scanner_parse_float (scanner, &factor))
return G_TOKEN_FLOAT;
goto cleanup;
break;
case UNIT_DIGITS:
token = G_TOKEN_INT;
if (! gimp_scanner_parse_int (scanner, &digits))
return G_TOKEN_INT;
goto cleanup;
break;
case UNIT_SYMBOL:
token = G_TOKEN_STRING;
if (! gimp_scanner_parse_string (scanner, &symbol))
return G_TOKEN_STRING;
goto cleanup;
break;
case UNIT_ABBREV:
token = G_TOKEN_STRING;
if (! gimp_scanner_parse_string (scanner, &abbreviation))
return G_TOKEN_STRING;
goto cleanup;
break;
case UNIT_SINGULAR:
token = G_TOKEN_STRING;
if (! gimp_scanner_parse_string (scanner, &singular))
return G_TOKEN_STRING;
goto cleanup;
break;
case UNIT_PLURAL:
token = G_TOKEN_STRING;
if (! gimp_scanner_parse_string (scanner, &plural))
return G_TOKEN_STRING;
goto cleanup;
break;
default:
break;
}
token = G_TOKEN_RIGHT_PAREN;
break;
case G_TOKEN_RIGHT_PAREN:
@ -308,30 +304,23 @@ gimp_unitrc_unit_info_deserialize (GScanner *scanner,
break;
}
}
while (token != G_TOKEN_EOF);
if (token == G_TOKEN_LEFT_PAREN)
{
token = G_TOKEN_RIGHT_PAREN;
if (gimp_scanner_parse_token (scanner, token))
if (g_scanner_peek_next_token (scanner) == token)
{
unit = _gimp_unit_new (gimp, identifier, factor, digits,
symbol, abbreviation, singular, plural);
/* make the unit definition persistent */
gimp_unit_set_deletion_flag (unit, FALSE);
g_free (identifier);
g_free (symbol);
g_free (abbreviation);
g_free (singular);
g_free (plural);
return G_TOKEN_LEFT_PAREN;
}
}
cleanup:
g_free (identifier);
g_free (symbol);
g_free (abbreviation);

View File

@ -46,6 +46,7 @@ enum
enum
{
PROP_0,
PROP_GIMP,
PROP_MODE,
PROP_AXES,
PROP_KEYS
@ -124,6 +125,13 @@ gimp_device_info_class_init (GimpDeviceInfoClass *klass)
object_class->set_property = gimp_device_info_set_property;
object_class->get_property = gimp_device_info_get_property;
g_object_class_install_property (object_class, PROP_GIMP,
g_param_spec_object ("gimp",
NULL, NULL,
GIMP_TYPE_GIMP,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_MODE, "mode",
GDK_TYPE_INPUT_MODE,
GDK_MODE_DISABLED);
@ -192,6 +200,51 @@ gimp_device_info_set_property (GObject *object,
switch (property_id)
{
case PROP_GIMP:
{
GimpContext *context;
Gimp *gimp;
context = GIMP_CONTEXT (device_info);
gimp = g_value_get_object (value);
/* we override GimpContext's "gimp" property, so we need to
* register the context just like GimpContext would do it.
*/
context->gimp = gimp;
gimp->context_list = g_list_prepend (gimp->context_list, context);
gimp_context_define_properties (context,
GIMP_DEVICE_INFO_CONTEXT_MASK,
FALSE);
gimp_context_copy_properties (gimp_get_user_context (gimp),
context,
GIMP_DEVICE_INFO_CONTEXT_MASK);
/* FIXME: this is ugly and needs to be done via "notify" once
* the contexts' properties are dynamic.
*/
g_signal_connect_swapped (G_OBJECT (context), "foreground_changed",
G_CALLBACK (gimp_device_info_changed),
device_info);
g_signal_connect_swapped (G_OBJECT (context), "background_changed",
G_CALLBACK (gimp_device_info_changed),
device_info);
g_signal_connect_swapped (G_OBJECT (context), "tool_changed",
G_CALLBACK (gimp_device_info_changed),
device_info);
g_signal_connect_swapped (G_OBJECT (context), "brush_changed",
G_CALLBACK (gimp_device_info_changed),
device_info);
g_signal_connect_swapped (G_OBJECT (context), "pattern_changed",
G_CALLBACK (gimp_device_info_changed),
device_info);
g_signal_connect_swapped (G_OBJECT (context), "gradient_changed",
G_CALLBACK (gimp_device_info_changed),
device_info);
}
break;
case PROP_MODE:
if (device_info->device)
gdk_device_set_mode (device_info->device, g_value_get_enum (value));
@ -305,6 +358,10 @@ gimp_device_info_get_property (GObject *object,
switch (property_id)
{
case PROP_GIMP:
g_value_set_object (value, GIMP_CONTEXT (device_info)->gimp);
break;
case PROP_MODE:
if (device)
g_value_set_enum (value, device->mode);
@ -399,7 +456,6 @@ gimp_device_info_new (Gimp *gimp,
const gchar *name)
{
GimpDeviceInfo *device_info;
GimpContext *context;
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
g_return_val_if_fail (name != NULL, NULL);
@ -409,38 +465,6 @@ gimp_device_info_new (Gimp *gimp,
"gimp", gimp,
NULL);
context = GIMP_CONTEXT (device_info);
gimp_context_define_properties (context,
GIMP_DEVICE_INFO_CONTEXT_MASK,
FALSE);
gimp_context_copy_properties (gimp_get_user_context (gimp),
context,
GIMP_DEVICE_INFO_CONTEXT_MASK);
/*
* FIXME: this is ugly and needs to be done via "notify" once
* the contexts' properties are dynamic.
*/
g_signal_connect_swapped (G_OBJECT (context), "foreground_changed",
G_CALLBACK (gimp_device_info_changed),
device_info);
g_signal_connect_swapped (G_OBJECT (context), "background_changed",
G_CALLBACK (gimp_device_info_changed),
device_info);
g_signal_connect_swapped (G_OBJECT (context), "tool_changed",
G_CALLBACK (gimp_device_info_changed),
device_info);
g_signal_connect_swapped (G_OBJECT (context), "brush_changed",
G_CALLBACK (gimp_device_info_changed),
device_info);
g_signal_connect_swapped (G_OBJECT (context), "pattern_changed",
G_CALLBACK (gimp_device_info_changed),
device_info);
g_signal_connect_swapped (G_OBJECT (context), "gradient_changed",
G_CALLBACK (gimp_device_info_changed),
device_info);
return device_info;
}

View File

@ -182,6 +182,8 @@ void
gimp_devices_restore_test (Gimp *gimp)
{
GimpDeviceManager *manager;
GimpDeviceInfo *device_info;
GimpContext *user_context;
gchar *filename;
GError *error = NULL;
@ -193,7 +195,29 @@ gimp_devices_restore_test (Gimp *gimp)
filename = gimp_personal_rc_file ("test-devicerc");
if (! gimp_config_deserialize (G_OBJECT (manager->device_info_list),
filename,
gimp,
&error))
{
g_message ("Could not read test-devicerc: %s", error->message);
g_clear_error (&error);
g_free (filename);
return;
}
g_free (filename);
device_info = gimp_device_info_get_by_device (manager->current_device);
g_return_if_fail (GIMP_IS_DEVICE_INFO (device_info));
user_context = gimp_get_user_context (gimp);
gimp_context_copy_properties (GIMP_CONTEXT (device_info), user_context,
GIMP_DEVICE_INFO_CONTEXT_MASK);
gimp_context_set_parent (GIMP_CONTEXT (device_info), user_context);
}
void
@ -213,7 +237,7 @@ gimp_devices_save_test (Gimp *gimp)
if (! gimp_config_serialize (G_OBJECT (manager->device_info_list),
filename,
"# test-devicerc",
"# test-devicerc\n",
"# end test-devicerc",
NULL,
&error))

View File

@ -90,6 +90,7 @@ static inline gboolean scanner_string_utf8_valid (GScanner *scanner,
* gimp_config_deserialize_properties:
* @object: a #GObject.
* @scanner: a #GScanner.
* @embedded_scope: %TRUE if a trailing ')' should not trigger a parse error.
* @store_unknown_tokens: %TRUE if you want to store unknown tokens.
*
* This function uses the @scanner to configure the properties of @object.
@ -105,6 +106,7 @@ static inline gboolean scanner_string_utf8_valid (GScanner *scanner,
gboolean
gimp_config_deserialize_properties (GObject *object,
GScanner *scanner,
gint nest_level,
gboolean store_unknown_tokens)
{
GObjectClass *klass;
@ -124,7 +126,7 @@ gimp_config_deserialize_properties (GObject *object,
if (!property_specs)
return TRUE;
scope_id = g_quark_from_static_string ("gimp_config_deserialize_properties");
scope_id = g_type_qname (G_TYPE_FROM_INSTANCE (object));
old_scope_id = g_scanner_set_scope (scanner, scope_id);
for (i = 0; i < n_property_specs; i++)
@ -141,8 +143,8 @@ gimp_config_deserialize_properties (GObject *object,
g_free (property_specs);
token = G_TOKEN_LEFT_PAREN;
do
while (TRUE)
{
next = g_scanner_peek_next_token (scanner);
@ -160,7 +162,7 @@ gimp_config_deserialize_properties (GObject *object,
case G_TOKEN_LEFT_PAREN:
token = G_TOKEN_SYMBOL;
break;
case G_TOKEN_IDENTIFIER:
token = gimp_config_deserialize_unknown (object, scanner);
break;
@ -177,17 +179,11 @@ gimp_config_deserialize_properties (GObject *object,
break;
}
}
while (token != G_TOKEN_EOF);
if (next != G_TOKEN_EOF && next != token && token != G_TOKEN_NONE)
{
g_scanner_get_next_token (scanner);
g_scanner_unexp_token (scanner, token, NULL, NULL, NULL, NULL, TRUE);
}
g_scanner_set_scope (scanner, old_scope_id);
return (next == G_TOKEN_EOF || next == token);
return gimp_config_deserialize_return (scanner, token,
nest_level, NULL);
}
static GTokenType
@ -219,7 +215,9 @@ static GTokenType
gimp_config_deserialize_property (GObject *object,
GScanner *scanner)
{
GTypeClass *owner_class;
GimpConfigInterface *gimp_config_iface;
GimpConfigInterface *parent_iface;
GParamSpec *prop_spec;
GTokenType token = G_TOKEN_RIGHT_PAREN;
GValue value = { 0, };
@ -228,11 +226,33 @@ gimp_config_deserialize_property (GObject *object,
g_value_init (&value, prop_spec->value_type);
gimp_config_iface =
g_type_interface_peek (g_type_class_peek (prop_spec->owner_type),
GIMP_TYPE_CONFIG_INTERFACE);
owner_class = g_type_class_peek (prop_spec->owner_type);
if (gimp_config_iface &&
gimp_config_iface = g_type_interface_peek (owner_class,
GIMP_TYPE_CONFIG_INTERFACE);
/* 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 (gimp_config_iface)
{
GTypeClass *owner_parent_class;
owner_parent_class = g_type_class_peek_parent (owner_class),
parent_iface = g_type_interface_peek (owner_parent_class,
GIMP_TYPE_CONFIG_INTERFACE);
}
if (gimp_config_iface &&
gimp_config_iface != parent_iface && /* see comment above */
gimp_config_iface->deserialize_property &&
gimp_config_iface->deserialize_property (object,
prop_spec->param_id,
@ -385,14 +405,14 @@ gimp_config_deserialize_fundamental (GValue *value,
break;
case G_TYPE_ULONG:
g_value_set_uint (value, scanner->value.v_int);
break;
break;
case G_TYPE_FLOAT:
g_value_set_float (value, scanner->value.v_float);
break;
case G_TYPE_DOUBLE:
g_value_set_double (value, scanner->value.v_float);
break;
default:
g_assert_not_reached ();
break;
@ -519,11 +539,8 @@ gimp_config_deserialize_color (GValue *value,
token = G_TOKEN_LEFT_PAREN;
do
while (g_scanner_peek_next_token (scanner) == token)
{
if (g_scanner_peek_next_token (scanner) != token)
break;
token = g_scanner_get_next_token (scanner);
switch (token)
@ -595,7 +612,6 @@ gimp_config_deserialize_color (GValue *value,
break;
}
}
while (token != G_TOKEN_EOF);
finish:

View File

@ -25,6 +25,7 @@
gboolean gimp_config_deserialize_properties (GObject *object,
GScanner *scanner,
gint nest_level,
gboolean store_unknown_tokens);

View File

@ -53,6 +53,7 @@ static gboolean gimp_config_iface_serialize (GObject *object,
gpointer data);
static gboolean gimp_config_iface_deserialize (GObject *object,
GScanner *scanner,
gint nest_level,
gpointer data);
static GObject *gimp_config_iface_duplicate (GObject *object);
static gboolean gimp_config_iface_equal (GObject *a,
@ -111,9 +112,10 @@ gimp_config_iface_serialize (GObject *object,
static gboolean
gimp_config_iface_deserialize (GObject *object,
GScanner *scanner,
gint nest_level,
gpointer data)
{
return gimp_config_deserialize_properties (object, scanner, FALSE);
return gimp_config_deserialize_properties (object, scanner, nest_level, FALSE);
}
static GObject *
@ -227,7 +229,8 @@ gimp_config_serialize (GObject *object,
if (success && footer)
success = (write (fd, "\n", 1) != -1 &&
write (fd, footer, strlen (footer)) != -1);
write (fd, footer, strlen (footer)) != -1 &&
write (fd, "\n", 1) != -1);
if (! success)
{
@ -311,10 +314,12 @@ gimp_config_deserialize (GObject *object,
scanner->msg_handler = gimp_config_scanner_message;
scanner->input_name = filename;
scanner->config->cset_identifier_first = ( G_CSET_a_2_z );
scanner->config->cset_identifier_nth = ( G_CSET_a_2_z "-_" );
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 "-_" );
success = gimp_config_iface->deserialize (object, scanner, data);
scanner->config->scan_identifier_1char = TRUE;
success = gimp_config_iface->deserialize (object, scanner, 0, data);
g_scanner_destroy (scanner);
close (fd);
@ -325,6 +330,45 @@ gimp_config_deserialize (GObject *object,
return success;
}
gboolean
gimp_config_deserialize_return (GScanner *scanner,
GTokenType expected_token,
gint nest_level,
const gchar *symbol_name)
{
GTokenType next_token;
g_return_val_if_fail (scanner != NULL, FALSE);
next_token = g_scanner_peek_next_token (scanner);
if (expected_token != G_TOKEN_LEFT_PAREN)
{
g_scanner_get_next_token (scanner);
g_scanner_unexp_token (scanner, expected_token, NULL, NULL,
symbol_name,
_("fatal parse error"), TRUE);
return FALSE;
}
else
{
if (nest_level > 0 && next_token == G_TOKEN_RIGHT_PAREN)
{
return TRUE;
}
else if (next_token != G_TOKEN_EOF)
{
g_scanner_get_next_token (scanner);
g_scanner_unexp_token (scanner, expected_token, NULL, NULL,
symbol_name,
_("fatal parse error"), TRUE);
return FALSE;
}
}
return TRUE;
}
GQuark
gimp_config_error_quark (void)
{

View File

@ -46,6 +46,7 @@ struct _GimpConfigInterface
gpointer data);
gboolean (* deserialize) (GObject *object,
GScanner *scanner,
gint nest_level,
gpointer data);
gboolean (* serialize_property) (GObject *object,
guint property_id,
@ -81,6 +82,11 @@ gboolean gimp_config_deserialize (GObject *object,
gpointer data,
GError **error);
gboolean gimp_config_deserialize_return (GScanner *scanner,
GTokenType expected_token,
gint nest_level,
const gchar *symbol_name);
GObject * gimp_config_duplicate (GObject *object);
gboolean gimp_config_equal (GObject *a,
GObject *b);

View File

@ -389,18 +389,42 @@ gimp_config_serialize_property (GObject *object,
GString *str,
gboolean escaped)
{
GTypeClass *owner_class;
GimpConfigInterface *gimp_config_iface;
GimpConfigInterface *parent_iface;
GValue value = { 0, };
gboolean retval;
g_value_init (&value, param_spec->value_type);
g_object_get_property (object, param_spec->name, &value);
gimp_config_iface =
g_type_interface_peek (g_type_class_peek (param_spec->owner_type),
GIMP_TYPE_CONFIG_INTERFACE);
owner_class = g_type_class_peek (param_spec->owner_type);
gimp_config_iface = g_type_interface_peek (owner_class,
GIMP_TYPE_CONFIG_INTERFACE);
/* 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 (gimp_config_iface)
{
GTypeClass *owner_parent_class;
owner_parent_class = g_type_class_peek_parent (owner_class),
parent_iface = g_type_interface_peek (owner_parent_class,
GIMP_TYPE_CONFIG_INTERFACE);
}
if (gimp_config_iface &&
gimp_config_iface != parent_iface && /* see comment above */
gimp_config_iface->serialize_property &&
gimp_config_iface->serialize_property (object,
param_spec->param_id,