From bb8d65bcee39b110168c4649a6325a125776a095 Mon Sep 17 00:00:00 2001 From: Michael Natterer Date: Fri, 30 May 2014 19:38:17 +0200 Subject: [PATCH] Bug 730862 - Preview frozen while dragging selection tools... ...(crop, rectangle, etc) in large image zoomed-to-fit Introduce a hash of the last 16 used icons in GimpStatusbar, it was loading icons at a very high frequency. Found by Massimo. --- app/display/gimpstatusbar.c | 92 ++++++++++++++++++++++++++++++++++--- app/display/gimpstatusbar.h | 1 + 2 files changed, 87 insertions(+), 6 deletions(-) diff --git a/app/display/gimpstatusbar.c b/app/display/gimpstatusbar.c index 5f4ffd0bb0..f568d53fb6 100644 --- a/app/display/gimpstatusbar.c +++ b/app/display/gimpstatusbar.c @@ -73,6 +73,11 @@ static void gimp_statusbar_progress_iface_init (GimpProgressInterface *iface static void gimp_statusbar_dispose (GObject *object); static void gimp_statusbar_finalize (GObject *object); +static void gimp_statusbar_screen_changed (GtkWidget *widget, + GdkScreen *previous); +static void gimp_statusbar_style_set (GtkWidget *widget, + GtkStyle *prev_style); + static void gimp_statusbar_hbox_size_request (GtkWidget *widget, GtkRequisition *requisition, GimpStatusbar *statusbar); @@ -122,6 +127,9 @@ static void gimp_statusbar_msg_free (GimpStatusbarMsg *msg); static gchar * gimp_statusbar_vprintf (const gchar *format, va_list args) G_GNUC_PRINTF (1, 0); +static GdkPixbuf * gimp_statusbar_load_icon (GimpStatusbar *statusbar, + const gchar *icon_name); + G_DEFINE_TYPE_WITH_CODE (GimpStatusbar, gimp_statusbar, GTK_TYPE_STATUSBAR, G_IMPLEMENT_INTERFACE (GIMP_TYPE_PROGRESS, @@ -133,10 +141,14 @@ G_DEFINE_TYPE_WITH_CODE (GimpStatusbar, gimp_statusbar, GTK_TYPE_STATUSBAR, static void gimp_statusbar_class_init (GimpStatusbarClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - object_class->dispose = gimp_statusbar_dispose; - object_class->finalize = gimp_statusbar_finalize; + object_class->dispose = gimp_statusbar_dispose; + object_class->finalize = gimp_statusbar_finalize; + + widget_class->screen_changed = gimp_statusbar_screen_changed; + widget_class->style_set = gimp_statusbar_style_set; } static void @@ -296,6 +308,12 @@ gimp_statusbar_finalize (GObject *object) statusbar->icon = NULL; } + if (statusbar->icon_hash) + { + g_hash_table_unref (statusbar->icon_hash); + statusbar->icon_hash = NULL; + } + g_slist_free_full (statusbar->messages, (GDestroyNotify) gimp_statusbar_msg_free); statusbar->messages = NULL; @@ -309,6 +327,37 @@ gimp_statusbar_finalize (GObject *object) G_OBJECT_CLASS (parent_class)->finalize (object); } +static void +gimp_statusbar_screen_changed (GtkWidget *widget, + GdkScreen *previous) +{ + GimpStatusbar *statusbar = GIMP_STATUSBAR (widget); + + if (GTK_WIDGET_CLASS (parent_class)->screen_changed) + GTK_WIDGET_CLASS (parent_class)->screen_changed (widget, previous); + + if (statusbar->icon_hash) + { + g_hash_table_unref (statusbar->icon_hash); + statusbar->icon_hash = NULL; + } +} + +static void +gimp_statusbar_style_set (GtkWidget *widget, + GtkStyle *prev_style) +{ + GimpStatusbar *statusbar = GIMP_STATUSBAR (widget); + + GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style); + + if (statusbar->icon_hash) + { + g_hash_table_unref (statusbar->icon_hash); + statusbar->icon_hash = NULL; + } +} + static void gimp_statusbar_hbox_size_request (GtkWidget *widget, GtkRequisition *requisition, @@ -551,7 +600,7 @@ gimp_statusbar_progress_message (GimpProgress *progress, { GdkPixbuf *pixbuf; - pixbuf = gimp_widget_load_icon (statusbar->label, icon_name, 16); + pixbuf = gimp_statusbar_load_icon (statusbar, icon_name); width += ICON_SPACING + gdk_pixbuf_get_width (pixbuf); @@ -601,8 +650,7 @@ gimp_statusbar_set_text (GimpStatusbar *statusbar, } if (icon_name) - statusbar->icon = gimp_widget_load_icon (statusbar->label, - icon_name, 16); + statusbar->icon = gimp_statusbar_load_icon (statusbar, icon_name); if (statusbar->icon) { @@ -1547,3 +1595,35 @@ gimp_statusbar_vprintf (const gchar *format, return message; } + +static GdkPixbuf * +gimp_statusbar_load_icon (GimpStatusbar *statusbar, + const gchar *icon_name) +{ + GdkPixbuf *icon; + + if (G_UNLIKELY (! statusbar->icon_hash)) + { + statusbar->icon_hash = + g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_object_unref); + } + + icon = g_hash_table_lookup (statusbar->icon_hash, icon_name); + + if (icon) + return g_object_ref (icon); + + icon = gimp_widget_load_icon (statusbar->label, icon_name, 16); + + /* this is not optimal but so what */ + if (g_hash_table_size (statusbar->icon_hash) > 16) + g_hash_table_remove_all (statusbar->icon_hash); + + g_hash_table_insert (statusbar->icon_hash, + g_strdup (icon_name), g_object_ref (icon)); + + return icon; +} diff --git a/app/display/gimpstatusbar.h b/app/display/gimpstatusbar.h index a0c7f8d7ae..3d517244ed 100644 --- a/app/display/gimpstatusbar.h +++ b/app/display/gimpstatusbar.h @@ -45,6 +45,7 @@ struct _GimpStatusbar guint seq_context_id; GdkPixbuf *icon; + GHashTable *icon_hash; guint temp_context_id; guint temp_timeout_id;