[gimp] app, libgimp, libgimpbase: plug-in and PDB protocol refactoring part two



commit 32ea28b6b1c1b22837add271f532896a7511a020
Author: Michael Natterer <mitch gimp org>
Date:   Sat Jul 27 16:37:55 2019 +0200

    app, libgimp, libgimpbase: plug-in and PDB protocol refactoring part two
    
    - Change the wire protocol's GPProcInstall to transmit the entire
      information needed for constructing all GParamSpecs we use, don't
      use GimpPDBArgType in GPProcInstall but an enum private to the wire
      protocol plus the GParamSpec's GType name. Bump the wire protocol
      version.
    
    - Add gimpgpparamspecs.[ch] in both app/plug-in/ and libgimp/ which
      take care of converting between GPParamDef and GParamSpec. They
      share code as far as possible.
    
    - Change pluginrc writing and parsing to re-use GPParamDef and the
      utility functions from gimpgpparamspecs.
    
    - Remove gimp_pdb_compat_param_spec() from app/pdb/gimp-pdb-compat.[ch],
      the entire core uses proper GParamSpecs from the wire protocol now,
      the whole file will follow down the drain once we use a GValue
      representation on the wire too.
    
    - In gimp_plug_in_handle_proc_install(), change the "run-mode"
      parameter to a GParamSpecEnum(GIMP_TYPE_RUN_MODE) (if it is not
      already an enum). and change all places in app/ to treat it as an
      enum value.
    
    - plug-ins: fix cml-explorer to register correctly, a typo in
      "run-mode" was never noticed until now.
    
    - Add gimpgpcompat.[ch] in libgimp to deal with all the transforms
      between old-style wire communication and using GParamSpec and
      GValue, it contains some functions that are subject to change or
      even removal in the next steps.
    
    - Change the libgimp GimpProcedure and GimpPlugIn in many ways to be
      able to actually install procedures the new way.
    
    - plug-ins: change goat-exercise to completely use the new GimpPlugIn
      and GimpProcedure API, look here to see how plug-ins will look in
      the future, of course subject to change until this is finished.
    
    - Next: changing GPParam to transmit all information about a GValue.

 app/Makefile.am                      |   1 -
 app/actions/gimpgeglprocedure.c      |  11 +-
 app/actions/procedure-commands.c     |  35 +-
 app/config/Makefile.am               |   1 -
 app/core/gimp-batch.c                |  17 +-
 app/file-data/file-data.c            |  77 ++--
 app/file/file-open.c                 |   6 +-
 app/file/file-save.c                 |   2 +-
 app/operations/tests/Makefile.am     |   1 -
 app/pdb/gimp-pdb-compat.c            | 184 +--------
 app/pdb/gimp-pdb-compat.h            |   6 -
 app/plug-in/Makefile.am              |   2 +
 app/plug-in/gimpgpparamspecs.c       | 204 ++++++++++
 app/plug-in/gimpgpparamspecs.h       |  35 ++
 app/plug-in/gimpplugin-message.c     |  64 ++-
 app/plug-in/gimppluginmanager-file.c |  11 +-
 app/plug-in/gimppluginprocedure.c    |  63 +--
 app/plug-in/plug-in-rc.c             | 246 ++++++++++--
 app/tests/Makefile.am                |   1 -
 app/xcf/xcf.c                        |  22 +-
 libgimp/Makefile.am                  |  12 +-
 libgimp/gimp.c                       |  85 +++-
 libgimp/gimpgpcompat.c               | 756 +++++++++++++++++++++++++++++++++++
 libgimp/gimpgpcompat.h               |  45 +++
 libgimp/gimpgpparamspecs-body.c      | 134 +++++++
 libgimp/gimpgpparamspecs.c           |  41 ++
 libgimp/gimpgpparamspecs.h           |  33 ++
 libgimp/gimpplugin-private.c         | 100 ++---
 libgimp/gimpplugin-private.h         |  11 +-
 libgimp/gimpplugin.c                 |  17 +
 libgimp/gimpplugin.h                 |  10 +-
 libgimp/gimpprocedure-private.c      |  96 +++++
 libgimp/gimpprocedure-private.h      |  32 ++
 libgimp/gimpprocedure.c              | 320 ++++++++-------
 libgimp/gimpprocedure.h              |  91 ++---
 libgimpbase/gimpprotocol.c           | 354 +++++++++++++---
 libgimpbase/gimpprotocol.h           | 105 ++++-
 plug-ins/common/cml-explorer.c       |   2 +-
 plug-ins/common/goat-exercise.c      | 161 +++++---
 39 files changed, 2672 insertions(+), 722 deletions(-)
---
diff --git a/app/Makefile.am b/app/Makefile.am
index 5e4872d146..749e7a11f6 100644
--- a/app/Makefile.am
+++ b/app/Makefile.am
@@ -149,7 +149,6 @@ AM_LDFLAGS = \
        -Wl,-u,$(SYMPREFIX)xcf_init                             \
        -Wl,-u,$(SYMPREFIX)internal_procs_init                  \
        -Wl,-u,$(SYMPREFIX)gimp_plug_in_manager_restore         \
-       -Wl,-u,$(SYMPREFIX)gimp_pdb_compat_param_spec           \
        -Wl,-u,$(SYMPREFIX)gimp_layer_mode_is_legacy            \
        -Wl,-u,$(SYMPREFIX)gimp_parallel_init                   \
        -Wl,-u,$(SYMPREFIX)gimp_async_set_new                   \
