[gimp] app: save custom gradient across sessions



commit e4440e3fdbb400b567fb573469ec0cb3b56e9e00
Author: Ell <ell_se yahoo com>
Date:   Sun Oct 29 09:50:28 2017 -0400

    app: save custom gradient across sessions
    
    Add a framework for saving and restoring internal data objects, in
    gimp-internal-data.c.  Internal data objects are saved in separate
    files under a new "internal-data" subdirectory of the user's gimp
    directory.  The internal data is saved, restored, and cleared
    together with the tool options.
    
    Use this to save and restore the custom gradient.  In the future,
    we might add similar writable internal data objects that we'd want
    to save.

 app/core/Makefile.am          |    2 +
 app/core/gimp-internal-data.c |  311 +++++++++++++++++++++++++++++++++++++++++
 app/core/gimp-internal-data.h |   34 +++++
 app/tools/gimp-tools.c        |   17 +++
 po/POTFILES.in                |    1 +
 5 files changed, 365 insertions(+), 0 deletions(-)
---
diff --git a/app/core/Makefile.am b/app/core/Makefile.am
index 70dbbaf..8e87169 100644
--- a/app/core/Makefile.am
+++ b/app/core/Makefile.am
@@ -44,6 +44,8 @@ libappcore_a_sources = \
        gimp-gradients.h                        \
        gimp-gui.c                              \
        gimp-gui.h                              \
+       gimp-internal-data.c                    \
+       gimp-internal-data.h                    \
        gimp-memsize.c                          \
        gimp-memsize.h                          \
        gimp-modules.c                          \
