From c00173ccd05034421f378b0ab311edc4b50f6364 Mon Sep 17 00:00:00 2001 From: Sven Neumann Date: Mon, 31 Oct 2005 11:29:01 +0000 Subject: [PATCH] app/core/gimpdata.[ch] applied a heavily modified version of the patch 2005-10-31 Sven Neumann * app/core/gimpdata.[ch] * app/core/gimpdatafactory.c: applied a heavily modified version of the patch provided by Shlomi Fish in bug #311740. Introduces a cache to speed up reloading of data files. * app/actions/data-commands.c: set gimp busy while refreshing data factories. * app/widgets/gimpwidgets-utils.c (gimp_widget_accel_changed): free the return value of gimp_get_accel_string(). --- ChangeLog | 13 ++ app/actions/data-commands.c | 4 + app/core/gimpdata.c | 10 +- app/core/gimpdata.h | 2 + app/core/gimpdatafactory.c | 345 ++++++++++++++++++++------------ app/widgets/gimpwidgets-utils.c | 11 +- 6 files changed, 255 insertions(+), 130 deletions(-) diff --git a/ChangeLog b/ChangeLog index 446db05c62..03e3a6b8b7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2005-10-31 Sven Neumann + + * app/core/gimpdata.[ch] + * app/core/gimpdatafactory.c: applied a heavily modified version + of the patch provided by Shlomi Fish in bug #311740. Introduces a + cache to speed up reloading of data files. + + * app/actions/data-commands.c: set gimp busy while refreshing data + factories. + + * app/widgets/gimpwidgets-utils.c (gimp_widget_accel_changed): + free the return value of gimp_get_accel_string(). + 2005-10-31 Michael Natterer * app/widgets/gimpviewablebutton.[ch] (gimp_viewable_button_new): diff --git a/app/actions/data-commands.c b/app/actions/data-commands.c index fa9f861771..e7f1f3b799 100644 --- a/app/actions/data-commands.c +++ b/app/actions/data-commands.c @@ -228,8 +228,12 @@ data_refresh_cmd_callback (GtkAction *action, gpointer user_data) { GimpDataFactoryView *view = GIMP_DATA_FACTORY_VIEW (user_data); + Gimp *gimp; + return_if_no_gimp (gimp, user_data); + gimp_set_busy (gimp); gimp_data_factory_data_refresh (view->factory); + gimp_unset_busy (gimp); } void diff --git a/app/core/gimpdata.c b/app/core/gimpdata.c index 43b6ba4840..f064b3cfbf 100644 --- a/app/core/gimpdata.c +++ b/app/core/gimpdata.c @@ -177,6 +177,7 @@ gimp_data_init (GimpData *data, data->dirty = TRUE; data->internal = FALSE; data->freeze_count = 0; + data->mtime = 0; /* look at the passed class pointer, not at GIMP_DATA_GET_CLASS(data) * here, because the latter is always GimpDataClass itself @@ -335,7 +336,14 @@ gimp_data_save (GimpData *data, success = GIMP_DATA_GET_CLASS (data)->save (data, error); if (success) - data->dirty = FALSE; + { + struct stat filestat; + + g_stat (data->filename, &filestat); + + data->mtime = filestat.st_mtime; + data->dirty = FALSE; + } return success; } diff --git a/app/core/gimpdata.h b/app/core/gimpdata.h index 03cf14476e..547f70787c 100644 --- a/app/core/gimpdata.h +++ b/app/core/gimpdata.h @@ -22,6 +22,7 @@ #ifndef __GIMP_DATA_H__ #define __GIMP_DATA_H__ +#include /* time_t */ #include "gimpviewable.h" @@ -56,6 +57,7 @@ struct _GimpData guint dirty : 1; guint internal : 1; gint freeze_count; + time_t mtime; }; struct _GimpDataClass diff --git a/app/core/gimpdatafactory.c b/app/core/gimpdatafactory.c index f0b8c528f3..ed70d0481e 100644 --- a/app/core/gimpdatafactory.c +++ b/app/core/gimpdatafactory.c @@ -42,21 +42,21 @@ #define WRITABLE_PATH_KEY "gimp-data-factory-writable-path" +static void gimp_data_factory_class_init (GimpDataFactoryClass *klass); +static void gimp_data_factory_init (GimpDataFactory *factory); -static void gimp_data_factory_class_init (GimpDataFactoryClass *klass); -static void gimp_data_factory_init (GimpDataFactory *factory); +static void gimp_data_factory_finalize (GObject *object); -static void gimp_data_factory_finalize (GObject *object); +static void gimp_data_factory_data_load (GimpDataFactory *factory, + GHashTable *cache); -static void gimp_data_factory_data_load (GimpDataFactory *factory); +static gint64 gimp_data_factory_get_memsize (GimpObject *object, + gint64 *gui_size); -static gint64 gimp_data_factory_get_memsize (GimpObject *object, - gint64 *gui_size); - -static gchar * gimp_data_factory_get_save_dir (GimpDataFactory *factory); -static void gimp_data_factory_load_data (const GimpDatafileData *file_data, - gpointer user_data); +static gchar * gimp_data_factory_get_save_dir (GimpDataFactory *factory); +static void gimp_data_factory_load_data (const GimpDatafileData *file_data, + gpointer data); static GimpObjectClass *parent_class = NULL; @@ -213,28 +213,102 @@ gimp_data_factory_data_init (GimpDataFactory *factory, g_print ("%s: loading data\n", name ? name : "???"); } - gimp_data_factory_data_load (factory); + gimp_data_factory_data_load (factory, NULL); } gimp_container_thaw (factory->container); } -void -gimp_data_factory_data_refresh (GimpDataFactory *factory) +typedef struct { - g_return_if_fail (GIMP_IS_DATA_FACTORY (factory)); + GimpDataFactory *factory; + GHashTable *cache; +} GimpDataLoadContext; + +typedef struct data_load_context_struct data_load_context; + +static gboolean +gimp_data_factory_refresh_cache_remove (gpointer key, + gpointer value, + gpointer user_data) +{ + GList *list; + + for (list = value; list; list = g_list_next (list)) + g_object_unref (list->data); + + g_list_free (value); + + return TRUE; +} + +static void +gimp_data_factory_data_move_to_cache (GimpDataFactory *factory, + gpointer object, + gpointer data) +{ + GHashTable *cache = data; + GList *list; + const gchar *filename = GIMP_DATA (object)->filename; + + g_object_ref (object); + + gimp_container_remove (factory->container, GIMP_OBJECT (object)); + + list = g_hash_table_lookup (cache, filename); + list = g_list_prepend (list, object); + + g_hash_table_insert (cache, (gpointer) filename, list); +} + +static void +gimp_data_factory_data_foreach (GimpDataFactory *factory, + void (*callback) (GimpDataFactory *factory, + gpointer expr, + gpointer context), + gpointer context) +{ + GimpList *list; + + if (gimp_container_is_empty (factory->container)) + return; + + list = GIMP_LIST (factory->container); gimp_container_freeze (factory->container); - gimp_data_factory_data_save (factory); - gimp_data_factory_data_free (factory); - gimp_data_factory_data_load (factory); + if (list->list) + { + if (GIMP_DATA (list->list->data)->internal) + { + /* if there are internal objects in the list, skip them */ + GList *glist; + + for (glist = list->list; glist; glist = g_list_next (glist)) + { + if (glist->next && ! GIMP_DATA (glist->next->data)->internal) + { + while (glist->next) + callback (factory, glist->next->data, context); + + break; + } + } + } + else + { + /* otherwise delete everything */ + while (list->list) + callback (factory, list->list->data, context); + } + } gimp_container_thaw (factory->container); } static void -gimp_data_factory_data_load (GimpDataFactory *factory) +gimp_data_factory_data_load (GimpDataFactory *factory, + GHashTable *cache) { gchar *path; gchar *writable_path; @@ -246,8 +320,12 @@ gimp_data_factory_data_load (GimpDataFactory *factory) if (path && strlen (path)) { - GList *writable_list = NULL; - gchar *tmp; + GList *writable_list = NULL; + gchar *tmp; + GimpDataLoadContext context; + + context.factory = factory; + context.cache = cache; tmp = gimp_config_path_expand (path, TRUE, NULL); g_free (path); @@ -261,14 +339,12 @@ gimp_data_factory_data_load (GimpDataFactory *factory) writable_list = gimp_path_parse (writable_path, 16, TRUE, NULL); - g_object_set_data (G_OBJECT (factory), WRITABLE_PATH_KEY, - writable_list); + g_object_set_data (G_OBJECT (factory), + WRITABLE_PATH_KEY, writable_list); } - gimp_datafiles_read_directories (path, - G_FILE_TEST_EXISTS, - gimp_data_factory_load_data, - factory); + gimp_datafiles_read_directories (path, G_FILE_TEST_EXISTS, + gimp_data_factory_load_data, &context); if (writable_path) { @@ -281,6 +357,49 @@ gimp_data_factory_data_load (GimpDataFactory *factory) g_free (writable_path); } +static void +gimp_data_factory_data_reload (GimpDataFactory *factory) +{ + + GHashTable *cache; + + g_return_if_fail (GIMP_IS_DATA_FACTORY (factory)); + + cache = g_hash_table_new (g_str_hash, g_str_equal); + + gimp_data_factory_data_foreach (factory, + gimp_data_factory_data_move_to_cache, cache); + + /* Now the cache contains a filename => list-of-objects mapping of + * the old objects. So we should now traverse the directory and for + * each file load it only if it's mtime is newer. + * + * Once a file was added, it is removed from the cache, so the only + * objects remaining there will be those that are not present on the + * disk (that have to be destroyed) + */ + gimp_data_factory_data_load (factory, cache); + + /* Now all the data is loaded. Free what remains in the cache. */ + g_hash_table_foreach_remove (cache, + gimp_data_factory_refresh_cache_remove, NULL); + g_hash_table_destroy (cache); +} + +void +gimp_data_factory_data_refresh (GimpDataFactory *factory) +{ + g_return_if_fail (GIMP_IS_DATA_FACTORY (factory)); + + gimp_container_freeze (factory->container); + + gimp_data_factory_data_save (factory); + + gimp_data_factory_data_reload (factory); + + gimp_container_thaw (factory->container); +} + void gimp_data_factory_data_save (GimpDataFactory *factory) { @@ -319,8 +438,7 @@ gimp_data_factory_data_save (GimpDataFactory *factory) */ if (error) { - g_message (_("Warning: Failed to save data:\n\n%s"), - error->message); + g_message (_("Failed to save data:\n\n%s"), error->message); g_clear_error (&error); } } @@ -332,55 +450,19 @@ gimp_data_factory_data_save (GimpDataFactory *factory) g_free (writable_dir); } +static void +gimp_data_factory_remove_cb (GimpDataFactory *factory, + gpointer data, + gpointer context) +{ + gimp_container_remove (factory->container, GIMP_OBJECT (data)); +} + void gimp_data_factory_data_free (GimpDataFactory *factory) { - GimpList *list; - - g_return_if_fail (GIMP_IS_DATA_FACTORY (factory)); - - if (gimp_container_is_empty (factory->container)) - return; - - list = GIMP_LIST (factory->container); - - gimp_container_freeze (factory->container); - - if (list->list) - { - if (GIMP_DATA (list->list->data)->internal) - { - /* if there are internal objects in the list, skip them */ - - GList *glist; - - for (glist = list->list; glist; glist = g_list_next (glist)) - { - if (glist->next && ! GIMP_DATA (glist->next->data)->internal) - { - while (glist->next) - { - gimp_container_remove (factory->container, - GIMP_OBJECT (glist->next->data)); - } - - break; - } - } - } - else - { - /* otherwise delete everything */ - - while (list->list) - { - gimp_container_remove (factory->container, - GIMP_OBJECT (list->list->data)); - } - } - } - - gimp_container_thaw (factory->container); + return gimp_data_factory_data_foreach (factory, + gimp_data_factory_remove_cb, NULL); } GimpData * @@ -529,8 +611,7 @@ gimp_data_factory_data_save_single (GimpDataFactory *factory, */ if (error) { - g_message (_("Warning: Failed to save data:\n\n%s"), - error->message); + g_message (_("Failed to save data:\n\n%s"), error->message); g_clear_error (&error); } @@ -592,72 +673,88 @@ gimp_data_factory_get_save_dir (GimpDataFactory *factory) static void gimp_data_factory_load_data (const GimpDatafileData *file_data, - gpointer user_data) + gpointer data) { - GimpDataFactory *factory = GIMP_DATA_FACTORY (user_data); - gint i; + GimpDataLoadContext *context = data; + GimpDataFactory *factory = context->factory; + GHashTable *cache = context->cache; + gint i; for (i = 0; i < factory->n_loader_entries; i++) { - if (factory->loader_entries[i].extension) - { - if (gimp_datafiles_check_extension (file_data->filename, - factory->loader_entries[i].extension)) - { - goto insert; - } - } - else - { - goto insert; - } + if (! factory->loader_entries[i].extension || + gimp_datafiles_check_extension (file_data->filename, + factory->loader_entries[i].extension)) + goto insert; } return; insert: { - GList *data_list; - GError *error = NULL; + GList *cached_data; + gboolean load_from_disk = TRUE; - data_list = factory->loader_entries[i].load_func (file_data->filename, - &error); - - if (! data_list) + if (cache && + (cached_data = g_hash_table_lookup (cache, file_data->filename))) { - g_message (_("Warning: Failed to load data:\n\n%s"), - error->message); - g_clear_error (&error); - } - else - { - GList *writable_list; - GList *list; - gboolean writable; - gboolean deletable; + GimpData *data = cached_data->data; - writable_list = g_object_get_data (G_OBJECT (factory), - WRITABLE_PATH_KEY); + load_from_disk = (data->mtime == 0 || data->mtime != file_data->mtime); - deletable = (g_list_length (data_list) == 1 && - g_list_find_custom (writable_list, file_data->dirname, - (GCompareFunc) strcmp) != NULL); - - writable = (deletable && factory->loader_entries[i].writable); - - for (list = data_list; list; list = g_list_next (list)) + if (! load_from_disk) { - GimpData *data = list->data; + GList *list; - gimp_data_set_filename (data, file_data->filename, - writable, deletable); - data->dirty = FALSE; - - gimp_container_add (factory->container, GIMP_OBJECT (data)); - g_object_unref (data); + for (list = cached_data; list; list = g_list_next (list)) + gimp_container_add (factory->container, GIMP_OBJECT (list->data)); } + } - g_list_free (data_list); + if (load_from_disk) + { + GList *data_list; + GError *error = NULL; + + data_list = factory->loader_entries[i].load_func (file_data->filename, + &error); + + if (G_LIKELY (data_list)) + { + GList *writable_list; + GList *list; + gboolean writable; + gboolean deletable; + + writable_list = g_object_get_data (G_OBJECT (factory), + WRITABLE_PATH_KEY); + + deletable = (g_list_length (data_list) == 1 && + g_list_find_custom (writable_list, file_data->dirname, + (GCompareFunc) strcmp) != NULL); + + writable = (deletable && factory->loader_entries[i].writable); + + for (list = data_list; list; list = g_list_next (list)) + { + GimpData *data = list->data; + + gimp_data_set_filename (data, file_data->filename, + writable, deletable); + data->mtime = file_data->mtime; + data->dirty = FALSE; + + gimp_container_add (factory->container, GIMP_OBJECT (data)); + g_object_unref (data); + } + + g_list_free (data_list); + } + else + { + g_message (_("Failed to load data:\n\n%s"), error->message); + g_clear_error (&error); + } } } } diff --git a/app/widgets/gimpwidgets-utils.c b/app/widgets/gimpwidgets-utils.c index 3215436c7b..6c58d1ee81 100644 --- a/app/widgets/gimpwidgets-utils.c +++ b/app/widgets/gimpwidgets-utils.c @@ -966,11 +966,12 @@ gimp_widget_accel_changed (GtkAccelGroup *accel_group, accel_key->accel_key && accel_key->accel_flags & GTK_ACCEL_VISIBLE) { - tooltip = g_strconcat (orig_tooltip, - " ", - gimp_get_accel_string (accel_key->accel_key, - accel_key->accel_mods), - NULL); + gchar *tmp = gimp_get_accel_string (accel_key->accel_key, + accel_key->accel_mods); + + tooltip = g_strconcat (orig_tooltip, " ", tmp, NULL); + + g_free (tmp); } else {