diff --git a/app/actions/gimpgeglprocedure.c b/app/actions/gimpgeglprocedure.c
index 2e4c5e438c..a901fba0ec 100644
--- a/app/actions/gimpgeglprocedure.c
+++ b/app/actions/gimpgeglprocedure.c
@@ -447,11 +447,12 @@ gimp_gegl_procedure_new (Gimp        *gimp,
                               NULL);
 
   gimp_procedure_add_argument (procedure,
-                               gimp_param_spec_int32 ("run-mode",
-                                                      "Run mode",
-                                                      "Run mode",
-                                                      G_MININT32, G_MAXINT32, 0,
-                                                      GIMP_PARAM_READWRITE));
+                               gimp_param_spec_enum ("run-mode",
+                                                     "Run mode",
+                                                     "Run mode",
+                                                     GIMP_TYPE_RUN_MODE,
+                                                     GIMP_RUN_INTERACTIVE,
+                                                     GIMP_PARAM_READWRITE));
   gimp_procedure_add_argument (procedure,
                                gimp_param_spec_image_id ("image",
                                                          "Image",
diff --git a/app/actions/procedure-commands.c b/app/actions/procedure-commands.c
index 93ec29db0e..d67391d774 100644
--- a/app/actions/procedure-commands.c
+++ b/app/actions/procedure-commands.c
@@ -36,6 +36,13 @@
 #include "procedure-commands.h"
 
 
+static inline gboolean
+GIMP_IS_PARAM_SPEC_RUN_MODE (GParamSpec *pspec)
+{
+  return (G_IS_PARAM_SPEC_ENUM (pspec) &&
+          pspec->value_type == GIMP_TYPE_RUN_MODE);
+}
+
 GimpValueArray *
 procedure_commands_get_run_mode_arg (GimpProcedure *procedure)
 {
@@ -46,10 +53,10 @@ procedure_commands_get_run_mode_arg (GimpProcedure *procedure)
 
   /* initialize the first argument  */
   if (gimp_value_array_length (args) > n_args &&
-      GIMP_IS_PARAM_SPEC_INT32 (procedure->args[n_args]))
+      GIMP_IS_PARAM_SPEC_RUN_MODE (procedure->args[n_args]))
     {
-      g_value_set_int (gimp_value_array_index (args, n_args),
-                       GIMP_RUN_INTERACTIVE);
+      g_value_set_enum (gimp_value_array_index (args, n_args),
+                        GIMP_RUN_INTERACTIVE);
       n_args++;
     }
 
@@ -68,8 +75,8 @@ procedure_commands_get_data_args (GimpProcedure *procedure,
   args = gimp_procedure_get_arguments (procedure);
 
   /* initialize the first argument  */
-  g_value_set_int (gimp_value_array_index (args, n_args),
-                   GIMP_RUN_INTERACTIVE);
+  g_value_set_enum (gimp_value_array_index (args, n_args),
+                    GIMP_RUN_INTERACTIVE);
   n_args++;
 
   if (gimp_value_array_length (args) > n_args &&
@@ -104,8 +111,8 @@ procedure_commands_get_image_args (GimpProcedure   *procedure,
   args = gimp_procedure_get_arguments (procedure);
 
   /* initialize the first argument  */
-  g_value_set_int (gimp_value_array_index (args, n_args),
-                   GIMP_RUN_INTERACTIVE);
+  g_value_set_enum (gimp_value_array_index (args, n_args),
+                    GIMP_RUN_INTERACTIVE);
   n_args++;
 
   if (gimp_value_array_length (args) > n_args &&
@@ -140,8 +147,8 @@ procedure_commands_get_item_args (GimpProcedure *procedure,
   args = gimp_procedure_get_arguments (procedure);
 
   /* initialize the first argument  */
-  g_value_set_int (gimp_value_array_index (args, n_args),
-                   GIMP_RUN_INTERACTIVE);
+  g_value_set_enum (gimp_value_array_index (args, n_args),
+                    GIMP_RUN_INTERACTIVE);
   n_args++;
 
   if (gimp_value_array_length (args) > n_args &&
@@ -189,8 +196,8 @@ procedure_commands_get_display_args (GimpProcedure *procedure,
   args = gimp_procedure_get_arguments (procedure);
 
   /* initialize the first argument  */
-  g_value_set_int (gimp_value_array_index (args, n_args),
-                   GIMP_RUN_INTERACTIVE);
+  g_value_set_enum (gimp_value_array_index (args, n_args),
+                    GIMP_RUN_INTERACTIVE);
   n_args++;
 
   if (gimp_value_array_length (args) > n_args &&
@@ -268,7 +275,8 @@ procedure_commands_run_procedure (GimpProcedure  *procedure,
   g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
   g_return_val_if_fail (args != NULL, FALSE);
 
-  g_value_set_int (gimp_value_array_index (args, 0), GIMP_RUN_NONINTERACTIVE);
+  g_value_set_enum (gimp_value_array_index (args, 0),
+                    GIMP_RUN_NONINTERACTIVE);
 
   return_vals = gimp_procedure_execute (procedure, gimp,
                                         gimp_get_user_context (gimp),
@@ -305,7 +313,8 @@ procedure_commands_run_procedure_async (GimpProcedure  *procedure,
   g_return_val_if_fail (display == NULL || GIMP_IS_DISPLAY (display), FALSE);
   g_return_val_if_fail (args != NULL, FALSE);
 
-  g_value_set_int (gimp_value_array_index (args, 0), run_mode);
+  g_value_set_enum (gimp_value_array_index (args, 0),
+                    run_mode);
 
   gimp_procedure_execute_async (procedure, gimp,
                                 gimp_get_user_context (gimp),
diff --git a/app/config/Makefile.am b/app/config/Makefile.am
index b682eca82b..371b790321 100644
--- a/app/config/Makefile.am
+++ b/app/config/Makefile.am
@@ -91,7 +91,6 @@ test_config_LDFLAGS = \
        -Wl,-u,$(SYMPREFIX)xcf_init                             \
        -Wl,-u,$(SYMPREFIX)internal_procs_init                  \
        -Wl,-u,$(SYMPREFIX)gimp_plug_in_manager_restore         \
-       -Wl,-u,$(SYMPREFIX)gimp_pdb_compat_param_spec           \
        -Wl,-u,$(SYMPREFIX)gimp_layer_mode_is_legacy            \
        -Wl,-u,$(SYMPREFIX)gimp_async_set_new                   \
        -Wl,-u,$(SYMPREFIX)gimp_uncancelable_waitable_new
diff --git a/app/core/gimp-batch.c b/app/core/gimp-batch.c
index 0115086f74..92e0f9a750 100644
--- a/app/core/gimp-batch.c
+++ b/app/core/gimp-batch.c
@@ -134,6 +134,13 @@ gimp_batch_exit_after_callback (Gimp *gimp)
   exit (EXIT_SUCCESS);
 }
 
+static inline gboolean
+GIMP_IS_PARAM_SPEC_RUN_MODE (GParamSpec *pspec)
+{
+  return (G_IS_PARAM_SPEC_ENUM (pspec) &&
+          pspec->value_type == GIMP_TYPE_RUN_MODE);
+}
+
 static void
 gimp_batch_run_cmd (Gimp          *gimp,
                     const gchar   *proc_name,
@@ -149,12 +156,16 @@ gimp_batch_run_cmd (Gimp          *gimp,
   args = gimp_procedure_get_arguments (procedure);
 
   if (procedure->num_args > i &&
-      GIMP_IS_PARAM_SPEC_INT32 (procedure->args[i]))
-    g_value_set_int (gimp_value_array_index (args, i++), run_mode);
+      GIMP_IS_PARAM_SPEC_RUN_MODE (procedure->args[i]))
+    {
+      g_value_set_enum (gimp_value_array_index (args, i++), run_mode);
+    }
 
   if (procedure->num_args > i &&
       GIMP_IS_PARAM_SPEC_STRING (procedure->args[i]))
-    g_value_set_static_string (gimp_value_array_index (args, i++), cmd);
+    {
+      g_value_set_static_string (gimp_value_array_index (args, i++), cmd);
+    }
 
   return_vals =
     gimp_pdb_execute_procedure_by_name_args (gimp->pdb,
diff --git a/app/file-data/file-data.c b/app/file-data/file-data.c
index 88c0047b08..28365f22e2 100644
--- a/app/file-data/file-data.c
+++ b/app/file-data/file-data.c
@@ -81,11 +81,12 @@ file_data_init (Gimp *gimp)
                                      NULL);
 
   gimp_procedure_add_argument (procedure,
-                               gimp_param_spec_int32 ("dummy-param",
-                                                      "Dummy Param",
-                                                      "Dummy parameter",
-                                                      G_MININT32, G_MAXINT32, 0,
-                                                      GIMP_PARAM_READWRITE));
+                               gimp_param_spec_enum ("dummy-param",
+                                                     "Dummy Param",
+                                                     "Dummy parameter",
+                                                     GIMP_TYPE_RUN_MODE,
+                                                     GIMP_RUN_INTERACTIVE,
+                                                     GIMP_PARAM_READWRITE));
   gimp_procedure_add_argument (procedure,
                                gimp_param_spec_string ("uri",
                                                        "URI",
@@ -147,11 +148,12 @@ file_data_init (Gimp *gimp)
                                      NULL);
 
   gimp_procedure_add_argument (procedure,
-                               gimp_param_spec_int32 ("dummy-param",
-                                                      "Dummy Param",
-                                                      "Dummy parameter",
-                                                      G_MININT32, G_MAXINT32, 0,
-                                                      GIMP_PARAM_READWRITE));
+                               gimp_param_spec_enum ("dummy-param",
+                                                     "Dummy Param",
+                                                     "Dummy parameter",
+                                                     GIMP_TYPE_RUN_MODE,
+                                                     GIMP_RUN_INTERACTIVE,
+                                                     GIMP_PARAM_READWRITE));
   gimp_procedure_add_argument (procedure,
                                gimp_param_spec_image_id ("image",
                                                          "Image",
@@ -229,11 +231,12 @@ file_data_init (Gimp *gimp)
                                      NULL);
 
   gimp_procedure_add_argument (procedure,
-                               gimp_param_spec_int32 ("dummy-param",
-                                                      "Dummy Param",
-                                                      "Dummy parameter",
-                                                      G_MININT32, G_MAXINT32, 0,
-                                                      GIMP_PARAM_READWRITE));
+                               gimp_param_spec_enum ("dummy-param",
+                                                     "Dummy Param",
+                                                     "Dummy parameter",
+                                                     GIMP_TYPE_RUN_MODE,
+                                                     GIMP_RUN_INTERACTIVE,
+                                                     GIMP_PARAM_READWRITE));
   gimp_procedure_add_argument (procedure,
                                gimp_param_spec_string ("uri",
                                                        "URI",
@@ -295,11 +298,12 @@ file_data_init (Gimp *gimp)
                                      NULL);
 
   gimp_procedure_add_argument (procedure,
-                               gimp_param_spec_int32 ("dummy-param",
-                                                      "Dummy Param",
-                                                      "Dummy parameter",
-                                                      G_MININT32, G_MAXINT32, 0,
-                                                      GIMP_PARAM_READWRITE));
+                               gimp_param_spec_enum ("dummy-param",
+                                                     "Dummy Param",
+                                                     "Dummy parameter",
+                                                     GIMP_TYPE_RUN_MODE,
+                                                     GIMP_RUN_INTERACTIVE,
+                                                     GIMP_PARAM_READWRITE));
   gimp_procedure_add_argument (procedure,
                                gimp_param_spec_image_id ("image",
                                                          "Image",
@@ -384,11 +388,12 @@ file_data_init (Gimp *gimp)
                                      NULL);
 
   gimp_procedure_add_argument (procedure,
-                               gimp_param_spec_int32 ("dummy-param",
-                                                      "Dummy Param",
-                                                      "Dummy parameter",
-                                                      G_MININT32, G_MAXINT32, 0,
-                                                      GIMP_PARAM_READWRITE));
+                               gimp_param_spec_enum ("dummy-param",
+                                                     "Dummy Param",
+                                                     "Dummy parameter",
+                                                     GIMP_TYPE_RUN_MODE,
+                                                     GIMP_RUN_INTERACTIVE,
+                                                     GIMP_PARAM_READWRITE));
   gimp_procedure_add_argument (procedure,
                                gimp_param_spec_string ("uri",
                                                        "URI",
@@ -449,11 +454,12 @@ file_data_init (Gimp *gimp)
                                      NULL);
 
   gimp_procedure_add_argument (procedure,
-                               gimp_param_spec_int32 ("dummy-param",
-                                                      "Dummy Param",
-                                                      "Dummy parameter",
-                                                      G_MININT32, G_MAXINT32, 0,
-                                                      GIMP_PARAM_READWRITE));
+                               gimp_param_spec_enum ("dummy-param",
+                                                     "Dummy Param",
+                                                     "Dummy parameter",
+                                                     GIMP_TYPE_RUN_MODE,
+                                                     GIMP_RUN_INTERACTIVE,
+                                                     GIMP_PARAM_READWRITE));
   gimp_procedure_add_argument (procedure,
                                gimp_param_spec_image_id ("image",
                                                          "Image",
@@ -524,11 +530,12 @@ file_data_init (Gimp *gimp)
                                      NULL);
 
   gimp_procedure_add_argument (procedure,
-                               gimp_param_spec_int32 ("dummy-param",
-                                                      "Dummy Param",
-                                                      "Dummy parameter",
-                                                      G_MININT32, G_MAXINT32, 0,
-                                                      GIMP_PARAM_READWRITE));
+                               gimp_param_spec_enum ("dummy-param",
+                                                     "Dummy Param",
+                                                     "Dummy parameter",
+                                                     GIMP_TYPE_RUN_MODE,
+                                                     GIMP_RUN_INTERACTIVE,
+                                                     GIMP_PARAM_READWRITE));
   gimp_procedure_add_argument (procedure,
                                gimp_param_spec_string ("uri",
                                                        "URI",
diff --git a/app/file/file-open.c b/app/file/file-open.c
index dc800170eb..0f11f0b354 100644
--- a/app/file/file-open.c
+++ b/app/file/file-open.c
@@ -231,9 +231,9 @@ file_open_image (Gimp                *gimp,
     gimp_pdb_execute_procedure_by_name (gimp->pdb,
                                         context, progress, error,
                                         gimp_object_get_name (file_proc),
-                                        GIMP_TYPE_INT32, run_mode,
-                                        G_TYPE_STRING,   path,
-                                        G_TYPE_STRING,   entered_uri,
+                                        GIMP_TYPE_RUN_MODE, run_mode,
+                                        G_TYPE_STRING,      path,
+                                        G_TYPE_STRING,      entered_uri,
                                         G_TYPE_NONE);
 
   if (progress)
diff --git a/app/file/file-save.c b/app/file/file-save.c
index 7fc2dfdb9c..bf7b08d272 100644
--- a/app/file/file-save.c
+++ b/app/file/file-save.c
@@ -207,7 +207,7 @@ file_save (Gimp                *gimp,
                                         gimp_get_user_context (gimp),
                                         progress, error,
                                         gimp_object_get_name (file_proc),
-                                        GIMP_TYPE_INT32,       run_mode,
+                                        GIMP_TYPE_RUN_MODE,    run_mode,
                                         GIMP_TYPE_IMAGE_ID,    image_ID,
                                         GIMP_TYPE_DRAWABLE_ID, drawable_ID,
                                         G_TYPE_STRING,         path,
diff --git a/app/operations/tests/Makefile.am b/app/operations/tests/Makefile.am
index fdf0a9addc..0d9528c132 100644
--- a/app/operations/tests/Makefile.am
+++ b/app/operations/tests/Makefile.am
@@ -30,7 +30,6 @@ AM_LDFLAGS = \
        -Wl,-u,$(SYMPREFIX)xcf_init                             \
        -Wl,-u,$(SYMPREFIX)internal_procs_init                  \
        -Wl,-u,$(SYMPREFIX)gimp_plug_in_manager_restore         \
-       -Wl,-u,$(SYMPREFIX)gimp_pdb_compat_param_spec           \
        -Wl,-u,$(SYMPREFIX)gimp_vectors_undo_get_type           \
        -Wl,-u,$(SYMPREFIX)gimp_vectors_mod_undo_get_type       \
        -Wl,-u,$(SYMPREFIX)gimp_vectors_prop_undo_get_type
diff --git a/app/pdb/gimp-pdb-compat.c b/app/pdb/gimp-pdb-compat.c
index c220c22afe..8493984f0c 100644
--- a/app/pdb/gimp-pdb-compat.c
+++ b/app/pdb/gimp-pdb-compat.c
@@ -33,163 +33,16 @@
 #include "gimp-pdb-compat.h"
 
 
-/*  public functions  */
-
-GParamSpec *
-gimp_pdb_compat_param_spec (Gimp           *gimp,
-                            GimpPDBArgType  arg_type,
-                            const gchar    *name,
-                            const gchar    *desc)
-{
-  GParamSpec *pspec = NULL;
-
-  g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
-  g_return_val_if_fail (name != NULL, NULL);
-
-  switch (arg_type)
-    {
-    case GIMP_PDB_INT32:
-      pspec = gimp_param_spec_int32 (name, name, desc,
-                                     G_MININT32, G_MAXINT32, 0,
-                                     G_PARAM_READWRITE);
-      break;
+/*  local function prototypes  */
 
-    case GIMP_PDB_INT16:
-      pspec = gimp_param_spec_int16 (name, name, desc,
-                                     G_MININT16, G_MAXINT16, 0,
-                                     G_PARAM_READWRITE);
-      break;
+static gchar * gimp_pdb_compat_arg_type_to_string (GimpPDBArgType type);
 
-    case GIMP_PDB_INT8:
-      pspec = gimp_param_spec_int8 (name, name, desc,
-                                    0, G_MAXUINT8, 0,
-                                    G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_FLOAT:
-      pspec = g_param_spec_double (name, name, desc,
-                                   -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
-                                   G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_STRING:
-      pspec = gimp_param_spec_string (name, name, desc,
-                                      TRUE, TRUE, FALSE,
-                                      NULL,
-                                      G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_INT32ARRAY:
-      pspec = gimp_param_spec_int32_array (name, name, desc,
-                                           G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_INT16ARRAY:
-      pspec = gimp_param_spec_int16_array (name, name, desc,
-                                           G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_INT8ARRAY:
-      pspec = gimp_param_spec_int8_array (name, name, desc,
-                                          G_PARAM_READWRITE);
-      break;
 
-    case GIMP_PDB_FLOATARRAY:
-      pspec = gimp_param_spec_float_array (name, name, desc,
-                                           G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_STRINGARRAY:
-      pspec = gimp_param_spec_string_array (name, name, desc,
-                                            G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_COLOR:
-      pspec = gimp_param_spec_rgb (name, name, desc,
-                                   TRUE, NULL,
-                                   G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_ITEM:
-      pspec = gimp_param_spec_item_id (name, name, desc,
-                                       gimp, TRUE,
-                                       G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_DISPLAY:
-      pspec = gimp_param_spec_display_id (name, name, desc,
-                                          gimp, TRUE,
-                                          G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_IMAGE:
-      pspec = gimp_param_spec_image_id (name, name, desc,
-                                        gimp, TRUE,
-                                        G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_LAYER:
-      pspec = gimp_param_spec_layer_id (name, name, desc,
-                                        gimp, TRUE,
-                                        G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_CHANNEL:
-      pspec = gimp_param_spec_channel_id (name, name, desc,
-                                          gimp, TRUE,
-                                          G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_DRAWABLE:
-      pspec = gimp_param_spec_drawable_id (name, name, desc,
-                                           gimp, TRUE,
-                                           G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_SELECTION:
-      pspec = gimp_param_spec_selection_id (name, name, desc,
-                                            gimp, TRUE,
-                                            G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_COLORARRAY:
-      pspec = gimp_param_spec_rgb_array (name, name, desc,
-                                         G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_VECTORS:
-      pspec = gimp_param_spec_vectors_id (name, name, desc,
-                                          gimp, TRUE,
-                                          G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_PARASITE:
-      pspec = gimp_param_spec_parasite (name, name, desc,
-                                        G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_STATUS:
-      pspec = g_param_spec_enum (name, name, desc,
-                                 GIMP_TYPE_PDB_STATUS_TYPE,
-                                 GIMP_PDB_EXECUTION_ERROR,
-                                 G_PARAM_READWRITE);
-      break;
-
-    case GIMP_PDB_END:
-      break;
-    }
-
-  if (! pspec)
-    g_warning ("%s: returning NULL for %s (%s)",
-               G_STRFUNC, name, gimp_pdb_compat_arg_type_to_string (arg_type));
-
-  return pspec;
-}
+/*  public functions  */
 
 GType
 gimp_pdb_compat_arg_type_to_gtype (GimpPDBArgType  type)
 {
-
   switch (type)
     {
     case GIMP_PDB_INT32:
@@ -340,20 +193,6 @@ gimp_pdb_compat_arg_type_from_gtype (GType type)
   return pdb_type;
 }
 
-gchar *
-gimp_pdb_compat_arg_type_to_string (GimpPDBArgType type)
-{
-  const gchar *name;
-
-  if (! gimp_enum_get_value (GIMP_TYPE_PDB_ARG_TYPE, type,
-                             &name, NULL, NULL, NULL))
-    {
-      return  g_strdup_printf ("(PDB type %d unknown)", type);
-    }
-
-  return g_strdup (name);
-}
-
 void
 gimp_pdb_compat_procs_register (GimpPDB           *pdb,
                                 GimpPDBCompatMode  compat_mode)
@@ -501,3 +340,20 @@ gimp_pdb_compat_procs_register (GimpPDB           *pdb,
                                             compat_procs[i].new_name);
     }
 }
+
+
+/*  private functions  */
+
+static gchar *
+gimp_pdb_compat_arg_type_to_string (GimpPDBArgType type)
+{
+  const gchar *name;
+
+  if (! gimp_enum_get_value (GIMP_TYPE_PDB_ARG_TYPE, type,
+                             &name, NULL, NULL, NULL))
+    {
+      return  g_strdup_printf ("(PDB type %d unknown)", type);
+    }
+
+  return g_strdup (name);
+}
diff --git a/app/pdb/gimp-pdb-compat.h b/app/pdb/gimp-pdb-compat.h
index 74c26959e2..0a53e3eb24 100644
--- a/app/pdb/gimp-pdb-compat.h
+++ b/app/pdb/gimp-pdb-compat.h
@@ -19,14 +19,8 @@
 #define __GIMP_PDB_COMPAT_H__
 
 
-GParamSpec     * gimp_pdb_compat_param_spec          (Gimp           *gimp,
-                                                      GimpPDBArgType  arg_type,
-                                                      const gchar    *name,
-                                                      const gchar    *desc);
-
 GType            gimp_pdb_compat_arg_type_to_gtype   (GimpPDBArgType  type);
 GimpPDBArgType   gimp_pdb_compat_arg_type_from_gtype (GType           type);
-gchar          * gimp_pdb_compat_arg_type_to_string  (GimpPDBArgType  type);
 
 void             gimp_pdb_compat_procs_register (GimpPDB           *pdb,
                                                  GimpPDBCompatMode  compat_mode);
diff --git a/app/plug-in/Makefile.am b/app/plug-in/Makefile.am
index 852fdbb37e..9a939f310b 100644
--- a/app/plug-in/Makefile.am
+++ b/app/plug-in/Makefile.am
@@ -20,6 +20,8 @@ libappplug_in_a_SOURCES = \
        \
        gimpenvirontable.c                      \
        gimpenvirontable.h                      \
+       gimpgpparamspecs.c                      \
+       gimpgpparamspecs.h                      \
        gimpinterpreterdb.c                     \
        gimpinterpreterdb.h                     \
        gimpplugindebug.c                       \
diff --git a/app/plug-in/gimpgpparamspecs.c b/app/plug-in/gimpgpparamspecs.c
new file mode 100644
index 0000000000..da99b0a5c5
--- /dev/null
+++ b/app/plug-in/gimpgpparamspecs.c
@@ -0,0 +1,204 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpgpparamspecs.c
+ *
+ * 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 <cairo.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gegl.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpcolor/gimpcolor.h"
+#include "libgimpbase/gimpprotocol.h"
+
+#include "plug-in-types.h"
+
+#include "core/gimp.h"
+#include "core/gimpparamspecs.h"
+
+#include "gimpgpparamspecs.h"
+
+
+/*  public functions  */
+
+/*  include the implementation of _gimp_param_spec_to_gp_param_def()
+ *  from libgimp, they are identical.
+ */
+#include "../../libgimp/gimpgpparamspecs-body.c"
+
+GParamSpec *
+_gimp_gp_param_def_to_param_spec (Gimp       *gimp,
+                                  GPParamDef *param_def)
+{
+  const gchar *name  = param_def->name;
+  const gchar *nick  = param_def->nick;
+  const gchar *blurb = param_def->blurb;
+  GParamFlags  flags = G_PARAM_READWRITE;
+
+  switch (param_def->param_def_type)
+    {
+    case GP_PARAM_DEF_TYPE_DEFAULT:
+      if (! strcmp (param_def->type_name, "GimpParamInt32Array"))
+        return gimp_param_spec_int32_array (name, nick, blurb, flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamInt16Array"))
+        return gimp_param_spec_int16_array (name, nick, blurb, flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamInt8Array"))
+        return gimp_param_spec_int8_array (name, nick, blurb, flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamFloatArray"))
+        return gimp_param_spec_float_array (name, nick, blurb, flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamStringArray"))
+        return gimp_param_spec_string_array (name, nick, blurb, flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamRGBArray"))
+        return gimp_param_spec_rgb_array (name, nick, blurb, flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamParasite"))
+        return gimp_param_spec_parasite (name, nick, blurb, flags);
+      break;
+
+    case GP_PARAM_DEF_TYPE_INT:
+      if (! strcmp (param_def->type_name, "GimpParamInt32"))
+        return gimp_param_spec_int32 (name, nick, blurb,
+                                      param_def->meta.m_int.min_val,
+                                      param_def->meta.m_int.max_val,
+                                      param_def->meta.m_int.default_val,
+                                      flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamInt16"))
+        return gimp_param_spec_int16 (name, nick, blurb,
+                                      param_def->meta.m_int.min_val,
+                                      param_def->meta.m_int.max_val,
+                                      param_def->meta.m_int.default_val,
+                                      flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamInt8"))
+        return gimp_param_spec_int8 (name, nick, blurb,
+                                     param_def->meta.m_int.min_val,
+                                     param_def->meta.m_int.max_val,
+                                     param_def->meta.m_int.default_val,
+                                     flags);
+      break;
+
+    case GP_PARAM_DEF_TYPE_ENUM:
+      if (! strcmp (param_def->type_name, "GParamEnum"))
+        return g_param_spec_enum (name, nick, blurb,
+                                  g_type_from_name (param_def->meta.m_enum.type_name),
+                                  param_def->meta.m_enum.default_val,
+                                  flags);
+      break;
+
+    case GP_PARAM_DEF_TYPE_BOOLEAN:
+      if (! strcmp (param_def->type_name, "GParamBoolean"))
+        return g_param_spec_boolean (name, nick, blurb,
+                                     param_def->meta.m_boolean.default_val,
+                                     flags);
+      break;
+
+    case GP_PARAM_DEF_TYPE_FLOAT:
+      if (! strcmp (param_def->type_name, "GParamDouble"))
+        return g_param_spec_double (name, nick, blurb,
+                                    param_def->meta.m_float.min_val,
+                                    param_def->meta.m_float.max_val,
+                                    param_def->meta.m_float.default_val,
+                                    flags);
+      break;
+
+    case GP_PARAM_DEF_TYPE_STRING:
+      if (! strcmp (param_def->type_name, "GimpParamString"))
+        return gimp_param_spec_string (name, nick, blurb,
+                                       param_def->meta.m_string.allow_non_utf8,
+                                       param_def->meta.m_string.null_ok,
+                                       param_def->meta.m_string.non_empty,
+                                       param_def->meta.m_string.default_val,
+                                       flags);
+      break;
+
+    case GP_PARAM_DEF_TYPE_COLOR:
+      if (! strcmp (param_def->type_name, "GimpParamRGB"))
+        return gimp_param_spec_rgb (name, nick, blurb,
+                                    param_def->meta.m_color.has_alpha,
+                                    &param_def->meta.m_color.default_val,
+                                    flags);
+
+    case GP_PARAM_DEF_TYPE_ID:
+      if (! strcmp (param_def->type_name, "GimpParamDisplayID"))
+        return gimp_param_spec_display_id (name, nick, blurb,
+                                           gimp,
+                                           param_def->meta.m_id.none_ok,
+                                           flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamImageID"))
+        return gimp_param_spec_image_id (name, nick, blurb,
+                                         gimp,
+                                         param_def->meta.m_id.none_ok,
+                                         flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamItemID"))
+        return gimp_param_spec_item_id (name, nick, blurb,
+                                        gimp,
+                                        param_def->meta.m_id.none_ok,
+                                        flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamDrawableID"))
+        return gimp_param_spec_drawable_id (name, nick, blurb,
+                                            gimp,
+                                            param_def->meta.m_id.none_ok,
+                                            flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamLayerID"))
+        return gimp_param_spec_layer_id (name, nick, blurb,
+                                         gimp,
+                                         param_def->meta.m_id.none_ok,
+                                         flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamChannelID"))
+        return gimp_param_spec_channel_id (name, nick, blurb,
+                                           gimp,
+                                           param_def->meta.m_id.none_ok,
+                                           flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamLayerMaskID"))
+        return gimp_param_spec_layer_mask_id (name, nick, blurb,
+                                              gimp,
+                                              param_def->meta.m_id.none_ok,
+                                              flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamSelectionID"))
+        return gimp_param_spec_selection_id (name, nick, blurb,
+                                             gimp,
+                                             param_def->meta.m_id.none_ok,
+                                             flags);
+
+      if (! strcmp (param_def->type_name, "GimpParamVectorsID"))
+        return gimp_param_spec_vectors_id (name, nick, blurb,
+                                           gimp,
+                                           param_def->meta.m_id.none_ok,
+                                           flags);
+      break;
+    }
+
+  g_printerr ("%s: GParamSpec type '%s' is not handled\n",
+              G_STRFUNC, param_def->type_name);
+
+  return NULL;
+}
diff --git a/app/plug-in/gimpgpparamspecs.h b/app/plug-in/gimpgpparamspecs.h
new file mode 100644
index 0000000000..cc1fe73038
--- /dev/null
+++ b/app/plug-in/gimpgpparamspecs.h
@@ -0,0 +1,35 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpgpparamspecs.h
+ *
+ * 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/>.
+ */
+
+#ifndef __GIMP_GP_PARAM_SPECS_H__
+#define __GIMP_GP_PARAM_SPECS_H__
+
+
+/*  function names start with an underscore because we incude code
+ *  from libgimp/ which is private there
+ */
+
+void         _gimp_param_spec_to_gp_param_def (GParamSpec *pspec,
+                                               GPParamDef *param_def);
+
+GParamSpec * _gimp_gp_param_def_to_param_spec (Gimp       *gimp,
+                                               GPParamDef *param_def);
+
+
+#endif /* __GIMP_GP_PARAM_SPECS_H__ */
diff --git a/app/plug-in/gimpplugin-message.c b/app/plug-in/gimpplugin-message.c
index 0ee2c5d3e3..b1499d59da 100644
--- a/app/plug-in/gimpplugin-message.c
+++ b/app/plug-in/gimpplugin-message.c
@@ -42,6 +42,7 @@
 #include "pdb/gimppdb.h"
 #include "pdb/gimppdberror.h"
 
+#include "gimpgpparamspecs.h"
 #include "gimpplugin.h"
 #include "gimpplugin-cleanup.h"
 #include "gimpplugin-message.h"
@@ -711,13 +712,17 @@ gimp_plug_in_handle_proc_install (GimpPlugIn    *plug_in,
 
   for (i = 1; i < proc_install->nparams; i++)
     {
-      if ((proc_install->params[i].type == GIMP_PDB_INT32ARRAY ||
-           proc_install->params[i].type == GIMP_PDB_INT8ARRAY  ||
-           proc_install->params[i].type == GIMP_PDB_FLOATARRAY ||
-           proc_install->params[i].type == GIMP_PDB_STRINGARRAY ||
-           proc_install->params[i].type == GIMP_PDB_COLORARRAY)
+      GPParamDef *param_def      = &proc_install->params[i];
+      GPParamDef *prev_param_def = &proc_install->params[i - 1];
+
+      if ((! strcmp (param_def->type_name, "GimpParamInt32Array")     ||
+           ! strcmp (param_def->type_name, "GimpParamInt16Array")     ||
+           ! strcmp (param_def->type_name, "GimpParamInt8Array")      ||
+           ! strcmp (param_def->type_name, "GimpParamIntFloatArray")  ||
+           ! strcmp (param_def->type_name, "GimpParamIntStringArray") ||
+           ! strcmp (param_def->type_name, "GimpParamIntColorArray"))
           &&
-          proc_install->params[i - 1].type != GIMP_PDB_INT32)
+          strcmp (prev_param_def->type_name, "GimpParamInt32"))
         {
           gimp_message (plug_in->manager->gimp, NULL, GIMP_MESSAGE_ERROR,
                         "Plug-in \"%s\"\n(%s)\n\n"
@@ -755,7 +760,8 @@ gimp_plug_in_handle_proc_install (GimpPlugIn    *plug_in,
               null_name = TRUE;
             }
           else if (! (VALIDATE         (proc_install->params[i].name) &&
-                      VALIDATE_OR_NULL (proc_install->params[i].description)))
+                      VALIDATE_OR_NULL (proc_install->params[i].nick) &&
+                      VALIDATE_OR_NULL (proc_install->params[i].blurb)))
             {
               valid_utf8 = FALSE;
             }
@@ -768,7 +774,8 @@ gimp_plug_in_handle_proc_install (GimpPlugIn    *plug_in,
               null_name = TRUE;
             }
           else if (! (VALIDATE         (proc_install->return_vals[i].name) &&
-                      VALIDATE_OR_NULL (proc_install->return_vals[i].description)))
+                      VALIDATE_OR_NULL (proc_install->return_vals[i].nick) &&
+                      VALIDATE_OR_NULL (proc_install->return_vals[i].blurb)))
             {
               valid_utf8 = FALSE;
             }
@@ -858,23 +865,44 @@ gimp_plug_in_handle_proc_install (GimpPlugIn    *plug_in,
   for (i = 0; i < proc_install->nparams; i++)
     {
       GParamSpec *pspec =
-        gimp_pdb_compat_param_spec (plug_in->manager->gimp,
-                                    proc_install->params[i].type,
-                                    proc_install->params[i].name,
-                                    proc_install->params[i].description);
+        _gimp_gp_param_def_to_param_spec (plug_in->manager->gimp,
+                                          &proc_install->params[i]);
 
-      gimp_procedure_add_argument (procedure, pspec);
+      if (pspec)
+        {
+          if (i == 0 &&
+              GIMP_IS_PARAM_SPEC_INT32 (pspec) &&
+              (! strcmp ("run-mode", g_param_spec_get_name (pspec)) ||
+               ! strcmp ("run_mode", g_param_spec_get_name (pspec))))
+            {
+              GParamSpec *enum_spec =
+                g_param_spec_enum (g_param_spec_get_name (pspec),
+                                   g_param_spec_get_nick (pspec),
+                                   g_param_spec_get_blurb (pspec),
+                                   GIMP_TYPE_RUN_MODE,
+                                   G_PARAM_SPEC_INT (pspec)->default_value,
+                                   pspec->flags);
+
+              gimp_procedure_add_argument (procedure, enum_spec);
+
+              g_param_spec_ref_sink (pspec);
+              g_param_spec_unref (pspec);
+            }
+          else
+            {
+              gimp_procedure_add_argument (procedure, pspec);
+            }
+        }
     }
 
   for (i = 0; i < proc_install->nreturn_vals; i++)
     {
       GParamSpec *pspec =
-        gimp_pdb_compat_param_spec (plug_in->manager->gimp,
-                                    proc_install->return_vals[i].type,
-                                    proc_install->return_vals[i].name,
-                                    proc_install->return_vals[i].description);
+        _gimp_gp_param_def_to_param_spec (plug_in->manager->gimp,
+                                          &proc_install->return_vals[i]);
 
-      gimp_procedure_add_return_value (procedure, pspec);
+      if (pspec)
+        gimp_procedure_add_return_value (procedure, pspec);
     }
 
   /*  Install the procedure  */
diff --git a/app/plug-in/gimppluginmanager-file.c b/app/plug-in/gimppluginmanager-file.c
index beadf226f4..7b67f1b46d 100644
--- a/app/plug-in/gimppluginmanager-file.c
+++ b/app/plug-in/gimppluginmanager-file.c
@@ -45,6 +45,13 @@ static gboolean   file_procedure_in_group (GimpPlugInProcedure    *file_proc,
 
 /*  public functions  */
 
+static inline gboolean
+GIMP_IS_PARAM_SPEC_RUN_MODE (GParamSpec *pspec)
+{
+  return (G_IS_PARAM_SPEC_ENUM (pspec) &&
+          pspec->value_type == GIMP_TYPE_RUN_MODE);
+}
+
 gboolean
 gimp_plug_in_manager_register_load_handler (GimpPlugInManager *manager,
                                             const gchar       *name,
@@ -78,7 +85,7 @@ gimp_plug_in_manager_register_load_handler (GimpPlugInManager *manager,
 
   if (((procedure->num_args   < 3)                        ||
        (procedure->num_values < 1)                        ||
-       ! GIMP_IS_PARAM_SPEC_INT32    (procedure->args[0]) ||
+       ! GIMP_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) ||
        ! G_IS_PARAM_SPEC_STRING      (procedure->args[1]) ||
        ! G_IS_PARAM_SPEC_STRING      (procedure->args[2]) ||
        (! file_proc->generic_file_proc &&
@@ -130,7 +137,7 @@ gimp_plug_in_manager_register_save_handler (GimpPlugInManager *manager,
   procedure = GIMP_PROCEDURE (file_proc);
 
   if ((procedure->num_args < 5)                             ||
-      ! GIMP_IS_PARAM_SPEC_INT32       (procedure->args[0]) ||
+      ! GIMP_IS_PARAM_SPEC_RUN_MODE    (procedure->args[0]) ||
       ! GIMP_IS_PARAM_SPEC_IMAGE_ID    (procedure->args[1]) ||
       ! GIMP_IS_PARAM_SPEC_DRAWABLE_ID (procedure->args[2]) ||
       ! G_IS_PARAM_SPEC_STRING         (procedure->args[3]) ||
diff --git a/app/plug-in/gimppluginprocedure.c b/app/plug-in/gimppluginprocedure.c
index 33a0dab2e2..dab746b8c1 100644
--- a/app/plug-in/gimppluginprocedure.c
+++ b/app/plug-in/gimppluginprocedure.c
@@ -442,6 +442,13 @@ gimp_plug_in_procedure_real_get_file (GimpPlugInProcedure *procedure)
   return procedure->file;
 }
 
+static inline gboolean
+GIMP_IS_PARAM_SPEC_RUN_MODE (GParamSpec *pspec)
+{
+  return (G_IS_PARAM_SPEC_ENUM (pspec) &&
+          pspec->value_type == GIMP_TYPE_RUN_MODE);
+}
+
 static gboolean
 gimp_plug_in_procedure_validate_args (GimpPlugInProcedure *proc,
                                       Gimp                *gimp,
@@ -459,7 +466,7 @@ gimp_plug_in_procedure_validate_args (GimpPlugInProcedure *proc,
 
       if ((procedure->num_args   >= 3)                     &&
           (procedure->num_values >= 1)                     &&
-          GIMP_IS_PARAM_SPEC_INT32    (procedure->args[0]) &&
+          GIMP_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) &&
           G_IS_PARAM_SPEC_STRING      (procedure->args[1]) &&
           G_IS_PARAM_SPEC_STRING      (procedure->args[2]) &&
           GIMP_IS_PARAM_SPEC_IMAGE_ID (procedure->values[0]))
@@ -467,7 +474,7 @@ gimp_plug_in_procedure_validate_args (GimpPlugInProcedure *proc,
           uri_value = gimp_value_array_index (args, 1);
         }
       else if ((procedure->num_args >= 5)                          &&
-               GIMP_IS_PARAM_SPEC_INT32       (procedure->args[0]) &&
+               GIMP_IS_PARAM_SPEC_RUN_MODE    (procedure->args[0]) &&
                GIMP_IS_PARAM_SPEC_IMAGE_ID    (procedure->args[1]) &&
                GIMP_IS_PARAM_SPEC_DRAWABLE_ID (procedure->args[2]) &&
                G_IS_PARAM_SPEC_STRING         (procedure->args[3]) &&
@@ -613,69 +620,69 @@ gimp_plug_in_procedure_add_menu_path (GimpPlugInProcedure  *proc,
   if (g_str_has_prefix (menu_path, "<Image>"))
     {
       if ((procedure->num_args < 1) ||
-          ! GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0]))
+          ! GIMP_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]))
         {
-          required = "INT32";
+          required = "(INT32 | ENUM GimpRunMode)";
           goto failure;
         }
     }
   else if (g_str_has_prefix (menu_path, "<Layers>"))
     {
-      if ((procedure->num_args < 3)                             ||
-          ! GIMP_IS_PARAM_SPEC_INT32       (procedure->args[0]) ||
-          ! GIMP_IS_PARAM_SPEC_IMAGE_ID    (procedure->args[1]) ||
+      if ((procedure->num_args < 3)                          ||
+          ! GIMP_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) ||
+          ! GIMP_IS_PARAM_SPEC_IMAGE_ID (procedure->args[1]) ||
           ! (G_TYPE_FROM_INSTANCE (procedure->args[2])
-                               == GIMP_TYPE_PARAM_LAYER_ID ||
+                               == GIMP_TYPE_PARAM_LAYER_ID   ||
              G_TYPE_FROM_INSTANCE (procedure->args[2])
                                == GIMP_TYPE_PARAM_DRAWABLE_ID))
         {
-          required = "INT32, IMAGE, (LAYER | DRAWABLE)";
+          required = "(INT32 | ENUM GimpRunMode), IMAGE, (LAYER | DRAWABLE)";
           goto failure;
         }
     }
   else if (g_str_has_prefix (menu_path, "<Channels>"))
     {
-      if ((procedure->num_args < 3)                             ||
-          ! GIMP_IS_PARAM_SPEC_INT32       (procedure->args[0]) ||
-          ! GIMP_IS_PARAM_SPEC_IMAGE_ID    (procedure->args[1]) ||
+      if ((procedure->num_args < 3)                          ||
+          ! GIMP_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) ||
+          ! GIMP_IS_PARAM_SPEC_IMAGE_ID (procedure->args[1]) ||
           ! (G_TYPE_FROM_INSTANCE (procedure->args[2])
                                == GIMP_TYPE_PARAM_CHANNEL_ID ||
              G_TYPE_FROM_INSTANCE (procedure->args[2])
                                == GIMP_TYPE_PARAM_DRAWABLE_ID))
         {
-          required = "INT32, IMAGE, (CHANNEL | DRAWABLE)";
+          required = "(INT32 | ENUM GimpRunMode), IMAGE, (CHANNEL | DRAWABLE)";
           goto failure;
         }
     }
   else if (g_str_has_prefix (menu_path, "<Vectors>"))
     {
       if ((procedure->num_args < 3)                            ||
-          ! GIMP_IS_PARAM_SPEC_INT32      (procedure->args[0]) ||
+          ! GIMP_IS_PARAM_SPEC_RUN_MODE   (procedure->args[0]) ||
           ! GIMP_IS_PARAM_SPEC_IMAGE_ID   (procedure->args[1]) ||
           ! GIMP_IS_PARAM_SPEC_VECTORS_ID (procedure->args[2]))
         {
-          required = "INT32, IMAGE, VECTORS";
+          required = "(INT32 | ENUM GimpRunMode), IMAGE, VECTORS";
           goto failure;
         }
     }
   else if (g_str_has_prefix (menu_path, "<Colormap>"))
     {
-      if ((procedure->num_args < 2)                            ||
-          ! GIMP_IS_PARAM_SPEC_INT32      (procedure->args[0]) ||
-          ! GIMP_IS_PARAM_SPEC_IMAGE_ID   (procedure->args[1]))
+      if ((procedure->num_args < 2)                          ||
+          ! GIMP_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) ||
+          ! GIMP_IS_PARAM_SPEC_IMAGE_ID (procedure->args[1]))
         {
-          required = "INT32, IMAGE";
+          required = "(INT32 | ENUM GimpRunMode), IMAGE";
           goto failure;
         }
     }
   else if (g_str_has_prefix (menu_path, "<Load>"))
     {
-      if ((procedure->num_args < 3)                       ||
-          ! GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0]) ||
-          ! G_IS_PARAM_SPEC_STRING   (procedure->args[1]) ||
-          ! G_IS_PARAM_SPEC_STRING   (procedure->args[2]))
+      if ((procedure->num_args < 3)                          ||
+          ! GIMP_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) ||
+          ! G_IS_PARAM_SPEC_STRING      (procedure->args[1]) ||
+          ! G_IS_PARAM_SPEC_STRING      (procedure->args[2]))
         {
-          required = "INT32, STRING, STRING";
+          required = "(INT32 | ENUM GimpRunMode), STRING, STRING";
           goto failure;
         }
 
@@ -689,13 +696,13 @@ gimp_plug_in_procedure_add_menu_path (GimpPlugInProcedure  *proc,
   else if (g_str_has_prefix (menu_path, "<Save>"))
     {
       if ((procedure->num_args < 5)                             ||
-          ! GIMP_IS_PARAM_SPEC_INT32       (procedure->args[0]) ||
+          ! GIMP_IS_PARAM_SPEC_RUN_MODE    (procedure->args[0]) ||
           ! GIMP_IS_PARAM_SPEC_IMAGE_ID    (procedure->args[1]) ||
           ! GIMP_IS_PARAM_SPEC_DRAWABLE_ID (procedure->args[2]) ||
           ! G_IS_PARAM_SPEC_STRING         (procedure->args[3]) ||
           ! G_IS_PARAM_SPEC_STRING         (procedure->args[4]))
         {
-          required = "INT32, IMAGE, DRAWABLE, STRING, STRING";
+          required = "(INT32 | ENUM GimpRunMode), IMAGE, DRAWABLE, STRING, STRING";
           goto failure;
         }
     }
@@ -710,9 +717,9 @@ gimp_plug_in_procedure_add_menu_path (GimpPlugInProcedure  *proc,
            g_str_has_prefix (menu_path, "<Buffers>"))
     {
       if ((procedure->num_args < 1) ||
-          ! GIMP_IS_PARAM_SPEC_INT32 (procedure->args[0]))
+          ! GIMP_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]))
         {
-          required = "INT32";
+          required = "(INT32 | ENUM GimpRunMode)";
           goto failure;
         }
     }
diff --git a/app/plug-in/plug-in-rc.c b/app/plug-in/plug-in-rc.c
index 87bd8e7292..500e543ebb 100644
--- a/app/plug-in/plug-in-rc.c
+++ b/app/plug-in/plug-in-rc.c
@@ -33,6 +33,7 @@
 
 #include "pdb/gimp-pdb-compat.h"
 
+#include "gimpgpparamspecs.h"
 #include "gimpplugindef.h"
 #include "gimppluginprocedure.h"
 #include "plug-in-rc.h"
@@ -742,9 +743,7 @@ plug_in_proc_arg_deserialize (GScanner      *scanner,
                               gboolean       return_value)
 {
   GTokenType  token;
-  gint        arg_type;
-  gchar      *name = NULL;
-  gchar      *desc = NULL;
+  GPParamDef  param_def = { 0, };
   GParamSpec *pspec;
 
   if (! gimp_scanner_parse_token (scanner, G_TOKEN_LEFT_PAREN))
@@ -760,20 +759,124 @@ plug_in_proc_arg_deserialize (GScanner      *scanner,
       goto error;
     }
 
-  if (! gimp_scanner_parse_int (scanner, (gint *) &arg_type))
+  if (! gimp_scanner_parse_int (scanner, (gint *) &param_def.param_def_type))
     {
       token = G_TOKEN_INT;
       goto error;
     }
-  if (! gimp_scanner_parse_string (scanner, &name))
+
+  if (! gimp_scanner_parse_string (scanner, &param_def.type_name) ||
+      ! gimp_scanner_parse_string (scanner, &param_def.name)      ||
+      ! gimp_scanner_parse_string (scanner, &param_def.nick)      ||
+      ! gimp_scanner_parse_string (scanner, &param_def.blurb))
     {
       token = G_TOKEN_STRING;
       goto error;
     }
-  if (! gimp_scanner_parse_string (scanner, &desc))
+
+  switch (param_def.param_def_type)
     {
-      token = G_TOKEN_STRING;
-      goto error;
+    case GP_PARAM_DEF_TYPE_DEFAULT:
+      break;
+
+    case GP_PARAM_DEF_TYPE_INT:
+      if (! gimp_scanner_parse_int (scanner,
+                                    &param_def.meta.m_int.min_val) ||
+          ! gimp_scanner_parse_int (scanner,
+                                    &param_def.meta.m_int.max_val) ||
+          ! gimp_scanner_parse_int (scanner,
+                                    &param_def.meta.m_int.default_val))
+        {
+          token = G_TOKEN_INT;
+          goto error;
+        }
+      break;
+
+    case GP_PARAM_DEF_TYPE_ENUM:
+      if (! gimp_scanner_parse_string (scanner,
+                                       &param_def.meta.m_enum.type_name))
+        {
+          token = G_TOKEN_STRING;
+          goto error;
+        }
+      if (! gimp_scanner_parse_int (scanner,
+                                    &param_def.meta.m_enum.default_val))
+        {
+          token = G_TOKEN_STRING;
+          goto error;
+        }
+      break;
+
+    case GP_PARAM_DEF_TYPE_BOOLEAN:
+      if (! gimp_scanner_parse_int (scanner,
+                                    &param_def.meta.m_boolean.default_val))
+        {
+          token = G_TOKEN_INT;
+          goto error;
+        }
+      break;
+
+    case GP_PARAM_DEF_TYPE_FLOAT:
+      if (! gimp_scanner_parse_float (scanner,
+                                      &param_def.meta.m_float.min_val) ||
+          ! gimp_scanner_parse_float (scanner,
+                                      &param_def.meta.m_float.max_val) ||
+          ! gimp_scanner_parse_float (scanner,
+                                      &param_def.meta.m_float.default_val))
+        {
+          token = G_TOKEN_FLOAT;
+          goto error;
+        }
+      break;
+
+    case GP_PARAM_DEF_TYPE_STRING:
+      if (! gimp_scanner_parse_int (scanner,
+                                    &param_def.meta.m_string.allow_non_utf8) ||
+          ! gimp_scanner_parse_int (scanner,
+                                    &param_def.meta.m_string.null_ok) ||
+          ! gimp_scanner_parse_int (scanner,
+                                    &param_def.meta.m_string.non_empty))
+        {
+          token = G_TOKEN_INT;
+          goto error;
+        }
+      if (! gimp_scanner_parse_string (scanner,
+                                       &param_def.meta.m_string.default_val))
+        {
+          token = G_TOKEN_STRING;
+          goto error;
+        }
+      break;
+
+    case GP_PARAM_DEF_TYPE_COLOR:
+      if (! gimp_scanner_parse_int (scanner,
+                                    &param_def.meta.m_color.has_alpha))
+        {
+          token = G_TOKEN_INT;
+          goto error;
+        }
+      if (! gimp_scanner_parse_float (scanner,
+                                      &param_def.meta.m_color.default_val.r) ||
+          ! gimp_scanner_parse_float (scanner,
+                                      &param_def.meta.m_color.default_val.g) ||
+          ! gimp_scanner_parse_float (scanner,
+                                      &param_def.meta.m_color.default_val.b) ||
+          ! gimp_scanner_parse_float (scanner,
+                                      &param_def.meta.m_color.default_val.a))
+        {
+          token = G_TOKEN_FLOAT;
+          goto error;
+        }
+      break;
+
+    case GP_PARAM_DEF_TYPE_ID:
+      if (! gimp_scanner_parse_int (scanner,
+                                    &param_def.meta.m_id.none_ok))
+        {
+          token = G_TOKEN_INT;
+          goto error;
+        }
+      break;
     }
 
   if (! gimp_scanner_parse_token (scanner, G_TOKEN_RIGHT_PAREN))
@@ -784,7 +887,7 @@ plug_in_proc_arg_deserialize (GScanner      *scanner,
 
   token = G_TOKEN_LEFT_PAREN;
 
-  pspec = gimp_pdb_compat_param_spec (gimp, arg_type, name, desc);
+  pspec = _gimp_gp_param_def_to_param_spec (gimp, &param_def);
 
   if (return_value)
     gimp_procedure_add_return_value (procedure, pspec);
@@ -793,8 +896,33 @@ plug_in_proc_arg_deserialize (GScanner      *scanner,
 
  error:
 
-  g_free (name);
-  g_free (desc);
+  g_free (param_def.type_name);
+  g_free (param_def.name);
+  g_free (param_def.nick);
+  g_free (param_def.blurb);
+
+  switch (param_def.param_def_type)
+    {
+    case GP_PARAM_DEF_TYPE_DEFAULT:
+    case GP_PARAM_DEF_TYPE_INT:
+      break;
+
+    case GP_PARAM_DEF_TYPE_ENUM:
+      g_free (param_def.meta.m_enum.type_name);
+      break;
+
+    case GP_PARAM_DEF_TYPE_BOOLEAN:
+    case GP_PARAM_DEF_TYPE_FLOAT:
+      break;
+
+    case GP_PARAM_DEF_TYPE_STRING:
+      g_free (param_def.meta.m_string.default_val);
+      break;
+
+    case GP_PARAM_DEF_TYPE_COLOR:
+    case GP_PARAM_DEF_TYPE_ID:
+      break;
+    }
 
   return token;
 }
@@ -864,6 +992,80 @@ plug_in_has_init_deserialize (GScanner      *scanner,
 
 /* serialize functions */
 
+static void
+plug_in_rc_write_proc_arg (GimpConfigWriter *writer,
+                           GParamSpec       *pspec)
+{
+  GPParamDef param_def = { 0, };
+
+  _gimp_param_spec_to_gp_param_def (pspec, &param_def);
+
+  gimp_config_writer_open (writer, "proc-arg");
+  gimp_config_writer_printf (writer, "%d", param_def.param_def_type);
+
+  gimp_config_writer_string (writer, param_def.type_name);
+  gimp_config_writer_string (writer, g_param_spec_get_name (pspec));
+  gimp_config_writer_string (writer, g_param_spec_get_nick (pspec));
+  gimp_config_writer_string (writer, g_param_spec_get_blurb (pspec));
+
+  switch (param_def.param_def_type)
+    {
+    case GP_PARAM_DEF_TYPE_DEFAULT:
+      break;
+
+    case GP_PARAM_DEF_TYPE_INT:
+      gimp_config_writer_printf (writer, "%d %d %d",
+                                 param_def.meta.m_int.min_val,
+                                 param_def.meta.m_int.max_val,
+                                 param_def.meta.m_int.default_val);
+      break;
+
+    case GP_PARAM_DEF_TYPE_ENUM:
+      gimp_config_writer_string (writer,
+                                 param_def.meta.m_enum.type_name);
+      gimp_config_writer_printf (writer, "%d",
+                                 param_def.meta.m_enum.default_val);
+      break;
+
+    case GP_PARAM_DEF_TYPE_BOOLEAN:
+      gimp_config_writer_printf (writer, "%d",
+                                 param_def.meta.m_boolean.default_val);
+      break;
+
+    case GP_PARAM_DEF_TYPE_FLOAT:
+      gimp_config_writer_printf (writer, "%f %f %f",
+                                 param_def.meta.m_float.min_val,
+                                 param_def.meta.m_float.max_val,
+                                 param_def.meta.m_float.default_val);
+      break;
+
+    case GP_PARAM_DEF_TYPE_STRING:
+      gimp_config_writer_printf (writer, "%d %d %d",
+                                 param_def.meta.m_string.allow_non_utf8,
+                                 param_def.meta.m_string.null_ok,
+                                 param_def.meta.m_string.non_empty);
+      gimp_config_writer_string (writer,
+                                 param_def.meta.m_string.default_val);
+      break;
+
+    case GP_PARAM_DEF_TYPE_COLOR:
+      gimp_config_writer_printf (writer, "%d %f %f %f %f",
+                                 param_def.meta.m_color.has_alpha,
+                                 param_def.meta.m_color.default_val.r,
+                                 param_def.meta.m_color.default_val.g,
+                                 param_def.meta.m_color.default_val.b,
+                                 param_def.meta.m_color.default_val.a);
+      break;
+
+    case GP_PARAM_DEF_TYPE_ID:
+      gimp_config_writer_printf (writer, "%d",
+                                 param_def.meta.m_id.none_ok);
+      break;
+    }
+
+  gimp_config_writer_close (writer);
+}
+
 gboolean
 plug_in_rc_write (GSList  *plug_in_defs,
                   GFile   *file,
@@ -1057,32 +1259,14 @@ plug_in_rc_write (GSList  *plug_in_defs,
                 {
                   GParamSpec *pspec = procedure->args[i];
 
-                  gimp_config_writer_open (writer, "proc-arg");
-                  gimp_config_writer_printf (writer, "%d",
-                                             gimp_pdb_compat_arg_type_from_gtype (G_PARAM_SPEC_VALUE_TYPE 
(pspec)));
-
-                  gimp_config_writer_string (writer,
-                                             g_param_spec_get_name (pspec));
-                  gimp_config_writer_string (writer,
-                                             g_param_spec_get_blurb (pspec));
-
-                  gimp_config_writer_close (writer);
+                  plug_in_rc_write_proc_arg (writer, pspec);
                 }
 
               for (i = 0; i < procedure->num_values; i++)
                 {
                   GParamSpec *pspec = procedure->values[i];
 
-                  gimp_config_writer_open (writer, "proc-arg");
-                  gimp_config_writer_printf (writer, "%d",
-                                             gimp_pdb_compat_arg_type_from_gtype (G_PARAM_SPEC_VALUE_TYPE 
(pspec)));
-
-                  gimp_config_writer_string (writer,
-                                             g_param_spec_get_name (pspec));
-                  gimp_config_writer_string (writer,
-                                             g_param_spec_get_blurb (pspec));
-
-                  gimp_config_writer_close (writer);
+                  plug_in_rc_write_proc_arg (writer, pspec);
                 }
 
               gimp_config_writer_close (writer);
diff --git a/app/tests/Makefile.am b/app/tests/Makefile.am
index 841daf6da0..3bb2097975 100644
--- a/app/tests/Makefile.am
+++ b/app/tests/Makefile.am
@@ -87,7 +87,6 @@ AM_LDFLAGS = \
        -Wl,-u,$(SYMPREFIX)xcf_init                             \
        -Wl,-u,$(SYMPREFIX)internal_procs_init                  \
        -Wl,-u,$(SYMPREFIX)gimp_plug_in_manager_restore         \
-       -Wl,-u,$(SYMPREFIX)gimp_pdb_compat_param_spec           \
        -Wl,-u,$(SYMPREFIX)gimp_layer_mode_is_legacy            \
        -Wl,-u,$(SYMPREFIX)gui_init                             \
        -Wl,-u,$(SYMPREFIX)gimp_tool_cursors_get_resource       \
diff --git a/app/xcf/xcf.c b/app/xcf/xcf.c
index 254da0841a..de7a2f6279 100644
--- a/app/xcf/xcf.c
+++ b/app/xcf/xcf.c
@@ -135,11 +135,12 @@ xcf_init (Gimp *gimp)
                                      NULL);
 
   gimp_procedure_add_argument (procedure,
-                               gimp_param_spec_int32 ("dummy-param",
-                                                      "Dummy Param",
-                                                      "Dummy parameter",
-                                                      G_MININT32, G_MAXINT32, 0,
-                                                      GIMP_PARAM_READWRITE));
+                               gimp_param_spec_enum ("dummy-param",
+                                                     "Dummy Param",
+                                                     "Dummy parameter",
+                                                     GIMP_TYPE_RUN_MODE,
+                                                     GIMP_RUN_INTERACTIVE,
+                                                     GIMP_PARAM_READWRITE));
   gimp_procedure_add_argument (procedure,
                                gimp_param_spec_image_id ("image",
                                                          "Image",
@@ -207,11 +208,12 @@ xcf_init (Gimp *gimp)
                                      NULL);
 
   gimp_procedure_add_argument (procedure,
-                               gimp_param_spec_int32 ("dummy-param",
-                                                      "Dummy Param",
-                                                      "Dummy parameter",
-                                                      G_MININT32, G_MAXINT32, 0,
-                                                      GIMP_PARAM_READWRITE));
+                               gimp_param_spec_enum ("dummy-param",
+                                                     "Dummy Param",
+                                                     "Dummy parameter",
+                                                     GIMP_TYPE_RUN_MODE,
+                                                     GIMP_RUN_INTERACTIVE,
+                                                     GIMP_PARAM_READWRITE));
   gimp_procedure_add_argument (procedure,
                                gimp_param_spec_string ("filename",
                                                        "Filename",
diff --git a/libgimp/Makefile.am b/libgimp/Makefile.am
index 3c948e20d8..cafc2e00db 100644
--- a/libgimp/Makefile.am
+++ b/libgimp/Makefile.am
@@ -107,10 +107,18 @@ libgimp_built_sources = \
        gimpenums.c
 
 libgimp_private_sources = \
+       gimpgpcompat.c          \
+       gimpgpcompat.h          \
+       gimpgpparamspecs.c      \
+       gimpgpparamspecs.h      \
        gimpplugin-private.c    \
-       gimpplugin-private.h
+       gimpplugin-private.h    \
+       gimpprocedure-private.c \
+       gimpprocedure-private.h
 
-libgimp_extra_sources = gimpenums.c.tail
+libgimp_extra_sources = \
+       gimpenums.c.tail        \
+       gimpgpparamspecs-body.c
 
 libgimp_@GIMP_API_VERSION@_la_SOURCES = \
        $(libgimp_built_sources)        \
diff --git a/libgimp/gimp.c b/libgimp/gimp.c
index bd3a0a1f52..63f6331dbf 100644
--- a/libgimp/gimp.c
+++ b/libgimp/gimp.c
@@ -118,6 +118,8 @@
 #include "libgimpbase/gimpwire.h"
 
 #include "gimp.h"
+#include "gimpgpcompat.h"
+#include "gimpgpparamspecs.h"
 #include "gimpplugin-private.h"
 #include "gimpunitcache.h"
 
@@ -255,8 +257,8 @@ static const GDebugKey gimp_debug_keys[] =
   { "on",             GIMP_DEBUG_DEFAULT        }
 };
 
-static GimpPlugIn     *PLUG_IN;
-static GimpPlugInInfo  PLUG_IN_INFO;
+static GimpPlugIn     *PLUG_IN      = NULL;
+static GimpPlugInInfo  PLUG_IN_INFO = { 0, };
 
 
 static GimpPDBStatusType  pdb_error_status   = GIMP_PDB_SUCCESS;
@@ -725,7 +727,7 @@ gimp_main_internal (GType                 plug_in_type,
     {
       if (PLUG_IN)
         {
-          if (GIMP_PLUG_IN_GET_CLASS (PLUG_IN)->init)
+          if (GIMP_PLUG_IN_GET_CLASS (PLUG_IN)->init_procedures)
             gp_has_init_write (_writechannel, NULL);
         }
       else
@@ -889,7 +891,9 @@ gimp_install_procedure (const gchar        *name,
                         const GimpParamDef *params,
                         const GimpParamDef *return_vals)
 {
-  GPProcInstall proc_install;
+  GPProcInstall  proc_install;
+  GList         *pspecs = NULL;
+  gint           i;
 
   g_return_if_fail (name != NULL);
   g_return_if_fail (type != GIMP_INTERNAL);
@@ -909,11 +913,41 @@ gimp_install_procedure (const gchar        *name,
   proc_install.type         = type;
   proc_install.nparams      = n_params;
   proc_install.nreturn_vals = n_return_vals;
-  proc_install.params       = (GPParamDef *) params;
-  proc_install.return_vals  = (GPParamDef *) return_vals;
+  proc_install.params       = g_new0 (GPParamDef, n_params);
+  proc_install.return_vals  = g_new0 (GPParamDef, n_return_vals);
+
+  for (i = 0; i < n_params; i++)
+    {
+      GParamSpec *pspec = _gimp_gp_compat_param_spec (params[i].type,
+                                                      params[i].name,
+                                                      params[i].name,
+                                                      params[i].description);
+
+      _gimp_param_spec_to_gp_param_def (pspec, &proc_install.params[i]);
+
+      pspecs = g_list_prepend (pspecs, pspec);
+    }
+
+  for (i = 0; i < n_return_vals; i++)
+    {
+      GParamSpec *pspec = _gimp_gp_compat_param_spec (return_vals[i].type,
+                                                      return_vals[i].name,
+                                                      return_vals[i].name,
+                                                      return_vals[i].description);
+
+      _gimp_param_spec_to_gp_param_def (pspec, &proc_install.return_vals[i]);
+
+      pspecs = g_list_prepend (pspecs, pspec);
+    }
 
   if (! gp_proc_install_write (_writechannel, &proc_install, NULL))
     gimp_quit ();
+
+  g_list_foreach (pspecs, (GFunc) g_param_spec_ref_sink, NULL);
+  g_list_free_full (pspecs, (GDestroyNotify) g_param_spec_unref);
+
+  g_free (proc_install.params);
+  g_free (proc_install.return_vals);
 }
 
 /**
@@ -2373,16 +2407,41 @@ gimp_proc_run (GPProcRun *proc_run)
   if (PLUG_IN || PLUG_IN_INFO.run_proc)
     {
       GPProcReturn  proc_return;
-      GimpParam    *return_vals;
-      gint          n_return_vals;
+      GimpParam    *return_vals   = NULL;
+      gint          n_return_vals = 0;
 
       if (PLUG_IN)
         {
-          _gimp_plug_in_run (PLUG_IN,
-                             proc_run->name,
-                             proc_run->nparams,
-                             (GimpParam *) proc_run->params,
-                             &n_return_vals, &return_vals);
+          GimpProcedure   *procedure;
+          GimpValueArray  *arguments;
+          GimpValueArray  *return_values;
+          GParamSpec     **arg_specs;
+          gint             n_arg_specs;
+
+          procedure = gimp_plug_in_create_procedure (PLUG_IN, proc_run->name);
+
+          if (procedure)
+            {
+              arg_specs = gimp_procedure_get_arguments (procedure,
+                                                        &n_arg_specs);
+
+              arguments = _gimp_pdb_params_to_args (arg_specs,
+                                                    n_arg_specs,
+                                                    (GimpParam *) proc_run->params,
+                                                    proc_run->nparams,
+                                                    FALSE, FALSE);
+
+              return_values = gimp_procedure_run (procedure, arguments);
+
+              gimp_value_array_unref (arguments);
+
+              n_return_vals = gimp_value_array_length (return_values);
+              return_vals   = _gimp_pdb_args_to_params (return_values, TRUE);
+
+              gimp_value_array_unref (return_values);
+
+              g_object_unref (procedure);
+            }
          }
       else
         {
diff --git a/libgimp/gimpgpcompat.c b/libgimp/gimpgpcompat.c
new file mode 100644
index 0000000000..9d9fb5d633
--- /dev/null
+++ b/libgimp/gimpgpcompat.c
@@ -0,0 +1,756 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball
+ *
+ * gimppdbcompat.c
+ *
+ * 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 <gegl.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpbase/gimpprotocol.h"
+#include "libgimpcolor/gimpcolor.h"
+
+#include "gimp.h"
+#include "gimpgpcompat.h"
+
+
+GParamSpec *
+_gimp_gp_compat_param_spec (GimpPDBArgType  arg_type,
+                            const gchar    *name,
+                            const gchar    *nick,
+                            const gchar    *blurb)
+{
+  GParamSpec *pspec = NULL;
+
+  g_return_val_if_fail (name != NULL, NULL);
+
+  switch (arg_type)
+    {
+    case GIMP_PDB_INT32:
+      pspec = gimp_param_spec_int32 (name, nick, blurb,
+                                     G_MININT32, G_MAXINT32, 0,
+                                     G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_INT16:
+      pspec = gimp_param_spec_int16 (name, nick, blurb,
+                                     G_MININT16, G_MAXINT16, 0,
+                                     G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_INT8:
+      pspec = gimp_param_spec_int8 (name, nick, blurb,
+                                    0, G_MAXUINT8, 0,
+                                    G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_FLOAT:
+      pspec = g_param_spec_double (name, nick, blurb,
+                                   -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+                                   G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_STRING:
+      pspec = gimp_param_spec_string (name, nick, blurb,
+                                      TRUE, TRUE, FALSE,
+                                      NULL,
+                                      G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_INT32ARRAY:
+      pspec = gimp_param_spec_int32_array (name, nick, blurb,
+                                           G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_INT16ARRAY:
+      pspec = gimp_param_spec_int16_array (name, nick, blurb,
+                                           G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_INT8ARRAY:
+      pspec = gimp_param_spec_int8_array (name, nick, blurb,
+                                          G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_FLOATARRAY:
+      pspec = gimp_param_spec_float_array (name, nick, blurb,
+                                           G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_STRINGARRAY:
+      pspec = gimp_param_spec_string_array (name, nick, blurb,
+                                            G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_COLOR:
+      pspec = gimp_param_spec_rgb (name, nick, blurb,
+                                   TRUE, NULL,
+                                   G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_ITEM:
+      pspec = gimp_param_spec_item_id (name, nick, blurb,
+                                       TRUE,
+                                       G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_DISPLAY:
+      pspec = gimp_param_spec_display_id (name, nick, blurb,
+                                          TRUE,
+                                          G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_IMAGE:
+      pspec = gimp_param_spec_image_id (name, nick, blurb,
+                                        TRUE,
+                                        G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_LAYER:
+      pspec = gimp_param_spec_layer_id (name, nick, blurb,
+                                        TRUE,
+                                        G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_CHANNEL:
+      pspec = gimp_param_spec_channel_id (name, nick, blurb,
+                                          TRUE,
+                                          G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_DRAWABLE:
+      pspec = gimp_param_spec_drawable_id (name, nick, blurb,
+                                           TRUE,
+                                           G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_SELECTION:
+      pspec = gimp_param_spec_selection_id (name, nick, blurb,
+                                            TRUE,
+                                            G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_COLORARRAY:
+      pspec = gimp_param_spec_rgb_array (name, nick, blurb,
+                                         G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_VECTORS:
+      pspec = gimp_param_spec_vectors_id (name, nick, blurb,
+                                          TRUE,
+                                          G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_PARASITE:
+      pspec = gimp_param_spec_parasite (name, nick, blurb,
+                                        G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_STATUS:
+      pspec = g_param_spec_enum (name, nick, blurb,
+                                 GIMP_TYPE_PDB_STATUS_TYPE,
+                                 GIMP_PDB_EXECUTION_ERROR,
+                                 G_PARAM_READWRITE);
+      break;
+
+    case GIMP_PDB_END:
+      break;
+    }
+
+  if (! pspec)
+    g_warning ("%s: returning NULL for %s (%s)",
+               G_STRFUNC, name, _gimp_pdb_arg_type_to_string (arg_type));
+
+  return pspec;
+}
+
+GType
+_gimp_pdb_arg_type_to_gtype (GimpPDBArgType  type)
+{
+  switch (type)
+    {
+    case GIMP_PDB_INT32:
+      return GIMP_TYPE_INT32;
+
+    case GIMP_PDB_INT16:
+      return GIMP_TYPE_INT16;
+
+    case GIMP_PDB_INT8:
+      return GIMP_TYPE_INT8;
+
+    case GIMP_PDB_FLOAT:
+      return G_TYPE_DOUBLE;
+
+    case GIMP_PDB_STRING:
+      return G_TYPE_STRING;
+
+    case GIMP_PDB_INT32ARRAY:
+      return GIMP_TYPE_INT32_ARRAY;
+
+    case GIMP_PDB_INT16ARRAY:
+      return GIMP_TYPE_INT16_ARRAY;
+
+    case GIMP_PDB_INT8ARRAY:
+      return GIMP_TYPE_INT8_ARRAY;
+
+    case GIMP_PDB_FLOATARRAY:
+      return GIMP_TYPE_FLOAT_ARRAY;
+
+    case GIMP_PDB_STRINGARRAY:
+      return GIMP_TYPE_STRING_ARRAY;
+
+    case GIMP_PDB_COLOR:
+      return GIMP_TYPE_RGB;
+
+    case GIMP_PDB_ITEM:
+      return GIMP_TYPE_ITEM_ID;
+
+    case GIMP_PDB_DISPLAY:
+      return GIMP_TYPE_DISPLAY_ID;
+
+    case GIMP_PDB_IMAGE:
+      return GIMP_TYPE_IMAGE_ID;
+
+    case GIMP_PDB_LAYER:
+      return GIMP_TYPE_LAYER_ID;
+
+    case GIMP_PDB_CHANNEL:
+      return GIMP_TYPE_CHANNEL_ID;
+
+    case GIMP_PDB_DRAWABLE:
+      return GIMP_TYPE_DRAWABLE_ID;
+
+    case GIMP_PDB_SELECTION:
+      return GIMP_TYPE_SELECTION_ID;
+
+    case GIMP_PDB_COLORARRAY:
+      return GIMP_TYPE_RGB_ARRAY;
+
+    case GIMP_PDB_VECTORS:
+      return GIMP_TYPE_VECTORS_ID;
+
+    case GIMP_PDB_PARASITE:
+      return GIMP_TYPE_PARASITE;
+
+    case GIMP_PDB_STATUS:
+      return GIMP_TYPE_PDB_STATUS_TYPE;
+
+    case GIMP_PDB_END:
+      break;
+    }
+
+  g_warning ("%s: returning G_TYPE_NONE for %d (%s)",
+             G_STRFUNC, type, _gimp_pdb_arg_type_to_string (type));
+
+  return G_TYPE_NONE;
+}
+
+GimpPDBArgType
+_gimp_pdb_gtype_to_arg_type (GType type)
+{
+  static GQuark  pdb_type_quark = 0;
+  GimpPDBArgType pdb_type;
+
+  if (! pdb_type_quark)
+    {
+      struct
+      {
+        GType          g_type;
+        GimpPDBArgType pdb_type;
+      }
+      type_mapping[] =
+      {
+        { GIMP_TYPE_INT32,           GIMP_PDB_INT32       },
+        { G_TYPE_INT,                GIMP_PDB_INT32       },
+        { G_TYPE_UINT,               GIMP_PDB_INT32       },
+        { G_TYPE_ENUM,               GIMP_PDB_INT32       },
+        { G_TYPE_BOOLEAN,            GIMP_PDB_INT32       },
+
+        { GIMP_TYPE_INT16,           GIMP_PDB_INT16       },
+        { GIMP_TYPE_INT8,            GIMP_PDB_INT8        },
+        { G_TYPE_DOUBLE,             GIMP_PDB_FLOAT       },
+
+        { G_TYPE_STRING,             GIMP_PDB_STRING      },
+
+        { GIMP_TYPE_RGB,             GIMP_PDB_COLOR       },
+
+        { GIMP_TYPE_INT32_ARRAY,     GIMP_PDB_INT32ARRAY  },
+        { GIMP_TYPE_INT16_ARRAY,     GIMP_PDB_INT16ARRAY  },
+        { GIMP_TYPE_INT8_ARRAY,      GIMP_PDB_INT8ARRAY   },
+        { GIMP_TYPE_FLOAT_ARRAY,     GIMP_PDB_FLOATARRAY  },
+        { GIMP_TYPE_STRING_ARRAY,    GIMP_PDB_STRINGARRAY },
+        { GIMP_TYPE_RGB_ARRAY,       GIMP_PDB_COLORARRAY  },
+
+        { GIMP_TYPE_ITEM_ID,         GIMP_PDB_ITEM        },
+        { GIMP_TYPE_DISPLAY_ID,      GIMP_PDB_DISPLAY     },
+        { GIMP_TYPE_IMAGE_ID,        GIMP_PDB_IMAGE       },
+        { GIMP_TYPE_LAYER_ID,        GIMP_PDB_LAYER       },
+        { GIMP_TYPE_CHANNEL_ID,      GIMP_PDB_CHANNEL     },
+        { GIMP_TYPE_DRAWABLE_ID,     GIMP_PDB_DRAWABLE    },
+        { GIMP_TYPE_SELECTION_ID,    GIMP_PDB_SELECTION   },
+        { GIMP_TYPE_LAYER_MASK_ID,   GIMP_PDB_CHANNEL     },
+        { GIMP_TYPE_VECTORS_ID,      GIMP_PDB_VECTORS     },
+
+        { GIMP_TYPE_PARASITE,        GIMP_PDB_PARASITE    },
+
+        { GIMP_TYPE_PDB_STATUS_TYPE, GIMP_PDB_STATUS      }
+      };
+
+      gint i;
+
+      pdb_type_quark = g_quark_from_static_string ("gimp-pdb-type");
+
+      for (i = 0; i < G_N_ELEMENTS (type_mapping); i++)
+        g_type_set_qdata (type_mapping[i].g_type, pdb_type_quark,
+                          GINT_TO_POINTER (type_mapping[i].pdb_type));
+    }
+
+  pdb_type = GPOINTER_TO_INT (g_type_get_qdata (type, pdb_type_quark));
+
+#if 0
+  g_printerr ("%s: arg_type = %p (%s)  ->  %d (%s)\n",
+              G_STRFUNC,
+              (gpointer) type, g_type_name (type),
+              pdb_type, _gimp_pdb_arg_type_to_string (pdb_type));
+#endif
+
+  return pdb_type;
+}
+
+gchar *
+_gimp_pdb_arg_type_to_string (GimpPDBArgType type)
+{
+  const gchar *name;
+
+  if (! gimp_enum_get_value (GIMP_TYPE_PDB_ARG_TYPE, type,
+                             &name, NULL, NULL, NULL))
+    {
+      return g_strdup_printf ("(PDB type %d unknown)", type);
+    }
+
+  return g_strdup (name);
+}
+
+GimpValueArray *
+_gimp_pdb_params_to_args (GParamSpec      **pspecs,
+                          gint              n_pspecs,
+                          const GimpParam  *params,
+                          gint              n_params,
+                          gboolean          return_values,
+                          gboolean          full_copy)
+{
+  GimpValueArray *args;
+  gint            i;
+
+  g_return_val_if_fail ((pspecs != NULL && n_pspecs  > 0) ||
+                        (pspecs == NULL && n_pspecs == 0), NULL);
+  g_return_val_if_fail ((params != NULL && n_params  > 0) ||
+                        (params == NULL && n_params == 0), NULL);
+
+  args = gimp_value_array_new (n_params);
+
+  for (i = 0; i < n_params; i++)
+    {
+      GValue value = G_VALUE_INIT;
+      GType  type;
+      gint   count;
+
+      /*  first get the fallback compat GType that matches the pdb type  */
+      type = _gimp_pdb_arg_type_to_gtype (params[i].type);
+
+      /*  then try to try to be more specific by looking at the param
+       *  spec (return values have one additional value (the status),
+       *  skip that, it's not in the array of param specs)
+       */
+      if (i > 0 || ! return_values)
+        {
+          gint pspec_index = i;
+
+          if (return_values)
+            pspec_index--;
+
+          /*  are there param specs left?  */
+          if (pspec_index < n_pspecs)
+            {
+              GType          pspec_gtype;
+              GimpPDBArgType pspec_arg_type;
+
+              pspec_gtype    = G_PARAM_SPEC_VALUE_TYPE (pspecs[pspec_index]);
+              pspec_arg_type = _gimp_pdb_gtype_to_arg_type (pspec_gtype);
+
+              /*  if the param spec's GType, mapped to a pdb type, matches
+               *  the passed pdb type, use the param spec's GType
+               */
+              if (pspec_arg_type == params[i].type)
+                type = pspec_gtype;
+            }
+        }
+
+      g_value_init (&value, type);
+
+      switch (_gimp_pdb_gtype_to_arg_type (type))
+        {
+        case GIMP_PDB_INT32:
+          if (G_VALUE_HOLDS_INT (&value))
+            g_value_set_int (&value, params[i].data.d_int32);
+          else if (G_VALUE_HOLDS_UINT (&value))
+            g_value_set_uint (&value, params[i].data.d_int32);
+          else if (G_VALUE_HOLDS_ENUM (&value))
+            g_value_set_enum (&value, params[i].data.d_int32);
+          else if (G_VALUE_HOLDS_BOOLEAN (&value))
+            g_value_set_boolean (&value, params[i].data.d_int32 ? TRUE : FALSE);
+          else
+            {
+              g_printerr ("%s: unhandled GIMP_PDB_INT32 type: %s\n",
+                          G_STRFUNC, g_type_name (G_VALUE_TYPE (&value)));
+              g_return_val_if_reached (args);
+            }
+          break;
+
+        case GIMP_PDB_INT16:
+          g_value_set_int (&value, params[i].data.d_int16);
+          break;
+
+        case GIMP_PDB_INT8:
+          g_value_set_uint (&value, params[i].data.d_int8);
+          break;
+
+        case GIMP_PDB_FLOAT:
+          g_value_set_double (&value, params[i].data.d_float);
+          break;
+
+        case GIMP_PDB_STRING:
+          if (full_copy)
+            g_value_set_string (&value, params[i].data.d_string);
+          else
+            g_value_set_static_string (&value, params[i].data.d_string);
+          break;
+
+        case GIMP_PDB_INT32ARRAY:
+          count = g_value_get_int (gimp_value_array_index (args, i - 1));
+          if (full_copy)
+            gimp_value_set_int32_array (&value,
+                                        params[i].data.d_int32array,
+                                        count);
+          else
+            gimp_value_set_static_int32_array (&value,
+                                               params[i].data.d_int32array,
+                                               count);
+          break;
+
+        case GIMP_PDB_INT16ARRAY:
+          count = g_value_get_int (gimp_value_array_index (args, i - 1));
+          if (full_copy)
+            gimp_value_set_int16_array (&value,
+                                        params[i].data.d_int16array,
+                                        count);
+          else
+            gimp_value_set_static_int16_array (&value,
+                                               params[i].data.d_int16array,
+                                               count);
+          break;
+
+        case GIMP_PDB_INT8ARRAY:
+          count = g_value_get_int (gimp_value_array_index (args, i - 1));
+          if (full_copy)
+            gimp_value_set_int8_array (&value,
+                                       params[i].data.d_int8array,
+                                       count);
+          else
+            gimp_value_set_static_int8_array (&value,
+                                              params[i].data.d_int8array,
+                                              count);
+          break;
+
+        case GIMP_PDB_FLOATARRAY:
+          count = g_value_get_int (gimp_value_array_index (args, i - 1));
+          if (full_copy)
+            gimp_value_set_float_array (&value,
+                                        params[i].data.d_floatarray,
+                                        count);
+          else
+            gimp_value_set_static_float_array (&value,
+                                               params[i].data.d_floatarray,
+                                               count);
+          break;
+
+        case GIMP_PDB_STRINGARRAY:
+          count = g_value_get_int (gimp_value_array_index (args, i - 1));
+          if (full_copy)
+            gimp_value_set_string_array (&value,
+                                        (const gchar **) params[i].data.d_stringarray,
+                                        count);
+          else
+            gimp_value_set_static_string_array (&value,
+                                                (const gchar **) params[i].data.d_stringarray,
+                                                count);
+          break;
+
+        case GIMP_PDB_COLOR:
+          gimp_value_set_rgb (&value, &params[i].data.d_color);
+          break;
+
+        case GIMP_PDB_ITEM:
+          g_value_set_int (&value, params[i].data.d_item);
+          break;
+
+        case GIMP_PDB_DISPLAY:
+          g_value_set_int (&value, params[i].data.d_display);
+          break;
+
+        case GIMP_PDB_IMAGE:
+          g_value_set_int (&value, params[i].data.d_image);
+          break;
+
+        case GIMP_PDB_LAYER:
+          g_value_set_int (&value, params[i].data.d_layer);
+          break;
+
+        case GIMP_PDB_CHANNEL:
+          g_value_set_int (&value, params[i].data.d_channel);
+          break;
+
+        case GIMP_PDB_DRAWABLE:
+          g_value_set_int (&value, params[i].data.d_drawable);
+          break;
+
+        case GIMP_PDB_SELECTION:
+          g_value_set_int (&value, params[i].data.d_selection);
+          break;
+
+        case GIMP_PDB_COLORARRAY:
+          count = g_value_get_int (gimp_value_array_index (args, i - 1));
+          if (full_copy)
+            gimp_value_set_rgb_array (&value,
+                                      params[i].data.d_colorarray,
+                                      count);
+          else
+            gimp_value_set_static_rgb_array (&value,
+                                             params[i].data.d_colorarray,
+                                             count);
+          break;
+
+        case GIMP_PDB_VECTORS:
+          g_value_set_int (&value, params[i].data.d_vectors);
+          break;
+
+        case GIMP_PDB_PARASITE:
+          if (full_copy)
+            g_value_set_boxed (&value, &params[i].data.d_parasite);
+          else
+            g_value_set_static_boxed (&value, &params[i].data.d_parasite);
+          break;
+
+        case GIMP_PDB_STATUS:
+          g_value_set_enum (&value, params[i].data.d_status);
+          break;
+
+        case GIMP_PDB_END:
+          break;
+        }
+
+      gimp_value_array_append (args, &value);
+      g_value_unset (&value);
+    }
+
+  return args;
+}
+
+GimpParam *
+_gimp_pdb_args_to_params (GimpValueArray *args,
+                          gboolean        full_copy)
+{
+  GimpParam *params;
+  gint       length;
+  gint       i;
+
+  g_return_val_if_fail (args != NULL, NULL);
+
+  params = g_new0 (GimpParam, gimp_value_array_length (args));
+
+  length = gimp_value_array_length (args);
+
+  for (i = 0; i < length; i++)
+    {
+      GValue *value = gimp_value_array_index (args, i);
+
+      params[i].type = _gimp_pdb_gtype_to_arg_type (G_VALUE_TYPE (value));
+
+      switch (params[i].type)
+        {
+        case GIMP_PDB_INT32:
+          if (G_VALUE_HOLDS_INT (value))
+            params[i].data.d_int32 = g_value_get_int (value);
+          else if (G_VALUE_HOLDS_UINT (value))
+            params[i].data.d_int32 = g_value_get_uint (value);
+          else if (G_VALUE_HOLDS_ENUM (value))
+            params[i].data.d_int32 = g_value_get_enum (value);
+          else if (G_VALUE_HOLDS_BOOLEAN (value))
+            params[i].data.d_int32 = g_value_get_boolean (value);
+          else
+            {
+              g_printerr ("%s: unhandled GIMP_PDB_INT32 type: %s\n",
+                          G_STRFUNC, g_type_name (G_VALUE_TYPE (value)));
+              g_return_val_if_reached (params);
+            }
+          break;
+
+        case GIMP_PDB_INT16:
+          params[i].data.d_int16 = g_value_get_int (value);
+          break;
+
+        case GIMP_PDB_INT8:
+          params[i].data.d_int8 = g_value_get_uint (value);
+          break;
+
+        case GIMP_PDB_FLOAT:
+          params[i].data.d_float = g_value_get_double (value);
+          break;
+
+        case GIMP_PDB_STRING:
+          if (full_copy)
+            params[i].data.d_string = g_value_dup_string (value);
+          else
+            params[i].data.d_string = (gchar *) g_value_get_string (value);
+          break;
+
+        case GIMP_PDB_INT32ARRAY:
+          if (full_copy)
+            params[i].data.d_int32array = gimp_value_dup_int32_array (value);
+          else
+            params[i].data.d_int32array = (gint32 *) gimp_value_get_int32_array (value);
+          break;
+
+        case GIMP_PDB_INT16ARRAY:
+          if (full_copy)
+            params[i].data.d_int16array = gimp_value_dup_int16_array (value);
+          else
+            params[i].data.d_int16array = (gint16 *) gimp_value_get_int16_array (value);
+          break;
+
+        case GIMP_PDB_INT8ARRAY:
+          if (full_copy)
+            params[i].data.d_int8array = gimp_value_dup_int8_array (value);
+          else
+            params[i].data.d_int8array = (guint8 *) gimp_value_get_int8_array (value);
+          break;
+
+        case GIMP_PDB_FLOATARRAY:
+          if (full_copy)
+            params[i].data.d_floatarray = gimp_value_dup_float_array (value);
+          else
+            params[i].data.d_floatarray = (gdouble *) gimp_value_get_float_array (value);
+          break;
+
+        case GIMP_PDB_STRINGARRAY:
+          if (full_copy)
+            params[i].data.d_stringarray = gimp_value_dup_string_array (value);
+          else
+            params[i].data.d_stringarray = (gchar **) gimp_value_get_string_array (value);
+          break;
+
+        case GIMP_PDB_COLOR:
+          gimp_value_get_rgb (value, &params[i].data.d_color);
+          break;
+
+        case GIMP_PDB_ITEM:
+          params[i].data.d_item = g_value_get_int (value);
+          break;
+
+        case GIMP_PDB_DISPLAY:
+          params[i].data.d_display = g_value_get_int (value);
+          break;
+
+        case GIMP_PDB_IMAGE:
+          params[i].data.d_image = g_value_get_int (value);
+          break;
+
+        case GIMP_PDB_LAYER:
+          params[i].data.d_layer = g_value_get_int (value);
+          break;
+
+        case GIMP_PDB_CHANNEL:
+          params[i].data.d_channel = g_value_get_int (value);
+          break;
+
+        case GIMP_PDB_DRAWABLE:
+          params[i].data.d_drawable = g_value_get_int (value);
+          break;
+
+        case GIMP_PDB_SELECTION:
+          params[i].data.d_selection = g_value_get_int (value);
+          break;
+
+        case GIMP_PDB_COLORARRAY:
+          if (full_copy)
+            params[i].data.d_colorarray = gimp_value_dup_rgb_array (value);
+          else
+            params[i].data.d_colorarray = (GimpRGB *) gimp_value_get_rgb_array (value);
+          break;
+
+        case GIMP_PDB_VECTORS:
+          params[i].data.d_vectors = g_value_get_int (value);
+          break;
+
+        case GIMP_PDB_PARASITE:
+          {
+            GimpParasite *parasite = (full_copy ?
+                                      g_value_dup_boxed (value) :
+                                      g_value_get_boxed (value));
+
+            if (parasite)
+              {
+                params[i].data.d_parasite.name  = parasite->name;
+                params[i].data.d_parasite.flags = parasite->flags;
+                params[i].data.d_parasite.size  = parasite->size;
+                params[i].data.d_parasite.data  = parasite->data;
+
+                if (full_copy)
+                  {
+                    parasite->name  = NULL;
+                    parasite->flags = 0;
+                    parasite->size  = 0;
+                    parasite->data  = NULL;
+
+                    gimp_parasite_free (parasite);
+                  }
+              }
+            else
+              {
+                params[i].data.d_parasite.name  = NULL;
+                params[i].data.d_parasite.flags = 0;
+                params[i].data.d_parasite.size  = 0;
+                params[i].data.d_parasite.data  = NULL;
+              }
+          }
+          break;
+
+        case GIMP_PDB_STATUS:
+          params[i].data.d_status = g_value_get_enum (value);
+          break;
+
+        case GIMP_PDB_END:
+          break;
+        }
+    }
+
+  return params;
+}
diff --git a/libgimp/gimpgpcompat.h b/libgimp/gimpgpcompat.h
new file mode 100644
index 0000000000..34128b6128
--- /dev/null
+++ b/libgimp/gimpgpcompat.h
@@ -0,0 +1,45 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball
+ *
+ * gimpgpcompat.c
+ *
+ * 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/>.
+ */
+
+#ifndef __GIMP_GP_COMPAT_H__
+#define __GIMP_GP_COMPAT_H__
+
+
+GParamSpec     * _gimp_gp_compat_param_spec   (GimpPDBArgType   arg_type,
+                                               const gchar     *name,
+                                               const gchar     *nick,
+                                               const gchar     *blurb);
+
+GType            _gimp_pdb_arg_type_to_gtype  (GimpPDBArgType   type);
+GimpPDBArgType   _gimp_pdb_gtype_to_arg_type  (GType            type);
+
+gchar          * _gimp_pdb_arg_type_to_string (GimpPDBArgType   type);
+
+GimpValueArray * _gimp_pdb_params_to_args     (GParamSpec     **pspecs,
+                                               gint             n_pspecs,
+                                               const GimpParam *params,
+                                               gint             n_params,
+                                               gboolean         return_values,
+                                               gboolean         full_copy);
+GimpParam      * _gimp_pdb_args_to_params     (GimpValueArray  *args,
+                                               gboolean         full_copy);
+
+
+#endif /* __GIMP_GP_COMPAT_H__ */
diff --git a/libgimp/gimpgpparamspecs-body.c b/libgimp/gimpgpparamspecs-body.c
new file mode 100644
index 0000000000..de53660761
--- /dev/null
+++ b/libgimp/gimpgpparamspecs-body.c
@@ -0,0 +1,134 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball
+ *
+ * gimpgpparamspecs-body.c
+ *
+ * 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/>.
+ */
+
+/*  this file is included by both libgimp/gimpgpparamspecs.c
+ *  and app/plug-in/gimpgpparamspecs.c
+ */
+
+void
+_gimp_param_spec_to_gp_param_def (GParamSpec *pspec,
+                                  GPParamDef *param_def)
+{
+  GType pspec_type;
+
+  param_def->param_def_type = GP_PARAM_DEF_TYPE_DEFAULT;
+  param_def->type_name      = (gchar *) G_PARAM_SPEC_TYPE_NAME (pspec);
+  param_def->name           = (gchar *) g_param_spec_get_name (pspec);
+  param_def->nick           = (gchar *) g_param_spec_get_nick (pspec);
+  param_def->blurb          = (gchar *) g_param_spec_get_blurb (pspec);
+
+  pspec_type = G_PARAM_SPEC_TYPE (pspec);
+
+  if (pspec_type == GIMP_TYPE_PARAM_INT32 ||
+      pspec_type == GIMP_TYPE_PARAM_INT16)
+    {
+      GParamSpecInt *ispec = G_PARAM_SPEC_INT (pspec);
+
+      param_def->param_def_type = GP_PARAM_DEF_TYPE_INT;
+
+      param_def->meta.m_int.min_val     = ispec->minimum;
+      param_def->meta.m_int.max_val     = ispec->maximum;
+      param_def->meta.m_int.default_val = ispec->default_value;
+    }
+  else if (pspec_type == GIMP_TYPE_PARAM_INT8)
+    {
+      GParamSpecUInt *uspec = G_PARAM_SPEC_UINT (pspec);
+
+      param_def->param_def_type = GP_PARAM_DEF_TYPE_INT;
+
+      param_def->meta.m_int.min_val     = uspec->minimum;
+      param_def->meta.m_int.max_val     = uspec->maximum;
+      param_def->meta.m_int.default_val = uspec->default_value;
+    }
+  else if (pspec_type == G_TYPE_PARAM_ENUM)
+    {
+      GParamSpecEnum *espec     = G_PARAM_SPEC_ENUM (pspec);
+      GType           enum_type = pspec->value_type;
+
+      param_def->param_def_type = GP_PARAM_DEF_TYPE_ENUM;
+
+      param_def->meta.m_enum.type_name    = (gchar *) g_type_name (enum_type);
+      param_def->meta.m_float.default_val = espec->default_value;
+    }
+  else if (pspec_type == G_TYPE_PARAM_BOOLEAN)
+    {
+      GParamSpecBoolean *bspec = G_PARAM_SPEC_BOOLEAN (pspec);
+
+      param_def->param_def_type = GP_PARAM_DEF_TYPE_BOOLEAN;
+
+      param_def->meta.m_boolean.default_val = bspec->default_value;
+    }
+  else if (pspec_type == G_TYPE_PARAM_DOUBLE)
+    {
+      GParamSpecDouble *dspec = G_PARAM_SPEC_DOUBLE (pspec);
+
+      param_def->param_def_type = GP_PARAM_DEF_TYPE_FLOAT;
+
+      param_def->meta.m_float.min_val     = dspec->minimum;
+      param_def->meta.m_float.max_val     = dspec->maximum;
+      param_def->meta.m_float.default_val = dspec->default_value;
+    }
+  else if (pspec_type == GIMP_TYPE_PARAM_STRING)
+    {
+      GParamSpecString    *gsspec = G_PARAM_SPEC_STRING (pspec);
+      GimpParamSpecString *sspec  = GIMP_PARAM_SPEC_STRING (pspec);
+
+      param_def->param_def_type = GP_PARAM_DEF_TYPE_STRING;
+
+      param_def->meta.m_string.allow_non_utf8 = sspec->allow_non_utf8;
+      param_def->meta.m_string.null_ok        = ! gsspec->ensure_non_null;
+      param_def->meta.m_string.non_empty      = sspec->non_empty;
+      param_def->meta.m_string.default_val    = gsspec->default_value;
+    }
+  else if (pspec_type == GIMP_TYPE_PARAM_RGB)
+    {
+      param_def->param_def_type = GP_PARAM_DEF_TYPE_COLOR;
+
+      param_def->meta.m_color.has_alpha =
+        gimp_param_spec_rgb_has_alpha (pspec);
+
+      gimp_param_spec_rgb_get_default (pspec,
+                                       &param_def->meta.m_color.default_val);
+    }
+  else if (pspec_type == GIMP_TYPE_PARAM_DISPLAY_ID)
+    {
+      GimpParamSpecDisplayID *ispec = GIMP_PARAM_SPEC_DISPLAY_ID (pspec);
+
+      param_def->param_def_type = GP_PARAM_DEF_TYPE_ID;
+
+      param_def->meta.m_id.none_ok = ispec->none_ok;
+    }
+  else if (pspec_type == GIMP_TYPE_PARAM_IMAGE_ID)
+    {
+      GimpParamSpecImageID *ispec = GIMP_PARAM_SPEC_IMAGE_ID (pspec);
+
+      param_def->param_def_type = GP_PARAM_DEF_TYPE_ID;
+
+      param_def->meta.m_id.none_ok = ispec->none_ok;
+    }
+  else if (GIMP_IS_PARAM_SPEC_ITEM_ID (pspec))
+    {
+      GimpParamSpecItemID *ispec = GIMP_PARAM_SPEC_ITEM_ID (pspec);
+
+      param_def->param_def_type = GP_PARAM_DEF_TYPE_ID;
+
+      param_def->meta.m_id.none_ok = ispec->none_ok;
+    }
+}
diff --git a/libgimp/gimpgpparamspecs.c b/libgimp/gimpgpparamspecs.c
new file mode 100644
index 0000000000..58bfe0c92e
--- /dev/null
+++ b/libgimp/gimpgpparamspecs.c
@@ -0,0 +1,41 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball
+ *
+ * gimpgpparamspecs.c
+ *
+ * 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 <gio/gio.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gegl.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpcolor/gimpcolor.h"
+#include "libgimpbase/gimpprotocol.h"
+
+#include "gimp.h"
+#include "gimpgpparamspecs.h"
+
+
+/*  public functions  */
+
+/*  include the implementation of _gimp_param_spec_to_gp_param_def()
+ *  from libgimp, they are identical.
+ */
+#include "gimpgpparamspecs-body.c"
diff --git a/libgimp/gimpgpparamspecs.h b/libgimp/gimpgpparamspecs.h
new file mode 100644
index 0000000000..f5d036943b
--- /dev/null
+++ b/libgimp/gimpgpparamspecs.h
@@ -0,0 +1,33 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball
+ *
+ * gimpgpparamspecs.h
+ *
+ * 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/>.
+ */
+
+#ifndef __GIMP_GP_PARAM_SPECS_H__
+#define __GIMP_GP_PARAM_SPECS_H__
+
+G_BEGIN_DECLS
+
+
+void   _gimp_param_spec_to_gp_param_def (GParamSpec *pspec,
+                                         GPParamDef *param_def);
+
+
+G_END_DECLS
+
+#endif /* __GIMP_GP_PARAM_SPECS_H__ */
diff --git a/libgimp/gimpplugin-private.c b/libgimp/gimpplugin-private.c
index dbb3fa1412..e9ca4f39dc 100644
--- a/libgimp/gimpplugin-private.c
+++ b/libgimp/gimpplugin-private.c
@@ -20,13 +20,9 @@
 
 #include "config.h"
 
-#include <string.h>
-
 #include "gimp.h"
 #include "gimpplugin-private.h"
-
-
-static void   gimp_plug_in_add_procedures (GimpPlugIn *plug_in);
+#include "gimpprocedure-private.h"
 
 
 /*  public functions  */
@@ -34,86 +30,58 @@ static void   gimp_plug_in_add_procedures (GimpPlugIn *plug_in);
 void
 _gimp_plug_in_init (GimpPlugIn *plug_in)
 {
-  g_return_if_fail (GIMP_IS_PLUG_IN (plug_in));
+  gchar **procedures;
+  gint    n_procedures;
+  gint    i;
 
-  if (GIMP_PLUG_IN_GET_CLASS (plug_in)->init)
-    GIMP_PLUG_IN_GET_CLASS (plug_in)->init (plug_in);
-}
-
-void
-_gimp_plug_in_quit (GimpPlugIn *plug_in)
-{
   g_return_if_fail (GIMP_IS_PLUG_IN (plug_in));
 
-  if (GIMP_PLUG_IN_GET_CLASS (plug_in)->quit)
-    GIMP_PLUG_IN_GET_CLASS (plug_in)->quit (plug_in);
-}
+  if (! GIMP_PLUG_IN_GET_CLASS (plug_in)->init_procedures)
+    return;
 
-void
-_gimp_plug_in_query (GimpPlugIn *plug_in)
-{
-  g_return_if_fail (GIMP_IS_PLUG_IN (plug_in));
+  procedures = GIMP_PLUG_IN_GET_CLASS (plug_in)->init_procedures (plug_in,
+                                                                  &n_procedures);
 
-  if (GIMP_PLUG_IN_GET_CLASS (plug_in)->query)
-    GIMP_PLUG_IN_GET_CLASS (plug_in)->query (plug_in);
+  for (i = 0; i < n_procedures; i++)
+    {
+      GimpProcedure *procedure;
 
-  gimp_plug_in_add_procedures (plug_in);
+      procedure = gimp_plug_in_create_procedure (plug_in, procedures[i]);
+      _gimp_procedure_register (procedure);
+      g_object_unref (procedure);
+    }
 }
 
 void
-_gimp_plug_in_run (GimpPlugIn       *plug_in,
-                   const gchar      *name,
-                   gint              n_params,
-                   const GimpParam  *params,
-                   gint             *n_return_vals,
-                   GimpParam       **return_vals)
+_gimp_plug_in_query (GimpPlugIn *plug_in)
 {
-  GimpProcedure *procedure;
+  gchar **procedures;
+  gint    n_procedures;
+  gint    i;
 
   g_return_if_fail (GIMP_IS_PLUG_IN (plug_in));
-  g_return_if_fail (name != NULL);
 
-  gimp_plug_in_add_procedures (plug_in);
+  if (! GIMP_PLUG_IN_GET_CLASS (plug_in)->query_procedures)
+    return;
 
-  procedure = gimp_plug_in_get_procedure (plug_in, name);
+  procedures = GIMP_PLUG_IN_GET_CLASS (plug_in)->query_procedures (plug_in,
+                                                                   &n_procedures);
 
-  if (procedure)
+  for (i = 0; i < n_procedures; i++)
     {
-      gimp_procedure_run_legacy (procedure,
-                                 n_params,      params,
-                                 n_return_vals, return_vals);
+      GimpProcedure *procedure;
+
+      procedure = gimp_plug_in_create_procedure (plug_in, procedures[i]);
+      _gimp_procedure_register (procedure);
+      g_object_unref (procedure);
     }
 }
 
-
-/*  private functions  */
-
-static void
-gimp_plug_in_add_procedures (GimpPlugIn *plug_in)
+void
+_gimp_plug_in_quit (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);
-        }
+  g_return_if_fail (GIMP_IS_PLUG_IN (plug_in));
 
-      g_strfreev (procedures);
-    }
+  if (GIMP_PLUG_IN_GET_CLASS (plug_in)->quit)
+    GIMP_PLUG_IN_GET_CLASS (plug_in)->quit (plug_in);
 }
diff --git a/libgimp/gimpplugin-private.h b/libgimp/gimpplugin-private.h
index 01b88306d5..ce1270ebea 100644
--- a/libgimp/gimpplugin-private.h
+++ b/libgimp/gimpplugin-private.h
@@ -23,17 +23,10 @@
 
 G_BEGIN_DECLS
 
+
 void   _gimp_plug_in_init  (GimpPlugIn *plug_in);
-void   _gimp_plug_in_quit  (GimpPlugIn *plug_in);
 void   _gimp_plug_in_query (GimpPlugIn *plug_in);
-
-/* temp */
-void   _gimp_plug_in_run   (GimpPlugIn       *plug_in,
-                            const gchar      *name,
-                            gint              n_params,
-                            const GimpParam  *params,
-                            gint             *n_return_vals,
-                            GimpParam       **return_vals);
+void   _gimp_plug_in_quit  (GimpPlugIn *plug_in);
 
 
 G_END_DECLS
diff --git a/libgimp/gimpplugin.c b/libgimp/gimpplugin.c
index c1ee07be54..df049f2eaa 100644
--- a/libgimp/gimpplugin.c
+++ b/libgimp/gimpplugin.c
@@ -79,6 +79,23 @@ gimp_plug_in_finalize (GObject *object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+
+/*  public functions  */
+
+GimpProcedure *
+gimp_plug_in_create_procedure (GimpPlugIn    *plug_in,
+                               const gchar   *name)
+{
+  g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), NULL);
+  g_return_val_if_fail (name != NULL, NULL);
+
+  if (GIMP_PLUG_IN_GET_CLASS (plug_in)->create_procedure)
+    return GIMP_PLUG_IN_GET_CLASS (plug_in)->create_procedure (plug_in,
+                                                               name);
+
+  return NULL;
+}
+
 void
 gimp_plug_in_add_procedure (GimpPlugIn    *plug_in,
                             GimpProcedure *procedure)
diff --git a/libgimp/gimpplugin.h b/libgimp/gimpplugin.h
index 9cce67790a..c87dd25d02 100644
--- a/libgimp/gimpplugin.h
+++ b/libgimp/gimpplugin.h
@@ -52,12 +52,13 @@ struct _GimpPlugInClass
 {
   GObjectClass  parent_class;
 
-  void             (* init)             (GimpPlugIn  *plug_in);
   void             (* quit)             (GimpPlugIn  *plug_in);
-  void             (* query)            (GimpPlugIn  *plug_in);
 
-  gchar         ** (* list_procedures)  (GimpPlugIn  *plug_in,
+  gchar         ** (* init_procedures)  (GimpPlugIn  *plug_in,
                                          gint        *n_procedures);
+  gchar         ** (* query_procedures) (GimpPlugIn  *plug_in,
+                                         gint        *n_procedures);
+
   GimpProcedure  * (* create_procedure) (GimpPlugIn  *plug_in,
                                          const gchar *name);
 
@@ -75,6 +76,9 @@ struct _GimpPlugInClass
 
 GType           gimp_plug_in_get_type         (void) G_GNUC_CONST;
 
+GimpProcedure * gimp_plug_in_create_procedure (GimpPlugIn    *plug_in,
+                                               const gchar   *name);
+
 void            gimp_plug_in_add_procedure    (GimpPlugIn    *plug_in,
                                                GimpProcedure *procedure);
 void            gimp_plug_in_remove_procedure (GimpPlugIn    *plug_in,
diff --git a/libgimp/gimpprocedure-private.c b/libgimp/gimpprocedure-private.c
new file mode 100644
index 0000000000..506802ae08
--- /dev/null
+++ b/libgimp/gimpprocedure-private.c
@@ -0,0 +1,96 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball
+ *
+ * gimpprocedure-private.c
+ *
+ * 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 <gio/gio.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gegl.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpcolor/gimpcolor.h"
+#include "libgimpbase/gimpprotocol.h"
+
+#include "gimp.h"
+#include "gimpgpparamspecs.h"
+#include "gimpprocedure-private.h"
+
+
+/*  public functions  */
+
+void
+_gimp_procedure_register (GimpProcedure *procedure)
+{
+  extern GIOChannel *_writechannel;
+
+  GParamSpec   **args;
+  GParamSpec   **return_vals;
+  gint           n_args;
+  gint           n_return_vals;
+  GList         *list;
+  GPProcInstall  proc_install;
+  gint           i;
+
+  g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
+
+  args        = gimp_procedure_get_arguments (procedure, &n_args);
+  return_vals = gimp_procedure_get_return_values (procedure, &n_return_vals);
+
+  proc_install.name         = (gchar *) gimp_procedure_get_name (procedure);
+  proc_install.blurb        = (gchar *) gimp_procedure_get_blurb (procedure);
+  proc_install.help         = (gchar *) gimp_procedure_get_help (procedure);
+  proc_install.author       = (gchar *) gimp_procedure_get_author (procedure);
+  proc_install.copyright    = (gchar *) gimp_procedure_get_copyright (procedure);
+  proc_install.date         = (gchar *) gimp_procedure_get_date (procedure);
+  proc_install.menu_label   = (gchar *) gimp_procedure_get_menu_label (procedure);
+  proc_install.image_types  = (gchar *) gimp_procedure_get_image_types (procedure);
+  proc_install.type         = GIMP_PLUGIN;
+  proc_install.nparams      = n_args;
+  proc_install.nreturn_vals = n_return_vals;
+  proc_install.params       = g_new0 (GPParamDef, n_args);
+  proc_install.return_vals  = g_new0 (GPParamDef, n_return_vals);
+
+  for (i = 0; i < n_args; i++)
+    {
+      _gimp_param_spec_to_gp_param_def (args[i],
+                                        &proc_install.params[i]);
+    }
+
+  for (i = 0; i < n_return_vals; i++)
+    {
+      _gimp_param_spec_to_gp_param_def (return_vals[i],
+                                        &proc_install.return_vals[i]);
+    }
+
+  if (! gp_proc_install_write (_writechannel, &proc_install, NULL))
+    gimp_quit ();
+
+  g_free (proc_install.params);
+  g_free (proc_install.return_vals);
+
+  for (list = gimp_procedure_get_menu_paths (procedure);
+       list;
+       list = g_list_next (list))
+    {
+      gimp_plugin_menu_register (gimp_procedure_get_name (procedure),
+                                 list->data);
+    }
+}
diff --git a/libgimp/gimpprocedure-private.h b/libgimp/gimpprocedure-private.h
new file mode 100644
index 0000000000..76b117eb05
--- /dev/null
+++ b/libgimp/gimpprocedure-private.h
@@ -0,0 +1,32 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball
+ *
+ * gimpprocedure-private.h
+ *
+ * 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/>.
+ */
+
+#ifndef __GIMP_PROCEDURE_PRIVATE_H__
+#define __GIMP_PROCEDURE_PRIVATE_H__
+
+G_BEGIN_DECLS
+
+
+void _gimp_procedure_register (GimpProcedure *procedure);
+
+
+G_END_DECLS
+
+#endif  /*  __GIMP_PROCEDURE_H__  */
diff --git a/libgimp/gimpprocedure.c b/libgimp/gimpprocedure.c
index 99399da72a..cc46ec90cc 100644
--- a/libgimp/gimpprocedure.c
+++ b/libgimp/gimpprocedure.c
@@ -52,22 +52,24 @@ gimp_pdb_error_quark (void)
 struct _GimpProcedurePrivate
 {
   gchar            *name;           /* procedure name                 */
-  gchar            *label;
+  gchar            *menu_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                     */
+  gchar            *image_types;
 
-  gint32            num_args;       /* Number of procedure arguments  */
+  GList            *menu_paths;
+
+  gint32            n_args;         /* Number of procedure arguments  */
   GParamSpec      **args;           /* Array of procedure arguments   */
 
-  gint32            num_values;     /* Number of return values        */
+  gint32            n_values;       /* Number of return values        */
   GParamSpec      **values;         /* Array of return values         */
 
   GimpRunFunc       run_func;
-  GimpRunFuncOld    run_func_old;
 };
 
 
@@ -111,9 +113,12 @@ gimp_procedure_finalize (GObject *object)
 
   gimp_procedure_free_strings (procedure);
 
+  g_list_free_full (procedure->priv->menu_paths, g_free);
+  procedure->priv->menu_paths = NULL;
+
   if (procedure->priv->args)
     {
-      for (i = 0; i < procedure->priv->num_args; i++)
+      for (i = 0; i < procedure->priv->n_args; i++)
         g_param_spec_unref (procedure->priv->args[i]);
 
       g_clear_pointer (&procedure->priv->args, g_free);
@@ -121,7 +126,7 @@ gimp_procedure_finalize (GObject *object)
 
   if (procedure->priv->values)
     {
-      for (i = 0; i < procedure->priv->num_values; i++)
+      for (i = 0; i < procedure->priv->n_values; i++)
         g_param_spec_unref (procedure->priv->values[i]);
 
       g_clear_pointer (&procedure->priv->values, g_free);
@@ -150,42 +155,29 @@ gimp_procedure_new (const gchar *name,
   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   *menu_label,
                             const gchar   *blurb,
                             const gchar   *help,
                             const gchar   *help_id,
                             const gchar   *author,
                             const gchar   *copyright,
-                            const gchar   *date)
+                            const gchar   *date,
+                            const gchar   *image_types)
 {
   g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
 
   gimp_procedure_free_strings (procedure);
 
+  procedure->priv->menu_label    = g_strdup (menu_label);
   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);
+  procedure->priv->image_types   = g_strdup (image_types);
 }
 
 const gchar *
@@ -197,11 +189,11 @@ gimp_procedure_get_name (GimpProcedure *procedure)
 }
 
 const gchar *
-gimp_procedure_get_label (GimpProcedure *procedure)
+gimp_procedure_get_menu_label (GimpProcedure *procedure)
 {
   g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
 
-  return procedure->priv->label;
+  return procedure->priv->menu_label;
 }
 
 const gchar *
@@ -212,6 +204,14 @@ gimp_procedure_get_blurb (GimpProcedure *procedure)
   return procedure->priv->blurb;
 }
 
+const gchar *
+gimp_procedure_get_help (GimpProcedure *procedure)
+{
+  g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+
+  return procedure->priv->help;
+}
+
 const gchar *
 gimp_procedure_get_help_id (GimpProcedure *procedure)
 {
@@ -220,69 +220,117 @@ gimp_procedure_get_help_id (GimpProcedure *procedure)
   return procedure->priv->help_id;
 }
 
-GimpValueArray *
-gimp_procedure_run (GimpProcedure   *procedure,
-                    GimpValueArray  *args,
-                    GError         **error)
+const gchar *
+gimp_procedure_get_author (GimpProcedure *procedure)
 {
-  GimpValueArray *return_vals;
-  GError         *my_error = NULL;
+  g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+
+  return procedure->priv->author;
+}
 
+const gchar *
+gimp_procedure_get_copyright (GimpProcedure *procedure)
+{
   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 procedure->priv->copyright;
+}
 
-      return return_vals;
-    }
+const gchar *
+gimp_procedure_get_date (GimpProcedure *procedure)
+{
+  g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
 
-  /*  call the procedure  */
-  return_vals = procedure->priv->run_func (procedure, args, error);
+  return procedure->priv->date;
+}
 
-  if (! return_vals)
-    {
-      g_warning ("%s: no return values, shouldn't happen", G_STRFUNC);
+const gchar *
+gimp_procedure_get_image_types (GimpProcedure *procedure)
+{
+  g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
 
-      my_error = g_error_new (0, 0, 0,
-                              _("Procedure '%s' returned no return values"),
-                              gimp_procedure_get_name (procedure));
+  return procedure->priv->image_types;
+}
 
-      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);
-    }
+void
+gimp_procedure_add_menu_path (GimpProcedure *procedure,
+                              const gchar   *menu_path)
+{
+  g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
+  g_return_if_fail (menu_path != NULL);
 
-  return return_vals;
+  procedure->priv->menu_paths = g_list_append (procedure->priv->menu_paths,
+                                               g_strdup (menu_path));
+}
+
+GList *
+gimp_procedure_get_menu_paths (GimpProcedure *procedure)
+{
+  g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+
+  return procedure->priv->menu_paths;
 }
 
 void
-gimp_procedure_run_legacy (GimpProcedure    *procedure,
-                           gint              n_params,
-                           const GimpParam  *params,
-                           gint             *n_return_vals,
-                           GimpParam       **return_vals)
+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));
 
-  /*  call the procedure  */
-  procedure->priv->run_func_old (procedure,
-                                 n_params, params,
-                                 n_return_vals, return_vals);
+  procedure->priv->args = g_renew (GParamSpec *, procedure->priv->args,
+                                   procedure->priv->n_args + 1);
+
+  procedure->priv->args[procedure->priv->n_args] = pspec;
+
+  g_param_spec_ref_sink (pspec);
+
+  procedure->priv->n_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->n_values + 1);
+
+  procedure->priv->values[procedure->priv->n_values] = pspec;
+
+  g_param_spec_ref_sink (pspec);
+
+  procedure->priv->n_values++;
+}
+
+GParamSpec **
+gimp_procedure_get_arguments (GimpProcedure *procedure,
+                              gint          *n_arguments)
+{
+  g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+  g_return_val_if_fail (n_arguments != NULL, NULL);
+
+  *n_arguments = procedure->priv->n_args;
+
+  return procedure->priv->args;
+}
+
+GParamSpec **
+gimp_procedure_get_return_values (GimpProcedure *procedure,
+                                  gint          *n_return_values)
+{
+  g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+  g_return_val_if_fail (n_return_values != NULL, NULL);
+
+  *n_return_values = procedure->priv->n_values;
+
+  return procedure->priv->values;
 }
 
 GimpValueArray *
-gimp_procedure_get_arguments (GimpProcedure *procedure)
+gimp_procedure_new_arguments (GimpProcedure *procedure)
 {
   GimpValueArray *args;
   GValue          value = G_VALUE_INIT;
@@ -290,9 +338,9 @@ gimp_procedure_get_arguments (GimpProcedure *procedure)
 
   g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
 
-  args = gimp_value_array_new (procedure->priv->num_args);
+  args = gimp_value_array_new (procedure->priv->n_args);
 
-  for (i = 0; i < procedure->priv->num_args; i++)
+  for (i = 0; i < procedure->priv->n_args; i++)
     {
       g_value_init (&value,
                     G_PARAM_SPEC_VALUE_TYPE (procedure->priv->args[i]));
@@ -304,66 +352,43 @@ gimp_procedure_get_arguments (GimpProcedure *procedure)
 }
 
 GimpValueArray *
-gimp_procedure_get_return_values (GimpProcedure *procedure,
-                                  gboolean       success,
-                                  const GError  *error)
+gimp_procedure_new_return_values (GimpProcedure     *procedure,
+                                  GimpPDBStatusType  status,
+                                  const GError      *error)
 {
   GimpValueArray *args;
   GValue          value = G_VALUE_INIT;
   gint            i;
 
-  g_return_val_if_fail (success == FALSE || GIMP_IS_PROCEDURE (procedure),
-                        NULL);
+  g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+  g_return_val_if_fail (status != GIMP_PDB_PASS_THROUGH, NULL);
 
-  if (success)
+  switch (status)
     {
-      args = gimp_value_array_new (procedure->priv->num_values + 1);
+    case GIMP_PDB_SUCCESS:
+    case GIMP_PDB_CANCEL:
+      args = gimp_value_array_new (procedure->priv->n_values + 1);
 
       g_value_init (&value, GIMP_TYPE_PDB_STATUS_TYPE);
-      g_value_set_enum (&value, GIMP_PDB_SUCCESS);
+      g_value_set_enum (&value, status);
       gimp_value_array_append (args, &value);
       g_value_unset (&value);
 
-      for (i = 0; i < procedure->priv->num_values; i++)
+      for (i = 0; i < procedure->priv->n_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
-    {
+      break;
+
+    case GIMP_PDB_EXECUTION_ERROR:
+    case GIMP_PDB_CALLING_ERROR:
       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);
-        }
-
+      g_value_set_enum (&value, status);
       gimp_value_array_append (args, &value);
       g_value_unset (&value);
 
@@ -374,43 +399,56 @@ gimp_procedure_get_return_values (GimpProcedure *procedure,
           gimp_value_array_append (args, &value);
           g_value_unset (&value);
         }
+      break;
+
+    default:
+      g_return_val_if_reached (NULL);
     }
 
   return args;
 }
 
-void
-gimp_procedure_add_argument (GimpProcedure *procedure,
-                             GParamSpec    *pspec)
+GimpValueArray *
+gimp_procedure_run (GimpProcedure   *procedure,
+                    GimpValueArray  *args)
 {
-  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);
+  GimpValueArray *return_vals;
+  GError         *error = NULL;
 
-  procedure->priv->args[procedure->priv->num_args] = pspec;
+  g_return_val_if_fail (GIMP_IS_PROCEDURE (procedure), NULL);
+  g_return_val_if_fail (args != NULL, NULL);
 
-  g_param_spec_ref_sink (pspec);
+  if (! gimp_procedure_validate_args (procedure,
+                                      procedure->priv->args,
+                                      procedure->priv->n_args,
+                                      args, FALSE, &error))
+    {
+      return_vals = gimp_procedure_new_return_values (procedure,
+                                                      GIMP_PDB_CALLING_ERROR,
+                                                      error);
+      g_clear_error (&error);
 
-  procedure->priv->num_args++;
-}
+      return return_vals;
+    }
 
-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));
+  /*  call the procedure  */
+  return_vals = procedure->priv->run_func (procedure, args);
 
-  procedure->priv->values = g_renew (GParamSpec *, procedure->priv->values,
-                               procedure->priv->num_values + 1);
+  if (! return_vals)
+    {
+      g_warning ("%s: no return values, shouldn't happen", G_STRFUNC);
 
-  procedure->priv->values[procedure->priv->num_values] = pspec;
+      error = g_error_new (0, 0, 0,
+                           _("Procedure '%s' returned no return values"),
+                           gimp_procedure_get_name (procedure));
 
-  g_param_spec_ref_sink (pspec);
+      return_vals = gimp_procedure_new_return_values (procedure,
+                                                      GIMP_PDB_EXECUTION_ERROR,
+                                                      error);
+      g_clear_error (&error);
+    }
 
-  procedure->priv->num_values++;
+  return return_vals;
 }
 
 
@@ -419,12 +457,14 @@ gimp_procedure_add_return_value (GimpProcedure *procedure,
 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);
+  g_clear_pointer (&procedure->priv->menu_label,  g_free);
+  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);
+  g_clear_pointer (&procedure->priv->image_types, g_free);
 }
 
 static gboolean
diff --git a/libgimp/gimpprocedure.h b/libgimp/gimpprocedure.h
index 2416a5e97a..ce13eb3946 100644
--- a/libgimp/gimpprocedure.h
+++ b/libgimp/gimpprocedure.h
@@ -28,14 +28,8 @@ 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);
+typedef GimpValueArray * (* GimpRunFunc) (GimpProcedure        *procedure,
+                                          const GimpValueArray *args);
 
 
 #define GIMP_TYPE_PROCEDURE            (gimp_procedure_get_type ())
@@ -64,43 +58,50 @@ struct _GimpProcedureClass
 
 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);
+GimpProcedure  * gimp_procedure_new                (const gchar       *name,
+                                                    GimpRunFunc        run_func);
+
+void             gimp_procedure_set_strings        (GimpProcedure     *procedure,
+                                                    const gchar       *menu_label,
+                                                    const gchar       *blurb,
+                                                    const gchar       *help,
+                                                    const gchar       *help_id,
+                                                    const gchar       *author,
+                                                    const gchar       *copyright,
+                                                    const gchar       *date,
+                                                    const gchar       *image_types);
+
+const gchar    * gimp_procedure_get_name           (GimpProcedure     *procedure);
+const gchar    * gimp_procedure_get_menu_label     (GimpProcedure     *procedure);
+const gchar    * gimp_procedure_get_blurb          (GimpProcedure     *procedure);
+const gchar    * gimp_procedure_get_help           (GimpProcedure     *procedure);
+const gchar    * gimp_procedure_get_help_id        (GimpProcedure     *procedure);
+const gchar    * gimp_procedure_get_author         (GimpProcedure     *procedure);
+const gchar    * gimp_procedure_get_copyright      (GimpProcedure     *procedure);
+const gchar    * gimp_procedure_get_date           (GimpProcedure     *procedure);
+const gchar    * gimp_procedure_get_image_types    (GimpProcedure     *procedure);
+
+void             gimp_procedure_add_menu_path      (GimpProcedure     *procedure,
+                                                    const gchar       *menu_path);
+GList          * gimp_procedure_get_menu_paths     (GimpProcedure     *procedure);
+
+void             gimp_procedure_add_argument       (GimpProcedure     *procedure,
+                                                    GParamSpec        *pspec);
+void             gimp_procedure_add_return_value   (GimpProcedure     *procedure,
+                                                    GParamSpec        *pspec);
+
+GParamSpec    ** gimp_procedure_get_arguments      (GimpProcedure     *procedure,
+                                                    gint              *n_arguments);
+GParamSpec    ** gimp_procedure_get_return_values  (GimpProcedure     *procedure,
+                                                    gint              *n_return_values);
+
+GimpValueArray * gimp_procedure_new_arguments      (GimpProcedure     *procedure);
+GimpValueArray * gimp_procedure_new_return_values  (GimpProcedure     *procedure,
+                                                    GimpPDBStatusType  status,
+                                                    const GError      *error);
+
+GimpValueArray * gimp_procedure_run                (GimpProcedure     *procedure,
+                                                    GimpValueArray    *args);
 
 
 G_END_DECLS
diff --git a/libgimpbase/gimpprotocol.c b/libgimpbase/gimpprotocol.c
index a79895f7ed..2f6ac677a2 100644
--- a/libgimpbase/gimpprotocol.c
+++ b/libgimpbase/gimpprotocol.c
@@ -1008,6 +1008,162 @@ _gp_temp_proc_return_destroy (GimpWireMessage *msg)
 
 /*  proc_install  */
 
+static gboolean
+_gp_param_def_read (GIOChannel *channel,
+                    GPParamDef *param_def,
+                    gpointer    user_data)
+{
+  if (! _gimp_wire_read_int32 (channel,
+                               &param_def->param_def_type, 1,
+                               user_data))
+    return FALSE;
+
+  if (! _gimp_wire_read_string (channel,
+                                &param_def->type_name, 1,
+                                user_data))
+    return FALSE;
+
+  if (! _gimp_wire_read_string (channel,
+                                &param_def->name, 1,
+                                user_data))
+    return FALSE;
+
+  if (! _gimp_wire_read_string (channel,
+                                &param_def->nick, 1,
+                                user_data))
+    return FALSE;
+
+  if (! _gimp_wire_read_string (channel,
+                                &param_def->blurb, 1,
+                                user_data))
+    return FALSE;
+
+  switch (param_def->param_def_type)
+    {
+    case GP_PARAM_DEF_TYPE_DEFAULT:
+      break;
+
+    case GP_PARAM_DEF_TYPE_INT:
+      if (! _gimp_wire_read_int32 (channel,
+                                   (guint32 *) &param_def->meta.m_int.min_val, 1,
+                                   user_data) ||
+          ! _gimp_wire_read_int32 (channel,
+                                   (guint32 *) &param_def->meta.m_int.max_val, 1,
+                                   user_data) ||
+          ! _gimp_wire_read_int32 (channel,
+                                   (guint32 *) &param_def->meta.m_int.default_val, 1,
+                                   user_data))
+        return FALSE;
+      break;
+
+    case GP_PARAM_DEF_TYPE_ENUM:
+      if (! _gimp_wire_read_string (channel,
+                                    &param_def->meta.m_enum.type_name, 1,
+                                    user_data) ||
+          ! _gimp_wire_read_int32 (channel,
+                                   (guint32 *) &param_def->meta.m_enum.default_val, 1,
+                                   user_data))
+        return FALSE;
+      break;
+
+    case GP_PARAM_DEF_TYPE_BOOLEAN:
+      if (! _gimp_wire_read_int32 (channel,
+                                   (guint32 *) &param_def->meta.m_boolean.default_val, 1,
+                                   user_data))
+        return FALSE;
+      break;
+
+    case GP_PARAM_DEF_TYPE_FLOAT:
+      if (! _gimp_wire_read_double (channel,
+                                    &param_def->meta.m_float.min_val, 1,
+                                    user_data) ||
+          ! _gimp_wire_read_double (channel,
+                                    &param_def->meta.m_float.max_val, 1,
+                                    user_data) ||
+          ! _gimp_wire_read_double (channel,
+                                    &param_def->meta.m_float.default_val, 1,
+                                    user_data))
+        return FALSE;
+      break;
+
+    case GP_PARAM_DEF_TYPE_STRING:
+      if (! _gimp_wire_read_int32 (channel,
+                                   (guint32 *) &param_def->meta.m_string.allow_non_utf8, 1,
+                                   user_data) ||
+          ! _gimp_wire_read_int32 (channel,
+                                   (guint32 *) &param_def->meta.m_string.null_ok, 1,
+                                   user_data) ||
+          ! _gimp_wire_read_int32 (channel,
+                                   (guint32 *) &param_def->meta.m_string.non_empty, 1,
+                                   user_data) ||
+          ! _gimp_wire_read_string (channel,
+                                    &param_def->meta.m_string.default_val, 1,
+                                    user_data))
+        return FALSE;
+      break;
+
+    case GP_PARAM_DEF_TYPE_COLOR:
+      if (! _gimp_wire_read_int32 (channel,
+                                   (guint32 *) &param_def->meta.m_color.has_alpha, 1,
+                                   user_data) ||
+          ! _gimp_wire_read_double (channel,
+                                    &param_def->meta.m_color.default_val.r, 1,
+                                    user_data) ||
+          ! _gimp_wire_read_double (channel,
+                                    &param_def->meta.m_color.default_val.g, 1,
+                                    user_data) ||
+          ! _gimp_wire_read_double (channel,
+                                    &param_def->meta.m_color.default_val.b, 1,
+                                    user_data) ||
+          ! _gimp_wire_read_double (channel,
+                                    &param_def->meta.m_color.default_val.a, 1,
+                                    user_data))
+        return FALSE;
+      break;
+
+    case GP_PARAM_DEF_TYPE_ID:
+      if (! _gimp_wire_read_int32 (channel,
+                                   (guint32 *) &param_def->meta.m_id.none_ok, 1,
+                                   user_data))
+        return FALSE;
+      break;
+    }
+
+  return TRUE;
+}
+
+static void
+_gp_param_def_destroy (GPParamDef *param_def)
+{
+  g_free (param_def->type_name);
+  g_free (param_def->name);
+  g_free (param_def->nick);
+  g_free (param_def->blurb);
+
+  switch (param_def->param_def_type)
+    {
+    case GP_PARAM_DEF_TYPE_DEFAULT:
+    case GP_PARAM_DEF_TYPE_INT:
+      break;
+
+    case GP_PARAM_DEF_TYPE_ENUM:
+      g_free (param_def->meta.m_enum.type_name);
+      break;
+
+    case GP_PARAM_DEF_TYPE_BOOLEAN:
+    case GP_PARAM_DEF_TYPE_FLOAT:
+      break;
+
+    case GP_PARAM_DEF_TYPE_STRING:
+      g_free (param_def->meta.m_string.default_val);
+      break;
+
+    case GP_PARAM_DEF_TYPE_COLOR:
+    case GP_PARAM_DEF_TYPE_ID:
+      break;
+    }
+}
+
 static void
 _gp_proc_install_read (GIOChannel      *channel,
                        GimpWireMessage *msg,
@@ -1055,17 +1211,9 @@ _gp_proc_install_read (GIOChannel      *channel,
 
   for (i = 0; i < proc_install->nparams; i++)
     {
-      if (! _gimp_wire_read_int32 (channel,
-                                   (guint32 *) &proc_install->params[i].type, 1,
-                                   user_data))
-        goto cleanup;
-      if (! _gimp_wire_read_string (channel,
-                                    &proc_install->params[i].name, 1,
-                                    user_data))
-        goto cleanup;
-      if (! _gimp_wire_read_string (channel,
-                                    &proc_install->params[i].description, 1,
-                                    user_data))
+      if (! _gp_param_def_read (channel,
+                                &proc_install->params[i],
+                                user_data))
         goto cleanup;
     }
 
@@ -1073,17 +1221,9 @@ _gp_proc_install_read (GIOChannel      *channel,
 
   for (i = 0; i < proc_install->nreturn_vals; i++)
     {
-      if (! _gimp_wire_read_int32 (channel,
-                                   (guint32 *) &proc_install->return_vals[i].type, 1,
-                                   user_data))
-        goto cleanup;
-      if (! _gimp_wire_read_string (channel,
-                                    &proc_install->return_vals[i].name, 1,
-                                    user_data))
-        goto cleanup;
-      if (! _gimp_wire_read_string (channel,
-                                    &proc_install->return_vals[i].description, 1,
-                                    user_data))
+      if (! _gp_param_def_read (channel,
+                                &proc_install->return_vals[i],
+                                user_data))
         goto cleanup;
     }
 
@@ -1104,11 +1244,10 @@ _gp_proc_install_read (GIOChannel      *channel,
     {
       for (i = 0; i < proc_install->nparams; i++)
         {
-          if (!proc_install->params[i].name)
+          if (! proc_install->params[i].name)
             break;
 
-          g_free (proc_install->params[i].name);
-          g_free (proc_install->params[i].description);
+          _gp_param_def_destroy (&proc_install->params[i]);
         }
 
       g_free (proc_install->params);
@@ -1118,11 +1257,10 @@ _gp_proc_install_read (GIOChannel      *channel,
     {
       for (i = 0; i < proc_install->nreturn_vals; i++)
         {
-          if (!proc_install->return_vals[i].name)
+          if (! proc_install->return_vals[i].name)
             break;
 
-          g_free (proc_install->return_vals[i].name);
-          g_free (proc_install->return_vals[i].description);
+          _gp_param_def_destroy (&proc_install->return_vals[i]);
         }
 
       g_free (proc_install->return_vals);
@@ -1132,7 +1270,131 @@ _gp_proc_install_read (GIOChannel      *channel,
   msg->data = NULL;
 }
 
-static void
+static gboolean
+_gp_param_def_write (GIOChannel *channel,
+                     GPParamDef *param_def,
+                     gpointer    user_data)
+{
+  if (! _gimp_wire_write_int32 (channel,
+                                &param_def->param_def_type, 1,
+                                user_data))
+    return FALSE;
+
+  if (! _gimp_wire_write_string (channel,
+                                 &param_def->type_name, 1,
+                                 user_data))
+    return FALSE;
+
+  if (! _gimp_wire_write_string (channel,
+                                 &param_def->name, 1,
+                                 user_data))
+    return FALSE;
+
+  if (! _gimp_wire_write_string (channel,
+                                 &param_def->nick, 1,
+                                 user_data))
+    return FALSE;
+
+  if (! _gimp_wire_write_string (channel,
+                                 &param_def->blurb, 1,
+                                 user_data))
+    return FALSE;
+
+  switch (param_def->param_def_type)
+    {
+    case GP_PARAM_DEF_TYPE_DEFAULT:
+      break;
+
+    case GP_PARAM_DEF_TYPE_INT:
+      if (! _gimp_wire_write_int32 (channel,
+                                    (guint32 *) &param_def->meta.m_int.min_val, 1,
+                                    user_data) ||
+          ! _gimp_wire_write_int32 (channel,
+                                    (guint32 *) &param_def->meta.m_int.max_val, 1,
+                                    user_data) ||
+          ! _gimp_wire_write_int32 (channel,
+                                    (guint32 *) &param_def->meta.m_int.default_val, 1,
+                                    user_data))
+        return FALSE;
+      break;
+
+    case GP_PARAM_DEF_TYPE_ENUM:
+      if (! _gimp_wire_write_string (channel,
+                                     &param_def->meta.m_enum.type_name, 1,
+                                     user_data) ||
+          ! _gimp_wire_write_int32 (channel,
+                                    (guint32 *) &param_def->meta.m_enum.default_val, 1,
+                                    user_data))
+        return FALSE;
+      break;
+
+    case GP_PARAM_DEF_TYPE_BOOLEAN:
+      if (! _gimp_wire_write_int32 (channel,
+                                    (guint32 *) &param_def->meta.m_boolean.default_val, 1,
+                                    user_data))
+        return FALSE;
+      break;
+
+    case GP_PARAM_DEF_TYPE_FLOAT:
+      if (! _gimp_wire_write_double (channel,
+                                     &param_def->meta.m_float.min_val, 1,
+                                     user_data) ||
+          ! _gimp_wire_write_double (channel,
+                                     &param_def->meta.m_float.max_val, 1,
+                                     user_data) ||
+          ! _gimp_wire_write_double (channel,
+                                     &param_def->meta.m_float.default_val, 1,
+                                     user_data))
+        return FALSE;
+      break;
+
+    case GP_PARAM_DEF_TYPE_STRING:
+      if (! _gimp_wire_write_int32 (channel,
+                                    (guint32 *) &param_def->meta.m_string.allow_non_utf8, 1,
+                                    user_data) ||
+          ! _gimp_wire_write_int32 (channel,
+                                    (guint32 *) &param_def->meta.m_string.null_ok, 1,
+                                    user_data) ||
+          ! _gimp_wire_write_int32 (channel,
+                                    (guint32 *) &param_def->meta.m_string.non_empty, 1,
+                                    user_data) ||
+          ! _gimp_wire_write_string (channel,
+                                     &param_def->meta.m_string.default_val, 1,
+                                     user_data))
+        return FALSE;
+      break;
+
+    case GP_PARAM_DEF_TYPE_COLOR:
+      if (! _gimp_wire_write_int32 (channel,
+                                    (guint32 *) &param_def->meta.m_color.has_alpha, 1,
+                                    user_data) ||
+          ! _gimp_wire_write_double (channel,
+                                     &param_def->meta.m_color.default_val.r, 1,
+                                     user_data) ||
+          ! _gimp_wire_write_double (channel,
+                                     &param_def->meta.m_color.default_val.g, 1,
+                                     user_data) ||
+          ! _gimp_wire_write_double (channel,
+                                     &param_def->meta.m_color.default_val.b, 1,
+                                     user_data) ||
+          ! _gimp_wire_write_double (channel,
+                                     &param_def->meta.m_color.default_val.a, 1,
+                                     user_data))
+        return FALSE;
+      break;
+
+    case GP_PARAM_DEF_TYPE_ID:
+      if (! _gimp_wire_write_int32 (channel,
+                                    (guint32 *) &param_def->meta.m_id.none_ok, 1,
+                                    user_data))
+        return FALSE;
+      break;
+    }
+
+  return TRUE;
+}
+
+  static void
 _gp_proc_install_write (GIOChannel      *channel,
                         GimpWireMessage *msg,
                         gpointer         user_data)
@@ -1177,33 +1439,17 @@ _gp_proc_install_write (GIOChannel      *channel,
 
   for (i = 0; i < proc_install->nparams; i++)
     {
-      if (! _gimp_wire_write_int32 (channel,
-                                    (guint32 *) &proc_install->params[i].type, 1,
-                                    user_data))
-        return;
-      if (! _gimp_wire_write_string (channel,
-                                     &proc_install->params[i].name, 1,
-                                     user_data))
-        return;
-      if (! _gimp_wire_write_string (channel,
-                                     &proc_install->params[i].description, 1,
-                                     user_data))
+      if (! _gp_param_def_write (channel,
+                                 &proc_install->params[i],
+                                 user_data))
         return;
     }
 
   for (i = 0; i < proc_install->nreturn_vals; i++)
     {
-      if (! _gimp_wire_write_int32 (channel,
-                                    (guint32 *) &proc_install->return_vals[i].type, 1,
-                                    user_data))
-        return;
-      if (! _gimp_wire_write_string (channel,
-                                     &proc_install->return_vals[i].name, 1,
-                                     user_data))
-        return;
-      if (! _gimp_wire_write_string (channel,
-                                     &proc_install->return_vals[i].description, 1,
-                                     user_data))
+      if (! _gp_param_def_write (channel,
+                                 &proc_install->return_vals[i],
+                                 user_data))
         return;
     }
 }
@@ -1228,14 +1474,12 @@ _gp_proc_install_destroy (GimpWireMessage *msg)
 
       for (i = 0; i < proc_install->nparams; i++)
         {
-          g_free (proc_install->params[i].name);
-          g_free (proc_install->params[i].description);
+          _gp_param_def_destroy (&proc_install->params[i]);
         }
 
       for (i = 0; i < proc_install->nreturn_vals; i++)
         {
-          g_free (proc_install->return_vals[i].name);
-          g_free (proc_install->return_vals[i].description);
+          _gp_param_def_destroy (&proc_install->return_vals[i]);
         }
 
       g_free (proc_install->params);
diff --git a/libgimpbase/gimpprotocol.h b/libgimpbase/gimpprotocol.h
index b8e21be0d6..fcb0ee9bfb 100644
--- a/libgimpbase/gimpprotocol.h
+++ b/libgimpbase/gimpprotocol.h
@@ -26,7 +26,7 @@ G_BEGIN_DECLS
 
 /* Increment every time the protocol changes
  */
-#define GIMP_PROTOCOL_VERSION  0x0103
+#define GIMP_PROTOCOL_VERSION  0x0104
 
 
 enum
@@ -46,17 +46,36 @@ enum
   GP_HAS_INIT
 };
 
+typedef enum
+{
+  GP_PARAM_DEF_TYPE_DEFAULT,
+  GP_PARAM_DEF_TYPE_INT,
+  GP_PARAM_DEF_TYPE_ENUM,
+  GP_PARAM_DEF_TYPE_BOOLEAN,
+  GP_PARAM_DEF_TYPE_FLOAT,
+  GP_PARAM_DEF_TYPE_STRING,
+  GP_PARAM_DEF_TYPE_COLOR,
+  GP_PARAM_DEF_TYPE_ID
+} GPParamDefType;
+
 
-typedef struct _GPConfig        GPConfig;
-typedef struct _GPTileReq       GPTileReq;
-typedef struct _GPTileAck       GPTileAck;
-typedef struct _GPTileData      GPTileData;
-typedef struct _GPParam         GPParam;
-typedef struct _GPParamDef      GPParamDef;
-typedef struct _GPProcRun       GPProcRun;
-typedef struct _GPProcReturn    GPProcReturn;
-typedef struct _GPProcInstall   GPProcInstall;
-typedef struct _GPProcUninstall GPProcUninstall;
+typedef struct _GPConfig          GPConfig;
+typedef struct _GPTileReq         GPTileReq;
+typedef struct _GPTileAck         GPTileAck;
+typedef struct _GPTileData        GPTileData;
+typedef struct _GPParam           GPParam;
+typedef struct _GPParamDef        GPParamDef;
+typedef struct _GPParamDefInt     GPParamDefInt;
+typedef struct _GPParamDefEnum    GPParamDefEnum;
+typedef struct _GPParamDefBoolean GPParamDefBoolean;
+typedef struct _GPParamDefFloat   GPParamDefFloat;
+typedef struct _GPParamDefString  GPParamDefString;
+typedef struct _GPParamDefColor   GPParamDefColor;
+typedef struct _GPParamDefID      GPParamDefID;
+typedef struct _GPProcRun         GPProcRun;
+typedef struct _GPProcReturn      GPProcReturn;
+typedef struct _GPProcInstall     GPProcInstall;
+typedef struct _GPProcUninstall   GPProcUninstall;
 
 
 struct _GPConfig
@@ -126,6 +145,7 @@ struct _GPParam
     gint32        d_image;
     gint32        d_item;
     gint32        d_layer;
+    gint32        d_layer_mask;
     gint32        d_channel;
     gint32        d_drawable;
     gint32        d_selection;
@@ -136,11 +156,68 @@ struct _GPParam
   } data;
 };
 
+struct _GPParamDefInt
+{
+  gint32 min_val;
+  gint32 max_val;
+  gint32 default_val;
+};
+
+struct _GPParamDefEnum
+{
+  gchar  *type_name;
+  gint32  default_val;
+};
+
+struct _GPParamDefBoolean
+{
+  gint32 default_val;
+};
+
+struct _GPParamDefFloat
+{
+  gdouble min_val;
+  gdouble max_val;
+  gdouble default_val;
+};
+
+struct _GPParamDefString
+{
+  gint32  allow_non_utf8;
+  gint32  null_ok;
+  gint32  non_empty;
+  gchar  *default_val;
+};
+
+struct _GPParamDefColor
+{
+  gint32  has_alpha;
+  GimpRGB default_val;
+};
+
+struct _GPParamDefID
+{
+  gint32 none_ok;
+};
+
 struct _GPParamDef
 {
-  guint32  type;
-  gchar   *name;
-  gchar   *description;
+  GPParamDefType  param_def_type;
+  gchar          *type_name;
+  gchar          *name;
+  gchar          *nick;
+  gchar          *blurb;
+
+  union
+  {
+    GPParamDefInt     m_int;
+    GPParamDefEnum    m_enum;
+    GPParamDefBoolean m_boolean;
+    GPParamDefFloat   m_float;
+    GPParamDefString  m_string;
+    GPParamDefColor   m_color;
+    GPParamDefID      m_id;
+  } meta;
 };
 
 struct _GPProcRun
diff --git a/plug-ins/common/cml-explorer.c b/plug-ins/common/cml-explorer.c
index 6b8465828c..2e04dd1399 100644
--- a/plug-ins/common/cml-explorer.c
+++ b/plug-ins/common/cml-explorer.c
@@ -450,7 +450,7 @@ query (void)
 {
   static const GimpParamDef args [] =
   {
-    { GIMP_PDB_INT32,    "ru-_mode",           "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) 
}" },
+    { GIMP_PDB_INT32,    "run-mode",           "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) 
}" },
     { GIMP_PDB_IMAGE,    "image",              "Input image (not used)" },
     { GIMP_PDB_DRAWABLE, "drawable",           "Input drawable"  },
     { GIMP_PDB_STRING,   "parameter-filename", "The name of parameter file. CML_explorer makes an image with 
its settings." }
diff --git a/plug-ins/common/goat-exercise.c b/plug-ins/common/goat-exercise.c
index 75b74414db..b20b438a72 100644
--- a/plug-ins/common/goat-exercise.c
+++ b/plug-ins/common/goat-exercise.c
@@ -27,74 +27,132 @@
 #define PLUG_IN_PROC "plug-in-goat-exercise"
 
 
-/* Declare local functions.
- */
-static void   query       (void);
-static void   run         (const gchar      *name,
-                           gint              nparams,
-                           const GimpParam  *param,
-                           gint             *nreturn_vals,
-                           GimpParam       **return_vals);
+typedef struct _Goat      Goat;
+typedef struct _GoatClass GoatClass;
 
+struct _Goat
+{
+  GimpPlugIn parent_instance;
+};
 
-const GimpPlugInInfo PLUG_IN_INFO =
+struct _GoatClass
 {
-  NULL,  /* init_proc  */
-  NULL,  /* quit_proc  */
-  query, /* query_proc */
-  run,   /* run_proc   */
+  GimpPlugInClass parent_class;
 };
 
-MAIN ()
+
+/* Declare local functions.
+ */
+
+#define GOAT_TYPE  (goat_get_type ())
+#define GOAT (obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOAT_TYPE, Goat))
+
+GType                   goat_get_type         (void) G_GNUC_CONST;
+
+static gchar         ** goat_query_procedures (GimpPlugIn           *plug_in,
+                                               gint                 *n_procedures);
+static GimpProcedure  * goat_create_procedure (GimpPlugIn           *plug_in,
+                                               const gchar          *name);
+
+static GimpValueArray * goat_run              (GimpProcedure        *procedure,
+                                               const GimpValueArray *args);
+
+
+G_DEFINE_TYPE (Goat, goat, GIMP_TYPE_PLUG_IN)
+
+GIMP_MAIN (GOAT_TYPE)
 
 
 static void
-query (void)
+goat_class_init (GoatClass *klass)
 {
-  static const GimpParamDef args[] =
-  {
-    { GIMP_PDB_INT32,    "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
-    { GIMP_PDB_IMAGE,    "image",    "Input image (unused)"         },
-    { GIMP_PDB_DRAWABLE, "drawable", "Input drawable"               }
-  };
-
-  gimp_install_procedure (PLUG_IN_PROC,
-                          N_("Exercise a goat"),
-                          "takes a goat for a walk",
-                          "Øyvind Kolås <pippin gimp org>",
-                          "Øyvind Kolås <pippin gimp org>",
-                          "21march 2012",
-                          N_("Goat-exercise"),
-                          "RGB*, INDEXED*, GRAY*",
-                          GIMP_PLUGIN,
-                          G_N_ELEMENTS (args), 0,
-                          args, NULL);
-
-  gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Filters");
+  GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);
+
+  plug_in_class->query_procedures = goat_query_procedures;
+  plug_in_class->create_procedure = goat_create_procedure;
 }
 
 static void
-run (const gchar      *name,
-     gint              nparams,
-     const GimpParam  *param,
-     gint             *nreturn_vals,
-     GimpParam       **return_vals)
+goat_init (Goat *goat)
 {
-  static GimpParam   values[1];
-  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
-  gint32             drawable_id;
-  gint               x, y, width, height;
+}
+
+static gchar **
+goat_query_procedures (GimpPlugIn *plug_in,
+                       gint       *n_procedures)
+{
+  gchar **procedures = g_new0 (gchar *, 2);
+
+  procedures[0] = g_strdup (PLUG_IN_PROC);
+
+  *n_procedures = 1;
+
+  return procedures;
+}
+
+static GimpProcedure *
+goat_create_procedure (GimpPlugIn  *plug_in,
+                       const gchar *name)
+{
+  GimpProcedure *procedure = NULL;
+
+  if (! strcmp (name, PLUG_IN_PROC))
+    {
+      procedure = gimp_procedure_new (name, goat_run);
+
+      gimp_procedure_set_strings (procedure,
+                                  N_("Goat-exercise"),
+                                  N_("Exercise a goat"),
+                                  "takes a goat for a walk",
+                                  PLUG_IN_PROC,
+                                  "Øyvind Kolås <pippin gimp org>",
+                                  "Øyvind Kolås <pippin gimp org>",
+                                  "21march 2012",
+                                  "RGB*, INDEXED*, GRAY*");
+
+      gimp_procedure_add_menu_path (procedure, "<Image>/Filters");
+
+      gimp_procedure_add_argument (procedure,
+                                   g_param_spec_enum ("run-mode",
+                                                      "Run mode",
+                                                      "The run mode",
+                                                      GIMP_TYPE_RUN_MODE,
+                                                      GIMP_RUN_NONINTERACTIVE,
+                                                      G_PARAM_READWRITE));
+      gimp_procedure_add_argument (procedure,
+                                   gimp_param_spec_image_id ("image",
+                                                             "Image",
+                                                             "The input image",
+                                                             FALSE,
+                                                             G_PARAM_READWRITE));
+      gimp_procedure_add_argument (procedure,
+                                   gimp_param_spec_drawable_id ("drawable",
+                                                                "Drawable",
+                                                                "The input drawable",
+                                                                FALSE,
+                                                                G_PARAM_READWRITE));
+    }
+
+  return procedure;
+}
+
+static GimpValueArray *
+goat_run (GimpProcedure        *procedure,
+          const GimpValueArray *args)
+{
+  GimpPDBStatusType status = GIMP_PDB_SUCCESS;
+  gint32            drawable_id;
+  gint              x, y, width, height;
 
   INIT_I18N();
   gegl_init (NULL, NULL);
 
-  *nreturn_vals = 1;
-  *return_vals = values;
+  g_printerr ("goat run %d %d %d\n",
+              g_value_get_enum           (gimp_value_array_index (args, 0)),
+              gimp_value_get_image_id    (gimp_value_array_index (args, 1)),
+              gimp_value_get_drawable_id (gimp_value_array_index (args, 2)));
 
-  values[0].type          = GIMP_PDB_STATUS;
-  values[0].data.d_status = status;
-
-  drawable_id = param[2].data.d_drawable;
+  drawable_id = gimp_value_get_drawable_id (gimp_value_array_index (args, 2));
 
   if (gimp_drawable_mask_intersect (drawable_id, &x, &y, &width, &height))
     {
@@ -114,6 +172,7 @@ run (const gchar      *name,
       gimp_displays_flush ();
     }
 
-  values[0].data.d_status = status;
   gegl_exit ();
+
+  return gimp_procedure_new_return_values (procedure, status, NULL);
 }


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