Index: eel-background.c
===================================================================
RCS file: /cvs/gnome/eel/eel/eel-background.c,v
retrieving revision 1.45
diff -u -p -r1.45 eel-background.c
--- eel-background.c	5 Feb 2003 18:30:31 -0000	1.45
+++ eel-background.c	14 Mar 2005 02:02:55 -0000
@@ -44,6 +44,12 @@
 #include <math.h>
 #include <stdio.h>
 
+/* To work with desktop background */
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <gdk/gdkx.h>
+
+
 /* FIXME: This could really be eliminated now */
 typedef struct {
 	/* 24-bit RGB buffer for rendering */
@@ -82,6 +88,11 @@ static void     eel_background_draw_to_c
 static void     eel_background_draw_aa                   (EelBackground *background,
 							  EelCanvasBuf  *buffer);
 					  
+static gboolean eel_background_swap_timeout              (gpointer data);
+static void     eel_background_cancel_swap               (EelBackground *background);
+static void     eel_background_start_swap                (EelBackground *background);
+static void     eel_background_ensure_image_nonswapped   (EelBackground *background);
+
 
 EEL_CLASS_BOILERPLATE (EelBackground, eel_background, GTK_TYPE_OBJECT)
 
@@ -139,6 +150,11 @@ struct EelBackgroundDetails {
 	gboolean background_changes_with_size;
 
 	gboolean use_base;
+	
+	/* Desktop background swap */
+	gulong swap_timeout;
+	/* Desktop screen size watcher */
+	gulong screen_size_handler;
 };
 
 static void
@@ -231,6 +247,7 @@ eel_background_remove_current_image (Eel
 		g_object_unref (background->details->image);
 		background->details->image = NULL;
 	}
+	eel_background_cancel_swap (background);
 }
 
 static void
@@ -545,6 +562,51 @@ eel_background_image_totally_obscures (E
 	}
 }
 
