# Description: cache wallpapers resized and transformed are stored in ~/.cache/wallpaper/.
# the cache is refreshed for each new current wallpaper depending on the resolution or transformation,
# and each time the source image is refreshed. The source image format is preserved.
# Origin: Ubuntu
# Bug:

diff -Nur -x '*.orig' -x '*~' gnome-desktop-2.29.4/libgnome-desktop/gnome-bg.c gnome-desktop-2.29.4.new/libgnome-desktop/gnome-bg.c
--- gnome-desktop-2.29.4/libgnome-desktop/gnome-bg.c	2009-12-22 17:09:51.000000000 +0100
+++ gnome-desktop-2.29.4.new/libgnome-desktop/gnome-bg.c	2010-01-28 17:36:32.844431886 +0100
@@ -33,6 +33,7 @@
 #include <stdlib.h>
 
 #include <gio/gio.h>
+#include <glib/gstdio.h>
 
 #include <gdk/gdkx.h>
 #include <X11/Xlib.h>
@@ -576,6 +577,76 @@
 	return bg->filename;
 }
 
+static char*
+get_wallpaper_cache_dir ()
+{
+	return g_build_filename (g_get_user_cache_dir(), "wallpaper", NULL);
+}
+
+static char *
+get_wallpaper_cache_filename (GnomeBGPlacement	 placement,
+                              const char        *filename,
+                              int                width,
+                              int                height)
+{
+	gchar *changed_filename;
+	gchar *cache_filename;
+	gchar *cache_fullpath;
+	gchar *cache_dir;
+
+	changed_filename = g_strdup (filename);
+	changed_filename = g_strdelimit (changed_filename, G_DIR_SEPARATOR_S, '_');
+	cache_filename = g_strdup_printf ("%i_%i_%i_%s", placement, width, height, changed_filename);
+	cache_dir = get_wallpaper_cache_dir ();
+	cache_fullpath = g_build_filename (cache_dir, cache_filename, NULL);
+
+	g_free (changed_filename);
+	g_free (cache_filename);
+	g_free (cache_dir);
+
+	return cache_fullpath;
+
+}
+
+static gboolean
+cache_file_is_valid (const char *filename,
+		     const char *cache_filename)
+{
+	time_t mtime = get_mtime (filename);
+	time_t cache_mtime = get_mtime (cache_filename);
+
+	if (mtime < cache_mtime)
+		return TRUE;
+	return FALSE;
+}
+
+static void
+refresh_cache_file (GnomeBG     *bg,
+                    GdkPixbuf   *new_pixbuf,
+                    int          width,
+                    int          height)
+{
+	gchar *cache_filename;
+	gchar *cache_dir;
+	GdkPixbufFormat *format;
+
+	cache_filename = get_wallpaper_cache_filename (bg->placement, bg->filename, width, height);
+	cache_dir = get_wallpaper_cache_dir ();
+
+	/* Only refresh scaled file on disk if useful (and don't cache slideshow) */
+	if (!cache_file_is_valid (bg->filename, cache_filename)) {
+		format = gdk_pixbuf_get_file_info (bg->filename, NULL, NULL);
+		if (format != NULL) {
+			if (!g_file_test (cache_dir, G_FILE_TEST_IS_DIR))
+				g_mkdir (cache_dir, 0700);
+			gdk_pixbuf_save (new_pixbuf, cache_filename, gdk_pixbuf_format_get_name (format), NULL, NULL);
+		}
+	}
+
+	g_free(cache_filename);
+	g_free(cache_dir);
+}
+
 static void
 file_changed (GFileMonitor *file_monitor,
 	      GFile *child,
@@ -762,7 +833,7 @@
 }
 
 static void
