[Nautilus-list] Desktop background, fixes and hacks



The attached patches implement two fixes and one hack that greatly
improve the efficiency of handling the desktop background.

Fix 1) eel_background_is_loaded() returned FALSE if the loading
previously failed. This caused code like:

    static void
    nautilus_file_update_desktop_pixmaps (EelBackground *background)
    {	
            if (eel_background_is_loaded (background)) {
                    image_loading_done_callback (background, TRUE, GINT_TO_POINTER (FALSE));
            } else {
                    gtk_signal_connect (GTK_OBJECT (background),
                                        "image_loading_done",
                                        GTK_SIGNAL_FUNC (image_loading_done_callback),
                                        GINT_TO_POINTER (TRUE));
            }
    }

To never realize that the image was loaded. Since everywhere else
treated failure to load the background as the same as not having
a background, it seems that TRUE should be returned in this
case. 


Fix 2) a pixmap as big as the screen was always used for the
root window background pixmap, even when (with a tile, solid
color or gradient) a much smaller tile could be used.

The attached patches adds a call eel_background_get_sample_size(),
which determines how big of an area needs to be rendered
for the tile. This can savs a tidy 5-6 megs on a larger display.

The magic 128 is the size of the GdkRGB dither matrix. Using
strips of this size for gradients avoids discontinuities
at the sample boundaries. 

In theory, the size when tiling a pixmap should be
LCM(width/height, 128), but generally tiles are "rougher "
than gradients, and the dither boundaries should be minimally
visible. (It's a small effect at 16bpp anyways.)

Also, in theory, we could use a value smaller than 128
if not dithering (at 24bpp), and even a solid color instead
of a tile, though the memory saved (when not using the LCM check) 
is comparitiviely small.


Hack) Nautilus spends a fair bit of time rendering the background
areas of the background to recompute whate is already set as
the background pixmap. The included patches add a special
mode to GnomeCanvas where it uses gdk_window_clear_area()
instead of gdk_draw_rectangle() to draw areas with nothing
but background.

This allows eel_background() to leave unrendered areas as
"background" rather than rendering into them, and thus take
advantage of the background optimization of GnomeCanvas.

The hackiness of this part of the patches comes mostly from
the fact that I used object data and g_module_open (NULL),
g_module_symbol() to achieve a "runtime optional" API, since
I didn't want to make our nautilus packages depend on a 
locally modified gnome-libs. If added as a straightforward:

 gnome_canvas_set/get_use_bg_pixmap ()

call it wouldn't be nearly as hacky. One could also imagine doing
this more comprehensively as a "canvas background drawing
function" facility and also, at the same time, eliminate the 
supplant-the-root-object hack in EelBackgruond.


The two fixes I think should definitely go in the mainline.  I'm less
sure about the hack. It reduces nautilus's share of CPU usage on my
(fast) machine from ~10% to ~1% when moving a window over a otherwise
empty desktop background, so it's a pretty big effect, but the
need to change GnomeCanvas makes things ugly.

Regards,
                                        Owen


--- gnome-libs-1.2.13/libgnomeui/gnome-canvas.c.bghack	Mon Jan  8 12:51:06 2001
+++ gnome-libs-1.2.13/libgnomeui/gnome-canvas.c	Mon Jul 23 16:45:01 2001
@@ -3172,6 +3172,18 @@
 #define IMAGE_WIDTH_AA 256
 #define IMAGE_HEIGHT_AA 64
 
+static GQuark bg_hack_quark = 0;
+void
+gnome_canvas_set_nautilus_bg_hack (GnomeCanvas *canvas,
+				   gboolean     use_bg_hack)
+{
+	if (!bg_hack_quark)
+		bg_hack_quark = g_quark_from_static_string ("nautilus-bg-hack");
+
+	use_bg_hack = use_bg_hack != FALSE;
+	gtk_object_set_data_by_id (GTK_OBJECT (canvas), bg_hack_quark, GUINT_TO_POINTER (use_bg_hack));
+}
+
 /* Repaints the areas in the canvas that need it */
 static void
 paint (GnomeCanvas *canvas)
@@ -3183,6 +3195,12 @@
 	GdkPixmap *pixmap;
 	ArtIRect *rects;
 	gint n_rects, i;
