[gnome-shell] st-texture-cache: Cancel sliced image loading on target actor destroy



commit e3c5c9a2e7b5d2aca275a064b40d38145a16af95
Author: Marco Trevisan (Treviño) <mail 3v1n0 net>
Date:   Thu Nov 30 02:48:02 2017 +0100

    st-texture-cache: Cancel sliced image loading on target actor destroy
    
    It might happen that the target clutter actor that we return on call
    of st_texture_cache_load_sliced_image might be destroyed while the
    loading task is still running. To protect from this, let's connect
    to "destroy" signal and when this happens we use a cancellable to
    stop the task.
    
    This allows to safely reuse the return value of this function to
    cancel the execution and avoiding that load_callback is called
    even for a request that is not anymore under our control.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=765011

 src/st/st-texture-cache.c | 30 ++++++++++++++++++++++++++----
 1 file changed, 26 insertions(+), 4 deletions(-)
---
diff --git a/src/st/st-texture-cache.c b/src/st/st-texture-cache.c
index 90b85d0bd..ae5ac09cb 100644
--- a/src/st/st-texture-cache.c
+++ b/src/st/st-texture-cache.c
@@ -1080,6 +1080,7 @@ typedef struct {
   gint   paint_scale;
   gfloat resource_scale;
   ClutterActor *actor;
+  GCancellable *cancellable;
   GFunc load_callback;
   gpointer load_callback_data;
 } AsyncImageData;
@@ -1090,9 +1091,20 @@ on_data_destroy (gpointer data)
   AsyncImageData *d = (AsyncImageData *)data;
   g_object_unref (d->gfile);
   g_object_unref (d->actor);
+  g_object_unref (d->cancellable);
   g_free (d);
 }
 
+static void
+on_sliced_image_actor_destroyed (ClutterActor *actor,
+                                 gpointer data)
+{
+  GTask *task = data;
+  GCancellable *cancellable = g_task_get_cancellable (task);
+
+  g_cancellable_cancel (cancellable);
+}
+
 static void
 on_sliced_image_loaded (GObject *source_object,
                         GAsyncResult *res,
@@ -1103,7 +1115,7 @@ on_sliced_image_loaded (GObject *source_object,
   GTask *task = G_TASK (res);
   GList *list, *pixbufs;
 
-  if (g_task_had_error (task))
+  if (g_task_had_error (task) || g_cancellable_is_cancelled (data->cancellable))
     return;
 
   pixbufs = g_task_propagate_pointer (task, NULL);
@@ -1119,6 +1131,10 @@ on_sliced_image_loaded (GObject *source_object,
 
   g_list_free_full (pixbufs, g_object_unref);
 
+  g_signal_handlers_disconnect_by_func (data->actor,
+                                        on_sliced_image_actor_destroyed,
+                                        task);
+
   if (data->load_callback != NULL)
     data->load_callback (cache, data->load_callback_data);
 }
@@ -1157,7 +1173,7 @@ load_sliced_image (GTask        *result,
   gchar *buffer = NULL;
   gsize length;
 
-  g_assert (!cancellable);
+  g_assert (cancellable);
 
   data = task_data;
   g_assert (data);
@@ -1165,7 +1181,7 @@ load_sliced_image (GTask        *result,
   loader = gdk_pixbuf_loader_new ();
   g_signal_connect (loader, "size-prepared", G_CALLBACK (on_loader_size_prepared), data);
 
-  if (!g_file_load_contents (data->gfile, NULL, &buffer, &length, NULL, &error))
+  if (!g_file_load_contents (data->gfile, cancellable, &buffer, &length, NULL, &error))
     {
       g_warning ("Failed to open sliced image: %s", error->message);
       goto out;
@@ -1235,6 +1251,7 @@ st_texture_cache_load_sliced_image (StTextureCache *cache,
   AsyncImageData *data;
   GTask *result;
   ClutterActor *actor = clutter_actor_new ();
+  GCancellable *cancellable = g_cancellable_new ();
 
   g_return_val_if_fail (G_IS_FILE (file), NULL);
   g_assert (paint_scale > 0);
@@ -1247,11 +1264,16 @@ st_texture_cache_load_sliced_image (StTextureCache *cache,
   data->resource_scale = resource_scale;
   data->gfile = g_object_ref (file);
   data->actor = actor;
+  data->cancellable = cancellable;
   data->load_callback = load_callback;
   data->load_callback_data = user_data;
   g_object_ref (G_OBJECT (actor));
 
-  result = g_task_new (cache, NULL, on_sliced_image_loaded, data);
+  result = g_task_new (cache, cancellable, on_sliced_image_loaded, data);
+
+  g_signal_connect (actor, "destroy",
+                    G_CALLBACK (on_sliced_image_actor_destroyed), result);
+
   g_task_set_task_data (result, data, on_data_destroy);
   g_task_run_in_thread (result, load_sliced_image);
 


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