[gimp] libgimp: add a GimpProcedure class



commit 8a462e867d4254dfabd61a73a1a6c02d5aefd498
Author: Michael Natterer <mitch gimp org>
Date:   Fri Jul 26 02:05:11 2019 +0200

    libgimp: add a GimpProcedure class
    
    Mostly the same code as GimpProcedure in app/pdb/.
    
    Move the "run" function to GimpProcedure. Add API to GimpPlugIn to
    list and create procedures, and always keep a list of the plug-ins
    procedures around. Still only using the old params and return_vals.

 libgimp/Makefile.gi          |   4 +-
 libgimp/gimp.def             |  27 ++-
 libgimp/gimp.h               |   1 +
 libgimp/gimpplugin-private.c |  60 ++++-
 libgimp/gimpplugin-private.h |   2 +-
 libgimp/gimpplugin.c         |  69 +++++-
 libgimp/gimpplugin.h         |  30 ++-
 libgimp/gimpprocedure.c      | 534 +++++++++++++++++++++++++++++++++++++++++++
 libgimp/gimpprocedure.h      | 108 +++++++++
 po-libgimp/POTFILES.in       |   1 +
 10 files changed, 811 insertions(+), 25 deletions(-)
---
diff --git a/libgimp/Makefile.gi b/libgimp/Makefile.gi
index a97f3268c6..5f1dfc9296 100644
--- a/libgimp/Makefile.gi
+++ b/libgimp/Makefile.gi
@@ -142,6 +142,8 @@ libgimp_introspectable = \
        $(top_srcdir)/libgimp/gimpplugin.h              \
        $(top_srcdir)/libgimp/gimpproceduraldb.c        \
        $(top_srcdir)/libgimp/gimpproceduraldb.h        \
+       $(top_srcdir)/libgimp/gimpprocedure.c           \
+       $(top_srcdir)/libgimp/gimpprocedure.h           \
        $(top_srcdir)/libgimp/gimpprogress.c            \
        $(top_srcdir)/libgimp/gimpprogress.h            \
        $(top_srcdir)/libgimp/gimpselection.c           \
@@ -150,7 +152,7 @@ libgimp_introspectable = \
 libgimpui_introspectable =                             \
        $(top_srcdir)/libgimp/gimpui.c                  \
        $(top_srcdir)/libgimp/gimpui.h                  \
-       $(top_srcdir)/libgimp/gimpuitypes.h                     \
+       $(top_srcdir)/libgimp/gimpuitypes.h             \
        $(top_srcdir)/libgimp/gimpaspectpreview.c       \
        $(top_srcdir)/libgimp/gimpaspectpreview.h       \
        $(top_srcdir)/libgimp/gimpbrushselectbutton.c   \
diff --git a/libgimp/gimp.def b/libgimp/gimp.def
index f94ab8bb28..2d885cc5d1 100644
--- a/libgimp/gimp.def
+++ b/libgimp/gimp.def
@@ -468,7 +468,7 @@ EXPORTS
        gimp_item_detach_parasite
        gimp_item_get_children
        gimp_item_get_color_tag
-        gimp_item_get_expanded
+       gimp_item_get_expanded
        gimp_item_get_image
        gimp_item_get_linked
        gimp_item_get_lock_content
@@ -489,7 +489,7 @@ EXPORTS
        gimp_item_is_valid
        gimp_item_is_vectors
        gimp_item_set_color_tag
-        gimp_item_set_expanded
+       gimp_item_set_expanded
        gimp_item_set_linked
        gimp_item_set_lock_content
        gimp_item_set_lock_position
@@ -547,6 +547,7 @@ EXPORTS
        gimp_layer_set_opacity
        gimp_layer_set_show_mask
        gimp_main
+       gimp_main_legacy
        gimp_message
        gimp_message_get_handler
        gimp_message_set_handler
@@ -585,6 +586,12 @@ EXPORTS
        gimp_patterns_refresh
        gimp_patterns_set_popup
        gimp_pencil
