diff options
-rw-r--r-- | ChangeLog | 19 | ||||
-rw-r--r-- | lib/widgets/ephy-spinner.c | 819 |
2 files changed, 535 insertions, 303 deletions
@@ -1,3 +1,22 @@ +2004-07-05 Christian Persch <chpe@cvs.gnome.org> + + * lib/widgets/ephy-spinner.c: (ephy_spinner_cache_get_type), + (ephy_spinner_images_free), (ephy_spinner_images_copy), + (ephy_spinner_cache_unload), (extract_frame), + (ephy_spinner_cache_load), (compare_size), (scale_to_size), + (ephy_spinner_cache_get_images), (ephy_spinner_cache_init), + (ephy_spinner_cache_finalize), (ephy_spinner_cache_class_init), + (ephy_spinner_cache_ref), (ephy_spinner_load_images), + (ephy_spinner_unload_images), (icon_theme_changed_cb), + (ephy_spinner_init), (select_spinner_image), (ephy_spinner_expose), + (bump_spinner_frame_cb), (ephy_spinner_start), + (ephy_spinner_remove_update_callback), (ephy_spinner_stop), + (ephy_spinner_set_size), (ephy_spinner_size_request), + (ephy_spinner_finalize), (ephy_spinner_class_init): + + Cache the scaled spinner images to make creating new spinners very + fast, now that we use so many of them. + 2004-07-04 Christian Persch <chpe@cvs.gnome.org> * NEWS: diff --git a/lib/widgets/ephy-spinner.c b/lib/widgets/ephy-spinner.c index e84afa68a..d2b09bd37 100644 --- a/lib/widgets/ephy-spinner.c +++ b/lib/widgets/ephy-spinner.c @@ -39,30 +39,433 @@ #include <gtk/gtkicontheme.h> #include <gtk/gtkiconfactory.h> -#define spinner_DEFAULT_TIMEOUT 100 /* Milliseconds Per Frame */ +/* Spinner cache implementation */ + +#define EPHY_TYPE_SPINNER_CACHE (ephy_spinner_cache_get_type()) +#define EPHY_SPINNER_CACHE(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_SPINNER_CACHE, EphySpinnerCache)) +#define EPHY_SPINNER_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_SPINNER_CACHE, EphySpinnerCacheClass)) +#define EPHY_IS_SPINNER_CACHE(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_SPINNER_CACHE)) +#define EPHY_IS_SPINNER_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_SPINNER_CACHE)) +#define EPHY_SPINNER_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_SPINNER_CACHE, EphySpinnerCacheClass)) + +typedef struct _EphySpinnerCache EphySpinnerCache; +typedef struct _EphySpinnerCacheClass EphySpinnerCacheClass; +typedef struct _EphySpinnerCachePrivate EphySpinnerCachePrivate; +typedef struct _EphySpinnerImages EphySpinnerImages; + +struct _EphySpinnerImages +{ + GtkIconSize size; + int width; + int height; + GdkPixbuf *quiescent_pixbuf; + GList *images; +}; + +struct _EphySpinnerCacheClass +{ + GObjectClass parent_class; +}; + +struct _EphySpinnerCache +{ + GObject parent_object; + + /*< private >*/ + EphySpinnerCachePrivate *priv; +}; + +#define EPHY_SPINNER_CACHE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_SPINNER_CACHE, EphySpinnerCachePrivate)) + +struct _EphySpinnerCachePrivate +{ + GtkIconTheme *icon_theme; + EphySpinnerImages *originals; + /* List of EphySpinnerImages scaled to different sizes */ + GList *images; +}; + +static void ephy_spinner_cache_class_init (EphySpinnerCacheClass *klass); +static void ephy_spinner_cache_init (EphySpinnerCache *cache); + +static GObjectClass *cache_parent_class = NULL; + +static GType +ephy_spinner_cache_get_type (void) +{ + static GType type = 0; + + if (type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphySpinnerCacheClass), + NULL, + NULL, + (GClassInitFunc) ephy_spinner_cache_class_init, + NULL, + NULL, + sizeof (EphySpinnerCache), + 0, + (GInstanceInitFunc) ephy_spinner_cache_init + }; + + type = g_type_register_static (G_TYPE_OBJECT, + "EphySpinnerCache", + &our_info, 0); + } + + return type; +} + +static void +ephy_spinner_images_free (EphySpinnerImages *images) +{ + if (images != NULL) + { + g_list_foreach (images->images, (GFunc) g_object_unref, NULL); + g_object_unref (images->quiescent_pixbuf); + + g_free (images); + } +} + +static EphySpinnerImages * +ephy_spinner_images_copy (EphySpinnerImages *images) +{ + EphySpinnerImages *copy = g_new (EphySpinnerImages, 1); + + copy->size = images->size; + copy->width = images->width; + copy->height = images->height; + + copy->quiescent_pixbuf = g_object_ref (images->quiescent_pixbuf); + copy->images = g_list_copy (images->images); + g_list_foreach (copy->images, (GFunc) g_object_ref, NULL); + + return copy; +} + +static void +ephy_spinner_cache_unload (EphySpinnerCache *cache) +{ + g_list_foreach (cache->priv->images, (GFunc) ephy_spinner_images_free, NULL); + cache->priv->images = NULL; + cache->priv->originals = NULL; +} + +static GdkPixbuf * +extract_frame (GdkPixbuf *grid_pixbuf, + int x, + int y, + int size) +{ + GdkPixbuf *pixbuf; + + if (x + size > gdk_pixbuf_get_width (grid_pixbuf) || + y + size > gdk_pixbuf_get_height (grid_pixbuf)) + { + return NULL; + } + + pixbuf = gdk_pixbuf_new_subpixbuf (grid_pixbuf, + x, y, + size, size); + g_return_val_if_fail (pixbuf != NULL, NULL); + + return pixbuf; +} + +static void +ephy_spinner_cache_load (EphySpinnerCache *cache) +{ + EphySpinnerImages *images; + GdkPixbuf *icon_pixbuf, *pixbuf; + GtkIconInfo *icon_info; + int grid_width, grid_height, x, y, size, h, w; + const char *icon; + + LOG ("EphySpinnerCache loading") + + ephy_spinner_cache_unload (cache); + + START_PROFILER ("loading spinner animation") + + /* Load the animation */ + icon_info = gtk_icon_theme_lookup_icon (cache->priv->icon_theme, + "gnome-spinner", -1, 0); + if (icon_info == NULL) + { + STOP_PROFILER ("loading spinner animation") + + 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); + g_return_if_fail (icon != NULL); + + icon_pixbuf = gdk_pixbuf_new_from_file (icon, NULL); + 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; + } + + grid_width = gdk_pixbuf_get_width (icon_pixbuf); + grid_height = gdk_pixbuf_get_height (icon_pixbuf); + + images = g_new (EphySpinnerImages, 1); + cache->priv->images = g_list_prepend (NULL, images); + cache->priv->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) + { + pixbuf = extract_frame (icon_pixbuf, x, y, size); + + if (pixbuf) + { + images->images = + g_list_prepend (images->images, pixbuf); + } + else + { + g_warning ("Cannot extract frame from the grid\n"); + } + } + } + images->images = g_list_reverse (images->images); + + gtk_icon_info_free (icon_info); + g_object_unref (icon_pixbuf); + + /* Load the rest icon */ + icon_info = gtk_icon_theme_lookup_icon (cache->priv->icon_theme, + "gnome-spinner-rest", -1, 0); + if (icon_info == NULL) + { + STOP_PROFILER ("loading spinner animation") + + g_warning ("Throbber rest icon not found\n"); + return; + } + + size = gtk_icon_info_get_base_size (icon_info); + icon = gtk_icon_info_get_filename (icon_info); + g_return_if_fail (icon != NULL); + + 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 spinner rest icon\n"); + ephy_spinner_images_free (images); + return; + } + + 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); + + STOP_PROFILER ("loading spinner animation") +} + +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, + GtkIconSize size) +{ + EphySpinnerImages *images; + GdkPixbuf *pixbuf, *scaled_pixbuf; + GList *element, *l; + int h, w; + + LOG ("Getting animation images at size %d", size) + + if (cache->priv->images == NULL || cache->priv->originals == NULL) + { + return NULL; + } + + element = g_list_find_custom (cache->priv->images, + GINT_TO_POINTER (size), + (GCompareFunc) compare_size); + if (element != NULL) + { + return ephy_spinner_images_copy ((EphySpinnerImages *) element->data); + } + + if (!gtk_icon_size_lookup (size, &w, &h)) + { + g_warning ("Failed to lookup icon size\n"); + return NULL; + } + + images = g_new (EphySpinnerImages, 1); + images->size = size; + images->width = w; + images->height = h; + images->images = NULL; + + START_PROFILER ("scaling spinner animation") + + for (l = cache->priv->originals->images; l != NULL; l = l->next) + { + pixbuf = (GdkPixbuf *) l->data; + scaled_pixbuf = scale_to_size (pixbuf, w, h); + + images->images = g_list_prepend (images->images, scaled_pixbuf); + } + images->images = g_list_reverse (images->images); + + images->quiescent_pixbuf = + scale_to_size (cache->priv->originals->quiescent_pixbuf, w, h); + + /* store in cache */ + cache->priv->images = g_list_prepend (cache->priv->images, images); + + STOP_PROFILER ("scaling spinner animation") + + return ephy_spinner_images_copy (images); +} + +static void +ephy_spinner_cache_init (EphySpinnerCache *cache) +{ + cache->priv = EPHY_SPINNER_CACHE_GET_PRIVATE (cache); + + LOG ("EphySpinnerCache initialising") + + /* FIXME: icon theme is per-screen, not global */ + cache->priv->icon_theme = gtk_icon_theme_get_default (); + g_signal_connect_swapped (cache->priv->icon_theme, "changed", + G_CALLBACK (ephy_spinner_cache_load), cache); + + ephy_spinner_cache_load (cache); +} + +static void +ephy_spinner_cache_finalize (GObject *object) +{ + EphySpinnerCache *cache = EPHY_SPINNER_CACHE (object); + + LOG ("EphySpinnerCache finalising") + + g_signal_handlers_disconnect_by_func + (cache->priv->icon_theme, G_CALLBACK(ephy_spinner_cache_load), cache); + + ephy_spinner_cache_unload (cache); + + G_OBJECT_CLASS (cache_parent_class)->finalize (object); +} + +static void +ephy_spinner_cache_class_init (EphySpinnerCacheClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + cache_parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_spinner_cache_finalize; + + g_type_class_add_private (object_class, sizeof (EphySpinnerCachePrivate)); +} + +static EphySpinnerCache *spinner_cache = NULL; + +static EphySpinnerCache * +ephy_spinner_cache_ref (void) +{ + if (spinner_cache == NULL) + { + EphySpinnerCache **cache_ptr; + + spinner_cache = g_object_new (EPHY_TYPE_SPINNER_CACHE, NULL); + cache_ptr = &spinner_cache; + g_object_add_weak_pointer (G_OBJECT (spinner_cache), + (gpointer *) cache_ptr); + + return spinner_cache; + } + else + { + return g_object_ref (spinner_cache); + } +} + +/* Spinner implementation */ + +#define SPINNER_TIMEOUT 100 /* Milliseconds Per Frame */ #define EPHY_SPINNER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_SPINNER, EphySpinnerDetails)) struct EphySpinnerDetails { - GList *image_list; - GdkPixbuf *quiescent_pixbuf; GtkIconTheme *icon_theme; + EphySpinnerCache *cache; GtkIconSize size; - - int max_frame; - int delay; - int current_frame; - guint timer_task; + EphySpinnerImages *images; + GList *current_image; + guint timer_task; }; -static void ephy_spinner_class_init (EphySpinnerClass *class); -static void ephy_spinner_init (EphySpinner *spinner); -static void ephy_spinner_load_images (EphySpinner *spinner); -static void ephy_spinner_unload_images (EphySpinner *spinner); -static void ephy_spinner_remove_update_callback (EphySpinner *spinner); -static void ephy_spinner_theme_changed (GtkIconTheme *icon_theme, - EphySpinner *spinner); +static void ephy_spinner_class_init (EphySpinnerClass *class); +static void ephy_spinner_init (EphySpinner *spinner); static GObjectClass *parent_class = NULL; @@ -95,59 +498,42 @@ ephy_spinner_get_type (void) } static gboolean -is_throbbing (EphySpinner *spinner) -{ - return spinner->details->timer_task != 0; -} - -/* loop through all the images taking their union to compute the width and height of the spinner */ -static void -get_spinner_dimensions (EphySpinner *spinner, int *spinner_width, int* spinner_height) +ephy_spinner_load_images (EphySpinner *spinner) { - int current_width, current_height; - int pixbuf_width, pixbuf_height; - GList *image_list; - GdkPixbuf *pixbuf; + EphySpinnerDetails *details = spinner->details; - if (spinner->details->image_list == NULL) + if (details->images == NULL) { - ephy_spinner_load_images (spinner); - } - - current_width = 0; - current_height = 0; - - if (spinner->details->quiescent_pixbuf != NULL) - { - /* start with the quiescent image */ - current_width = gdk_pixbuf_get_width (spinner->details->quiescent_pixbuf); - current_height = gdk_pixbuf_get_height (spinner->details->quiescent_pixbuf); - } - - /* loop through all the installed images, taking the union */ - image_list = spinner->details->image_list; - while (image_list != NULL) - { - pixbuf = GDK_PIXBUF (image_list->data); - pixbuf_width = gdk_pixbuf_get_width (pixbuf); - pixbuf_height = gdk_pixbuf_get_height (pixbuf); + START_PROFILER ("ephy_spinner_load_images") - if (pixbuf_width > current_width) - { - current_width = pixbuf_width; - } + details->images = + ephy_spinner_cache_get_images (details->cache, details->size); - if (pixbuf_height > current_height) + if (details->images != NULL) { - current_height = pixbuf_height; + details->current_image = details->images->images; } - image_list = image_list->next; + STOP_PROFILER ("ephy_spinner_load_images") } - /* return the result */ - *spinner_width = current_width; - *spinner_height = current_height; + return details->images != NULL; +} + +static void +ephy_spinner_unload_images (EphySpinner *spinner) +{ + ephy_spinner_images_free (spinner->details->images); + spinner->details->images = NULL; + spinner->details->current_image = NULL; +} + +static void +icon_theme_changed_cb (GtkIconTheme *icon_theme, + EphySpinner *spinner) +{ + ephy_spinner_unload_images (spinner); + gtk_widget_queue_resize (GTK_WIDGET (spinner)); } static void @@ -162,66 +548,42 @@ ephy_spinner_init (EphySpinner *spinner) spinner->details = EPHY_SPINNER_GET_PRIVATE (spinner); - spinner->details->delay = spinner_DEFAULT_TIMEOUT; + spinner->details->cache = ephy_spinner_cache_ref (); + spinner->details->size = GTK_ICON_SIZE_INVALID; + /* FIXME: icon theme is per-screen, not global */ spinner->details->icon_theme = gtk_icon_theme_get_default (); - g_signal_connect_object (spinner->details->icon_theme, - "changed", - G_CALLBACK (ephy_spinner_theme_changed), - spinner, 0); - - spinner->details->quiescent_pixbuf = NULL; - spinner->details->image_list = NULL; - spinner->details->max_frame = 0; - spinner->details->current_frame = 0; - spinner->details->timer_task = 0; - spinner->details->size = GTK_ICON_SIZE_INVALID; -} + g_signal_connect (spinner->details->icon_theme, "changed", + G_CALLBACK (icon_theme_changed_cb), spinner); -/* handler for handling theme changes */ -static void -ephy_spinner_theme_changed (GtkIconTheme *icon_theme, EphySpinner *spinner) -{ - gtk_widget_hide (GTK_WIDGET (spinner)); - ephy_spinner_load_images (spinner); - gtk_widget_show (GTK_WIDGET (spinner)); - gtk_widget_queue_resize ( GTK_WIDGET (spinner)); } -/* here's the routine that selects the image to draw, based on the spinner's state */ - static GdkPixbuf * select_spinner_image (EphySpinner *spinner) { - GList *element; + EphySpinnerDetails *details = spinner->details; + EphySpinnerImages *images = details->images; + + g_return_val_if_fail (images != NULL, NULL); if (spinner->details->timer_task == 0) { - if (spinner->details->quiescent_pixbuf) + if (images->quiescent_pixbuf != NULL) { - return g_object_ref (spinner->details->quiescent_pixbuf); + return g_object_ref (details->images->quiescent_pixbuf); } - else - { - return NULL; - } - } - if (spinner->details->image_list == NULL) - { return NULL; } - element = g_list_nth (spinner->details->image_list, spinner->details->current_frame); - g_return_val_if_fail (element != NULL, NULL); + g_return_val_if_fail (details->current_image != NULL, NULL); - return g_object_ref (element->data); + return g_object_ref (details->current_image->data); } -/* handle expose events */ - static int -ephy_spinner_expose (GtkWidget *widget, GdkEventExpose *event) +ephy_spinner_expose (GtkWidget *widget, + GdkEventExpose *event) { EphySpinner *spinner = EPHY_SPINNER (widget); GdkPixbuf *pixbuf; @@ -229,11 +591,14 @@ ephy_spinner_expose (GtkWidget *widget, GdkEventExpose *event) int x_offset, y_offset, width, height; GdkRectangle pix_area, dest; - if (!GTK_WIDGET_DRAWABLE (spinner)) return TRUE; + if (!GTK_WIDGET_DRAWABLE (spinner)) + { + return TRUE; + } - if (spinner->details->image_list == NULL) + if (!ephy_spinner_load_images (spinner)) { - ephy_spinner_load_images (spinner); + return TRUE; } pixbuf = select_spinner_image (spinner); @@ -274,27 +639,32 @@ ephy_spinner_expose (GtkWidget *widget, GdkEventExpose *event) return FALSE; } -/* here's the actual timeout task to bump the frame and schedule a redraw */ - static gboolean -bump_spinner_frame (gpointer callback_data) +bump_spinner_frame_cb (EphySpinner *spinner) { - EphySpinner *spinner; - - spinner = EPHY_SPINNER (callback_data); + GList *frame; if (!GTK_WIDGET_DRAWABLE (spinner)) { return TRUE; } - spinner->details->current_frame += 1; - if (spinner->details->current_frame > spinner->details->max_frame - 1) + frame = spinner->details->current_image; + + if (g_list_next (frame) != NULL) + { + frame = frame->next; + } + else { - spinner->details->current_frame = 0; + frame = g_list_first (frame); } + spinner->details->current_image = frame; + gtk_widget_queue_draw (GTK_WIDGET (spinner)); + + /* run again */ return TRUE; } @@ -307,21 +677,21 @@ bump_spinner_frame (gpointer callback_data) void ephy_spinner_start (EphySpinner *spinner) { - if (is_throbbing (spinner)) + if (spinner->details->timer_task == 0) { - return; - } - if (spinner->details->timer_task != 0) - { - g_source_remove (spinner->details->timer_task); - } + if (spinner->details->images != NULL) + { + /* reset to first frame */ + spinner->details->current_image = + spinner->details->images->images; + } - /* reset the frame count */ - spinner->details->current_frame = 0; - spinner->details->timer_task = g_timeout_add (spinner->details->delay, - bump_spinner_frame, - spinner); + spinner->details->timer_task = + g_timeout_add (SPINNER_TIMEOUT, + (GSourceFunc) bump_spinner_frame_cb, + spinner); + } } static void @@ -330,9 +700,8 @@ ephy_spinner_remove_update_callback (EphySpinner *spinner) if (spinner->details->timer_task != 0) { g_source_remove (spinner->details->timer_task); + spinner->details->timer_task = 0; } - - spinner->details->timer_task = 0; } /** @@ -344,169 +713,11 @@ ephy_spinner_remove_update_callback (EphySpinner *spinner) void ephy_spinner_stop (EphySpinner *spinner) { - if (!is_throbbing (spinner)) - { - return; - } - - ephy_spinner_remove_update_callback (spinner); - gtk_widget_queue_draw (GTK_WIDGET (spinner)); - -} - -/* routines to load the images used to draw the spinner */ - -/* unload all the images, and the list itself */ - -static void -ephy_spinner_unload_images (EphySpinner *spinner) -{ - if (spinner->details->quiescent_pixbuf != NULL) - { - g_object_unref (spinner->details->quiescent_pixbuf); - spinner->details->quiescent_pixbuf = NULL; - } - - /* unref all the images in the list, and then let go of the list itself */ - g_list_foreach (spinner->details->image_list, (GFunc) g_object_unref, NULL); - g_list_free (spinner->details->image_list); - spinner->details->image_list = NULL; - - spinner->details->current_frame = 0; -} - -static GdkPixbuf * -scale_to_real_size (EphySpinner *spinner, GdkPixbuf *pixbuf) -{ - GdkPixbuf *result; - int sw, sh, pw, ph; - - if (spinner->details->size == GTK_ICON_SIZE_INVALID) - { - return g_object_ref (pixbuf); - } - - if (!gtk_icon_size_lookup (spinner->details->size, &sw, &sh)) - { - return NULL; - } - - pw = gdk_pixbuf_get_width (pixbuf); - ph = gdk_pixbuf_get_height (pixbuf); - - if (pw != sw || ph != sh) - { - result = gdk_pixbuf_scale_simple (pixbuf, sw, sh, - GDK_INTERP_BILINEAR); - } - else - { - result = g_object_ref (pixbuf); - } - - return result; -} - -static GdkPixbuf * -extract_frame (EphySpinner *spinner, GdkPixbuf *grid_pixbuf, int x, int y, int size) -{ - GdkPixbuf *pixbuf, *result; - - if (x + size > gdk_pixbuf_get_width (grid_pixbuf) || - y + size > gdk_pixbuf_get_height (grid_pixbuf)) - { - return NULL; - } - - pixbuf = gdk_pixbuf_new_subpixbuf (grid_pixbuf, - x, y, - size, size); - g_return_val_if_fail (pixbuf != NULL, NULL); - - result = scale_to_real_size (spinner, pixbuf); - g_object_unref (pixbuf); - - return result; -} - -/* load all of the images of the spinner sequentially */ -static void -ephy_spinner_load_images (EphySpinner *spinner) -{ - int grid_width, grid_height, x, y, size; - const char *icon; - GdkPixbuf *icon_pixbuf, *pixbuf; - GList *image_list; - GtkIconInfo *icon_info; - - ephy_spinner_unload_images (spinner); - - START_PROFILER ("loading spinner animation") - - /* Load the animation */ - icon_info = gtk_icon_theme_lookup_icon (spinner->details->icon_theme, - "gnome-spinner", -1, 0); - if (icon_info == NULL) - { - STOP_PROFILER ("loading spinner animation") - - g_warning ("Throbber animation not found"); - return; - } - - size = gtk_icon_info_get_base_size (icon_info); - icon = gtk_icon_info_get_filename (icon_info); - g_return_if_fail (icon != NULL); - - icon_pixbuf = gdk_pixbuf_new_from_file (icon, NULL); - grid_width = gdk_pixbuf_get_width (icon_pixbuf); - grid_height = gdk_pixbuf_get_height (icon_pixbuf); - - image_list = NULL; - for (y = 0; y < grid_height; y += size) - { - for (x = 0; x < grid_width ; x += size) - { - pixbuf = extract_frame (spinner, icon_pixbuf, x, y, size); - - if (pixbuf) - { - image_list = g_list_prepend (image_list, pixbuf); - } - else - { - g_warning ("Cannot extract frame from the grid"); - } - } - } - spinner->details->image_list = g_list_reverse (image_list); - spinner->details->max_frame = g_list_length (spinner->details->image_list); - - gtk_icon_info_free (icon_info); - g_object_unref (icon_pixbuf); - - /* Load the rest icon */ - icon_info = gtk_icon_theme_lookup_icon (spinner->details->icon_theme, - "gnome-spinner-rest", -1, 0); - if (icon_info == NULL) + if (spinner->details->timer_task != 0) { - STOP_PROFILER ("loading spinner animation") - - g_warning ("Throbber rest icon not found"); - return; + ephy_spinner_remove_update_callback (spinner); + gtk_widget_queue_draw (GTK_WIDGET (spinner)); } - - size = gtk_icon_info_get_base_size (icon_info); - icon = gtk_icon_info_get_filename (icon_info); - g_return_if_fail (icon != NULL); - - icon_pixbuf = gdk_pixbuf_new_from_file (icon, NULL); - spinner->details->quiescent_pixbuf = scale_to_real_size (spinner, icon_pixbuf); - - g_object_unref (icon_pixbuf); - gtk_icon_info_free (icon_info); - - STOP_PROFILER ("loading spinner animation") } /* @@ -515,10 +726,11 @@ ephy_spinner_load_images (EphySpinner *spinner) * @size: the size of type %GtkIconSize * * Set the size of the spinner. Use %GTK_ICON_SIZE_INVALID to use the - * native size of the icon. + * native size of the icons. **/ void -ephy_spinner_set_size (EphySpinner *spinner, GtkIconSize size) +ephy_spinner_set_size (EphySpinner *spinner, + GtkIconSize size) { if (size != spinner->details->size) { @@ -530,25 +742,23 @@ ephy_spinner_set_size (EphySpinner *spinner, GtkIconSize size) } } -/* handle setting the size */ - static void -ephy_spinner_size_request (GtkWidget *widget, GtkRequisition *requisition) +ephy_spinner_size_request (GtkWidget *widget, + GtkRequisition *requisition) { EphySpinner *spinner = EPHY_SPINNER (widget); - int width = 0, height = 0; - if (spinner->details->size == GTK_ICON_SIZE_INVALID) + if (!ephy_spinner_load_images (spinner)) { - get_spinner_dimensions (spinner, &width, &height); - } - else - { - gtk_icon_size_lookup (spinner->details->size, &width, &height); + requisition->width = requisition->height = 0; + gtk_icon_size_lookup (spinner->details->size, + &requisition->width, + &requisition->height); + return; } - requisition->width = width; - requisition->height = height; + requisition->width = spinner->details->images->width; + requisition->height = spinner->details->images->height; /* allocate some extra margin so we don't butt up against toolbar edges */ if (spinner->details->size != GTK_ICON_SIZE_MENU) @@ -563,20 +773,23 @@ ephy_spinner_finalize (GObject *object) { EphySpinner *spinner = EPHY_SPINNER (object); + g_signal_handlers_disconnect_by_func + (spinner->details->icon_theme, + G_CALLBACK (icon_theme_changed_cb), spinner); + ephy_spinner_remove_update_callback (spinner); ephy_spinner_unload_images (spinner); + g_object_unref (spinner->details->cache); + G_OBJECT_CLASS (parent_class)->finalize (object); } static void ephy_spinner_class_init (EphySpinnerClass *class) { - GObjectClass *object_class; - GtkWidgetClass *widget_class; - - object_class = G_OBJECT_CLASS (class); - widget_class = GTK_WIDGET_CLASS (class); + GObjectClass *object_class = G_OBJECT_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); parent_class = g_type_class_peek_parent (class); |