[gimp] app: make sure name references to GimpData objects are serialized correctly



commit 9be16e00bccc3f5c8ee47b998ab10df04d3f86e1
Author: Michael Natterer <mitch gimp org>
Date:   Thu Feb 26 22:17:45 2015 +0100

    app: make sure name references to GimpData objects are serialized correctly
    
    They were also serialized correctly before, but only because many
    GimpData objects were (bogusly) always dirty after loading, which
    caused them to always be written do disk on exit. This commit fixes
    this problem and updates by-name references explicitly as things are
    renamed, instead of relying on bugs.
    
    Add gimp_data_factory_data_clean() which clears the dirty flags from
    all a factory's objects. Call the new function on all factories at the
    end of gimp_restore(), when all data has been loaded. This might be
    total overkill, but ensures that everything is clean in the beginning.
    
    Add new signal GimpContext::prop_name_changed() which is emitted when
    any of the context's object properties (brush, gradient etc) is
    renamed.
    
    In GimpToolPreset, connect to the new signal and dirty the preset if a
    relevant object propery was renamed, making sure the preset is saved
    to disk later. Also optmize updates quite a bit by ignoring
    notifications on tool option properties that are irrelevant to the
    preset.
    
    This might or might not address the issues discussed in bug #739487.

 app/core/gimp.c            |   11 ++++++
 app/core/gimpcontext.c     |   48 +++++++++++++++++++++++++++++
 app/core/gimpcontext.h     |    3 ++
 app/core/gimpdatafactory.c |   73 +++++++++++++++++++++++++++++---------------
 app/core/gimpdatafactory.h |    1 +
 app/core/gimptoolpreset.c  |   44 ++++++++++++++++++++++++++-
 6 files changed, 154 insertions(+), 26 deletions(-)
---
diff --git a/app/core/gimp.c b/app/core/gimp.c
index d1e00a6..7571f69 100644
--- a/app/core/gimp.c
+++ b/app/core/gimp.c
@@ -1101,6 +1101,17 @@ gimp_restore (Gimp               *gimp,
                                 gimp_data_factory_get_container (gimp->tool_preset_factory));
 
   g_signal_emit (gimp, gimp_signals[RESTORE], 0, status_callback);
+
+  /* when done, make sure everything is clean, to clean out dirty
+   * states from data object which reference each other and got
+   * dirtied by loading the referenced object
+   */
+  gimp_data_factory_data_clean (gimp->brush_factory);
+  gimp_data_factory_data_clean (gimp->dynamics_factory);
+  gimp_data_factory_data_clean (gimp->pattern_factory);
+  gimp_data_factory_data_clean (gimp->palette_factory);
+  gimp_data_factory_data_clean (gimp->gradient_factory);
+  gimp_data_factory_data_clean (gimp->tool_preset_factory);
 }
 
 /**
diff --git a/app/core/gimpcontext.c b/app/core/gimpcontext.c
index f962f9c..02e6f1f 100644
--- a/app/core/gimpcontext.c
+++ b/app/core/gimpcontext.c
@@ -301,6 +301,7 @@ enum
   BUFFER_CHANGED,
   IMAGEFILE_CHANGED,
   TEMPLATE_CHANGED,
+  PROP_NAME_CHANGED,
   LAST_SIGNAL
 };
 
@@ -553,6 +554,16 @@ gimp_context_class_init (GimpContextClass *klass)
                   G_TYPE_NONE, 1,
                   GIMP_TYPE_TEMPLATE);
 
+  gimp_context_signals[PROP_NAME_CHANGED] =
+    g_signal_new ("prop-name-changed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (GimpContextClass, prop_name_changed),
+                  NULL, NULL,
+                  gimp_marshal_VOID__INT,
+                  G_TYPE_NONE, 1,
+                  G_TYPE_INT);
+
   object_class->constructed      = gimp_context_constructed;
   object_class->set_property     = gimp_context_set_property;
   object_class->get_property     = gimp_context_get_property;
@@ -579,6 +590,7 @@ gimp_context_class_init (GimpContextClass *klass)
   klass->buffer_changed          = NULL;
   klass->imagefile_changed       = NULL;
   klass->template_changed        = NULL;
+  klass->prop_name_changed       = NULL;
 
   gimp_context_prop_types[GIMP_CONTEXT_PROP_IMAGE]       = GIMP_TYPE_IMAGE;
   gimp_context_prop_types[GIMP_CONTEXT_PROP_TOOL]        = GIMP_TYPE_TOOL_INFO;
@@ -2013,6 +2025,9 @@ gimp_context_tool_dirty (GimpToolInfo *tool_info,
 {
   g_free (context->tool_name);
   context->tool_name = g_strdup (gimp_object_get_name (tool_info));
+
+  g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0,
+                 GIMP_CONTEXT_PROP_TOOL);
 }
 
 /*  the global tool list is there again after refresh  */
