libgimpconfig: add gimp_config_type_register()

which implements a generalized (not GEGL operation specific) version
of the dynamic config type creation code from gimp-operation-config.c.
This commit is contained in:
Michael Natterer 2019-09-16 10:45:22 +02:00
parent 832e7fafc1
commit 3598722020
7 changed files with 364 additions and 213 deletions

View File

@ -86,166 +86,6 @@ gimp_operation_config_get_container_table (Gimp *gimp)
return config_containers; return config_containers;
} }
static GValue *
gimp_operation_config_value_new (GParamSpec *pspec)
{
GValue *value = g_slice_new0 (GValue);
g_value_init (value, pspec->value_type);
g_param_value_set_default (pspec, value);
return value;
}
static void
gimp_operation_config_value_free (GValue *value)
{
g_value_unset (value);
g_slice_free (GValue, value);
}
static GHashTable *
gimp_operation_config_get_properties (GObject *object)
{
GHashTable *properties = g_object_get_data (object, "properties");
if (! properties)
{
properties = g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) gimp_operation_config_value_free);
g_object_set_data_full (object, "properties", properties,
(GDestroyNotify) g_hash_table_unref);
}
return properties;
}
static GValue *
gimp_operation_config_value_get (GObject *object,
GParamSpec *pspec)
{
GHashTable *properties = gimp_operation_config_get_properties (object);
GValue *value;
value = g_hash_table_lookup (properties, pspec->name);
if (! value)
{
value = gimp_operation_config_value_new (pspec);
g_hash_table_insert (properties, g_strdup (pspec->name), value);
}
return value;
}
static void
gimp_operation_config_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GValue *val = gimp_operation_config_value_get (object, pspec);
g_value_copy (value, val);
}
static void
gimp_operation_config_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GValue *val = gimp_operation_config_value_get (object, pspec);
g_value_copy (val, value);
}
static void
gimp_operation_config_class_init (GObjectClass *klass,
const gchar *operation)
{
GParamSpec **pspecs;
guint n_pspecs;
gint i;
klass->set_property = gimp_operation_config_set_property;
klass->get_property = gimp_operation_config_get_property;
pspecs = gegl_operation_list_properties (operation, &n_pspecs);
for (i = 0; i < n_pspecs; i++)
{
GParamSpec *pspec = pspecs[i];
if ((pspec->flags & G_PARAM_READABLE) &&
(pspec->flags & G_PARAM_WRITABLE) &&
strcmp (pspec->name, "input") &&
strcmp (pspec->name, "output"))
{
GParamSpec *copy = gimp_config_param_spec_duplicate (pspec);
if (copy)
{
g_object_class_install_property (klass, i + 1, copy);
}
else if (! G_IS_PARAM_SPEC_OBJECT (pspec) &&
! G_IS_PARAM_SPEC_POINTER (pspec))
{
/* silently ignore object properties */
g_warning ("%s: not supported: %s (%s)\n", G_STRFUNC,
g_type_name (G_TYPE_FROM_INSTANCE (pspec)), pspec->name);
}
}
}
g_free (pspecs);
}
static gboolean
gimp_operation_config_equal (GimpConfig *a,
GimpConfig *b)
{
GList *diff;
gboolean equal = TRUE;
diff = gimp_config_diff (G_OBJECT (a), G_OBJECT (b),
GIMP_CONFIG_PARAM_SERIALIZE);
if (G_TYPE_FROM_INSTANCE (a) == G_TYPE_FROM_INSTANCE (b))
{
GList *list;
for (list = diff; list; list = g_list_next (list))
{
GParamSpec *pspec = list->data;
if (pspec->owner_type == G_TYPE_FROM_INSTANCE (a))
{
equal = FALSE;
break;
}
}
}
else if (diff)
{
equal = FALSE;
}
g_list_free (diff);
return equal;
}
static void
gimp_operation_config_config_iface_init (GimpConfigInterface *iface)
{
iface->equal = gimp_operation_config_equal;
}
/* public functions */ /* public functions */
@ -265,7 +105,7 @@ gimp_operation_config_register (Gimp *gimp,
g_hash_table_insert (config_types, g_hash_table_insert (config_types,
g_strdup (operation), g_strdup (operation),
(gpointer) config_type); (gpointer) config_type);
} }
GType GType
gimp_operation_config_get_type (Gimp *gimp, gimp_operation_config_get_type (Gimp *gimp,
@ -278,6 +118,8 @@ gimp_operation_config_get_type (Gimp *gimp,
g_return_val_if_fail (GIMP_IS_GIMP (gimp), G_TYPE_NONE); g_return_val_if_fail (GIMP_IS_GIMP (gimp), G_TYPE_NONE);
g_return_val_if_fail (operation != NULL, G_TYPE_NONE); g_return_val_if_fail (operation != NULL, G_TYPE_NONE);
g_return_val_if_fail (g_type_is_a (parent_type, GIMP_TYPE_OBJECT),
G_TYPE_NONE);
config_types = gimp_operation_config_get_type_table (gimp); config_types = gimp_operation_config_get_type_table (gimp);
@ -285,59 +127,51 @@ gimp_operation_config_get_type (Gimp *gimp,
if (! config_type) if (! config_type)
{ {
GTypeQuery query; GParamSpec **pspecs;
guint n_pspecs;
gchar *type_name;
gint i, j;
g_return_val_if_fail (g_type_is_a (parent_type, GIMP_TYPE_OBJECT), pspecs = gegl_operation_list_properties (operation, &n_pspecs);
G_TYPE_NONE);
g_type_query (parent_type, &query); for (i = 0, j = 0; i < n_pspecs; i++)
{
GTypeInfo info =
{ {
query.class_size, GParamSpec *pspec = pspecs[i];
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gimp_operation_config_class_init,
NULL, /* class_finalize */
operation,
query.instance_size,
0, /* n_preallocs */
(GInstanceInitFunc) NULL,
};
const GInterfaceInfo config_info = if ((pspec->flags & G_PARAM_READABLE) &&
(pspec->flags & G_PARAM_WRITABLE) &&
strcmp (pspec->name, "input") &&
strcmp (pspec->name, "output"))
{
pspecs[j] = pspec;
j++;
}
}
n_pspecs = j;
type_name = g_strdup_printf ("GimpGegl-%s-config", operation);
g_strcanon (type_name,
G_CSET_DIGITS "-" G_CSET_a_2_z G_CSET_A_2_Z, '-');
config_type = gimp_config_type_register (parent_type,
type_name,
pspecs, n_pspecs);
g_free (pspecs);
g_free (type_name);
if (icon_name && g_type_is_a (config_type, GIMP_TYPE_VIEWABLE))
{ {
(GInterfaceInitFunc) gimp_operation_config_config_iface_init, GimpViewableClass *viewable_class = g_type_class_ref (config_type);
NULL, /* interface_finalize */
NULL /* interface_data */
};
gchar *type_name = g_strdup_printf ("GimpGegl-%s-config", viewable_class->default_icon_name = g_strdup (icon_name);
operation);
g_strcanon (type_name, g_type_class_unref (viewable_class);
G_CSET_DIGITS "-" G_CSET_a_2_z G_CSET_A_2_Z, '-'); }
config_type = g_type_register_static (parent_type, type_name, gimp_operation_config_register (gimp, operation, config_type);
&info, 0);
g_free (type_name);
g_type_add_interface_static (config_type, GIMP_TYPE_CONFIG,
&config_info);
if (icon_name && g_type_is_a (config_type, GIMP_TYPE_VIEWABLE))
{
GimpViewableClass *viewable_class = g_type_class_ref (config_type);
viewable_class->default_icon_name = g_strdup (icon_name);
g_type_class_unref (viewable_class);
}
gimp_operation_config_register (gimp, operation, config_type);
}
} }
return config_type; return config_type;

View File

@ -8,6 +8,7 @@ libgimpconfig_introspectable_headers = \
../libgimpconfig/gimpconfig-error.h \ ../libgimpconfig/gimpconfig-error.h \
../libgimpconfig/gimpconfig-params.h \ ../libgimpconfig/gimpconfig-params.h \
../libgimpconfig/gimpconfig-path.h \ ../libgimpconfig/gimpconfig-path.h \
../libgimpconfig/gimpconfig-register.h \
../libgimpconfig/gimpconfig-serialize.h \ ../libgimpconfig/gimpconfig-serialize.h \
../libgimpconfig/gimpconfig-utils.h \ ../libgimpconfig/gimpconfig-utils.h \
../libgimpconfig/gimpconfigwriter.h \ ../libgimpconfig/gimpconfigwriter.h \
@ -20,6 +21,7 @@ libgimpconfig_introspectable = \
../libgimpconfig/gimpconfig-error.c \ ../libgimpconfig/gimpconfig-error.c \
../libgimpconfig/gimpconfig-path.c \ ../libgimpconfig/gimpconfig-path.c \
../libgimpconfig/gimpconfig-params.c \ ../libgimpconfig/gimpconfig-params.c \
../libgimpconfig/gimpconfig-register.c \
../libgimpconfig/gimpconfig-serialize.c \ ../libgimpconfig/gimpconfig-serialize.c \
../libgimpconfig/gimpconfig-utils.c \ ../libgimpconfig/gimpconfig-utils.c \
../libgimpconfig/gimpconfigwriter.c \ ../libgimpconfig/gimpconfigwriter.c \

View File

@ -0,0 +1,269 @@
/* LIBGIMP - The GIMP Library
* Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball
*
* gimpconfig-register.c
* Copyright (C) 2008-2019 Michael Natterer <mitch@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "libgimpbase/gimpbase.h"
#include "gimpconfig.h"
/* local function prototypes */
static void gimp_config_class_init (GObjectClass *klass,
GParamSpec **pspecs);
static void gimp_config_config_iface_init (GimpConfigInterface *iface);
static void gimp_config_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_config_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static gboolean gimp_config_equal (GimpConfig *a,
GimpConfig *b);
static GValue * gimp_config_value_get (GObject *object,
GParamSpec *pspec);
static GValue * gimp_config_value_new (GParamSpec *pspec);
static void gimp_config_value_free (GValue *value);
/* public functions */
/**
* gimp_config_type_register:
* @parent_type: type from which this type will be derived
* @type_name: string used as the name of the new type
* @pspecs: array of #GParamSpec to install as properties on the new type
* @n_pspecs: the number of param specs in @pspecs
*
* This function is a fancy wrapper around g_type_register_static().
* It creates a new object type as subclass of @parent_type, installs
* @pspecs on it and makes the new type implement the #GimpConfig
* interface.
*
* Returns: the newly registered #GType
*
* Since: 3.0
**/
GType
gimp_config_type_register (GType parent_type,
const gchar *type_name,
GParamSpec **pspecs,
gint n_pspecs)
{
GParamSpec **terminated_pspecs;
GTypeQuery query;
GType config_type;
g_return_val_if_fail (g_type_is_a (parent_type, G_TYPE_OBJECT), G_TYPE_NONE);
g_return_val_if_fail (type_name != NULL, G_TYPE_NONE);
g_return_val_if_fail (pspecs != NULL, G_TYPE_NONE);
g_return_val_if_fail (n_pspecs > 0, G_TYPE_NONE);
terminated_pspecs = g_new0 (GParamSpec *, n_pspecs + 1);
memcpy (terminated_pspecs, pspecs, sizeof (GParamSpec *) * n_pspecs);
g_type_query (parent_type, &query);
{
GTypeInfo info =
{
query.class_size,
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gimp_config_class_init,
NULL, /* class_finalize */
terminated_pspecs,
query.instance_size,
0, /* n_preallocs */
(GInstanceInitFunc) NULL,
};
const GInterfaceInfo config_info =
{
(GInterfaceInitFunc) gimp_config_config_iface_init,
NULL, /* interface_finalize */
NULL /* interface_data */
};
config_type = g_type_register_static (parent_type, type_name,
&info, 0);
g_type_add_interface_static (config_type, GIMP_TYPE_CONFIG,
&config_info);
}
return config_type;
}
/* private functions */
static void
gimp_config_class_init (GObjectClass *klass,
GParamSpec **pspecs)
{
gint i;
klass->set_property = gimp_config_set_property;
klass->get_property = gimp_config_get_property;
for (i = 0; pspecs[i] != NULL; i++)
{
GParamSpec *pspec = pspecs[i];
GParamSpec *copy = gimp_config_param_spec_duplicate (pspec);
if (copy)
{
g_object_class_install_property (klass, i + 1, copy);
}
else if (! G_IS_PARAM_SPEC_OBJECT (pspec) &&
! G_IS_PARAM_SPEC_POINTER (pspec))
{
/* silently ignore object properties */
g_warning ("%s: not supported: %s (%s)\n", G_STRFUNC,
g_type_name (G_TYPE_FROM_INSTANCE (pspec)), pspec->name);
}
}
}
static void
gimp_config_config_iface_init (GimpConfigInterface *iface)
{
iface->equal = gimp_config_equal;
}
static void
gimp_config_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GValue *val = gimp_config_value_get (object, pspec);
g_value_copy (value, val);
}
static void
gimp_config_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GValue *val = gimp_config_value_get (object, pspec);
g_value_copy (val, value);
}
static gboolean
gimp_config_equal (GimpConfig *a,
GimpConfig *b)
{
GList *diff;
gboolean equal = TRUE;
diff = gimp_config_diff (G_OBJECT (a), G_OBJECT (b),
GIMP_CONFIG_PARAM_SERIALIZE);
if (G_TYPE_FROM_INSTANCE (a) == G_TYPE_FROM_INSTANCE (b))
{
GList *list;
for (list = diff; list; list = g_list_next (list))
{
GParamSpec *pspec = list->data;
if (pspec->owner_type == G_TYPE_FROM_INSTANCE (a))
{
equal = FALSE;
break;
}
}
}
else if (diff)
{
equal = FALSE;
}
g_list_free (diff);
return equal;
}
static GValue *
gimp_config_value_get (GObject *object,
GParamSpec *pspec)
{
GHashTable *properties;
GValue *value;
properties = g_object_get_data (object, "gimp-config-properties");
if (! properties)
{
properties =
g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) gimp_config_value_free);
g_object_set_data_full (object, "gimp-config-properties", properties,
(GDestroyNotify) g_hash_table_unref);
}
value = g_hash_table_lookup (properties, pspec->name);
if (! value)
{
value = gimp_config_value_new (pspec);
g_hash_table_insert (properties, g_strdup (pspec->name), value);
}
return value;
}
static GValue *
gimp_config_value_new (GParamSpec *pspec)
{
GValue *value = g_slice_new0 (GValue);
g_value_init (value, pspec->value_type);
g_param_value_set_default (pspec, value);
return value;
}
static void
gimp_config_value_free (GValue *value)
{
g_value_unset (value);
g_slice_free (GValue, value);
}

