[gimp] app: temporarily move GimpLineArt ownership to context when bucket…



commit 0db35973c819abe5fd0f3d1425f9de5eb54929dc
Author: Jehan <jehan girinstud io>
Date:   Tue Feb 8 00:30:15 2022 +0100

    app: temporarily move GimpLineArt ownership to context when bucket…
    
    … fill tool finalizes.
    
    The idea is that you may want to quickly switch tool to do something and
    back to the bucket fill for line art selection. If the input drawable(s)
    did not change, the previously computed data is still valid, so let's
    hang on the line art object a little longer.
    Since we are resetting the input when we get back, we would still
    recompute anyway *if needed*, and the line art object does follow
    changes on the input pickable so we would not get any deprecated data
    anyway. Still we move around ownership a tiny bit to optimize for
    common case of tool switching.
    
    In order not to keep forever this data (buffer and distmap in
    particular) forever just because one tried the line art once, I add a
    timer to free it after a few minutes.
    
    Moreover it will be useful for other cases, such as being able to share
    the same line art object with the fuzzy select tool (if we end up adding
    the line art option there). In a coming commit, the usage will be even
    more obvious for use case where you want to edit the filled area with
    other paint tools, then back to bucket fill while not touching the line
    art source layer.

 app/core/gimpcontext.c         | 78 ++++++++++++++++++++++++++++++++++++++++++
 app/core/gimpcontext.h         |  8 +++++
 app/tools/gimpbucketfilltool.c | 55 ++++++++++++++++++++---------
 3 files changed, 124 insertions(+), 17 deletions(-)
---
diff --git a/app/core/gimpcontext.c b/app/core/gimpcontext.c
index 86ea8c22c9..7b3420f43b 100644
--- a/app/core/gimpcontext.c
+++ b/app/core/gimpcontext.c
@@ -44,6 +44,7 @@
 #include "gimpimagefile.h"
 #include "gimpgradient.h"
 #include "gimpimage.h"
+#include "gimplineart.h"
 #include "gimpmybrush.h"
 #include "gimppaintinfo.h"
 #include "gimppalette.h"
@@ -287,6 +288,10 @@ static void gimp_context_real_set_template   (GimpContext      *context,
                                               GimpTemplate     *template);
 
 
+/*  line art  */
+static gboolean gimp_context_free_line_art   (GimpContext      *context);
+
+
 /*  utilities  */
 static gpointer gimp_context_find_object     (GimpContext      *context,
                                               GimpContainer    *container,
@@ -816,6 +821,9 @@ gimp_context_init (GimpContext *context)
 
   context->template        = NULL;
   context->template_name   = NULL;
+
+  context->line_art            = NULL;
+  context->line_art_timeout_id = 0;
 }
 
 static void
@@ -1012,6 +1020,8 @@ gimp_context_finalize (GObject *object)
   g_clear_pointer (&context->imagefile_name,   g_free);
   g_clear_pointer (&context->template_name,    g_free);
 
+  g_clear_object (&context->line_art);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -3784,6 +3794,74 @@ gimp_context_real_set_template (GimpContext  *context,
 }
 
 
+/*****************************************************************************/
+/*  Line Art  ****************************************************************/
+
+GimpLineArt *
+gimp_context_take_line_art (GimpContext *context)
+{
+  GimpLineArt *line_art;
+
+  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
+
+  if (context->line_art)
+    {
+      g_source_remove (context->line_art_timeout_id);
+      context->line_art_timeout_id = 0;
+
+      line_art = context->line_art;
+      context->line_art = NULL;
+    }
+  else
+    {
+      line_art = gimp_line_art_new ();
+    }
+
+  return line_art;
+}
+
+/*
+ * gimp_context_store_line_art:
+ * @context:
+ * @line_art:
+ *
+ * The @context takes ownership of @line_art until the next time it is
+ * requested with gimp_context_take_line_art() or until 3 minutes have
+ * passed.
+ * This function allows to temporarily store the computed line art data
+ * in case it is needed very soon again, so that not to free and
+ * recompute all the time the data when quickly switching tools.
+ */
+void
+gimp_context_store_line_art (GimpContext *context,
+                             GimpLineArt *line_art)
+{
+  g_return_if_fail (GIMP_IS_CONTEXT (context));
+  g_return_if_fail (GIMP_IS_LINE_ART (line_art));
+
+  if (context->line_art)
+    {
+      g_source_remove (context->line_art_timeout_id);
+      context->line_art_timeout_id = 0;
+    }
+
+  context->line_art            = line_art;
+  context->line_art_timeout_id = g_timeout_add (180000,
+                                                (GSourceFunc) gimp_context_free_line_art,
+                                                context);
+}
+
+static gboolean
+gimp_context_free_line_art (GimpContext *context)
+{
+  g_clear_object (&context->line_art);
+
+  context->line_art_timeout_id = 0;
+
+  return G_SOURCE_REMOVE;
+}
+
+
 /*****************************************************************************/
 /*  utility functions  *******************************************************/
 
diff --git a/app/core/gimpcontext.h b/app/core/gimpcontext.h
index 82ff26a752..260d1b1b89 100644
--- a/app/core/gimpcontext.h
+++ b/app/core/gimpcontext.h
@@ -102,6 +102,9 @@ struct _GimpContext
 
   GimpTemplate         *template;
   gchar                *template_name;