+       gimp_plug_in_add_procedure
+       gimp_plug_in_get_procedure
+       gimp_plug_in_get_procedures
+       gimp_plug_in_get_type
+       gimp_plug_in_info_set_callbacks
+       gimp_plug_in_remove_procedure
        gimp_plugin_domain_register
        gimp_plugin_get_pdb_error_handler
        gimp_plugin_help_register
@@ -592,8 +599,6 @@ EXPORTS
        gimp_plugin_menu_branch_register
        gimp_plugin_menu_register
        gimp_plugin_set_pdb_error_handler
-       gimp_plug_in_get_type
-       gimp_plug_in_info_set_callbacks
        gimp_procedural_db_dump
        gimp_procedural_db_get_data
        gimp_procedural_db_get_data_size
@@ -604,6 +609,20 @@ EXPORTS
        gimp_procedural_db_query
        gimp_procedural_db_set_data
        gimp_procedural_db_temp_name
+       gimp_procedure_add_argument
+       gimp_procedure_add_return_value
+       gimp_procedure_get_arguments
+       gimp_procedure_get_blurb
+       gimp_procedure_get_help_id
+       gimp_procedure_get_label
+       gimp_procedure_get_name
+       gimp_procedure_get_return_values
+       gimp_procedure_get_type
+       gimp_procedure_new
+       gimp_procedure_new_legacy
+       gimp_procedure_run
+       gimp_procedure_run_legacy
+       gimp_procedure_set_strings
        gimp_progress_cancel
        gimp_progress_end
        gimp_progress_get_window_handle
diff --git a/libgimp/gimp.h b/libgimp/gimp.h
index 9a9143ddcb..18e5d0aab5 100644
--- a/libgimp/gimp.h
+++ b/libgimp/gimp.h
@@ -49,6 +49,7 @@
 #include <libgimp/gimppixbuf.h>
 #include <libgimp/gimpplugin.h>
 #include <libgimp/gimpproceduraldb.h>
+#include <libgimp/gimpprocedure.h>
 #include <libgimp/gimpprogress.h>
 #include <libgimp/gimpselection.h>
 
diff --git a/libgimp/gimpplugin-private.c b/libgimp/gimpplugin-private.c
index 89ebc6da9c..dbb3fa1412 100644
--- a/libgimp/gimpplugin-private.c
+++ b/libgimp/gimpplugin-private.c
@@ -26,6 +26,11 @@
 #include "gimpplugin-private.h"
 
 
+static void   gimp_plug_in_add_procedures (GimpPlugIn *plug_in);
+
+
+/*  public functions  */
+
 void
 _gimp_plug_in_init (GimpPlugIn *plug_in)
 {
@@ -51,21 +56,64 @@ _gimp_plug_in_query (GimpPlugIn *plug_in)
 
   if (GIMP_PLUG_IN_GET_CLASS (plug_in)->query)
     GIMP_PLUG_IN_GET_CLASS (plug_in)->query (plug_in);
+
+  gimp_plug_in_add_procedures (plug_in);
 }
 
 void
 _gimp_plug_in_run (GimpPlugIn       *plug_in,
                    const gchar      *name,
                    gint              n_params,
-                   const GimpParam  *param,
+                   const GimpParam  *params,
                    gint             *n_return_vals,
                    GimpParam       **return_vals)
 {
+  GimpProcedure *procedure;
+
   g_return_if_fail (GIMP_IS_PLUG_IN (plug_in));
+  g_return_if_fail (name != NULL);
+
+  gimp_plug_in_add_procedures (plug_in);
+
+  procedure = gimp_plug_in_get_procedure (plug_in, name);
+
+  if (procedure)
+    {
+      gimp_procedure_run_legacy (procedure,
+                                 n_params,      params,
+                                 n_return_vals, return_vals);
+    }
+}
+
+
+/*  private functions  */
+
+static void
+gimp_plug_in_add_procedures (GimpPlugIn *plug_in)
+{
+  if (GIMP_PLUG_IN_GET_CLASS (plug_in)->list_procedures &&
+      GIMP_PLUG_IN_GET_CLASS (plug_in)->create_procedure)
+    {
+      gchar **procedures;
+      gint    n_procedures;
+      gint    i;
+
+      procedures =
+        GIMP_PLUG_IN_GET_CLASS (plug_in)->list_procedures (plug_in,
+                                                           &n_procedures);
+
+      for (i = 0; i < n_procedures; i++)
+        {
+          GimpProcedure *procedure;
+
+          procedure =
+            GIMP_PLUG_IN_GET_CLASS (plug_in)->create_procedure (plug_in,
+                                                                procedures[i]);
+
+          gimp_plug_in_add_procedure (plug_in, procedure);
+          g_object_unref (procedure);
+        }
 
-  if (GIMP_PLUG_IN_GET_CLASS (plug_in)->run)
-    GIMP_PLUG_IN_GET_CLASS (plug_in)->run (plug_in,
-                                           name,
-                                           n_params, param,
-                                           n_return_vals, return_vals);
+      g_strfreev (procedures);
+    }
 }