@@ -2137,6 +2152,9 @@ gimp_context_paint_info_dirty (GimpPaintInfo *paint_info,
 {
   g_free (context->paint_name);
   context->paint_name = g_strdup (gimp_object_get_name (paint_info));
+
+  g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0,
+                 GIMP_CONTEXT_PROP_PAINT_INFO);
 }
 
 /*  the global paint info list is there again after refresh  */
@@ -2548,6 +2566,9 @@ gimp_context_brush_dirty (GimpBrush   *brush,
 {
   g_free (context->brush_name);
   context->brush_name = g_strdup (gimp_object_get_name (brush));
+
+  g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0,
+                 GIMP_CONTEXT_PROP_BRUSH);
 }
 
 /*  the global brush list is there again after refresh  */
@@ -2668,6 +2689,9 @@ gimp_context_dynamics_dirty (GimpDynamics *dynamics,
 {
   g_free (context->dynamics_name);
   context->dynamics_name = g_strdup (gimp_object_get_name (dynamics));
+
+  g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0,
+                 GIMP_CONTEXT_PROP_DYNAMICS);
 }
 
 static void
@@ -2786,6 +2810,9 @@ gimp_context_pattern_dirty (GimpPattern *pattern,
 {
   g_free (context->pattern_name);
   context->pattern_name = g_strdup (gimp_object_get_name (pattern));
+
+  g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0,
+                 GIMP_CONTEXT_PROP_PATTERN);
 }
 
 /*  the global pattern list is there again after refresh  */
@@ -2906,6 +2933,9 @@ gimp_context_gradient_dirty (GimpGradient *gradient,
 {
   g_free (context->gradient_name);
   context->gradient_name = g_strdup (gimp_object_get_name (gradient));
+
+  g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0,
+                 GIMP_CONTEXT_PROP_GRADIENT);
 }
 
 /*  the global gradient list is there again after refresh  */
@@ -3026,6 +3056,9 @@ gimp_context_palette_dirty (GimpPalette *palette,
 {
   g_free (context->palette_name);
   context->palette_name = g_strdup (gimp_object_get_name (palette));
+
+  g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0,
+                 GIMP_CONTEXT_PROP_PALETTE);
 }
 
 /*  the global palette list is there again after refresh  */
@@ -3146,6 +3179,9 @@ gimp_context_tool_preset_dirty (GimpToolPreset *tool_preset,
 {
   g_free (context->tool_preset_name);
   context->tool_preset_name = g_strdup (gimp_object_get_name (tool_preset));
+
+  g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0,
+                 GIMP_CONTEXT_PROP_TOOL_PRESET);
 }
 
 static void
@@ -3292,6 +3328,9 @@ gimp_context_font_dirty (GimpFont    *font,
 {
   g_free (context->font_name);
   context->font_name = g_strdup (gimp_object_get_name (font));
+
+  g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0,
+                 GIMP_CONTEXT_PROP_FONT);
 }
 
 /*  the global font list is there again after refresh  */
@@ -3412,6 +3451,9 @@ gimp_context_buffer_dirty (GimpBuffer  *buffer,
 {
   g_free (context->buffer_name);
   context->buffer_name = g_strdup (gimp_object_get_name (buffer));
+
+  g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0,
+                 GIMP_CONTEXT_PROP_BUFFER);
 }
 
 /*  the global buffer list is there again after refresh  */
@@ -3535,6 +3577,9 @@ gimp_context_imagefile_dirty (GimpImagefile *imagefile,
 {
   g_free (context->imagefile_name);
   context->imagefile_name = g_strdup (gimp_object_get_name (imagefile));
+
+  g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0,
+                 GIMP_CONTEXT_PROP_IMAGEFILE);
 }
 
 /*  the global imagefile list is there again after refresh  */
