operation: massive refactoring of how operation meta data is handled

Operations can now hold arbitrary string based key/value pairs, this
permits dynamically extending what is stored without needing to break
API/ABI, it also means we can encode things like gimp menu paths or
similar.
parent 8048343e
...@@ -48,6 +48,8 @@ G_DEFINE_TYPE (GeglOperation, gegl_operation, G_TYPE_OBJECT) ...@@ -48,6 +48,8 @@ G_DEFINE_TYPE (GeglOperation, gegl_operation, G_TYPE_OBJECT)
static void static void
gegl_operation_class_init (GeglOperationClass *klass) gegl_operation_class_init (GeglOperationClass *klass)
{ {
/* XXX: leaked for now, should replace G_DEFINE_TYPE with the expanded one */
klass->keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
klass->name = NULL; /* an operation class with klass->name = NULL; /* an operation class with
* name == NULL is not * name == NULL is not
* included when doing * included when doing
...@@ -55,8 +57,6 @@ gegl_operation_class_init (GeglOperationClass *klass) ...@@ -55,8 +57,6 @@ gegl_operation_class_init (GeglOperationClass *klass)
* name * name
*/ */
klass->compat_name = NULL; klass->compat_name = NULL;
klass->description = NULL;
klass->categories = NULL;
klass->attach = attach; klass->attach = attach;
klass->prepare = NULL; klass->prepare = NULL;
klass->no_cache = FALSE; klass->no_cache = FALSE;
...@@ -458,3 +458,119 @@ gegl_operation_invalidate (GeglOperation *operation, ...@@ -458,3 +458,119 @@ gegl_operation_invalidate (GeglOperation *operation,
gegl_node_invalidated (node, roi, TRUE); gegl_node_invalidated (node, roi, TRUE);
} }
gchar **
gegl_operation_list_keys (const gchar *operation_name,
guint *n_keys)
{
GType type;
GObjectClass *klass;
GList *list, *l;
gchar **ret;
int count;
int i;
type = gegl_operation_gtype_from_name (operation_name);
if (!type)
{
if (n_keys)
*n_keys = 0;
return NULL;
}
klass = g_type_class_ref (type);
count = g_hash_table_size (GEGL_OPERATION_CLASS (klass)->keys);
ret = g_malloc0 (sizeof (gpointer) * (count + 1));
list = g_hash_table_get_keys (GEGL_OPERATION_CLASS (klass)->keys);
for (i = 0, l = list; l; l = l->next)
{
ret[i] = l->data;
}
g_list_free (list);
if (n_keys)
*n_keys = count;
g_type_class_unref (klass);
return ret;
}
void
gegl_operation_class_set_key (GeglOperationClass *klass,
const gchar *key_name,
const gchar *key_value)
{
if (!strcmp (key_name, "name"))
{
if (klass->name)
{
g_warning ("tried changing name of op %s to %s",
klass->name, key_value);
return;
}
klass->name = g_strdup (key_value);
}
if (key_value)
g_hash_table_remove (klass->keys, key_name);
else
g_hash_table_insert (klass->keys, g_strdup (key_name),
g_strdup (key_value));
}
void
gegl_operation_class_set_keys (GeglOperationClass *klass,
const gchar *key_name,
...)
{
va_list var_args;
va_start (var_args, key_name);
while (key_name)
{
const char *value = va_arg (var_args, char *);
gegl_operation_class_set_key (klass, key_name, value);
key_name = va_arg (var_args, char *);
}
va_end (var_args);
}
void
gegl_operation_set_key (const gchar *operation_name,
const gchar *key_name,
const gchar *key_value)
{
GType type;
GObjectClass *klass;
type = gegl_operation_gtype_from_name (operation_name);
if (!type)
return;
klass = g_type_class_ref (type);
gegl_operation_class_set_key (GEGL_OPERATION_CLASS (klass), key_name, key_value);
g_type_class_unref (klass);
}
const gchar *
gegl_operation_class_get_key (GeglOperationClass *operation_class,
const gchar *key_name)
{
const gchar *ret = NULL;
ret = g_hash_table_lookup (GEGL_OPERATION_CLASS (operation_class)->keys, key_name);
return ret;
}
const gchar *
gegl_operation_get_key (const gchar *operation_name,
const gchar *key_name)
{
GType type;
GObjectClass *klass;
const gchar *ret = NULL;
type = gegl_operation_gtype_from_name (operation_name);
if (!type)
{
return NULL;
}
klass = g_type_class_ref (type);
ret = gegl_operation_class_get_key (GEGL_OPERATION_CLASS (klass), key_name);
g_type_class_unref (klass);
return ret;
}
...@@ -75,27 +75,11 @@ struct _GeglOperationClass ...@@ -75,27 +75,11 @@ struct _GeglOperationClass
{ {
GObjectClass parent_class; GObjectClass parent_class;
const gchar *name; /* name(string) used to create/indetify const gchar *name; /* name(string) used to create/identify
this type of operation in GEGL*/ this type of operation in GEGL*/
const gchar *compat_name; /* allows specifying an alias that the op is const gchar *compat_name; /* allows specifying an alias that the op is
also known as */ also known as */
const gchar *categories; /* a colon seperated list of categories */ GHashTable *keys; /* hashtable used for storing meta-data about an op */
const gchar *description; /* textual description of the operation */
const gchar *help; /* documentation for the use of the op and it's properties
(individual properties are documented in-place with the
property)
*/
const gchar *sample_graph;/* sample XML graph using a stock set of images
for inputs, providing a visual preview of how the op is
to be used.
*/
const gchar *authors; /* credits for having written the op */
const gchar *license; /* license of the op */
guint no_cache :1; /* do not create a cache for this operation */ guint no_cache :1; /* do not create a cache for this operation */
guint opencl_support:1; guint opencl_support:1;
...@@ -232,9 +216,31 @@ const gchar * gegl_operation_get_name (GeglOperation *operation); ...@@ -232,9 +216,31 @@ const gchar * gegl_operation_get_name (GeglOperation *operation);
GeglNode * gegl_operation_get_source_node (GeglOperation *operation, GeglNode * gegl_operation_get_source_node (GeglOperation *operation,
const gchar *pad_name); const gchar *pad_name);
/* XXX: should be changed to gegl_op_list_properties */
GParamSpec ** gegl_list_properties (const gchar *operation_type, GParamSpec ** gegl_list_properties (const gchar *operation_type,
guint *n_properties_p); guint *n_properties_p);
/* API to change */
void gegl_operation_class_set_key (GeglOperationClass *klass,
const gchar *key_name,
const gchar *key_value);
const gchar * gegl_operation_class_get_key (GeglOperationClass *operation_class,
const gchar *key_name);
void gegl_operation_class_set_keys (GeglOperationClass *klass,
const gchar *key_name,
...);
gchar ** gegl_operation_list_keys (const gchar *operation_type,
guint *n_keys);
void gegl_operation_set_key (const gchar *operation_type,
const gchar *key_name,
const gchar *key_value);
const gchar * gegl_operation_get_key (const gchar *operation_type,
const gchar *key_name);
/* invalidate a specific rectangle, indicating the any computation depending /* invalidate a specific rectangle, indicating the any computation depending
* on this roi is now invalid. * on this roi is now invalid.
......
...@@ -187,12 +187,13 @@ op_affine_class_init (OpAffineClass *klass) ...@@ -187,12 +187,13 @@ op_affine_class_init (OpAffineClass *klass)
op_class->get_required_for_output = gegl_affine_get_required_for_output; op_class->get_required_for_output = gegl_affine_get_required_for_output;
op_class->detect = gegl_affine_detect; op_class->detect = gegl_affine_detect;
op_class->process = gegl_affine_process; op_class->process = gegl_affine_process;
op_class->categories = "transform";
op_class->prepare = gegl_affine_prepare; op_class->prepare = gegl_affine_prepare;
op_class->no_cache = TRUE; op_class->no_cache = TRUE;
klass->create_matrix = NULL; klass->create_matrix = NULL;
gegl_operation_class_set_key (op_class, "categories", "transform");
g_object_class_install_property (gobject_class, PROP_ORIGIN_X, g_object_class_install_property (gobject_class, PROP_ORIGIN_X,
g_param_spec_double ( g_param_spec_double (
"origin-x", "origin-x",
......
...@@ -276,13 +276,15 @@ gegl_chant_class_init (ChantClass * klass) ...@@ -276,13 +276,15 @@ gegl_chant_class_init (ChantClass * klass)
class_init (operation_class); class_init (operation_class);
#endif #endif
#if 1
#define M_GEGL_CHANT_SET_NAME_EXTENDED(nam) \ #define M_GEGL_CHANT_SET_NAME_EXTENDED(nam) \
operation_class->name=g_strdup("gegl:"#nam); operation_class->name=g_strdup("gegl:"#nam);
#define M_GEGL_CHANT_SET_NAME(name) M_GEGL_CHANT_SET_NAME_EXTENDED(name) #define M_GEGL_CHANT_SET_NAME(name) M_GEGL_CHANT_SET_NAME_EXTENDED(name)
M_GEGL_CHANT_SET_NAME (GEGL_CHANT_NAME); M_GEGL_CHANT_SET_NAME (GEGL_CHANT_NAME);
#endif
#ifdef GEGL_CHANT_DESCRIPTION #ifdef GEGL_CHANT_DESCRIPTION
operation_class->description = GEGL_CHANT_DESCRIPTION; gegl_operation_class_set_key (operation_class, "description", GEGL_CHANT_DESCRIPTION);
#endif #endif
#define gegl_chant_int(name, min, max, def, blurb) \ #define gegl_chant_int(name, min, max, def, blurb) \
......
...@@ -178,12 +178,14 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -178,12 +178,14 @@ gegl_chant_class_init (GeglChantClass *klass)
filter_class->process = process; filter_class->process = process;
operation_class->prepare = prepare; operation_class->prepare = prepare;
operation_class->name = "gegl:bilateral-filter"; gegl_operation_class_set_keys (operation_class,
operation_class->categories = "misc"; "name", "gegl:bilateral-filter",
operation_class->description = "categories", "misc",
"description",
_("An edge preserving blur filter that can be used for noise reduction. " _("An edge preserving blur filter that can be used for noise reduction. "
"It is a gaussian blur where the contribution of neighbourhood pixels " "It is a gaussian blur where the contribution of neighbourhood pixels "
"are weighted by the color difference from the center pixel."); "are weighted by the color difference from the center pixel."),
NULL);
} }
#endif #endif
...@@ -407,11 +407,11 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -407,11 +407,11 @@ gegl_chant_class_init (GeglChantClass *klass)
filter_class->process = process; filter_class->process = process;
operation_class->prepare = prepare; operation_class->prepare = prepare;
operation_class->categories = "blur"; gegl_operation_class_set_keys (operation_class,
operation_class->name = "gegl:box-blur"; "name", "gegl:box-blur",
operation_class->opencl_support = TRUE; "categories", "blur",
operation_class->description = "description", _("Performs an averaging of a square box of pixels."),
_("Performs an averaging of a square box of pixels."); NULL);
} }
#endif #endif
...@@ -190,14 +190,13 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -190,14 +190,13 @@ gegl_chant_class_init (GeglChantClass *klass)
/* specify the name this operation is found under in the GUI/when /* specify the name this operation is found under in the GUI/when
* programming/in XML * programming/in XML
*/ */
operation_class->name = "gegl:brightness-contrast";
operation_class->opencl_support = TRUE; operation_class->opencl_support = TRUE;
/* a colon separated list of categories/tags for this operations */ gegl_operation_class_set_keys (operation_class,
operation_class->categories = "color"; "name", "gegl:brightness-contrast",
"categories", "color",
/* a description of what this operations does */ "description", _("Changes the light level and contrast."),
operation_class->description = _("Changes the light level and contrast."); NULL);
} }
#endif /* closing #ifdef GEGL_CHANT_PROPERTIES ... else ... */ #endif /* closing #ifdef GEGL_CHANT_PROPERTIES ... else ... */
...@@ -77,10 +77,11 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -77,10 +77,11 @@ gegl_chant_class_init (GeglChantClass *klass)
sink_class->process = process; sink_class->process = process;
sink_class->needs_full = TRUE; sink_class->needs_full = TRUE;
operation_class->name = "gegl:buffer-sink"; gegl_operation_class_set_keys (operation_class,
operation_class->compat_name = "gegl:save-buffer"; "name", "gegl:buffer-sink",
operation_class->categories = "programming:output"; "categories", "programming:output",
operation_class->description = _("A GEGL buffer destination surface."); "description", _("A GEGL buffer destination surface."),
NULL);
} }
#endif #endif
...@@ -110,11 +110,11 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -110,11 +110,11 @@ gegl_chant_class_init (GeglChantClass *klass)
G_OBJECT_CLASS (klass)->dispose = dispose; G_OBJECT_CLASS (klass)->dispose = dispose;
operation_class->name = "gegl:buffer-source"; gegl_operation_class_set_keys (operation_class,
operation_class->compat_name = "gegl:load-buffer"; "name", "gegl:buffer-source",
operation_class->categories = "programming:input"; "categories", "programming:input",
operation_class->description = "description", _("A source that uses an in-memory GeglBuffer, for use internally by GEGL."),
_("A source that uses an in-memory GeglBuffer, for use internally by GEGL."); NULL);
operation_class->no_cache = TRUE; operation_class->no_cache = TRUE;
} }
......
...@@ -186,12 +186,14 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -186,12 +186,14 @@ gegl_chant_class_init (GeglChantClass *klass)
*/ */
operation_class->get_bounding_box = get_bounding_box; operation_class->get_bounding_box = get_bounding_box;
operation_class->name = "gegl:c2g"; gegl_operation_class_set_keys (operation_class,
operation_class->categories = "enhance"; "name", "gegl:c2g",
operation_class->description = "categories", "enhance",
"description",
_("Color to grayscale conversion, uses envelopes formed from spatial " _("Color to grayscale conversion, uses envelopes formed from spatial "
" color differences to perform color-feature preserving grayscale " " color differences to perform color-feature preserving grayscale "
" spatial contrast enhancement."); " spatial contrast enhancement."),
NULL);
} }
#endif #endif
...@@ -140,9 +140,11 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -140,9 +140,11 @@ gegl_chant_class_init (GeglChantClass *klass)
operation_class->get_bounding_box = get_bounding_box; operation_class->get_bounding_box = get_bounding_box;
operation_class->prepare = prepare; operation_class->prepare = prepare;
operation_class->name = "gegl:checkerboard"; gegl_operation_class_set_keys (operation_class,
operation_class->categories = "render"; "name", "gegl:checkerboard",
operation_class->description = _("Checkerboard renderer"); "categories", "render",
"description", _("Checkerboard renderer"),
NULL);
} }
#endif #endif
...@@ -254,15 +254,17 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -254,15 +254,17 @@ gegl_chant_class_init (GeglChantClass *klass)
object_class->notify = notify; object_class->notify = notify;
operation_class->prepare = prepare; operation_class->prepare = prepare;
operation_class->opencl_support = TRUE;
point_filter_class->process = process; point_filter_class->process = process;
point_filter_class->cl_process = cl_process; point_filter_class->cl_process = cl_process;
operation_class->name = "gegl:color-temperature"; gegl_operation_class_set_keys (operation_class,
operation_class->opencl_support = TRUE; "name" , "gegl:color-temperature",
operation_class->categories = "color"; "categories" , "color",
operation_class->description = "description",
_("Allows changing the color temperature of an image."); _("Allows changing the color temperature of an image."),
NULL);
} }
/* Coefficients of rational functions of degree 5 fitted per color channel to /* Coefficients of rational functions of degree 5 fitted per color channel to
......
...@@ -164,9 +164,11 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -164,9 +164,11 @@ gegl_chant_class_init (GeglChantClass *klass)
filter_class->process = process; filter_class->process = process;
operation_class->prepare = prepare; operation_class->prepare = prepare;
operation_class->categories = "color"; gegl_operation_class_set_keys (operation_class,
operation_class->name = "gegl:color-to-alpha"; "name" , "gegl:color-to-alpha",
operation_class->description = _("Performs color-to-alpha on the image."); "categories" , "color",
"description", _("Performs color-to-alpha on the image."),
NULL);
} }
#endif #endif
...@@ -81,11 +81,13 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -81,11 +81,13 @@ gegl_chant_class_init (GeglChantClass *klass)
operation_class->get_bounding_box = gegl_color_op_get_bounding_box; operation_class->get_bounding_box = gegl_color_op_get_bounding_box;
operation_class->prepare = gegl_color_op_prepare; operation_class->prepare = gegl_color_op_prepare;
operation_class->name = "gegl:color"; gegl_operation_class_set_keys (operation_class,
operation_class->categories = "render"; "name" , "gegl:color",
operation_class->description = "categories" , "render",
"description",
_("Generates a buffer entirely filled with the specified color, " _("Generates a buffer entirely filled with the specified color, "
"crop it to get smaller dimensions."); "crop it to get smaller dimensions."),
NULL);
} }
#endif #endif
...@@ -118,10 +118,12 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -118,10 +118,12 @@ gegl_chant_class_init (GeglChantClass *klass)
point_filter_class->process = process; point_filter_class->process = process;
operation_class->prepare = prepare; operation_class->prepare = prepare;
operation_class->name = "gegl:contrast-curve"; gegl_operation_class_set_keys (operation_class,
operation_class->categories = "color"; "name" , "gegl:contrast-curve",
operation_class->description = "categories" , "color",
_("Adjusts the contrast of the image according to a curve."); "description",
_("Adjusts the contrast of the image according to a curve."),
NULL);
} }
#endif #endif
...@@ -92,10 +92,12 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -92,10 +92,12 @@ gegl_chant_class_init (GeglChantClass *klass)
operation_class = GEGL_OPERATION_CLASS (klass); operation_class = GEGL_OPERATION_CLASS (klass);
operation_class->attach = attach; operation_class->attach = attach;
operation_class->name = "gegl:difference-of-gaussians"; gegl_operation_class_set_keys (operation_class,
operation_class->categories = "meta:edge"; "name" , "gegl:difference-of-gaussians",
operation_class->description = "categories" , "meta:edge",
_("Does an edge detection based on the difference of two gaussian blurs."); "description",
_("Does an edge detection based on the difference of two gaussian blurs."),
NULL);
} }
#endif #endif
...@@ -135,9 +135,11 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -135,9 +135,11 @@ gegl_chant_class_init (GeglChantClass *klass)
sink_class->needs_full = TRUE; sink_class->needs_full = TRUE;
operation_class->name = "gegl:display"; gegl_operation_class_set_keys (operation_class,
operation_class->categories = "meta:display"; "name" , "gegl:display",
operation_class->description = "categories" , "meta:display",
_("Display the input buffer in a window."); "description" ,
_("Display the input buffer in a window."),
NULL);
} }
#endif #endif
...@@ -75,10 +75,12 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -75,10 +75,12 @@ gegl_chant_class_init (GeglChantClass *klass)
operation_class = GEGL_OPERATION_CLASS (klass); operation_class = GEGL_OPERATION_CLASS (klass);
operation_class->attach = attach; operation_class->attach = attach;
operation_class->name = "gegl:dropshadow"; gegl_operation_class_set_keys (operation_class,
operation_class->categories = "meta:effects"; "name" , "gegl:dropshadow",
operation_class->description = "categories" , "meta:effects",
_("Creates a dropshadow effect on the input buffer."); "description",
_("Creates a dropshadow effect on the input buffer."),
NULL);
} }
#endif #endif
...@@ -238,10 +238,12 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -238,10 +238,12 @@ gegl_chant_class_init (GeglChantClass *klass)
filter_class->process = process; filter_class->process = process;
operation_class->prepare = prepare; operation_class->prepare = prepare;
operation_class->name = "gegl:edge-laplace"; gegl_operation_class_set_keys (operation_class,
operation_class->categories = "edge-detect"; "name" , "gegl:edge-laplace",
operation_class->description = "categories" , "edge-detect",
_("High-resolution edge detection"); "description" ,
_("High-resolution edge detection"),
NULL);
} }
#endif #endif
...@@ -196,10 +196,12 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -196,10 +196,12 @@ gegl_chant_class_init (GeglChantClass *klass)
filter_class->process = process; filter_class->process = process;
operation_class->prepare = prepare; operation_class->prepare = prepare;
operation_class->name = "gegl:edge-sobel"; gegl_operation_class_set_keys (operation_class,
operation_class->categories = "edge-detect"; "name" , "gegl:edge-sobel",
operation_class->description = "categories" , "edge-detect",
_("Specialized direction-dependent edge detection"); "description",
_("Specialized direction-dependent edge detection"),
NULL);
} }
#endif #endif
...@@ -1283,13 +1283,15 @@ gegl_chant_class_init (GeglChantClass *klass) ...@@ -1283,13 +1283,15 @@ gegl_chant_class_init (GeglChantClass *klass)
operation_class->get_bounding_box = gegl_expcombine_get_bounding_box; operation_class->get_bounding_box = gegl_expcombine_get_bounding_box;
operation_class->get_cached_region = gegl_expcombine_get_cached_region; operation_class->get_cached_region = gegl_expcombine_get_cached_region;
operation_class->prepare = gegl_expcombine_prepare;
operation_class->get_required_for_output = gegl_expcombine_get_required_for_output; operation_class->get_required_for_output = gegl_expcombine_get_required_for_output;
operation_class->name = "gegl:exp-combine"; gegl_operation_class_set_keys (operation_class,
operation_class->categories = "compositors"; "name" , "gegl:exp-combine",
operation_class->description = "categories" , "compositors",
_("Combine multiple scene exposures into one high range buffer"); "description",
operation_class->prepare = gegl_expcombine_prepare; _("Combine multiple scene exposures into one high range buffer"),