[gimp] libgimp: add GimpFileProcedure, GimpLoadProcedure and GimpSaveProcedure



commit a79eaaf503eb0c8e664db0cc6e79ffa679b7ef4a
Author: Michael Natterer <mitch gimp org>
Date:   Sat Aug 10 20:25:37 2019 +0200

    libgimp: add GimpFileProcedure, GimpLoadProcedure and GimpSaveProcedure
    
    which are GimpProcedure subclasses with API to register as load/save
    handlers and their own kind of run functions that get their standard
    arguments passed directly instead of packed into a GimpValueArray.
    
    They also register their standard arguments themselves, which removes
    quite some boilerplate from load/save plug-ins.
    
    Remove gimpprocedure-private.[ch] because install() and uninstall()
    are now virtual functions of GimpProcedure.

 libgimp/Makefile.am             |   2 -
 libgimp/Makefile.gi             |   6 +
 libgimp/gimp.h                  |   3 +-
 libgimp/gimpfileprocedure.c     | 282 ++++++++++++++++++++++++++++++++++++++++
 libgimp/gimpfileprocedure.h     |  82 ++++++++++++
 libgimp/gimploadprocedure.c     | 258 ++++++++++++++++++++++++++++++++++++
 libgimp/gimploadprocedure.h     |  95 ++++++++++++++
 libgimp/gimpplugin-private.c    |   3 +-
 libgimp/gimpplugin.c            |   5 +-
 libgimp/gimpprocedure-private.c | 182 --------------------------
 libgimp/gimpprocedure-private.h |  35 -----
 libgimp/gimpprocedure.c         | 190 +++++++++++++++++++++++----
 libgimp/gimpprocedure.h         |   7 +-
 libgimp/gimpsaveprocedure.c     | 217 +++++++++++++++++++++++++++++++
 libgimp/gimpsaveprocedure.h     |  95 ++++++++++++++
 15 files changed, 1212 insertions(+), 250 deletions(-)
---
diff --git a/libgimp/Makefile.am b/libgimp/Makefile.am
index 080fd9ae51..4d4882b0fe 100644
--- a/libgimp/Makefile.am
+++ b/libgimp/Makefile.am
@@ -123,8 +123,6 @@ libgimp_private_sources = \
        gimppixbuf.h            \
        gimpplugin-private.c    \
        gimpplugin-private.h    \
-       gimpprocedure-private.c \
-       gimpprocedure-private.h \
        \
        gimpunit_pdb.c          \
        gimpunit_pdb.h          \
diff --git a/libgimp/Makefile.gi b/libgimp/Makefile.gi
index 8d3438bb40..584f12d86e 100644
--- a/libgimp/Makefile.gi
+++ b/libgimp/Makefile.gi
@@ -112,12 +112,14 @@ libgimp_introspectable_headers = \
        ../libgimp/gimpbrushselect.h            \
        ../libgimp/gimpchannel.h                \
        ../libgimp/gimpdrawable.h               \
+       ../libgimp/gimpfileprocedure.h          \
        ../libgimp/gimpfontselect.h             \
        ../libgimp/gimpgimprc.h                 \
        ../libgimp/gimpgradientselect.h         \
        ../libgimp/gimpimage.h                  \
        ../libgimp/gimpimagecolorprofile.h      \
        ../libgimp/gimplayer.h                  \
+       ../libgimp/gimploadprocedure.h          \
        ../libgimp/gimppaletteselect.h          \
        ../libgimp/gimpparamspecs.h             \
        ../libgimp/gimppatternselect.h          \
@@ -125,6 +127,7 @@ libgimp_introspectable_headers = \
        ../libgimp/gimpplugin.h                 \
        ../libgimp/gimpprocedure.h              \
        ../libgimp/gimpprogress.h               \
+       ../libgimp/gimpsaveprocedure.h          \
        ../libgimp/gimpselection.h
 
 libgimp_introspectable = \
@@ -135,12 +138,14 @@ libgimp_introspectable = \
        ../libgimp/gimpbrushselect.c            \
        ../libgimp/gimpchannel.c                \
        ../libgimp/gimpdrawable.c               \
+       ../libgimp/gimpfileprocedure.c          \
        ../libgimp/gimpfontselect.c             \
        ../libgimp/gimpgimprc.c                 \
        ../libgimp/gimpgradientselect.c         \
        ../libgimp/gimpimage.c                  \
        ../libgimp/gimpimagecolorprofile.c      \
        ../libgimp/gimplayer.c                  \
+       ../libgimp/gimploadprocedure.c          \
        ../libgimp/gimppaletteselect.c          \
        ../libgimp/gimpparamspecs.c             \
        ../libgimp/gimppatternselect.c          \
@@ -148,6 +153,7 @@ libgimp_introspectable = \
        ../libgimp/gimpplugin.c                 \
        ../libgimp/gimpprocedure.c              \
        ../libgimp/gimpprogress.c               \
+       ../libgimp/gimpsaveprocedure.c          \
        ../libgimp/gimpselection.c
 
 libgimpui_introspectable_headers = \
diff --git a/libgimp/gimp.h b/libgimp/gimp.h
index 00edc46eb8..bdfa69481e 100644
--- a/libgimp/gimp.h
+++ b/libgimp/gimp.h
@@ -44,14 +44,15 @@
 #include <libgimp/gimpimage.h>
 #include <libgimp/gimpimagecolorprofile.h>
 #include <libgimp/gimplayer.h>
+#include <libgimp/gimploadprocedure.h>
 #include <libgimp/gimplegacy.h>
 #include <libgimp/gimppaletteselect.h>
 #include <libgimp/gimpparamspecs.h>
 #include <libgimp/gimppatternselect.h>
 #include <libgimp/gimppdb.h>
 #include <libgimp/gimpplugin.h>
-#include <libgimp/gimpprocedure.h>
 #include <libgimp/gimpprogress.h>
+#include <libgimp/gimpsaveprocedure.h>
 #include <libgimp/gimpselection.h>
 
 #include <libgimp/gimp_pdb_headers.h>
