From 2f82409c7697e94ac001e4b0a4266e5357ac4ae7 Mon Sep 17 00:00:00 2001 From: Christian Persch Date: Fri, 29 Sep 2006 19:24:03 +0000 Subject: Fix spinner with new g-i-t. Fixes bug #330415. Fix a crash when failing to 2006-09-29 Christian Persch * lib/widgets/ephy-spinner.c: (ephy_spinner_images_free), (ephy_spinner_cache_data_unload), (scale_to_size), (ephy_spinner_images_load), (ephy_spinner_cache_data_new), (ephy_spinner_cache_data_free), (ephy_spinner_cache_get_images), (ephy_spinner_cache_finalize), (ephy_spinner_cache_class_init), (ephy_spinner_cache_ref), (ephy_spinner_init), (ephy_spinner_set_size), (ephy_spinner_size_request): * lib/widgets/testspinner.c: Fix spinner with new g-i-t. Fixes bug #330415. Fix a crash when failing to load some icon data, Gedit bug #357456. --- lib/widgets/ephy-spinner.c | 334 +++++++++++++++++++++++---------------------- lib/widgets/testspinner.c | 2 +- 2 files changed, 172 insertions(+), 164 deletions(-) (limited to 'lib/widgets') diff --git a/lib/widgets/ephy-spinner.c b/lib/widgets/ephy-spinner.c index 964c8e36e..c713fb9ee 100644 --- a/lib/widgets/ephy-spinner.c +++ b/lib/widgets/ephy-spinner.c @@ -68,6 +68,12 @@ struct _EphySpinnerCache #define EPHY_SPINNER_CACHE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_SPINNER_CACHE, EphySpinnerCachePrivate)) +struct _EphySpinnerCachePrivate +{ + /* Hash table of GdkScreen -> EphySpinnerCacheData */ + GHashTable *hash; +}; + typedef struct { GtkIconSize size; @@ -77,25 +83,22 @@ typedef struct GList *images; } EphySpinnerImages; +#define LAST_ICON_SIZE GTK_ICON_SIZE_DIALOG + 1 +#define SPINNER_ICON_NAME "gnome-spinner" +#define SPINNER_REST_ICON_NAME "gnome-spinner-rest" +#define EPHY_SPINNER_IMAGES_INVALID ((EphySpinnerImages *) 0x1) + typedef struct { GdkScreen *screen; GtkIconTheme *icon_theme; - EphySpinnerImages *originals; - /* List of EphySpinnerImages scaled to different sizes */ - GList *images; + EphySpinnerImages *images[LAST_ICON_SIZE]; } EphySpinnerCacheData; -struct _EphySpinnerCachePrivate -{ - /* Hash table of GdkScreen -> EphySpinnerCacheData */ - GHashTable *hash; -}; - static void ephy_spinner_cache_class_init (EphySpinnerCacheClass *klass); static void ephy_spinner_cache_init (EphySpinnerCache *cache); -static GObjectClass *cache_parent_class = NULL; +static GObjectClass *ephy_spinner_cache_parent_class = NULL; static GType ephy_spinner_cache_get_type (void) @@ -131,6 +134,8 @@ ephy_spinner_images_free (EphySpinnerImages *images) if (images != NULL) { g_list_foreach (images->images, (GFunc) g_object_unref, NULL); + g_list_free (images->images); + g_object_unref (images->quiescent_pixbuf); g_free (images); @@ -156,13 +161,23 @@ ephy_spinner_images_copy (EphySpinnerImages *images) static void ephy_spinner_cache_data_unload (EphySpinnerCacheData *data) { + GtkIconSize size; + EphySpinnerImages *images; + g_return_if_fail (data != NULL); LOG ("EphySpinnerDataCache unload for screen %p", data->screen); - g_list_foreach (data->images, (GFunc) ephy_spinner_images_free, NULL); - data->images = NULL; - data->originals = NULL; + for (size = GTK_ICON_SIZE_INVALID; size < LAST_ICON_SIZE; ++size) + { + images = data->images[size]; + if (images != NULL && images != EPHY_SPINNER_IMAGES_INVALID) + { + ephy_spinner_images_free (images); + } + + data->images[size] = NULL; + } } static GdkPixbuf * @@ -187,60 +202,106 @@ extract_frame (GdkPixbuf *grid_pixbuf, return pixbuf; } -static void -ephy_spinner_cache_data_load (EphySpinnerCacheData *data) +static GdkPixbuf * +scale_to_size (GdkPixbuf *pixbuf, + int dw, + int dh) +{ + GdkPixbuf *result; + int pw, ph; + + g_return_val_if_fail (pixbuf != NULL, NULL); + + pw = gdk_pixbuf_get_width (pixbuf); + ph = gdk_pixbuf_get_height (pixbuf); + + if (pw != dw || ph != dh) + { + result = gdk_pixbuf_scale_simple (pixbuf, dw, dh, + GDK_INTERP_BILINEAR); + g_object_unref (pixbuf); + return result; + } + + return pixbuf; +} + +static EphySpinnerImages * +ephy_spinner_images_load (GdkScreen *screen, + GtkIconTheme *icon_theme, + GtkIconSize icon_size) { EphySpinnerImages *images; + GdkPixbuf *rest_pixbuf = NULL; GdkPixbuf *icon_pixbuf, *pixbuf; - GtkIconInfo *icon_info; - int grid_width, grid_height, x, y, size, h, w; + GtkIconInfo *icon_info = NULL; + int grid_width, grid_height, x, y, requested_size, size, h, w, isw, ish; const char *icon; + GList *list = NULL, *l; - g_return_if_fail (data != NULL); + LOG ("EphySpinnerCacheData loading for screen %p at size %d", screen, icon_size); - LOG ("EphySpinnerCacheData loading for screen %p", data->screen); + START_PROFILER ("loading spinner animation") - ephy_spinner_cache_data_unload (data); + if (!gtk_icon_size_lookup_for_settings (gtk_settings_get_for_screen (screen), + icon_size, &isw, &ish)) goto loser; - START_PROFILER ("loading spinner animation") + requested_size = MAX (ish, isw); - /* Load the animation */ - icon_info = gtk_icon_theme_lookup_icon (data->icon_theme, - "gnome-spinner", -1, 0); + /* Load the rest icon */ + icon_info = gtk_icon_theme_lookup_icon (icon_theme, + SPINNER_REST_ICON_NAME, + requested_size, 0); if (icon_info == NULL) { - STOP_PROFILER ("loading spinner animation") + g_warning ("Throbber rest icon not found"); + goto loser; + } - g_warning ("Throbber animation not found\n"); - return; + size = gtk_icon_info_get_base_size (icon_info); + icon = gtk_icon_info_get_filename (icon_info); + if (icon == NULL) goto loser; + + rest_pixbuf = gdk_pixbuf_new_from_file (icon, NULL); + gtk_icon_info_free (icon_info); + + if (rest_pixbuf == NULL) + { + g_warning ("Could not load spinner rest icon"); + goto loser; + } + + if (size > requested_size) + { + rest_pixbuf = scale_to_size (rest_pixbuf, isw, ish); + } + + /* Load the animation */ + icon_info = gtk_icon_theme_lookup_icon (icon_theme, + SPINNER_ICON_NAME, + requested_size, 0); + if (icon_info == NULL) + { + g_warning ("Throbber animation not found"); + goto loser; } size = gtk_icon_info_get_base_size (icon_info); icon = gtk_icon_info_get_filename (icon_info); - g_return_if_fail (icon != NULL); + if (icon == NULL) goto loser; icon_pixbuf = gdk_pixbuf_new_from_file (icon, NULL); + gtk_icon_info_free (icon_info); + if (icon_pixbuf == NULL) { - STOP_PROFILER ("loading spinner animation") - - g_warning ("Could not load the spinner file\n"); - gtk_icon_info_free (icon_info); - return; + g_warning ("Could not load the spinner file"); + goto loser; } grid_width = gdk_pixbuf_get_width (icon_pixbuf); grid_height = gdk_pixbuf_get_height (icon_pixbuf); - images = g_new (EphySpinnerImages, 1); - data->images = g_list_prepend (NULL, images); - data->originals = images; - - images->size = GTK_ICON_SIZE_INVALID; - images->width = images->height = size; - images->images = NULL; - images->quiescent_pixbuf = NULL; - for (y = 0; y < grid_height; y += size) { for (x = 0; x < grid_width ; x += size) @@ -249,55 +310,54 @@ ephy_spinner_cache_data_load (EphySpinnerCacheData *data) if (pixbuf) { - images->images = - g_list_prepend (images->images, pixbuf); + list = g_list_prepend (list, pixbuf); } else { - g_warning ("Cannot extract frame from the grid\n"); + g_warning ("Cannot extract frame (%d, %d) from the grid\n", x, y); } } } - images->images = g_list_reverse (images->images); - gtk_icon_info_free (icon_info); + list = g_list_reverse (list); g_object_unref (icon_pixbuf); - /* Load the rest icon */ - icon_info = gtk_icon_theme_lookup_icon (data->icon_theme, - "gnome-spinner-rest", -1, 0); - if (icon_info == NULL) - { - STOP_PROFILER ("loading spinner animation") + if (list == NULL) goto loser; - g_warning ("Throbber rest icon not found\n"); - return; + if (size > requested_size) + { + for (l = list; l != NULL; l = l->next) + { + l->data = scale_to_size (l->data, isw, ish); + } } + + /* Now we've successfully got all the data */ + images = g_new (EphySpinnerImages, 1); - size = gtk_icon_info_get_base_size (icon_info); - icon = gtk_icon_info_get_filename (icon_info); - g_return_if_fail (icon != NULL); + images->size = icon_size; + images->width = images->height = requested_size; + images->images = list; + images->quiescent_pixbuf = rest_pixbuf; - icon_pixbuf = gdk_pixbuf_new_from_file (icon, NULL); - gtk_icon_info_free (icon_info); + STOP_PROFILER ("loading spinner animation") - if (icon_pixbuf == NULL) - { - STOP_PROFILER ("loading spinner animation") + return images; - g_warning ("Could not load spinner rest icon\n"); - ephy_spinner_images_free (images); - return; +loser: + if (icon_info) + { + gtk_icon_info_free (icon_info); } - - images->quiescent_pixbuf = icon_pixbuf; - - w = gdk_pixbuf_get_width (icon_pixbuf); - h = gdk_pixbuf_get_height (icon_pixbuf); - images->width = MAX (images->width, w); - images->height = MAX (images->height, h); + if (rest_pixbuf) + { + g_object_unref (rest_pixbuf); + } + g_list_foreach (list, (GFunc) g_object_unref, NULL); STOP_PROFILER ("loading spinner animation") + + return NULL; } static EphySpinnerCacheData * @@ -310,11 +370,9 @@ ephy_spinner_cache_data_new (GdkScreen *screen) data->screen = screen; data->icon_theme = gtk_icon_theme_get_for_screen (screen); g_signal_connect_swapped (data->icon_theme, "changed", - G_CALLBACK (ephy_spinner_cache_data_load), + G_CALLBACK (ephy_spinner_cache_data_unload), data); - ephy_spinner_cache_data_load (data); - return data; } @@ -326,56 +384,17 @@ ephy_spinner_cache_data_free (EphySpinnerCacheData *data) g_signal_handlers_disconnect_by_func (data->icon_theme, - G_CALLBACK (ephy_spinner_cache_data_load), data); + G_CALLBACK (ephy_spinner_cache_data_unload), data); ephy_spinner_cache_data_unload (data); g_free (data); } -static int -compare_size (gconstpointer images_ptr, - gconstpointer size_ptr) -{ - const EphySpinnerImages *images = (const EphySpinnerImages *) images_ptr; - GtkIconSize size = GPOINTER_TO_INT (size_ptr); - - if (images->size == size) - { - return 0; - } - - return -1; -} - -static GdkPixbuf * -scale_to_size (GdkPixbuf *pixbuf, - int dw, - int dh) -{ - GdkPixbuf *result; - int pw, ph; - - pw = gdk_pixbuf_get_width (pixbuf); - ph = gdk_pixbuf_get_height (pixbuf); - - if (pw != dw || ph != dh) - { - result = gdk_pixbuf_scale_simple (pixbuf, dw, dh, - GDK_INTERP_BILINEAR); - } - else - { - result = g_object_ref (pixbuf); - } - - return result; -} - static EphySpinnerImages * ephy_spinner_cache_get_images (EphySpinnerCache *cache, GdkScreen *screen, - GtkIconSize size) + GtkIconSize icon_size) { EphySpinnerCachePrivate *priv = cache->priv; EphySpinnerCacheData *data; @@ -385,7 +404,15 @@ ephy_spinner_cache_get_images (EphySpinnerCache *cache, GList *element, *l; int h, w; - LOG ("Getting animation images at size %d for screen %p", size, screen); + LOG ("Getting animation images for screen %p at size %d", screen, icon_size); + + g_return_val_if_fail (icon_size >= 0 && icon_size < LAST_ICON_SIZE, NULL); + + /* Backward compat: "invalid" meant "native" size which doesn't exist anymore */ + if (icon_size == GTK_ICON_SIZE_INVALID) + { + icon_size = GTK_ICON_SIZE_DIALOG; + } data = g_hash_table_lookup (priv->hash, screen); if (data == NULL) @@ -394,51 +421,30 @@ ephy_spinner_cache_get_images (EphySpinnerCache *cache, g_hash_table_insert (priv->hash, screen, data); } - if (data->images == NULL || data->originals == NULL) + images = data->images[icon_size]; + if (images == EPHY_SPINNER_IMAGES_INVALID) { /* Load failed, but don't try endlessly again! */ return NULL; } - element = g_list_find_custom (data->images, - GINT_TO_POINTER (size), - (GCompareFunc) compare_size); - if (element != NULL) - { - return ephy_spinner_images_copy ((EphySpinnerImages *) element->data); - } - - settings = gtk_settings_get_for_screen (screen); - if (!gtk_icon_size_lookup_for_settings (settings, size, &w, &h)) + if (images != NULL) { - g_warning ("Failed to look up icon size\n"); - return NULL; + /* Return cached data */ + return ephy_spinner_images_copy (images); } - images = g_new (EphySpinnerImages, 1); - images->size = size; - images->width = w; - images->height = h; - images->images = NULL; - - START_PROFILER ("scaling spinner animation") + images = ephy_spinner_images_load (screen, data->icon_theme, icon_size); - for (l = data->originals->images; l != NULL; l = l->next) + if (images == NULL) { - pixbuf = (GdkPixbuf *) l->data; - scaled_pixbuf = scale_to_size (pixbuf, w, h); + /* Mark as failed-to-load */ + data->images[icon_size] = EPHY_SPINNER_IMAGES_INVALID; - images->images = g_list_prepend (images->images, scaled_pixbuf); + return NULL; } - images->images = g_list_reverse (images->images); - - images->quiescent_pixbuf = - scale_to_size (data->originals->quiescent_pixbuf, w, h); - /* store in cache */ - data->images = g_list_prepend (data->images, images); - - STOP_PROFILER ("scaling spinner animation") + data->images[icon_size] = images; return ephy_spinner_images_copy (images); } @@ -463,11 +469,11 @@ ephy_spinner_cache_finalize (GObject *object) EphySpinnerCache *cache = EPHY_SPINNER_CACHE (object); EphySpinnerCachePrivate *priv = cache->priv; - LOG ("EphySpinnerCache finalising"); - g_hash_table_destroy (priv->hash); - G_OBJECT_CLASS (cache_parent_class)->finalize (object); + LOG ("EphySpinnerCache finalised"); + + G_OBJECT_CLASS (ephy_spinner_cache_parent_class)->finalize (object); } static void @@ -475,7 +481,7 @@ ephy_spinner_cache_class_init (EphySpinnerCacheClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - cache_parent_class = g_type_class_peek_parent (klass); + ephy_spinner_cache_parent_class = g_type_class_peek_parent (klass); object_class->finalize = ephy_spinner_cache_finalize; @@ -498,10 +504,8 @@ ephy_spinner_cache_ref (void) return spinner_cache; } - else - { - return g_object_ref (spinner_cache); - } + + return g_object_ref (spinner_cache); } /* Spinner implementation */ @@ -611,7 +615,7 @@ ephy_spinner_init (EphySpinner *spinner) details = spinner->details = EPHY_SPINNER_GET_PRIVATE (spinner); details->cache = ephy_spinner_cache_ref (); - details->size = GTK_ICON_SIZE_INVALID; + details->size = GTK_ICON_SIZE_DIALOG; details->spinning = FALSE; details->timeout = SPINNER_TIMEOUT; } @@ -800,13 +804,17 @@ ephy_spinner_stop (EphySpinner *spinner) * @spinner: a #EphySpinner * @size: the size of type %GtkIconSize * - * Set the size of the spinner. Use %GTK_ICON_SIZE_INVALID to use the - * native size of the icons. + * Set the size of the spinner. **/ void ephy_spinner_set_size (EphySpinner *spinner, GtkIconSize size) { + if (size == GTK_ICON_SIZE_INVALID) + { + size = GTK_ICON_SIZE_DIALOG; + } + if (size != spinner->details->size) { ephy_spinner_unload_images (spinner); @@ -867,8 +875,8 @@ ephy_spinner_size_request (GtkWidget *widget, /* allocate some extra margin so we don't butt up against toolbar edges */ if (spinner->details->size != GTK_ICON_SIZE_MENU) { - requisition->width += 4; - requisition->height += 4; + requisition->width += 2; + requisition->height += 2; } } diff --git a/lib/widgets/testspinner.c b/lib/widgets/testspinner.c index 7ed4d3c52..46eca658c 100644 --- a/lib/widgets/testspinner.c +++ b/lib/widgets/testspinner.c @@ -22,7 +22,7 @@ #include #define COMPILING_TESTSPINNER -#define LOG(msg, args...) G_STMT_START { } G_STMT_END +#define LOG(msg, args...) g_print(msg, ## args); g_print ("\n") #define START_PROFILER(name) #define STOP_PROFILER(name) -- cgit v1.2.3