@@ -3658,6 +3703,9 @@ gimp_context_template_dirty (GimpTemplate *template,
 {
   g_free (context->template_name);
   context->template_name = g_strdup (gimp_object_get_name (template));
+
+  g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0,
+                 GIMP_CONTEXT_PROP_TEMPLATE);
 }
 
 /*  the global template list is there again after refresh  */
diff --git a/app/core/gimpcontext.h b/app/core/gimpcontext.h
index 48623ee..0406a95 100644
--- a/app/core/gimpcontext.h
+++ b/app/core/gimpcontext.h
@@ -143,6 +143,9 @@ struct _GimpContextClass
                                GimpImagefile        *imagefile);
   void (* template_changed)   (GimpContext          *context,
                                GimpTemplate         *template);
+
+  void (* prop_name_changed)  (GimpContext          *context,
+                               GimpContextPropType   prop);
 };
 
 
diff --git a/app/core/gimpdatafactory.c b/app/core/gimpdatafactory.c
index 2351cae..81d1486 100644
--- a/app/core/gimpdatafactory.c
+++ b/app/core/gimpdatafactory.c
@@ -71,31 +71,36 @@ struct _GimpDataFactoryPriv
 };
 
 
-static void    gimp_data_factory_finalize       (GObject          *object);
-
-static gint64  gimp_data_factory_get_memsize    (GimpObject       *object,
-                                                 gint64           *gui_size);
-
-static void    gimp_data_factory_data_load      (GimpDataFactory  *factory,
-                                                 GimpContext      *context,
-                                                 GHashTable       *cache);
-
-static GFile * gimp_data_factory_get_save_dir   (GimpDataFactory  *factory,
-                                                 GError          **error);
-
-static void    gimp_data_factory_load_directory (GimpDataFactory  *factory,
-                                                 GimpContext      *context,
-                                                 GHashTable       *cache,
-                                                 gboolean          dir_writable,
-                                                 GFile            *directory,
-                                                 GFile            *top_directory);
-static void    gimp_data_factory_load_data      (GimpDataFactory  *factory,
-                                                 GimpContext      *context,
-                                                 GHashTable       *cache,
-                                                 gboolean          dir_writable,
-                                                 GFile            *file,
-                                                 guint64           mtime,
-                                                 GFile            *top_directory);
+static void    gimp_data_factory_finalize       (GObject             *object);
+
+static gint64  gimp_data_factory_get_memsize    (GimpObject          *object,
+                                                 gint64              *gui_size);
+
+static void    gimp_data_factory_data_foreach   (GimpDataFactory     *factory,
+                                                 gboolean             skip_internal,
+                                                 GimpDataForeachFunc  callback,
+                                                 gpointer             user_data);
+
+static void    gimp_data_factory_data_load      (GimpDataFactory     *factory,
+                                                 GimpContext         *context,
+                                                 GHashTable          *cache);
+
+static GFile * gimp_data_factory_get_save_dir   (GimpDataFactory     *factory,
+                                                 GError             **error);
+
+static void    gimp_data_factory_load_directory (GimpDataFactory     *factory,
+                                                 GimpContext         *context,
+                                                 GHashTable          *cache,
+                                                 gboolean             dir_writable,
+                                                 GFile               *directory,
+                                                 GFile               *top_directory);
+static void    gimp_data_factory_load_data      (GimpDataFactory     *factory,
+                                                 GimpContext         *context,
+                                                 GHashTable          *cache,
+                                                 gboolean             dir_writable,
+                                                 GFile               *file,
+                                                 guint64              mtime,
+                                                 GFile               *top_directory);
 
 
 G_DEFINE_TYPE (GimpDataFactory, gimp_data_factory, GIMP_TYPE_OBJECT)
@@ -252,6 +257,24 @@ gimp_data_factory_data_init (GimpDataFactory *factory,
 }
 
 static void
+gimp_data_factory_clean_cb (GimpDataFactory *factory,
+                            GimpData        *data,
+                            gpointer         user_data)
+{
+  if (gimp_data_is_dirty (data))
+    gimp_data_clean (data);
+}
+
+void
+gimp_data_factory_data_clean (GimpDataFactory *factory)
+{
+  g_return_if_fail (GIMP_IS_DATA_FACTORY (factory));
+
+  gimp_data_factory_data_foreach (factory, TRUE,
+                                  gimp_data_factory_clean_cb, NULL);
+}
+
+static void
 gimp_data_factory_refresh_cache_add (GimpDataFactory *factory,
                                      GimpData        *data,
                                      gpointer         user_data)