diff --git a/libgimp/gimpplugin-private.h b/libgimp/gimpplugin-private.h
index 9f486d28ec..01b88306d5 100644
--- a/libgimp/gimpplugin-private.h
+++ b/libgimp/gimpplugin-private.h
@@ -31,7 +31,7 @@ void   _gimp_plug_in_query (GimpPlugIn *plug_in);
 void   _gimp_plug_in_run   (GimpPlugIn       *plug_in,
                             const gchar      *name,
                             gint              n_params,
-                            const GimpParam  *param,
+                            const GimpParam  *params,
                             gint             *n_return_vals,
                             GimpParam       **return_vals);
 
diff --git a/libgimp/gimpplugin.c b/libgimp/gimpplugin.c
index 0c78424c4c..c1ee07be54 100644
--- a/libgimp/gimpplugin.c
+++ b/libgimp/gimpplugin.c
@@ -39,7 +39,7 @@
 
 struct _GimpPlugInPrivate
 {
-  gint foo;
+  GList *procedures;
 };
 
 
@@ -68,6 +68,73 @@ gimp_plug_in_init (GimpPlugIn *plug_in)
 static void
 gimp_plug_in_finalize (GObject *object)
 {
+  GimpPlugIn *plug_in = GIMP_PLUG_IN (object);
+
+  if (plug_in->priv->procedures)
+    {
+      g_list_free_full (plug_in->priv->procedures, g_object_unref);
+      plug_in->priv->procedures = NULL;
+    }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+void
+gimp_plug_in_add_procedure (GimpPlugIn    *plug_in,
+                            GimpProcedure *procedure)
+{
+  g_return_if_fail (GIMP_IS_PLUG_IN (plug_in));
+  g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
+
+  plug_in->priv->procedures = g_list_prepend (plug_in->priv->procedures,
+                                              g_object_ref (procedure));
+}
+
+void
+gimp_plug_in_remove_procedure (GimpPlugIn  *plug_in,
+                               const gchar *name)
+{
+  GimpProcedure *procedure;
+
+  g_return_if_fail (GIMP_IS_PLUG_IN (plug_in));
+  g_return_if_fail (name != NULL);
+
+  procedure = gimp_plug_in_get_procedure (plug_in, name);
+
+  if (procedure)
+    {
+      plug_in->priv->procedures = g_list_remove (plug_in->priv->procedures,
+                                                 procedure);
+      g_object_unref (procedure);
+    }
+}
+
+GList *
+gimp_plug_in_get_procedures (GimpPlugIn *plug_in)
+{
+  g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), NULL);
+
+  return plug_in->priv->procedures;
+}
+
+GimpProcedure *
+gimp_plug_in_get_procedure (GimpPlugIn  *plug_in,
+                            const gchar *name)
+{
+  GList *list;
+
+  g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), NULL);
+  g_return_val_if_fail (name != NULL, NULL);
+
+  for (list = plug_in->priv->procedures; list; list = g_list_next (list))
+    {
+      GimpProcedure *procedure = list->data;
+
+      if (! strcmp (name, gimp_procedure_get_name (procedure)))
+        return procedure;
+    }
+
+  return NULL;
 }
 
 
