aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Persch <chpe@cvs.gnome.org>2004-07-05 07:46:26 +0800
committerChristian Persch <chpe@src.gnome.org>2004-07-05 07:46:26 +0800
commit1448306a534067e474d26a2e590c96c45cc6d40d (patch)
tree4f7b35478da01aacc7902138f4f1a8e959b88a94
parentf710ef7614259d91c45e56e63568c1e241232792 (diff)
downloadgsoc2013-epiphany-1448306a534067e474d26a2e590c96c45cc6d40d.tar
gsoc2013-epiphany-1448306a534067e474d26a2e590c96c45cc6d40d.tar.gz
gsoc2013-epiphany-1448306a534067e474d26a2e590c96c45cc6d40d.tar.bz2
gsoc2013-epiphany-1448306a534067e474d26a2e590c96c45cc6d40d.tar.lz
gsoc2013-epiphany-1448306a534067e474d26a2e590c96c45cc6d40d.tar.xz
gsoc2013-epiphany-1448306a534067e474d26a2e590c96c45cc6d40d.tar.zst
gsoc2013-epiphany-1448306a534067e474d26a2e590c96c45cc6d40d.zip
Cache the scaled spinner images to make creating new spinners very fast,
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.
-rw-r--r--ChangeLog19
-rw-r--r--lib/widgets/ephy-spinner.c819
2 files changed, 535 insertions, 303 deletions
diff --git a/ChangeLog b/ChangeLog
index f23bf90ac..4df849b1e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);