diff --git a/app/core/gimp-internal-data.c b/app/core/gimp-internal-data.c
new file mode 100644
index 0000000..a03f82d
--- /dev/null
+++ b/app/core/gimp-internal-data.c
@@ -0,0 +1,311 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995-2002 Spencer Kimball, Peter Mattis, and others
+ *
+ * gimp-internal-data.c
+ * Copyright (C) 2017 Ell
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gegl.h>
+
+#include "libgimpbase/gimpbase.h"
+
+#include "core-types.h"
+
+#include "gimp.h"
+#include "gimp-gradients.h"
+#include "gimp-internal-data.h"
+#include "gimpdata.h"
+#include "gimpdatafactory.h"
+#include "gimperror.h"
+#include "gimpgradient-load.h"
+
+#include "gimp-intl.h"
+
+
+#define GIMP_INTERNAL_DATA_DIRECTORY "internal-data"
+
+
+typedef GimpData * (* GimpDataGetFunc) (Gimp *gimp);
+
+
+typedef struct _GimpInternalDataFile GimpInternalDataFile;
+
+struct _GimpInternalDataFile
+{
+  const gchar      *name;
+  GimpDataGetFunc   get_func;
+  GimpDataLoadFunc  load_func;
+};
+
+
+/*  local function prototypes  */
+
+static gboolean   gimp_internal_data_create_directory (GError                     **error);
+
+static GFile    * gimp_internal_data_get_file         (const GimpInternalDataFile  *data_file);
+
+static gboolean   gimp_internal_data_load_data_file   (Gimp                        *gimp,
+                                                       const GimpInternalDataFile  *data_file,
+                                                       GError                     **error);
+static gboolean   gimp_internal_data_save_data_file   (Gimp                        *gimp,
+                                                       const GimpInternalDataFile  *data_file,
+                                                       GError                     **error);
+static gboolean   gimp_internal_data_delete_data_file (Gimp                        *gimp,
+                                                       const GimpInternalDataFile  *data_file,
+                                                       GError                     **error);
+
+/*  static variables  */
+
+static const GimpInternalDataFile internal_data_files[] = {
+  /* Custom gradient */
+  {
+    .name      = "custom" GIMP_GRADIENT_FILE_EXTENSION,
+    .get_func  = (GimpDataGetFunc) gimp_gradients_get_custom,
+    .load_func = gimp_gradient_load
+  }
+};
+
+
+/*  public functions  */
+
+gboolean
+gimp_internal_data_load (Gimp    *gimp,
+                         GError **error)
+{
+  gint i;
+
+  g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  for (i = 0; i < G_N_ELEMENTS (internal_data_files); i++)
+    {
+      const GimpInternalDataFile *data_file = &internal_data_files[i];
+
+      if (! gimp_internal_data_load_data_file (gimp, data_file, error))
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+gboolean
+gimp_internal_data_save (Gimp    *gimp,
+                         GError **error)
+{
+  gint i;
+
+  g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  if (! gimp_internal_data_create_directory (error))
+    return FALSE;
+
+  for (i = 0; i < G_N_ELEMENTS (internal_data_files); i++)
+    {
+      const GimpInternalDataFile *data_file = &internal_data_files[i];
+
+      if (! gimp_internal_data_save_data_file (gimp, data_file, error))
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+gboolean
+gimp_internal_data_clear (Gimp    *gimp,
+                          GError **error)
+{
+  gint i;
+
+  g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  for (i = 0; i < G_N_ELEMENTS (internal_data_files); i++)
+    {
+      const GimpInternalDataFile *data_file = &internal_data_files[i];
+
+      if (! gimp_internal_data_delete_data_file (gimp, data_file, error))
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+
+/*  private functions  */
+
+static gboolean
+gimp_internal_data_create_directory (GError **error)
+{
+  GFile    *directory;
+  GError   *my_error = NULL;
+  gboolean  success;
+
+  directory = gimp_directory_file (GIMP_INTERNAL_DATA_DIRECTORY, NULL);
+
+  success = g_file_make_directory (directory, NULL, &my_error);
+
+  g_object_unref (directory);
+
+  if (! success)
+    {
+      if (my_error->code == G_IO_ERROR_EXISTS)
+        {
+          g_clear_error (&my_error);
+          success = TRUE;
+        }
+      else
+        {
+          g_propagate_error (error, my_error);
+        }
+    }
+
+  return success;
+}
+
+static GFile *
+gimp_internal_data_get_file (const GimpInternalDataFile *data_file)
+{
+  return gimp_directory_file (GIMP_INTERNAL_DATA_DIRECTORY,
+                              data_file->name,
+                              NULL);
+}
+
+static gboolean
+gimp_internal_data_load_data_file (Gimp                        *gimp,
+                                   const GimpInternalDataFile  *data_file,
+                                   GError                     **error)
+{
+  GFile        *file;
+  GInputStream *input;
+  GimpData     *data;
+  GList        *list;
+  GError       *my_error = NULL;
+
+  file = gimp_internal_data_get_file (data_file);
+
+  if (gimp->be_verbose)
+    g_print ("Parsing '%s'\n", gimp_file_get_utf8_name (file));
+
+  input = G_INPUT_STREAM (g_file_read (file, NULL, &my_error));
+
+  if (! input)
+    {
+      g_object_unref (file);
+
+      if (my_error->code == G_IO_ERROR_NOT_FOUND)
+        {
+          g_clear_error (&my_error);
+          return TRUE;
+        }
+      else
+        {
+          g_propagate_error (error, my_error);
+          return FALSE;
+        }
+    }
+
+  list = data_file->load_func (gimp->user_context, file, input, error);
+
+  g_object_unref (input);
+  g_object_unref (file);
+
+  if (! list)
+    return FALSE;
+
+  data = data_file->get_func (gimp);
+
+  gimp_data_copy (data, GIMP_DATA (list->data));
+
+  g_list_free_full (list, g_object_unref);
+
+  return TRUE;
+}
+
+static gboolean
+gimp_internal_data_save_data_file (Gimp                        *gimp,
+                                   const GimpInternalDataFile  *data_file,
+                                   GError                     **error)
+{
+  GFile         *file;
+  GOutputStream *output;
+  GimpData      *data;
+  gboolean       success;
+
+  file = gimp_internal_data_get_file (data_file);
+
+  if (gimp->be_verbose)
+    g_print ("Writing '%s'\n", gimp_file_get_utf8_name (file));
+
+  output = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE,
+                                            G_FILE_CREATE_REPLACE_DESTINATION,
+                                            NULL, error));
+
+  g_object_unref (file);
+
+  if (! output)
+    return FALSE;
+
+  data = data_file->get_func (gimp);
+
+  /* we bypass gimp_data_save() and call the data's save() virtual function
+   * directly, since gimp_data_save() is a nop for internal data.
+   *
+   * FIXME:  we save the data whether it's dirty or not, since it might not
+   * exist on disk.  currently, we only use this for cheap data, such as
+   * gradients, so this is not a big concern, but if we save more expensive 
+   * data in the future, we should fix this.
+   */
+  g_assert (GIMP_DATA_GET_CLASS (data)->save);
+  success = GIMP_DATA_GET_CLASS (data)->save (data, output, error);
+
+  g_object_unref (output);
+
+  return success;
+}
+
+static gboolean
+gimp_internal_data_delete_data_file (Gimp                        *gimp,
+                                     const GimpInternalDataFile  *data_file,
+                                     GError                     **error)
+{
+  GFile    *file;
+  GError   *my_error = NULL;
+  gboolean  success  = TRUE;
+
+  file = gimp_internal_data_get_file (data_file);
+
+  if (gimp->be_verbose)
+    g_print ("Deleting '%s'\n", gimp_file_get_utf8_name (file));
+
+  if (! g_file_delete (file, NULL, &my_error) &&
+      my_error->code != G_IO_ERROR_NOT_FOUND)
+    {
+      success = FALSE;
+
+      g_set_error (error, GIMP_ERROR, GIMP_FAILED,
+                   _("Deleting \"%s\" failed: %s"),
+                   gimp_file_get_utf8_name (file), my_error->message);
+    }
+
+  g_clear_error (&my_error);
+  g_object_unref (file);
+
+  return success;
+}
diff --git a/app/core/gimp-internal-data.h b/app/core/gimp-internal-data.h
new file mode 100644
index 0000000..bdb7b6c
--- /dev/null
+++ b/app/core/gimp-internal-data.h
@@ -0,0 +1,34 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995-2002 Spencer Kimball, Peter Mattis, and others
+ *
+ * gimp-internal-data.h
+ * Copyright (C) 2017 Ell
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_INTERNAL_DATA__
+#define __GIMP_INTERNAL_DATA__
+
+
+gboolean   gimp_internal_data_load  (Gimp    *gimp,
+                                     GError **error);
+gboolean   gimp_internal_data_save  (Gimp    *gimp,
+                                     GError **error);
+
+gboolean   gimp_internal_data_clear (Gimp    *gimp,
+                                     GError **error);
+
+
+#endif /* __GIMP_INTERNAL_DATA__ */
diff --git a/app/tools/gimp-tools.c b/app/tools/gimp-tools.c
index 7c33c32..58086b5 100644
--- a/app/tools/gimp-tools.c
+++ b/app/tools/gimp-tools.c
@@ -30,6 +30,7 @@
 
 #include "core/gimp.h"
 #include "core/gimp-contexts.h"
+#include "core/gimp-internal-data.h"
 #include "core/gimplist.h"
 #include "core/gimptoolinfo.h"
 #include "core/gimptooloptions.h"
@@ -326,6 +327,12 @@ gimp_tools_restore (Gimp *gimp)
       g_clear_error (&error);
     }
 
+  if (! gimp_internal_data_load (gimp, &error))
+    {
+      gimp_message_literal (gimp, NULL, GIMP_MESSAGE_WARNING, error->message);
+      g_clear_error (&error);
+    }
+
   /*  make sure there is always a tool active, so broken config files
    *  can't leave us with no initial tool
    */
@@ -407,6 +414,13 @@ gimp_tools_save (Gimp     *gimp,
           g_clear_error (&error);
         }
 
+        if (! gimp_internal_data_save (gimp, &error))
+          {
+            gimp_message_literal (gimp, NULL, GIMP_MESSAGE_WARNING,
+                                  error->message);
+            g_clear_error (&error);
+          }
+
       gimp_tool_options_create_folder ();
 
       for (list = gimp_get_tool_info_iter (gimp);
@@ -454,6 +468,9 @@ gimp_tools_clear (Gimp    *gimp,
     success = gimp_contexts_clear (gimp, error);
 
   if (success)
+    success = gimp_internal_data_clear (gimp, error);
+
+  if (success)
     tool_options_deleted = TRUE;
 
   return success;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 961b14a..fe15ef3 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -106,6 +106,7 @@ app/core/gimp-data-factories.c
 app/core/gimp-edit.c
 app/core/gimp-gradients.c
 app/core/gimp-gui.c
+app/core/gimp-internal-data.c
 app/core/gimp-modules.c
 app/core/gimp-palettes.c
 app/core/gimp-tags.c


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