[gimp/gimp-2-10] app: allow waiting on idle asyncs



commit 24db85bef6bb8a81d601bb6570b01f16a83fbc3c
Author: Ell <ell_se yahoo com>
Date:   Sat Mar 14 12:41:46 2020 +0200

    app: allow waiting on idle asyncs
    
    In gimp_idle_run_async(), connect to the async's "waiting" signal,
    and run the async func in the context of the caller in response, to
    avoid blocking indefinitely.
    
    (cherry picked from commit 30f509c84dae06d612468a759bba90bb649a36a2)

 app/core/gimp-utils.c | 88 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 77 insertions(+), 11 deletions(-)
---
diff --git a/app/core/gimp-utils.c b/app/core/gimp-utils.c
index c171e5ce8d..d3df098126 100644
--- a/app/core/gimp-utils.c
+++ b/app/core/gimp-utils.c
@@ -884,6 +884,8 @@ gimp_g_list_compare (GList *list1,
 
 typedef struct
 {
+  gint              ref_count;
+
   GimpAsync        *async;
   gint              idle_id;
 
@@ -895,35 +897,92 @@ typedef struct
 static GimpIdleRunAsyncData *
 gimp_idle_run_async_data_new (void)
 {
-  return g_slice_new0 (GimpIdleRunAsyncData);
+  GimpIdleRunAsyncData *data;
+
+  data = g_slice_new0 (GimpIdleRunAsyncData);
+
+  data->ref_count = 1;
+
+  return data;
+}
+
+static void
+gimp_idle_run_async_data_inc_ref (GimpIdleRunAsyncData *data)
+{
+  data->ref_count++;
 }
 
 static void
-gimp_idle_run_async_data_free (GimpIdleRunAsyncData *data)
+gimp_idle_run_async_data_dec_ref (GimpIdleRunAsyncData *data)
 {
-  g_signal_handlers_disconnect_by_data (data->async, data);
+  data->ref_count--;
+
+  if (data->ref_count == 0)
+    {
+      g_signal_handlers_disconnect_by_data (data->async, data);
 
-  if (data->user_data && data->user_data_destroy_func)
-    data->user_data_destroy_func (data->user_data);
+      if (! gimp_async_is_stopped (data->async))
+        gimp_async_abort (data->async);
 
-  if (! gimp_async_is_stopped (data->async))
-    gimp_async_abort (data->async);
+      g_object_unref (data->async);
 
-  g_object_unref (data->async);
+      if (data->user_data && data->user_data_destroy_func)
+        data->user_data_destroy_func (data->user_data);
 
-  g_slice_free (GimpIdleRunAsyncData, data);
+      g_slice_free (GimpIdleRunAsyncData, data);
+    }
 }
 
 static void
 gimp_idle_run_async_cancel (GimpAsync            *async,
                             GimpIdleRunAsyncData *data)
 {
-  g_source_remove (data->idle_id);
+  gimp_idle_run_async_data_inc_ref (data);
+
+  if (data->idle_id)
+    {
+      g_source_remove (data->idle_id);
+
+      data->idle_id = 0;
+    }
+
+  gimp_idle_run_async_data_dec_ref (data);
+}
+
+static void
+gimp_idle_run_async_waiting (GimpAsync            *async,
+                             GimpIdleRunAsyncData *data)
+{
+  gimp_idle_run_async_data_inc_ref (data);
+
+  if (data->idle_id)
+    {
+      g_source_remove (data->idle_id);
+
+      data->idle_id = 0;
+    }
+
+  g_signal_handlers_block_by_func (data->async,
+                                   gimp_idle_run_async_cancel,
+                                   data);
+
+  while (! gimp_async_is_stopped (data->async))
+    data->func (data->async, data->user_data);
+
+  g_signal_handlers_unblock_by_func (data->async,
+                                     gimp_idle_run_async_cancel,
+                                     data);
+
+  data->user_data = NULL;
+
+  gimp_idle_run_async_data_dec_ref (data);
 }
 
 static gboolean
 gimp_idle_run_async_idle (GimpIdleRunAsyncData *data)
 {
+  gimp_idle_run_async_data_inc_ref (data);
+
   g_signal_handlers_block_by_func (data->async,
                                    gimp_idle_run_async_cancel,
                                    data);
@@ -938,9 +997,13 @@ gimp_idle_run_async_idle (GimpIdleRunAsyncData *data)
     {
       data->user_data = NULL;
 
+      gimp_idle_run_async_data_dec_ref (data);
+
       return G_SOURCE_REMOVE;
     }
 
+  gimp_idle_run_async_data_dec_ref (data);
+
   return G_SOURCE_CONTINUE;
 }
 
@@ -973,12 +1036,15 @@ gimp_idle_run_async_full (gint             priority,
   g_signal_connect (data->async, "cancel",
                     G_CALLBACK (gimp_idle_run_async_cancel),
                     data);
+  g_signal_connect (data->async, "waiting",
+                    G_CALLBACK (gimp_idle_run_async_waiting),
+                    data);
 
   data->idle_id = g_idle_add_full (
     priority,
     (GSourceFunc) gimp_idle_run_async_idle,
     data,
-    (GDestroyNotify) gimp_idle_run_async_data_free);
+    (GDestroyNotify) gimp_idle_run_async_data_dec_ref);
 
   return g_object_ref (data->async);
 }


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