From 596bc5798a33e9cd1f83d3fb1536a4072eb1905d Mon Sep 17 00:00:00 2001 From: Meriipu Date: Wed, 27 May 2020 11:20:34 +0200 Subject: [PATCH] Bootleg fix for bug #16467 (thumnail generation). It is not particularly clean and it might have some unorthodox methods (particularly the malloc of the structs). There may also be other errors that I have overlooked; GLib is not very enjoyable to work with. In addition there is a straggling issue where some actions the user might perform causes the visible files to be gathered for queueup, and although I added a check to skip the files that have a recent last-modified date, it seems that if: * the files already exist * the files are currently being written to then the timestamp was old when the file was gathered, but the file is queued up and gets partially written to in the process and once the queue gets to it, it is still not complete. Running the script attached to the initial bug and frantically refreshing in the folder over and over occasionally reproduces this issue, but it appears to be a rare one. --- thunar/thunar-file.c | 2 +- thunar/thunar-standard-view.c | 128 +++++++++++++++++++++++++++++----- 2 files changed, 112 insertions(+), 18 deletions(-) diff --git a/thunar/thunar-file.c b/thunar/thunar-file.c index 18687ff5..416cf171 100644 --- a/thunar/thunar-file.c +++ b/thunar/thunar-file.c @@ -3581,7 +3581,7 @@ thunar_file_get_thumbnail_path (ThunarFile *file, ThunarThumbnailSize thumbnail_ g_checksum_free (checksum); /* The thumbnail is in the format/location - * $XDG_CACHE_HOME/thumbnails/(nromal|large)/MD5_Hash_Of_URI.png + * $XDG_CACHE_HOME/thumbnails/(normal|large)/MD5_Hash_Of_URI.png * for version 0.8.0 if XDG_CACHE_HOME is defined, otherwise * /homedir/.thumbnails/(normal|large)/MD5_Hash_Of_URI.png * will be used, which is also always used for versions prior diff --git a/thunar/thunar-standard-view.c b/thunar/thunar-standard-view.c index c9f0e1b3..8378c3c2 100644 --- a/thunar/thunar-standard-view.c +++ b/thunar/thunar-standard-view.c @@ -3902,6 +3902,48 @@ thunar_standard_view_rows_reordered (ThunarListModel *model, } +/* Check the last-modified time of the file, and return TRUE until some seconds + * have passed. This is to not generate thumbnails until the file is complete. */ +static gboolean +thunar_thumbnailing_last_modified_delay (gpointer data) +{ + guint64 current_time; + guint64 file_modified_time; + const guint64 atleast_seconds_ago = 5; + ThunarFile *file; + ThunarStandardView *standard_view; + struct thumbnailer_data_t { ThunarStandardView *standard_view; ThunarFile *file; }; + struct thumbnailer_data_t *thumbnailer_data; + + thumbnailer_data = data; + file = thumbnailer_data->file; + file_modified_time = thunar_file_get_date (file, THUNAR_FILE_DATE_MODIFIED); + current_time = (guint64) (g_get_real_time() / G_USEC_PER_SEC); + return (current_time - file_modified_time < atleast_seconds_ago); +} + + +/* Actually send the request to queue the file for thumbnail-generation, + * now that the last-modified timer has expired. */ +static void +thunar_thumbnailing_delay_completed (gpointer data) +{ + ThunarFile *file; + ThunarStandardView *standard_view; + struct thumbnailer_data_t { ThunarStandardView *standard_view; ThunarFile *file; }; + struct thumbnailer_data_t *thumbnailer_data; + + thumbnailer_data = data; + file = thumbnailer_data->file; + standard_view = thumbnailer_data->standard_view; + + thunar_thumbnailer_queue_file (standard_view->priv->thumbnailer, file, + &standard_view->priv->thumbnail_request); + free(thumbnailer_data); + g_object_unref (G_OBJECT (file)); +} + + static void thunar_standard_view_row_changed (ThunarListModel *model, @@ -3909,7 +3951,12 @@ thunar_standard_view_row_changed (ThunarListModel *model, GtkTreeIter *iter, ThunarStandardView *standard_view) { - ThunarFile *file; + ThunarFile *file; + guint64 current_time; + guint64 file_modified_time; + const guint64 atleast_seconds_ago = 5; + struct thumbnailer_data_t { ThunarStandardView *standard_view; ThunarFile *file; }; + struct thumbnailer_data_t *thumbnailer_data; _thunar_return_if_fail (THUNAR_IS_LIST_MODEL (model)); _thunar_return_if_fail (path != NULL); @@ -3929,10 +3976,36 @@ thunar_standard_view_row_changed (ThunarListModel *model, if (thunar_file_get_thumb_state (file) == THUNAR_FILE_THUMB_STATE_UNKNOWN) { thunar_standard_view_cancel_thumbnailing (standard_view); - thunar_thumbnailer_queue_file (standard_view->priv->thumbnailer, file, - &standard_view->priv->thumbnail_request); + + /* check if the file has been written to very recently. If so, it is likely + * that the file is still incomplete. In that case, follow the roundabout + * route of periodically checking again until some seconds have passed. */ + file_modified_time = thunar_file_get_date (file, THUNAR_FILE_DATE_MODIFIED); + current_time = (guint64) (g_get_real_time() / G_USEC_PER_SEC); + if (current_time - file_modified_time < atleast_seconds_ago) + { + thumbnailer_data = (struct thumbnailer_data_t *) malloc(sizeof(struct thumbnailer_data_t)); + + thumbnailer_data->standard_view = standard_view; + thumbnailer_data->file = file; + /* Every 1000 msec, check whether last-modified is some seconds ago from now. + * If it is, it is reasonably safe to send the thumbnailing-queueup. */ + g_timeout_add_full (G_PRIORITY_DEFAULT, 1000, + thunar_thumbnailing_last_modified_delay, thumbnailer_data, thunar_thumbnailing_delay_completed); + } + else + { + + /* This file has been modified long enough ago that there is no need to wait */ + thunar_thumbnailer_queue_file (standard_view->priv->thumbnailer, file, + &standard_view->priv->thumbnail_request); + g_object_unref (G_OBJECT (file)); + } + } + else + { + g_object_unref (G_OBJECT (file)); } - g_object_unref (G_OBJECT (file)); } @@ -4246,13 +4319,16 @@ static gboolean thunar_standard_view_request_thumbnails_real (ThunarStandardView *standard_view, gboolean lazy_request) { - GtkTreePath *start_path; - GtkTreePath *end_path; - GtkTreePath *path; - GtkTreeIter iter; - ThunarFile *file; - gboolean valid_iter; - GList *visible_files = NULL; + GtkTreePath *start_path; + GtkTreePath *end_path; + GtkTreePath *path; + GtkTreeIter iter; + ThunarFile *file; + gboolean valid_iter; + GList *visible_files = NULL; + guint64 current_time; + guint64 file_modified_time; + const guint64 atleast_seconds_ago = 5; _thunar_return_val_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view), FALSE); _thunar_return_val_if_fail (THUNAR_IS_ICON_FACTORY (standard_view->icon_factory), FALSE); @@ -4277,9 +4353,25 @@ thunar_standard_view_request_thumbnails_real (ThunarStandardView *standard_view, while (valid_iter) { - /* prepend the file to the visible items list */ file = thunar_list_model_get_file (standard_view->model, &iter); - visible_files = g_list_prepend (visible_files, file); + + /* A manual refresh will trigger this, and may cause Thunar to + * attempt to update thumbnails of very recently modified files. + * Do not generate thumbnails for such recent files; they are either + * already being generated or will be generated on next refresh in a + * few seconds. */ + file_modified_time = thunar_file_get_date (file, THUNAR_FILE_DATE_MODIFIED); + current_time = (guint64) (g_get_real_time() / G_USEC_PER_SEC); + if (current_time - file_modified_time > atleast_seconds_ago) + { + /* prepend the file to the visible items list. This still rarely causes + * some issues if files are being written which have the same name as + * existing files, and the user is frantically refreshing the directory. + * It is hard to reproduce but does not happen if the line below is + * commented out (although doing this breaks other thumbnail generation) + * It is a much rarer issue than it used to be, nonetheless. */ + visible_files = g_list_prepend (visible_files, file); + } /* check if we've reached the end of the visible range */ path = gtk_tree_model_get_path (GTK_TREE_MODEL (standard_view->model), &iter); @@ -4300,10 +4392,12 @@ thunar_standard_view_request_thumbnails_real (ThunarStandardView *standard_view, } /* queue a thumbnail request */ - thunar_thumbnailer_queue_files (standard_view->priv->thumbnailer, - lazy_request, visible_files, - &standard_view->priv->thumbnail_request); - + if (g_list_length (visible_files) > 0) + { + thunar_thumbnailer_queue_files (standard_view->priv->thumbnailer, + lazy_request, visible_files, + &standard_view->priv->thumbnail_request); + } /* release the file list */ g_list_free_full (visible_files, g_object_unref); -- 2.26.2