View File

@ -0,0 +1,42 @@
/* LIBGIMP - The GIMP Library
* Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball
*
* gimpconfig-register.c
* Copyright (C) 2008-2019 Michael Natterer <mitch@gimp.org>
*
* This library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__GIMP_CONFIG_H_INSIDE__) && !defined (GIMP_CONFIG_COMPILATION)
#error "Only <libgimpconfig/gimpconfig.h> can be included directly."
#endif
#ifndef __GIMP_CONFIG_REGISTER_H__
#define __GIMP_CONFIG_REGISTER_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
GType gimp_config_type_register (GType parent_type,
const gchar *type_name,
GParamSpec **pspecs,
gint n_pspecs);
G_END_DECLS
#endif /* __GIMP_CONFIG_REGISTER_H__ */

View File

@ -35,11 +35,11 @@ EXPORTS
gimp_config_error_quark gimp_config_error_quark
gimp_config_get_type gimp_config_get_type
gimp_config_is_equal_to gimp_config_is_equal_to
gimp_config_param_spec_duplicate
gimp_config_path_expand gimp_config_path_expand
gimp_config_path_expand_to_files gimp_config_path_expand_to_files
gimp_config_path_get_type gimp_config_path_get_type
gimp_config_path_unexpand gimp_config_path_unexpand
gimp_config_param_spec_duplicate
gimp_config_reset gimp_config_reset
gimp_config_reset_properties gimp_config_reset_properties
gimp_config_reset_property gimp_config_reset_property
@ -56,6 +56,7 @@ EXPORTS
gimp_config_serialize_value gimp_config_serialize_value
gimp_config_string_append_escaped gimp_config_string_append_escaped
gimp_config_sync gimp_config_sync
gimp_config_type_register
gimp_config_writer_close gimp_config_writer_close
gimp_config_writer_comment gimp_config_writer_comment
gimp_config_writer_comment_mode gimp_config_writer_comment_mode

