diff options
author | Christian Persch <chpe@cvs.gnome.org> | 2005-10-02 21:56:48 +0800 |
---|---|---|
committer | Christian Persch <chpe@src.gnome.org> | 2005-10-02 21:56:48 +0800 |
commit | a2bbf31b11386534161bdaf16fdec29cbd685673 (patch) | |
tree | a02af9189584dbf50c7ba7e7a72fbd03bb06ff32 /lib/widgets/ephy-spinner.c | |
parent | 456c0769c5dccb2c8ce312031219624e6edddc5c (diff) | |
download | gsoc2013-epiphany-a2bbf31b11386534161bdaf16fdec29cbd685673.tar.gz gsoc2013-epiphany-a2bbf31b11386534161bdaf16fdec29cbd685673.tar.zst gsoc2013-epiphany-a2bbf31b11386534161bdaf16fdec29cbd685673.zip |
Don't include config.h here.
2005-10-02 Christian Persch <chpe@cvs.gnome.org>
* lib/ephy-debug.h:
Don't include config.h here.
* lib/widgets/ephy-spinner.c: (ephy_spinner_cache_data_unload),
(ephy_spinner_cache_data_load), (ephy_spinner_cache_data_new),
(ephy_spinner_cache_data_free), (ephy_spinner_cache_get_images),
(ephy_spinner_cache_init), (ephy_spinner_cache_finalize),
(ephy_spinner_load_images), (ephy_spinner_init),
(bump_spinner_frame_cb), (ephy_spinner_start),
(ephy_spinner_set_timeout), (ephy_spinner_finalize),
(ephy_spinner_screen_changed), (ephy_spinner_class_init):
Make spinner multihead safe.
* lib/widgets/testspinner.c:
Add a tiny spinner test program.
Diffstat (limited to 'lib/widgets/ephy-spinner.c')
-rw-r--r-- | lib/widgets/ephy-spinner.c | 233 |
1 files changed, 177 insertions, 56 deletions
diff --git a/lib/widgets/ephy-spinner.c b/lib/widgets/ephy-spinner.c index 34876cf95..5d6ff5916 100644 --- a/lib/widgets/ephy-spinner.c +++ b/lib/widgets/ephy-spinner.c @@ -28,10 +28,12 @@ * $Id$ */ +#ifndef COMPILING_TESTSPINNER #include "config.h" +#include "ephy-debug.h" +#endif #include "ephy-spinner.h" -#include "ephy-debug.h" #include <gdk-pixbuf/gdk-pixbuf.h> #include <gtk/gtkicontheme.h> @@ -50,16 +52,6 @@ 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 { @@ -76,12 +68,28 @@ struct _EphySpinnerCache #define EPHY_SPINNER_CACHE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_SPINNER_CACHE, EphySpinnerCachePrivate)) -struct _EphySpinnerCachePrivate +typedef struct { + GtkIconSize size; + int width; + int height; + GdkPixbuf *quiescent_pixbuf; + GList *images; +} EphySpinnerImages; + +typedef struct +{ + GdkScreen *screen; GtkIconTheme *icon_theme; EphySpinnerImages *originals; /* List of EphySpinnerImages scaled to different sizes */ GList *images; +} EphySpinnerCacheData; + +struct _EphySpinnerCachePrivate +{ + /* Hash table of GdkScreen -> EphySpinnerCacheData */ + GHashTable *hash; }; static void ephy_spinner_cache_class_init (EphySpinnerCacheClass *klass); @@ -146,11 +154,15 @@ ephy_spinner_images_copy (EphySpinnerImages *images) } static void -ephy_spinner_cache_unload (EphySpinnerCache *cache) +ephy_spinner_cache_data_unload (EphySpinnerCacheData *data) { - g_list_foreach (cache->priv->images, (GFunc) ephy_spinner_images_free, NULL); - cache->priv->images = NULL; - cache->priv->originals = NULL; + 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; } static GdkPixbuf * @@ -176,7 +188,7 @@ extract_frame (GdkPixbuf *grid_pixbuf, } static void -ephy_spinner_cache_load (EphySpinnerCache *cache) +ephy_spinner_cache_data_load (EphySpinnerCacheData *data) { EphySpinnerImages *images; GdkPixbuf *icon_pixbuf, *pixbuf; @@ -184,14 +196,16 @@ ephy_spinner_cache_load (EphySpinnerCache *cache) int grid_width, grid_height, x, y, size, h, w; const char *icon; - LOG ("EphySpinnerCache loading"); + g_return_if_fail (data != NULL); + + LOG ("EphySpinnerCacheData loading for screen %p", data->screen); - ephy_spinner_cache_unload (cache); + ephy_spinner_cache_data_unload (data); START_PROFILER ("loading spinner animation") /* Load the animation */ - icon_info = gtk_icon_theme_lookup_icon (cache->priv->icon_theme, + icon_info = gtk_icon_theme_lookup_icon (data->icon_theme, "gnome-spinner", -1, 0); if (icon_info == NULL) { @@ -219,8 +233,8 @@ ephy_spinner_cache_load (EphySpinnerCache *cache) 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; + data->images = g_list_prepend (NULL, images); + data->originals = images; images->size = GTK_ICON_SIZE_INVALID; images->width = images->height = size; @@ -250,7 +264,7 @@ ephy_spinner_cache_load (EphySpinnerCache *cache) g_object_unref (icon_pixbuf); /* Load the rest icon */ - icon_info = gtk_icon_theme_lookup_icon (cache->priv->icon_theme, + icon_info = gtk_icon_theme_lookup_icon (data->icon_theme, "gnome-spinner-rest", -1, 0); if (icon_info == NULL) { @@ -286,6 +300,39 @@ ephy_spinner_cache_load (EphySpinnerCache *cache) STOP_PROFILER ("loading spinner animation") } +static EphySpinnerCacheData * +ephy_spinner_cache_data_new (GdkScreen *screen) +{ + EphySpinnerCacheData *data; + + data = g_new0 (EphySpinnerCacheData, 1); + + 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), + data); + + ephy_spinner_cache_data_load (data); + + return data; +} + +static void +ephy_spinner_cache_data_free (EphySpinnerCacheData *data) +{ + g_return_if_fail (data != NULL); + g_return_if_fail (data->icon_theme != NULL); + + g_signal_handlers_disconnect_by_func + (data->icon_theme, + G_CALLBACK (ephy_spinner_cache_data_load), data); + + ephy_spinner_cache_data_unload (data); + + g_free (data); +} + static int compare_size (gconstpointer images_ptr, gconstpointer size_ptr) @@ -327,21 +374,33 @@ scale_to_size (GdkPixbuf *pixbuf, static EphySpinnerImages * ephy_spinner_cache_get_images (EphySpinnerCache *cache, + GdkScreen *screen, GtkIconSize size) { + EphySpinnerCachePrivate *priv = cache->priv; + EphySpinnerCacheData *data; EphySpinnerImages *images; + GtkSettings *settings; GdkPixbuf *pixbuf, *scaled_pixbuf; GList *element, *l; int h, w; - LOG ("Getting animation images at size %d", size); + LOG ("Getting animation images at size %d for screen %p", size, screen); - if (cache->priv->images == NULL || cache->priv->originals == NULL) + data = g_hash_table_lookup (priv->hash, screen); + if (data == NULL) { + data = ephy_spinner_cache_data_new (screen); + g_hash_table_insert (priv->hash, screen, data); + } + + if (data->images == NULL || data->originals == NULL) + { + /* Load failed, but don't try endlessly again! */ return NULL; } - element = g_list_find_custom (cache->priv->images, + element = g_list_find_custom (data->images, GINT_TO_POINTER (size), (GCompareFunc) compare_size); if (element != NULL) @@ -349,9 +408,10 @@ ephy_spinner_cache_get_images (EphySpinnerCache *cache, return ephy_spinner_images_copy ((EphySpinnerImages *) element->data); } - if (!gtk_icon_size_lookup_for_settings (gtk_settings_get_default (), size, &w, &h)) + settings = gtk_settings_get_for_screen (screen); + if (!gtk_icon_size_lookup_for_settings (settings, size, &w, &h)) { - g_warning ("Failed to lookup icon size\n"); + g_warning ("Failed to look up icon size\n"); return NULL; } @@ -363,7 +423,7 @@ ephy_spinner_cache_get_images (EphySpinnerCache *cache, START_PROFILER ("scaling spinner animation") - for (l = cache->priv->originals->images; l != NULL; l = l->next) + for (l = data->originals->images; l != NULL; l = l->next) { pixbuf = (GdkPixbuf *) l->data; scaled_pixbuf = scale_to_size (pixbuf, w, h); @@ -373,10 +433,10 @@ ephy_spinner_cache_get_images (EphySpinnerCache *cache, images->images = g_list_reverse (images->images); images->quiescent_pixbuf = - scale_to_size (cache->priv->originals->quiescent_pixbuf, w, h); + scale_to_size (data->originals->quiescent_pixbuf, w, h); /* store in cache */ - cache->priv->images = g_list_prepend (cache->priv->images, images); + data->images = g_list_prepend (data->images, images); STOP_PROFILER ("scaling spinner animation") @@ -386,29 +446,26 @@ ephy_spinner_cache_get_images (EphySpinnerCache *cache, static void ephy_spinner_cache_init (EphySpinnerCache *cache) { - cache->priv = EPHY_SPINNER_CACHE_GET_PRIVATE (cache); + EphySpinnerCachePrivate *priv; - LOG ("EphySpinnerCache initialising"); + priv = cache->priv = EPHY_SPINNER_CACHE_GET_PRIVATE (cache); - /* 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); + LOG ("EphySpinnerCache initialising"); - ephy_spinner_cache_load (cache); + priv->hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, + (GDestroyNotify) ephy_spinner_cache_data_free); } static void ephy_spinner_cache_finalize (GObject *object) { EphySpinnerCache *cache = EPHY_SPINNER_CACHE (object); + EphySpinnerCachePrivate *priv = cache->priv; 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_hash_table_destroy (priv->hash); G_OBJECT_CLASS (cache_parent_class)->finalize (object); } @@ -460,6 +517,7 @@ struct _EphySpinnerDetails GtkIconSize size; EphySpinnerImages *images; GList *current_image; + guint timeout; guint timer_task; guint spinning : 1; }; @@ -507,7 +565,10 @@ ephy_spinner_load_images (EphySpinner *spinner) START_PROFILER ("ephy_spinner_load_images") details->images = - ephy_spinner_cache_get_images (details->cache, details->size); + ephy_spinner_cache_get_images + (details->cache, + gtk_widget_get_screen (GTK_WIDGET (spinner)), + details->size); if (details->images != NULL) { @@ -539,6 +600,7 @@ icon_theme_changed_cb (GtkIconTheme *icon_theme, static void ephy_spinner_init (EphySpinner *spinner) { + EphySpinnerDetails *details = spinner->details; GtkWidget *widget = GTK_WIDGET (spinner); gtk_widget_set_events (widget, @@ -546,17 +608,12 @@ ephy_spinner_init (EphySpinner *spinner) | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); - spinner->details = EPHY_SPINNER_GET_PRIVATE (spinner); - - spinner->details->cache = ephy_spinner_cache_ref (); - spinner->details->size = GTK_ICON_SIZE_INVALID; - spinner->details->spinning = FALSE; - - /* FIXME: multihead */ - spinner->details->icon_theme = gtk_icon_theme_get_default (); - g_signal_connect (spinner->details->icon_theme, "changed", - G_CALLBACK (icon_theme_changed_cb), spinner); + details = spinner->details = EPHY_SPINNER_GET_PRIVATE (spinner); + details->cache = ephy_spinner_cache_ref (); + details->size = GTK_ICON_SIZE_INVALID; + details->spinning = FALSE; + details->timeout = SPINNER_TIMEOUT; } static GdkPixbuf * @@ -652,7 +709,7 @@ bump_spinner_frame_cb (EphySpinner *spinner) frame = spinner->details->current_image; - if (g_list_next (frame) != NULL) + if (frame->next != NULL) { frame = frame->next; } @@ -694,7 +751,7 @@ ephy_spinner_start (EphySpinner *spinner) } spinner->details->timer_task = - g_timeout_add (SPINNER_TIMEOUT, + g_timeout_add (details->timeout, (GSourceFunc) bump_spinner_frame_cb, spinner); } @@ -756,6 +813,32 @@ ephy_spinner_set_size (EphySpinner *spinner, } } +/* + * ephy_spinner_set_timeout: + * @spinner: a #EphySpinner + * @timeout: time delay between updates to the spinner. + * + * Sets the timeout delay for spinner updates. + **/ +static void +ephy_spinner_set_timeout (EphySpinner *spinner, + guint timeout) +{ + EphySpinnerDetails *details = spinner->details; + + if (timeout != details->timeout) + { + ephy_spinner_stop (spinner); + + details->timeout = timeout; + + if (details->spinning) + { + ephy_spinner_start (spinner); + } + } +} + static void ephy_spinner_size_request (GtkWidget *widget, GtkRequisition *requisition) @@ -813,7 +896,7 @@ ephy_spinner_finalize (GObject *object) EphySpinner *spinner = EPHY_SPINNER (object); g_signal_handlers_disconnect_by_func - (spinner->details->icon_theme, + (spinner->details->icon_theme, G_CALLBACK (icon_theme_changed_cb), spinner); ephy_spinner_remove_update_callback (spinner); @@ -825,6 +908,43 @@ ephy_spinner_finalize (GObject *object) } static void +ephy_spinner_screen_changed (GtkWidget *widget, + GdkScreen *old_screen) +{ + EphySpinner *spinner = EPHY_SPINNER (widget); + EphySpinnerDetails *details = spinner->details; + GdkScreen *screen; + + if (GTK_WIDGET_CLASS (parent_class)->screen_changed) + { + GTK_WIDGET_CLASS (parent_class)->screen_changed (widget, old_screen); + } + + screen = gtk_widget_get_screen (widget); + + /* FIXME: this seems to be happening when then spinner is destroyed!? */ + if (old_screen == screen) return; + + /* We'll get mapped again on the new screen, but not unmapped from + * the old screen, so remove timeout here. + */ + ephy_spinner_remove_update_callback (spinner); + + ephy_spinner_unload_images (spinner); + + if (old_screen != NULL) + { + g_signal_handlers_disconnect_by_func + (gtk_icon_theme_get_for_screen (old_screen), + G_CALLBACK (icon_theme_changed_cb), spinner); + } + + details->icon_theme = gtk_icon_theme_get_for_screen (screen); + g_signal_connect (details->icon_theme, "changed", + G_CALLBACK (icon_theme_changed_cb), spinner); +} + +static void ephy_spinner_class_init (EphySpinnerClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); @@ -838,6 +958,7 @@ ephy_spinner_class_init (EphySpinnerClass *class) widget_class->size_request = ephy_spinner_size_request; widget_class->map = ephy_spinner_map; widget_class->unmap = ephy_spinner_unmap; + widget_class->screen_changed = ephy_spinner_screen_changed; g_type_class_add_private (object_class, sizeof (EphySpinnerDetails)); } |