+	gboolean bg_hack = FALSE;
+
+	if (!bg_hack_quark)
+		bg_hack_quark = g_quark_from_static_string ("nautilus-bg-hack");
+	if (gtk_object_get_data_by_id (GTK_OBJECT (canvas), bg_hack_quark))
+		bg_hack = TRUE;
 
 	if (canvas->need_update) {
 		double affine[6];
@@ -3241,7 +3259,9 @@
 			if (canvas->aa) {
 				GnomeCanvasBuf buf;
 				GdkColor *color;
-
+				gint dest_x;
+				gint dest_y;
+				
 				buf.buf = g_new (guchar, IMAGE_WIDTH_AA * IMAGE_HEIGHT_AA * 3);
 				buf.buf_rowstride = IMAGE_WIDTH_AA * 3;
 				buf.rect.x0 = draw_x1;
@@ -3260,23 +3280,26 @@
 						canvas->root->object.klass)->render) (
 							canvas->root, &buf);
 
+				dest_x = draw_x1 - DISPLAY_X1 (canvas) + canvas->zoom_xofs;
+				dest_y = draw_y1 - DISPLAY_Y1 (canvas) + canvas->zoom_yofs;
+
 				if (buf.is_bg) {
-					gdk_rgb_gc_set_foreground (canvas->pixmap_gc, buf.bg_color);
-					gdk_draw_rectangle (canvas->layout.bin_window,
-							    canvas->pixmap_gc,
-							    TRUE,
-							    (draw_x1 - DISPLAY_X1 (canvas)
-							     + canvas->zoom_xofs),
-							    (draw_y1 - DISPLAY_Y1 (canvas)
-							     + canvas->zoom_yofs),
-							    width, height);
+					if (bg_hack)
+						gdk_window_clear_area (canvas->layout.bin_window,
+								       dest_x, dest_y,
+								       width, height);
+					else {
+						gdk_rgb_gc_set_foreground (canvas->pixmap_gc, buf.bg_color);
+						gdk_draw_rectangle (canvas->layout.bin_window,
+								    canvas->pixmap_gc,
+								    TRUE,
+								    dest_x, dest_y,
+								    width, height);
+					}
 				} else {
 					gdk_draw_rgb_image_dithalign (canvas->layout.bin_window,
 							    canvas->pixmap_gc,
-							    (draw_x1 - DISPLAY_X1 (canvas)
-							     + canvas->zoom_xofs),
-							    (draw_y1 - DISPLAY_Y1 (canvas)
-							     + canvas->zoom_yofs),
+						            dest_x, dest_y,
 							    width, height,
 							    canvas->dither,
 							    buf.buf,
diff -ur eel-1.0.1/eel/eel-background-canvas-group.c eel-1.0.1-bghack/eel/eel-background-canvas-group.c
--- eel-1.0.1/eel/eel-background-canvas-group.c	Wed Jun  6 15:33:24 2001
+++ eel-1.0.1-bghack/eel/eel-background-canvas-group.c	Mon Jul 23 22:44:23 2001
@@ -25,6 +25,7 @@
 #include <config.h>
 #include "eel-background-canvas-group.h"
 
+#include <gmodule.h>
 #include <libgnomeui/gnome-canvas.h>
 #include <libgnomeui/gnome-canvas-util.h>
 #include <libart_lgpl/art_rgb_affine.h>
@@ -191,15 +192,81 @@
 	EEL_CALL_PARENT (GNOME_CANVAS_ITEM_CLASS, draw, (item, drawable, x, y, width, height));				     
 }
 
+/* Check to see if our gnome canvas supports the "nautilus_bg_hack" (using a window background
+ * for the root layer, and that is enabled for this window
+ */
+static gboolean
+use_bg_hack (GnomeCanvas *canvas)
+{
+	static gboolean init = FALSE;
+	static gboolean have_bg_hack = FALSE;
+	static GQuark bg_hack_quark = 0;
+	
+	if (!init) {
+		GModule *module = g_module_open (NULL, 0);
+		void (*set_nautilus_bg_hack) (GnomeCanvas *canvas,
+					      gboolean     use_bg_hack);
+
+		if (module) {
+			if (g_module_symbol (module,
+					     "gnome_canvas_set_nautilus_bg_hack",
+					     (gpointer *)&set_nautilus_bg_hack)) {
+				have_bg_hack = TRUE;
+				bg_hack_quark = g_quark_from_static_string ("nautilus-bg-hack");
+			}
+		}
+		init = TRUE;
+	}
+
+	if (have_bg_hack)
+		return GPOINTER_TO_UINT (gtk_object_get_data_by_id (GTK_OBJECT (canvas), bg_hack_quark));
+	else
+		return FALSE;
+}
+
+/* See if we need to fill in the background for this buffer. We don't
+ * need to do this if we are using the "nautilus_bg_hack" and no children intersect
+ * the buffer's area
+ */
+static gboolean
+draw_bg_for_buffer (GnomeCanvasItem *item, GnomeCanvasBuf *buffer)
+{
+	GnomeCanvasGroup *group;
+	GnomeCanvasItem *child;
+	GList *list;
+
+	if (!use_bg_hack (item->canvas))
+		return TRUE;
+	
+	group = GNOME_CANVAS_GROUP (item);
+
+	for (list = group->item_list; list; list = list->next) {
+		child = list->data;
+
+		if (((child->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
+		     && ((child->x1 < buffer->rect.x1)
+			 && (child->y1 < buffer->rect.y1)
+			 && (child->x2 > buffer->rect.x0)
+			 && (child->y2 > buffer->rect.y0)))
+		    || ((GTK_OBJECT_FLAGS (child) & GNOME_CANVAS_ITEM_ALWAYS_REDRAW)
+			&& (child->x1 < child->canvas->redraw_x2)
+			&& (child->y1 < child->canvas->redraw_y2)
+			&& (child->x2 > child->canvas->redraw_x1)
+			&& (child->y2 > child->canvas->redraw_y2)))
+			return TRUE;
+	}
+
+	return FALSE;
+}
 
 /* draw the background for the anti-aliased canvas case */
 static void
 eel_background_canvas_group_render (GnomeCanvasItem *item, GnomeCanvasBuf *buffer)
 {
 	EelBackground *background;
-			
+
 	background = eel_get_widget_background (GTK_WIDGET (item->canvas));
-	if (background != NULL) {
+	if (background != NULL && draw_bg_for_buffer (item, buffer)) {
 		/* FIXME bugzilla.eazel.com 5349:
 		 * It shouldn't be necessary to call eel_background_pre_draw here.
 		 * However, eel_background_canvas_group_update (who should be the one
diff -ur eel-1.0.1/eel/eel-background.c eel-1.0.1-bghack/eel/eel-background.c
--- eel-1.0.1/eel/eel-background.c	Wed Jun  6 15:33:24 2001
+++ eel-1.0.1-bghack/eel/eel-background.c	Mon Jul 23 23:23:49 2001
@@ -715,6 +715,36 @@
 	buffer->is_buf = TRUE;
 }
 
+/* Get the size that can be used as a tiled pixmap to draw the background */
+void
+eel_background_get_sample_size (EelBackground *background,
+				int            entire_width,
+				int            entire_height,
+				int           *sample_width,
+				int           *sample_height)
+{
+	g_return_if_fail (EEL_IS_BACKGROUND (background));
+
+	if (background->details->image != NULL) {
+		if (background->details->image_placement == EEL_BACKGROUND_TILED) {
+			*sample_width = gdk_pixbuf_get_width (background->details->image);
+			*sample_height = gdk_pixbuf_get_height (background->details->image);
+		} else {
+			*sample_width = entire_width;
+			*sample_height = entire_height;
+		}
+	} else if (background->details->is_solid_color) {
+		*sample_width = 128;
+		*sample_height = 128;
+	} else if (background->details->gradient_is_horizontal) {
+		*sample_width = entire_width;
+		*sample_height = 128;
+	} else {
+		*sample_width = 128;
+		*sample_height = entire_height;
+	}
+}
+
 void
 eel_background_draw_to_canvas (EelBackground *background,
 				    GnomeCanvasBuf *buffer,
@@ -1094,8 +1124,7 @@
 {
 	g_return_val_if_fail (EEL_IS_BACKGROUND (background), FALSE);
 	
-	return background->details->image_uri == NULL ||
-		   (!eel_background_is_image_load_in_progress (background) && background->details->image != NULL);
+	return !eel_background_is_image_load_in_progress (background);
 }
 
 /**
diff -ur eel-1.0.1/eel/eel-background.h eel-1.0.1-bghack/eel/eel-background.h
--- eel-1.0.1/eel/eel-background.h	Wed Jun  6 15:33:24 2001
+++ eel-1.0.1-bghack/eel/eel-background.h	Mon Jul 23 23:05:04 2001
@@ -147,6 +147,13 @@
 									     int                          entire_width,
 									     int                          entire_height);
 							       
+/* Get the size that can be used as a tiled pixmap to draw the background */
+void                       eel_background_get_sample_size                   (EelBackground               *background,
+									     int                          entire_width,
+									     int                          entire_height,
+									     int                         *sample_width,
+									     int                         *sample_height);
+
 /* Handles a dragged color being dropped on a widget to change the background color. */
 void                        eel_background_receive_dropped_color            (EelBackground               *background,
 									     GtkWidget                   *widget,
diff -u -r nautilus-1.0.4/libnautilus-private/nautilus-directory-background.c nautilus-1.0.4-bghack/libnautilus-private/nautilus-directory-background.c
--- nautilus-1.0.4/libnautilus-private/nautilus-directory-background.c	Thu May 10 21:30:30 2001
+++ nautilus-1.0.4-bghack/libnautilus-private/nautilus-directory-background.c	Mon Jul 23 23:28:10 2001
@@ -41,6 +41,7 @@
 #include <libgnome/gnome-config.h>
 #include <libgnome/gnome-util.h>
 #include <libgnomevfs/gnome-vfs-utils.h>
+#include <gmodule.h>
 
 static void background_changed_callback     (EelBackground *background, 
                                              NautilusFile       *file);
@@ -647,11 +648,41 @@
 	XFlush(GDK_DISPLAY());
 }
 	
+/* Check to see if our gnome canvas supports the "nautilus_bg_hack", if so
+ * turn it on.
+ */
+static void
+turn_on_bg_hack (GnomeCanvas *canvas)
+{
+	static gboolean init = FALSE;
+	static gboolean have_bg_hack = FALSE;
+	static void (*set_nautilus_bg_hack) (GnomeCanvas *canvas,
+                                             gboolean     use_bg_hack) = NULL;
+        
+	if (!init) {
+		GModule *module = g_module_open (NULL, 0);
+		if (module) {
+			if (g_module_symbol (module,
+					     "gnome_canvas_set_nautilus_bg_hack",
+					     (gpointer *)&set_nautilus_bg_hack)) {
+				have_bg_hack = TRUE;
+			}
+		}
+		init = TRUE;
+	}
+        
+	if (have_bg_hack) {
+                set_nautilus_bg_hack (canvas, TRUE);
+        }
+}
+
 static void
 image_loading_done_callback (EelBackground *background, gboolean successful_load, void *disconnect_signal)
 {
 	int	      width;
 	int	      height;
+	int	      screen_width;
+	int	      screen_height;
 	GdkGC        *gc;
 	GdkPixmap    *pixmap;
 	GdkWindow    *background_window;
@@ -662,18 +693,24 @@
 					       disconnect_signal);
 	}
 
-	width  = gdk_screen_width ();
-	height = gdk_screen_height ();
+	screen_width  = gdk_screen_width ();
+	screen_height = gdk_screen_height ();
+
+        eel_background_get_sample_size (background,
+                                        screen_width, screen_height,
+                                        &width, &height);
 
-	pixmap = make_root_pixmap (width, height);
+        pixmap = make_root_pixmap (width, height);
 	gc = gdk_gc_new (pixmap);
-	eel_background_draw_to_drawable (background, pixmap, gc, 0, 0, width, height, width, height);
+	eel_background_draw_to_drawable (background, pixmap, gc, 0, 0, width, height, screen_width, screen_height);
 	gdk_gc_unref (gc);
 
 	set_root_pixmap (pixmap);
 
 	background_window = eel_background_get_desktop_background_window (background);
 	if (background_window != NULL) {
+                GnomeCanvas *canvas = gtk_object_get_data (GTK_OBJECT (background), "icon_container");
+                turn_on_bg_hack (canvas);
 		gdk_window_set_back_pixmap (background_window, pixmap, FALSE);
 	}
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]