diff --git a/libgimp/gimpfileprocedure.c b/libgimp/gimpfileprocedure.c
new file mode 100644
index 0000000000..3c2f426f9d
--- /dev/null
+++ b/libgimp/gimpfileprocedure.c
@@ -0,0 +1,282 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpfileprocedure.c
+ * Copyright (C) 2019 Michael Natterer <mitch gimp org>
+ *
+ * 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 "gimp.h"
+#include "gimpfileprocedure.h"
+
+
+struct _GimpFileProcedurePrivate
+{
+  gchar *mime_types;
+  gchar *extensions;
+  gchar *prefixes;
+  gchar *magics;
+  gint   priority;
+};
+
+
+static void   gimp_file_procedure_constructed (GObject *object);
+static void   gimp_file_procedure_finalize    (GObject *object);
+
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GimpFileProcedure, gimp_file_procedure,
+                                     GIMP_TYPE_PROCEDURE)
+
+#define parent_class gimp_file_procedure_parent_class
+
+
+static void
+gimp_file_procedure_class_init (GimpFileProcedureClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->constructed  = gimp_file_procedure_constructed;
+  object_class->finalize     = gimp_file_procedure_finalize;
+}
+
+static void
+gimp_file_procedure_init (GimpFileProcedure *procedure)
+{
+  procedure->priv = gimp_file_procedure_get_instance_private (procedure);
+}
+
+static void
+gimp_file_procedure_constructed (GObject *object)
+{
+  GimpProcedure *procedure = GIMP_PROCEDURE (object);
+
+  G_OBJECT_CLASS (parent_class)->constructed (object);
+
+  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));
+}
+
+static void
+gimp_file_procedure_finalize (GObject *object)
+{
+  GimpFileProcedure *procedure = GIMP_FILE_PROCEDURE (object);
+
+  g_clear_pointer (&procedure->priv->mime_types, g_free);
+  g_clear_pointer (&procedure->priv->extensions, g_free);
+  g_clear_pointer (&procedure->priv->prefixes,   g_free);
+  g_clear_pointer (&procedure->priv->magics,     g_free);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+/*  public functions  */
+
+/**
+ * gimp_file_procedure_set_mime_types:
+ * @procedure: A #GimpFileProcedure.
+ * @mime_types: A comma-separated list of MIME types, such as "image/jpeg".
+ *
+ * Associates MIME types with a file handler procedure.
+ *
+ * Registers MIME types for a file handler procedure. This allows GIMP
+ * to determine the MIME type of the file opened or saved using this
+ * procedure. It is recommended that only one MIME type is registered
+ * per file procedure; when registering more than one MIME type, GIMP
+ * will associate the first one with files opened or saved with this
+ * procedure.
+ *
+ * Since: 3.0
+ **/
+void
+gimp_file_procedure_set_mime_types (GimpFileProcedure *procedure,
+                                    const gchar       *mime_types)
+{
+  g_return_if_fail (GIMP_IS_FILE_PROCEDURE (procedure));
+
+  g_free (procedure->priv->mime_types);
+  procedure->priv->mime_types = g_strdup (mime_types);
+}
+
+/**
+ * gimp_file_procedure_get_mime_types:
+ * @procedure: A #GimpFileProcedure.
+ *
+ * Returns: The procedure's mime-type as set with
+ *          gimp_file_procedure_set_mime_types().
+ *
+ * Since: 3.0
+ **/
+const gchar *
+gimp_file_procedure_get_mime_types (GimpFileProcedure *procedure)
+{
+  g_return_val_if_fail (GIMP_IS_FILE_PROCEDURE (procedure), NULL);
+
+  return procedure->priv->mime_types;
+}
+
+/**
+ * gimp_file_procedure_set_extensions:
+ * @procedure:  A #GimpFileProcedure.
+ * @extensions: A comma separated list of extensions this procedure can
+ *              handle (i.e. "jpg,jpeg").
+ *
+ * Since: 3.0
+ **/
+void
+gimp_file_procedure_set_extensions (GimpFileProcedure *procedure,
+                                    const gchar       *extensions)
+{
+  g_return_if_fail (GIMP_IS_FILE_PROCEDURE (procedure));
+
+  g_free (procedure->priv->extensions);
+  procedure->priv->extensions = g_strdup (extensions);
+}
+
+/**
+ * gimp_file_procedure_get_extensions:
+ * @procedure: A #GimpFileProcedure.
+ *
+ * Returns: The procedure's extensions as set with
+ *          gimp_file_procedure_set_extensions().
+ *
+ * Since: 3.0
+ **/
+const gchar *
+gimp_file_procedure_get_extensions (GimpFileProcedure *procedure)
+{
+  g_return_val_if_fail (GIMP_IS_FILE_PROCEDURE (procedure), NULL);
+
+  return procedure->priv->extensions;
+}
+
+/**
+ * gimp_file_procedure_set_prefixes:
+ * @procedure: A #GimpFileProcedure.
+ * @prefixes:  A comma separated list of prefixes this procedure can
+ *             handle (i.e. "http:,ftp:").
+ *
+ * It should almost never be neccessary to register prefixes with file
+ * procedures, because most sorty of URIs should be handled by GIO.
+ *
+ * Since: 3.0
+ **/
+void
+gimp_file_procedure_set_prefixes (GimpFileProcedure *procedure,
+                                  const gchar       *prefixes)
+{
+  g_return_if_fail (GIMP_IS_FILE_PROCEDURE (procedure));
+
+  g_free (procedure->priv->prefixes);
+  procedure->priv->prefixes = g_strdup (prefixes);
+}
+
+/**
+ * gimp_file_procedure_get_prefixes:
+ * @procedure: A #GimpFileProcedure.
+ *
+ * Returns: The procedure's prefixes as set with
+ *          gimp_file_procedure_set_prefixes().
+ *
+ * Since: 3.0
+ **/
+const gchar *
+gimp_file_procedure_get_prefixes (GimpFileProcedure *procedure)
+{
+  g_return_val_if_fail (GIMP_IS_FILE_PROCEDURE (procedure), NULL);
+
+  return procedure->priv->prefixes;
+}
+
+/**
+ * gimp_file_procedure_set_magics:
+ * @procedure: A #GimpFileProcedure.
+ * @magics:    A comma separated list of magic file information this procedure
+ *             can hande (i.e. "0,string,GIF").
+ *
+ * Since: 3.0
+ **/
+void
+gimp_file_procedure_set_magics (GimpFileProcedure *procedure,
+                                const gchar       *magics)
+{
+  g_return_if_fail (GIMP_IS_FILE_PROCEDURE (procedure));
+
+  g_free (procedure->priv->magics);
+  procedure->priv->magics = g_strdup (magics);
+}
+
+/**
+ * gimp_file_procedure_get_magics:
+ * @procedure: A #GimpFileProcedure.
+ *
+ * Returns: The procedure's magics as set with
+ *          gimp_file_procedure_set_magics().
+ *
+ * Since: 3.0
+ **/
+const gchar *
+gimp_file_procedure_get_magics (GimpFileProcedure *procedure)
+{
+  g_return_val_if_fail (GIMP_IS_FILE_PROCEDURE (procedure), NULL);
+
+  return procedure->priv->magics;
+}
+
+/**
+ * gimp_file_procedure_set_priority:
+ * @procedure: A #GimpFileProcedure.
+ * @priority: The procedure's priority.
+ *
+ * Sets the priority of a file handler procedure. When more than one
+ * procedure matches a given file, the procedure with the lowest
+ * priority is used; if more than one procedure has the lowest
+ * priority, it is unspecified which one of them is used. The default
+ * priority for file handler procedures is 0.
+ *
+ * Since: 3.0
+ **/
+void
+gimp_file_procedure_set_priority (GimpFileProcedure *procedure,
+                                  gint               priority)
+{
+  g_return_if_fail (GIMP_IS_FILE_PROCEDURE (procedure));
+
+  procedure->priv->priority = priority;
+}
+
+/**
+ * gimp_file_procedure_get_priority:
+ * @procedure: A #GimpFileProcedure.
+ *
+ * Returns: The procedure's priority as set with
+ *          gimp_file_procedure_set_priority().
+ *
+ * Since: 3.0
+ **/
+gint
+gimp_file_procedure_get_priority (GimpFileProcedure *procedure)
+{
+  g_return_val_if_fail (GIMP_IS_FILE_PROCEDURE (procedure), 0);
+
+  return procedure->priv->priority;
+}
diff --git a/libgimp/gimpfileprocedure.h b/libgimp/gimpfileprocedure.h
new file mode 100644
index 0000000000..bb554ea479
--- /dev/null
+++ b/libgimp/gimpfileprocedure.h
@@ -0,0 +1,82 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpfileprocedure.h
+ * Copyright (C) 2019 Michael Natterer <mitch gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_FILE_PROCEDURE_H__
+#define __GIMP_FILE_PROCEDURE_H__
+
+#include <libgimp/gimpprocedure.h>
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+#define GIMP_TYPE_FILE_PROCEDURE            (gimp_file_procedure_get_type ())
+#define GIMP_FILE_PROCEDURE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_FILE_PROCEDURE, 
GimpFileProcedure))
+#define GIMP_FILE_PROCEDURE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_FILE_PROCEDURE, 
GimpFileProcedureClass))
+#define GIMP_IS_FILE_PROCEDURE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_FILE_PROCEDURE))
+#define GIMP_IS_FILE_PROCEDURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_FILE_PROCEDURE))
+#define GIMP_FILE_PROCEDURE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_FILE_PROCEDURE, 
GimpFileProcedureClass))
+
+
+typedef struct _GimpFileProcedure        GimpFileProcedure;
+typedef struct _GimpFileProcedureClass   GimpFileProcedureClass;
+typedef struct _GimpFileProcedurePrivate GimpFileProcedurePrivate;
+
+struct _GimpFileProcedure
+{
+  GimpProcedure             parent_instance;
+
+  GimpFileProcedurePrivate *priv;
+};
+
+struct _GimpFileProcedureClass
+{
+  GimpProcedureClass parent_class;
+};
+
+
+GType           gimp_file_procedure_get_type       (void) G_GNUC_CONST;
+
+void            gimp_file_procedure_set_mime_types (GimpFileProcedure *procedure,
+                                                    const gchar       *mime_types);
+const gchar   * gimp_file_procedure_get_mime_types (GimpFileProcedure *procedure);
+
+void            gimp_file_procedure_set_extensions (GimpFileProcedure *procedure,
+                                                    const gchar       *extensions);
+const gchar   * gimp_file_procedure_get_extensions (GimpFileProcedure *procedure);
+
+void            gimp_file_procedure_set_prefixes   (GimpFileProcedure *procedure,
+                                                    const gchar       *prefixes);
+const gchar   * gimp_file_procedure_get_prefixes   (GimpFileProcedure *procedure);
+
+void            gimp_file_procedure_set_magics     (GimpFileProcedure *procedure,
+                                                    const gchar       *magics);
+const gchar   * gimp_file_procedure_get_magics     (GimpFileProcedure *procedure);
+
+void            gimp_file_procedure_set_priority   (GimpFileProcedure *procedure,
+                                                    gint               priority);
+gint            gimp_file_procedure_get_priority   (GimpFileProcedure *procedure);
+
+
+G_END_DECLS
+
+#endif  /*  __GIMP_FILE_PROCEDURE_H__  */
diff --git a/libgimp/gimploadprocedure.c b/libgimp/gimploadprocedure.c
new file mode 100644
index 0000000000..34c72fa5b3
--- /dev/null
+++ b/libgimp/gimploadprocedure.c
@@ -0,0 +1,258 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimploadprocedure.c
+ * Copyright (C) 2019 Michael Natterer <mitch gimp org>
+ *
+ * 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 "gimp.h"
+#include "gimploadprocedure.h"
+
+
+struct _GimpLoadProcedurePrivate
+{
+  GimpLoadFunc    run_func;
+  gpointer        run_data;
+  GDestroyNotify  run_data_destroy;
+
+  gboolean        handles_raw;
+};
+
+
+static void   gimp_load_procedure_constructed (GObject              *object);
+static void   gimp_load_procedure_finalize    (GObject              *object);
+
+static void   gimp_load_procedure_install     (GimpProcedure        *procedure);
+static GimpValueArray *
+              gimp_load_procedure_run         (GimpProcedure        *procedure,
+                                               const GimpValueArray *args);
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (GimpLoadProcedure, gimp_load_procedure,
+                            GIMP_TYPE_FILE_PROCEDURE)
+
+#define parent_class gimp_load_procedure_parent_class
+
+
+static void
+gimp_load_procedure_class_init (GimpLoadProcedureClass *klass)
+{
+  GObjectClass       *object_class    = G_OBJECT_CLASS (klass);
+  GimpProcedureClass *procedure_class = GIMP_PROCEDURE_CLASS (klass);
+
+  object_class->constructed  = gimp_load_procedure_constructed;
+  object_class->finalize     = gimp_load_procedure_finalize;
+
+  procedure_class->install   = gimp_load_procedure_install;
+  procedure_class->run       = gimp_load_procedure_run;
+}
+
+static void
+gimp_load_procedure_init (GimpLoadProcedure *procedure)
+{
+  procedure->priv = gimp_load_procedure_get_instance_private (procedure);
+}
+
+static void
+gimp_load_procedure_constructed (GObject *object)
+{
+  GimpProcedure *procedure = GIMP_PROCEDURE (object);
+
+  G_OBJECT_CLASS (parent_class)->constructed (object);
+
+  gimp_procedure_add_argument (procedure,
+                               gimp_param_spec_string ("uri",
+                                                       "URI",
+                                                       "The URI of the file "
+                                                       "to load",
+                                                       FALSE, FALSE, TRUE,
+                                                       NULL,
+                                                       GIMP_PARAM_READWRITE));
+  gimp_procedure_add_argument (procedure,
+                               gimp_param_spec_string ("raw-uri",
+                                                       "Raw URI",
+                                                       "The URI of the file "
+                                                       "to load",
+                                                       FALSE, FALSE, TRUE,
+                                                       NULL,
+                                                       GIMP_PARAM_READWRITE));
+
+  gimp_procedure_add_return_value (procedure,
+                                   gimp_param_spec_image_id ("image",
+                                                             "Image",
+                                                             "Output image",
+                                                             FALSE,
+                                                             GIMP_PARAM_READWRITE));
+}
+
+static void
+gimp_load_procedure_finalize (GObject *object)
+{
+  GimpLoadProcedure *procedure = GIMP_LOAD_PROCEDURE (object);
+
+  if (procedure->priv->run_data_destroy)
+    procedure->priv->run_data_destroy (procedure->priv->run_data);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_load_procedure_install (GimpProcedure *procedure)
+{
+  GimpLoadProcedure *load_proc = GIMP_LOAD_PROCEDURE (procedure);
+  GimpFileProcedure *file_proc = GIMP_FILE_PROCEDURE (procedure);
+  const gchar       *mime_types;
+  gint               priority;
+
+  GIMP_PROCEDURE_CLASS (parent_class)->install (procedure);
+
+  if (gimp_file_procedure_get_magics (file_proc))
+    {
+      gimp_register_magic_load_handler (gimp_procedure_get_name (procedure),
+                                        gimp_file_procedure_get_extensions (file_proc),
+                                        gimp_file_procedure_get_prefixes (file_proc),
+                                        gimp_file_procedure_get_magics (file_proc));
+    }
+  else
+    {
+      gimp_register_load_handler (gimp_procedure_get_name (procedure),
+                                  gimp_file_procedure_get_extensions (file_proc),
+                                  gimp_file_procedure_get_prefixes (file_proc));
+    }
+
+  gimp_register_file_handler_uri (gimp_procedure_get_name (procedure));
+
+  mime_types = gimp_file_procedure_get_mime_types (file_proc);
+  if (mime_types)
+    gimp_register_file_handler_mime (gimp_procedure_get_name (procedure),
+                                     mime_types);
+
+  priority = gimp_file_procedure_get_priority (file_proc);
+  if (priority != 0)
+    gimp_register_file_handler_priority (gimp_procedure_get_name (procedure),
+                                         priority);
+
+  if (load_proc->priv->handles_raw)
+    gimp_register_file_handler_raw (gimp_procedure_get_name (procedure));
+}
+
+static GimpValueArray *
+gimp_load_procedure_run (GimpProcedure        *procedure,
+                         const GimpValueArray *args)
+{
+  GimpLoadProcedure *load_proc = GIMP_LOAD_PROCEDURE (procedure);
+  GimpValueArray    *remaining;
+  GimpValueArray    *return_values;
+  GimpRunMode        run_mode;
+  const gchar       *uri;
+  GFile             *file;
+  gint               i;
+
+  run_mode   = g_value_get_enum   (gimp_value_array_index (args, 0));
+  uri        = g_value_get_string (gimp_value_array_index (args, 1));
+  /* raw_uri = g_value_get_string (gimp_value_array_index (args, 2)); */
+
+  file = g_file_new_for_uri (uri);
+
+  remaining = gimp_value_array_new (gimp_value_array_length (args) - 3);
+
+  for (i = 3; i < gimp_value_array_length (args); i++)
+    {
+      GValue *value = gimp_value_array_index (args, i);
+
+      gimp_value_array_append (remaining, value);
+    }
+
+  return_values = load_proc->priv->run_func (procedure,
+                                             run_mode,
+                                             file,
+                                             remaining,
+                                             load_proc->priv->run_data);
+
+  gimp_value_array_unref (remaining);
+  g_object_unref (file);
+
+  return return_values;
+}
+
+
+/*  public functions  */
+
+GimpProcedure  *
+gimp_load_procedure_new (GimpPlugIn      *plug_in,
+                         const gchar     *name,
+                         GimpPDBProcType  proc_type,
+                         GimpLoadFunc     run_func,
+                         gpointer         run_data,
+                         GDestroyNotify   run_data_destroy)
+{
+  GimpLoadProcedure *procedure;
+
+  g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), NULL);
+  g_return_val_if_fail (gimp_is_canonical_identifier (name), NULL);
+  g_return_val_if_fail (proc_type != GIMP_INTERNAL, NULL);
+  g_return_val_if_fail (run_func != NULL, NULL);
+
+  procedure = g_object_new (GIMP_TYPE_LOAD_PROCEDURE,
+                            "plug-in",        plug_in,
+                            "name",           name,
+                            "procedure-type", proc_type,
+                            NULL);
+
+  procedure->priv->run_func         = run_func;
+  procedure->priv->run_data         = run_data;
+  procedure->priv->run_data_destroy = run_data_destroy;
+
+  return GIMP_PROCEDURE (procedure);
+}
+
+/**
+ * gimp_load_procedure_set_handles_raw:
+ * @procedure:   A #GimpLoadProcedure.
+ * @handles_raw: The procedure's handles raw flag.
+ *
+ * Registers a load loader procedure as capable of handling raw
+ * digital camera loads.
+ *
+ * Since: 3.0
+ **/
+void
+gimp_load_procedure_set_handles_raw (GimpLoadProcedure *procedure,
+                                     gint               handles_raw)
+{
+  g_return_if_fail (GIMP_IS_LOAD_PROCEDURE (procedure));
+
+  procedure->priv->handles_raw = handles_raw;
+}
+
+/**
+ * gimp_load_procedure_get_handles_raw:
+ * @procedure: A #GimpLoadProcedure.
+ *
+ * Returns: The procedure's handles raw flag as set with
+ *          gimp_load_procedure_set_handles_raw().
+ *
+ * Since: 3.0
+ **/
+gint
+gimp_load_procedure_get_handles_raw (GimpLoadProcedure *procedure)
+{
+  g_return_val_if_fail (GIMP_IS_LOAD_PROCEDURE (procedure), 0);
+
+  return procedure->priv->handles_raw;
+}
diff --git a/libgimp/gimploadprocedure.h b/libgimp/gimploadprocedure.h
new file mode 100644
index 0000000000..1b77e03908
--- /dev/null
+++ b/libgimp/gimploadprocedure.h
@@ -0,0 +1,95 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimploadprocedure.h
+ * Copyright (C) 2019 Michael Natterer <mitch gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_LOAD_PROCEDURE_H__
+#define __GIMP_LOAD_PROCEDURE_H__
+
+#include <libgimp/gimpfileprocedure.h>
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+/**
+ * GimpLoadFunc:
+ * @procedure:   the #GimpProcedure that runs.
+ * @run_mode:    the #GimpRunMode.
+ * @file:        the #GFile to load from.
+ * @args:        the @procedure's remaining arguments.
+ * @run_data:    the run_data given in gimp_load_procedure_new().
+ *
+ * The load function is run during the lifetime of the GIMP session,
+ * each time a plug-in load procedure is called.
+ *
+ * Returns: (transfer full): the @procedure's return values.
+ *
+ * Since: 3.0
+ **/
+typedef GimpValueArray * (* GimpLoadFunc) (GimpProcedure        *procedure,
+                                           GimpRunMode           run_mode,
+                                           GFile                *file,
+                                           const GimpValueArray *args,
+                                           gpointer              run_data);
+
+
+#define GIMP_TYPE_LOAD_PROCEDURE            (gimp_load_procedure_get_type ())
+#define GIMP_LOAD_PROCEDURE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_LOAD_PROCEDURE, 
GimpLoadProcedure))
+#define GIMP_LOAD_PROCEDURE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_LOAD_PROCEDURE, 
GimpLoadProcedureClass))
+#define GIMP_IS_LOAD_PROCEDURE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_LOAD_PROCEDURE))
+#define GIMP_IS_LOAD_PROCEDURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_LOAD_PROCEDURE))
+#define GIMP_LOAD_PROCEDURE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_LOAD_PROCEDURE, 
GimpLoadProcedureClass))
+
+
+typedef struct _GimpLoadProcedure        GimpLoadProcedure;
+typedef struct _GimpLoadProcedureClass   GimpLoadProcedureClass;
+typedef struct _GimpLoadProcedurePrivate GimpLoadProcedurePrivate;
+
+struct _GimpLoadProcedure
+{
+  GimpFileProcedure         parent_instance;
+
+  GimpLoadProcedurePrivate *priv;
+};
+
+struct _GimpLoadProcedureClass
+{
+  GimpFileProcedureClass parent_class;
+};
+
+
+GType           gimp_load_procedure_get_type        (void) G_GNUC_CONST;
+
+GimpProcedure * gimp_load_procedure_new             (GimpPlugIn        *plug_in,
+                                                     const gchar       *name,
+                                                     GimpPDBProcType    proc_type,
+                                                     GimpLoadFunc       run_func,
+                                                     gpointer           run_data,
+                                                     GDestroyNotify     run_data_destroy);
+
+void            gimp_load_procedure_set_handles_raw (GimpLoadProcedure *procedure,
+                                                     gboolean           handles_raw);
+gboolean        gimp_load_procedure_get_handles_raw (GimpLoadProcedure *procedure);
+
+
+G_END_DECLS
+
+#endif  /*  __GIMP_LOAD_PROCEDURE_H__  */
diff --git a/libgimp/gimpplugin-private.c b/libgimp/gimpplugin-private.c
index 1ebcc60633..5b40c659ec 100644
--- a/libgimp/gimpplugin-private.c
+++ b/libgimp/gimpplugin-private.c
@@ -31,7 +31,6 @@
 #include "gimpgpparams.h"
 #include "gimpplugin-private.h"
 #include "gimpplugin_pdb.h"
