From d8a9c8c3526980e576e8d61d033cd983562b07d3 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 1 Oct 2018 20:36:05 +0200 Subject: [PATCH] background: Add queue to load 4 pictures at a time We need to process the pictures sequentially rather than trying to thumbnail all of them in parallel. This commit adds a simple task queue from which 4 tasks at will be processed at the same time. Fixes #191 --- diff --git a/panels/background/bg-pictures-source.c b/panels/background/bg-pictures-source.c index 3a3027b..3b955bb 100644 --- a/panels/background/bg-pictures-source.c +++ b/panels/background/bg-pictures-source.c @@ -45,12 +45,26 @@ struct _BgPicturesSource CcBackgroundGriloMiner *grl_miner; + GQueue add_queue; + gint adds_running; + GFileMonitor *picture_dir_monitor; GFileMonitor *cache_dir_monitor; GHashTable *known_items; }; +#define MAX_PARALLEL_ADD 4 + +typedef struct { + BgPicturesSource *bg_source; + GFile *file; + gchar *content_type; + guint64 mtime; + GtkTreeRowReference **ret_row_ref; + GCancellable *cancellable; +} AddQueueData; + G_DEFINE_TYPE (BgPicturesSource, bg_pictures_source, BG_TYPE_SOURCE) const char * const content_types[] = { @@ -72,6 +86,86 @@ static char *bg_pictures_source_get_unique_filename (const char *uri); static void picture_opened_for_read (GObject *source_object, GAsyncResult *res, gpointer user_data); +static gboolean add_single_file_real (BgPicturesSource *bg_source, + GFile *file, + const gchar *content_type, + guint64 mtime, + GtkTreeRowReference **ret_row_ref); + +static void +add_queue_data_free (AddQueueData *data) +{ + g_clear_object (&data->file); + g_clear_object (&data->cancellable); + g_free (data->content_type); + g_free (data); +} + +static gboolean +add_single_file_idle (gpointer user_data) +{ + AddQueueData *data = (AddQueueData*) user_data; + + if (!g_cancellable_is_cancelled (data->cancellable)) + add_single_file_real (data->bg_source, data->file, data->content_type, + data->mtime, data->ret_row_ref); + add_queue_data_free (data); + + return FALSE; +} + +static void +ensure_add_processing (BgPicturesSource *bg_source) +{ + while (bg_source->adds_running < MAX_PARALLEL_ADD) + { + AddQueueData *data = g_queue_pop_head (&bg_source->add_queue); + + /* Nothing left to process */ + if (!data) + return; + + g_idle_add (add_single_file_idle, data); + + bg_source->adds_running += 1; + } +} + +static void +add_processing_finished (BgPicturesSource *bg_source) +{ + g_assert (bg_source->adds_running > 0); + + bg_source->adds_running -= 1; + + ensure_add_processing (bg_source); +} + +static gboolean +add_single_file (BgPicturesSource *bg_source, + GFile *file, + const gchar *content_type, + guint64 mtime, + GtkTreeRowReference **ret_row_ref) +{ + AddQueueData *data = g_new0 (AddQueueData, 1); + + data->bg_source = bg_source; + data->file = g_object_ref (file); + data->content_type = g_strdup (content_type); + data->mtime = mtime; + data->ret_row_ref = ret_row_ref; + data->cancellable = g_object_ref (bg_source->cancellable); + + g_queue_push_tail (&bg_source->add_queue, data); + + ensure_add_processing (bg_source); + + /* Just return TRUE. */ + return TRUE; +} + + static void bg_pictures_source_dispose (GObject *object) { @@ -83,6 +177,9 @@ bg_pictures_source_dispose (GObject *object) g_clear_object (&source->cancellable); } + g_queue_foreach (&source->add_queue, (GFunc) add_queue_data_free, NULL); + g_queue_clear (&source->add_queue); + g_clear_object (&source->grl_miner); G_OBJECT_CLASS (bg_pictures_source_parent_class)->dispose (object); @@ -206,6 +303,10 @@ picture_scaled (GObject *source_object, { g_warning ("Failed to load image: %s", error->message); remove_placeholder (BG_PICTURES_SOURCE (user_data), item); + + bg_source = BG_PICTURES_SOURCE (user_data); + add_processing_finished (bg_source); + } return; @@ -227,7 +328,9 @@ picture_scaled (GObject *source_object, { g_debug ("Ignored URL '%s' as it's a screenshot from gnome-screenshot", uri); remove_placeholder (BG_PICTURES_SOURCE (user_data), item); - return; + + add_processing_finished (bg_source); + return; } /* Process embedded orientation */ @@ -262,6 +365,8 @@ picture_scaled (GObject *source_object, GINT_TO_POINTER (TRUE)); g_clear_pointer (&surface, cairo_surface_destroy); + + add_processing_finished (bg_source); } static void @@ -286,6 +391,9 @@ picture_opened_for_read (GObject *source_object, g_autofree gchar *filename = g_file_get_path (G_FILE (source_object)); g_warning ("Failed to load picture '%s': %s", filename, error->message); remove_placeholder (BG_PICTURES_SOURCE (user_data), item); + + bg_source = BG_PICTURES_SOURCE (user_data); + add_processing_finished (bg_source); } return; @@ -339,6 +447,10 @@ picture_copied_for_read (GObject *source_object, uri = g_file_get_uri (thumbnail_file); g_warning ("Failed to download '%s': %s", uri, error->message); + + bg_source = BG_PICTURES_SOURCE (user_data); + add_processing_finished (bg_source); + return; } } @@ -378,10 +490,11 @@ bg_pictures_source_get_cache_file (void) } static gboolean -add_single_file (BgPicturesSource *bg_source, - GFile *file, - const gchar *content_type, - guint64 mtime) +add_single_file_real (BgPicturesSource *bg_source, + GFile *file, + const gchar *content_type, + guint64 mtime, + GtkTreeRowReference **ret_row_ref) { g_autoptr(CcBackgroundItem) item = NULL; CcBackgroundItemFlags flags = 0; @@ -480,6 +593,11 @@ add_single_file (BgPicturesSource *bg_source, retval = TRUE; out: + + /* Async processing is happening. */ + if (!retval) + add_processing_finished (bg_source); + return retval; } @@ -493,7 +611,7 @@ add_single_file_from_info (BgPicturesSource *bg_source, content_type = g_file_info_get_content_type (info); mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED); - return add_single_file (bg_source, file, content_type, mtime); + return add_single_file (bg_source, file, content_type, mtime, NULL); } static gboolean @@ -518,7 +636,7 @@ add_single_file_from_media (BgPicturesSource *bg_source, else mtime_unix = g_get_real_time () / G_USEC_PER_SEC; - return add_single_file (bg_source, file, content_type, (guint64) mtime_unix); + return add_single_file (bg_source, file, content_type, (guint64) mtime_unix, NULL); } gboolean @@ -828,6 +946,8 @@ bg_pictures_source_init (BgPicturesSource *self) (GDestroyNotify) g_free, NULL); + g_queue_init (&self->add_queue); + pictures_path = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES); if (pictures_path == NULL) pictures_path = g_get_home_dir ();