-draw_image_area (GnomeBGPlacement  placement,
+draw_image_area (GnomeBG	  *bg,
 		 GdkPixbuf        *pixbuf,
 		 GdkPixbuf        *dest,
 		 GdkRectangle     *area)
@@ -775,9 +846,9 @@
 	if (!pixbuf)
 		return;
 
-	scaled = get_scaled_pixbuf (placement, pixbuf, dest_width, dest_height, &x, &y, &w, &h);
+	scaled = get_scaled_pixbuf (bg->placement, pixbuf, dest_width, dest_height, &x, &y, &w, &h);
 
-	switch (placement) {
+	switch (bg->placement) {
 	case GNOME_BG_PLACEMENT_TILED:
 		pixbuf_tile (scaled, dest);
 		break;
@@ -791,12 +862,14 @@
 		g_assert_not_reached ();
 		break;
 	}
+
+	refresh_cache_file(bg, scaled, dest_width, dest_height);
 	
 	g_object_unref (scaled);
 }
 
 static void
-draw_image (GnomeBGPlacement  placement,
+draw_image (GnomeBG          *bg,
 	    GdkPixbuf        *pixbuf,
 	    GdkPixbuf        *dest)
 {
@@ -807,7 +880,7 @@
 	rect.width = gdk_pixbuf_get_width (dest);
 	rect.height = gdk_pixbuf_get_height (dest);
 
-	draw_image_area (placement, pixbuf, dest, &rect);
+	draw_image_area (bg, pixbuf, dest, &rect);
 }
 
 static void
@@ -825,7 +898,7 @@
 
 	pixbuf = get_pixbuf_for_size (bg, gdk_pixbuf_get_width (dest), gdk_pixbuf_get_height (dest));
 	if (pixbuf) {
-		draw_image_area (bg->placement,
+		draw_image_area (bg,
 				 pixbuf,
 				 dest,
 				 &rect);
@@ -848,7 +921,7 @@
 		gdk_screen_get_monitor_geometry (screen, monitor, &rect);
 		pixbuf = get_pixbuf_for_size (bg, rect.width, rect.height);
 		if (pixbuf) {
-			draw_image_area (bg->placement,
+			draw_image_area (bg,
 					 pixbuf,
 					 dest, &rect);
 			g_object_unref (pixbuf);
@@ -1191,7 +1264,7 @@
 	thumb = create_img_thumbnail (bg, factory, screen, dest_width, dest_height, -1);
 	
 	if (thumb) {
-		draw_image (bg->placement, thumb, result);
+		draw_image (bg, thumb, result);
 		g_object_unref (thumb);
 	}
 	
@@ -1638,19 +1711,28 @@
 	}
 	else {
 		GdkPixbufFormat *format;
-		GdkPixbuf *pixbuf;
+		GdkPixbuf *pixbuf = NULL;
+		gchar *cache_filename;
 
-		/* If scalable choose maximum size */
-		format = gdk_pixbuf_get_file_info (filename, NULL, NULL);
-		if (format != NULL &&
-		    strcmp (gdk_pixbuf_format_get_name (format), "svg") == 0 &&
-		    (best_width > 0 && best_height > 0) &&
-		    (bg->placement == GNOME_BG_PLACEMENT_FILL_SCREEN ||
-		     bg->placement == GNOME_BG_PLACEMENT_SCALED ||
-		     bg->placement == GNOME_BG_PLACEMENT_ZOOMED))
-			pixbuf = gdk_pixbuf_new_from_file_at_size (filename, best_width, best_height, NULL);
-		else
-			pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+		/* Try to hit local cache first */
+		cache_filename = get_wallpaper_cache_filename (bg->placement, filename, best_width, best_height);
+		if (cache_file_is_valid(filename, cache_filename))
+			pixbuf = gdk_pixbuf_new_from_file (cache_filename, NULL);
+		g_free(cache_filename);
+
+		if (!pixbuf) {
+			/* If scalable choose maximum size */
+			format = gdk_pixbuf_get_file_info (filename, NULL, NULL);
+			if (format != NULL &&
+			    strcmp (gdk_pixbuf_format_get_name (format), "svg") == 0 &&
+			    (best_width > 0 && best_height > 0) &&
+			    (bg->placement == GNOME_BG_PLACEMENT_FILL_SCREEN ||
+			     bg->placement == GNOME_BG_PLACEMENT_SCALED ||
+			     bg->placement == GNOME_BG_PLACEMENT_ZOOMED))
+				pixbuf = gdk_pixbuf_new_from_file_at_size (filename, best_width, best_height, NULL);
+			else
+				pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+		}
 
 		if (pixbuf)
 			file_cache_add_pixbuf (bg, filename, pixbuf);
@@ -2895,7 +2977,7 @@
 	thumb = create_img_thumbnail (bg, factory, screen, dest_width, dest_height, frame_num + skipped);
 
 	if (thumb) {
-		draw_image (bg->placement, thumb, result);
+		draw_image (bg, thumb, result);
 		g_object_unref (thumb);
 	}
 