+static gboolean
+eel_background_swap_timeout (gpointer data)
+{	
+	EelBackground *background = EEL_BACKGROUND (data);
+	eel_background_remove_current_image (background);
+	background->details->swap_timeout = 0;
+	return FALSE;
+}
+
+static void
+eel_background_cancel_swap (EelBackground *background)
+{
+    if (background->details->swap_timeout > 0)
+	    {
+		g_source_remove (background->details->swap_timeout);
+		background->details->swap_timeout = 0;
+	    }
+}
+
+static void
+eel_background_start_swap (EelBackground *background)
+{
+    if (g_object_get_data (G_OBJECT (background), "is_desktop") == 0) 	
+	    return;
+    if (background->details->image_uri == NULL || background->details->image == NULL) 	
+	    return;
+
+    if (background->details->swap_timeout > 0)
+		g_source_remove (background->details->swap_timeout);
+    background->details->swap_timeout =
+       g_timeout_add (30000, eel_background_swap_timeout, background);	
+}
+
+static void
+eel_background_ensure_image_nonswapped (EelBackground *background)
+{
+    if (g_object_get_data (G_OBJECT (background), "is_desktop") == 0)
+	return;
+
+    if (background->details->image_uri != NULL && background->details->image == NULL)
+			eel_background_start_loading_image (background, FALSE, FALSE);
+    eel_background_start_swap (background);
+    return;
+}
+
 static void
 eel_background_ensure_image_scaled (EelBackground *background, int dest_width, int dest_height)
 {
@@ -646,8 +708,20 @@ get_pixmap_size (EelBackground    *backg
 	
 	if (background->details->image == NULL) {
 		if (background->details->is_solid_color) {
-			*changes_with_size = FALSE;
-			return FALSE;
+			if (g_object_get_data (G_OBJECT (background), "is_desktop") == 0) {
+	    	    		*changes_with_size = FALSE;
+				return FALSE;
+			} else {
+				/* We should create small pixmap in this
+				 * case too since most transparent programs
+				 * like terminal or panel requires background
+				 * pixmap and can't handle just color 
+				 */
+				*pixmap_width = GRADIENT_PIXMAP_TILE_SIZE;
+		    		*pixmap_height = GRADIENT_PIXMAP_TILE_SIZE;
+	    	    		*changes_with_size = FALSE;				
+				return TRUE;
+			}
 		}
 		if (background->details->gradient_is_horizontal) {
 			*pixmap_width = entire_width;
@@ -709,6 +783,114 @@ eel_background_unrealize (EelBackground 
 	background->details->background_entire_height = 0;
 }
 
+/* 
+/* Create a persistent pixmap. We create a separate display
+ * and set the closedown mode on it to RetainPermanent.
+ */
+static GdkPixmap *
+make_root_pixmap (GdkScreen *screen, gint width, gint height)
+{
+	Display *display;
+        const char *display_name;
+	Pixmap result;
+	GdkPixmap *gdk_pixmap;
+	int screen_num;
+
+	screen_num = gdk_screen_get_number (screen);
+
+	gdk_flush ();
+
+	display_name = gdk_display_get_name (gdk_screen_get_display (screen));
+	display = XOpenDisplay (display_name);
+
+        if (display == NULL) {
+                g_warning ("Unable to open display '%s' when setting background pixmap\n",
+                           (display_name) ? display_name : "NULL");
+                return NULL;
+        }
+
+	/* Desktop background pixmap should be created from 
+	 * dummy X client since most applications will try to
+	 * kill it with XKillClient later when changing pixmap
+	 */
+
+	XSetCloseDownMode (display, RetainPermanent);
+
+	result = XCreatePixmap (display,
+				RootWindow (display, screen_num),
+				width, height,
+				DefaultDepth (display, screen_num));
+
+	XCloseDisplay (display);
+
+	gdk_pixmap = gdk_pixmap_foreign_new (result);
+	gdk_drawable_set_colormap (GDK_DRAWABLE (gdk_pixmap),
+				   gdk_drawable_get_colormap (gdk_screen_get_root_window (screen)));
+
+	return gdk_pixmap;
+}
+
+/* Set the root pixmap, and properties pointing to it. We
+ * do this atomically with XGrabServer to make sure that
+ * we won't leak the pixmap if somebody else it setting
+ * it at the same time. (This assumes that they follow the
+ * same conventions we do)
+ */
+static void 
+set_root_pixmap (GdkPixmap *pixmap, GdkScreen *screen)
+{
+	int      result;
+	gint     format;
+	gulong   nitems;
+	gulong   bytes_after;
+	guchar  *data_esetroot;
+	Pixmap   pixmap_id;
+	Atom     type;
+	Display *display;
+	int      screen_num;
+
+	screen_num = gdk_screen_get_number (screen);
+
+	data_esetroot = NULL;
+	display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
+
+	XGrabServer (display);
+
+	result = XGetWindowProperty (display, RootWindow (display, screen_num),
+				     gdk_x11_get_xatom_by_name ("ESETROOT_PMAP_ID"),
+				     0L, 1L, False, XA_PIXMAP,
+				     &type, &format, &nitems, &bytes_after,
+				     &data_esetroot);
+
+	if (data_esetroot != NULL) {
+		if (result == Success && type == XA_PIXMAP && format == 32 && nitems == 1) {
+			gdk_error_trap_push ();
+			XKillClient (display, *(Pixmap *)data_esetroot);
+			gdk_flush ();
+			gdk_error_trap_pop ();
+		}
+		XFree (data_esetroot);
+	}
+
+	pixmap_id = GDK_WINDOW_XWINDOW (pixmap);
+
+	XChangeProperty (display, RootWindow (display, screen_num),
+			 gdk_x11_get_xatom_by_name ("ESETROOT_PMAP_ID"), XA_PIXMAP,
+			 32, PropModeReplace,
+			 (guchar *) &pixmap_id, 1);
+	XChangeProperty (display, RootWindow (display, screen_num),
+			 gdk_x11_get_xatom_by_name ("_XROOTPMAP_ID"), XA_PIXMAP,
+			 32, PropModeReplace,
+			 (guchar *) &pixmap_id, 1);
+
+	XSetWindowBackgroundPixmap (display, RootWindow (display, screen_num), pixmap_id);
+	XClearWindow (display, RootWindow (display, screen_num));
+
+	XUngrabServer (display);
+	
+	XFlush (display);
+}
+
 static gboolean
 eel_background_ensure_realized (EelBackground *background, GdkWindow *window,
 				int entire_width, int entire_height)
@@ -724,6 +906,8 @@ eel_background_ensure_realized (EelBackg
 
 	/* Try to parse the color spec.  If we fail, default to the style's color */
 
+        eel_background_ensure_image_nonswapped (background);
+
 	start_color_spec = eel_gradient_get_start_color_spec (background->details->color);
 
 	if (start_color_spec && eel_gdk_color_parse (start_color_spec, &color))
@@ -731,14 +915,13 @@ eel_background_ensure_realized (EelBackg
 	else {
 		/* Get the widget to which the window belongs and its style as well */
 		gdk_window_get_user_data (window, (void **) &widget);
-		g_assert (widget != NULL);
-
-		style = gtk_widget_get_style (widget);
-
-		if (background->details->use_base) {
-			background->details->background_color = style->base[GTK_STATE_NORMAL];
-		} else {
-			background->details->background_color = style->bg[GTK_STATE_NORMAL];
+		if (widget != NULL) {
+    			style = gtk_widget_get_style (widget);
+	    		if (background->details->use_base) {
+				background->details->background_color = style->base[GTK_STATE_NORMAL];
+			} else {
+		    		background->details->background_color = style->bg[GTK_STATE_NORMAL];
+			}
 		}
 	}
 
@@ -766,7 +949,12 @@ eel_background_ensure_realized (EelBackg
 	changed = FALSE;
 	if (get_pixmap_size (background, entire_width, entire_height,
 			      &pixmap_width, &pixmap_height, &background->details->background_changes_with_size)) {
-		pixmap = gdk_pixmap_new (window, pixmap_width, pixmap_height, -1);
+		
+		if (g_object_get_data (G_OBJECT (background), "is_desktop") == 0) 	
+			pixmap = gdk_pixmap_new (window, pixmap_width, pixmap_height, -1);
+		else
+			pixmap = make_root_pixmap (gdk_drawable_get_screen(window), pixmap_width, pixmap_height);
+		
 		gc = gdk_gc_new (pixmap);
 		eel_background_pre_draw (background,  entire_width, entire_height);
 		eel_background_draw (background, pixmap, gc,
@@ -780,6 +968,8 @@ eel_background_ensure_realized (EelBackg
 	background->details->background_entire_width = entire_width;
 	background->details->background_entire_height = entire_height;
 	
+        eel_background_start_swap (background);
+	
 	return changed;
 }
 
@@ -1505,16 +1695,6 @@ eel_background_set_up_widget (EelBackgro
 
 	gdk_drawable_get_size (widget->window, &window_width, &window_height);
 
-	/* HACK HACK HACK HACK
-	 * Hack to work around the fact that bonoboplug/socket first realizes
-	 * the child at the wrong size. This allows us to avoid re-reading the
-	 * image when we later get the right size */
-	if (g_object_get_data (G_OBJECT (background), "is_desktop") != 0) {
-		screen = gtk_widget_get_screen (widget);
-		window_width = gdk_screen_get_width (screen);
-		window_height = gdk_screen_get_height (screen);
-	}
-	
 	pixmap = eel_background_get_pixmap_and_color (background,
 						      widget->window,
 						      window_width,
@@ -1535,9 +1715,14 @@ eel_background_set_up_widget (EelBackgro
 	if (pixmap && !changes_with_size) {
 		gdk_window_set_back_pixmap (window, pixmap, FALSE);
 	} else {
+		gdk_window_set_back_pixmap (window, NULL, FALSE);
 		gdk_window_set_background (window, &color);
 	}
-
+	
+	if (g_object_get_data (G_OBJECT (background), "is_desktop") != 0) {
+		set_root_pixmap (pixmap, gdk_drawable_get_screen (window));
+	} 	
+	
 	if (pixmap) {
 		g_object_unref (pixmap);
 	}
@@ -1566,6 +1751,13 @@ widget_style_set_cb (GtkWidget *widget, 
 }
 
 static void
+screen_size_changed (GdkScreen *screen, EelBackground *background)
+{
+	g_signal_emit (background, signals[APPEARANCE_CHANGED], 0);
+}
+
+
+static void
 widget_realize_cb (GtkWidget *widget, gpointer data)
 {
 	EelBackground *background;
@@ -1573,6 +1765,27 @@ widget_realize_cb (GtkWidget *widget, gp
 	background = EEL_BACKGROUND (data);
 	
 	eel_background_set_up_widget (background, widget);
+	
+        if (g_object_get_data (G_OBJECT (background), "is_desktop") != 0) {
+		
+		background->details->screen_size_handler = 
+			g_signal_connect (gtk_widget_get_screen (GTK_WIDGET (widget)), "size_changed",
+            						         G_CALLBACK (screen_size_changed), background);
+	}
+}
+
+static void
+widget_unrealize_cb (GtkWidget *widget, gpointer data)
+{
+	EelBackground *background;
+	
+	background = EEL_BACKGROUND (data);
+
+	if (background->details->screen_size_handler > 0) {
+		        g_signal_handler_disconnect (gtk_widget_get_screen (GTK_WIDGET (widget)),
+				                     background->details->screen_size_handler);
+			background->details->screen_size_handler = 0;
+	}
 }
 
 /* Gets the background attached to a widget.
@@ -1624,6 +1837,10 @@ eel_get_widget_background (GtkWidget *wi
 				 G_CALLBACK (widget_realize_cb),
 				 background,
 				 0);
+	g_signal_connect_object (widget, "unrealize",
+				 G_CALLBACK (widget_unrealize_cb),
+				 background,
+				 0);
 
 	return background;
 }