diff --git a/libgimp/gimpplugin.h b/libgimp/gimpplugin.h
index a6e0f10d99..9cce67790a 100644
--- a/libgimp/gimpplugin.h
+++ b/libgimp/gimpplugin.h
@@ -52,17 +52,14 @@ struct _GimpPlugInClass
 {
   GObjectClass  parent_class;
 
-  void (* init)  (GimpPlugIn *plug_in);
-  void (* quit)  (GimpPlugIn *plug_in);
-  void (* query) (GimpPlugIn *plug_in);
-
-  /* temp */
-  void (* run)   (GimpPlugIn       *plug_in,
-                  const gchar      *name,
-                  gint              n_params,
-                  const GimpParam  *param,
-                  gint             *n_return_vals,
-                  GimpParam       **return_vals);
+  void             (* init)             (GimpPlugIn  *plug_in);
+  void             (* quit)             (GimpPlugIn  *plug_in);
+  void             (* query)            (GimpPlugIn  *plug_in);
+
+  gchar         ** (* list_procedures)  (GimpPlugIn  *plug_in,
+                                         gint        *n_procedures);
+  GimpProcedure  * (* create_procedure) (GimpPlugIn  *plug_in,
+                                         const gchar *name);
 
   /* Padding for future expansion */
   void (* _gimp_reserved1) (void);
@@ -76,7 +73,16 @@ struct _GimpPlugInClass
 };
 
 
-GType    gimp_plug_in_get_type     (void) G_GNUC_CONST;
+GType           gimp_plug_in_get_type         (void) G_GNUC_CONST;
+
+void            gimp_plug_in_add_procedure    (GimpPlugIn    *plug_in,
+                                               GimpProcedure *procedure);
+void            gimp_plug_in_remove_procedure (GimpPlugIn    *plug_in,
+                                               const gchar   *name);
+
+GList         * gimp_plug_in_get_procedures   (GimpPlugIn   *plug_in);
+GimpProcedure * gimp_plug_in_get_procedure    (GimpPlugIn   *plug_in,
+                                               const gchar  *name);
 
 
 /*  unrelated old API  */