+
+  GimpLineArt          *line_art;
+  guint                 line_art_timeout_id;
 };
 
 struct _GimpContextClass
@@ -356,5 +359,10 @@ void             gimp_context_set_template        (GimpContext     *context,
                                                    GimpTemplate    *template);
 void             gimp_context_template_changed    (GimpContext     *context);
 
+/*  line art  */
+GimpLineArt    * gimp_context_take_line_art       (GimpContext     *context);
+void             gimp_context_store_line_art      (GimpContext     *context,
+                                                   GimpLineArt     *line_art);
+
 
 #endif /* __GIMP_CONTEXT_H__ */
diff --git a/app/tools/gimpbucketfilltool.c b/app/tools/gimpbucketfilltool.c
index 18c6662ffb..53a6b01b20 100644
--- a/app/tools/gimpbucketfilltool.c
+++ b/app/tools/gimpbucketfilltool.c
@@ -70,6 +70,7 @@ struct _GimpBucketFillToolPrivate
   GimpLineArt        *line_art;
   GimpImage          *line_art_image;
   GimpDisplayShell   *line_art_shell;
+  GList              *line_art_bindings;
 
   /* For preview */
   GeglNode           *graph;
@@ -215,6 +216,8 @@ gimp_bucket_fill_tool_constructed (GObject *object)
   GimpBucketFillOptions *options     = GIMP_BUCKET_FILL_TOOL_GET_OPTIONS (tool);
   Gimp                  *gimp        = GIMP_CONTEXT (options)->gimp;
   GimpContext           *context     = gimp_get_user_context (gimp);
+  GList                 *bindings    = NULL;
+  GBinding              *binding;
   GimpLineArt           *line_art;
 
   G_OBJECT_CLASS (parent_class)->constructed (object);
@@ -223,22 +226,27 @@ gimp_bucket_fill_tool_constructed (GObject *object)
                                      options->fill_area == GIMP_BUCKET_FILL_LINE_ART ?
                                      GIMP_MOTION_MODE_EXACT : GIMP_MOTION_MODE_COMPRESS);
 
-  line_art = gimp_line_art_new ();
-  g_object_bind_property (options,  "fill-transparent",
-                          line_art, "select-transparent",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-  g_object_bind_property (options,  "line-art-threshold",
-                          line_art, "threshold",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-  g_object_bind_property (options,  "line-art-max-grow",
-                          line_art, "max-grow",
-                          G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
-  g_object_bind_property (options,  "line-art-max-gap-length",
-                          line_art, "spline-max-length",
-                          G_BINDING_SYNC_CREATE | G_BINDING_DEFAULT);
-  g_object_bind_property (options,  "line-art-max-gap-length",
-                          line_art, "segment-max-length",
-                          G_BINDING_SYNC_CREATE | G_BINDING_DEFAULT);
+  line_art = gimp_context_take_line_art (context);
+  binding = g_object_bind_property (options,  "fill-transparent",
+                                    line_art, "select-transparent",
+                                    G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+  bindings = g_list_prepend (bindings, binding);
+  binding = g_object_bind_property (options,  "line-art-threshold",
+                                    line_art, "threshold",
+                                    G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+  bindings = g_list_prepend (bindings, binding);
+  binding = g_object_bind_property (options,  "line-art-max-grow",
+                                    line_art, "max-grow",
+                                    G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+  bindings = g_list_prepend (bindings, binding);
+  binding = g_object_bind_property (options,  "line-art-max-gap-length",
+                                    line_art, "spline-max-length",
+                                    G_BINDING_SYNC_CREATE | G_BINDING_DEFAULT);
+  bindings = g_list_prepend (bindings, binding);
+  binding = g_object_bind_property (options,  "line-art-max-gap-length",
+                                    line_art, "segment-max-length",
+                                    G_BINDING_SYNC_CREATE | G_BINDING_DEFAULT);
+  bindings = g_list_prepend (bindings, binding);
   g_signal_connect_swapped (line_art, "computing-start",
                             G_CALLBACK (gimp_bucket_fill_tool_line_art_computing_start),
                             tool);
@@ -247,6 +255,7 @@ gimp_bucket_fill_tool_constructed (GObject *object)
                             tool);
   gimp_line_art_bind_gap_length (line_art, TRUE);
   bucket_tool->priv->line_art = line_art;
+  bucket_tool->priv->line_art_bindings = bindings;
 
   gimp_bucket_fill_tool_reset_line_art (bucket_tool);
 
@@ -284,7 +293,19 @@ gimp_bucket_fill_tool_finalize (GObject *object)
         tool);
       tool->priv->line_art_shell = NULL;
     }
-  g_clear_object (&tool->priv->line_art);
+
+  /* We don't free the line art object, but gives temporary ownership to
+   * the user context which will free it if a timer runs out.
+   *
+   * This way, we allow people to not suffer a new computational delay
+   * if for instance they just needed to switch tools for a few seconds
+   * while the source layer stays the same.
+   */
+  g_signal_handlers_disconnect_by_data (tool->priv->line_art, tool);
+  g_list_free_full (tool->priv->line_art_bindings,
+                    (GDestroyNotify) g_binding_unbind);
+  gimp_context_store_line_art (context, tool->priv->line_art);
+  tool->priv->line_art = NULL;
 
   g_signal_handlers_disconnect_by_data (options, tool);
   g_signal_handlers_disconnect_by_data (context, tool);


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