[Nautilus-list] AA rectangles in non-aa mode + speedups



Here is a patch (discussed on irc) that adds an EelCanvasRect object that 
can be used to implement a selection rectangle in non-aa canvases that 
look like the one in the aa canvas. It uses Xrender with a fallback to 
gdk_pixbuf_render_to_drawable_alpha() if Xrender is not supported. On my 
machine they both seem to be about the same speed.

It also has the update optimization, so it only redraws the areas that 
actually changed color. This is a huge speedup when resizing large 
rectangles slightly. 

The second patch is for nautilus to use the eel canvas item for the 
selection rectangle. 

It also has some changes to nautilus-icon-container.c that change the way 
the seletion rectangle is kept on top of the canvas. The old way that 
always called gnome_canvas_item_raise_to_top() on the selection item all 
the time was pretty bad, as it kept redrawing the whole rectangle. Instead 
it creates the selection rectangle at top and makes sure no other item is 
moved on top of it.

Using this makes the selection quite snappy here, and it's one step 
towards killing smooth mode (in the sense of having two completely 
different implementations).

/ Alex
Index: libnautilus-private/nautilus-icon-container.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-icon-container.c,v
retrieving revision 1.244
diff -u -p -r1.244 nautilus-icon-container.c
--- libnautilus-private/nautilus-icon-container.c	2002/01/21 22:49:32	1.244
+++ libnautilus-private/nautilus-icon-container.c	2002/01/26 23:21:26
@@ -34,6 +34,7 @@
 #include "nautilus-marshal.h"
 #include "nautilus-theme.h"
 #include <eel/eel-background.h>
+#include <eel/eel-canvas-rect.h>
 #include <eel/eel-gdk-pixbuf-extensions.h>
 #include <eel/eel-glib-extensions.h>
 #include <eel/eel-gnome-extensions.h>