diff --git a/libgimp/gimpprocedure.c b/libgimp/gimpprocedure.c
new file mode 100644
index 0000000000..99399da72a
--- /dev/null
+++ b/libgimp/gimpprocedure.c
@@ -0,0 +1,534 @@
+/* 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 "gimp.h"
+
+#include "libgimp-intl.h"
+
+
+typedef enum
+{
+  GIMP_PDB_ERROR_FAILED,  /* generic error condition */
+  GIMP_PDB_ERROR_CANCELLED,
+  GIMP_PDB_ERROR_PROCEDURE_NOT_FOUND,
+  GIMP_PDB_ERROR_INVALID_ARGUMENT,
+  GIMP_PDB_ERROR_INVALID_RETURN_VALUE,
+  GIMP_PDB_ERROR_INTERNAL_ERROR
+} GimpPdbErrorCode;
+
+#define GIMP_PDB_ERROR (gimp_pdb_error_quark ())
+
+static GQuark
+gimp_pdb_error_quark (void)
+{
+  return g_quark_from_static_string ("gimp-pdb-error-quark");
+}
+
+
+struct _GimpProcedurePrivate
+{
+  gchar            *name;           /* procedure name                 */
+  gchar            *label;
+  gchar            *blurb;          /* Short procedure description    */
+  gchar            *help;           /* Detailed help instructions     */
+  gchar            *help_id;
+  gchar            *author;         /* Author field                   */
+  gchar            *copyright;      /* Copyright field                */
+  gchar            *date;           /* Date field                     */
+
+  gint32            num_args;       /* Number of procedure arguments  */
+  GParamSpec      **args;           /* Array of procedure arguments   */
+
+  gint32            num_values;     /* Number of return values        */
+  GParamSpec      **values;         /* Array of return values         */
+
+  GimpRunFunc       run_func;
+  GimpRunFuncOld    run_func_old;
+};
+
+
+static void       gimp_procedure_finalize      (GObject         *object);
+
+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_WITH_PRIVATE (GimpProcedure, gimp_procedure, G_TYPE_OBJECT)
+
+#define parent_class gimp_procedure_parent_class
+
+
+static void
+gimp_procedure_class_init (GimpProcedureClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gimp_procedure_finalize;
+}
+
+static void
+gimp_procedure_init (GimpProcedure *procedure)
+{
+  procedure->priv = gimp_procedure_get_instance_private (procedure);
+}
+
+static void
+gimp_procedure_finalize (GObject *object)
+{
+  GimpProcedure *procedure = GIMP_PROCEDURE (object);
+  gint           i;
+
+  g_clear_pointer (&procedure->priv->name, g_free);
+
+  gimp_procedure_free_strings (procedure);
+
+  if (procedure->priv->args)
+    {
+      for (i = 0; i < procedure->priv->num_args; i++)
+        g_param_spec_unref (procedure->priv->args[i]);
+
+      g_clear_pointer (&procedure->priv->args, g_free);
+    }
+
+  if (procedure->priv->values)
+    {
+      for (i = 0; i < procedure->priv->num_values; i++)
+        g_param_spec_unref (procedure->priv->values[i]);
+
+      g_clear_pointer (&procedure->priv->values, g_free);
+    }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+/*  public functions  */
+
+GimpProcedure  *
+gimp_procedure_new (const gchar *name,
+                    GimpRunFunc  run_func)
+{
+  GimpProcedure *procedure;
+
+  g_return_val_if_fail (name != NULL, NULL);
+  g_return_val_if_fail (run_func != NULL, NULL);
+
+  procedure = g_object_new (GIMP_TYPE_PROCEDURE, NULL);
+
+  procedure->priv->name     = g_strdup (name);
+  procedure->priv->run_func = run_func;
+
+  return procedure;
+}
+
+GimpProcedure  *
+gimp_procedure_new_legacy (const gchar    *name,
+                           GimpRunFuncOld  run_func_old)
+{
+  GimpProcedure *procedure;
+
+  g_return_val_if_fail (name != NULL, NULL);
+  g_return_val_if_fail (run_func_old != NULL, NULL);
+
+  procedure = g_object_new (GIMP_TYPE_PROCEDURE, NULL);
+
+  procedure->priv->name         = g_strdup (name);
+  procedure->priv->run_func_old = run_func_old;
+
+  return procedure;
+}
+
+void
+gimp_procedure_set_strings (GimpProcedure *procedure,
+                            const gchar   *blurb,
+                            const gchar   *help,
+                            const gchar   *help_id,
+                            const gchar   *author,
+                            const gchar   *copyright,
+                            const gchar   *date)
+{
+  g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
+
+  gimp_procedure_free_strings (procedure);
+
+  procedure->priv->blurb         = g_strdup (blurb);
+  procedure->priv->help          = g_strdup (help);
+  procedure->priv->help_id       = g_strdup (help_id);
+  procedure->priv->author        = g_strdup (author);
+  procedure->priv->copyright     = g_strdup (copyright);
+  procedure->priv->date          = g_strdup (date);
+}
+
+const gchar *
+gimp_procedure_get_name (GimpProcedure *procedure)
+{
+  g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+
+  return procedure->priv->name;
+}
+
+const gchar *
+gimp_procedure_get_label (GimpProcedure *procedure)
+{
+  g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+
+  return procedure->priv->label;
+}
+
+const gchar *
+gimp_procedure_get_blurb (GimpProcedure *procedure)
+{
+  g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+
+  return procedure->priv->blurb;
+}
+
+const gchar *
+gimp_procedure_get_help_id (GimpProcedure *procedure)
+{
+  g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+
+  return procedure->priv->help_id;
+}
+
+GimpValueArray *
+gimp_procedure_run (GimpProcedure   *procedure,
+                    GimpValueArray  *args,
+                    GError         **error)
+{
+  GimpValueArray *return_vals;
+  GError         *my_error = NULL;
+
+  g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), 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->priv->args,
+                                      procedure->priv->num_args,
+                                      args, FALSE, &my_error))
+    {
+      return_vals = gimp_procedure_get_return_values (procedure, FALSE,
+                                                      my_error);
+      g_propagate_error (error, my_error);
+
+      return return_vals;
+    }
+
+  /*  call the procedure  */
+  return_vals = procedure->priv->run_func (procedure, args, error);
+
+  if (! return_vals)
+    {
+      g_warning ("%s: no return values, shouldn't happen", G_STRFUNC);
+
+      my_error = g_error_new (0, 0, 0,
+                              _("Procedure '%s' returned no return values"),
+                              gimp_procedure_get_name (procedure));
+
+      return_vals = gimp_procedure_get_return_values (procedure, FALSE,
+                                                      my_error);
+      if (error && *error == NULL)
+        g_propagate_error (error, my_error);
+      else
+        g_error_free (my_error);
+    }
+
+  return return_vals;
+}
+
+void
+gimp_procedure_run_legacy (GimpProcedure    *procedure,
+                           gint              n_params,
+                           const GimpParam  *params,
+                           gint             *n_return_vals,
+                           GimpParam       **return_vals)
+{
+  g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
+
+  /*  call the procedure  */
+  procedure->priv->run_func_old (procedure,
+                                 n_params, params,
+                                 n_return_vals, return_vals);
+}
+
+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->priv->num_args);
+
+  for (i = 0; i < procedure->priv->num_args; i++)
+    {
+      g_value_init (&value,
+                    G_PARAM_SPEC_VALUE_TYPE (procedure->priv->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->priv->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->priv->num_values; i++)
+        {
+          g_value_init (&value,
+                        G_PARAM_SPEC_VALUE_TYPE (procedure->priv->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:
+              g_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->priv->args = g_renew (GParamSpec *, procedure->priv->args,
+                                   procedure->priv->num_args + 1);
+
+  procedure->priv->args[procedure->priv->num_args] = pspec;
+
+  g_param_spec_ref_sink (pspec);
+
+  procedure->priv->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->priv->values = g_renew (GParamSpec *, procedure->priv->values,
+                               procedure->priv->num_values + 1);
+
+  procedure->priv->values[procedure->priv->num_values] = pspec;
+
+  g_param_spec_ref_sink (pspec);
+
+  procedure->priv->num_values++;
+}
+
+
+/*  private functions  */
+
+static void
+gimp_procedure_free_strings (GimpProcedure *procedure)
+{
+  g_clear_pointer (&procedure->priv->blurb,     g_free);
+  g_clear_pointer (&procedure->priv->help,      g_free);
+  g_clear_pointer (&procedure->priv->help_id,   g_free);
+  g_clear_pointer (&procedure->priv->author,    g_free);
+  g_clear_pointer (&procedure->priv->copyright, g_free);
+  g_clear_pointer (&procedure->priv->date,      g_free);
+}
+
+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_procedure_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_procedure_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))
+            {
+              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_procedure_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_procedure_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;
+}
diff --git a/libgimp/gimpprocedure.h b/libgimp/gimpprocedure.h
new file mode 100644
index 0000000000..2416a5e97a
--- /dev/null
+++ b/libgimp/gimpprocedure.h
@@ -0,0 +1,108 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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_H_INSIDE__) && !defined (GIMP_COMPILATION)
+#error "Only <libgimp/gimp.h> can be included directly."
+#endif
+
+#ifndef __GIMP_PROCEDURE_H__
+#define __GIMP_PROCEDURE_H__
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+typedef GimpValueArray * (* GimpRunFunc)    (GimpProcedure         *procedure,
+                                             const GimpValueArray  *args,
+                                             GError               **error);
+typedef void             (* GimpRunFuncOld) (GimpProcedure         *procedure,
+                                             gint                   n_params,
+                                             const GimpParam       *params,
+                                             gint                  *n_return_vals,
+                                             GimpParam            **return_vals);
+
+
+#define GIMP_TYPE_PROCEDURE            (gimp_procedure_get_type ())
+#define GIMP_PROCEDURE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_PROCEDURE, 
GimpProcedure))
+#define GIMP_PROCEDURE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_PROCEDURE, 
GimpProcedureClass))
+#define GIMP_IS_PROCEDURE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_PROCEDURE))
+#define GIMP_IS_PROCEDURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_PROCEDURE))
+#define GIMP_PROCEDURE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_PROCEDURE, 
GimpProcedureClass))
+
+
+typedef struct _GimpProcedureClass   GimpProcedureClass;
+typedef struct _GimpProcedurePrivate GimpProcedurePrivate;
+
+struct _GimpProcedure
+{
+  GObject               parent_instance;
+
+  GimpProcedurePrivate *priv;
+};
+
+struct _GimpProcedureClass
+{
+  GObjectClass parent_class;
+};
+
+
+GType            gimp_procedure_get_type           (void) G_GNUC_CONST;
+
+GimpProcedure  * gimp_procedure_new                (const gchar      *name,
+                                                    GimpRunFunc       run_func);
+GimpProcedure  * gimp_procedure_new_legacy         (const gchar      *name,
+                                                    GimpRunFuncOld    run_func_old);
+
+void             gimp_procedure_set_strings        (GimpProcedure    *procedure,
+                                                    const gchar      *blurb,
+                                                    const gchar      *help,
+                                                    const gchar      *help_id,
+                                                    const gchar      *author,
+                                                    const gchar      *copyright,
+                                                    const gchar      *date);
+
+const gchar    * gimp_procedure_get_name           (GimpProcedure    *procedure);
+const gchar    * gimp_procedure_get_label          (GimpProcedure    *procedure);
+const gchar    * gimp_procedure_get_blurb          (GimpProcedure    *procedure);
+const gchar    * gimp_procedure_get_help_id        (GimpProcedure    *procedure);
+
+void             gimp_procedure_add_argument       (GimpProcedure    *procedure,
+                                                    GParamSpec       *pspec);
+void             gimp_procedure_add_return_value   (GimpProcedure    *procedure,
+                                                    GParamSpec       *pspec);
+
+GimpValueArray * gimp_procedure_get_arguments      (GimpProcedure    *procedure);
+GimpValueArray * gimp_procedure_get_return_values  (GimpProcedure    *procedure,
+                                                    gboolean          success,
+                                                    const GError     *error);
+
+GimpValueArray * gimp_procedure_run                (GimpProcedure    *procedure,
+                                                    GimpValueArray   *args,
+                                                    GError          **error);
+
+void             gimp_procedure_run_legacy         (GimpProcedure    *procedure,
+                                                    gint              n_params,
+                                                    const GimpParam  *params,
+                                                    gint             *n_return_vals,
+                                                    GimpParam       **return_vals);
+
+
+G_END_DECLS
+
+#endif  /*  __GIMP_PROCEDURE_H__  */
diff --git a/po-libgimp/POTFILES.in b/po-libgimp/POTFILES.in
index 9c0fd4a7a4..8a3655703f 100644
--- a/po-libgimp/POTFILES.in
+++ b/po-libgimp/POTFILES.in
@@ -12,6 +12,7 @@ libgimp/gimpimagemetadata.c
 libgimp/gimppaletteselectbutton.c
 libgimp/gimppatternselectbutton.c
 libgimp/gimpprocbrowserdialog.c
+libgimp/gimpprocedure.c
 libgimp/gimpprocview.c
 libgimp/gimpunitcache.c
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]