-#include "gimpprocedure-private.h"
 
 
 /*  local function prototpes  */
@@ -185,7 +184,7 @@ gimp_plug_in_register (GimpPlugIn *plug_in,
       procedure = gimp_plug_in_create_procedure (plug_in, name);
       if (procedure)
         {
-          _gimp_procedure_register (procedure);
+          GIMP_PROCEDURE_GET_CLASS (procedure)->install (procedure);
           g_object_unref (procedure);
         }
       else
diff --git a/libgimp/gimpplugin.c b/libgimp/gimpplugin.c
index 2f7030b6e6..ab6b3be060 100644
--- a/libgimp/gimpplugin.c
+++ b/libgimp/gimpplugin.c
@@ -31,7 +31,6 @@
 
 #include "gimpplugin-private.h"
 #include "gimpplugin_pdb.h"
-#include "gimpprocedure-private.h"
 
 
 /**
@@ -393,7 +392,7 @@ gimp_plug_in_add_temp_procedure (GimpPlugIn    *plug_in,
     g_list_prepend (plug_in->priv->temp_procedures,
                     g_object_ref (procedure));
 
-  _gimp_procedure_register (procedure);
+  GIMP_PROCEDURE_GET_CLASS (procedure)->install (procedure);
 }
 
 /**
@@ -419,7 +418,7 @@ gimp_plug_in_remove_temp_procedure (GimpPlugIn  *plug_in,
 
   if (procedure)
     {
-      _gimp_procedure_unregister (procedure);
+      GIMP_PROCEDURE_GET_CLASS (procedure)->uninstall (procedure);
 
       plug_in->priv->temp_procedures =
         g_list_remove (plug_in->priv->temp_procedures,
diff --git a/libgimp/gimpprocedure.c b/libgimp/gimpprocedure.c
index 6336269eae..251b2d39c3 100644
--- a/libgimp/gimpprocedure.c
+++ b/libgimp/gimpprocedure.c
@@ -25,8 +25,13 @@
 
 #include "gimp.h"
 
+#include "libgimpbase/gimpprotocol.h"
+#include "libgimpbase/gimpwire.h"
+
+#include "gimpgpparams.h"
 #include "gimppdb-private.h"
-#include "gimpprocedure-private.h"
+#include "gimpplugin-private.h"
+#include "gimpplugin_pdb.h"
 
 #include "libgimp-intl.h"
 
@@ -76,31 +81,33 @@ struct _GimpProcedurePrivate
 };
 
 
-static void       gimp_procedure_constructed   (GObject              *object);
-static void       gimp_procedure_finalize      (GObject              *object);
-static void       gimp_procedure_set_property  (GObject              *object,
-                                                guint                 property_id,
-                                                const GValue         *value,
-                                                GParamSpec           *pspec);
-static void       gimp_procedure_get_property  (GObject              *object,
-                                                guint                 property_id,
-                                                GValue               *value,
-                                                GParamSpec           *pspec);
+static void       gimp_procedure_constructed    (GObject              *object);
+static void       gimp_procedure_finalize       (GObject              *object);
+static void       gimp_procedure_set_property   (GObject              *object,
+                                                 guint                 property_id,
+                                                 const GValue         *value,
+                                                 GParamSpec           *pspec);
+static void       gimp_procedure_get_property   (GObject              *object,
+                                                 guint                 property_id,
+                                                 GValue               *value,
+                                                 GParamSpec           *pspec);
 
+static void       gimp_procedure_real_install   (GimpProcedure        *procedure);
+static void       gimp_procedure_real_uninstall (GimpProcedure        *procedure);
 static GimpValueArray *
-                  gimp_procedure_real_run      (GimpProcedure        *procedure,
-                                                const GimpValueArray *args);
+                  gimp_procedure_real_run       (GimpProcedure        *procedure,
+                                                 const GimpValueArray *args);
 
-static gboolean   gimp_procedure_validate_args (GimpProcedure        *procedure,
-                                                GParamSpec          **param_specs,
-                                                gint                  n_param_specs,
-                                                const GimpValueArray *args,
-                                                gboolean              return_vals,
-                                                GError              **error);
+static gboolean   gimp_procedure_validate_args  (GimpProcedure        *procedure,
+                                                 GParamSpec          **param_specs,
+                                                 gint                  n_param_specs,
+                                                 const GimpValueArray *args,
+                                                 gboolean              return_vals,
+                                                 GError              **error);
 
-static void       gimp_procedure_set_icon      (GimpProcedure        *procedure,
-                                                GimpIconType          icon_type,
-                                                gconstpointer         icon_data);
+static void       gimp_procedure_set_icon       (GimpProcedure        *procedure,
+                                                 GimpIconType          icon_type,
+                                                 gconstpointer         icon_data);
 
 
 G_DEFINE_TYPE_WITH_PRIVATE (GimpProcedure, gimp_procedure, G_TYPE_OBJECT)
@@ -120,6 +127,8 @@ gimp_procedure_class_init (GimpProcedureClass *klass)
   object_class->set_property = gimp_procedure_set_property;
   object_class->get_property = gimp_procedure_get_property;
 
+  klass->install             = gimp_procedure_real_install;
+  klass->uninstall           = gimp_procedure_real_uninstall;
   klass->run                 = gimp_procedure_real_run;
 
   props[PROP_PLUG_IN] =
@@ -269,6 +278,135 @@ gimp_procedure_get_property (GObject    *object,
     }
 }
 
+static void
+gimp_procedure_real_install (GimpProcedure *procedure)
+{
+  GParamSpec   **args;
+  GParamSpec   **return_vals;
+  gint           n_args;
+  gint           n_return_vals;
+  GList         *list;
+  GimpPlugIn    *plug_in;
+  GPProcInstall  proc_install;
+  GimpIconType   icon_type;
+  guint8        *icon_data        = NULL;
+  gsize          icon_data_length = 0;
+  gint           i;
+
+  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.help_id      = (gchar *) gimp_procedure_get_help_id (procedure);
+  proc_install.authors      = (gchar *) gimp_procedure_get_authors (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_procedure_get_proc_type (procedure);
+  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]);
+    }
+
+  plug_in = gimp_procedure_get_plug_in (procedure);
+
+  if (! gp_proc_install_write (_gimp_plug_in_get_write_channel (plug_in),
+                               &proc_install, plug_in))
+    gimp_quit ();
+
+  icon_type = gimp_procedure_get_icon_type (procedure);
+
+  switch (icon_type)
+    {
+    case GIMP_ICON_TYPE_ICON_NAME:
+      {
+        icon_data = (guint8 *) gimp_procedure_get_icon_name (procedure);
+        if (icon_data)
+          icon_data_length = strlen ((gchar *) icon_data) + 1;
+      }
+      break;
+
+    case GIMP_ICON_TYPE_PIXBUF:
+      {
+        GdkPixbuf *pixbuf = gimp_procedure_get_icon_pixbuf (procedure);
+
+        if (pixbuf)
+          gdk_pixbuf_save_to_buffer (pixbuf,
+                                     (gchar **) &icon_data, &icon_data_length,
+                                     "png", NULL, NULL);
+      }
+      break;
+
+    case GIMP_ICON_TYPE_IMAGE_FILE:
+      {
+        GFile *file = gimp_procedure_get_icon_file (procedure);
+
+        if (file)
+          {
+            icon_data        = (guchar *) g_file_get_uri (file);
+            icon_data_length = strlen ((gchar *) icon_data) + 1;
+          }
+      }
+      break;
+    }
+
+  if (icon_data)
+    _gimp_plugin_icon_register (gimp_procedure_get_name (procedure),
+                                icon_type, icon_data_length, icon_data);
+
+  switch (icon_type)
+    {
+    case GIMP_ICON_TYPE_ICON_NAME:
+      break;
+
+    case GIMP_ICON_TYPE_PIXBUF:
+    case GIMP_ICON_TYPE_IMAGE_FILE:
+      g_free (icon_data);
+      break;
+    }
+
+  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);
+    }
+}
+
+static void
+gimp_procedure_real_uninstall (GimpProcedure *procedure)
+{
+  GimpPlugIn      *plug_in;
+  GPProcUninstall  proc_uninstall;
+
+  proc_uninstall.name = (gchar *) gimp_procedure_get_name (procedure);
+
+  plug_in = gimp_procedure_get_plug_in (procedure);
+
+  if (! gp_proc_uninstall_write (_gimp_plug_in_get_write_channel (plug_in),
+                                 &proc_uninstall, plug_in))
+    gimp_quit ();
+}
+
 static GimpValueArray *
 gimp_procedure_real_run (GimpProcedure        *procedure,
                          const GimpValueArray *args)
@@ -1239,10 +1377,16 @@ gimp_procedure_run (GimpProcedure        *procedure,
 void
 gimp_procedure_extension_ready (GimpProcedure *procedure)
 {
+  GimpPlugIn *plug_in;
+
   g_return_if_fail (GIMP_IS_PROCEDURE (procedure));
   g_return_if_fail (procedure->priv->proc_type == GIMP_EXTENSION);
 
-  _gimp_procedure_extension_ready (procedure);
+  plug_in = gimp_procedure_get_plug_in (procedure);
+
+  if (! gp_extension_ack_write (_gimp_plug_in_get_write_channel (plug_in),
+                                plug_in))
+    gimp_quit ();
 }
 
 
diff --git a/libgimp/gimpprocedure.h b/libgimp/gimpprocedure.h
index fb83c33bfd..4de5c72b97 100644
--- a/libgimp/gimpprocedure.h
+++ b/libgimp/gimpprocedure.h
@@ -71,8 +71,11 @@ struct _GimpProcedureClass
 {
   GObjectClass parent_class;
 
-  GimpValueArray * (* run) (GimpProcedure        *procedure,
-                            const GimpValueArray *args);
+  void             (* install)   (GimpProcedure        *procedure);
+  void             (* uninstall) (GimpProcedure        *procedure);
+
+  GimpValueArray * (* run)       (GimpProcedure        *procedure,
+                                  const GimpValueArray *args);
 
   /* Padding for future expansion */
   void (*_gimp_reserved1) (void);
diff --git a/libgimp/gimpsaveprocedure.c b/libgimp/gimpsaveprocedure.c
new file mode 100644
index 0000000000..1eb7380145
--- /dev/null
+++ b/libgimp/gimpsaveprocedure.c
@@ -0,0 +1,217 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpsaveprocedure.c
+ * Copyright (C) 2019 Michael Natterer <mitch gimp org>
+ *
+ * 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 "gimp.h"
+#include "gimpsaveprocedure.h"
+
+
+struct _GimpSaveProcedurePrivate
+{
+  GimpSaveFunc    run_func;
+  gpointer        run_data;
+  GDestroyNotify  run_data_destroy;
+};
+
+
+static void   gimp_save_procedure_constructed (GObject              *object);
+static void   gimp_save_procedure_finalize    (GObject              *object);
+
+static void   gimp_save_procedure_install     (GimpProcedure        *procedure);
+static GimpValueArray *
+              gimp_save_procedure_run         (GimpProcedure        *procedure,
+                                               const GimpValueArray *args);
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (GimpSaveProcedure, gimp_save_procedure,
+                            GIMP_TYPE_FILE_PROCEDURE)
+
+#define parent_class gimp_save_procedure_parent_class
+
+
+static void
+gimp_save_procedure_class_init (GimpSaveProcedureClass *klass)
+{
+  GObjectClass       *object_class    = G_OBJECT_CLASS (klass);
+  GimpProcedureClass *procedure_class = GIMP_PROCEDURE_CLASS (klass);
+
+  object_class->constructed  = gimp_save_procedure_constructed;
+  object_class->finalize     = gimp_save_procedure_finalize;
+
+  procedure_class->install   = gimp_save_procedure_install;
+  procedure_class->run       = gimp_save_procedure_run;
+}
+
+static void
+gimp_save_procedure_init (GimpSaveProcedure *procedure)
+{
+  procedure->priv = gimp_save_procedure_get_instance_private (procedure);
+}
+
+static void
+gimp_save_procedure_constructed (GObject *object)
+{
+  GimpProcedure *procedure = GIMP_PROCEDURE (object);
+
+  G_OBJECT_CLASS (parent_class)->constructed (object);
+
+  gimp_procedure_add_argument (procedure,
+                               gimp_param_spec_image_id ("image",
+                                                         "Image",
+                                                         "The image to save",
+                                                         FALSE,
+                                                         G_PARAM_READWRITE));
+  gimp_procedure_add_argument (procedure,
+                               gimp_param_spec_drawable_id ("drawable",
+                                                            "Drawable",
+                                                            "The drawable "
+                                                            "to save",
+                                                            FALSE,
+                                                            G_PARAM_READWRITE));
+  gimp_procedure_add_argument (procedure,
+                               gimp_param_spec_string ("uri",
+                                                       "URI",
+                                                       "The URI of the file "
+                                                       "to save to",
+                                                       FALSE, FALSE, TRUE,
+                                                       NULL,
+                                                       GIMP_PARAM_READWRITE));
+  gimp_procedure_add_argument (procedure,
+                               gimp_param_spec_string ("raw-uri",
+                                                       "Raw URI",
+                                                       "The URI of the file "
+                                                       "to save to",
+                                                       FALSE, FALSE, TRUE,
+                                                       NULL,
+                                                       GIMP_PARAM_READWRITE));
+}
+
+static void
+gimp_save_procedure_finalize (GObject *object)
+{
+  GimpSaveProcedure *procedure = GIMP_SAVE_PROCEDURE (object);
+
+  if (procedure->priv->run_data_destroy)
+    procedure->priv->run_data_destroy (procedure->priv->run_data);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_save_procedure_install (GimpProcedure *procedure)
+{
+  GimpFileProcedure *file_proc = GIMP_FILE_PROCEDURE (procedure);
+  const gchar       *mime_types;
+  gint               priority;
+
+  GIMP_PROCEDURE_CLASS (parent_class)->install (procedure);
+
+  gimp_register_save_handler (gimp_procedure_get_name (procedure),
+                              gimp_file_procedure_get_extensions (file_proc),
+                              gimp_file_procedure_get_prefixes (file_proc));
+
+  gimp_register_file_handler_uri (gimp_procedure_get_name (procedure));
+
+  mime_types = gimp_file_procedure_get_mime_types (file_proc);
+  if (mime_types)
+    gimp_register_file_handler_mime (gimp_procedure_get_name (procedure),
+                                     mime_types);
+
+  priority = gimp_file_procedure_get_priority (file_proc);
+  if (priority != 0)
+    gimp_register_file_handler_priority (gimp_procedure_get_name (procedure),
+                                         priority);
+}
+
+static GimpValueArray *
+gimp_save_procedure_run (GimpProcedure        *procedure,
+                         const GimpValueArray *args)
+{
+  GimpSaveProcedure *save_proc = GIMP_SAVE_PROCEDURE (procedure);
+  GimpValueArray    *remaining;
+  GimpValueArray    *return_values;
+  GimpRunMode        run_mode;
+  gint32             image_id;
+  gint32             drawable_id;
+  const gchar       *uri;
+  GFile             *file;
+  gint               i;
+
+  run_mode    = g_value_get_enum           (gimp_value_array_index (args, 0));
+  image_id    = gimp_value_get_image_id    (gimp_value_array_index (args, 1));
+  drawable_id = gimp_value_get_drawable_id (gimp_value_array_index (args, 2));
+  uri         = g_value_get_string         (gimp_value_array_index (args, 3));
+  /* raw_uri  = g_value_get_string         (gimp_value_array_index (args, 4)); */
+
+  file = g_file_new_for_uri (uri);
+
+  remaining = gimp_value_array_new (gimp_value_array_length (args) - 5);
+
+  for (i = 5; i < gimp_value_array_length (args); i++)
+    {
+      GValue *value = gimp_value_array_index (args, i);
+
+      gimp_value_array_append (remaining, value);
+    }
+
+  return_values = save_proc->priv->run_func (procedure,
+                                             run_mode,
+                                             image_id, drawable_id,
+                                             file,
+                                             remaining,
+                                             save_proc->priv->run_data);
+
+  gimp_value_array_unref (remaining);
+  g_object_unref (file);
+
+  return return_values;
+}
+
+
+/*  public functions  */
+
+GimpProcedure  *
+gimp_save_procedure_new (GimpPlugIn      *plug_in,
+                         const gchar     *name,
+                         GimpPDBProcType  proc_type,
+                         GimpSaveFunc     run_func,
+                         gpointer         run_data,
+                         GDestroyNotify   run_data_destroy)
+{
+  GimpSaveProcedure *procedure;
+
+  g_return_val_if_fail (GIMP_IS_PLUG_IN (plug_in), NULL);
+  g_return_val_if_fail (gimp_is_canonical_identifier (name), NULL);
+  g_return_val_if_fail (proc_type != GIMP_INTERNAL, NULL);
+  g_return_val_if_fail (run_func != NULL, NULL);
+
+  procedure = g_object_new (GIMP_TYPE_SAVE_PROCEDURE,
+                            "plug-in",        plug_in,
+                            "name",           name,
+                            "procedure-type", proc_type,
+                            NULL);
+
+  procedure->priv->run_func         = run_func;
+  procedure->priv->run_data         = run_data;
+  procedure->priv->run_data_destroy = run_data_destroy;
+
+  return GIMP_PROCEDURE (procedure);
+}
diff --git a/libgimp/gimpsaveprocedure.h b/libgimp/gimpsaveprocedure.h
new file mode 100644
index 0000000000..2755487cc1
--- /dev/null
+++ b/libgimp/gimpsaveprocedure.h
@@ -0,0 +1,95 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpsaveprocedure.h
+ * Copyright (C) 2019 Michael Natterer <mitch gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_SAVE_PROCEDURE_H__
+#define __GIMP_SAVE_PROCEDURE_H__
+
+#include <libgimp/gimpfileprocedure.h>
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+/**
+ * GimpSaveFunc:
+ * @procedure:   the #GimpProcedure that runs.
+ * @run_mode:    the #GimpRunMode.
+ * @image_id:    the image to save.
+ * @drawable_id: the drawable to save.
+ * @file:        the #GFile to save to.
+ * @args:        the @procedure's remaining arguments.
+ * @run_data:    the run_data given in gimp_save_procedure_new().
+ *
+ * The save function is run during the lifetime of the GIMP session,
+ * each time a plug-in save procedure is called.
+ *
+ * Returns: (transfer full): the @procedure's return values.
+ *
+ * Since: 3.0
+ **/
+typedef GimpValueArray * (* GimpSaveFunc) (GimpProcedure        *procedure,
+                                           GimpRunMode           run_mode,
+                                           gint32                image_id,
+                                           gint32                drawable_id,
+                                           GFile                *file,
+                                           const GimpValueArray *args,
+                                           gpointer              run_data);
+
+
+#define GIMP_TYPE_SAVE_PROCEDURE            (gimp_save_procedure_get_type ())
+#define GIMP_SAVE_PROCEDURE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_SAVE_PROCEDURE, 
GimpSaveProcedure))
+#define GIMP_SAVE_PROCEDURE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_SAVE_PROCEDURE, 
GimpSaveProcedureClass))
+#define GIMP_IS_SAVE_PROCEDURE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_SAVE_PROCEDURE))
+#define GIMP_IS_SAVE_PROCEDURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_SAVE_PROCEDURE))
+#define GIMP_SAVE_PROCEDURE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_SAVE_PROCEDURE, 
GimpSaveProcedureClass))
+
+
+typedef struct _GimpSaveProcedure        GimpSaveProcedure;
+typedef struct _GimpSaveProcedureClass   GimpSaveProcedureClass;
+typedef struct _GimpSaveProcedurePrivate GimpSaveProcedurePrivate;
+
+struct _GimpSaveProcedure
+{
+  GimpFileProcedure         parent_instance;
+
+  GimpSaveProcedurePrivate *priv;
+};
+
+struct _GimpSaveProcedureClass
+{
+  GimpFileProcedureClass parent_class;
+};
+
+
+GType           gimp_save_procedure_get_type (void) G_GNUC_CONST;
+
+GimpProcedure * gimp_save_procedure_new      (GimpPlugIn      *plug_in,
+                                              const gchar     *name,
+                                              GimpPDBProcType  proc_type,
+                                              GimpSaveFunc     run_func,
+                                              gpointer         run_data,
+                                              GDestroyNotify   run_data_destroy);
+
+
+G_END_DECLS
+
+#endif  /*  __GIMP_SAVE_PROCEDURE_H__  */


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