6e3a31a
diff -up gnome-desktop-2.24.0/libgnome-desktop/gnome-bg.c.fade gnome-desktop-2.24.0/libgnome-desktop/gnome-bg.c
d4fe16f
--- gnome-desktop-2.24.0/libgnome-desktop/gnome-bg.c.fade	2008-09-22 17:01:45.000000000 -0400
953c81a
+++ gnome-desktop-2.24.0/libgnome-desktop/gnome-bg.c	2008-10-15 11:12:56.000000000 -0400
99fa927
@@ -37,11 +37,15 @@ Author: Soren Sandmann 
99fa927
 #include <X11/Xlib.h>
99fa927
 #include <X11/Xatom.h>
99fa927
 
99fa927
+#include <cairo.h>
99fa927
+#include <cairo-xlib.h>
99fa927
+
99fa927
 #include <gconf/gconf-client.h>
99fa927
 #include <libgnomeui/libgnomeui.h>
99fa927
 
99fa927
 #define GNOME_DESKTOP_USE_UNSTABLE_API
99fa927
 #include <libgnomeui/gnome-bg.h>
99fa927
+#include <libgnomeui/gnome-bg-crossfade.h>
99fa927
 
99fa927
 #define BG_KEY_DRAW_BACKGROUND    GNOME_BG_KEY_DIR "/draw_background"
99fa927
 #define BG_KEY_PRIMARY_COLOR      GNOME_BG_KEY_DIR "/primary_color"
a5fb6e1
@@ -98,6 +102,7 @@ struct _GnomeBG
a5fb6e1
 	GFileMonitor *		file_monitor;
a5fb6e1
 
a5fb6e1
 	guint                   changed_id;
a5fb6e1
+	guint                   transitioned_id;
a5fb6e1
 	
a5fb6e1
 	/* Cached information, only access through cache accessor functions */
a5fb6e1
         SlideShow *		slideshow;
f3623b9
@@ -106,6 +111,8 @@ struct _GnomeBG
f3623b9
 	int			timeout_id;
f3623b9
 
f3623b9
 	GList *		        file_cache;
f3623b9
+
f3623b9
+        guint                   ignore_changes : 1;
f3623b9
 };
f3623b9
 
f3623b9
 struct _GnomeBGClass
f3623b9
@@ -115,6 +122,7 @@ struct _GnomeBGClass
a5fb6e1
 
a5fb6e1
 enum {
a5fb6e1
 	CHANGED,
a5fb6e1
+	TRANSITIONED,
a5fb6e1
 	N_SIGNALS
a5fb6e1
 };
a5fb6e1
 
f3623b9
@@ -264,6 +272,10 @@ do_changed (GnomeBG *bg)
f3623b9
 static void
f3623b9
 queue_changed (GnomeBG *bg)
f3623b9
 {
f3623b9
+	if (bg->ignore_changes) {
f3623b9
+		return;
f3623b9
+	}
f3623b9
+
f3623b9
 	if (bg->changed_id > 0) {
f3623b9
 		g_source_remove (bg->changed_id);
f3623b9
 	}
f3623b9
@@ -275,6 +287,30 @@ queue_changed (GnomeBG *bg)
a5fb6e1
 					     NULL);
a5fb6e1
 }
a5fb6e1
 
a5fb6e1
+static gboolean
a5fb6e1
+do_transitioned (GnomeBG *bg)
a5fb6e1
+{
a5fb6e1
+	bg->transitioned_id = 0;
a5fb6e1
+
a5fb6e1
+	g_signal_emit (G_OBJECT (bg), signals[TRANSITIONED], 0);
a5fb6e1
+
a5fb6e1
+	return FALSE;
a5fb6e1
+}
a5fb6e1
+
a5fb6e1
+static void
a5fb6e1
+queue_transitioned (GnomeBG *bg)
a5fb6e1
+{
a5fb6e1
+	if (bg->transitioned_id > 0) {
a5fb6e1
+		g_source_remove (bg->transitioned_id);
a5fb6e1
+	}
a5fb6e1
+
a5fb6e1
+	bg->transitioned_id = g_timeout_add_full (G_PRIORITY_LOW,
a5fb6e1
+					     100,
a5fb6e1
+					     (GSourceFunc)do_transitioned,
a5fb6e1
+					     bg,
a5fb6e1
+					     NULL);
a5fb6e1
+}
a5fb6e1
+
a5fb6e1
 void
a5fb6e1
 gnome_bg_load_from_preferences (GnomeBG     *bg,
a5fb6e1
 				GConfClient *client)
f3623b9
@@ -414,6 +450,14 @@ gnome_bg_class_init (GnomeBGClass *klass
a5fb6e1
 					 NULL, NULL,
a5fb6e1
 					 g_cclosure_marshal_VOID__VOID,
a5fb6e1
 					 G_TYPE_NONE, 0);
a5fb6e1
+
a5fb6e1
+	signals[TRANSITIONED] = g_signal_new ("transitioned",
a5fb6e1
+					 G_OBJECT_CLASS_TYPE (object_class),
a5fb6e1
+					 G_SIGNAL_RUN_LAST,
a5fb6e1
+					 0,
a5fb6e1
+					 NULL, NULL,
a5fb6e1
+					 g_cclosure_marshal_VOID__VOID,
a5fb6e1
+					 G_TYPE_NONE, 0);
a5fb6e1
 }
a5fb6e1
 
a5fb6e1
 GnomeBG *
f3623b9
@@ -547,6 +591,13 @@ gnome_bg_set_filename (GnomeBG     *bg,
f3623b9
 	}
f3623b9
 }
f3623b9
 
