summaryrefslogtreecommitdiffstats
path: root/app/pdb/gimpprocedure.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 03:13:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 03:13:10 +0000
commit3c57dd931145d43f2b0aef96c4d178135956bf91 (patch)
tree3de698981e9f0cc2c4f9569b19a5f3595e741f6b /app/pdb/gimpprocedure.c
parentInitial commit. (diff)
downloadgimp-3c57dd931145d43f2b0aef96c4d178135956bf91.tar.xz
gimp-3c57dd931145d43f2b0aef96c4d178135956bf91.zip
Adding upstream version 2.10.36.upstream/2.10.36
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'app/pdb/gimpprocedure.c')
-rw-r--r--app/pdb/gimpprocedure.c897
1 files changed, 897 insertions, 0 deletions
diff --git a/app/pdb/gimpprocedure.c b/app/pdb/gimpprocedure.c
new file mode 100644
index 0000000..a12dab9
--- /dev/null
+++ b/app/pdb/gimpprocedure.c
@@ -0,0 +1,897 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <sys/types.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gegl.h>
+
+#include "libgimpbase/gimpbase.h"
+
+#include "pdb-types.h"
+
+#include "core/gimp.h"
+#include "core/gimp-memsize.h"
+#include "core/gimpchannel.h"
+#include "core/gimplayer.h"
+#include "core/gimpparamspecs.h"
+#include "core/gimpprogress.h"
+
+#include "vectors/gimpvectors.h"
+
+#include "gimppdbcontext.h"
+#include "gimppdberror.h"
+#include "gimpprocedure.h"
+
+#include "gimp-intl.h"
+
+
+static void gimp_procedure_finalize (GObject *object);
+
+static gint64 gimp_procedure_get_memsize (GimpObject *object,
+ gint64 *gui_size);
+
+static const gchar * gimp_procedure_real_get_label (GimpProcedure *procedure);
+static const gchar * gimp_procedure_real_get_menu_label (GimpProcedure *procedure);
+static const gchar * gimp_procedure_real_get_blurb (GimpProcedure *procedure);
+static const gchar * gimp_procedure_real_get_help_id (GimpProcedure *procedure);
+static gboolean gimp_procedure_real_get_sensitive (GimpProcedure *procedure,
+ GimpObject *object,
+ const gchar **tooltip);
+static GimpValueArray * gimp_procedure_real_execute (GimpProcedure *procedure,
+ Gimp *gimp,
+ GimpContext *context,
+ GimpProgress *progress,
+ GimpValueArray *args,
+ GError **error);
+static void gimp_procedure_real_execute_async (GimpProcedure *procedure,
+ Gimp *gimp,
+ GimpContext *context,
+ GimpProgress *progress,
+ GimpValueArray *args,
+ GimpObject *display);
+
+static void gimp_procedure_free_strings (GimpProcedure *procedure);
+static gboolean gimp_procedure_validate_args (GimpProcedure *procedure,
+ GParamSpec **param_specs,
+ gint n_param_specs,
+ GimpValueArray *args,
+ gboolean return_vals,
+ GError **error);
+
+
+G_DEFINE_TYPE (GimpProcedure, gimp_procedure, GIMP_TYPE_VIEWABLE)
+
+#define parent_class gimp_procedure_parent_class
+
+
+static void
+gimp_procedure_class_init (GimpProcedureClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
+
+ object_class->finalize = gimp_procedure_finalize;
+
+ gimp_object_class->get_memsize = gimp_procedure_get_memsize;
+
+ klass->get_label = gimp_procedure_real_get_label;
+ klass->get_menu_label = gimp_procedure_real_get_menu_label;
+ klass->get_blurb = gimp_procedure_real_get_blurb;
+ klass->get_help_id = gimp_procedure_real_get_help_id;
+ klass->get_sensitive = gimp_procedure_real_get_sensitive;
+ klass->execute = gimp_procedure_real_execute;
+ klass->execute_async = gimp_procedure_real_execute_async;
+}
+
+static void
+gimp_procedure_init (GimpProcedure *procedure)
+{
+ procedure->proc_type = GIMP_INTERNAL;
+}
+
+static void
+gimp_procedure_finalize (GObject *object)
+{
+ GimpProcedure *procedure = GIMP_PROCEDURE (object);
+ gint i;
+
+ gimp_procedure_free_strings (procedure);
+
+ if (procedure->args)
+ {
+ for (i = 0; i < procedure->num_args; i++)
+ g_param_spec_unref (procedure->args[i]);
+
+ g_clear_pointer (&procedure->args, g_free);
+ }
+
+ if (procedure->values)
+ {
+ for (i = 0; i < procedure->num_values; i++)
+ g_param_spec_unref (procedure->values[i]);
+
+ g_clear_pointer (&procedure->values, g_free);
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gint64
+gimp_procedure_get_memsize (GimpObject *object,
+ gint64 *gui_size)
+{
+ GimpProcedure *procedure = GIMP_PROCEDURE (object);
+ gint64 memsize = 0;
+ gint i;
+
+ if (! procedure->static_strings)
+ {
+ memsize += gimp_string_get_memsize (procedure->original_name);
+ memsize += gimp_string_get_memsize (procedure->blurb);
+ memsize += gimp_string_get_memsize (procedure->help);
+ memsize += gimp_string_get_memsize (procedure->author);
+ memsize += gimp_string_get_memsize (procedure->copyright);
+ memsize += gimp_string_get_memsize (procedure->date);
+ memsize += gimp_string_get_memsize (procedure->deprecated);
+ }
+
+ memsize += procedure->num_args * sizeof (GParamSpec *);
+
+ for (i = 0; i < procedure->num_args; i++)
+ memsize += gimp_g_param_spec_get_memsize (procedure->args[i]);
+
+ memsize += procedure->num_values * sizeof (GParamSpec *);
+
+ for (i = 0; i < procedure->num_values; i++)
+ memsize += gimp_g_param_spec_get_memsize (procedure->values[i]);
+
+ return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
+ gui_size);
+}
+
+static const gchar *
+gimp_procedure_real_get_label (GimpProcedure *procedure)
+{
+ return gimp_object_get_name (procedure); /* lame fallback */
+}
+
+static const gchar *
+gimp_procedure_real_get_menu_label (GimpProcedure *procedure)
+{
+ return gimp_procedure_get_label (procedure);
+}
+
+static const gchar *
+gimp_procedure_real_get_blurb (GimpProcedure *procedure)
+{
+ return procedure->blurb;
+}
+
+static const gchar *
+gimp_procedure_real_get_help_id (GimpProcedure *procedure)
+{
+ return NULL;
+}
+
+static gboolean
+gimp_procedure_real_get_sensitive (GimpProcedure *procedure,
+ GimpObject *object,
+ const gchar **tooltip)
+{
+ return TRUE /* random fallback */;
+}
+
+static GimpValueArray *
+gimp_procedure_real_execute (GimpProcedure *procedure,
+ Gimp *gimp,
+ GimpContext *context,
+ GimpProgress *progress,
+ GimpValueArray *args,
+ GError **error)
+{
+ g_return_val_if_fail (gimp_value_array_length (args) >=
+ procedure->num_args, NULL);
+
+ return procedure->marshal_func (procedure, gimp,
+ context, progress,
+ args, error);
+}
+
+static void
+gimp_procedure_real_execute_async (GimpProcedure *procedure,
+ Gimp *gimp,
+ GimpContext *context,
+ GimpProgress *progress,
+ GimpValueArray *args,
+ GimpObject *display)
+{
+ GimpValueArray *return_vals;
+ GError *error = NULL;
+
+ g_return_if_fail (gimp_value_array_length (args) >= procedure->num_args);
+
+ return_vals = GIMP_PROCEDURE_GET_CLASS (procedure)->execute (procedure,
+ gimp,
+ context,
+ progress,
+ args,
+ &error);
+
+ gimp_value_array_unref (return_vals);
+
+ if (error)
+ {
+ gimp_message_literal (gimp, G_OBJECT (progress), GIMP_MESSAGE_ERROR,
+ error->message);
+ g_error_free (error);
+ }
+}
+
+
+/* public functions */
+
+GimpProcedure *
+gimp_procedure_new (GimpMarshalFunc marshal_func)
+{
+ GimpProcedure *procedure;
+
+ g_return_val_if_fail (marshal_func != NULL, NULL);
+
+ procedure = g_object_new (GIMP_TYPE_PROCEDURE, NULL);
+
+ procedure->marshal_func = marshal_func;
+
+ return procedure;
+}
+
+void
+gimp_procedure_set_strings (GimpProcedure *procedure,
+ const gchar *original_name,
+ const gchar *blurb,
+ const gchar *help,
+ const gchar *author,
+ const gchar *copyright,
+ const gchar *date,
+ const gchar *deprecated)
+{
+ g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
+
+ gimp_procedure_free_strings (procedure);
+
+ procedure->original_name = g_strdup (original_name);
+ procedure->blurb = g_strdup (blurb);
+ procedure->help = g_strdup (help);
+ procedure->author = g_strdup (author);
+ procedure->copyright = g_strdup (copyright);
+ procedure->date = g_strdup (date);
+ procedure->deprecated = g_strdup (deprecated);
+
+ procedure->static_strings = FALSE;
+}
+
+void
+gimp_procedure_set_static_strings (GimpProcedure *procedure,
+ const gchar *original_name,
+ const gchar *blurb,
+ const gchar *help,
+ const gchar *author,
+ const gchar *copyright,
+ const gchar *date,
+ const gchar *deprecated)
+{
+ g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
+
+ gimp_procedure_free_strings (procedure);
+
+ procedure->original_name = (gchar *) original_name;
+ procedure->blurb = (gchar *) blurb;
+ procedure->help = (gchar *) help;
+ procedure->author = (gchar *) author;
+ procedure->copyright = (gchar *) copyright;
+ procedure->date = (gchar *) date;
+ procedure->deprecated = (gchar *) deprecated;
+
+ procedure->static_strings = TRUE;
+}
+
+void
+gimp_procedure_take_strings (GimpProcedure *procedure,
+ gchar *original_name,
+ gchar *blurb,
+ gchar *help,
+ gchar *author,
+ gchar *copyright,
+ gchar *date,
+ gchar *deprecated)
+{
+ g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
+
+ gimp_procedure_free_strings (procedure);
+
+ procedure->original_name = original_name;
+ procedure->blurb = blurb;
+ procedure->help = help;
+ procedure->author = author;
+ procedure->copyright = copyright;
+ procedure->date = date;
+ procedure->deprecated = deprecated;
+
+ procedure->static_strings = FALSE;
+}
+
+const gchar *
+gimp_procedure_get_label (GimpProcedure *procedure)
+{
+ g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+
+ return GIMP_PROCEDURE_GET_CLASS (procedure)->get_label (procedure);
+}
+
+const gchar *
+gimp_procedure_get_menu_label (GimpProcedure *procedure)
+{
+ g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+
+ return GIMP_PROCEDURE_GET_CLASS (procedure)->get_menu_label (procedure);
+}
+
+const gchar *
+gimp_procedure_get_blurb (GimpProcedure *procedure)
+{
+ g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+
+ return GIMP_PROCEDURE_GET_CLASS (procedure)->get_blurb (procedure);
+}
+
+const gchar *
+gimp_procedure_get_help_id (GimpProcedure *procedure)
+{
+ g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+
+ return GIMP_PROCEDURE_GET_CLASS (procedure)->get_help_id (procedure);
+}
+
+gboolean
+gimp_procedure_get_sensitive (GimpProcedure *procedure,
+ GimpObject *object,
+ const gchar **tooltip)
+{
+ const gchar *my_tooltip = NULL;
+ gboolean sensitive;
+
+ g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), FALSE);
+ g_return_val_if_fail (object == NULL || GIMP_IS_OBJECT (object), FALSE);
+
+ sensitive = GIMP_PROCEDURE_GET_CLASS (procedure)->get_sensitive (procedure,
+ object,
+ &my_tooltip);
+
+ if (tooltip)
+ *tooltip = my_tooltip;
+
+ return sensitive;
+}
+
+GimpValueArray *
+gimp_procedure_execute (GimpProcedure *procedure,
+ Gimp *gimp,
+ GimpContext *context,
+ GimpProgress *progress,
+ GimpValueArray *args,
+ GError **error)
+{
+ GimpValueArray *return_vals;
+ GError *pdb_error = NULL;
+
+ g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+ g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
+ g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
+ g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL);
+ g_return_val_if_fail (args != NULL, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ if (! gimp_procedure_validate_args (procedure,
+ procedure->args, procedure->num_args,
+ args, FALSE, &pdb_error))
+ {
+ return_vals = gimp_procedure_get_return_values (procedure, FALSE,
+ pdb_error);
+ g_propagate_error (error, pdb_error);
+
+ return return_vals;
+ }
+
+ if (GIMP_IS_PDB_CONTEXT (context))
+ context = g_object_ref (context);
+ else
+ context = gimp_pdb_context_new (gimp, context, TRUE);
+
+ if (progress)
+ g_object_ref (progress);
+
+ /* call the procedure */
+ return_vals = GIMP_PROCEDURE_GET_CLASS (procedure)->execute (procedure,
+ gimp,
+ context,
+ progress,
+ args,
+ error);
+
+ if (progress)
+ g_object_unref (progress);
+
+ g_object_unref (context);
+
+ if (return_vals)
+ {
+ switch (g_value_get_enum (gimp_value_array_index (return_vals, 0)))
+ {
+ case GIMP_PDB_CALLING_ERROR:
+ case GIMP_PDB_EXECUTION_ERROR:
+ /* If the error has not already been set, construct one
+ * from the error message that is optionally passed with
+ * the return values.
+ */
+ if (error && *error == NULL &&
+ gimp_value_array_length (return_vals) > 1 &&
+ G_VALUE_HOLDS_STRING (gimp_value_array_index (return_vals, 1)))
+ {
+ GValue *value = gimp_value_array_index (return_vals, 1);
+ const gchar *message = g_value_get_string (value);
+
+ if (message)
+ g_set_error_literal (error, GIMP_PDB_ERROR,
+ GIMP_PDB_ERROR_FAILED,
+ message);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ g_warning ("%s: no return values, shouldn't happen", G_STRFUNC);
+
+ pdb_error = g_error_new (GIMP_PDB_ERROR,
+ GIMP_PDB_ERROR_INVALID_RETURN_VALUE,
+ _("Procedure '%s' returned no return values"),
+ gimp_object_get_name (procedure));
+
+ return_vals = gimp_procedure_get_return_values (procedure, FALSE,
+ pdb_error);
+ if (error && *error == NULL)
+ g_propagate_error (error, pdb_error);
+ else
+ g_error_free (pdb_error);
+
+ }
+
+ return return_vals;
+}
+
+void
+gimp_procedure_execute_async (GimpProcedure *procedure,
+ Gimp *gimp,
+ GimpContext *context,
+ GimpProgress *progress,
+ GimpValueArray *args,
+ GimpObject *display,
+ GError **error)
+{
+ g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
+ g_return_if_fail (GIMP_IS_GIMP (gimp));
+ g_return_if_fail (GIMP_IS_CONTEXT (context));
+ g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
+ g_return_if_fail (args != NULL);
+ g_return_if_fail (display == NULL || GIMP_IS_OBJECT (display));
+ g_return_if_fail (error == NULL || *error == NULL);
+
+ if (gimp_procedure_validate_args (procedure,
+ procedure->args, procedure->num_args,
+ args, FALSE, error))
+ {
+ if (GIMP_IS_PDB_CONTEXT (context))
+ context = g_object_ref (context);
+ else
+ context = gimp_pdb_context_new (gimp, context, TRUE);
+
+ if (progress)
+ g_object_ref (progress);
+
+ GIMP_PROCEDURE_GET_CLASS (procedure)->execute_async (procedure, gimp,
+ context, progress,
+ args, display);
+
+ if (progress)
+ g_object_unref (progress);
+
+ g_object_unref (context);
+ }
+}
+
+GimpValueArray *
+gimp_procedure_get_arguments (GimpProcedure *procedure)
+{
+ GimpValueArray *args;
+ GValue value = G_VALUE_INIT;
+ gint i;
+
+ g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+
+ args = gimp_value_array_new (procedure->num_args);
+
+ for (i = 0; i < procedure->num_args; i++)
+ {
+ g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (procedure->args[i]));
+ gimp_value_array_append (args, &value);
+ g_value_unset (&value);
+ }
+
+ return args;
+}
+
+GimpValueArray *
+gimp_procedure_get_return_values (GimpProcedure *procedure,
+ gboolean success,
+ const GError *error)
+{
+ GimpValueArray *args;
+ GValue value = G_VALUE_INIT;
+ gint i;
+
+ g_return_val_if_fail (success == FALSE || GIMP_IS_PROCEDURE (procedure),
+ NULL);
+
+ if (success)
+ {
+ args = gimp_value_array_new (procedure->num_values + 1);
+
+ g_value_init (&value, GIMP_TYPE_PDB_STATUS_TYPE);
+ g_value_set_enum (&value, GIMP_PDB_SUCCESS);
+ gimp_value_array_append (args, &value);
+ g_value_unset (&value);
+
+ for (i = 0; i < procedure->num_values; i++)
+ {
+ g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (procedure->values[i]));
+ gimp_value_array_append (args, &value);
+ g_value_unset (&value);
+ }
+ }
+ else
+ {
+ args = gimp_value_array_new ((error && error->message) ? 2 : 1);
+
+ g_value_init (&value, GIMP_TYPE_PDB_STATUS_TYPE);
+
+ /* errors in the GIMP_PDB_ERROR domain are calling errors */
+ if (error && error->domain == GIMP_PDB_ERROR)
+ {
+ switch ((GimpPdbErrorCode) error->code)
+ {
+ case GIMP_PDB_ERROR_FAILED:
+ case GIMP_PDB_ERROR_PROCEDURE_NOT_FOUND:
+ case GIMP_PDB_ERROR_INVALID_ARGUMENT:
+ case GIMP_PDB_ERROR_INVALID_RETURN_VALUE:
+ case GIMP_PDB_ERROR_INTERNAL_ERROR:
+ g_value_set_enum (&value, GIMP_PDB_CALLING_ERROR);
+ break;
+
+ case GIMP_PDB_ERROR_CANCELLED:
+ g_value_set_enum (&value, GIMP_PDB_CANCEL);
+ break;
+
+ default:
+ gimp_assert_not_reached ();
+ }
+ }
+ else
+ {
+ g_value_set_enum (&value, GIMP_PDB_EXECUTION_ERROR);
+ }
+
+ gimp_value_array_append (args, &value);
+ g_value_unset (&value);
+
+ if (error && error->message)
+ {
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, error->message);
+ gimp_value_array_append (args, &value);
+ g_value_unset (&value);
+ }
+ }
+
+ return args;
+}
+
+void
+gimp_procedure_add_argument (GimpProcedure *procedure,
+ GParamSpec *pspec)
+{
+ g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
+ g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+
+ procedure->args = g_renew (GParamSpec *, procedure->args,
+ procedure->num_args + 1);
+
+ procedure->args[procedure->num_args] = pspec;
+
+ g_param_spec_ref_sink (pspec);
+
+ procedure->num_args++;
+}
+
+void
+gimp_procedure_add_return_value (GimpProcedure *procedure,
+ GParamSpec *pspec)
+{
+ g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
+ g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+
+ procedure->values = g_renew (GParamSpec *, procedure->values,
+ procedure->num_values + 1);
+
+ procedure->values[procedure->num_values] = pspec;
+
+ g_param_spec_ref_sink (pspec);
+
+ procedure->num_values++;
+}
+
+/**
+ * gimp_procedure_create_override:
+ * @procedure:
+ * @new_marshal_func:
+ *
+ * Creates a new GimpProcedure that can be used to override the
+ * existing @procedure.
+ *
+ * Returns: The new #GimpProcedure.
+ **/
+GimpProcedure *
+gimp_procedure_create_override (GimpProcedure *procedure,
+ GimpMarshalFunc new_marshal_func)
+{
+ GimpProcedure *new_procedure = NULL;
+ const gchar *name = NULL;
+ int i = 0;
+
+ new_procedure = gimp_procedure_new (new_marshal_func);
+ name = gimp_object_get_name (procedure);
+
+ gimp_object_set_static_name (GIMP_OBJECT (new_procedure), name);
+
+ for (i = 0; i < procedure->num_args; i++)
+ gimp_procedure_add_argument (new_procedure, procedure->args[i]);
+
+ for (i = 0; i < procedure->num_values; i++)
+ gimp_procedure_add_return_value (new_procedure, procedure->values[i]);
+
+ return new_procedure;
+}
+
+gint
+gimp_procedure_name_compare (GimpProcedure *proc1,
+ GimpProcedure *proc2)
+{
+ /* Assume there always is a name, don't bother with NULL checks */
+ return strcmp (proc1->original_name,
+ proc2->original_name);
+}
+
+/* private functions */
+
+static void
+gimp_procedure_free_strings (GimpProcedure *procedure)
+{
+ if (! procedure->static_strings)
+ {
+ g_free (procedure->original_name);
+ g_free (procedure->blurb);
+ g_free (procedure->help);
+ g_free (procedure->author);
+ g_free (procedure->copyright);
+ g_free (procedure->date);
+ g_free (procedure->deprecated);
+ }
+
+ procedure->original_name = NULL;
+ procedure->blurb = NULL;
+ procedure->help = NULL;
+ procedure->author = NULL;
+ procedure->copyright = NULL;
+ procedure->date = NULL;
+ procedure->deprecated = NULL;
+
+ procedure->static_strings = FALSE;
+}
+
+static gboolean
+gimp_procedure_validate_args (GimpProcedure *procedure,
+ GParamSpec **param_specs,
+ gint n_param_specs,
+ GimpValueArray *args,
+ gboolean return_vals,
+ GError **error)
+{
+ gint i;
+
+ for (i = 0; i < MIN (gimp_value_array_length (args), n_param_specs); i++)
+ {
+ GValue *arg = gimp_value_array_index (args, i);
+ GParamSpec *pspec = param_specs[i];
+ GType arg_type = G_VALUE_TYPE (arg);
+ GType spec_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
+
+ if (arg_type != spec_type)
+ {
+ if (return_vals)
+ {
+ g_set_error (error,
+ GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_RETURN_VALUE,
+ _("Procedure '%s' returned a wrong value type "
+ "for return value '%s' (#%d). "
+ "Expected %s, got %s."),
+ gimp_object_get_name (procedure),
+ g_param_spec_get_name (pspec),
+ i + 1, g_type_name (spec_type),
+ g_type_name (arg_type));
+ }
+ else
+ {
+ g_set_error (error,
+ GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
+ _("Procedure '%s' has been called with a "
+ "wrong value type for argument '%s' (#%d). "
+ "Expected %s, got %s."),
+ gimp_object_get_name (procedure),
+ g_param_spec_get_name (pspec),
+ i + 1, g_type_name (spec_type),
+ g_type_name (arg_type));
+ }
+
+ return FALSE;
+ }
+ else if (! (pspec->flags & GIMP_PARAM_NO_VALIDATE))
+ {
+ GValue string_value = G_VALUE_INIT;
+
+ g_value_init (&string_value, G_TYPE_STRING);
+
+ if (g_value_type_transformable (arg_type, G_TYPE_STRING))
+ g_value_transform (arg, &string_value);
+ else
+ g_value_set_static_string (&string_value,
+ "<not transformable to string>");
+
+ if (g_param_value_validate (pspec, arg))
+ {
+ if (GIMP_IS_PARAM_SPEC_DRAWABLE_ID (pspec) &&
+ g_value_get_int (arg) == -1)
+ {
+ if (return_vals)
+ {
+ g_set_error (error,
+ GIMP_PDB_ERROR,
+ GIMP_PDB_ERROR_INVALID_RETURN_VALUE,
+ _("Procedure '%s' returned an "
+ "invalid ID for argument '%s'. "
+ "Most likely a plug-in is trying "
+ "to work on a layer that doesn't "
+ "exist any longer."),
+ gimp_object_get_name (procedure),
+ g_param_spec_get_name (pspec));
+ }
+ else
+ {
+ g_set_error (error,
+ GIMP_PDB_ERROR,
+ GIMP_PDB_ERROR_INVALID_ARGUMENT,
+ _("Procedure '%s' has been called with an "
+ "invalid ID for argument '%s'. "
+ "Most likely a plug-in is trying "
+ "to work on a layer that doesn't "
+ "exist any longer."),
+ gimp_object_get_name (procedure),
+ g_param_spec_get_name (pspec));
+ }
+ }
+ else if (GIMP_IS_PARAM_SPEC_IMAGE_ID (pspec) &&
+ g_value_get_int (arg) == -1)
+ {
+ if (return_vals)
+ {
+ g_set_error (error,
+ GIMP_PDB_ERROR,
+ GIMP_PDB_ERROR_INVALID_RETURN_VALUE,
+ _("Procedure '%s' returned an "
+ "invalid ID for argument '%s'. "
+ "Most likely a plug-in is trying "
+ "to work on an image that doesn't "
+ "exist any longer."),
+ gimp_object_get_name (procedure),
+ g_param_spec_get_name (pspec));
+ }
+ else
+ {
+ g_set_error (error,
+ GIMP_PDB_ERROR,
+ GIMP_PDB_ERROR_INVALID_ARGUMENT,
+ _("Procedure '%s' has been called with an "
+ "invalid ID for argument '%s'. "
+ "Most likely a plug-in is trying "
+ "to work on an image that doesn't "
+ "exist any longer."),
+ gimp_object_get_name (procedure),
+ g_param_spec_get_name (pspec));
+ }
+ }
+ else
+ {
+ const gchar *value = g_value_get_string (&string_value);
+
+ if (value == NULL)
+ value = "(null)";
+
+ if (return_vals)
+ {
+ g_set_error (error,
+ GIMP_PDB_ERROR,
+ GIMP_PDB_ERROR_INVALID_RETURN_VALUE,
+ _("Procedure '%s' returned "
+ "'%s' as return value '%s' "
+ "(#%d, type %s). "
+ "This value is out of range."),
+ gimp_object_get_name (procedure),
+ value,
+ g_param_spec_get_name (pspec),
+ i + 1, g_type_name (spec_type));
+ }
+ else
+ {
+ g_set_error (error,
+ GIMP_PDB_ERROR,
+ GIMP_PDB_ERROR_INVALID_ARGUMENT,
+ _("Procedure '%s' has been called with "
+ "value '%s' for argument '%s' "
+ "(#%d, type %s). "
+ "This value is out of range."),
+ gimp_object_get_name (procedure),
+ value,
+ g_param_spec_get_name (pspec),
+ i + 1, g_type_name (spec_type));
+ }
+ }
+
+ g_value_unset (&string_value);
+
+ return FALSE;
+ }
+
+ g_value_unset (&string_value);
+ }
+ }
+
+ return TRUE;
+}