[gthumb] fixed some performance issues when updating thumbnails
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] fixed some performance issues when updating thumbnails
- Date: Thu, 22 Mar 2012 18:30:02 +0000 (UTC)
commit 69ec88345124cd707ece0b8b5855f287ad3dd3ef
Author: Paolo Bacchilega <paobac src gnome org>
Date: Thu Mar 22 19:28:29 2012 +0100
fixed some performance issues when updating thumbnails
use a state machine to avoid to scan the whole list for each thumbnail
gthumb/gth-file-list.c | 313 +++++++++++++++++++++++++++++------------------
1 files changed, 193 insertions(+), 120 deletions(-)
---
diff --git a/gthumb/gth-file-list.c b/gthumb/gth-file-list.c
index 3717273..96355b5 100644
--- a/gthumb/gth-file-list.c
+++ b/gthumb/gth-file-list.c
@@ -103,32 +103,51 @@ enum {
};
+typedef enum {
+ THUMBNAILER_PHASE_INITIALIZE,
+ THUMBNAILER_PHASE_UPDATE_VISIBLE,
+ THUMBNAILER_PHASE_UPDATE_DOWNWARD,
+ THUMBNAILER_PHASE_UPDATE_UPWARD,
+ THUMBNAILER_PHASE_COMPLETED
+} ThumbnailerPhase;
+
+
+typedef struct {
+ ThumbnailerPhase phase;
+ int first_visibile;
+ int last_visible;
+ int current_pos;
+ GList *current_item;
+} ThumbnailerState;
+
+
struct _GthFileListPrivateData
{
- GSettings *settings;
- GthFileListType type;
- GtkAdjustment *vadj;
- GtkWidget *notebook;
- GtkWidget *view;
- GtkWidget *message;
- GtkWidget *scrolled_window;
- GthIconCache *icon_cache;
- GthFileSource *file_source;
- gboolean load_thumbs;
- int thumb_size;
- gboolean ignore_hidden_thumbs;
- GHashTable *thumb_data;
- GthThumbLoader *thumb_loader;
- gboolean loading_thumbs;
- gboolean dirty;
- guint dirty_event;
- guint restart_thumb_update;
- GList *queue; /* list of GthFileListOp */
- GList *jobs; /* list of ThumbnailJob */
- gboolean cancelling;
- guint update_event;
- gboolean visibility_changed;
- GList *visibles;
+ GSettings *settings;
+ GthFileListType type;
+ GtkAdjustment *vadj;
+ GtkWidget *notebook;
+ GtkWidget *view;
+ GtkWidget *message;
+ GtkWidget *scrolled_window;
+ GthIconCache *icon_cache;
+ GthFileSource *file_source;
+ gboolean load_thumbs;
+ int thumb_size;
+ gboolean ignore_hidden_thumbs;
+ GHashTable *thumb_data;
+ GthThumbLoader *thumb_loader;
+ gboolean loading_thumbs;
+ gboolean dirty;
+ guint dirty_event;
+ guint restart_thumb_update;
+ GList *queue; /* list of GthFileListOp */
+ GList *jobs; /* list of ThumbnailJob */
+ gboolean cancelling;
+ guint update_event;
+ gboolean visibility_changed;
+ GList *visibles;
+ ThumbnailerState thumbnailer_state;
};
@@ -398,6 +417,7 @@ gth_file_list_init (GthFileList *file_list)
file_list->priv->update_event = 0;
file_list->priv->visibles = NULL;
file_list->priv->visibility_changed = FALSE;
+ file_list->priv->thumbnailer_state.phase = THUMBNAILER_PHASE_INITIALIZE;
}
@@ -483,6 +503,9 @@ static void
vadj_changed_cb (GtkAdjustment *adjustment,
gpointer user_data)
{
+ GthFileList *file_list = user_data;
+
+ file_list->priv->thumbnailer_state.phase = THUMBNAILER_PHASE_INITIALIZE;
start_update_next_thumb (GTH_FILE_LIST (user_data));
}
@@ -548,6 +571,7 @@ file_store_visibility_changed_cb (GthFileStore *file_store,
GthFileList *file_list)
{
file_list->priv->visibility_changed = TRUE;
+ file_list->priv->thumbnailer_state.phase = THUMBNAILER_PHASE_INITIALIZE;
}
@@ -559,7 +583,9 @@ file_store_rows_reordered_cb (GtkTreeModel *tree_model,
gpointer user_data)
{
GthFileList *file_list = user_data;
+
file_list->priv->visibility_changed = TRUE;
+ file_list->priv->thumbnailer_state.phase = THUMBNAILER_PHASE_INITIALIZE;
}
@@ -1599,142 +1625,189 @@ _gth_file_list_get_visibles (GthFileList *file_list)
}
-static void
-_gth_file_list_update_next_thumb (GthFileList *file_list)
-{
- int pos;
- int first_pos;
- int last_pos;
- GthFileData *file_data = NULL;
- ThumbData *thumb_data;
- GList *list, *scan;
- int new_pos = -1;
- GTimeVal current_time;
- gboolean young_file_found = FALSE;
- ThumbnailJob *job;
+static gboolean
+_gth_file_list_thumbnailer_iterate (GthFileList *file_list,
+ int *new_pos,
+ GTimeVal *current_time,
+ gboolean *young_file_found)
+{
+ gboolean iterate_again = TRUE;
+ GList *list;
+ GList *scan;
+ int pos;
+ GthFileData *file_data;
+ ThumbData *thumb_data;
- if (file_list->priv->queue != NULL) {
- if (file_list->priv->update_event != 0)
- g_source_remove (file_list->priv->update_event);
- file_list->priv->update_event = g_idle_add (update_thumbs_stopped, file_list);
- return;
- }
+ list = _gth_file_list_get_visibles (file_list);
- if (file_list->priv->cancelling)
- return;
+ switch (file_list->priv->thumbnailer_state.phase) {
+ case THUMBNAILER_PHASE_INITIALIZE:
+ file_list->priv->thumbnailer_state.first_visibile = gth_file_view_get_first_visible (GTH_FILE_VIEW (file_list->priv->view));
+ file_list->priv->thumbnailer_state.last_visible = gth_file_view_get_last_visible (GTH_FILE_VIEW (file_list->priv->view));
+
+ /* pass to the 'update visible files' phase. */
+ file_list->priv->thumbnailer_state.phase = THUMBNAILER_PHASE_UPDATE_VISIBLE;
+ file_list->priv->thumbnailer_state.current_pos = file_list->priv->thumbnailer_state.first_visibile;
+ file_list->priv->thumbnailer_state.current_item = g_list_nth (list, file_list->priv->thumbnailer_state.current_pos);
+ if (file_list->priv->thumbnailer_state.current_item == NULL) {
+ file_list->priv->thumbnailer_state.phase = THUMBNAILER_PHASE_COMPLETED;
+ return FALSE;
+ }
+ break;
- if (! file_list->priv->load_thumbs) {
- _gth_file_list_thumbs_completed (file_list);
- return;
- }
+ case THUMBNAILER_PHASE_UPDATE_VISIBLE:
+ /* Find a non-loaded thumbnail among the visible files. */
- /* Find first visible undone. */
+ scan = file_list->priv->thumbnailer_state.current_item;
+ pos = file_list->priv->thumbnailer_state.current_pos;
+ while (scan && (pos <= file_list->priv->thumbnailer_state.last_visible)) {
+ file_data = scan->data;
+ thumb_data = g_hash_table_lookup (file_list->priv->thumb_data, file_data->file);
+ if (! thumb_data->thumb_loaded && can_create_file_thumbnail (file_data, thumb_data, current_time, young_file_found)) {
+ /* found a thumbnail to load */
+ file_list->priv->thumbnailer_state.current_item = scan;
+ file_list->priv->thumbnailer_state.current_pos = pos;
+ *new_pos = pos;
+ return FALSE;
+ }
- list = _gth_file_list_get_visibles (file_list);
- first_pos = gth_file_view_get_first_visible (GTH_FILE_VIEW (file_list->priv->view));
- last_pos = gth_file_view_get_last_visible (GTH_FILE_VIEW (file_list->priv->view));
+ pos++;
+ scan = scan->next;
+ }
- scan = NULL;
- pos = first_pos;
- if (pos >= 0)
- scan = g_list_nth (list, pos);
- if (scan == NULL) {
- _gth_file_list_thumbs_completed (file_list);
- return;
- }
+ /* No thumbnail to load among the visible images, pass to the
+ * next phase. Start from the one after the last visible image. */
+ file_list->priv->thumbnailer_state.phase = THUMBNAILER_PHASE_UPDATE_DOWNWARD;
+ file_list->priv->thumbnailer_state.current_pos = file_list->priv->thumbnailer_state.last_visible + 1;
+ file_list->priv->thumbnailer_state.current_item = g_list_nth (list, file_list->priv->thumbnailer_state.current_pos);
+ break;
- /* Find a not loaded thumbnail among the visible images. */
+ case THUMBNAILER_PHASE_UPDATE_DOWNWARD:
+ scan = file_list->priv->thumbnailer_state.current_item;
+ pos = file_list->priv->thumbnailer_state.current_pos;
+ while (scan && (pos <= file_list->priv->thumbnailer_state.last_visible + N_CREATEAHEAD)) {
+ gboolean requested_action_performed;
- g_get_current_time (¤t_time);
+ file_data = scan->data;
+ thumb_data = g_hash_table_lookup (file_list->priv->thumb_data, file_data->file);
+
+ if (pos <= file_list->priv->thumbnailer_state.last_visible + N_VIEWAHEAD)
+ requested_action_performed = thumb_data->thumb_loaded;
+ else
+ requested_action_performed = thumb_data->thumb_created;
+
+ if (! requested_action_performed && can_create_file_thumbnail (file_data, thumb_data, current_time, young_file_found)) {
+ /* found a thumbnail to load */
+ file_list->priv->thumbnailer_state.current_item = scan;
+ file_list->priv->thumbnailer_state.current_pos = pos;
+ *new_pos = pos;
+ return FALSE;
+ }
- while (pos <= last_pos) {
- file_data = scan->data;
- thumb_data = g_hash_table_lookup (file_list->priv->thumb_data, file_data->file);
- if (! thumb_data->thumb_loaded && can_create_file_thumbnail (file_data, thumb_data, ¤t_time, &young_file_found)) {
- new_pos = pos;
- break;
- }
- else {
pos++;
scan = scan->next;
}
- }
- if (! file_list->priv->ignore_hidden_thumbs) {
+ /* No thumbnail to load, pass to the next phase. Start from the
+ * one before the first visible upward to the first one. */
+ file_list->priv->thumbnailer_state.phase = THUMBNAILER_PHASE_UPDATE_UPWARD;
+ file_list->priv->thumbnailer_state.current_pos = file_list->priv->thumbnailer_state.first_visibile - 1;
+ file_list->priv->thumbnailer_state.current_item = g_list_nth (list, file_list->priv->thumbnailer_state.current_pos);
+ break;
- /* Find a not created thumbnail among the not-visible images. */
+ case THUMBNAILER_PHASE_UPDATE_UPWARD:
+ scan = file_list->priv->thumbnailer_state.current_item;
+ pos = file_list->priv->thumbnailer_state.current_pos;
+ while (scan && (pos >= file_list->priv->thumbnailer_state.first_visibile - N_CREATEAHEAD)) {
+ gboolean requested_action_performed;
- /* start from the one after the last visible image... */
+ file_data = scan->data;
+ thumb_data = g_hash_table_lookup (file_list->priv->thumb_data, file_data->file);
- if (new_pos == -1) {
- pos = last_pos + 1;
- for (scan = g_list_nth (list, pos); scan && (pos <= last_pos + N_CREATEAHEAD); scan = scan->next) {
- gboolean requested_action_performed;
+ if (pos >= file_list->priv->thumbnailer_state.first_visibile - N_VIEWAHEAD)
+ requested_action_performed = thumb_data->thumb_loaded;
+ else
+ requested_action_performed = thumb_data->thumb_created;
+
+ if (! requested_action_performed && can_create_file_thumbnail (file_data, thumb_data, current_time, young_file_found)) {
+ /* found a thumbnail to load */
+ file_list->priv->thumbnailer_state.current_item = scan;
+ file_list->priv->thumbnailer_state.current_pos = pos;
+ *new_pos = pos;
+ return FALSE;
+ }
- file_data = scan->data;
- thumb_data = g_hash_table_lookup (file_list->priv->thumb_data, file_data->file);
+ pos--;
+ scan = scan->prev;
+ }
- if (pos <= last_pos + N_VIEWAHEAD)
- requested_action_performed = thumb_data->thumb_loaded;
- else
- requested_action_performed = thumb_data->thumb_created;
+ /* No thumbnail to load, terminate the process. */
+ file_list->priv->thumbnailer_state.phase = THUMBNAILER_PHASE_COMPLETED;
+ break;
- if (! requested_action_performed && can_create_file_thumbnail (file_data, thumb_data, ¤t_time, &young_file_found)) {
- new_pos = pos;
- break;
- }
- pos++;
- }
- }
+ case THUMBNAILER_PHASE_COMPLETED:
+ return FALSE;
+ }
+
+ return iterate_again;
+}
- /* ...continue from the one before the first visible upward to
- * the first one. */
- if (new_pos == -1) {
- pos = first_pos - 1;
- for (scan = g_list_nth (list, pos); scan && (pos >= first_pos - N_CREATEAHEAD); scan = scan->prev) {
- gboolean requested_action_performed;
+static void
+_gth_file_list_update_next_thumb (GthFileList *file_list)
+{
+ int new_pos;
+ GTimeVal current_time;
+ gboolean young_file_found;
+ ThumbnailJob *job;
- file_data = scan->data;
- thumb_data = g_hash_table_lookup (file_list->priv->thumb_data, file_data->file);
+ /* give priority to any other operation, the thumbnailer will restart
+ * again soon after the operation terminates. */
+ if (file_list->priv->queue != NULL) {
+ if (file_list->priv->update_event != 0)
+ g_source_remove (file_list->priv->update_event);
+ file_list->priv->update_event = g_idle_add (update_thumbs_stopped, file_list);
+ return;
+ }
- if (pos >= first_pos - N_VIEWAHEAD)
- requested_action_performed = thumb_data->thumb_loaded;
- else
- requested_action_performed = thumb_data->thumb_created;
+ if (file_list->priv->cancelling)
+ return;
- if (! requested_action_performed && can_create_file_thumbnail (file_data, thumb_data, ¤t_time, &young_file_found)) {
- new_pos = pos;
- break;
- }
- pos--;
- }
- }
+ if (! file_list->priv->load_thumbs) {
+ _gth_file_list_thumbs_completed (file_list);
+ return;
}
- if (new_pos != -1)
- file_data = g_object_ref (file_data);
+ /* find the new thumbnail to load */
+
+ new_pos = -1;
+ g_get_current_time (¤t_time);
+ young_file_found = FALSE;
+ while (_gth_file_list_thumbnailer_iterate (file_list, &new_pos, ¤t_time, &young_file_found))
+ /* void */;
- if (new_pos == -1) {
+ if (file_list->priv->thumbnailer_state.phase == THUMBNAILER_PHASE_COMPLETED) {
_gth_file_list_thumbs_completed (file_list);
if (young_file_found && (file_list->priv->restart_thumb_update == 0))
file_list->priv->restart_thumb_update = g_timeout_add (RESTART_LOADING_THUMBS_DELAY, restart_thumb_update_cb, file_list);
return;
}
+ g_assert (file_list->priv->thumbnailer_state.current_item != NULL);
+
job = g_new0 (ThumbnailJob, 1);
job->file_list = g_object_ref (file_list);
job->loader = g_object_ref (file_list->priv->thumb_loader);
job->cancellable = g_cancellable_new ();
- job->file_data = file_data; /* already ref-ed above */
- job->pos = new_pos;
- job->update_in_view = (new_pos >= (first_pos - N_VIEWAHEAD)) && (new_pos <= (last_pos + N_VIEWAHEAD));
+ job->file_data = g_object_ref (file_list->priv->thumbnailer_state.current_item->data);
+ job->pos = file_list->priv->thumbnailer_state.current_pos;
+ job->update_in_view = (job->pos >= (file_list->priv->thumbnailer_state.first_visibile - N_VIEWAHEAD)) && (job->pos <= (file_list->priv->thumbnailer_state.last_visible + N_VIEWAHEAD));
#if 0
g_print ("%d in [%d, %d] => %d\n",
job->pos,
- (first_pos - N_VIEWAHEAD),
- (last_pos + N_VIEWAHEAD),
+ (file_list->priv->thumbnailer_state.first_visibile - N_VIEWAHEAD),
+ (file_list->priv->thumbnailer_state.last_visible + N_VIEWAHEAD),
job->update_in_view);
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]