@@ -304,7 +305,35 @@ icon_set_size (NautilusIconContainer *co
 static void
 icon_raise (NautilusIcon *icon)
 {
-	gnome_canvas_item_raise_to_top (GNOME_CANVAS_ITEM (icon->item));
+	NautilusIconContainer *container;
+	NautilusIconRubberbandInfo *band_info;
+	GnomeCanvasItem *item;
+	GnomeCanvasGroup *parent;
+	GList *link;
+	int len;
+	
+	item = GNOME_CANVAS_ITEM (icon->item);
+	container = NAUTILUS_ICON_CONTAINER (item->canvas);
+	band_info = &container->details->rubberband_info;
+	
+	if (band_info->selection_rectangle) {
+		/* Don't raise items past the selection_rectangle */
+		if (!item->parent)
+			return;
+
+		parent = GNOME_CANVAS_GROUP (item->parent);
+		link = g_list_find (parent->item_list, item);
+		g_assert (link != NULL);
+
+		len = g_list_length (link);
+		if (len > 2) {
+			gnome_canvas_item_raise (item, len - 2);
+		} else if (len == 1) {
+			gnome_canvas_item_lower (item, 1);
+		}
+	} else {
+		gnome_canvas_item_raise_to_top (item);
+	}
 }
 
 static void
@@ -1430,7 +1459,8 @@ rubberband_timeout_callback (gpointer da
 	band_info = &container->details->rubberband_info;
 
 	g_assert (band_info->timer_id != 0);
-	g_assert (GNOME_IS_CANVAS_RECT (band_info->selection_rectangle));
+	g_assert (GNOME_IS_CANVAS_RECT (band_info->selection_rectangle) ||
+		  EEL_IS_CANVAS_RECT (band_info->selection_rectangle));
 
 	gdk_window_get_pointer (widget->window, &x, &y, NULL);
 	gdk_window_get_pointer (GTK_LAYOUT (widget)->bin_window, &bin_x, &bin_y, NULL);
@@ -1504,8 +1534,6 @@ rubberband_timeout_callback (gpointer da
 			   &band_info->prev_rect,
 			   &selection_rect);
 	
-	gnome_canvas_item_raise_to_top (band_info->selection_rectangle);
-	
 	band_info->prev_x = x;
 	band_info->prev_y = y;
 
@@ -1572,27 +1600,31 @@ start_rubberbanding (NautilusIconContain
 			 NULL);
 	
 	} else {
-		fill_color_str = nautilus_theme_get_theme_data ("directory", "selection_box_color");
+		fill_color_str = nautilus_theme_get_theme_data ("directory", "selection_box_color_rgba");
 		if (fill_color_str == NULL) {
-			fill_color_str = g_strdup ("#77BBDD");
+			fill_color = 0x77BBDD40;
+		} else {
+			fill_color = strtoul (fill_color_str, NULL, 0);
+			/* FIXME: Need error handling here. */
+			g_free (fill_color_str);
 		}
+		
+		outline_color = fill_color | 255;
 
 		band_info->selection_rectangle = gnome_canvas_item_new
 			(gnome_canvas_root
 			 (GNOME_CANVAS (container)),
-			 GNOME_TYPE_CANVAS_RECT,
+			 EEL_TYPE_CANVAS_RECT,
 			 "x1", band_info->start_x,
 			 "y1", band_info->start_y,
 			 "x2", band_info->start_x,
 			 "y2", band_info->start_y,
-			 "fill_color", fill_color_str,
-			 "fill_stipple", stipple,
-			 "outline_color", fill_color_str,
+			 "fill_color_rgba", fill_color,
+			 "outline_color_rgba", outline_color,
 			 "width_pixels", 1,
 			 NULL);
-		g_free (fill_color_str);
 	}
-	
+
 	band_info->prev_x = event->x;
 	band_info->prev_y = event->y;
 
@@ -3976,6 +4008,9 @@ nautilus_icon_container_add (NautilusIco
 	gnome_canvas_item_hide (GNOME_CANVAS_ITEM (icon->item));
 	icon->item->user_data = icon;
 
+	/* Make sure the icon is under the selection_rectangle */
+	icon_raise (icon);
+	
 	/* Put it on both lists. */
 	details->icons = g_list_prepend (details->icons, icon);
 	details->new_icons = g_list_prepend (details->new_icons, icon);
Index: acconfig.h
===================================================================
RCS file: /cvs/gnome/eel/acconfig.h,v
retrieving revision 1.6
diff -u -p -r1.6 acconfig.h
--- acconfig.h	2001/11/08 20:32:43	1.6
+++ acconfig.h	2002/01/26 23:18:17
@@ -9,3 +9,4 @@
 #undef HAVE_STPCPY
 #undef GNOME_EXPLICIT_TRANSLATION_DOMAIN
 #undef GETTEXT_PACKAGE
+#undef HAVE_RENDER
Index: configure.in
===================================================================
RCS file: /cvs/gnome/eel/configure.in,v
retrieving revision 1.45
diff -u -p -r1.45 configure.in
--- configure.in	2002/01/23 05:16:36	1.45
+++ configure.in	2002/01/26 23:18:17
@@ -129,6 +129,26 @@ AC_CHECK_FUNCS(setenv unsetenv putenv)
 
 dnl ===========================================================================
 
+
+#
+# Checks for Xft/XRender
+#
+have_render=false
+RENDER_LIBS=""
+
+AC_CHECK_LIB(Xrender, XRenderFindFormat, 
+    have_xft=true,:,-lXext $EEL_LIBS)
+
+if $have_xft ; then
+   RENDER_LIBS="-lXrender -lXext"
+   AC_DEFINE(HAVE_RENDER)
+fi
+
+AC_SUBST(RENDER_LIBS)
+
+    
+dnl ===========================================================================
+
 dnl Turn on the additional warnings last, so -Werror doesn't affect other tests.
 
 AC_ARG_ENABLE(more-warnings,
Index: eel/Makefile.am
===================================================================
RCS file: /cvs/gnome/eel/eel/Makefile.am,v
retrieving revision 1.48
diff -u -p -r1.48 Makefile.am
--- eel/Makefile.am	2002/01/19 00:19:28	1.48
+++ eel/Makefile.am	2002/01/26 23:18:17
@@ -22,6 +22,7 @@ libeel_2_la_SOURCES =				\
 	eel-art-gtk-extensions.c		\
 	eel-background.c			\
 	eel-background-style.c			\
+	eel-canvas-rect.c			\
 	eel-caption-table.c			\
 	eel-caption.c				\
 	eel-cell-renderer-pixbuf-list.c		\
@@ -80,6 +81,7 @@ eel_headers =					\
 	eel-art-gtk-extensions.h		\
 	eel-background.h			\
 	eel-background-style.h			\
+	eel-canvas-rect.h			\
 	eel-caption-table.h			\
 	eel-caption.h				\
 	eel-cell-renderer-pixbuf-list.h		\
Index: eel/eel-lib-self-check-functions.h
===================================================================
RCS file: /cvs/gnome/eel/eel/eel-lib-self-check-functions.h,v
retrieving revision 1.14
diff -u -p -r1.14 eel-lib-self-check-functions.h
--- eel/eel-lib-self-check-functions.h	2002/01/16 02:47:22	1.14
+++ eel/eel-lib-self-check-functions.h	2002/01/26 23:18:17
@@ -41,6 +41,7 @@ void eel_run_lib_self_checks (void);
 #define EEL_LIB_FOR_EACH_SELF_CHECK_FUNCTION(macro) \
 	macro (eel_self_check_art_extensions) \
 	macro (eel_self_check_background) \
+	macro (eel_self_check_canvas_rect) \
 	macro (eel_self_check_enumeration) \
 	macro (eel_self_check_gdk_extensions) \
 	macro (eel_self_check_gdk_pixbuf_extensions) \
Index: test/Makefile.am
===================================================================
RCS file: /cvs/gnome/eel/test/Makefile.am,v
retrieving revision 1.19
diff -u -p -r1.19 Makefile.am
--- test/Makefile.am	2002/01/19 00:19:30	1.19
+++ test/Makefile.am	2002/01/26 23:18:17
@@ -14,6 +14,7 @@ LDADD =\
 
 noinst_PROGRAMS =\
 	test-eel-background \
+	test-eel-canvas-items	\
 	test-eel-ellipsizing	\
 	test-eel-font-picker \
 	test-eel-gtk-style \
@@ -27,6 +28,7 @@ noinst_PROGRAMS =\
 	$(NULL)
 
 test_eel_background_SOURCES = test-eel-background.c
+test_eel_canvas_items_SOURCES = test-eel-canvas-items.c
 test_eel_ellipsizing_SOURCES = test-eel-ellipsizing.c
 test_eel_font_picker_SOURCES = test-eel-font-picker.c test.c
 test_eel_gtk_style_SOURCES = test-eel-gtk-style.c test.c dumb-box.c dumb-box.h
--- /dev/null	Fri Aug  3 01:21:03 2001
+++ test/test-eel-canvas-items.c	Sat Jan 26 01:44:49 2002
@@ -0,0 +1,280 @@
+#include <config.h>
+
+#include <math.h>
+#include <eel/eel-canvas-rect.h>
+#include <libgnomecanvas/libgnomecanvas.h>
+#include <gtk/gtk.h>
+
+static gboolean
+quit_cb (GtkWidget *widget, GdkEventAny *event, gpointer dummy)
+{
+	gtk_main_quit ();
+
+	return TRUE;
+}
+
+static void
+zoom_changed (GtkAdjustment *adj, gpointer data)
+{
+	gnome_canvas_set_pixels_per_unit (data, adj->value);
+}
+
+static gint
+item_event (GnomeCanvasItem *item, GdkEvent *event, gpointer data)
+{
+	static double x, y;
+	double new_x, new_y;
+	GdkCursor *fleur;
+	static int dragging;
+	double item_x, item_y;
+
+	/* set item_[xy] to the event x,y position in the parent's item-relative coordinates */
+	item_x = event->button.x;
+	item_y = event->button.y;
+	gnome_canvas_item_w2i (item->parent, &item_x, &item_y);
+
+	switch (event->type) {
+	case GDK_BUTTON_PRESS:
+		switch (event->button.button) {
+		case 1:
+			if (event->button.state & GDK_SHIFT_MASK)
+				gtk_object_destroy (GTK_OBJECT (item));
+			else {
+				x = item_x;
+				y = item_y;
+
+				fleur = gdk_cursor_new (GDK_FLEUR);
+				gnome_canvas_item_grab (item,
+							GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
+							fleur,
+							event->button.time);
+				gdk_cursor_destroy (fleur);
+				dragging = TRUE;
+			}
+			break;
+
+		case 2:
+			if (event->button.state & GDK_SHIFT_MASK)
+				gnome_canvas_item_lower_to_bottom (item);
+			else
+				gnome_canvas_item_lower (item, 1);
+			break;
+
+		case 3:
+			if (event->button.state & GDK_SHIFT_MASK)
+				gnome_canvas_item_raise_to_top (item);
+			else
+				gnome_canvas_item_raise (item, 1);
+			break;
+
+		default:
+			break;
+		}
+
+		break;
+
+	case GDK_MOTION_NOTIFY:
+		if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) {
+			new_x = item_x;
+			new_y = item_y;
+
+			gnome_canvas_item_move (item, new_x - x, new_y - y);
+			x = new_x;
+			y = new_y;
+		}
+		break;
+
+	case GDK_BUTTON_RELEASE:
+		gnome_canvas_item_ungrab (item, event->button.time);
+		dragging = FALSE;
+		break;
+
+	default:
+		break;
+	}
+
+	return FALSE;
+}
+
+static void
+setup_item (GnomeCanvasItem *item)
+{
+	gtk_signal_connect (GTK_OBJECT (item), "event",
+			    (GtkSignalFunc) item_event,
+			    NULL);
+}
+
+
+static void
+setup_rectangles (GnomeCanvasGroup *root)
+{
+	setup_item (gnome_canvas_item_new (root,
+					   EEL_TYPE_CANVAS_RECT,
+					   "x1", 100.0,
+					   "y1", 100.0,
+					   "x2", 200.0,
+					   "y2", 200.0,
+					   "outline_color_rgba", 0x00ff00ff,
+					   "fill_color_rgba", 0x0000ff80,
+					   "width_pixels", 3,
+					   NULL));
+	
+	setup_item (gnome_canvas_item_new (root,
+					   EEL_TYPE_CANVAS_RECT,
+					   "x1", 40.0,
+					   "y1", 60.0,
+					   "x2", 120.0,
+					   "y2", 270.0,
+					   "outline_color_rgba", 0x4400ffff,
+					   "fill_color_rgba", 0xff000080,
+					   "width_pixels", 3,
+					   NULL));
+	
+	setup_item (gnome_canvas_item_new (root,
+					   EEL_TYPE_CANVAS_RECT,
+					   "x1", 140.0,
+					   "y1", 160.0,
+					   "x2", 170.0,
+					   "y2", 240.0,
+					   "outline_color_rgba", 0x4400ffff,
+					   "fill_color_rgba", 0x00ff0080,
+					   "width_pixels", 3,
+					   NULL));
+}
+
+
+static GtkWidget *
+create_canvas_items (void)
+{
+	GtkWidget *vbox;
+	GtkWidget *hbox;
+	GtkWidget *table;
+	GtkWidget *w;
+	GtkWidget *frame;
+	GtkWidget *canvas;
+	GtkAdjustment *adj;
+	GnomeCanvasGroup *root;
+
+	vbox = gtk_vbox_new (FALSE, 4);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
+	gtk_widget_show (vbox);
+
+	w = gtk_label_new ("Drag an item with button 1.  Click button 2 on an item to lower it,\n"
+			   "or button 3 to raise it.  Shift+click with buttons 2 or 3 to send\n"
+			   "an item to the bottom or top, respectively.");
+	gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0);
+	gtk_widget_show (w);
+
+	hbox = gtk_hbox_new (FALSE, 4);
+	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+	gtk_widget_show (hbox);
+
+	/* Create the canvas */
+
+	gtk_widget_push_colormap (gdk_rgb_get_cmap ());
+	
+	canvas = gnome_canvas_new ();
+
+	/* Setup canvas items */
+
+	root = gnome_canvas_root (GNOME_CANVAS (canvas));
+
+	setup_rectangles (root);
+
+	gtk_widget_pop_colormap ();
+
+	/* Zoom */
+
+	w = gtk_label_new ("Zoom:");
+	gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
+	gtk_widget_show (w);
+
+	adj = GTK_ADJUSTMENT (gtk_adjustment_new (1.00, 0.05, 5.00, 0.05, 0.50, 0.50));
+	gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
+			    (GtkSignalFunc) zoom_changed,
+			    canvas);
+	w = gtk_spin_button_new (adj, 0.0, 2);
+	gtk_widget_set_usize (w, 50, 0);
+	gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
+	gtk_widget_show (w);
+
+	/* Layout the stuff */
+
+	table = gtk_table_new (2, 2, FALSE);
+	gtk_table_set_row_spacings (GTK_TABLE (table), 4);
+	gtk_table_set_col_spacings (GTK_TABLE (table), 4);
+	gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
+	gtk_widget_show (table);
+
+	frame = gtk_frame_new (NULL);
+	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+	gtk_table_attach (GTK_TABLE (table), frame,
+			  0, 1, 0, 1,
+			  GTK_EXPAND | GTK_FILL | GTK_SHRINK,
+			  GTK_EXPAND | GTK_FILL | GTK_SHRINK,
+			  0, 0);
+	gtk_widget_show (frame);
+
+	gtk_widget_set_usize (canvas, 600, 450);
+	gnome_canvas_set_scroll_region (GNOME_CANVAS (canvas), 0, 0, 600, 450);
+	gtk_container_add (GTK_CONTAINER (frame), canvas);
+	gtk_widget_show (canvas);
+
+#if 0
+	gtk_signal_connect_after (GTK_OBJECT (canvas), "key_press_event",
+				  (GtkSignalFunc) key_press,
+				  NULL);
+#endif
+
+	w = gtk_hscrollbar_new (GTK_LAYOUT (canvas)->hadjustment);
+	gtk_table_attach (GTK_TABLE (table), w,
+			  0, 1, 1, 2,
+			  GTK_EXPAND | GTK_FILL | GTK_SHRINK,
+			  GTK_FILL,
+			  0, 0);
+	gtk_widget_show (w);
+
+	w = gtk_vscrollbar_new (GTK_LAYOUT (canvas)->vadjustment);
+	gtk_table_attach (GTK_TABLE (table), w,
+			  1, 2, 0, 1,
+			  GTK_FILL,
+			  GTK_EXPAND | GTK_FILL | GTK_SHRINK,
+			  0, 0);
+	gtk_widget_show (w);
+
+	GTK_WIDGET_SET_FLAGS (canvas, GTK_CAN_FOCUS);
+	gtk_widget_grab_focus (canvas);
+
+	return vbox;
+}
+
+
+
+static void
+create_canvas (void)
+{
+	GtkWidget *app;
+
+	app = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_policy (GTK_WINDOW (app), TRUE, TRUE, FALSE);
+
+	gtk_signal_connect (GTK_OBJECT (app), "delete_event",
+			    (GtkSignalFunc) quit_cb, NULL);
+
+	gtk_container_add (GTK_CONTAINER (app),
+			   create_canvas_items ());
+
+	gtk_widget_show (app);
+}
+
+int
+main (int argc, char *argv[])
+{
+	gtk_init (&argc, &argv);
+
+	create_canvas ();
+
+	gtk_main ();
+
+	return 0;
+}
--- /dev/null	Fri Aug  3 01:21:03 2001
+++ eel/eel-canvas-rect.h	Sat Jan 26 00:07:27 2002
@@ -0,0 +1,54 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-canvas-rect.h: rectangle canvas item with AA support.
+
+   Copyright (C) 2002 Alexander Larsson.
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Authors: Alexander Larsson <alla lysator liu se>
+*/
+
+#ifndef EEL_CANVAS_RECT_H
+#define EEL_CANVAS_RECT_H
+
+#include <libgnomecanvas/gnome-canvas.h>
+
+G_BEGIN_DECLS
+
+#define EEL_TYPE_CANVAS_RECT            (eel_canvas_rect_get_type ())
+#define EEL_CANVAS_RECT(obj)            (GTK_CHECK_CAST ((obj), EEL_TYPE_CANVAS_RECT, EelCanvasRect))
+#define EEL_CANVAS_RECT_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), EEL_TYPE_CANVAS_RECT, EelCanvasRectClass))
+#define EEL_IS_CANVAS_RECT(obj)         (GTK_CHECK_TYPE ((obj), EEL_TYPE_CANVAS_RECT))
+
+typedef struct EelCanvasRectDetails EelCanvasRectDetails;
+
+typedef struct
+{
+	GnomeCanvasItem item;
+	EelCanvasRectDetails *details;
+} EelCanvasRect;
+
+typedef struct
+{
+	GnomeCanvasItemClass parent_class;
+} EelCanvasRectClass;
+
+GType      eel_canvas_rect_get_type (void);
+
+G_END_DECLS
+
+#endif /* EEL_CANVAS_RECT_H */
--- /dev/null	Fri Aug  3 01:21:03 2001
+++ eel/eel-canvas-rect.c	Sat Jan 26 18:11:44 2002
@@ -0,0 +1,853 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* eel-canvas-rect.c: Rectangle canvas item with AA support.
+
+   Copyright (C) 2002 Alexander Larsson.
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Authors: Alexander Larsson <alla lysator liu se>
+*/
+
+#include <config.h>
+#include "eel-canvas-rect.h"
+#include "eel-lib-self-check-functions.h"
+
+#include <math.h>
+#include <string.h>
+
+#include <glib/gstring.h>
+#include <libgnome/gnome-macros.h>
+#include <libgnomecanvas/gnome-canvas-util.h>
+#include <gdk/gdkx.h>
+
+#ifdef HAVE_RENDER
+#include <X11/extensions/Xrender.h>
+#endif
+
+/*
+ * name			type		read/write	description
+ * ------------------------------------------------------------------------------------------
+ * x1			double		RW		Leftmost coordinate of rectangle or ellipse
+ * y1			double		RW		Topmost coordinate of rectangle or ellipse
+ * x2			double		RW		Rightmost coordinate of rectangle or ellipse
+ * y2			double		RW		Bottommost coordinate of rectangle or ellipse
+ * fill_color_rgba	uint		RW		RGBA color for fill,
+ * outline_color_rgba	uint		RW		RGBA color for outline
+ * width_pixels		uint		RW		Width of the outline in pixels.  The outline will
+ *							not be scaled when the canvas zoom factor is changed.
+ */
+
+enum {
+	PROP_0,
+
+	PROP_X1,
+	PROP_Y1,
+	PROP_X2,
+	PROP_Y2,
+
+	PROP_FILL_COLOR_RGBA,
+	PROP_OUTLINE_COLOR_RGBA,
+
+	PROP_WIDTH_PIXELS
+};
+
+struct EelCanvasRectDetails {
+	double x1, y1, x2, y2;
+	guint fill_color;
+	guint outline_color;
+	guint width_pixels;
+
+	ArtDRect last_update_rect;
+	ArtDRect last_outline_update_rect;
+	GdkGC *fill_gc;		/* GC for fill, lazily allocated */
+	GdkGC *outline_gc;	/* GC for outline */
+
+#ifdef HAVE_RENDER
+	gboolean use_render;
+	XRenderPictFormat *format;
+#endif
+};
+
+GNOME_CLASS_BOILERPLATE (EelCanvasRect, eel_canvas_rect,
+			 GnomeCanvasItem, GNOME_TYPE_CANVAS_ITEM);
+
+
+static ArtDRect  make_drect (double x0, double y0, double x1, double y1);
+static void      diff_rects (ArtDRect r1, ArtDRect r2, int *count, ArtDRect result[4]);
+
+static void
+eel_canvas_rect_update_fill_gc (EelCanvasRect *rect,
+				gboolean       create)
+{
+	EelCanvasRectDetails *details;
+	GnomeCanvasItem *item;
+	GdkColor c;
+
+	item = GNOME_CANVAS_ITEM (rect);
+	
+	details = rect->details;
+	
+	if (details->fill_gc == NULL) {
+		if (!create) {
+			return;
+		}
+		details->fill_gc =
+			gdk_gc_new (GTK_WIDGET (item->canvas)->window);
+	}
+	
+	c.pixel = gnome_canvas_get_color_pixel (item->canvas,
+						details->fill_color);
+	gdk_gc_set_foreground (details->fill_gc, &c);
+}
+
+static void
+eel_canvas_rect_update_outline_gc (EelCanvasRect *rect,
+				   gboolean       create)
+{
+	EelCanvasRectDetails *details;
+	GnomeCanvasItem *item;
+	GdkColor c;
+
+	item = GNOME_CANVAS_ITEM (rect);
+	
+	details = rect->details;
+	
+	if (details->outline_gc == NULL) {
+		if (!create) {
+			return;
+		}
+		details->outline_gc =
+			gdk_gc_new (GTK_WIDGET (item->canvas)->window);
+	}
+	
+	c.pixel = gnome_canvas_get_color_pixel (item->canvas,
+						details->outline_color);
+	gdk_gc_set_foreground (details->outline_gc, &c);
+	gdk_gc_set_line_attributes (details->outline_gc,
+				    details->width_pixels,
+				    GDK_LINE_SOLID,
+				    GDK_CAP_BUTT,
+				    GDK_JOIN_MITER);
+}
+
+
+static void
+eel_canvas_rect_instance_init (EelCanvasRect *rect)
+{
+	rect->details = g_new0 (EelCanvasRectDetails, 1);
+}
+
+
+static void
+eel_canvas_rect_finalize (GObject *object)
+{
+	EelCanvasRect *rect;
+
+	g_return_if_fail (EEL_IS_CANVAS_RECT (object));
+	
+	rect = EEL_CANVAS_RECT (object);
+
+	g_free (rect->details);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+eel_canvas_rect_set_property (GObject      *object,
+			      guint         param_id,
+			      const GValue *value,
+			      GParamSpec   *pspec)
+{
+	GnomeCanvasItem *item;
+	EelCanvasRect *rect;
+	EelCanvasRectDetails *details;
+
+	item = GNOME_CANVAS_ITEM (object);
+	rect = EEL_CANVAS_RECT (object);
+	details = rect->details;
+
+	switch (param_id) {
+	case PROP_X1:
+		details->x1 = g_value_get_double (value);
+		gnome_canvas_item_request_update (item);
+		break;
+
+	case PROP_Y1:
+		details->y1 = g_value_get_double (value);
+		gnome_canvas_item_request_update (item);
+		break;
+
+	case PROP_X2:
+		details->x2 = g_value_get_double (value);
+		gnome_canvas_item_request_update (item);
+		break;
+
+	case PROP_Y2:
+		details->y2 = g_value_get_double (value);
+		gnome_canvas_item_request_update (item);
+		break;
+
+	case PROP_FILL_COLOR_RGBA:
+		details->fill_color = g_value_get_uint (value);
+
+		eel_canvas_rect_update_fill_gc (rect, FALSE);
+		
+		gnome_canvas_item_request_update (item);
+		break;
+		
+	case PROP_OUTLINE_COLOR_RGBA:
+		details->outline_color = g_value_get_uint (value);
+
+		eel_canvas_rect_update_outline_gc (rect, FALSE);
+		
+		gnome_canvas_item_request_update (item);
+		break;
+
+	case PROP_WIDTH_PIXELS:
+		details->width_pixels = g_value_get_uint (value);
+		eel_canvas_rect_update_outline_gc (rect, FALSE);
+		gnome_canvas_item_request_update (item);
+		break;
+
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+		break;
+	}
+	
+}
+
+static void
+eel_canvas_rect_get_property (GObject     *object,
+			      guint        param_id,
+			      GValue      *value,
+			      GParamSpec  *pspec)
+{
+	EelCanvasRect *rect;
+	EelCanvasRectDetails *details;
+
+	rect = EEL_CANVAS_RECT (object);
+	details = rect->details;
+
+	switch (param_id) {
+	case PROP_X1:
+		g_value_set_double (value,  details->x1);
+		break;
+
+	case PROP_Y1:
+		g_value_set_double (value,  details->y1);
+		break;
+
+	case PROP_X2:
+		g_value_set_double (value,  details->x2);
+		break;
+
+	case PROP_Y2:
+		g_value_set_double (value,  details->y2);
+		break;
+		
+	case PROP_FILL_COLOR_RGBA:
+		g_value_set_uint (value, details->fill_color);
+		break;
+		
+	case PROP_OUTLINE_COLOR_RGBA:
+		g_value_set_uint (value, details->outline_color);
+		break;
+
+	case PROP_WIDTH_PIXELS:
+		g_value_set_uint (value, details->width_pixels);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+		break;
+	}	
+}
+
+static void
+request_redraw_borders (GnomeCanvas *canvas,
+			ArtDRect    *update_rect,
+			double       width)
+{
+	gnome_canvas_request_redraw (canvas,
+				     update_rect->x0, update_rect->y0,
+				     update_rect->x1, update_rect->y0 + width);
+	gnome_canvas_request_redraw (canvas,
+				     update_rect->x0, update_rect->y1-width,
+				     update_rect->x1, update_rect->y1);
+	gnome_canvas_request_redraw (canvas,
+				     update_rect->x0,       update_rect->y0,
+				     update_rect->x0+width, update_rect->y1);
+	gnome_canvas_request_redraw (canvas,
+				     update_rect->x1-width, update_rect->y0,
+				     update_rect->x1,       update_rect->y1);
+}
+
+static void
+eel_canvas_rect_update (GnomeCanvasItem *item,
+			double *affine,
+			ArtSVP *clip_path,
+			int flags)
+{
+	EelCanvasRect *rect;
+	EelCanvasRectDetails *details;
+	double x1, y1, x2, y2;
+	int cx1, cy1, cx2, cy2;
+	ArtDRect update_rect, repaint_rects[4];
+	int repaint_rects_count, i;
+	double width_lt, width_rb;
+
+	rect = EEL_CANVAS_RECT (item);
+	details = rect->details;
+
+	if (parent_class->update) {
+		(* parent_class->update) (item, affine, clip_path, flags);
+	}
+
+	/* Update bounding box: */
+	width_lt = floor (details->width_pixels / 2.0) / item->canvas->pixels_per_unit;
+	width_rb = ceil (details->width_pixels / 2.0) / item->canvas->pixels_per_unit;
+	
+	x1 = details->x1;
+	y1 = details->y1;
+	x2 = details->x2;
+	y2 = details->y2;
+
+	gnome_canvas_item_i2w (item, &x1, &y1);
+	gnome_canvas_item_i2w (item, &x2, &y2);
+
+	/* Inner box: */
+	gnome_canvas_w2c (item->canvas, x1 + width_rb, y1 + width_rb, &cx1, &cy1);
+	gnome_canvas_w2c (item->canvas, x2 - width_lt, y2 - width_lt, &cx2, &cy2);
+
+	update_rect = make_drect (cx1, cy1, cx2, cy2);
+	diff_rects (update_rect, details->last_update_rect,
+		    &repaint_rects_count, repaint_rects);
+	for (i = 0; i < repaint_rects_count; i++) {
+		gnome_canvas_request_redraw (item->canvas,
+					     repaint_rects[i].x0, repaint_rects[i].y0,
+					     repaint_rects[i].x1, repaint_rects[i].y1);
+	}
+	details->last_update_rect = update_rect;
+
+	
+	/* Outline and bounding box */
+	gnome_canvas_w2c (item->canvas, x1 - width_lt, y1 - width_lt, &cx1, &cy1);
+	gnome_canvas_w2c (item->canvas, x2 + width_rb, y2 + width_rb, &cx2, &cy2);
+	
+	update_rect = make_drect (cx1, cy1, cx2, cy2);
+	request_redraw_borders (item->canvas, &details->last_outline_update_rect,
+				(width_lt + width_rb)*item->canvas->pixels_per_unit);
+	request_redraw_borders (item->canvas, &update_rect,
+				(width_lt + width_rb)*item->canvas->pixels_per_unit);
+	details->last_outline_update_rect = update_rect;
+	
+	item->x1 = cx1;
+	item->y1 = cy1;
+	item->x2 = cx2;
+	item->y2 = cy2;
+}
+
+static void
+eel_canvas_rect_realize (GnomeCanvasItem *item)
+{
+	EelCanvasRect *rect;
+	EelCanvasRectDetails *details;
+	int event_base, error_base;
+
+	rect = EEL_CANVAS_RECT (item);
+	details = rect->details;
+	
+	eel_canvas_rect_update_outline_gc (rect, TRUE);
+
+#ifdef HAVE_RENDER
+	details->use_render = XRenderQueryExtension (gdk_display, &event_base, &error_base);
+
+	if (details->use_render) {
+		Display *dpy;
+		GdkVisual *gdk_visual;
+		Visual *visual;
+
+		dpy = gdk_x11_drawable_get_xdisplay (GTK_WIDGET (item->canvas)->window);
+		gdk_visual = gtk_widget_get_visual (GTK_WIDGET (item->canvas));
+		visual = gdk_x11_visual_get_xvisual (gdk_visual);
+
+		details->format = XRenderFindVisualFormat (dpy, visual);
+	}
+#endif
+}
+
+static void
+eel_canvas_rect_unrealize (GnomeCanvasItem *item)
+{
+	EelCanvasRect *rect;
+	EelCanvasRectDetails *details;
+
+	rect = EEL_CANVAS_RECT (item);
+	details = rect->details;
+
+	if (details->outline_gc) {
+		g_object_unref (details->outline_gc);
+		details->outline_gc = NULL;
+	}
+	
+	if (details->fill_gc) {
+		g_object_unref (details->fill_gc);
+		details->fill_gc = NULL;
+	}
+}
+
+static void
+eel_canvas_rect_render (GnomeCanvasItem *item,
+			GnomeCanvasBuf  *buf)
+{
+	g_assert_not_reached ();
+}
+
+static double
+eel_canvas_rect_point (GnomeCanvasItem *item,
+		       double x, double y,
+		       int cx, int cy,
+		       GnomeCanvasItem **actual_item)
+{
+	EelCanvasRect *rect;
+	EelCanvasRectDetails *details;
+	double x1, y1, x2, y2;
+	double hwidth;
+	double dx, dy;
+
+	rect = EEL_CANVAS_RECT (item);
+	details = rect->details;
+
+	*actual_item = item;
+
+	hwidth = (details->width_pixels / item->canvas->pixels_per_unit) / 2.0;
+	x1 = details->x1 - hwidth;
+	y1 = details->y1 - hwidth;
+	x2 = details->x2 + hwidth;
+	y2 = details->y2 + hwidth;
+
+
+	if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
+		return 0.0;
+	}
+
+	/* Point is outside rectangle */
+	if (x < x1)
+		dx = x1 - x;
+	else if (x > x2)
+		dx = x - x2;
+	else
+		dx = 0.0;
+
+	if (y < y1)
+		dy = y1 - y;
+	else if (y > y2)
+		dy = y - y2;
+	else
+		dy = 0.0;
+
+	return sqrt (dx * dx + dy * dy);
+}
+
+static void
+render_rect_alpha (EelCanvasRect *rect,
+		   GdkDrawable *drawable,
+		   int x, int y,
+		   int width, int height,
+		   guint32 rgba)
+{
+	GdkPixbuf *pixbuf;
+	guchar *data;
+	int rowstride, i;
+	guchar r, g, b, a;
+	EelCanvasRectDetails *details;
+
+	if (width <= 0 || height <= 0 ) {
+		return;
+	}
+	
+	details = rect->details;
+
+	r = (rgba >> 24) & 0xff;
+	g = (rgba >> 16) & 0xff;
+	b = (rgba >> 8) & 0xff;
+	a = (rgba >> 0) & 0xff;
+
+#ifdef HAVE_RENDER
+	if (details->use_render) {
+		Display *dpy;
+		Picture  pict;
+		XRenderPictureAttributes attributes;
+		XRenderColor color;
+	
+		dpy = gdk_x11_drawable_get_xdisplay (drawable);
+
+		pict = XRenderCreatePicture (dpy,
+					     gdk_x11_drawable_get_xid (drawable),
+					     details->format,
+					     0,
+					     &attributes);
+
+
+		/* Convert to premultiplied alpha: */
+		r = r * a / 255;
+		g = g * a / 255;
+		b = b * a / 255;
+		
+		color.red = (r << 8) + r;
+		color.green = (g << 8) + g;
+		color.blue = (b << 8) + b;
+		color.alpha = (a << 8) + a;
+		
+		XRenderFillRectangle (dpy,
+				      PictOpOver,
+				      pict,
+				      &color,
+				      x, y,
+				      width, height);
+		XRenderFreePicture (dpy, pict);
+
+		return;
+	}
+#endif
+	pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
+	data = gdk_pixbuf_get_pixels (pixbuf);
+	rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+	
+	r = (rgba >> 24) & 0xff;
+	g = (rgba >> 16) & 0xff;
+	b = (rgba >> 8) & 0xff;
+	a = (rgba >> 0) & 0xff;
+	
+	for (i = 0; i < width*4; ) {
+		data[i++] = r;
+		data[i++] = g;
+		data[i++] = b;
+		data[i++] = a;
+	}
+	
+	for (i = 1; i < height; i++) {
+		memcpy (data + i*rowstride, data, width*4);
+	}
+	
+	gdk_pixbuf_render_to_drawable_alpha (pixbuf,
+					     drawable,
+					     0, 0,
+					     x, y,
+					     width, height,
+					     GDK_PIXBUF_ALPHA_FULL,
+					     255,
+					     GDK_RGB_DITHER_NONE, 0, 0);
+	g_object_unref (pixbuf);
+}
+
+
+static void
+eel_canvas_rect_draw (GnomeCanvasItem *item,
+		      GdkDrawable *drawable,
+		      int x, int y,
+		      int width, int height)
+{
+	EelCanvasRect *rect;
+	EelCanvasRectDetails *details;
+	double x1, y1, x2, y2;
+	int cx1, cy1, cx2, cy2;
+	double width_lt, width_rb;
+
+	rect = EEL_CANVAS_RECT (item);
+	details = rect->details;
+
+	/* Update bounding box: */
+	width_lt = floor (details->width_pixels / 2.0) / item->canvas->pixels_per_unit;
+	width_rb = ceil (details->width_pixels / 2.0) / item->canvas->pixels_per_unit;
+
+	x1 = details->x1;
+	y1 = details->y1;
+	x2 = details->x2;
+	y2 = details->y2;
+
+	gnome_canvas_item_i2w (item, &x1, &y1);
+	gnome_canvas_item_i2w (item, &x2, &y2);
+
+	/* Inner box: */
+	gnome_canvas_w2c (item->canvas, x1 + width_rb, y1 + width_rb, &cx1, &cy1);
+	gnome_canvas_w2c (item->canvas, x2 - width_lt, y2 - width_lt, &cx2, &cy2);
+
+	/* Clip and offset to dest drawable */
+	cx1 = MAX (0, cx1 - x);
+	cy1 = MAX (0, cy1 - y);
+	cx2 = MIN (width, cx2 - x);
+	cy2 = MIN (height, cy2 - y);
+	
+	if ((details->fill_color & 0xff) != 255) {
+		render_rect_alpha (rect,
+				   drawable,
+				   cx1, cy1,
+				   cx2 - cx1, cy2 - cy1,
+				   details->fill_color);
+	} else {
+		if (details->fill_gc == NULL) {
+			eel_canvas_rect_update_fill_gc (rect, TRUE);
+		}
+		gdk_draw_rectangle (drawable,
+				    details->fill_gc,
+				    TRUE,
+				    cx1, cy1,
+				    cx2, cy2);
+	}
+
+	/* Box outline: */
+	
+	gnome_canvas_w2c (item->canvas, x1, y1, &cx1, &cy1);
+	gnome_canvas_w2c (item->canvas, x2, y2, &cx2, &cy2);
+	
+	/* FIXME: Doesn't handle alpha for outline. Nautilus doesn't currently use this */
+	gdk_draw_rectangle (drawable,
+			    details->outline_gc,
+			    FALSE,
+			    cx1 - x, cy1 - y,
+			    cx2 - cx1, cy2 - cy1);
+}
+
+static void
+eel_canvas_rect_bounds (GnomeCanvasItem *item,
+			double *x1, double *y1,
+			double *x2, double *y2)
+{
+	EelCanvasRect *rect;
+	EelCanvasRectDetails *details;
+	double hwidth;
+
+	rect = EEL_CANVAS_RECT (item);
+	details = rect->details;
+
+	hwidth = (details->width_pixels / item->canvas->pixels_per_unit) / 2.0;
+	
+	*x1 = details->x1 - hwidth;
+	*y1 = details->y1 - hwidth;
+	*x2 = details->x2 + hwidth;
+	*y2 = details->y2 + hwidth;
+}
+
+static void
+eel_canvas_rect_class_init (EelCanvasRectClass *class)
+{
+	GObjectClass *gobject_class;
+	GnomeCanvasItemClass *item_class;
+
+	gobject_class = G_OBJECT_CLASS (class);
+	item_class = GNOME_CANVAS_ITEM_CLASS (class);
+	
+	gobject_class->finalize = eel_canvas_rect_finalize;
+	gobject_class->set_property = eel_canvas_rect_set_property;
+	gobject_class->get_property = eel_canvas_rect_get_property;
+
+	item_class->update = eel_canvas_rect_update;
+	item_class->realize = eel_canvas_rect_realize;
+	item_class->unrealize = eel_canvas_rect_unrealize;
+	item_class->draw = eel_canvas_rect_draw;
+	item_class->point = eel_canvas_rect_point;
+	item_class->render = eel_canvas_rect_render;
+	item_class->bounds = eel_canvas_rect_bounds;
+	
+        g_object_class_install_property (gobject_class,
+					 PROP_X1,
+					 g_param_spec_double ("x1", NULL, NULL,
+							      -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+							      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property (gobject_class,
+					 PROP_Y1,
+					 g_param_spec_double ("y1", NULL, NULL,
+							      -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+							      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property (gobject_class,
+					 PROP_X2,
+					 g_param_spec_double ("x2", NULL, NULL,
+							      -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+							      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property (gobject_class,
+					 PROP_Y2,
+					 g_param_spec_double ("y2", NULL, NULL,
+							      -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+							      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+	
+        g_object_class_install_property (gobject_class,
+                                         PROP_FILL_COLOR_RGBA,
+                                         g_param_spec_uint ("fill_color_rgba", NULL, NULL,
+                                                            0, G_MAXUINT, 0,
+                                                            (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property (gobject_class,
+                                         PROP_OUTLINE_COLOR_RGBA,
+                                         g_param_spec_uint ("outline_color_rgba", NULL, NULL,
+                                                            0, G_MAXUINT, 0,
+                                                            (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+        g_object_class_install_property (gobject_class,
+                                         PROP_WIDTH_PIXELS,
+                                         g_param_spec_uint ("width_pixels", NULL, NULL,
+                                                            0, G_MAXUINT, 0,
+                                                            (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+}
+
+
+static ArtDRect
+make_drect (double x0, double y0, double x1, double y1)
+{
+	ArtDRect r;
+
+	r.x0 = x0;
+	r.y0 = y0;
+	r.x1 = x1;
+	r.y1 = y1;
+	return r;
+}
+
+static gboolean
+rects_intersect (ArtDRect r1, ArtDRect r2)
+{
+	if (r1.x0 >= r2.x1) {
+		return FALSE;
+	}
+	if (r2.x0 >= r1.x1) {
+		return FALSE;
+	}
+	if (r1.y0 >= r2.y1) {
+		return FALSE;
+	}
+	if (r2.y0 >= r1.y1) {
+		return FALSE;
+	}
+	return TRUE;
+}
+
+static void
+diff_rects_guts (ArtDRect ra, ArtDRect rb, int *count, ArtDRect result[4])
+{
+	if (ra.x0 < rb.x0) {
+		result[(*count)++] = make_drect (ra.x0, ra.y0, rb.x0, ra.y1);
+	}
+	if (ra.y0 < rb.y0) {
+		result[(*count)++] = make_drect (ra.x0, ra.y0, ra.x1, rb.y0);
+	}
+	if (ra.x1 < rb.x1) {
+		result[(*count)++] = make_drect (ra.x1, rb.y0, rb.x1, rb.y1);
+	}
+	if (ra.y1 < rb.y1) {
+		result[(*count)++] = make_drect (rb.x0, ra.y1, rb.x1, rb.y1);
+	}
+}
+
+static void
+diff_rects (ArtDRect r1, ArtDRect r2, int *count, ArtDRect result[4])
+{
+	g_assert (count != NULL);
+	g_assert (result != NULL);
+
+	*count = 0;
+
+	if (rects_intersect (r1, r2)) {
+		diff_rects_guts (r1, r2, count, result);
+		diff_rects_guts (r2, r1, count, result);
+	} else {
+		if (!art_drect_empty (&r1)) {
+			result[(*count)++] = r1;
+		}
+		if (!art_drect_empty (&r2)) {
+			result[(*count)++] = r2;
+		}
+	}
+}
+
+#ifndef EEL_OMIT_SELF_CHECK
+
+static gboolean
+test_rects_intersect (double x01, double y01, double x11, double y11,
+		      double x02, double y02, double x12, double y12)
+{
+	ArtDRect r1, r2;
+	
+	r1.x0 = x01;
+	r1.y0 = y01;
+	r1.x1 = x11;
+	r1.y1 = y11;
+	r2.x0 = x02;
+	r2.y0 = y02;
+	r2.x1 = x12;
+	r2.y1 = y12;
+	return rects_intersect (r1, r2);
+}
+
+static char *
+test_diff_rects (double x01, double y01, double x11, double y11,
+		 double x02, double y02, double x12, double y12)
+{
+	ArtDRect r1, r2, result[4];
+	int count, i;
+	GString *string;
+	char *str;
+	
+	r1.x0 = x01;
+	r1.y0 = y01;
+	r1.x1 = x11;
+	r1.y1 = y11;
+	r2.x0 = x02;
+	r2.y0 = y02;
+	r2.x1 = x12;
+	r2.y1 = y12;
+	diff_rects (r1, r2, &count, result);
+
+	if (count < 0 || count > 4) {
+		return g_strdup ("ERROR");
+	}
+
+	string = g_string_new ("");
+	for (i = 0; i < count; i++) {
+		g_string_append_printf (string, "(%.0f,%.0f,%.0f,%.0f) ",
+					result[i].x0,
+					result[i].y0,
+					result[i].x1,
+					result[i].y1);
+	}
+	if (string->len != 0) {
+		g_string_truncate (string, string->len - 1);
+	}
+	str = string->str;
+	g_string_free (string, FALSE);
+	return str;
+}
+
+void
+eel_self_check_canvas_rect (void)
+{
+	EEL_CHECK_BOOLEAN_RESULT (test_rects_intersect (0,0,0,0, 0,0,0,0), FALSE);
+	EEL_CHECK_BOOLEAN_RESULT (test_rects_intersect (0,0,0,0, 0,0,1,1), FALSE);
+	EEL_CHECK_BOOLEAN_RESULT (test_rects_intersect (1,1,1,1, 0,0,0,0), FALSE);
+	EEL_CHECK_BOOLEAN_RESULT (test_rects_intersect (1,1,1,1, 0,0,1,1), FALSE);
+	EEL_CHECK_BOOLEAN_RESULT (test_rects_intersect (0,0,1,1, 0,0,2,2), TRUE);
+	EEL_CHECK_BOOLEAN_RESULT (test_rects_intersect (0,0,3,3, 1,1,2,2), TRUE);
+	EEL_CHECK_BOOLEAN_RESULT (test_rects_intersect (0,0,5,5, 5,5,10,10), FALSE);
+	EEL_CHECK_BOOLEAN_RESULT (test_rects_intersect (0,0,10,10, 5,5,15,15), TRUE);
+
+	EEL_CHECK_STRING_RESULT (test_diff_rects (0,0,0,0, 0,0,0,0), "");
+	EEL_CHECK_STRING_RESULT (test_diff_rects (0,0,0,0, 0,0,1,1), "(0,0,1,1)");
+	EEL_CHECK_STRING_RESULT (test_diff_rects (1,1,1,1, 0,0,0,0), "");
+	EEL_CHECK_STRING_RESULT (test_diff_rects (1,1,1,1, 0,0,1,1), "(0,0,1,1)");
+	EEL_CHECK_STRING_RESULT (test_diff_rects (0,0,1,1, 0,0,2,2), "(1,0,2,2) (0,1,2,2)");
+	EEL_CHECK_STRING_RESULT (test_diff_rects (0,0,3,3, 1,1,2,2), "(0,0,1,3) (0,0,3,1) (2,0,3,3) (0,2,3,3)");
+	EEL_CHECK_STRING_RESULT (test_diff_rects (0,0,5,5, 5,5,10,10), "(0,0,5,5) (5,5,10,10)");
+	EEL_CHECK_STRING_RESULT (test_diff_rects (0,0,10,10, 5,5,15,15), "(0,0,5,10) (0,0,10,5) (10,5,15,15) (5,10,15,15)");
+}
+
+#endif


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