f3623b9
+void
f3623b9
+gnome_bg_ignore_changes (GnomeBG *bg,
f3623b9
+                         gboolean should_ignore)
f3623b9
+{
f3623b9
+	bg->ignore_changes = should_ignore;
f3623b9
+}
f3623b9
+
f3623b9
 static void
f3623b9
 draw_color (GnomeBG *bg, GdkPixbuf *dest)
f3623b9
 {
953c81a
@@ -1011,15 +1062,74 @@ gnome_bg_create_thumbnail (GnomeBG      
953c81a
 	return result;
99fa927
 }
99fa927
 
953c81a
+GdkPixmap *
953c81a
+gnome_bg_get_pixmap_from_root (GdkScreen *screen)
953c81a
+{
953c81a
+	int      result;
953c81a
+	gint     format;
953c81a
+	gulong   nitems;
953c81a
+	gulong   bytes_after;
953c81a
+	guchar  *data;
953c81a
+	Atom     type;
953c81a
+	Display *display;
953c81a
+	int      screen_num;
953c81a
+	GdkPixmap *pixmap;
99fa927
 
99fa927
-/* Set the root pixmap, and properties pointing to it. We
99fa927
- * do this atomically with XGrabServer to make sure that
99fa927
- * we won't leak the pixmap if somebody else it setting
99fa927
- * it at the same time. (This assumes that they follow the
99fa927
- * same conventions we do)
99fa927
- */
99fa927
-void 
99fa927
-gnome_bg_set_pixmap_as_root (GdkScreen *screen, GdkPixmap *pixmap)
6e3a31a
+        display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
6e3a31a
+
953c81a
+	result = XGetWindowProperty (display,
953c81a
+		RootWindow (display, screen_num),
953c81a
+		gdk_x11_get_xatom_by_name ("_XROOTPMAP_ID"),
953c81a
+		0L, 1L, False, XA_PIXMAP,
953c81a
+		&type, &format, &nitems, &bytes_after,
953c81a
+		&data);
953c81a
+	pixmap = NULL;
953c81a
+
953c81a
+	if (data != NULL) {
953c81a
+	    if (result == Success && type == XA_PIXMAP &&
953c81a
+		    format == 32 && nitems == 1) {
953c81a
+		GdkPixmap *source_pixmap;
953c81a
+		int width, height;
953c81a
+		cairo_t *cr;
953c81a
+		cairo_pattern_t *pattern;
953c81a
+
953c81a
+		source_pixmap = gdk_pixmap_foreign_new (*(Pixmap *) data);
953c81a
+		gdk_drawable_set_colormap (source_pixmap, gdk_screen_get_default_colormap (screen));
953c81a
+
953c81a
+		width = gdk_screen_get_width (screen);
953c81a
+		height = gdk_screen_get_width (screen);
953c81a
+
953c81a
+		pixmap = gdk_pixmap_new (source_pixmap != NULL? source_pixmap :
953c81a
+                                         gdk_screen_get_root_window (screen),
953c81a
+                                         width, height, -1);
953c81a
+
953c81a
+		cr = gdk_cairo_create (pixmap);
953c81a
+                if (source_pixmap != NULL) {
953c81a
+			gdk_cairo_set_source_pixmap (cr, source_pixmap, 0, 0);
953c81a
+			pattern = cairo_get_source (cr);
953c81a
+			cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
953c81a
+                } else {
953c81a
+			cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
953c81a
+		}
953c81a
+		cairo_paint (cr);
953c81a
+
953c81a
+		if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
953c81a
+		    g_object_unref (pixmap);
953c81a
+		    pixmap = NULL;
953c81a
+		}
953c81a
+		cairo_destroy (cr);
953c81a
+
953c81a
+		g_object_unref (source_pixmap);
953c81a
+	    }
953c81a
+	    XFree (data);
953c81a
+	}
953c81a
+
953c81a
+	return pixmap;
953c81a
+}
953c81a
+
953c81a
+static void
99fa927
+gnome_bg_set_root_pixmap_id (GdkScreen *screen,
953c81a
+			     GdkPixmap *pixmap)
99fa927
 {
99fa927
 	int      result;
99fa927
 	gint     format;
6e3a31a
@@ -1030,24 +1140,19 @@ gnome_bg_set_pixmap_as_root (GdkScreen *
6e3a31a
 	Atom     type;
99fa927
 	Display *display;
99fa927
 	int      screen_num;
6e3a31a
-	
99fa927
-	g_return_if_fail (screen != NULL);
99fa927
-	g_return_if_fail (pixmap != NULL);
953c81a
-	
6e3a31a
+
99fa927
 	screen_num = gdk_screen_get_number (screen);
99fa927
-	
953c81a
 	data_esetroot = NULL;
6e3a31a
+
6e3a31a
 	display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
6e3a31a
-	
f3623b9
-	XGrabServer (display);
6e3a31a
-	
6e3a31a
+
99fa927
 	result = XGetWindowProperty (
99fa927
 		display, RootWindow (display, screen_num),
6e3a31a
 		gdk_x11_get_xatom_by_name ("ESETROOT_PMAP_ID"),
6e3a31a
 		0L, 1L, False, XA_PIXMAP,
6e3a31a
 		&type, &format, &nitems, &bytes_after,
6e3a31a
 		&data_esetroot);
6e3a31a
-	
6e3a31a
+
6e3a31a
 	if (data_esetroot != NULL) {
6e3a31a
 		if (result == Success && type == XA_PIXMAP &&
6e3a31a
 		    format == 32 &&
6e3a31a
@@ -1059,9 +1164,9 @@ gnome_bg_set_pixmap_as_root (GdkScreen *
6e3a31a
 		}
6e3a31a
 		XFree (data_esetroot);
6e3a31a
 	}
6e3a31a
-	
6e3a31a
+
6e3a31a
 	pixmap_id = GDK_WINDOW_XWINDOW (pixmap);
6e3a31a
-	
6e3a31a
+
6e3a31a
 	XChangeProperty (display, RootWindow (display, screen_num),
6e3a31a
 			 gdk_x11_get_xatom_by_name ("ESETROOT_PMAP_ID"),
6e3a31a
 			 XA_PIXMAP, 32, PropModeReplace,
953c81a
@@ -1070,14 +1175,72 @@ gnome_bg_set_pixmap_as_root (GdkScreen *
953c81a
 			 gdk_x11_get_xatom_by_name ("_XROOTPMAP_ID"), XA_PIXMAP,
99fa927
 			 32, PropModeReplace,
99fa927
 			 (guchar *) &pixmap_id, 1);
99fa927
+}
99fa927
+
99fa927
+/* Set the root pixmap, and properties pointing to it. We
99fa927
+ * do this atomically with XGrabServer to make sure that
99fa927
+ * we won't leak the pixmap if somebody else it setting
99fa927
+ * it at the same time. (This assumes that they follow the
99fa927
+ * same conventions we do)
99fa927
+ */
99fa927
+void 
99fa927
+gnome_bg_set_pixmap_as_root (GdkScreen *screen, GdkPixmap *pixmap)
99fa927
+{
99fa927
+	Display *display;
99fa927
+	int      screen_num;
6e3a31a
 	
99fa927
+	g_return_if_fail (screen != NULL);
99fa927
+	g_return_if_fail (pixmap != NULL);
953c81a
+	
99fa927
+	screen_num = gdk_screen_get_number (screen);
99fa927
+	display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
99fa927
+
f3623b9
+	XGrabServer (display);
f3623b9
+
953c81a
+	gnome_bg_set_root_pixmap_id (screen, pixmap);
6e3a31a
+
953c81a
 	XSetWindowBackgroundPixmap (display, RootWindow (display, screen_num),
953c81a
-				    pixmap_id);
99fa927
+				    GDK_PIXMAP_XID (pixmap));
953c81a
 	XClearWindow (display, RootWindow (display, screen_num));
6e3a31a
-	
6e3a31a
-	XUngrabServer (display);
6e3a31a
-	
f3623b9
+
6e3a31a
 	XFlush (display);
6e3a31a
+
6e3a31a
+	XUngrabServer (display);
99fa927
+}
6e3a31a
+
99fa927
+GnomeBGCrossfade * 
99fa927
+gnome_bg_set_pixmap_as_root_with_crossfade (GdkScreen    *screen,
99fa927
+                                       GdkPixmap    *pixmap,
99fa927
+                                       GMainContext *context)
99fa927
+{
f3623b9
+	GdkDisplay *display;
99fa927
+	GdkWindow *root_window;
99fa927
+	GdkPixmap *old_pixmap;
99fa927
+	int      width, height;
99fa927
+	GnomeBGCrossfade *fade;
99fa927
+
99fa927
+	g_return_val_if_fail (screen != NULL, 0);
99fa927
+	g_return_val_if_fail (pixmap != NULL, 0);
99fa927
+
99fa927
+	root_window = gdk_screen_get_root_window (screen);
99fa927
+
99fa927
+	width = gdk_screen_get_width (screen);
99fa927
+	height = gdk_screen_get_height (screen);
99fa927
+
99fa927
+	fade = gnome_bg_crossfade_new (width, height);
99fa927
+
f3623b9
+	display = gdk_screen_get_display (screen);
f3623b9
+	gdk_x11_display_grab (display);
953c81a
+	old_pixmap = gnome_bg_get_pixmap_from_root (screen);
953c81a
+	gnome_bg_set_root_pixmap_id (screen, pixmap);
99fa927
+	gnome_bg_crossfade_set_start_pixmap (fade, old_pixmap);
99fa927
+	gnome_bg_crossfade_set_end_pixmap (fade, pixmap);
f3623b9
+	gdk_display_flush (display);
f3623b9
+	gdk_x11_display_ungrab (display);
99fa927
+
99fa927
+	gnome_bg_crossfade_start (fade, root_window, context);
99fa927
+
99fa927
+	return fade;
99fa927
 }
99fa927
 
99fa927
 
953c81a
@@ -1343,7 +1506,7 @@ on_timeout (gpointer data)
a5fb6e1
 
a5fb6e1
 	bg->timeout_id = 0;
a5fb6e1
 	
a5fb6e1
-	queue_changed (bg);
a5fb6e1
+	queue_transitioned (bg);
a5fb6e1
 
a5fb6e1
 	return FALSE;
a5fb6e1
 }
6e3a31a
diff -up /dev/null gnome-desktop-2.24.0/libgnome-desktop/gnome-bg-crossfade.c
6e3a31a
--- /dev/null	2008-10-20 05:51:19.470282574 -0400
1a3da47
+++ gnome-desktop-2.24.0/libgnome-desktop/gnome-bg-crossfade.c	2008-10-20 13:58:17.000000000 -0400
1a3da47
@@ -0,0 +1,451 @@
99fa927
+/* gnome-bg-crossfade.h - fade window background between two pixmaps
99fa927
+ *
99fa927
+ * Copyright (C) 2008 Red Hat, Inc.
99fa927
+ *
99fa927
+ * This program is free software; you can redistribute it and/or
99fa927
+ * modify it under the terms of the GNU Library General Public License
99fa927
+ * as published by the Free Software Foundation; either version 2 of
99fa927
+ * the License, or (at your option) any later version.
99fa927
+ *
99fa927
+ * This program is distributed in the hope that it will be useful, but
99fa927
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
99fa927
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
99fa927
+ * Library General Public License for more details.
99fa927
+ *
99fa927
+ * You should have received a copy of the GNU Library General Public
99fa927
+ * License along with this program; if not, write to the Free Software
99fa927
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
99fa927
+ * 02111-1307, USA.
99fa927
+ *
99fa927
+ * Author: Ray Strode <rstrode@redhat.com>
99fa927
+*/
99fa927
+
99fa927
+#include <string.h>
99fa927
+#include <math.h>
99fa927
+#include <stdarg.h>
99fa927
+
99fa927
+#include <gio/gio.h>
99fa927
+
99fa927
+#include <gdk/gdk.h>
99fa927
+#include <gdk/gdkx.h>
99fa927
+#include <X11/Xlib.h>
99fa927
+#include <X11/Xatom.h>
99fa927
+
99fa927
+#include <cairo.h>
99fa927
+#include <cairo-xlib.h>
99fa927
+
99fa927
+#include <libgnomeui/libgnomeui.h>
99fa927
+
99fa927
+#define GNOME_DESKTOP_USE_UNSTABLE_API
99fa927
+#include <libgnomeui/gnome-bg.h>
99fa927
+#include "libgnomeui/gnome-bg-crossfade.h"
99fa927
+
99fa927
+struct _GnomeBGCrossfadePrivate
99fa927
+{
99fa927
+	GObject		 parent_instance;
99fa927
+	GdkWindow	*window;
99fa927
+	int              width;
99fa927
+	int              height;
99fa927
+	GdkPixmap	*fading_pixmap;
99fa927
+	GdkPixmap	*end_pixmap;
99fa927
+	gdouble		 start_time;
6e3a31a
+	gdouble		 total_duration;
99fa927
+	guint		 timeout_id;
6e3a31a
+	guint		 is_first_frame : 1;
99fa927
+};
99fa927
+
99fa927
+enum {
99fa927
+	PROP_0,
99fa927
+	PROP_WIDTH,
99fa927
+	PROP_HEIGHT,
99fa927
+};
99fa927
+
99fa927
+enum {
99fa927
+	FINISHED,
99fa927
+	NUMBER_OF_SIGNALS
99fa927
+};
99fa927
+
99fa927
+static guint signals[NUMBER_OF_SIGNALS] = { 0 };
99fa927
+
99fa927
+G_DEFINE_TYPE (GnomeBGCrossfade, gnome_bg_crossfade, G_TYPE_OBJECT)
99fa927
+#define GNOME_BG_CROSSFADE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o),\
99fa927
+			                   GNOME_TYPE_BG_CROSSFADE,\
99fa927
+			                   GnomeBGCrossfadePrivate))
99fa927
+
99fa927
+static void
99fa927
+gnome_bg_crossfade_set_property (GObject      *object,
99fa927
+				 guint         property_id,
99fa927
+				 const GValue *value,
99fa927
+				 GParamSpec   *pspec)
99fa927
+{
99fa927
+	GnomeBGCrossfade *fade;
99fa927
+
99fa927
+	g_assert (GNOME_IS_BG_CROSSFADE (object));
99fa927
+
99fa927
+	fade = GNOME_BG_CROSSFADE (object);
99fa927
+
99fa927
+	switch (property_id)
99fa927
+	{
99fa927
+	case PROP_WIDTH:
99fa927
+		fade->priv->width = g_value_get_int (value);
99fa927
+		break;
99fa927
+	case PROP_HEIGHT:
99fa927
+		fade->priv->height = g_value_get_int (value);
99fa927
+		break;
99fa927
+	default:
99fa927
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
99fa927
+		break;
99fa927
+	}
99fa927
+}
99fa927
+
99fa927
+static void
99fa927
+gnome_bg_crossfade_get_property (GObject    *object,
99fa927
+			     guint       property_id,
99fa927
+			     GValue     *value,
99fa927
+			     GParamSpec *pspec)
99fa927
+{
99fa927
+	GnomeBGCrossfade *fade;
99fa927
+
99fa927
+	g_assert (GNOME_IS_BG_CROSSFADE (object));
99fa927
+
99fa927
+	fade = GNOME_BG_CROSSFADE (object);
99fa927
+
99fa927
+	switch (property_id)
99fa927
+	{
99fa927
+	case PROP_WIDTH:
99fa927
+		g_value_set_int (value, fade->priv->width);
99fa927
+		break;
99fa927
+	case PROP_HEIGHT:
99fa927
+		g_value_set_int (value, fade->priv->height);
99fa927
+		break;
99fa927
+
99fa927
+	default:
99fa927
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
99fa927
+		break;
99fa927
+	}
99fa927
+}
99fa927
+
99fa927
+static void
99fa927
+gnome_bg_crossfade_finalize (GObject *object)
99fa927
+{
99fa927
+	GnomeBGCrossfade *fade;
99fa927
+
99fa927
+	fade = GNOME_BG_CROSSFADE (object);
99fa927
+
99fa927
+	if (fade->priv->fading_pixmap != NULL) {
99fa927
+		g_object_unref (fade->priv->fading_pixmap);
99fa927
+		fade->priv->fading_pixmap = NULL;
99fa927
+	}
99fa927
+
99fa927
+	if (fade->priv->end_pixmap != NULL) {
99fa927
+		g_object_unref (fade->priv->end_pixmap);
99fa927
+		fade->priv->end_pixmap = NULL;
99fa927
+	}
99fa927
+
99fa927
+	if (fade->priv->timeout_id != 0) {
99fa927
+		g_source_remove (fade->priv->timeout_id);
99fa927
+		fade->priv->timeout_id = 0;
99fa927
+	}
99fa927
+
99fa927
+}
99fa927
+
99fa927
+static void
99fa927
+gnome_bg_crossfade_class_init (GnomeBGCrossfadeClass *fade_class)
99fa927
+{
99fa927
+	GObjectClass *gobject_class;
99fa927
+
99fa927
+	gobject_class = G_OBJECT_CLASS (fade_class);
99fa927
+
99fa927
+	gobject_class->get_property = gnome_bg_crossfade_get_property;
99fa927
+	gobject_class->set_property = gnome_bg_crossfade_set_property;
99fa927
+	gobject_class->finalize = gnome_bg_crossfade_finalize;
99fa927
+
99fa927
+	g_object_class_install_property (gobject_class,
99fa927
+					 PROP_WIDTH,
99fa927
+					 g_param_spec_int ("width",
99fa927
+						           "Window Width",
99fa927
+							    "Width of window to fade",
99fa927
+							    0, G_MAXINT, 0,
99fa927
+							    G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
99fa927
+
99fa927
+	g_object_class_install_property (gobject_class,
99fa927
+					 PROP_HEIGHT,
99fa927
+					 g_param_spec_int ("height", "Window Height",
99fa927
+						           "Height of window to fade on",
99fa927
+							   0, G_MAXINT, 0,
99fa927
+							   G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
99fa927
+	signals[FINISHED] = g_signal_new ("finished",
99fa927
+					  G_OBJECT_CLASS_TYPE (gobject_class),
99fa927
+					  G_SIGNAL_RUN_LAST, 0, NULL, NULL,
953c81a
+					  g_cclosure_marshal_VOID__OBJECT,
953c81a
+					  G_TYPE_NONE, 1, G_TYPE_OBJECT);
99fa927
+
99fa927
+	g_type_class_add_private (gobject_class, sizeof (GnomeBGCrossfadePrivate));
99fa927
+}
99fa927
+
99fa927
+static void
99fa927
+gnome_bg_crossfade_init (GnomeBGCrossfade *fade)
99fa927
+{
99fa927
+	fade->priv = GNOME_BG_CROSSFADE_GET_PRIVATE (fade);
99fa927
+}
99fa927
+
99fa927
+GnomeBGCrossfade *
99fa927
+gnome_bg_crossfade_new (int width,
99fa927
+			int height)
99fa927
+{
99fa927
+	GObject *object;
99fa927
+
99fa927
+	object = g_object_new (GNOME_TYPE_BG_CROSSFADE,
99fa927
+			       "width", width,
99fa927
+			       "height", height, NULL);
99fa927
+
99fa927
+	return (GnomeBGCrossfade *) object;
99fa927
+}
99fa927
+
99fa927
+static GdkPixmap *
953c81a
+tile_pixmap (GdkPixmap *pixmap,
99fa927
+	     int        width,
99fa927
+	     int        height)
99fa927
+{
99fa927
+	GdkPixmap *copy;
99fa927
+	cairo_t *cr;
99fa927
+
99fa927
+	copy = gdk_pixmap_new (pixmap, width, height, pixmap == NULL? 24 : -1);
99fa927
+
99fa927
+	cr = gdk_cairo_create (copy);
99fa927
+
99fa927
+	if (pixmap != NULL) {
99fa927
+		cairo_pattern_t *pattern;
99fa927
+		gdk_cairo_set_source_pixmap (cr, pixmap, 0.0, 0.0);
99fa927
+		pattern = cairo_get_source (cr);
99fa927
+		cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
99fa927
+	} else {
99fa927
+		GtkStyle *style;
99fa927
+		style = gtk_widget_get_default_style ();
99fa927
+		gdk_cairo_set_source_color (cr, &style->bg[GTK_STATE_NORMAL]);
99fa927
+	}
99fa927
+
99fa927
+	cairo_paint (cr);
99fa927
+
99fa927
+	if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
99fa927
+		g_object_unref (copy);
99fa927
+		copy = NULL;
99fa927
+	}
99fa927
+	cairo_destroy (cr);
99fa927
+
99fa927
+	return copy;
99fa927
+}
99fa927
+
99fa927
+gboolean
99fa927
+gnome_bg_crossfade_set_start_pixmap (GnomeBGCrossfade *fade,
99fa927
+				     GdkPixmap        *pixmap)
99fa927
+{
99fa927
+	g_return_val_if_fail (GNOME_IS_BG_CROSSFADE (fade), FALSE);
99fa927
+
99fa927
+	if (fade->priv->fading_pixmap != NULL) {
99fa927
+		g_object_unref (fade->priv->fading_pixmap);
99fa927
+		fade->priv->fading_pixmap = NULL;
99fa927
+	}
99fa927
+
953c81a
+	fade->priv->fading_pixmap = tile_pixmap (pixmap,
99fa927
+						 fade->priv->width,
99fa927
+						 fade->priv->height);
99fa927
+
99fa927
+	return fade->priv->fading_pixmap != NULL;
99fa927
+}
99fa927
+
99fa927
+gboolean
99fa927
+gnome_bg_crossfade_set_end_pixmap (GnomeBGCrossfade *fade,
99fa927
+				   GdkPixmap        *pixmap)
99fa927
+{
99fa927
+	g_return_val_if_fail (GNOME_IS_BG_CROSSFADE (fade), FALSE);
99fa927
+
99fa927
+	if (fade->priv->end_pixmap != NULL) {
99fa927
+		g_object_unref (fade->priv->end_pixmap);
99fa927
+		fade->priv->end_pixmap = NULL;
99fa927
+	}
99fa927
+
953c81a
+	fade->priv->end_pixmap = tile_pixmap (pixmap,
99fa927
+					      fade->priv->width,
99fa927
+					      fade->priv->height);
99fa927
+
99fa927
+	return fade->priv->end_pixmap != NULL;
99fa927
+}
99fa927
+
99fa927
+static gdouble
99fa927
+get_current_time (void)
99fa927
+{
99fa927
+	const double microseconds_per_second = 1000000.0;
99fa927
+	double       timestamp;
99fa927
+	GTimeVal     now;
99fa927
+
99fa927
+	g_get_current_time (&now;;
99fa927
+
99fa927
+	timestamp = ((microseconds_per_second * now.tv_sec) + now.tv_usec) /
99fa927
+	            microseconds_per_second;
99fa927
+
99fa927
+	return timestamp;
99fa927
+}
99fa927
+
99fa927
+static gboolean
99fa927
+animations_are_disabled (GnomeBGCrossfade *fade)
99fa927
+{
99fa927
+	GtkSettings *settings;
99fa927
+	GdkScreen *screen;
99fa927
+	gboolean are_enabled;
99fa927
+
99fa927
+	if (fade->priv->window == NULL) {
99fa927
+		return FALSE;
99fa927
+	}
99fa927
+
99fa927
+	screen = gdk_drawable_get_screen (fade->priv->window);
99fa927
+
99fa927
+	settings = gtk_settings_get_for_screen (screen);
99fa927
+
c94920f
+	g_object_get (settings, "gtk-enable-animations", &are_enabled, NULL);
99fa927
+
99fa927
+	return !are_enabled;
99fa927
+}
99fa927
+
6e3a31a
+static void
6e3a31a
+draw_background (GnomeBGCrossfade *fade)
6e3a31a
+{
6e3a31a
+	if (GDK_WINDOW_TYPE (fade->priv->window) == GDK_WINDOW_FOREIGN ||
1a3da47
+	    GDK_WINDOW_TYPE (fade->priv->window) == GDK_WINDOW_ROOT) {
6e3a31a
+		GdkDisplay *display;
6e3a31a
+		display = gdk_drawable_get_display (fade->priv->window);
6e3a31a
+		gdk_window_clear (fade->priv->window);
6e3a31a
+		gdk_flush ();
6e3a31a
+	} else {
6e3a31a
+		gdk_window_invalidate_rect (fade->priv->window, NULL, FALSE);
6e3a31a
+		gdk_window_process_updates (fade->priv->window, FALSE);
6e3a31a
+	}
6e3a31a
+}
6e3a31a
+
99fa927
+static gboolean
99fa927
+on_tick (GnomeBGCrossfade *fade)
99fa927
+{
99fa927
+	gdouble now, percent_done;
99fa927
+	cairo_t *cr;
12a19ec
+	cairo_status_t status;
99fa927
+
99fa927
+	g_return_val_if_fail (GNOME_IS_BG_CROSSFADE (fade), FALSE);
99fa927
+
6e3a31a
+	now = get_current_time ();
99fa927
+
6e3a31a
+	percent_done = (now - fade->priv->start_time) / fade->priv->total_duration;
99fa927
+	percent_done = CLAMP (percent_done, 0.0, 1.0);
99fa927
+
6e3a31a
+	/* If it's taking a long time to get to the first frame,
1a3da47
+	 * then double the duration, so the user will get to see
6e3a31a
+	 * the effect.
6e3a31a
+	 */
6e3a31a
+	if (fade->priv->is_first_frame && percent_done > .33) {
6e3a31a
+		fade->priv->is_first_frame = FALSE;
6e3a31a
+		fade->priv->total_duration *= 1.5;
6e3a31a
+		return on_tick (fade);
6e3a31a
+	}
6e3a31a
+
99fa927
+	if (fade->priv->fading_pixmap == NULL) {
99fa927
+		return FALSE;
99fa927
+	}
99fa927
+
99fa927
+	if (animations_are_disabled (fade)) {
99fa927
+		return FALSE;
99fa927
+	}
99fa927
+
99fa927
+	/* We accumulate the results in place for performance reasons.
99fa927
+	 *
99fa927
+	 * This means 1) The fade is exponential, not linear (looks good!)
99fa927
+	 * 2) The rate of fade is not independent of frame rate. Slower machines
6069ad8
+	 * will get a slower fade (but never longer than .75 seconds), and
99fa927
+	 * even the fastest machines will get *some* fade because the framerate
99fa927
+	 * is capped.
99fa927
+	 */
99fa927
+	cr = gdk_cairo_create (fade->priv->fading_pixmap);
99fa927
+
99fa927
+	gdk_cairo_set_source_pixmap (cr, fade->priv->end_pixmap,
99fa927
+				     0.0, 0.0);
99fa927
+	cairo_paint_with_alpha (cr, percent_done);
953c81a
+
12a19ec
+	status = cairo_status (cr);
12a19ec
+	cairo_destroy (cr);
99fa927
+
12a19ec
+	if (status == CAIRO_STATUS_SUCCESS) {
6e3a31a
+		draw_background (fade);
6e3a31a
+	}
99fa927
+	return percent_done <= .99;
99fa927
+}
99fa927
+
99fa927
+static void
99fa927
+on_finished (GnomeBGCrossfade *fade)
99fa927
+{
99fa927
+	if (fade->priv->end_pixmap != NULL) {
99fa927
+		gdk_window_set_back_pixmap (fade->priv->window,
99fa927
+					    fade->priv->end_pixmap,
99fa927
+					    FALSE);
6e3a31a
+		draw_background (fade);
99fa927
+	}
99fa927
+
99fa927
+	if (fade->priv->fading_pixmap != NULL) {
99fa927
+		g_object_unref (fade->priv->fading_pixmap);
99fa927
+		fade->priv->fading_pixmap = NULL;
99fa927
+	}
99fa927
+
99fa927
+	if (fade->priv->end_pixmap != NULL) {
99fa927
+		g_object_unref (fade->priv->end_pixmap);
99fa927
+		fade->priv->end_pixmap = NULL;
99fa927
+	}
99fa927
+
99fa927
+	fade->priv->timeout_id = 0;
953c81a
+	g_signal_emit (fade, signals[FINISHED], 0, fade->priv->window);
99fa927
+}
99fa927
+
99fa927
+void
99fa927
+gnome_bg_crossfade_start (GnomeBGCrossfade *fade,
99fa927
+			  GdkWindow        *window,
99fa927
+			  GMainContext     *context)
99fa927
+{
99fa927
+	GSource *source;
99fa927
+
99fa927
+	g_return_if_fail (GNOME_IS_BG_CROSSFADE (fade));
99fa927
+	g_return_if_fail (fade->priv->fading_pixmap != NULL);
99fa927
+	g_return_if_fail (fade->priv->end_pixmap != NULL);
99fa927
+	g_return_if_fail (!gnome_bg_crossfade_is_started (fade));
99fa927
+
a5fb6e1
+	source = g_timeout_source_new (1000 / 60.0);
99fa927
+	g_source_set_callback (source,
99fa927
+			       (GSourceFunc) on_tick,
99fa927
+			       fade,
99fa927
+			       (GDestroyNotify) on_finished);
99fa927
+	fade->priv->timeout_id = g_source_attach (source, context);
99fa927
+	g_source_unref (source);
99fa927
+
99fa927
+	fade->priv->window = window;
99fa927
+	gdk_window_set_back_pixmap (fade->priv->window,
99fa927
+				    fade->priv->fading_pixmap,
99fa927
+				    FALSE);
1a3da47
+        draw_background (fade);
6e3a31a
+
6e3a31a
+	fade->priv->is_first_frame = TRUE;
6e3a31a
+	fade->priv->total_duration = .75;
953c81a
+	fade->priv->start_time = get_current_time ();
99fa927
+}
99fa927
+
99fa927
+gboolean
99fa927
+gnome_bg_crossfade_is_started (GnomeBGCrossfade *fade)
99fa927
+{
99fa927
+	g_return_val_if_fail (GNOME_IS_BG_CROSSFADE (fade), FALSE);
99fa927
+
99fa927
+	return fade->priv->timeout_id != 0;
99fa927
+}
99fa927
+
99fa927
+void
99fa927
+gnome_bg_crossfade_stop (GnomeBGCrossfade *fade)
99fa927
+{
99fa927
+	g_return_if_fail (GNOME_IS_BG_CROSSFADE (fade));
99fa927
+
99fa927
+	if (fade->priv->timeout_id != 0) {
99fa927
+		g_source_remove (fade->priv->timeout_id);
99fa927
+	}
99fa927
+}
6e3a31a
diff -up /dev/null gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/gnome-bg-crossfade.h
6e3a31a
--- /dev/null	2008-10-20 05:51:19.470282574 -0400
953c81a
+++ gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/gnome-bg-crossfade.h	2008-10-15 08:57:26.000000000 -0400
953c81a
@@ -0,0 +1,76 @@
99fa927
+/* gnome-bg-crossfade.h - fade window background between two pixmaps
99fa927
+
99fa927
+   Copyright 2008, Red Hat, Inc.
99fa927
+
99fa927
+   This file is part of the Gnome Library.
99fa927
+
99fa927
+   The Gnome Library is free software; you can redistribute it and/or
99fa927
+   modify it under the terms of the GNU Library General Public License as
99fa927
+   published by the Free Software Foundation; either version 2 of the
99fa927
+   License, or (at your option) any later version.
99fa927
+   
99fa927
+   The Gnome Library is distributed in the hope that it will be useful,
99fa927
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
99fa927
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
99fa927
+   Library General Public License for more details.
99fa927
+   
99fa927
+   You should have received a copy of the GNU Library General Public
99fa927
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
99fa927
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
99fa927
+   Boston, MA 02111-1307, USA.
99fa927
+
99fa927
+   Author: Ray Strode <rstrode@redhat.com>
99fa927
+*/
99fa927
+
99fa927
+#ifndef __GNOME_BG_CROSSFADE_H__
99fa927
+#define __GNOME_BG_CROSSFADE_H__
99fa927
+
99fa927
+#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
99fa927
+#error    GnomeBGCrossfade is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-bg-crossfade.h
99fa927
+#endif
99fa927
+
99fa927
+#include <libgnomeui/libgnomeui.h>
99fa927
+#include <gdk/gdk.h>
99fa927
+
99fa927
+G_BEGIN_DECLS
99fa927
+
99fa927
+#define GNOME_TYPE_BG_CROSSFADE            (gnome_bg_crossfade_get_type ())
99fa927
+#define GNOME_BG_CROSSFADE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_BG_CROSSFADE, GnomeBGCrossfade))
99fa927
+#define GNOME_BG_CROSSFADE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GNOME_TYPE_BG_CROSSFADE, GnomeBGCrossfadeClass))
99fa927
+#define GNOME_IS_BG_CROSSFADE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_BG_CROSSFADE))
99fa927
+#define GNOME_IS_BG_CROSSFADE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GNOME_TYPE_BG_CROSSFADE))
99fa927
+#define GNOME_BG_CROSSFADE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GNOME_TYPE_BG_CROSSFADE, GnomeBGCrossfadeClass))
99fa927
+
99fa927
+typedef struct _GnomeBGCrossfadePrivate GnomeBGCrossfadePrivate;
99fa927
+typedef struct _GnomeBGCrossfade GnomeBGCrossfade;
99fa927
+typedef struct _GnomeBGCrossfadeClass GnomeBGCrossfadeClass;
99fa927
+
99fa927
+struct _GnomeBGCrossfade
99fa927
+{
99fa927
+	GObject parent_object;
99fa927
+
99fa927
+	GnomeBGCrossfadePrivate *priv;
99fa927
+};
99fa927
+
99fa927
+struct _GnomeBGCrossfadeClass
99fa927
+{
99fa927
+	GObjectClass parent_class;
99fa927
+
953c81a
+	void (* finished) (GnomeBGCrossfade *fade, GdkWindow *window);
99fa927
+};
99fa927
+
99fa927
+GType             gnome_bg_crossfade_get_type              (void);
99fa927
+GnomeBGCrossfade *gnome_bg_crossfade_new (int width, int height);
953c81a
+gboolean          gnome_bg_crossfade_set_start_pixmap (GnomeBGCrossfade *fade,
99fa927
+                                                      GdkPixmap *pixmap);
953c81a
+gboolean          gnome_bg_crossfade_set_end_pixmap (GnomeBGCrossfade *fade,
99fa927
+                                                    GdkPixmap *pixmap);
99fa927
+void              gnome_bg_crossfade_start (GnomeBGCrossfade *fade,
99fa927
+                                            GdkWindow        *window,
99fa927
+                                            GMainContext     *context);
99fa927
+gboolean          gnome_bg_crossfade_is_started (GnomeBGCrossfade *fade);
99fa927
+void              gnome_bg_crossfade_stop (GnomeBGCrossfade *fade);
99fa927
+
99fa927
+G_END_DECLS
99fa927
+
99fa927
+#endif
6e3a31a
diff -up gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/gnome-bg.h.fade gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/gnome-bg.h
d4fe16f
--- gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/gnome-bg.h.fade	2008-09-22 17:01:45.000000000 -0400
953c81a
+++ gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/gnome-bg.h	2008-10-14 17:49:44.000000000 -0400
99fa927
@@ -33,6 +33,8 @@
99fa927
 #include <gdk/gdk.h>
99fa927
 #include <gconf/gconf-client.h>
99fa927
 
99fa927
+#include <libgnomeui/gnome-bg-crossfade.h>
99fa927
+
99fa927
 G_BEGIN_DECLS
99fa927
 
99fa927
 #define GNOME_TYPE_BG            (gnome_bg_get_type ())
f3623b9
@@ -63,6 +65,8 @@ typedef enum {
f3623b9
 
f3623b9
 GType            gnome_bg_get_type              (void);
f3623b9
 GnomeBG *        gnome_bg_new                   (void);
f3623b9
+void             gnome_bg_ignore_changes        (GnomeBG *bg,
f3623b9
+                                                 gboolean should_ignore);
f3623b9
 void             gnome_bg_load_from_preferences (GnomeBG               *bg,
f3623b9
 						 GConfClient           *client);
f3623b9
 void             gnome_bg_save_to_preferences   (GnomeBG               *bg,
953c81a
@@ -109,6 +113,10 @@ gboolean         gnome_bg_changes_with_s
99fa927
 void             gnome_bg_set_pixmap_as_root    (GdkScreen             *screen,
99fa927
 						 GdkPixmap             *pixmap);
99fa927
 
99fa927
+GnomeBGCrossfade *gnome_bg_set_pixmap_as_root_with_crossfade (GdkScreen *screen,
99fa927
+                                                              GdkPixmap *pixmap,
99fa927
+                                                              GMainContext *context);
953c81a
+GdkPixmap *gnome_bg_get_pixmap_from_root (GdkScreen *screen);
99fa927
 
99fa927
 G_END_DECLS
99fa927
 
6e3a31a
diff -up gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/Makefile.am.fade gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/Makefile.am
d4fe16f
--- gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/Makefile.am.fade	2008-09-22 17:01:45.000000000 -0400
953c81a
+++ gnome-desktop-2.24.0/libgnome-desktop/libgnomeui/Makefile.am	2008-10-14 17:49:44.000000000 -0400
99fa927
@@ -3,6 +3,7 @@ libgnomeui_desktop_HEADERS =	\
99fa927
 	gnome-ditem-edit.h	\
99fa927
 	gnome-hint.h		\
99fa927
 	gnome-bg.h		\
99fa927
+	gnome-bg-crossfade.h		\
99fa927
 	gnome-rr.h		\
99fa927
 	gnome-rr-config.h	\
99fa927
 	gnome-rr-labeler.h
6e3a31a
diff -up gnome-desktop-2.24.0/libgnome-desktop/Makefile.am.fade gnome-desktop-2.24.0/libgnome-desktop/Makefile.am
d4fe16f
--- gnome-desktop-2.24.0/libgnome-desktop/Makefile.am.fade	2008-09-22 17:01:45.000000000 -0400
953c81a
+++ gnome-desktop-2.24.0/libgnome-desktop/Makefile.am	2008-10-14 17:49:44.000000000 -0400
99fa927
@@ -21,6 +21,7 @@ libgnome_desktop_2_la_SOURCES = \
99fa927
 	gnome-ditem-edit.c	\
99fa927
 	gnome-hint.c		\
99fa927
 	gnome-bg.c		\
99fa927
+	gnome-bg-crossfade.c	\
99fa927
 	display-name.c		\
99fa927
 	gnome-rr.c		\
99fa927
 	gnome-rr-config.c	\