2 * Copyright © 2000 Eazel, Inc.
3 * Copyright © 2002-2004 Marco Pesenti Gritti
4 * Copyright © 2004, 2006 Christian Persch
6 * Nautilus is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Nautilus is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Author: Andy Hertzfeld <andy@eazel.com>
22 * Ephy port by Marco Pesenti Gritti <marco@it.gnome.org>
24 * $Id: ephy-spinner.c 2114 2006-12-25 12:15:00Z mr $
29 #include "ephy-spinner.h"
31 /* #include "ephy-debug.h" */
32 #define LOG(msg, args...)
33 #define START_PROFILER(name)
34 #define STOP_PROFILER(name)
36 #include <gdk-pixbuf/gdk-pixbuf.h>
39 /* Spinner cache implementation */
41 #define EPHY_TYPE_SPINNER_CACHE (ephy_spinner_cache_get_type())
42 #define EPHY_SPINNER_CACHE(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_SPINNER_CACHE, EphySpinnerCache))
43 #define EPHY_SPINNER_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_SPINNER_CACHE, EphySpinnerCacheClass))
44 #define EPHY_IS_SPINNER_CACHE(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_SPINNER_CACHE))
45 #define EPHY_IS_SPINNER_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_SPINNER_CACHE))
46 #define EPHY_SPINNER_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_SPINNER_CACHE, EphySpinnerCacheClass))
48 typedef struct _EphySpinnerCache EphySpinnerCache
;
49 typedef struct _EphySpinnerCacheClass EphySpinnerCacheClass
;
50 typedef struct _EphySpinnerCachePrivate EphySpinnerCachePrivate
;
52 struct _EphySpinnerCacheClass
54 GObjectClass parent_class
;
57 struct _EphySpinnerCache
59 GObject parent_object
;
62 EphySpinnerCachePrivate
*priv
;
65 #define EPHY_SPINNER_CACHE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_SPINNER_CACHE, EphySpinnerCachePrivate))
67 struct _EphySpinnerCachePrivate
69 /* Hash table of GdkScreen -> EphySpinnerCacheData */
79 GdkPixbuf
**animation_pixbufs
;
80 guint n_animation_pixbufs
;
83 #define LAST_ICON_SIZE GTK_ICON_SIZE_DIALOG + 1
84 #define SPINNER_ICON_NAME "process-working"
85 #define SPINNER_FALLBACK_ICON_NAME "gnome-spinner"
86 #define EPHY_SPINNER_IMAGES_INVALID ((EphySpinnerImages *) 0x1)
91 GtkIconTheme
*icon_theme
;
92 EphySpinnerImages
*images
[LAST_ICON_SIZE
];
93 } EphySpinnerCacheData
;
95 static void ephy_spinner_cache_class_init (EphySpinnerCacheClass
*klass
);
96 static void ephy_spinner_cache_init (EphySpinnerCache
*cache
);
98 static GObjectClass
*ephy_spinner_cache_parent_class
;
101 ephy_spinner_cache_get_type (void)
103 static GType type
= 0;
105 if (G_UNLIKELY (type
== 0))
107 const GTypeInfo our_info
=
109 sizeof (EphySpinnerCacheClass
),
112 (GClassInitFunc
) ephy_spinner_cache_class_init
,
115 sizeof (EphySpinnerCache
),
117 (GInstanceInitFunc
) ephy_spinner_cache_init
120 type
= g_type_register_static (G_TYPE_OBJECT
,
128 static EphySpinnerImages
*
129 ephy_spinner_images_ref (EphySpinnerImages
*images
)
131 g_return_val_if_fail (images
!= NULL
, NULL
);
139 ephy_spinner_images_unref (EphySpinnerImages
*images
)
141 g_return_if_fail (images
!= NULL
);
144 if (images
->ref_count
== 0)
148 LOG ("Freeing spinner images %p for size %d", images
, images
->size
);
150 for (i
= 0; i
< images
->n_animation_pixbufs
; ++i
)
152 g_object_unref (images
->animation_pixbufs
[i
]);
154 g_free (images
->animation_pixbufs
);
161 ephy_spinner_cache_data_unload (EphySpinnerCacheData
*data
)
164 EphySpinnerImages
*images
;
166 g_return_if_fail (data
!= NULL
);
168 LOG ("EphySpinnerDataCache unload for screen %p", data
->screen
);
170 for (size
= GTK_ICON_SIZE_INVALID
; size
< LAST_ICON_SIZE
; ++size
)
172 images
= data
->images
[size
];
173 data
->images
[size
] = NULL
;
175 if (images
!= NULL
&& images
!= EPHY_SPINNER_IMAGES_INVALID
)
177 ephy_spinner_images_unref (images
);
183 extract_frame (GdkPixbuf
*grid_pixbuf
,
190 if (x
+ size
> gdk_pixbuf_get_width (grid_pixbuf
) ||
191 y
+ size
> gdk_pixbuf_get_height (grid_pixbuf
))
196 pixbuf
= gdk_pixbuf_new_subpixbuf (grid_pixbuf
,
199 g_return_val_if_fail (pixbuf
!= NULL
, NULL
);
205 scale_to_size (GdkPixbuf
*pixbuf
,
212 g_return_val_if_fail (pixbuf
!= NULL
, NULL
);
214 pw
= gdk_pixbuf_get_width (pixbuf
);
215 ph
= gdk_pixbuf_get_height (pixbuf
);
217 if (pw
!= dw
|| ph
!= dh
)
219 result
= gdk_pixbuf_scale_simple (pixbuf
, dw
, dh
,
220 GDK_INTERP_BILINEAR
);
221 g_object_unref (pixbuf
);
228 static EphySpinnerImages
*
229 ephy_spinner_images_load (GdkScreen
*screen
,
230 GtkIconTheme
*icon_theme
,
231 GtkIconSize icon_size
)
233 EphySpinnerImages
*images
;
234 GdkPixbuf
*icon_pixbuf
, *pixbuf
;
235 GtkIconInfo
*icon_info
= NULL
;
236 int grid_width
, grid_height
, x
, y
, requested_size
, size
, isw
, ish
, n
;
238 GSList
*list
= NULL
, *l
;
240 LOG ("EphySpinnerCacheData loading for screen %p at size %d", screen
, icon_size
);
242 START_PROFILER ("loading spinner animation")
244 if (!gtk_icon_size_lookup_for_settings (gtk_settings_get_for_screen (screen
),
245 icon_size
, &isw
, &ish
)) goto loser
;
247 requested_size
= MAX (ish
, isw
);
249 /* Load the animation. The 'rest icon' is the 0th frame */
250 icon_info
= gtk_icon_theme_lookup_icon (icon_theme
,
253 if (icon_info
== NULL
)
255 g_warning ("Throbber animation not found");
257 /* If the icon naming spec compliant name wasn't found, try the old name */
258 icon_info
= gtk_icon_theme_lookup_icon (icon_theme
,
259 SPINNER_FALLBACK_ICON_NAME
,
261 if (icon_info
== NULL
)
263 g_warning ("Throbber fallback animation not found either");
267 g_assert (icon_info
!= NULL
);
269 size
= gtk_icon_info_get_base_size (icon_info
);
270 icon
= gtk_icon_info_get_filename (icon_info
);
271 if (icon
== NULL
) goto loser
;
273 icon_pixbuf
= gdk_pixbuf_new_from_file (icon
, NULL
);
274 gtk_icon_info_free (icon_info
);
277 if (icon_pixbuf
== NULL
)
279 g_warning ("Could not load the spinner file");
283 grid_width
= gdk_pixbuf_get_width (icon_pixbuf
);
284 grid_height
= gdk_pixbuf_get_height (icon_pixbuf
);
287 for (y
= 0; y
< grid_height
; y
+= size
)
289 for (x
= 0; x
< grid_width
; x
+= size
)
291 pixbuf
= extract_frame (icon_pixbuf
, x
, y
, size
);
295 list
= g_slist_prepend (list
, pixbuf
);
300 g_warning ("Cannot extract frame (%d, %d) from the grid\n", x
, y
);
305 g_object_unref (icon_pixbuf
);
307 if (list
== NULL
) goto loser
;
310 if (size
> requested_size
)
312 for (l
= list
; l
!= NULL
; l
= l
->next
)
314 l
->data
= scale_to_size (l
->data
, isw
, ish
);
318 /* Now we've successfully got all the data */
319 images
= g_new (EphySpinnerImages
, 1);
320 images
->ref_count
= 1;
322 images
->size
= icon_size
;
323 images
->width
= images
->height
= requested_size
;
325 images
->n_animation_pixbufs
= n
;
326 images
->animation_pixbufs
= g_new (GdkPixbuf
*, n
);
328 for (l
= list
; l
!= NULL
; l
= l
->next
)
330 g_assert (l
->data
!= NULL
);
331 images
->animation_pixbufs
[--n
] = l
->data
;
337 STOP_PROFILER ("loading spinner animation")
344 gtk_icon_info_free (icon_info
);
346 g_slist_foreach (list
, (GFunc
) g_object_unref
, NULL
);
348 STOP_PROFILER ("loading spinner animation")
353 static EphySpinnerCacheData
*
354 ephy_spinner_cache_data_new (GdkScreen
*screen
)
356 EphySpinnerCacheData
*data
;
358 data
= g_new0 (EphySpinnerCacheData
, 1);
360 data
->screen
= screen
;
361 data
->icon_theme
= gtk_icon_theme_get_for_screen (screen
);
362 g_signal_connect_swapped (data
->icon_theme
, "changed",
363 G_CALLBACK (ephy_spinner_cache_data_unload
),
370 ephy_spinner_cache_data_free (EphySpinnerCacheData
*data
)
372 g_return_if_fail (data
!= NULL
);
373 g_return_if_fail (data
->icon_theme
!= NULL
);
375 g_signal_handlers_disconnect_by_func
377 G_CALLBACK (ephy_spinner_cache_data_unload
), data
);
379 ephy_spinner_cache_data_unload (data
);
384 static EphySpinnerImages
*
385 ephy_spinner_cache_get_images (EphySpinnerCache
*cache
,
387 GtkIconSize icon_size
)
389 EphySpinnerCachePrivate
*priv
= cache
->priv
;
390 EphySpinnerCacheData
*data
;
391 EphySpinnerImages
*images
;
393 LOG ("Getting animation images for screen %p at size %d", screen
, icon_size
);
395 g_return_val_if_fail (icon_size
< LAST_ICON_SIZE
, NULL
);
397 /* Backward compat: "invalid" meant "native" size which doesn't exist anymore */
398 if (icon_size
== GTK_ICON_SIZE_INVALID
)
400 icon_size
= GTK_ICON_SIZE_DIALOG
;
403 data
= g_hash_table_lookup (priv
->hash
, screen
);
406 data
= ephy_spinner_cache_data_new (screen
);
407 /* FIXME: think about what happens when the screen's display is closed later on */
408 g_hash_table_insert (priv
->hash
, screen
, data
);
411 images
= data
->images
[icon_size
];
412 if (images
== EPHY_SPINNER_IMAGES_INVALID
)
414 /* Load failed, but don't try endlessly again! */
420 /* Return cached data */
421 return ephy_spinner_images_ref (images
);
424 images
= ephy_spinner_images_load (screen
, data
->icon_theme
, icon_size
);
428 /* Mark as failed-to-load */
429 data
->images
[icon_size
] = EPHY_SPINNER_IMAGES_INVALID
;
434 data
->images
[icon_size
] = images
;
436 return ephy_spinner_images_ref (images
);
440 ephy_spinner_cache_init (EphySpinnerCache
*cache
)
442 EphySpinnerCachePrivate
*priv
;
444 priv
= cache
->priv
= EPHY_SPINNER_CACHE_GET_PRIVATE (cache
);
446 LOG ("EphySpinnerCache initialising");
448 priv
->hash
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
450 (GDestroyNotify
) ephy_spinner_cache_data_free
);
454 ephy_spinner_cache_finalize (GObject
*object
)
456 EphySpinnerCache
*cache
= EPHY_SPINNER_CACHE (object
);
457 EphySpinnerCachePrivate
*priv
= cache
->priv
;
459 g_hash_table_destroy (priv
->hash
);
461 LOG ("EphySpinnerCache finalised");
463 G_OBJECT_CLASS (ephy_spinner_cache_parent_class
)->finalize (object
);
467 ephy_spinner_cache_class_init (EphySpinnerCacheClass
*klass
)
469 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
471 ephy_spinner_cache_parent_class
= g_type_class_peek_parent (klass
);
473 object_class
->finalize
= ephy_spinner_cache_finalize
;
475 g_type_class_add_private (object_class
, sizeof (EphySpinnerCachePrivate
));
478 static EphySpinnerCache
*spinner_cache
= NULL
;
480 static EphySpinnerCache
*
481 ephy_spinner_cache_ref (void)
483 if (spinner_cache
== NULL
)
485 EphySpinnerCache
**cache_ptr
;
487 spinner_cache
= g_object_new (EPHY_TYPE_SPINNER_CACHE
, NULL
);
488 cache_ptr
= &spinner_cache
;
489 g_object_add_weak_pointer (G_OBJECT (spinner_cache
),
490 (gpointer
) cache_ptr
);
492 return spinner_cache
;
495 return g_object_ref (spinner_cache
);
498 /* Spinner implementation */
500 #define SPINNER_TIMEOUT 125 /* ms */
502 #define EPHY_SPINNER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_SPINNER, EphySpinnerDetails))
504 struct _EphySpinnerDetails
506 GtkIconTheme
*icon_theme
;
507 EphySpinnerCache
*cache
;
509 EphySpinnerImages
*images
;
517 static void ephy_spinner_class_init (EphySpinnerClass
*class);
518 static void ephy_spinner_init (EphySpinner
*spinner
);
520 static GObjectClass
*parent_class
;
523 ephy_spinner_get_type (void)
525 static GType type
= 0;
527 if (G_UNLIKELY (type
== 0))
529 const GTypeInfo our_info
=
531 sizeof (EphySpinnerClass
),
532 NULL
, /* base_init */
533 NULL
, /* base_finalize */
534 (GClassInitFunc
) ephy_spinner_class_init
,
536 NULL
, /* class_data */
537 sizeof (EphySpinner
),
539 (GInstanceInitFunc
) ephy_spinner_init
542 type
= g_type_register_static (GTK_TYPE_WIDGET
,
551 ephy_spinner_load_images (EphySpinner
*spinner
)
553 EphySpinnerDetails
*details
= spinner
->details
;
555 if (details
->need_load
)
557 START_PROFILER ("ephy_spinner_load_images")
560 ephy_spinner_cache_get_images
562 gtk_widget_get_screen (GTK_WIDGET (spinner
)),
565 STOP_PROFILER ("ephy_spinner_load_images")
567 details
->current_image
= 0; /* 'rest' icon */
568 details
->need_load
= FALSE
;
571 return details
->images
!= NULL
;
575 ephy_spinner_unload_images (EphySpinner
*spinner
)
577 EphySpinnerDetails
*details
= spinner
->details
;
579 if (details
->images
!= NULL
)
581 ephy_spinner_images_unref (details
->images
);
582 details
->images
= NULL
;
585 details
->current_image
= 0;
586 details
->need_load
= TRUE
;
590 icon_theme_changed_cb (GtkIconTheme
*icon_theme
,
591 EphySpinner
*spinner
)
593 ephy_spinner_unload_images (spinner
);
594 gtk_widget_queue_resize (GTK_WIDGET (spinner
));
598 ephy_spinner_init (EphySpinner
*spinner
)
600 EphySpinnerDetails
*details
;
602 details
= spinner
->details
= EPHY_SPINNER_GET_PRIVATE (spinner
);
604 gtk_widget_set_has_window (GTK_WIDGET (spinner
), FALSE
);
606 details
->cache
= ephy_spinner_cache_ref ();
607 details
->size
= GTK_ICON_SIZE_DIALOG
;
608 details
->spinning
= FALSE
;
609 details
->timeout
= SPINNER_TIMEOUT
;
610 details
->need_load
= TRUE
;
614 ephy_spinner_expose (GtkWidget
*widget
,
615 GdkEventExpose
*event
)
617 EphySpinner
*spinner
= EPHY_SPINNER (widget
);
618 EphySpinnerDetails
*details
= spinner
->details
;
619 EphySpinnerImages
*images
;
622 int x_offset
, y_offset
, width
, height
;
623 GdkRectangle pix_area
, dest
;
624 GtkAllocation allocation
;
626 if (!gtk_widget_is_drawable (GTK_WIDGET (spinner
)))
631 if (details
->need_load
&&
632 !ephy_spinner_load_images (spinner
))
637 images
= details
->images
;
643 /* Otherwise |images| will be NULL anyway */
644 g_assert (images
->n_animation_pixbufs
> 0);
646 g_assert (details
->current_image
< images
->n_animation_pixbufs
);
648 pixbuf
= images
->animation_pixbufs
[details
->current_image
];
650 g_assert (pixbuf
!= NULL
);
652 width
= gdk_pixbuf_get_width (pixbuf
);
653 height
= gdk_pixbuf_get_height (pixbuf
);
655 /* Compute the offsets for the image centered on our allocation */
656 gtk_widget_get_allocation (widget
, &allocation
);
657 x_offset
= (allocation
.width
- width
) / 2;
658 y_offset
= (allocation
.height
- height
) / 2;
660 pix_area
.x
= x_offset
+ allocation
.x
;
661 pix_area
.y
= y_offset
+ allocation
.y
;
662 pix_area
.width
= width
;
663 pix_area
.height
= height
;
665 if (!gdk_rectangle_intersect (&event
->area
, &pix_area
, &dest
))
670 gc
= gdk_gc_new (gtk_widget_get_window (widget
));
671 gdk_draw_pixbuf (gtk_widget_get_window (widget
), gc
, pixbuf
,
672 dest
.x
- x_offset
- allocation
.x
,
673 dest
.y
- y_offset
- allocation
.y
,
675 dest
.width
, dest
.height
,
676 GDK_RGB_DITHER_MAX
, 0, 0);
683 bump_spinner_frame_cb (EphySpinner
*spinner
)
685 EphySpinnerDetails
*details
= spinner
->details
;
687 /* This can happen when we've unloaded the images on a theme
688 * change, but haven't been in the queued size request yet.
689 * Just skip this update.
691 if (details
->images
== NULL
) return TRUE
;
693 details
->current_image
++;
694 if (details
->current_image
>= details
->images
->n_animation_pixbufs
)
696 /* the 0th frame is the 'rest' icon */
697 details
->current_image
= MIN (1, details
->images
->n_animation_pixbufs
);
700 gtk_widget_queue_draw (GTK_WIDGET (spinner
));
707 * ephy_spinner_start:
708 * @spinner: a #EphySpinner
710 * Start the spinner animation.
713 ephy_spinner_start (EphySpinner
*spinner
)
715 EphySpinnerDetails
*details
= spinner
->details
;
717 details
->spinning
= TRUE
;
719 if (GTK_WIDGET_MAPPED (GTK_WIDGET (spinner
)) &&
720 details
->timer_task
== 0 &&
721 ephy_spinner_load_images (spinner
))
723 /* the 0th frame is the 'rest' icon */
724 details
->current_image
= MIN (1, details
->images
->n_animation_pixbufs
);
726 details
->timer_task
=
727 g_timeout_add_full (G_PRIORITY_LOW
,
729 (GSourceFunc
) bump_spinner_frame_cb
,
736 ephy_spinner_remove_update_callback (EphySpinner
*spinner
)
738 EphySpinnerDetails
*details
= spinner
->details
;
740 if (details
->timer_task
!= 0)
742 g_source_remove (details
->timer_task
);
743 details
->timer_task
= 0;
749 * @spinner: a #EphySpinner
751 * Stop the spinner animation.
754 ephy_spinner_stop (EphySpinner
*spinner
)
756 EphySpinnerDetails
*details
= spinner
->details
;
758 details
->spinning
= FALSE
;
759 details
->current_image
= 0;
761 if (details
->timer_task
!= 0)
763 ephy_spinner_remove_update_callback (spinner
);
765 if (GTK_WIDGET_MAPPED (GTK_WIDGET (spinner
)))
767 gtk_widget_queue_draw (GTK_WIDGET (spinner
));
773 * ephy_spinner_set_size:
774 * @spinner: a #EphySpinner
775 * @size: the size of type %GtkIconSize
777 * Set the size of the spinner.
780 ephy_spinner_set_size (EphySpinner
*spinner
,
783 if (size
== GTK_ICON_SIZE_INVALID
)
785 size
= GTK_ICON_SIZE_DIALOG
;
788 if (size
!= spinner
->details
->size
)
790 ephy_spinner_unload_images (spinner
);
792 spinner
->details
->size
= size
;
794 gtk_widget_queue_resize (GTK_WIDGET (spinner
));
800 * ephy_spinner_set_timeout:
801 * @spinner: a #EphySpinner
802 * @timeout: time delay between updates to the spinner.
804 * Sets the timeout delay for spinner updates.
807 ephy_spinner_set_timeout (EphySpinner
*spinner
,
810 EphySpinnerDetails
*details
= spinner
->details
;
812 if (timeout
!= details
->timeout
)
814 ephy_spinner_stop (spinner
);
816 details
->timeout
= timeout
;
818 if (details
->spinning
)
820 ephy_spinner_start (spinner
);
827 ephy_spinner_size_request (GtkWidget
*widget
,
828 GtkRequisition
*requisition
)
830 EphySpinner
*spinner
= EPHY_SPINNER (widget
);
831 EphySpinnerDetails
*details
= spinner
->details
;
833 if ((details
->need_load
&&
834 !ephy_spinner_load_images (spinner
)) ||
835 details
->images
== NULL
)
837 requisition
->width
= requisition
->height
= 0;
838 gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (widget
),
841 &requisition
->height
);
845 requisition
->width
= details
->images
->width
;
846 requisition
->height
= details
->images
->height
;
848 /* FIXME fix this hack */
849 /* allocate some extra margin so we don't butt up against toolbar edges */
850 if (details
->size
!= GTK_ICON_SIZE_MENU
)
852 requisition
->width
+= 2;
853 requisition
->height
+= 2;
858 ephy_spinner_map (GtkWidget
*widget
)
860 EphySpinner
*spinner
= EPHY_SPINNER (widget
);
861 EphySpinnerDetails
*details
= spinner
->details
;
863 GTK_WIDGET_CLASS (parent_class
)->map (widget
);
865 if (details
->spinning
)
867 ephy_spinner_start (spinner
);
872 ephy_spinner_unmap (GtkWidget
*widget
)
874 EphySpinner
*spinner
= EPHY_SPINNER (widget
);
876 ephy_spinner_remove_update_callback (spinner
);
878 GTK_WIDGET_CLASS (parent_class
)->unmap (widget
);
882 ephy_spinner_dispose (GObject
*object
)
884 EphySpinner
*spinner
= EPHY_SPINNER (object
);
886 g_signal_handlers_disconnect_by_func
887 (spinner
->details
->icon_theme
,
888 G_CALLBACK (icon_theme_changed_cb
), spinner
);
890 G_OBJECT_CLASS (parent_class
)->dispose (object
);
894 ephy_spinner_finalize (GObject
*object
)
896 EphySpinner
*spinner
= EPHY_SPINNER (object
);
898 ephy_spinner_remove_update_callback (spinner
);
899 ephy_spinner_unload_images (spinner
);
901 g_object_unref (spinner
->details
->cache
);
903 G_OBJECT_CLASS (parent_class
)->finalize (object
);
907 ephy_spinner_screen_changed (GtkWidget
*widget
,
908 GdkScreen
*old_screen
)
910 EphySpinner
*spinner
= EPHY_SPINNER (widget
);
911 EphySpinnerDetails
*details
= spinner
->details
;
914 if (GTK_WIDGET_CLASS (parent_class
)->screen_changed
)
916 GTK_WIDGET_CLASS (parent_class
)->screen_changed (widget
, old_screen
);
919 screen
= gtk_widget_get_screen (widget
);
921 /* FIXME: this seems to be happening when then spinner is destroyed!? */
922 if (old_screen
== screen
) return;
924 /* We'll get mapped again on the new screen, but not unmapped from
925 * the old screen, so remove timeout here.
927 ephy_spinner_remove_update_callback (spinner
);
929 ephy_spinner_unload_images (spinner
);
931 if (old_screen
!= NULL
)
933 g_signal_handlers_disconnect_by_func
934 (gtk_icon_theme_get_for_screen (old_screen
),
935 G_CALLBACK (icon_theme_changed_cb
), spinner
);
938 details
->icon_theme
= gtk_icon_theme_get_for_screen (screen
);
939 g_signal_connect (details
->icon_theme
, "changed",
940 G_CALLBACK (icon_theme_changed_cb
), spinner
);
944 ephy_spinner_class_init (EphySpinnerClass
*class)
946 GObjectClass
*object_class
= G_OBJECT_CLASS (class);
947 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS (class);
949 parent_class
= g_type_class_peek_parent (class);
951 object_class
->dispose
= ephy_spinner_dispose
;
952 object_class
->finalize
= ephy_spinner_finalize
;
954 widget_class
->expose_event
= ephy_spinner_expose
;
955 widget_class
->size_request
= ephy_spinner_size_request
;
956 widget_class
->map
= ephy_spinner_map
;
957 widget_class
->unmap
= ephy_spinner_unmap
;
958 widget_class
->screen_changed
= ephy_spinner_screen_changed
;
960 g_type_class_add_private (object_class
, sizeof (EphySpinnerDetails
));
966 * Create a new #EphySpinner. The spinner is a widget
967 * that gives the user feedback about network status with
970 * Return Value: the spinner #GtkWidget
973 ephy_spinner_new (void)
975 return GTK_WIDGET (g_object_new (EPHY_TYPE_SPINNER
, NULL
));