diff --git a/app/core/gimpdatafactory.h b/app/core/gimpdatafactory.h
index edc3f16..8456464 100644
--- a/app/core/gimpdatafactory.h
+++ b/app/core/gimpdatafactory.h
@@ -82,6 +82,7 @@ GimpDataFactory * gimp_data_factory_new      (Gimp                             *
 void            gimp_data_factory_data_init         (GimpDataFactory  *factory,
                                                      GimpContext      *context,
                                                      gboolean          no_data);
+void            gimp_data_factory_data_clean        (GimpDataFactory  *factory);
 void            gimp_data_factory_data_refresh      (GimpDataFactory  *factory,
                                                      GimpContext      *context);
 void            gimp_data_factory_data_save         (GimpDataFactory  *factory);
diff --git a/app/core/gimptoolpreset.c b/app/core/gimptoolpreset.c
index b4c6003..f47a89a 100644
--- a/app/core/gimptoolpreset.c
+++ b/app/core/gimptoolpreset.c
@@ -90,6 +90,9 @@ static void          gimp_tool_preset_set_options          (GimpToolPreset   *pr
 static void          gimp_tool_preset_options_notify       (GObject          *tool_options,
                                                             const GParamSpec *pspec,
                                                             GimpToolPreset   *preset);
+static void     gimp_tool_preset_options_prop_name_changed (GimpContext         *tool_options,
+                                                            GimpContextPropType  prop,
+                                                            GimpToolPreset      *preset);
 
 
 G_DEFINE_TYPE_WITH_CODE (GimpToolPreset, gimp_tool_preset, GIMP_TYPE_DATA,
@@ -449,6 +452,10 @@ gimp_tool_preset_set_options (GimpToolPreset  *preset,
                                             gimp_tool_preset_options_notify,
                                             preset);
 
+       g_signal_handlers_disconnect_by_func (preset->tool_options,
+                                             gimp_tool_preset_options_prop_name_changed,
+                                             preset);
+
       g_object_unref (preset->tool_options);
       preset->tool_options = NULL;
     }
@@ -491,6 +498,10 @@ gimp_tool_preset_set_options (GimpToolPreset  *preset,
       g_signal_connect (preset->tool_options, "notify",
                         G_CALLBACK (gimp_tool_preset_options_notify),
                         preset);
+
+      g_signal_connect (preset->tool_options, "prop-name-changed",
+                        G_CALLBACK (gimp_tool_preset_options_prop_name_changed),
+                        preset);
     }
 
   g_object_notify (G_OBJECT (preset), "tool-options");
@@ -501,7 +512,38 @@ gimp_tool_preset_options_notify (GObject          *tool_options,
                                  const GParamSpec *pspec,
                                  GimpToolPreset   *preset)
 {
-  g_object_notify (G_OBJECT (preset), "tool-options");
+  if (pspec->owner_type == GIMP_TYPE_CONTEXT)
+    {
+      GimpContextPropMask serialize_props;
+
+      serialize_props =
+        gimp_context_get_serialize_properties (GIMP_CONTEXT (tool_options));
+
+      if ((1 << pspec->param_id) & serialize_props)
+        {
+          g_object_notify (G_OBJECT (preset), "tool-options");
+        }
+    }
+  else if (pspec->flags & GIMP_CONFIG_PARAM_SERIALIZE)
+    {
+      g_object_notify (G_OBJECT (preset), "tool-options");
+    }
+}
+
+static void
+gimp_tool_preset_options_prop_name_changed (GimpContext         *tool_options,
+                                            GimpContextPropType  prop,
+                                            GimpToolPreset      *preset)
+{
+  GimpContextPropMask serialize_props;
+
+  serialize_props =
+    gimp_context_get_serialize_properties (GIMP_CONTEXT (preset->tool_options));
+
+  if ((1 << prop) & serialize_props)
+    {
+      g_object_notify (G_OBJECT (preset), "tool-options");
+    }
 }
 
 


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