View File

@ -23,14 +23,15 @@
#include <libgimpconfig/gimpconfigtypes.h> #include <libgimpconfig/gimpconfigtypes.h>
#include <libgimpconfig/gimpconfigwriter.h>
#include <libgimpconfig/gimpconfig-iface.h>
#include <libgimpconfig/gimpconfig-error.h>
#include <libgimpconfig/gimpconfig-serialize.h>
#include <libgimpconfig/gimpconfig-deserialize.h> #include <libgimpconfig/gimpconfig-deserialize.h>
#include <libgimpconfig/gimpconfig-utils.h> #include <libgimpconfig/gimpconfig-error.h>
#include <libgimpconfig/gimpconfig-iface.h>
#include <libgimpconfig/gimpconfig-params.h> #include <libgimpconfig/gimpconfig-params.h>
#include <libgimpconfig/gimpconfig-path.h> #include <libgimpconfig/gimpconfig-path.h>
#include <libgimpconfig/gimpconfig-register.h>
#include <libgimpconfig/gimpconfig-serialize.h>
#include <libgimpconfig/gimpconfig-utils.h>
#include <libgimpconfig/gimpconfigwriter.h>
#include <libgimpconfig/gimpscanner.h> #include <libgimpconfig/gimpscanner.h>
#include <libgimpconfig/gimpcolorconfig.h> #include <libgimpconfig/gimpcolorconfig.h>

View File

@ -19,8 +19,9 @@ libgimpconfig_sources_introspectable = files(
'gimpconfig-deserialize.c', 'gimpconfig-deserialize.c',
'gimpconfig-error.c', 'gimpconfig-error.c',
'gimpconfig-iface.c', 'gimpconfig-iface.c',
'gimpconfig-path.c',
'gimpconfig-params.c', 'gimpconfig-params.c',
'gimpconfig-path.c',
'gimpconfig-register.c',
'gimpconfig-serialize.c', 'gimpconfig-serialize.c',
'gimpconfig-utils.c', 'gimpconfig-utils.c',
'gimpconfigwriter.c', 'gimpconfigwriter.c',
@ -39,6 +40,7 @@ libgimpconfig_headers_introspectable = files(
'gimpconfig-iface.h', 'gimpconfig-iface.h',
'gimpconfig-params.h', 'gimpconfig-params.h',
'gimpconfig-path.h', 'gimpconfig-path.h',
'gimpconfig-register.h',
'gimpconfig-serialize.h', 'gimpconfig-serialize.h',
'gimpconfig-utils.h', 'gimpconfig-utils.h',
'gimpconfigenums.h', 'gimpconfigenums.h',