[goffice] New cairo-based canvas.



commit 335b8c9640b49feaccded6e4e1fb86eb3c900437
Author: Jean Brefort <jean brefort normalesup org>
Date:   Sun Aug 9 15:58:03 2009 +0200

    New cairo-based canvas.

 NEWS                                |    1 +
 configure.in                        |    1 +
 goffice/Makefile.am                 |    3 +-
 goffice/canvas/Makefile.am          |   47 +++++
 goffice/canvas/Makefile.am~         |   49 +++++
 goffice/canvas/goc-canvas-impl.h    |   46 +++++
 goffice/canvas/goc-canvas.c         |  373 +++++++++++++++++++++++++++++++++++
 goffice/canvas/goc-canvas.h         |   55 +++++
 goffice/canvas/goc-circle-impl.h    |   39 ++++
 goffice/canvas/goc-circle.c         |  208 +++++++++++++++++++
 goffice/canvas/goc-circle.h         |   38 ++++
 goffice/canvas/goc-ellipse.c        |  266 +++++++++++++++++++++++++
 goffice/canvas/goc-ellipse.h        |   38 ++++
 goffice/canvas/goc-graph.c          |  271 +++++++++++++++++++++++++
 goffice/canvas/goc-graph.h          |   37 ++++
 goffice/canvas/goc-group-impl.h     |   44 ++++
 goffice/canvas/goc-group.c          |  338 +++++++++++++++++++++++++++++++
 goffice/canvas/goc-group.h          |   45 +++++
 goffice/canvas/goc-item-impl.h      |   70 +++++++
 goffice/canvas/goc-item.c           |  357 +++++++++++++++++++++++++++++++++
 goffice/canvas/goc-item.h           |   71 +++++++
 goffice/canvas/goc-line.c           |  221 +++++++++++++++++++++
 goffice/canvas/goc-line.h           |   38 ++++
 goffice/canvas/goc-pixbuf.c         |  267 +++++++++++++++++++++++++
 goffice/canvas/goc-pixbuf.h         |   38 ++++
 goffice/canvas/goc-polygon-impl.h   |   42 ++++
 goffice/canvas/goc-polygon.c        |  243 +++++++++++++++++++++++
 goffice/canvas/goc-polygon.h        |   38 ++++
 goffice/canvas/goc-rectangle-impl.h |   40 ++++
 goffice/canvas/goc-rectangle.c      |  235 ++++++++++++++++++++++
 goffice/canvas/goc-rectangle.h      |   38 ++++
 goffice/canvas/goc-structs.h        |   34 ++++
 goffice/canvas/goc-styled-item.c    |  219 ++++++++++++++++++++
 goffice/canvas/goc-styled-item.h    |   55 +++++
 goffice/canvas/goc-text.c           |  370 ++++++++++++++++++++++++++++++++++
 goffice/canvas/goc-text.h           |   38 ++++
 goffice/canvas/goc-utils.c          |   65 ++++++
 goffice/canvas/goc-utils.h          |   40 ++++
 goffice/canvas/goc-widget-impl.h    |   40 ++++
 goffice/canvas/goc-widget.c         |  258 ++++++++++++++++++++++++
 goffice/canvas/goc-widget.h         |   39 ++++
 goffice/canvas/goffice-canvas.h     |   73 +++++++
 goffice/canvas/goffice-canvas.h~    |   75 +++++++
 goffice/goffice.h                   |    1 +
 goffice/graph/gog-guru.c            |  248 ++++++++++++------------
 goffice/gtk/go-3d-rotation-sel.c    |  115 ++++++-----
 goffice/gtk/go-font-sel.c           |   30 +--
 goffice/gtk/go-rotation-sel.c       |   90 ++++-----
 goffice/utils/go-style.c            |    6 +-
 goffice/utils/go-style.h            |   13 +-
 goffice/utils/go-styled-object.c    |   67 +++++++
 goffice/utils/go-styled-object.h    |    2 +
 52 files changed, 5224 insertions(+), 251 deletions(-)
---
diff --git a/NEWS b/NEWS
index 5f964a0..72be221 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@ Jean:
 	* Align surface ticks with grid. [#585298]
 	* Fixed various contour plots related issues. [#589511, #589512]
 	* Comparison line for probability plots. [#590416]
+	* New cairo based canvas.
 
 Morten:
 	* Fix format localization problem. [#586567]
diff --git a/configure.in b/configure.in
index 48b8416..4029d46 100644
--- a/configure.in
+++ b/configure.in
@@ -613,6 +613,7 @@ goffice/gtk/Makefile
 goffice/graph/Makefile
 goffice/drawing/Makefile
 goffice/math/Makefile
+goffice/canvas/Makefile
 goffice/ms-compat/Makefile
 goffice/component/Makefile
 goffice/cut-n-paste/Makefile
diff --git a/goffice/Makefile.am b/goffice/Makefile.am
index c47aa73..3b0fcfc 100644
--- a/goffice/Makefile.am
+++ b/goffice/Makefile.am
@@ -12,11 +12,12 @@ libgoffice_ GOFFICE_API_VER@_la_LIBADD = 			\
 	$(GOFFICE_LIBS)
 
 if WITH_GTK
-SUBDIRS += gtk drawing component
+SUBDIRS += gtk drawing component canvas
 libgoffice_ GOFFICE_API_VER@_la_LIBADD += 			\
 	gtk/libgoffice-gtk.la			\
 	drawing/libgoffice-drawing.la		\
 	component/libgoffice-component.la	\
+	canvas/libgoffice-canvas.la	\
 	cut-n-paste/foocanvas/libfoocanvas.la
 endif
 
diff --git a/goffice/canvas/Makefile.am b/goffice/canvas/Makefile.am
new file mode 100644
index 0000000..4bb3125
--- /dev/null
+++ b/goffice/canvas/Makefile.am
@@ -0,0 +1,47 @@
+noinst_LTLIBRARIES = libgoffice-canvas.la
+
+libgoffice_canvas_la_SOURCES = \
+	goc-canvas.c		\
+	goc-circle.c		\
+	goc-ellipse.c		\
+	goc-graph.c			\
+	goc-group.c			\
+	goc-item.c			\
+	goc-line.c			\
+	goc-pixbuf.c		\
+	goc-polygon.c		\
+	goc-rectangle.c		\
+	goc-styled-item.c	\
+	goc-text.c			\
+	goc-utils.c			\
+	goc-widget.c
+
+libgoffice_canvas_ladir = $(goffice_include_dir)/canvas
+libgoffice_canvas_la_HEADERS = \
+	goc-canvas.h		\
+	goc-canvas-impl.h	\
+	goc-circle.h		\
+	goc-circle-impl.h	\
+	goc-ellipse.h		\
+	goc-graph.h			\
+	goc-group.h			\
+	goc-group-impl.h	\
+	goc-item.h			\
+	goc-item-impl.h		\
+	goc-line.h			\
+	goc-pixbuf.h		\
+	goc-polygon.h		\
+	goc-polygon-impl.h  \
+	goc-rectangle.h		\
+	goc-rectangle-impl.h\
+	goc-structs.h		\
+	goc-styled-item.h	\
+	goc-text.h			\
+	goc-utils.h			\
+	goc-widget.h		\
+	goc-widget-impl.h	\
+	goffice-canvas.h
+
+include $(top_srcdir)/goffice.mk
+
+LIB_PUBLIC_HDRS = $(libgoffice_canvas_la_HEADERS)
diff --git a/goffice/canvas/Makefile.am~ b/goffice/canvas/Makefile.am~
new file mode 100644
index 0000000..7621d9e
--- /dev/null
+++ b/goffice/canvas/Makefile.am~
@@ -0,0 +1,49 @@
+noinst_LTLIBRARIES = libgoffice-canvas.la
+
+libgoffice_canvas_la_SOURCES = \
+	goc-canvas.c		\
+	goc-circle.c		\
+	goc-ellipse.c		\
+	goc-graph.c			\
+	goc-group.c			\
+	goc-item.c			\
+	goc-line.c			\
+	goc-pixbuf.c		\
+	goc-polygon.c		\
+	goc-rectangle.c		\
+	goc-styled-item.c	\
+	goc-text.c			\
+	goc-utils.c			\
+	goc-widget.c
+
+libgoffice_canvas_ladir = $(goffice_include_dir)/canvas
+libgoffice_canvas_la_HEADERS = \
+	goc-canvas.h		\
+	goc-canvas-impl.h	\
+	goc-circle.h		\
+	goc-circle-impl.h	\
+	goc-component.h		\
+	goc-ellipse.h		\
+	goc-graph.h			\
+	goc-group.h			\
+	goc-group-impl.h	\
+	goc-item.h			\
+	goc-item-impl.h		\
+	goc-line.h			\
+	goc-pixbuf.h		\
+	goc-polygon.h		\
+	goc-polygon-impl.h  \
+	goc-polyline.h		\
+	goc-rectangle.h		\
+	goc-rectangle-impl.h\
+	goc-structs.h		\
+	goc-styled-item.h	\
+	goc-text.h			\
+	goc-utils.h			\
+	goc-widget.h		\
+	goc-widget-impl.h	\
+	goffice-canvas.h
+
+include $(top_srcdir)/goffice.mk
+
+LIB_PUBLIC_HDRS = $(libgoffice_canvas_la_HEADERS)
diff --git a/goffice/canvas/goc-canvas-impl.h b/goffice/canvas/goc-canvas-impl.h
new file mode 100644
index 0000000..ed5d113
--- /dev/null
+++ b/goffice/canvas/goc-canvas-impl.h
@@ -0,0 +1,46 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-canvas-impl.h :
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_CANVAS_IMPL_H
+#define GOC_CANVAS_IMPL_H
+
+#include <goffice/goffice.h>
+
+struct _GocCanvas {
+	GtkLayout base;
+	double scroll_x1, scroll_y1;
+	double pixels_per_unit;
+	double width, height;
+	int wwidth, wheight;
+	GocGroup *root;
+	GocItem *grabbed_item;
+	GocItem	*last_item;
+	GODoc *document;
+	GdkEvent *cur_event;
+};
+
+typedef struct {
+	GtkLayoutClass parent;
+	
+} GocCanvasClass;
+
+#endif  /* GOC_CANVAS_IMPL_H */
diff --git a/goffice/canvas/goc-canvas.c b/goffice/canvas/goc-canvas.c
new file mode 100644
index 0000000..7950916
--- /dev/null
+++ b/goffice/canvas/goc-canvas.c
@@ -0,0 +1,373 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-canvas.c :  
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <gsf/gsf-impl-utils.h>
+#include <math.h>
+
+static GObjectClass *parent_klass;
+
+static gboolean
+expose_cb (GocCanvas *canvas, GdkEventExpose *event, G_GNUC_UNUSED gpointer data)
+{
+	double x0, y0, x1, y1;
+	double ax0, ay0, ax1, ay1;
+
+       if (event->count)
+		return TRUE;
+	goc_item_get_bounds (GOC_ITEM (canvas->root),&x0, &y0, &x1, &y1);
+	ax0 = (double) event->area.x / canvas->pixels_per_unit + canvas->scroll_x1;
+	ay0 = (double) event->area.y / canvas->pixels_per_unit + canvas->scroll_y1;
+	ax1 = ((double) event->area.x + event->area.width) / canvas->pixels_per_unit + canvas->scroll_x1;
+	ay1 = ((double) event->area.y + event->area.height) / canvas->pixels_per_unit + canvas->scroll_y1;
+	if (x0 <= ax1 && x1 >= ax0 && y0 <= ay1 && y1 >= ay0) {
+		cairo_t *cr = gdk_cairo_create (event->window);
+		canvas->cur_event = (GdkEvent *) event;
+		goc_item_draw_region (GOC_ITEM (canvas->root), cr, ax0, ay0, ax1, ay1);
+		cairo_destroy (cr);
+		canvas->cur_event = NULL;
+	}
+	return TRUE;
+}
+
+static gboolean
+button_press_cb (GocCanvas *canvas, GdkEventButton *event, G_GNUC_UNUSED gpointer data)
+{
+	double x = canvas->scroll_x1 +  event->x / canvas->pixels_per_unit;
+	double y = canvas->scroll_y1 + event->y / canvas->pixels_per_unit;
+	GocItem *item = goc_canvas_get_item_at (canvas, x, y);
+	if (item) {
+		canvas->cur_event = (GdkEvent *) event;
+		if (event->type == GDK_2BUTTON_PRESS)
+			return GOC_ITEM_GET_CLASS (item)->button2_pressed (item, event->button, x, y);
+		return GOC_ITEM_GET_CLASS (item)->button_pressed (item, event->button, x, y);
+		canvas->cur_event = NULL;
+	}
+	return FALSE;
+}
+
+static gboolean
+button_release_cb (GocCanvas *canvas, GdkEventButton *event, G_GNUC_UNUSED gpointer data)
+{
+	double x = canvas->scroll_x1 +  event->x / canvas->pixels_per_unit;
+	double y = canvas->scroll_y1 + event->y / canvas->pixels_per_unit;
+	GocItem *item = (canvas->grabbed_item != NULL)?
+		canvas->grabbed_item:
+		goc_canvas_get_item_at (canvas, x, y);
+	if (item) {
+		canvas->cur_event = (GdkEvent *) event;
+		return GOC_ITEM_GET_CLASS (item)->button_released (item, event->button, x, y);
+		canvas->cur_event = NULL;
+	}
+	return FALSE;
+}
+
+static gboolean
+motion_cb (GocCanvas *canvas, GdkEventMotion *event, G_GNUC_UNUSED gpointer data)
+{
+	double x = canvas->scroll_x1 +  event->x / canvas->pixels_per_unit;
+	double y = canvas->scroll_y1 + event->y / canvas->pixels_per_unit;
+	GocItem *item;
+	if (canvas->grabbed_item != NULL) 
+		item = canvas->grabbed_item;
+	else
+		item = goc_canvas_get_item_at (canvas, x, y);
+	canvas->cur_event = (GdkEvent *) event;
+	if (canvas->last_item && item != canvas->last_item) {
+		GOC_ITEM_GET_CLASS (canvas->last_item)->leave_notify (canvas->last_item, x, y);
+		canvas->last_item = NULL;
+	}
+	if (item) {
+		GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+		if (item != canvas->last_item) {
+			canvas->last_item = item;
+			klass->enter_notify (item, x, y);
+		}
+		return klass->motion (item, x, y); 
+	}
+	canvas->cur_event = NULL;
+	return FALSE;
+}
+
+static void
+destroy_cb (GocCanvas *canvas, G_GNUC_UNUSED gpointer data)
+{
+}
+
+static gboolean
+key_release_cb (GocCanvas *canvas, GdkEventKey* event, G_GNUC_UNUSED gpointer data)
+{
+	return FALSE;
+}
+
+static gboolean
+key_press_cb (GocCanvas *canvas, GdkEventKey* event, G_GNUC_UNUSED gpointer data)
+{
+	return FALSE;
+}
+
+static gboolean
+enter_notify_cb (GocCanvas *canvas, GdkEventCrossing* event, G_GNUC_UNUSED gpointer data)
+{
+	double x = canvas->scroll_x1 +  event->x / canvas->pixels_per_unit;
+	double y = canvas->scroll_y1 + event->y / canvas->pixels_per_unit;
+	GocItem *item = goc_canvas_get_item_at (canvas, x, y);
+	if (item) {
+		canvas->last_item = item;
+		return GOC_ITEM_GET_CLASS (item)->enter_notify (item, x, y);
+	}
+	return FALSE;
+}
+
+static gboolean
+leave_notify_cb (GocCanvas *canvas, GdkEventCrossing* event, G_GNUC_UNUSED gpointer data)
+{
+	double x = canvas->scroll_x1 +  event->x / canvas->pixels_per_unit;
+	double y = canvas->scroll_y1 + event->y / canvas->pixels_per_unit;
+	if (canvas->last_item) {
+		gboolean result = GOC_ITEM_GET_CLASS (canvas->last_item)->leave_notify (canvas->last_item, x, y);
+		canvas->last_item = NULL;
+		return result;
+	}
+	return FALSE;
+}
+
+static void
+size_changed_cb (GocCanvas *canvas, GtkAllocation *alloc, G_GNUC_UNUSED gpointer data)
+{
+	canvas->wwidth = alloc->width;
+	canvas->wheight = alloc->height;
+}
+
+static void
+realize_cb (GocCanvas *canvas, G_GNUC_UNUSED gpointer data)
+{
+	GocItemClass *klass = GOC_ITEM_GET_CLASS (canvas->root);
+	klass->realize (GOC_ITEM (canvas->root));
+}
+
+static void
+unrealize_cb (GocCanvas *canvas, G_GNUC_UNUSED gpointer data)
+{
+	GocItemClass *klass = GOC_ITEM_GET_CLASS (canvas->root);
+	klass->unrealize (GOC_ITEM (canvas->root));
+}
+
+static void
+goc_canvas_finalize (GObject *obj)
+{
+	GocCanvas *canvas = GOC_CANVAS (obj);
+	g_object_unref (G_OBJECT (canvas->root));
+	(parent_klass->finalize) (obj);
+}
+
+static void
+goc_canvas_class_init (GObjectClass *klass)
+{
+	parent_klass = g_type_class_peek_parent (klass);
+	klass->finalize = goc_canvas_finalize;
+}
+
+static void
+goc_canvas_init (GocCanvas *canvas)
+{
+	GtkWidget *w = GTK_WIDGET (canvas);
+
+	canvas->root = GOC_GROUP (g_object_new (GOC_TYPE_GROUP, NULL));
+	canvas->root->base.canvas = canvas;
+	canvas->pixels_per_unit = 1.;
+	gtk_widget_add_events (w,
+			   GDK_POINTER_MOTION_MASK |
+			   GDK_BUTTON_MOTION_MASK |
+			   GDK_BUTTON_PRESS_MASK |
+			   GDK_2BUTTON_PRESS |
+			   GDK_BUTTON_RELEASE_MASK |
+			   GDK_KEY_PRESS_MASK |
+			   GDK_KEY_RELEASE_MASK |
+			   GDK_ENTER_NOTIFY_MASK	
+			   );
+	g_signal_connect (G_OBJECT (w), "button-press-event", G_CALLBACK (button_press_cb), NULL);
+	g_signal_connect (G_OBJECT (w), "button-release-event", G_CALLBACK (button_release_cb), NULL);
+	g_signal_connect (G_OBJECT (w), "motion-notify-event", G_CALLBACK (motion_cb), NULL);
+	g_signal_connect (G_OBJECT (w), "destroy", G_CALLBACK (destroy_cb), NULL);
+	g_signal_connect (G_OBJECT (w), "expose-event", G_CALLBACK (expose_cb), NULL);
+	g_signal_connect (G_OBJECT (w), "key_press_event", (GCallback) key_press_cb, NULL);
+	g_signal_connect (G_OBJECT (w), "key_release_event", (GCallback) key_release_cb, NULL);
+	g_signal_connect (G_OBJECT (w), "size-allocate", (GCallback) size_changed_cb, NULL);
+	g_signal_connect (G_OBJECT (w), "enter-notify-event", G_CALLBACK (enter_notify_cb), NULL);
+	g_signal_connect (G_OBJECT (w), "leave-notify-event", G_CALLBACK (leave_notify_cb), NULL);
+	g_signal_connect (G_OBJECT (w), "realize", G_CALLBACK (realize_cb), NULL);
+	g_signal_connect (G_OBJECT (w), "unrealize", G_CALLBACK (unrealize_cb), NULL);
+}
+
+GSF_CLASS (GocCanvas, goc_canvas,
+	   goc_canvas_class_init, goc_canvas_init,
+	   GTK_TYPE_LAYOUT)
+
+GocGroup*
+goc_canvas_get_root (GocCanvas *canvas)
+{
+	g_return_val_if_fail (GOC_IS_CANVAS (canvas), NULL);
+	return canvas->root;
+}
+
+void
+goc_canvas_set_scroll_region (GocCanvas *canvas, double width, double height)
+{
+	g_return_if_fail (GOC_IS_CANVAS (canvas));
+	canvas->width = width;
+	canvas->height = height;
+}
+
+double
+goc_canvas_get_width (GocCanvas *canvas)
+{
+	g_return_val_if_fail (GOC_IS_CANVAS (canvas), 0);
+	return canvas->width;
+}
+
+double
+goc_canvas_get_height (GocCanvas *canvas)
+{
+	g_return_val_if_fail (GOC_IS_CANVAS (canvas), 0);
+	return canvas->height;
+}
+
+void
+goc_canvas_scroll_to (GocCanvas *canvas, double x, double y)
+{
+	GocItemClass *klass;
+	g_return_if_fail (GOC_IS_CANVAS (canvas));
+	if (x == canvas->scroll_x1 && canvas->scroll_y1 == y)
+		return;
+	klass = GOC_ITEM_GET_CLASS (canvas->root);
+	canvas->scroll_x1 = x;
+	canvas->scroll_y1 = y;
+	klass->notify_scrolled (GOC_ITEM (canvas->root));
+	gtk_widget_queue_draw_area (GTK_WIDGET (canvas),
+					    0, 0, G_MAXINT, G_MAXINT);
+}
+
+void
+goc_canvas_get_scroll_position (GocCanvas *canvas, double *x, double *y)
+{
+	g_return_if_fail (GOC_IS_CANVAS (canvas));
+	if (x)
+		*x = canvas->scroll_x1;
+	if (y)
+		*y = canvas->scroll_y1;
+}
+
+void
+goc_canvas_set_pixels_per_unit (GocCanvas *canvas, double pixels_per_unit)
+{
+	GocItemClass *klass;
+	g_return_if_fail (GOC_IS_CANVAS (canvas));
+	if (pixels_per_unit == canvas->pixels_per_unit)
+		return;
+	klass = GOC_ITEM_GET_CLASS (canvas->root);
+	canvas->pixels_per_unit = pixels_per_unit;
+	klass->notify_scrolled (GOC_ITEM (canvas->root));
+	gtk_widget_queue_draw_area (GTK_WIDGET (canvas),
+					    0, 0, G_MAXINT, G_MAXINT);
+}
+
+double
+goc_canvas_get_pixels_per_unit (GocCanvas *canvas)
+{
+	g_return_val_if_fail (GOC_IS_CANVAS (canvas), 0);
+	return canvas->pixels_per_unit;
+}
+
+void
+goc_canvas_invalidate (GocCanvas *canvas, double x0, double y0, double x1, double y1)
+{
+	if (!GTK_WIDGET_REALIZED (canvas))
+		return;
+	x0 = (x0 - canvas->scroll_x1) * canvas->pixels_per_unit;
+	y0 = (y0 - canvas->scroll_y1) * canvas->pixels_per_unit;
+	x1 = (x1 - canvas->scroll_x1) * canvas->pixels_per_unit;
+	y1 = (y1 - canvas->scroll_y1) * canvas->pixels_per_unit;
+	if (x0 < 0.)
+		x0 = 0;
+	if (y0 < 0)
+		y0 = 0;
+	if (x1 > canvas->wwidth)
+		x1 = canvas->wwidth;
+	if (y1 > canvas->wheight)
+		y1 = canvas->wheight;
+	if (x1 > x0 && y1 > y0)
+		gtk_widget_queue_draw_area (GTK_WIDGET (canvas),
+					    (int) floor (x0), (int) floor (y0),
+					    (int) ceil (x1), (int) ceil (y1));
+}
+
+GocItem*
+goc_canvas_get_item_at (GocCanvas *canvas, double x, double y)
+{
+	GocItem *result = NULL;
+	double d = goc_item_distance (GOC_ITEM (canvas->root), x, y, &result);
+	return (d == 0.)? result: NULL;
+}
+
+void
+goc_canvas_grab_item (GocCanvas *canvas, GocItem *item)
+{
+	g_return_if_fail (GOC_IS_CANVAS (canvas) && canvas->grabbed_item == NULL);
+	canvas->grabbed_item = item;
+}
+
+void
+goc_canvas_ungrab_item (GocCanvas *canvas)
+{
+	g_return_if_fail (GOC_IS_CANVAS (canvas) && canvas->grabbed_item != NULL);
+	canvas->grabbed_item = NULL;
+}
+
+GocItem *
+goc_canvas_get_grabbed_item (GocCanvas *canvas)
+{
+	g_return_val_if_fail (GOC_IS_CANVAS (canvas), NULL);
+	return canvas->grabbed_item;
+}
+
+void
+goc_canvas_set_document (GocCanvas *canvas, GODoc *document)
+{
+	g_return_if_fail (GOC_IS_CANVAS (canvas));
+	canvas->document = document;
+}
+
+GODoc*
+goc_canvas_get_document (GocCanvas *canvas)
+{
+	g_return_val_if_fail (GOC_IS_CANVAS (canvas), NULL);
+	return canvas->document;
+}
+
+GdkEvent*
+goc_canvas_get_cur_event (GocCanvas *canvas)
+{
+	g_return_val_if_fail (GOC_IS_CANVAS (canvas), NULL);
+	return canvas->cur_event;
+}
diff --git a/goffice/canvas/goc-canvas.h b/goffice/canvas/goc-canvas.h
new file mode 100644
index 0000000..7083cc8
--- /dev/null
+++ b/goffice/canvas/goc-canvas.h
@@ -0,0 +1,55 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-canvas.h :  
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_CANVAS_H
+#define GOC_CANVAS_H
+
+#include <goffice/goffice.h>
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_CANVAS	(goc_canvas_get_type ())
+#define GOC_CANVAS(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_CANVAS, GocCanvas))
+#define GOC_IS_CANVAS(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_CANVAS))
+
+GType goc_canvas_get_type (void);
+
+GocGroup	*goc_canvas_get_root (GocCanvas *canvas);
+void		 goc_canvas_set_scroll_region (GocCanvas *canvas, double width, double height);
+double		 goc_canvas_get_width (GocCanvas *canvas);
+double		 goc_canvas_get_height (GocCanvas *canvas);
+void		 goc_canvas_scroll_to (GocCanvas *canvas, double x, double y);
+void		 goc_canvas_get_scroll_position (GocCanvas *canvas, double *x, double *y);
+void		 goc_canvas_set_pixels_per_unit (GocCanvas *canvas, double pixels_per_unit);
+double		 goc_canvas_get_pixels_per_unit (GocCanvas *canvas);
+void		 goc_canvas_invalidate (GocCanvas *canvas, double x0, double y0, double x1, double y1);
+GocItem		*goc_canvas_get_item_at (GocCanvas *canvas, double x, double y);
+void		 goc_canvas_grab_item (GocCanvas *canvas, GocItem *item);
+void		 goc_canvas_ungrab_item (GocCanvas *canvas);
+GocItem		*goc_canvas_get_grabbed_item (GocCanvas *canvas);
+void		 goc_canvas_set_document (GocCanvas *canvas, GODoc *document);
+GODoc		*goc_canvas_get_document (GocCanvas *canvas);
+GdkEvent	*goc_canvas_get_cur_event (GocCanvas *canvas);
+G_END_DECLS
+
+#endif  /* GOC_CANVAS_H */
diff --git a/goffice/canvas/goc-circle-impl.h b/goffice/canvas/goc-circle-impl.h
new file mode 100644
index 0000000..495351e
--- /dev/null
+++ b/goffice/canvas/goc-circle-impl.h
@@ -0,0 +1,39 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-circle-impl.h :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_CIRCLE_IMPL_H
+#define GOC_CIRCLE_IMPL_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+struct _GocCircle {
+	GocStyledItem base;
+
+	double x, y, radius;
+};
+
+typedef GocStyledItemClass GocCircleClass;
+
+G_END_DECLS
+
+#endif  /* GOC_CIRCLE_IMPL_H */
\ No newline at end of file
diff --git a/goffice/canvas/goc-circle.c b/goffice/canvas/goc-circle.c
new file mode 100644
index 0000000..b696375
--- /dev/null
+++ b/goffice/canvas/goc-circle.c
@@ -0,0 +1,208 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-circle.c :  
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <gsf/gsf-impl-utils.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+
+enum {
+	CIRCLE_PROP_0,
+	CIRCLE_PROP_X,
+	CIRCLE_PROP_Y,
+	CIRCLE_PROP_R
+};
+
+static void
+goc_circle_set_property (GObject *gobject, guint param_id,
+				    GValue const *value, GParamSpec *pspec)
+{
+	GocCircle *circle = GOC_CIRCLE (gobject);
+
+	switch (param_id) {
+	case CIRCLE_PROP_X:
+		circle->x = g_value_get_double (value);
+		break;
+
+	case CIRCLE_PROP_Y:
+		circle->y = g_value_get_double (value);
+		break;
+
+	case CIRCLE_PROP_R:
+		circle->radius = g_value_get_double (value);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+	goc_item_bounds_changed (GOC_ITEM (gobject));
+}
+
+static void
+goc_circle_get_property (GObject *gobject, guint param_id,
+				    GValue *value, GParamSpec *pspec)
+{
+	GocCircle *circle = GOC_CIRCLE (gobject);
+
+	switch (param_id) {
+	case CIRCLE_PROP_X:
+		g_value_set_double (value, circle->x);
+		break;
+
+	case CIRCLE_PROP_Y:
+		g_value_set_double (value, circle->y);
+		break;
+
+	case CIRCLE_PROP_R:
+		g_value_set_double (value, circle->radius);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+}
+
+static double
+goc_circle_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+	GocCircle *circle = GOC_CIRCLE (item);
+	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+	double d, extra_dist = 0.;
+	if (style->outline.dash_type != GO_LINE_NONE)
+		extra_dist = (style->outline.width)? style->outline.width / 2.: .5;
+	*near_item = item;
+	x -= circle->x;
+	y -= circle->y;
+	d = sqrt (x * x + y * y);
+	return MAX (d - circle->radius - extra_dist, 0);
+}
+
+static void
+goc_circle_draw (GocItem const *item, cairo_t *cr)
+{
+	GocCircle *circle = GOC_CIRCLE (item);
+	GOLineDashSequence *line_dash;
+	cairo_pattern_t *pat = NULL;
+	double width;
+	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+
+	cairo_save (cr);
+	goc_group_cairo_transform (item->parent, cr, circle->x, circle->y);
+	cairo_scale (cr, circle->radius, circle->radius);
+	cairo_arc (cr, 0., 0., 1., 0., 2 * M_PI);
+	cairo_restore (cr);
+	/* Fill the shape */
+	pat = go_style_create_cairo_pattern (style, cr);
+	if (pat) {
+		cairo_set_source (cr, pat);
+		cairo_fill_preserve (cr);
+		cairo_pattern_destroy (pat);
+	}
+	/* Draw the line */
+	width = (style->outline.width)? style->outline.width: 1.;
+	cairo_set_line_width (cr, width);
+	line_dash = go_line_dash_get_sequence (style->outline.dash_type, width);
+	if (line_dash != NULL)
+		cairo_set_dash (cr,
+				line_dash->dash,
+				line_dash->n_dash,
+				line_dash->offset);
+	else
+		cairo_set_dash (cr, NULL, 0, 0);
+	cairo_set_source_rgba (cr,
+		UINT_RGBA_R (style->outline.color),
+		UINT_RGBA_B (style->outline.color),
+		UINT_RGBA_G (style->outline.color),
+		UINT_RGBA_A (style->outline.color));
+	cairo_stroke (cr);
+
+	if (line_dash != NULL)
+		go_line_dash_sequence_free (line_dash);
+}
+
+static void
+goc_circle_update_bounds (GocItem *item)
+{
+	GocCircle *circle = GOC_CIRCLE (item);
+	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+	double r = circle->radius;
+	if (style->outline.dash_type != GO_LINE_NONE)
+		r += (style->outline.width)? style->outline.width / 2.: .5;
+	item->x0 = circle->x - r;
+	item->y0 = circle->y - r;
+	item->x1 = circle->x + r;
+	item->y1 = circle->y + r;
+}
+
+static void
+goc_circle_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
+{
+	style->interesting_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL;
+	if (style->outline.auto_dash)
+		style->outline.dash_type = GO_LINE_SOLID;
+	if (style->outline.auto_color)
+		style->outline.color = RGBA_BLACK;
+	if (style->fill.auto_type)
+		style->fill.type  = GO_STYLE_FILL_PATTERN;
+	if (style->fill.auto_fore)
+		go_pattern_set_solid (&style->fill.pattern, RGBA_WHITE);
+}
+
+static void
+goc_circle_class_init (GocItemClass *item_klass)
+{
+	GObjectClass *obj_klass = (GObjectClass *) item_klass;
+	GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+
+	obj_klass->get_property = goc_circle_get_property;
+	obj_klass->set_property = goc_circle_set_property;
+	g_object_class_install_property (obj_klass, CIRCLE_PROP_X,
+		g_param_spec_double ("x", 
+			_("x"),
+			_("The circle center horizontal position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, CIRCLE_PROP_Y,
+		g_param_spec_double ("y", 
+			_("y"),
+			_("The circle center vertical position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, CIRCLE_PROP_R,
+		g_param_spec_double ("radius", 
+			_("Radius"),
+			_("The circle radius"),
+			0., G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+	gsi_klass->init_style = goc_circle_init_style;
+
+	item_klass->distance = goc_circle_distance;
+	item_klass->draw = goc_circle_draw;
+	item_klass->update_bounds = goc_circle_update_bounds;
+}
+
+GSF_CLASS (GocCircle, goc_circle,
+	   goc_circle_class_init, NULL,
+	   GOC_TYPE_STYLED_ITEM)
diff --git a/goffice/canvas/goc-circle.h b/goffice/canvas/goc-circle.h
new file mode 100644
index 0000000..e88e707
--- /dev/null
+++ b/goffice/canvas/goc-circle.h
@@ -0,0 +1,38 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-circle.h :  
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_CIRCLE_H
+#define GOC_CIRCLE_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_CIRCLE	(goc_circle_get_type ())
+#define GOC_CIRCLE(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_CIRCLE, GocCircle))
+#define GOC_IS_CIRCLE(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_CIRCLE))
+
+GType goc_circle_get_type (void);
+
+G_END_DECLS
+
+#endif  /* GOC_CIRCLE_H */
diff --git a/goffice/canvas/goc-ellipse.c b/goffice/canvas/goc-ellipse.c
new file mode 100644
index 0000000..c27e0bd
--- /dev/null
+++ b/goffice/canvas/goc-ellipse.c
@@ -0,0 +1,266 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-ellipse.c :  
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+
+struct _GocEllipse {
+	GocStyledItem base;
+
+	double rotation; /* rotation around the center in radians */
+	double x, y, width, height;
+};
+
+typedef GocStyledItemClass GocEllipseClass;
+
+enum {
+	ELLIPSE_PROP_0,
+	ELLIPSE_PROP_X,
+	ELLIPSE_PROP_Y,
+	ELLIPSE_PROP_W,
+	ELLIPSE_PROP_H,
+	ELLIPSE_PROP_ROTATION
+};
+
+static void
+goc_ellipse_set_property (GObject *gobject, guint param_id,
+				    GValue const *value, GParamSpec *pspec)
+{
+	GocEllipse *ellipse = GOC_ELLIPSE (gobject);
+
+	switch (param_id) {
+	case ELLIPSE_PROP_X:
+		ellipse->x = g_value_get_double (value);
+		break;
+
+	case ELLIPSE_PROP_Y:
+		ellipse->y = g_value_get_double (value);
+		break;
+
+	case ELLIPSE_PROP_W:
+		ellipse->width = g_value_get_double (value);
+		break;
+
+	case ELLIPSE_PROP_H:
+		ellipse->height = g_value_get_double (value);
+		break;
+
+	case ELLIPSE_PROP_ROTATION:
+		ellipse->rotation = g_value_get_double (value);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+	goc_item_invalidate (GOC_ITEM (gobject));
+
+}
+
+static void
+goc_ellipse_get_property (GObject *gobject, guint param_id,
+				    GValue *value, GParamSpec *pspec)
+{
+	GocEllipse *ellipse = GOC_ELLIPSE (gobject);
+
+	switch (param_id) {
+	case ELLIPSE_PROP_X:
+		g_value_set_double (value, ellipse->x);
+		break;
+
+	case ELLIPSE_PROP_Y:
+		g_value_set_double (value, ellipse->y);
+		break;
+
+	case ELLIPSE_PROP_W:
+		g_value_set_double (value, ellipse->width);
+		break;
+
+	case ELLIPSE_PROP_H:
+		g_value_set_double (value, ellipse->height);
+		break;
+
+	case ELLIPSE_PROP_ROTATION:
+		g_value_set_double (value, ellipse->rotation);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+	goc_item_bounds_changed (GOC_ITEM (ellipse));
+}
+
+static void
+goc_ellipse_update_bounds (GocItem *item)
+{
+	GocEllipse *ellipse = GOC_ELLIPSE (item);
+	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+	/* FIXME: take rotation into account */
+	double extra_width = style->outline.width /2.;
+	if (extra_width <= 0.)
+		extra_width = .5;
+	item->x0 = ellipse->x - extra_width;
+	item->y0 = ellipse->y - extra_width;
+	item->x1 = ellipse->x + ellipse->width + extra_width;
+	item->y1 = ellipse->y + ellipse->height + extra_width;
+}
+
+static double
+goc_ellipse_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+	GocEllipse *ellipse = GOC_ELLIPSE (item);
+	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+	/* FIXME: take rotation into account */
+	/* FIXME: we just consider that a point inside the ellipse is at distance 0
+	 even if the ellipse is not filled */
+	double extra_width = (style->outline.width)? style->outline.width /2.: .5;
+	double last = G_MAXDOUBLE, df, d2f, t, cs, sn,
+		a = ellipse->width / 2, b = ellipse->height / 2,
+		c = a * a - b * b;
+	*near_item = item;
+	x = fabs (x - ellipse->x - a);
+	y = fabs (y - ellipse->y - b);
+	if (y < DBL_EPSILON) {
+		x -= a + extra_width;
+		return (x > 0.)? x: 0.;
+	}
+	if (x < DBL_EPSILON) {
+		y -= b + extra_width;
+		return (y > 0.)? y: 0.;
+	}
+	if (hypot (x / a, y / b) < 1.)
+		return 0.;
+
+	/* initial value: */
+	t = atan2 (y, x);
+	/* iterate using the Newton method */
+	while (1) {
+		cs = cos (t);
+		sn = sin (t);
+		df = a * x * sn - b * y * cs - c * cs * sn;
+		d2f = a * x * cs + b * y * sn - c * (cs * cs - sn * sn);
+		t -= df / d2f;
+		if ( last == df || fabs (df) < DBL_EPSILON || fabs (df) >= fabs (last))
+			break;
+		last = df;
+	}
+	/* evaluate the distance and store in df */
+	df = hypot (x - a * cos (t), y - b * sin (t)) - extra_width;
+	return (df > 0.)? df: 0.;
+}
+
+static void
+goc_ellipse_draw (GocItem const *item, cairo_t *cr)
+{
+	GocEllipse *ellipse = GOC_ELLIPSE (item);
+	cairo_pattern_t *pat = NULL;
+	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+
+	cairo_save (cr);
+	goc_group_cairo_transform (item->parent, cr, ellipse->x, ellipse->y);
+	cairo_translate (cr, ellipse->width / 2., ellipse->height / 2.);
+	cairo_scale (cr, ellipse->width / 2., ellipse->height / 2.);
+	cairo_rotate (cr, ellipse->rotation);
+	cairo_arc (cr, 0., 0., 1., 0., 2 * M_PI);
+	cairo_restore (cr);
+	/* Fill the shape */
+	pat = go_style_create_cairo_pattern (style, cr);
+	if (pat) {
+		cairo_set_source (cr, pat);
+		if (style->outline.dash_type != GO_LINE_NONE)
+			cairo_fill_preserve (cr);
+		else
+			cairo_fill (cr);
+		cairo_pattern_destroy (pat);
+	}
+	/* Draw the line */
+	if (go_styled_object_set_cairo_line (GO_STYLED_OBJECT (item), cr))
+		cairo_stroke (cr);
+	else
+		cairo_new_path (cr);
+}
+
+static void
+goc_ellipse_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
+{
+	style->interesting_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL;
+	if (style->outline.auto_dash)
+		style->outline.dash_type = GO_LINE_SOLID;
+	if (style->outline.auto_color)
+		style->outline.color = RGBA_BLACK;
+	if (style->fill.auto_type)
+		style->fill.type  = GO_STYLE_FILL_PATTERN;
+	if (style->fill.auto_fore)
+		go_pattern_set_solid (&style->fill.pattern, RGBA_WHITE);
+}
+
+static void
+goc_ellipse_class_init (GocItemClass *item_klass)
+{
+	GObjectClass *obj_klass = (GObjectClass *) item_klass;
+	GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+
+	obj_klass->get_property = goc_ellipse_get_property;
+	obj_klass->set_property = goc_ellipse_set_property;
+	g_object_class_install_property (obj_klass, ELLIPSE_PROP_X,
+		g_param_spec_double ("x",
+			_("x"),
+			_("The rectangle left position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, ELLIPSE_PROP_Y,
+		g_param_spec_double ("y",
+			_("y"),
+			_("The rectangle top position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, ELLIPSE_PROP_W,
+		g_param_spec_double ("width", 
+			_("Width"),
+			_("The rectangle width"),
+			0., G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, ELLIPSE_PROP_H,
+		g_param_spec_double ("height", 
+			_("Height"),
+			_("The rectangle height"),
+			0., G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+/*	g_object_class_install_property (obj_klass, ELLIPSE_PROP_ROTATION,
+		g_param_spec_double ("rotation", 
+			_("Rotation"),
+			_("The rotation around top left position"),
+			0., 2 * M_PI, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));*/
+
+	gsi_klass->init_style = goc_ellipse_init_style;
+
+	item_klass->update_bounds = goc_ellipse_update_bounds;
+	item_klass->distance = goc_ellipse_distance;
+	item_klass->draw = goc_ellipse_draw;
+}
+
+GSF_CLASS (GocEllipse, goc_ellipse,
+	   goc_ellipse_class_init, NULL,
+	   GOC_TYPE_STYLED_ITEM)
diff --git a/goffice/canvas/goc-ellipse.h b/goffice/canvas/goc-ellipse.h
new file mode 100644
index 0000000..9d7ac91
--- /dev/null
+++ b/goffice/canvas/goc-ellipse.h
@@ -0,0 +1,38 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-ellipse.h :  
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_ELLIPSE_H
+#define GOC_ELLIPSE_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_ELLIPSE	(goc_ellipse_get_type ())
+#define GOC_ELLIPSE(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_ELLIPSE, GocEllipse))
+#define GOC_IS_ELLIPSE(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_ELLIPSE))
+
+GType goc_ellipse_get_type (void);
+
+G_END_DECLS
+
+#endif  /* GOC_ELLIPSE_H */
diff --git a/goffice/canvas/goc-graph.c b/goffice/canvas/goc-graph.c
new file mode 100644
index 0000000..a5bd038
--- /dev/null
+++ b/goffice/canvas/goc-graph.c
@@ -0,0 +1,271 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-graph.c :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+
+#include <math.h>
+
+struct _GocGraph {
+	GocItem base;
+
+	double x, y, w, h;
+	GogRenderer *renderer;
+};
+
+typedef GocItemClass GocGraphClass;
+
+static GObjectClass *parent_klass;
+
+enum {
+	GRAPH_PROP_0,
+	GRAPH_PROP_X,
+	GRAPH_PROP_Y,
+	GRAPH_PROP_H,
+	GRAPH_PROP_W,
+	GRAPH_PROP_GRAPH,
+	GRAPH_PROP_RENDERER
+};
+
+static void
+goc_graph_set_property (GObject *obj, guint param_id,
+			GValue const *value, GParamSpec *pspec)
+{
+	GocGraph *graph = GOC_GRAPH (obj);
+	gboolean setup_renderer = FALSE;
+
+	switch (param_id) {
+	case GRAPH_PROP_X: {
+		double x = g_value_get_double (value);
+		if (x == graph->x)
+			return;
+		graph->x = x;
+		return;
+	}
+	case GRAPH_PROP_Y: {
+		double y = g_value_get_double (value);
+		if (y == graph->y)
+			return;
+		graph->y = y;
+		break;
+	}
+	case GRAPH_PROP_H: {
+		double h = g_value_get_double (value);
+		if (h == graph->h)
+			return;
+		graph->h = h;
+		break;
+	}
+	case GRAPH_PROP_W: {
+		double w = g_value_get_double (value);
+		if (w == graph->w)
+			return;
+		graph->w = w;
+		break;
+	}
+	case GRAPH_PROP_GRAPH:
+		if (graph->renderer != NULL)
+			g_object_unref (graph->renderer);
+		graph->renderer = gog_renderer_new (g_value_get_object (value));
+		setup_renderer = graph->renderer != NULL;
+		break;
+
+	case GRAPH_PROP_RENDERER:
+		if (graph->renderer != NULL)
+			g_object_unref (graph->renderer);
+		graph->renderer = GOG_RENDERER (g_value_get_object (value));
+		if (graph->renderer != NULL) {
+			g_object_ref (graph->renderer);
+			setup_renderer = TRUE;
+		}
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+
+	if (setup_renderer)
+		g_signal_connect_object (G_OBJECT (graph->renderer),
+			"request-update",
+			G_CALLBACK (goc_item_invalidate),
+			graph, G_CONNECT_SWAPPED);
+	goc_item_bounds_changed (GOC_ITEM (graph));
+}
+
+static void
+goc_graph_get_property (GObject *obj, guint param_id,
+			GValue *value, GParamSpec *pspec)
+{
+	GocGraph *graph = GOC_GRAPH (obj);
+
+	switch (param_id) {
+	case GRAPH_PROP_X:
+		g_value_set_double (value, graph->x);
+		break;
+	case GRAPH_PROP_Y:
+		g_value_set_double (value, graph->y);
+		break;
+	case GRAPH_PROP_H:
+		g_value_set_double (value, graph->h);
+		break;
+	case GRAPH_PROP_W:
+		g_value_set_double (value, graph->w);
+		break;
+	case GRAPH_PROP_RENDERER:
+		g_value_set_object (value, graph->renderer);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+		break;
+	}
+}
+
+static void
+goc_graph_finalize (GObject *obj)
+{
+	GocGraph *graph = GOC_GRAPH (obj);
+
+	if (graph->renderer != NULL) {
+		g_object_unref (graph->renderer);
+		graph->renderer = NULL;
+	}
+	(*parent_klass->finalize) (obj);
+}
+
+static double
+goc_graph_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+	GocGraph *graph = GOC_GRAPH (item);
+	double dx, dy;
+	x -= graph->x;
+	y -= graph->y;
+	if (x < 0) {
+		dx = -x;
+	} else if (x < graph->w) {
+		dx = 0;
+	} else {
+		dx = x - graph->w;
+	}
+	if (y < 0) {
+		dy = -y;
+	} else if (y < graph->h) {
+		dy = 0;
+	} else {
+		dy = y - graph->h;
+	}
+	*near_item = item;
+	return hypot (dx, dy);
+}
+
+static void
+goc_graph_draw (GocItem const *item, cairo_t *cr)
+{
+	GocGraph *graph = GOC_GRAPH (item);
+	GocCanvas *canvas = item->canvas;
+	cairo_surface_t *surf;
+	double x0 = item->x0, y0 = item->y0;
+	if (graph->renderer == NULL)
+		return;
+	goc_group_adjust_coords (item->parent, &x0, &y0);
+	cairo_save (cr);
+	cairo_translate (cr,
+	                 (int) (x0 - canvas->scroll_x1) * canvas->pixels_per_unit,
+	                 (int) (y0 - canvas->scroll_y1) * canvas->pixels_per_unit);
+	/* scaling only there gives a better rendering, and allows for caching */
+	gog_renderer_update (graph->renderer,
+				      (int) (graph->w * canvas->pixels_per_unit),
+				      (int) (graph->h * canvas->pixels_per_unit));
+	surf = gog_renderer_get_cairo_surface (graph->renderer);
+	cairo_set_source_surface (cr, surf, 0., 0.);
+	cairo_paint (cr);
+	cairo_restore (cr);
+}
+
+static void
+goc_graph_update_bounds (GocItem *item)
+{
+	GocGraph *graph = GOC_GRAPH (item);
+	item->x0 = graph->x;
+	item->y0 = graph->y;
+	item->x1 = graph->x + graph->w;
+	item->y1 = graph->y + graph->h;
+	gog_renderer_update (graph->renderer, graph->w, graph->h);
+}
+
+static void
+goc_graph_class_init (GocItemClass *item_klass)
+{
+	GObjectClass *obj_klass = (GObjectClass *) item_klass;
+
+	parent_klass = g_type_class_peek_parent (obj_klass);
+
+	obj_klass->set_property = goc_graph_set_property;
+	obj_klass->get_property = goc_graph_get_property;
+	obj_klass->finalize	    = goc_graph_finalize;
+
+	g_object_class_install_property (obj_klass, GRAPH_PROP_X,
+		g_param_spec_double ("x", 
+			_("x"),
+			_("The graph left position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, GRAPH_PROP_Y,
+		g_param_spec_double ("y", 
+			_("y"),
+			_("The graph top position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, GRAPH_PROP_H,
+		 g_param_spec_double ("height",
+			_("Height"),
+			_("Height"),
+			0, G_MAXDOUBLE, 100.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, GRAPH_PROP_W,
+		 g_param_spec_double ("width",
+			_("Width"),
+			_("Width"),
+			0, G_MAXDOUBLE, 100.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, GRAPH_PROP_GRAPH,
+		g_param_spec_object ("graph",
+			_("Graph"),
+			_("The GogGraph this object displays"),
+			GOG_TYPE_GRAPH,
+			GSF_PARAM_STATIC | G_PARAM_WRITABLE));
+	g_object_class_install_property (obj_klass, GRAPH_PROP_RENDERER,
+		g_param_spec_object ("renderer",
+			_("Renderer"),
+			_("The GogRenderer being displayed"),
+			GOG_TYPE_RENDERER,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+	item_klass->draw = goc_graph_draw;
+	item_klass->update_bounds = goc_graph_update_bounds;
+	item_klass->distance = goc_graph_distance;
+}
+
+GSF_CLASS (GocGraph, goc_graph,
+	   goc_graph_class_init, NULL,
+	   GOC_TYPE_ITEM)
diff --git a/goffice/canvas/goc-graph.h b/goffice/canvas/goc-graph.h
new file mode 100644
index 0000000..dd434af
--- /dev/null
+++ b/goffice/canvas/goc-graph.h
@@ -0,0 +1,37 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-graph.h :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_GRAPH_H
+#define GOC_GRAPH_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_GRAPH	(goc_graph_get_type ())
+#define GOC_GRAPH(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_GRAPH, GocGraph))
+#define GOC_IS_GRAPH(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_GRAPH))
+
+GType goc_graph_get_type (void);
+
+G_END_DECLS
+
+#endif  /* GOC_GRAPH_H */
diff --git a/goffice/canvas/goc-group-impl.h b/goffice/canvas/goc-group-impl.h
new file mode 100644
index 0000000..8f4a3f2
--- /dev/null
+++ b/goffice/canvas/goc-group-impl.h
@@ -0,0 +1,44 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-group-impl.h :  
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_GROUP_IMPL_H
+#define GOC_GROUP_IMPL_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+struct _GocGroup {
+	GocItem			 base;
+
+	double			 x, y;  /* group offset */
+	GList			*children;
+};
+
+typedef struct {
+	GocItemClass	 base;
+
+} GocGroupClass ;
+
+G_END_DECLS
+
+#endif  /* GOC_GROUP_IMPL_H */
diff --git a/goffice/canvas/goc-group.c b/goffice/canvas/goc-group.c
new file mode 100644
index 0000000..d917bff
--- /dev/null
+++ b/goffice/canvas/goc-group.c
@@ -0,0 +1,338 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-group.c :  
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+
+static GObjectClass *parent_klass;
+
+enum {
+	GROUP_PROP_0,
+	GROUP_PROP_X,
+	GROUP_PROP_Y,
+};
+
+static void
+goc_group_set_property (GObject *gobject, guint param_id,
+				    GValue const *value, GParamSpec *pspec)
+{
+	GocGroup *group = GOC_GROUP (gobject);
+
+	switch (param_id) {
+	case GROUP_PROP_X:
+		group->x = g_value_get_double (value);
+		break;
+
+	case GROUP_PROP_Y:
+		group->y = g_value_get_double (value);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+}
+
+static void
+goc_group_get_property (GObject *gobject, guint param_id,
+				    GValue *value, GParamSpec *pspec)
+{
+	GocGroup *group = GOC_GROUP (gobject);
+
+	switch (param_id) {
+	case GROUP_PROP_X:
+		g_value_set_double (value, group->x);
+		break;
+
+	case GROUP_PROP_Y:
+		g_value_set_double (value, group->y);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+}
+
+static void
+goc_group_update_bounds (GocItem *item)
+{
+	GocGroup *group = GOC_GROUP (item);
+	double x0, y0, x1, y1;
+	item->x0 = item->y0 = G_MAXDOUBLE;
+	item->x1 = item->y1 = -G_MAXDOUBLE;
+	if (group->children != NULL) {
+		GList *l = g_list_first (group->children);
+		while (l) {
+			if (l->data) {
+				goc_item_get_bounds (GOC_ITEM (l->data),
+						     &x0, &y0, &x1, &y1);
+				if (x0 < item->x0)
+					item->x0 = x0;
+				if (y0 < item->y0)
+					item->y0 = y0;
+				if (x1 > item->x1)
+					item->x1 = x1;
+				if (y1 > item->y1)
+					item->y1 = y1;
+			}
+			l = g_list_next (l);
+		}
+		item->x0 += group->x;
+		item->y0 += group->y;
+		item->x1 += group->x;
+		item->y1 += group->y;
+	}
+}
+
+static gboolean
+goc_group_draw_region (GocItem const *item, cairo_t *cr,
+		      double x0, double y0,
+		      double x1, double y1)
+{
+	GocGroup *group = GOC_GROUP (item);
+	GList *l = g_list_first (group->children);
+	if (!l)
+		return TRUE;
+	cairo_save (cr);
+	x0 -= group->x;
+	y0 -= group->y;
+	x1 -= group->x;
+	y1 -= group->y;
+	while (l) {
+		double x, y, x_, y_;
+		GocItem *item = GOC_ITEM (l->data);
+		if (!goc_item_is_visible (item)) {
+			l = l->next;
+			continue;
+		}
+		goc_item_get_bounds (item, &x, &y, &x_, &y_);
+		if (x <= x1 && x_ >= x0 && y <= y1 && y_ >= y0) {
+			cairo_set_operator (cr, goc_item_get_operator (item));
+			if (!goc_item_draw_region (item, cr, x0, y0, x1, y1))
+				goc_item_draw (item, cr);
+		}
+		l = g_list_next (l);
+	}
+	cairo_restore (cr);
+	return TRUE;
+}
+
+/* we just need the distance method to know if an event occured on an item
+ so we don't need to know exact distances when they are large enough, to avoid
+ recalculate a lot of complex distnaces and to optimize, everything more than
+ some thershold (in pixels) will be considered at infinite */
+
+#define GOC_THRESHOLD   10 /* 10 pixels should be enough */
+
+static double
+goc_group_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+	GocGroup *group = GOC_GROUP (item);
+	double result = G_MAXDOUBLE, dist;
+	GList *l;
+	GocItem *cur_item;
+	double th = GOC_THRESHOLD / item->canvas->pixels_per_unit;
+	x -= group->x;
+	y -= group->y;
+	for (l = g_list_last (group->children); l; l = g_list_previous (l)) {
+		GocItem *it = GOC_ITEM (l->data);
+		if (!it->visible || it->x0 > x + th || it->x1 < x - th 
+		    || it->y0 > y + th || it->y1 < y - th)
+			continue;
+		dist = goc_item_distance (GOC_ITEM (l->data), x, y, &cur_item);
+		if (dist < result) {
+			*near_item = cur_item;
+			result = dist;
+		}
+		if (result == 0.)
+			break;
+	}
+	return result;
+}
+
+static void
+goc_group_realize (GocItem *item)
+{
+	GocGroup *group = GOC_GROUP (item);
+	GList *l;
+	GocItemClass *klass;
+	for (l = g_list_first (group->children); l; l = g_list_next (l)) {
+		klass = GOC_ITEM_GET_CLASS (l->data);
+		if (klass->realize)
+			klass->realize (GOC_ITEM (l->data));
+	}
+}
+
+static void
+goc_group_unrealize (GocItem *item)
+{
+	GocGroup *group = GOC_GROUP (item);
+	GList *l;
+	GocItemClass *klass;
+	for (l = g_list_first (group->children); l; l = g_list_next (l)) {
+		klass = GOC_ITEM_GET_CLASS (l->data);
+		if (klass->unrealize)
+			klass->unrealize (GOC_ITEM (l->data));
+	}
+}
+
+static void
+goc_group_notify_scrolled (GocItem *item)
+{
+	GocGroup *group = GOC_GROUP (item);
+	GList *l;
+	GocItemClass *klass;
+	for (l = g_list_first (group->children); l; l = g_list_next (l)) {
+		klass = GOC_ITEM_GET_CLASS (l->data);
+		if (klass->notify_scrolled)
+			klass->notify_scrolled (GOC_ITEM (l->data));
+	}
+}
+
+static void
+goc_group_finalize (GObject *obj)
+{
+	GocGroup *group = GOC_GROUP (obj);
+	GList *l = g_list_first (group->children);
+	while (l) {
+		GOC_ITEM (l->data)->parent = NULL;
+		g_object_unref (G_OBJECT (l->data));
+		l = g_list_next (l);
+	}
+	g_list_free (group->children);
+	(parent_klass->finalize) (obj);
+}
+
+static void
+goc_group_class_init (GocItemClass *item_klass)
+{
+	GObjectClass *obj_klass = (GObjectClass*) item_klass;
+	parent_klass = g_type_class_peek_parent (item_klass);
+
+	obj_klass->get_property = goc_group_get_property;
+	obj_klass->set_property = goc_group_set_property;
+	obj_klass->finalize = goc_group_finalize;
+	g_object_class_install_property (obj_klass, GROUP_PROP_X,
+		g_param_spec_double ("x", 
+			_("x"),
+			_("The group horizontal offset"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, GROUP_PROP_Y,
+		g_param_spec_double ("y", 
+			_("y"),
+			_("The group vertical offset"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+	item_klass->draw_region = goc_group_draw_region;
+	item_klass->update_bounds = goc_group_update_bounds;
+	item_klass->distance = goc_group_distance;
+	item_klass->realize = goc_group_realize;
+	item_klass->unrealize = goc_group_unrealize;
+	item_klass->notify_scrolled = goc_group_notify_scrolled;
+}
+
+GSF_CLASS (GocGroup, goc_group,
+	   goc_group_class_init, NULL,
+	   GOC_TYPE_ITEM)
+
+GocGroup*
+goc_group_new (GocGroup *parent)
+{
+	GocGroup *group;
+
+	g_return_val_if_fail (GOC_IS_GROUP (parent), NULL);
+
+	group = GOC_GROUP (g_object_new (GOC_TYPE_GROUP, NULL));
+	g_return_val_if_fail ((group != NULL), NULL);
+
+	goc_group_add_child (parent, GOC_ITEM (group));
+
+	return group;
+}
+
+void
+goc_group_add_child (GocGroup *group, GocItem *item)
+{
+	g_return_if_fail (GOC_IS_GROUP (group));
+	g_return_if_fail (GOC_IS_ITEM (item));
+	if (item->parent == group)
+		return;
+	if (item->parent != NULL)
+		goc_group_remove_child (item->parent, item);
+	group->children = g_list_append (group->children, item);
+	item->parent = group;
+	item->canvas = group->base.canvas;
+	goc_item_parent_changed (item);
+	goc_item_bounds_changed (GOC_ITEM (group));
+}
+
+void
+goc_group_remove_child (GocGroup *group, GocItem *item)
+{
+	g_return_if_fail (GOC_IS_GROUP (group));
+	g_return_if_fail (GOC_IS_ITEM (item));
+	g_return_if_fail (item->parent == group);
+	group->children = g_list_remove (group->children, item);
+	item->parent = NULL;
+	item->canvas = NULL;
+	goc_item_bounds_changed (GOC_ITEM (group));
+}
+
+void
+goc_group_adjust_bounds (GocGroup const *group, double *x0, double *y0, double *x1, double *y1)
+{
+	g_return_if_fail (GOC_IS_GROUP (group));
+	*x0 += group->x;
+	*y0 += group->y;
+	*x1 += group->x;
+	*y1 += group->y;
+}
+
+void
+goc_group_adjust_coords (GocGroup const *group, double *x0, double *y0)
+{
+	GocGroup *parent;
+	g_return_if_fail (GOC_IS_GROUP (group));
+	*x0 += group->x;
+	*y0 += group->y;
+	parent = GOC_ITEM (group)->parent;
+	if (parent)
+		goc_group_adjust_coords (parent, x0, y0);
+}
+
+void goc_group_cairo_transform (GocGroup const *group, cairo_t *cr, double x, double y)
+{
+	GocGroup *parent;
+	g_return_if_fail (GOC_IS_GROUP (group));
+	parent = GOC_ITEM (group)->parent;
+	if (parent)
+		goc_group_cairo_transform (parent, cr, x + group->x, y + group->y);
+	else {
+		GocCanvas *canvas = GOC_ITEM (group)->canvas;
+		cairo_scale (cr, canvas->pixels_per_unit, canvas->pixels_per_unit);
+		cairo_translate (cr, x - canvas->scroll_x1, y - canvas->scroll_y1);
+	}
+}
diff --git a/goffice/canvas/goc-group.h b/goffice/canvas/goc-group.h
new file mode 100644
index 0000000..c227377
--- /dev/null
+++ b/goffice/canvas/goc-group.h
@@ -0,0 +1,45 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-group.h :  
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_GROUP_H
+#define GOC_GROUP_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_GROUP	(goc_group_get_type ())
+#define GOC_GROUP(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_GROUP, GocGroup))
+#define GOC_IS_GROUP(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_GROUP))
+
+GType goc_group_get_type (void);
+
+GocGroup *goc_group_new (GocGroup *parent);
+void goc_group_add_child (GocGroup *parent, GocItem *item);
+void goc_group_remove_child (GocGroup *parent, GocItem *item);
+void goc_group_adjust_bounds (GocGroup const *group, double *x0, double *y0, double *x1, double *y1);
+void goc_group_adjust_coords (GocGroup const *group, double *x0, double *y0);
+void goc_group_cairo_transform (GocGroup const *group, cairo_t *cr, double x, double y);
+
+G_END_DECLS
+
+#endif  /* GOC_GROUP_H */
diff --git a/goffice/canvas/goc-item-impl.h b/goffice/canvas/goc-item-impl.h
new file mode 100644
index 0000000..34ba4ec
--- /dev/null
+++ b/goffice/canvas/goc-item-impl.h
@@ -0,0 +1,70 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-item-impl.h :  
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_ITEM_IMPL_H
+#define GOC_ITEM_IMPL_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+struct _GocItem {
+	GObject			 base;
+
+	GocCanvas		*canvas;
+	GocGroup		*parent;
+	gboolean		 cached_bounds;
+	gboolean		 needs_redraw;
+	gboolean		 visible;
+	double			 x0, y0, x1, y1; /* the bounds */
+};
+
+typedef struct {
+	GObjectClass	 base;
+
+	double			(*distance) (GocItem *item,
+								 double x, double y, GocItem **near_item);
+	void			(*draw) (GocItem const *item, cairo_t *cr);
+	gboolean		(*draw_region) (GocItem const *item, cairo_t *cr,
+									double x0, double y0, double x1, double y1);
+	void			(*move) (GocItem *item, double x, double y);
+	void			(*update_bounds) (GocItem *item);
+	void			(*parent_changed) (GocItem *item);
+	cairo_operator_t
+					(*get_operator) (GocItem *item);
+	// events related functions
+	gboolean		(*button_pressed) (GocItem *item, int button, double x, double y);
+	gboolean		(*button2_pressed) (GocItem *item, int button, double x, double y);
+	gboolean		(*button_released) (GocItem *item, int button, double x, double y);
+	gboolean		(*motion) (GocItem *item, double x, double y);
+	gboolean		(*enter_notify) (GocItem *item, double x, double y);
+	gboolean		(*leave_notify) (GocItem *item, double x, double y);
+	void			(*realize) (GocItem *item);
+	void			(*unrealize) (GocItem *item);
+	gboolean		(*key_pressed) (GocItem *item, GdkEventKey* ev);
+	gboolean		(*key_released) (GocItem *item, GdkEventKey* ev);
+	void			(*notify_scrolled) (GocItem *item);
+} GocItemClass ;
+
+G_END_DECLS
+
+#endif  /* GOC_ITEM_IMPL_H */
diff --git a/goffice/canvas/goc-item.c b/goffice/canvas/goc-item.c
new file mode 100644
index 0000000..dfb7007
--- /dev/null
+++ b/goffice/canvas/goc-item.c
@@ -0,0 +1,357 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-item.c :  
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <gtk/gtk.h>
+#include <gsf/gsf-impl-utils.h>
+
+static GObjectClass *item_parent_class;
+
+static gboolean
+goc_item_button_pressed (GocItem *item, int button, double x, double y)
+{
+	return (item->parent)?
+		GOC_ITEM_GET_CLASS (item->parent)->button_pressed (GOC_ITEM (item->parent), button, x, y):
+		FALSE;
+}
+
+static gboolean
+goc_item_button2_pressed (GocItem *item, int button, double x, double y)
+{
+	return (item->parent)?
+		GOC_ITEM_GET_CLASS (item->parent)->button2_pressed (GOC_ITEM (item->parent), button, x, y):
+		FALSE;
+}
+
+static gboolean
+goc_item_button_released (GocItem *item, int button, double x, double y)
+{
+	return (item->parent)?
+		GOC_ITEM_GET_CLASS (item->parent)->button_released (GOC_ITEM (item->parent), button, x, y):
+		FALSE;
+}
+
+static gboolean
+goc_item_motion (GocItem *item, double x, double y)
+{
+	return (item->parent)?
+		GOC_ITEM_GET_CLASS (item->parent)->motion (GOC_ITEM (item->parent), x, y):
+		FALSE;
+}
+
+static gboolean
+goc_item_enter_notify (GocItem *item, double x, double y)
+{
+	return (item->parent)?
+		GOC_ITEM_GET_CLASS (item->parent)->enter_notify (GOC_ITEM (item->parent), x, y):
+		FALSE;
+}
+
+static gboolean
+goc_item_leave_notify (GocItem *item, double x, double y)
+{
+	return (item->parent)?
+		GOC_ITEM_GET_CLASS (item->parent)->leave_notify (GOC_ITEM (item->parent), x, y):
+		FALSE;
+}
+
+static void
+goc_item_finalize (GObject *object)
+{
+	GocItem *item = GOC_ITEM (object);
+	if (item->canvas->last_item == item)
+		item->canvas->last_item = NULL;
+	if (GTK_WIDGET_REALIZED (item->canvas)) {
+		GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+		if (klass->unrealize)
+			klass->unrealize (item);
+		goc_item_invalidate (item);
+	}
+	if (item->parent != NULL)
+		goc_group_remove_child (item->parent, item);
+	item_parent_class->finalize (object);
+}
+
+static void
+goc_item_class_init (GocItemClass *item_klass)
+{
+	GObjectClass *obj_klass = (GObjectClass *) item_klass;
+	item_parent_class = g_type_class_peek_parent (item_klass);
+
+	item_klass->button_pressed = goc_item_button_pressed;
+	item_klass->button2_pressed = goc_item_button2_pressed;
+	item_klass->button_released = goc_item_button_released;
+	item_klass->motion = goc_item_motion;
+	item_klass->enter_notify = goc_item_enter_notify;
+	item_klass->leave_notify = goc_item_leave_notify;
+
+	obj_klass->finalize = goc_item_finalize;
+}
+
+static void
+goc_item_init (GocItem *item)
+{
+	item->visible = TRUE;
+}
+
+GSF_CLASS (GocItem, goc_item,
+	   goc_item_class_init, goc_item_init,
+	   G_TYPE_OBJECT)
+
+GocItem*
+goc_item_new (GocGroup *group, GType type, const gchar *first_arg_name, ...)
+{
+	GocItem *item;
+	va_list args;
+
+	g_return_val_if_fail (GOC_IS_GROUP (group), NULL);
+
+	item = GOC_ITEM (g_object_new (type, NULL));
+	g_return_val_if_fail ((item != NULL), NULL);
+
+	goc_group_add_child (group, item);
+
+	va_start (args, first_arg_name);
+	g_object_set_valist (G_OBJECT (item), first_arg_name, args);
+	va_end (args);
+
+	if (GTK_WIDGET_REALIZED (item->canvas)) {
+		GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+		if (klass->realize)
+			klass->realize (item);
+	}
+
+	return item;
+}
+
+void
+goc_item_set (GocItem *item, const gchar *first_arg_name, ...)
+{
+	va_list args;
+
+	goc_item_invalidate (item);
+
+	va_start (args, first_arg_name);
+	g_object_set_valist (G_OBJECT (item), first_arg_name, args);
+	va_end (args);
+
+	goc_item_invalidate (item);
+}
+
+double
+goc_item_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+	GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+	g_return_val_if_fail (klass != NULL, G_MAXDOUBLE);
+
+	return (klass->distance)?
+		klass->distance (item, x, y, near_item): G_MAXDOUBLE;
+}
+
+void
+goc_item_draw (GocItem const *item, cairo_t *cr)
+{
+	GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+	g_return_if_fail (klass != NULL);
+
+	if (klass->draw)
+		klass->draw (item, cr);
+}
+
+gboolean
+goc_item_draw_region (GocItem const *item, cairo_t *cr,
+		      double x0, double y0,
+		      double x1, double y1)
+{
+	GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+	g_return_val_if_fail (klass != NULL, FALSE);
+
+	return (klass->draw_region)?
+		klass->draw_region (item, cr, x0, y0, x1, y1): FALSE;
+}
+
+cairo_operator_t
+goc_item_get_operator (GocItem *item)
+{
+	GocItemClass *klass;
+
+	g_return_val_if_fail (GOC_IS_ITEM (item), CAIRO_OPERATOR_OVER);
+	klass = GOC_ITEM_GET_CLASS (item);
+	g_return_val_if_fail (klass != NULL, CAIRO_OPERATOR_OVER);
+
+	return (klass->get_operator)?
+		klass->get_operator (item): CAIRO_OPERATOR_OVER;
+}
+
+void
+goc_item_move (GocItem *item, double x, double y)
+{
+	GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+	g_return_if_fail (klass != NULL);
+
+	if (klass->move)
+		klass->move (item, x, y);
+}
+
+void goc_item_invalidate (GocItem *item)
+{
+	GocGroup const *parent;
+	double x0, y0, x1, y1;
+
+	g_return_if_fail (GOC_IS_ITEM (item));
+	if (!GTK_WIDGET_REALIZED (item->canvas))
+		return;
+
+	parent = item->parent;
+	if (!item->cached_bounds)
+		goc_item_update_bounds (GOC_ITEM (item)); /* don't care about const */
+	x0 = item->x0;
+	y0 = item->y0;
+	x1 = item->x1;
+	y1 = item->y1;
+	while (parent) {
+		goc_group_adjust_bounds (parent, &x0, &y0, &x1, &y1);
+		parent = parent->base.parent;
+	}
+	goc_canvas_invalidate (item->canvas, x0, y0, x1, y1);
+}
+
+void
+goc_item_show (GocItem *item)
+{
+	g_return_if_fail (GOC_IS_ITEM (item));
+	item->visible = TRUE;
+	goc_item_invalidate (item);
+}
+
+void
+goc_item_hide (GocItem *item)
+{
+	g_return_if_fail (GOC_IS_ITEM (item));
+	item->visible = FALSE;
+	goc_item_invalidate (item);
+}
+
+gboolean
+goc_item_is_visible (GocItem *item)
+{
+	g_return_val_if_fail (GOC_IS_ITEM (item), FALSE);
+	return item->visible;
+}
+
+void
+goc_item_get_bounds (GocItem const *item, double *x0, double *y0, double *x1, double *y1)
+{
+	g_return_if_fail (GOC_IS_ITEM (item));
+	if (!item->cached_bounds) {
+		goc_item_update_bounds (GOC_ITEM (item)); /* don't care about const */
+	}
+	*x0 = item->x0;
+	*y0 = item->y0;
+	*x1 = item->x1;
+	*y1 = item->y1;
+}
+
+void
+goc_item_update_bounds (GocItem *item)
+{
+	GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+	g_return_if_fail (klass != NULL);
+
+	if (klass->update_bounds)
+		klass->update_bounds (item);
+	item->cached_bounds = TRUE;
+}
+
+void
+goc_item_bounds_changed (GocItem *item)
+{
+	g_return_if_fail (GOC_IS_ITEM (item));
+	item->cached_bounds = FALSE;
+	if (item->parent)
+		goc_item_bounds_changed (GOC_ITEM (item->parent));
+}
+
+void
+goc_item_parent_changed (GocItem *item)
+{
+	GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+	g_return_if_fail (klass != NULL);
+
+	if (klass->parent_changed)
+		klass->parent_changed (item);
+}
+
+void
+goc_item_grab (GocItem *item)
+{
+	g_return_if_fail (GOC_IS_ITEM (item));
+	goc_canvas_grab_item (item->canvas, item);
+}	
+	
+void
+goc_item_ungrab	(GocItem *item)
+{
+	g_return_if_fail (item == goc_canvas_get_grabbed_item (item->canvas));
+	goc_canvas_ungrab_item (item->canvas);
+}
+
+void
+goc_item_raise (GocItem *item, int n)
+{
+	GList *orig = g_list_find (item->parent->children, item);
+	GList *dest = g_list_nth (orig, n + 1);
+	if (dest)
+		item->parent->children = g_list_insert_before (item->parent->children, dest, item);
+	else
+		item->parent->children = g_list_append (item->parent->children, item);
+	item->parent->children = g_list_remove_link (item->parent->children, orig);
+}
+
+void
+goc_item_lower (GocItem *item, int n)
+{
+	GList *orig = g_list_find (item->parent->children, item);
+	GList *dest = g_list_nth_prev (orig, n);
+	if (dest)
+		item->parent->children = g_list_insert_before (item->parent->children, dest, item);
+	else
+		item->parent->children = g_list_prepend (item->parent->children, item);
+	item->parent->children = g_list_remove_link (item->parent->children, orig);
+}
+
+void
+goc_item_lower_to_bottom (GocItem *item)
+{
+	g_return_if_fail (item->parent != NULL);
+	item->parent->children = g_list_remove (item->parent->children, item);
+	item->parent->children = g_list_prepend (item->parent->children, item);
+}
+
+void
+goc_item_raise_to_top (GocItem *item)
+{
+	g_return_if_fail (item->parent != NULL);
+	item->parent->children = g_list_remove (item->parent->children, item);
+	item->parent->children = g_list_append (item->parent->children, item);
+}
diff --git a/goffice/canvas/goc-item.h b/goffice/canvas/goc-item.h
new file mode 100644
index 0000000..e75cd93
--- /dev/null
+++ b/goffice/canvas/goc-item.h
@@ -0,0 +1,71 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-item.h :  
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_ITEM_H
+#define GOC_ITEM_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_ITEM	(goc_item_get_type ())
+#define GOC_ITEM(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_ITEM, GocItem))
+#define GOC_IS_ITEM(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_ITEM))
+#define GOC_IS_ITEM_CLASS(k)		(G_TYPE_CHECK_CLASS_TYPE ((k), GOC_TYPE_ITEM))
+#define GOC_ITEM_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GOC_TYPE_ITEM, GocItemClass))
+
+GType goc_item_get_type (void);
+
+typedef struct {
+	GTypeInterface		   base;
+
+} GocItemClientClass;
+
+GocItem		*goc_item_new		(GocGroup *parent, GType type, const gchar *first_arg_name, ...);
+void		 goc_item_set		(GocItem *item, const gchar *first_arg_name, ...);
+double		 goc_item_distance	(GocItem *item, double x, double y, GocItem **near_item);
+void		 goc_item_draw		(GocItem const *item, cairo_t *cr);
+gboolean	 goc_item_draw_region	(GocItem const *item, cairo_t *cr,
+									 double x0, double y0, double x1, double y1);
+cairo_operator_t
+			 goc_item_get_operator  (GocItem *item);
+void		 goc_item_move			(GocItem *item, double x, double y);
+
+void		 goc_item_invalidate	(GocItem *item);
+void		 goc_item_show			(GocItem *item);
+void		 goc_item_hide			(GocItem *item);
+gboolean	 goc_item_is_visible	(GocItem *item);
+void		 goc_item_get_bounds	(GocItem const *item,
+									 double *x0, double *y0,
+									 double *x1, double *y1);
+void		 goc_item_update_bounds	(GocItem *item);
+void		 goc_item_bounds_changed (GocItem *item);
+void		 goc_item_parent_changed (GocItem *item);
+void		 goc_item_grab		(GocItem *item);
+void		 goc_item_ungrab	(GocItem *item);
+void		 goc_item_raise		(GocItem *item, int n);
+void		 goc_item_lower		(GocItem *item, int n);
+void		 goc_item_lower_to_bottom (GocItem *item);
+void		 goc_item_raise_to_top	(GocItem *item);
+
+G_END_DECLS
+
+#endif  /* GOC_ITEM_H */
diff --git a/goffice/canvas/goc-line.c b/goffice/canvas/goc-line.c
new file mode 100644
index 0000000..227b8c5
--- /dev/null
+++ b/goffice/canvas/goc-line.c
@@ -0,0 +1,221 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-line.c :  
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <gsf/gsf-impl-utils.h>
+#include <glib/gi18n-lib.h>
+
+enum {
+	LINE_PROP_0,
+	LINE_PROP_X0,
+	LINE_PROP_Y0,
+	LINE_PROP_X1,
+	LINE_PROP_Y1
+};
+
+struct _GocLine {
+	GocStyledItem base;
+
+	/* using these to avoid confusion with x0 and others in GocItem */
+	double startx, starty, endx, endy;
+};
+
+typedef GocStyledItemClass GocLineClass;
+
+static void
+goc_line_set_property (GObject *gobject, guint param_id,
+				    GValue const *value, GParamSpec *pspec)
+{
+	GocLine *line = GOC_LINE (gobject);
+
+	switch (param_id) {
+	case LINE_PROP_X0:
+		line->startx = g_value_get_double (value);
+		break;
+
+	case LINE_PROP_Y0:
+		line->starty = g_value_get_double (value);
+		break;
+
+	case LINE_PROP_X1:
+		line->endx = g_value_get_double (value);
+		break;
+
+	case LINE_PROP_Y1:
+		line->endy = g_value_get_double (value);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+	goc_item_bounds_changed (GOC_ITEM (gobject));
+}
+
+static void
+goc_line_get_property (GObject *gobject, guint param_id,
+				    GValue *value, GParamSpec *pspec)
+{
+	GocLine *line = GOC_LINE (gobject);
+
+	switch (param_id) {
+	case LINE_PROP_X0:
+		g_value_set_double (value, line->startx);
+		break;
+
+	case LINE_PROP_Y0:
+		g_value_set_double (value, line->starty);
+		break;
+
+	case LINE_PROP_X1:
+		g_value_set_double (value, line->endx);
+		break;
+
+	case LINE_PROP_Y1:
+		g_value_set_double (value, line->endy);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+}
+
+static void
+goc_line_update_bounds (GocItem *item)
+{
+	GocLine *line = GOC_LINE (item);
+	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+	/* FIXME: take rotation into account */
+	double extra_width = style->line.width /2.;
+	/* fix me, take ends and orientation into account */
+	if (extra_width <= 0.)
+		extra_width = .5;
+	if (line->startx < line->endx) {
+		item->x0 = line->startx - extra_width;
+		item->x1 = line->endx + extra_width;
+	} else {
+		item->x0 = line->endx - extra_width;
+		item->x1 = line->startx + extra_width;
+	}
+	if (line->starty < line->endy) {
+		item->y0 = line->starty - extra_width;
+		item->y1 = line->endy + extra_width;
+	} else {
+		item->y0 = line->endy - extra_width;
+		item->y1 = line->starty + extra_width;
+	}
+}
+
+static double
+goc_line_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+	GocLine *line = GOC_LINE (item);
+	double dx, dy, l, t;
+	GOStyle *style;
+	dx = line->endx - line->startx;
+	dy = line->endy - line->starty;
+	l = hypot (dx, dy);
+	x -= line->startx;
+	y -= line->starty;
+	t = (x * dx + y * dy) / l;
+	y = (-x * dy + y * dx) / l;
+	*near_item = item;
+	if (t < 0.)
+		return hypot (t, y); /* that might be not fully exact,
+	 but we don't need a large precision */
+	if (t > l)
+		return hypot (t - l, y);
+	style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+	t = y - style->line.width / 2.;
+	return (t > 0.)? t: 0.;
+}
+
+static void goc_line_draw (GocItem const *item, cairo_t *cr)
+{
+	GocLine *line = GOC_LINE (item);
+        if (go_styled_object_set_cairo_line (GO_STYLED_OBJECT (item), cr)) {
+		cairo_save (cr);
+		goc_group_cairo_transform (item->parent, cr, line->startx, line->starty);
+		cairo_move_to (cr, 0., 0.);
+		cairo_line_to (cr, line->endx - line->startx, line->endy - line->starty);
+		cairo_stroke (cr);
+		cairo_restore (cr);
+	}
+}
+
+static void
+goc_line_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
+{
+	style->interesting_fields = GO_STYLE_LINE;
+	if (style->line.auto_dash)
+		style->line.dash_type = GO_LINE_SOLID;
+	if (style->line.auto_color)
+		style->line.color = RGBA_BLACK;
+	if (style->line.auto_fore)
+		style->line.fore  = 0;
+}
+
+static void
+goc_line_class_init (GocItemClass *item_klass)
+{
+	GObjectClass *obj_klass = (GObjectClass *) item_klass;
+	GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+
+	gsi_klass->init_style = goc_line_init_style;
+
+	obj_klass->get_property = goc_line_get_property;
+	obj_klass->set_property = goc_line_set_property;
+	g_object_class_install_property (obj_klass, LINE_PROP_X0,
+		g_param_spec_double ("x0",
+			_("x0"),
+			_("The line start x coordinate"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, LINE_PROP_Y0,
+		g_param_spec_double ("y0",
+			_("y0"),
+			_("The line start y coordinate"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, LINE_PROP_X1,
+		g_param_spec_double ("x1",
+			_("x1"),
+			_("The line end x coordinate"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, LINE_PROP_Y1,
+		g_param_spec_double ("y1",
+			_("y1"),
+			_("The line end y coordinate"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+	item_klass->update_bounds = goc_line_update_bounds;
+	item_klass->distance = goc_line_distance;
+	item_klass->draw = goc_line_draw;
+}
+
+GSF_CLASS (GocLine, goc_line,
+	   goc_line_class_init, NULL,
+	   GOC_TYPE_STYLED_ITEM)
+
+G_END_DECLS
diff --git a/goffice/canvas/goc-line.h b/goffice/canvas/goc-line.h
new file mode 100644
index 0000000..5ededc9
--- /dev/null
+++ b/goffice/canvas/goc-line.h
@@ -0,0 +1,38 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-line.h :  
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_LINE_H
+#define GOC_LINE_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_LINE	(goc_line_get_type ())
+#define GOC_LINE(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_LINE, GocLine))
+#define GOC_IS_LINE(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_LINE))
+
+GType goc_line_get_type (void);
+
+G_END_DECLS
+
+#endif  /* GOC_LINE_H */
diff --git a/goffice/canvas/goc-pixbuf.c b/goffice/canvas/goc-pixbuf.c
new file mode 100644
index 0000000..905881b
--- /dev/null
+++ b/goffice/canvas/goc-pixbuf.c
@@ -0,0 +1,267 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-pixbuf.c:
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <gsf/gsf-impl-utils.h>
+#include <glib/gi18n-lib.h>
+
+enum {
+	PIXBUF_PROP_0,
+	PIXBUF_PROP_X,
+	PIXBUF_PROP_Y,
+	PIXBUF_PROP_W,
+	PIXBUF_PROP_H,
+	PIXBUF_PROP_ROTATION,
+	PIXBUF_PROP_PIXBUF
+};
+
+struct _GocPixbuf {
+	GocItem base;
+
+	double x, y, width, height, rotation;
+	GdkPixbuf *pixbuf;
+};
+
+typedef GocItemClass GocPixbufClass;
+static GocItemClass *parent_class;
+
+static void
+goc_pixbuf_set_property (GObject *gobject, guint param_id,
+				    GValue const *value, GParamSpec *pspec)
+{
+	GocPixbuf *pixbuf = GOC_PIXBUF (gobject);
+
+	switch (param_id) {
+	case PIXBUF_PROP_X:
+		pixbuf->x = g_value_get_double (value);
+		break;
+
+	case PIXBUF_PROP_Y:
+		pixbuf->y = g_value_get_double (value);
+		break;
+
+	case PIXBUF_PROP_W:
+		pixbuf->width = g_value_get_double (value);
+		break;
+
+	case PIXBUF_PROP_H:
+		pixbuf->height = g_value_get_double (value);
+		break;
+
+	case PIXBUF_PROP_ROTATION:
+		pixbuf->rotation = g_value_get_double (value);
+		break;
+
+	case PIXBUF_PROP_PIXBUF:
+		if (pixbuf->pixbuf)
+			g_object_unref (pixbuf);
+		pixbuf->pixbuf = GDK_PIXBUF (g_object_ref (g_value_get_object (value)));
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+	goc_item_bounds_changed (GOC_ITEM (gobject));
+
+}
+
+static void
+goc_pixbuf_get_property (GObject *gobject, guint param_id,
+				    GValue *value, GParamSpec *pspec)
+{
+	GocPixbuf *pixbuf = GOC_PIXBUF (gobject);
+
+	switch (param_id) {
+	case PIXBUF_PROP_X:
+		g_value_set_double (value, pixbuf->x);
+		break;
+
+	case PIXBUF_PROP_Y:
+		g_value_set_double (value, pixbuf->y);
+		break;
+
+	case PIXBUF_PROP_W:
+		g_value_set_double (value, pixbuf->width);
+		break;
+
+	case PIXBUF_PROP_H:
+		g_value_set_double (value, pixbuf->height);
+		break;
+
+	case PIXBUF_PROP_ROTATION:
+		g_value_set_double (value, pixbuf->rotation);
+		break;
+
+	case PIXBUF_PROP_PIXBUF:
+		if (pixbuf->pixbuf)
+			g_value_set_object (value, G_OBJECT (pixbuf->pixbuf));
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+}
+
+static void
+goc_pixbuf_finalize (GObject *gobject)
+{
+	GocPixbuf *pixbuf = GOC_PIXBUF (gobject);
+
+	if (pixbuf->pixbuf)
+		g_object_unref (pixbuf->pixbuf);
+	((GObjectClass *) parent_class)->finalize (gobject);
+}
+
+static void
+goc_pixbuf_update_bounds (GocItem *item)
+{
+	GocPixbuf *pixbuf = GOC_PIXBUF (item);
+	if (!pixbuf->pixbuf)
+		return;
+	/* FIXME: take rotation into account */
+	item->x0 = pixbuf->x;
+	item->y0 = pixbuf->y;
+	item->x1 = pixbuf->x + ((pixbuf->width > 0.)? pixbuf->width: gdk_pixbuf_get_width (pixbuf->pixbuf));
+	item->y1 = pixbuf->y + ((pixbuf->height > 0.)? pixbuf->height: gdk_pixbuf_get_height (pixbuf->pixbuf));
+}
+
+static double
+goc_pixbuf_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+	GocPixbuf *pixbuf = GOC_PIXBUF (item);
+	/* FIXME: take rotation into account */
+	double dx, dy, w, h;
+	if (pixbuf->pixbuf == NULL)
+		return G_MAXDOUBLE;
+	w = (pixbuf->width >= 0.)? pixbuf->width: gdk_pixbuf_get_width (pixbuf->pixbuf);
+	h = (pixbuf->height >= 0.)? pixbuf->height: gdk_pixbuf_get_height (pixbuf->pixbuf);
+	if (x < pixbuf->x) {
+		dx = pixbuf->x - x;
+	} else if (x < pixbuf->x + w) {
+		dx = 0;
+	} else {
+		dx = x - pixbuf->x - w;
+	}
+	if (y < pixbuf->y) {
+		dy = pixbuf->y - y;
+	} else if (y < pixbuf->y + h) {
+		dy = 0;
+	} else {
+		dy = y - pixbuf->y - h;
+	}
+	*near_item = item;
+	return hypot (dx, dy);
+}
+
+static void
+goc_pixbuf_draw (GocItem const *item, cairo_t *cr)
+{
+	GocPixbuf *pixbuf = GOC_PIXBUF (item);
+	GOImage * image;
+	cairo_pattern_t *pat;
+	double height, width;
+	double scalex = 1., scaley = 1.;
+
+	if (pixbuf->pixbuf == NULL)
+		return;
+
+	image = go_image_new_from_pixbuf (pixbuf->pixbuf);
+	pat = go_image_create_cairo_pattern (image);
+	if (pixbuf->width < 0.)
+		width = gdk_pixbuf_get_width (pixbuf->pixbuf);
+	else {
+		width = pixbuf->width;
+		scalex = width / gdk_pixbuf_get_width (pixbuf->pixbuf);
+	}
+	if (pixbuf->height < 0.)
+		height = gdk_pixbuf_get_height (pixbuf->pixbuf);
+	else {
+		height = pixbuf->height;
+		scaley = height / gdk_pixbuf_get_height (pixbuf->pixbuf);
+	}
+	cairo_save (cr);
+	goc_group_cairo_transform (item->parent, cr, pixbuf->x, pixbuf->y);
+	cairo_rotate (cr, pixbuf->rotation);
+	if (scalex != 1. || scaley != 1.)
+		cairo_scale (cr, scalex, scaley);
+	cairo_rectangle (cr, 0., 0., width, height);
+	cairo_set_source (cr, pat);
+	cairo_pattern_destroy (pat);
+        cairo_fill (cr);
+	cairo_restore (cr);
+	g_object_unref (image);
+}
+
+static void
+goc_pixbuf_class_init (GocItemClass *item_klass)
+{
+	GObjectClass *obj_klass = (GObjectClass *) item_klass;
+	parent_class = g_type_class_peek_parent (item_klass);
+
+	obj_klass->finalize = goc_pixbuf_finalize;
+	obj_klass->get_property = goc_pixbuf_get_property;
+	obj_klass->set_property = goc_pixbuf_set_property;
+	g_object_class_install_property (obj_klass, PIXBUF_PROP_X,
+		g_param_spec_double ("x",
+			_("x"),
+			_("The image left position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, PIXBUF_PROP_Y,
+		g_param_spec_double ("y",
+			_("y"),
+			_("The image top position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, PIXBUF_PROP_W,
+		g_param_spec_double ("width", 
+			_("Width"),
+			_("The image width or -1 to use the image width"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, PIXBUF_PROP_H,
+		g_param_spec_double ("height", 
+			_("Height"),
+			_("The image height or -1 to use the image height"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+/*	g_object_class_install_property (obj_klass, PIXBUF_PROP_ROTATION,
+		g_param_spec_double ("rotation", 
+			_("Rotation"),
+			_("The rotation around top left position"),
+			0., 2 * M_PI, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));*/
+	g_object_class_install_property (obj_klass, PIXBUF_PROP_PIXBUF,
+	        g_param_spec_object ("pixbuf", _("Pixbuf"),
+	                 _("The GdkPixbuf to display"),
+	                 GDK_TYPE_PIXBUF,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+	item_klass->update_bounds = goc_pixbuf_update_bounds;
+	item_klass->distance = goc_pixbuf_distance;
+	item_klass->draw = goc_pixbuf_draw;
+}
+
+GSF_CLASS (GocPixbuf, goc_pixbuf,
+	   goc_pixbuf_class_init, NULL,
+	   GOC_TYPE_ITEM)
diff --git a/goffice/canvas/goc-pixbuf.h b/goffice/canvas/goc-pixbuf.h
new file mode 100644
index 0000000..b6d4def
--- /dev/null
+++ b/goffice/canvas/goc-pixbuf.h
@@ -0,0 +1,38 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-pixbuf.h:
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_PIXBUF_H
+#define GOC_PIXBUF_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_PIXBUF	(goc_pixbuf_get_type ())
+#define GOC_PIXBUF(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_PIXBUF, GocPixbuf))
+#define GOC_IS_PIXBUF(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_PIXBUF))
+
+GType goc_pixbuf_get_type (void);
+
+G_END_DECLS
+
+#endif  /* GOC_PIXBUF_H */
diff --git a/goffice/canvas/goc-polygon-impl.h b/goffice/canvas/goc-polygon-impl.h
new file mode 100644
index 0000000..a8d57ff
--- /dev/null
+++ b/goffice/canvas/goc-polygon-impl.h
@@ -0,0 +1,42 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-polygon-impl.h :  
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_POLYGON_IMPL_H
+#define GOC_POLYGON_IMPL_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+typedef GocStyledItemClass GocPolygonClass;
+
+struct _GocPolygon {
+	GocStyledItem base;
+
+	GocPoint *points;
+	unsigned nb_points;
+	gboolean use_spline;
+};
+
+G_END_DECLS
+
+#endif  /* GOC_POLYGON_IMPL_H */
diff --git a/goffice/canvas/goc-polygon.c b/goffice/canvas/goc-polygon.c
new file mode 100644
index 0000000..64ff27b
--- /dev/null
+++ b/goffice/canvas/goc-polygon.c
@@ -0,0 +1,243 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-polygon.c :  
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <gsf/gsf-impl-utils.h>
+#include <glib/gi18n-lib.h>
+
+enum {
+	POLYGON_PROP_0,
+	POLYGON_PROP_POINTS,
+	POLYGON_PROP_SPLINE
+};
+
+static void
+goc_polygon_set_property (GObject *gobject, guint param_id,
+				    GValue const *value, GParamSpec *pspec)
+{
+	GocPolygon *polygon = GOC_POLYGON (gobject);
+
+	switch (param_id) {
+	case POLYGON_PROP_POINTS: {
+		unsigned i;
+		GocPoints *points = (GocPoints *) g_value_get_boxed (value);
+		polygon->nb_points = points->n;
+		if (polygon->points)
+			g_free (polygon->points);
+		polygon->points = g_new (GocPoint, points->n);
+		for (i = 0; i < points->n; i++)
+			polygon->points[i] = points->points[i];
+		break;
+	}
+	case POLYGON_PROP_SPLINE:
+		polygon->use_spline = g_value_get_boolean (value);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+	goc_item_bounds_changed (GOC_ITEM (gobject));
+
+}
+
+static void
+goc_polygon_get_property (GObject *gobject, guint param_id,
+				    GValue *value, GParamSpec *pspec)
+{
+	GocPolygon *polygon = GOC_POLYGON (gobject);
+
+	switch (param_id) {
+	case POLYGON_PROP_POINTS: {
+		unsigned i;
+		GocPoints *points = goc_points_new (polygon->nb_points);
+		for (i = 0; i < points->n; i++)
+			points->points[i] = polygon->points[i];
+		g_value_set_boxed (value, points);
+		goc_points_unref (points);
+		break;
+	}
+	case POLYGON_PROP_SPLINE:
+		g_value_set_boolean (value, polygon->use_spline);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+}
+
+static void
+goc_polygon_update_bounds (GocItem *item)
+{
+	GocPolygon *polygon = GOC_POLYGON (item);
+	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+	double extra_width = style->outline.width;
+	unsigned i;
+	if (extra_width <= 0.)
+		extra_width = 1.;
+	if (polygon->nb_points == 0)
+		return;
+	/* FIXME: implement the use_spline case */
+	item->x0 = item->x1 = polygon->points[0].x;
+	item->y0 = item->y1 = polygon->points[0].y;
+	for (i = 1; i < polygon->nb_points; i++) {
+		if (polygon->points[i].x < item->x0)
+			item->x0 = polygon->points[i].x;
+		else if (polygon->points[i].x > item->x1)
+			item->x1 = polygon->points[i].x;
+		if (polygon->points[i].y < item->y0)
+			item->y0 = polygon->points[i].y;
+		else if (polygon->points[i].y > item->y1)
+			item->y1 = polygon->points[i].y;
+	}
+	item->x0 -= extra_width;
+	item->y0 -= extra_width;
+	item->x1 -= extra_width;
+	item->y1 -= extra_width;
+}
+
+static double
+goc_polygon_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+	GocPolygon *polygon = GOC_POLYGON (item);
+	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+	/* FIXME: implement the use_spline case */
+	double extra_width = (style->outline.width)? style->outline.width /2.: .5;
+	double dx, dy, l, startx, starty, x_, y_, t, res = 0.;
+	int i, n;
+
+	*near_item = item;
+	/* FIXME: not tested!!! */
+	/* first test if the point is inside the polygon */
+	startx = atan2 (polygon->points[0].y - y, polygon->points[0].x - x);
+	for (i = polygon->nb_points - 1; i >= 0; i--) {
+		starty = atan2 (polygon->points[i].y - y, polygon->points[i].x - x);
+		startx -= starty;
+		if (startx > M_PI)
+			startx -= 2 * M_PI;
+		else if (startx < -M_PI)
+			startx += 2 * M_PI;
+		else if (startx == M_PI)
+			return 0.; /* the point is on the edge */
+		res += startx;
+		startx = starty;
+	}
+	n = res / 2. / M_PI;
+	if (n % 1)
+		return 0.; /* only odd-even fillinig supported for now */
+	startx = polygon->points[0].x;
+	starty = polygon->points[0].y;
+	res = G_MAXDOUBLE;
+	for (i = polygon->nb_points - 1; i >= 0; i--) {
+		dx = polygon->points[i].x - startx;
+		dy = polygon->points[i].y - starty;
+		l = hypot (dx, dy);
+		x_ = x - startx;
+		y_ = y - starty;
+		t = (x_ * dx + y_ * dy) / l;
+		y = (-x_ * dy + y_ * dx) / l;
+		x_ = t;
+		*near_item = item;
+		if (x < 0. ) {
+			t = hypot (x_, y_);
+			if (t < res)
+				res = t;
+		} else if (t <= l) {
+			if (y_ < res)
+				res = y_;
+		}
+		startx = polygon->points[i].x;
+		starty = polygon->points[i].y;
+	}
+	res -= extra_width; /* no need to be more precise */
+	return (res > 0.)? res: 0.;
+}
+
+static void
+goc_polygon_draw (GocItem const *item, cairo_t *cr)
+{
+	GocPolygon *polygon = GOC_POLYGON (item);
+	unsigned i;
+	if (polygon->nb_points == 0)
+		return;
+	cairo_save (cr);
+	goc_group_cairo_transform (item->parent, cr, polygon->points[0].x, polygon->points[0].y);
+        cairo_move_to (cr, 0., 0.);
+	/* FIXME: implement the use_spline case */
+
+	for (i = 1; i < polygon->nb_points; i++)
+		cairo_line_to (cr, polygon->points[i].x - polygon->points[0].x,
+		               polygon->points[i].y - polygon->points[0].y);
+	cairo_close_path (cr);
+
+	if (go_styled_object_set_cairo_fill (GO_STYLED_OBJECT (item), cr))
+		cairo_fill_preserve (cr);
+
+	if (go_styled_object_set_cairo_line (GO_STYLED_OBJECT (item), cr))
+		cairo_stroke (cr);
+	else
+		cairo_new_path (cr);
+	cairo_restore (cr);
+}
+
+static void
+goc_polygon_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
+{
+	style->interesting_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL;
+	if (style->outline.auto_dash)
+		style->outline.dash_type = GO_LINE_SOLID;
+	if (style->outline.auto_color)
+		style->outline.color = RGBA_BLACK;
+	if (style->fill.auto_type)
+		style->fill.type  = GO_STYLE_FILL_PATTERN;
+	if (style->fill.auto_fore)
+		go_pattern_set_solid (&style->fill.pattern, RGBA_WHITE);
+}
+
+static void
+goc_polygon_class_init (GocItemClass *item_klass)
+{
+	GObjectClass *obj_klass = (GObjectClass *) item_klass;
+	GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+
+	gsi_klass->init_style = goc_polygon_init_style;
+
+	obj_klass->get_property = goc_polygon_get_property;
+	obj_klass->set_property = goc_polygon_set_property;
+        g_object_class_install_property (obj_klass, POLYGON_PROP_POINTS,
+                 g_param_spec_boxed ("points", _("points"), _("The polygon vertices"),
+				     GOC_TYPE_POINTS,
+				     GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, POLYGON_PROP_SPLINE,
+		g_param_spec_boolean ("use-spline", 
+				      _("Use spline"),
+				      _("Use a Bezier closed cubic spline as contour"),
+				      FALSE, 
+				      GSF_PARAM_STATIC | G_PARAM_READABLE));
+
+	item_klass->update_bounds = goc_polygon_update_bounds;
+	item_klass->distance = goc_polygon_distance;
+	item_klass->draw = goc_polygon_draw;
+}
+
+GSF_CLASS (GocPolygon, goc_polygon,
+	   goc_polygon_class_init, NULL,
+	   GOC_TYPE_STYLED_ITEM)
diff --git a/goffice/canvas/goc-polygon.h b/goffice/canvas/goc-polygon.h
new file mode 100644
index 0000000..5b4b435
--- /dev/null
+++ b/goffice/canvas/goc-polygon.h
@@ -0,0 +1,38 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-polygon.h :  
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_POLYGON_H
+#define GOC_POLYGON_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_POLYGON	(goc_polygon_get_type ())
+#define GOC_POLYGON(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_POLYGON, GocPolygon))
+#define GOC_IS_POLYGON(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_POLYGON))
+
+GType goc_polygon_get_type (void);
+
+G_END_DECLS
+
+#endif  /* GOC_POLYGON_H */
diff --git a/goffice/canvas/goc-rectangle-impl.h b/goffice/canvas/goc-rectangle-impl.h
new file mode 100644
index 0000000..a716e60
--- /dev/null
+++ b/goffice/canvas/goc-rectangle-impl.h
@@ -0,0 +1,40 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-rectangle-impl.h :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_RECTANGLE_IMPL_H
+#define GOC_RECTANGLE_IMPL_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+struct _GocRectangle {
+	GocStyledItem base;
+
+	double rotation; /* rotation around the center in radians */
+	double x, y, width, height;
+};
+
+typedef GocStyledItemClass GocRectangleClass;
+
+G_END_DECLS
+
+#endif  /* GOC_RECTANGLE_IMPL_H */
\ No newline at end of file
diff --git a/goffice/canvas/goc-rectangle.c b/goffice/canvas/goc-rectangle.c
new file mode 100644
index 0000000..fce6d1f
--- /dev/null
+++ b/goffice/canvas/goc-rectangle.c
@@ -0,0 +1,235 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-rectangle.c:
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+
+enum {
+	RECT_PROP_0,
+	RECT_PROP_X,
+	RECT_PROP_Y,
+	RECT_PROP_W,
+	RECT_PROP_H,
+	RECT_PROP_ROTATION
+};
+
+static void
+goc_rectangle_set_property (GObject *gobject, guint param_id,
+				    GValue const *value, GParamSpec *pspec)
+{
+	GocRectangle *rect = GOC_RECTANGLE (gobject);
+
+	switch (param_id) {
+	case RECT_PROP_X:
+		rect->x = g_value_get_double (value);
+		break;
+
+	case RECT_PROP_Y:
+		rect->y = g_value_get_double (value);
+		break;
+
+	case RECT_PROP_W:
+		rect->width = g_value_get_double (value);
+		break;
+
+	case RECT_PROP_H:
+		rect->height = g_value_get_double (value);
+		break;
+
+	case RECT_PROP_ROTATION:
+		rect->rotation = g_value_get_double (value);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+	goc_item_bounds_changed (GOC_ITEM (gobject));
+
+}
+
+static void
+goc_rectangle_get_property (GObject *gobject, guint param_id,
+				    GValue *value, GParamSpec *pspec)
+{
+	GocRectangle *rect = GOC_RECTANGLE (gobject);
+
+	switch (param_id) {
+	case RECT_PROP_X:
+		g_value_set_double (value, rect->x);
+		break;
+
+	case RECT_PROP_Y:
+		g_value_set_double (value, rect->y);
+		break;
+
+	case RECT_PROP_W:
+		g_value_set_double (value, rect->width);
+		break;
+
+	case RECT_PROP_H:
+		g_value_set_double (value, rect->height);
+		break;
+
+	case RECT_PROP_ROTATION:
+		g_value_set_double (value, rect->rotation);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+}
+
+static void
+goc_rectangle_update_bounds (GocItem *item)
+{
+	GocRectangle *rect = GOC_RECTANGLE (item);
+	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+	/* FIXME: take rotation into account */
+	double extra_width = style->outline.width /2.;
+	if (extra_width <= 0.)
+		extra_width = .5;
+	item->x0 = rect->x - extra_width;
+	item->y0 = rect->y - extra_width;
+	item->x1 = rect->x + rect->width + extra_width;
+	item->y1 = rect->y + rect->height + extra_width;
+}
+
+static double
+goc_rectangle_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+	GocRectangle *rect = GOC_RECTANGLE (item);
+	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+	/* FIXME: take rotation into account */
+	double extra_width = (style->outline.width)? style->outline.width /2.: .5;
+	double dx, dy;
+	if (x < rect->x - extra_width) {
+		dx = rect->x - extra_width - x;
+	} else if (x < rect->x + rect->width + extra_width) {
+		dx = 0;
+	} else {
+		dx = x - extra_width - rect->x - rect->width;
+	}
+	if (y < rect->y - extra_width) {
+		dy = rect->y - extra_width - y;
+	} else if (y < rect->y + rect->height + extra_width) {
+		dy = 0;
+	} else {
+		dy = y - extra_width - rect->y - rect->height;
+	}
+	*near_item = item;
+	return hypot (dx, dy);
+}
+
+static void
+goc_rectangle_draw (GocItem const *item, cairo_t *cr)
+{
+	GocRectangle *rect = GOC_RECTANGLE (item);
+	cairo_pattern_t *pat = NULL;
+	GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+
+	cairo_save (cr);
+	goc_group_cairo_transform (item->parent, cr, rect->x, rect->y);
+	cairo_rotate (cr, rect->rotation);
+	cairo_rectangle (cr, 0., 0., rect->width, rect->height);
+	cairo_restore (cr);
+	/* Fill the shape */
+	pat = go_style_create_cairo_pattern (style, cr);
+	if (pat) {
+		cairo_set_source (cr, pat);
+		if (style->outline.dash_type != GO_LINE_NONE)
+			cairo_fill_preserve (cr);
+		else
+			cairo_fill (cr);
+		cairo_pattern_destroy (pat);
+	}
+	/* Draw the line */
+	if (go_styled_object_set_cairo_line (GO_STYLED_OBJECT (item), cr))
+		cairo_stroke (cr);
+	else
+		cairo_new_path (cr);
+}
+
+static void
+goc_rectangle_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
+{
+	style->interesting_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL;
+	if (style->outline.auto_dash)
+		style->outline.dash_type = GO_LINE_SOLID;
+	if (style->outline.auto_color)
+		style->outline.color = RGBA_BLACK;
+	if (style->fill.auto_type)
+		style->fill.type  = GO_STYLE_FILL_PATTERN;
+	if (style->fill.auto_fore)
+		go_pattern_set_solid (&style->fill.pattern, RGBA_WHITE);
+}
+
+static void
+goc_rectangle_class_init (GocItemClass *item_klass)
+{
+	GObjectClass *obj_klass = (GObjectClass *) item_klass;
+	GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+
+	obj_klass->get_property = goc_rectangle_get_property;
+	obj_klass->set_property = goc_rectangle_set_property;
+	g_object_class_install_property (obj_klass, RECT_PROP_X,
+		g_param_spec_double ("x",
+			_("x"),
+			_("The rectangle left position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, RECT_PROP_Y,
+		g_param_spec_double ("y",
+			_("y"),
+			_("The rectangle top position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, RECT_PROP_W,
+		g_param_spec_double ("width", 
+			_("Width"),
+			_("The rectangle width"),
+			0., G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, RECT_PROP_H,
+		g_param_spec_double ("height", 
+			_("Height"),
+			_("The rectangle height"),
+			0., G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+/*	g_object_class_install_property (obj_klass, RECT_PROP_ROTATION,
+		g_param_spec_double ("rotation", 
+			_("Rotation"),
+			_("The rotation around top left position"),
+			0., 2 * M_PI, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));*/
+
+	gsi_klass->init_style = goc_rectangle_init_style;
+
+	item_klass->update_bounds = goc_rectangle_update_bounds;
+	item_klass->distance = goc_rectangle_distance;
+	item_klass->draw = goc_rectangle_draw;
+}
+
+GSF_CLASS (GocRectangle, goc_rectangle,
+	   goc_rectangle_class_init, NULL,
+	   GOC_TYPE_STYLED_ITEM)
diff --git a/goffice/canvas/goc-rectangle.h b/goffice/canvas/goc-rectangle.h
new file mode 100644
index 0000000..725ba61
--- /dev/null
+++ b/goffice/canvas/goc-rectangle.h
@@ -0,0 +1,38 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-rectangle.h :  
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_RECTANGLE_H
+#define GOC_RECTANGLE_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_RECTANGLE	(goc_rectangle_get_type ())
+#define GOC_RECTANGLE(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_RECTANGLE, GocRectangle))
+#define GOC_IS_RECTANGLE(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_RECTANGLE))
+
+GType goc_rectangle_get_type (void);
+
+G_END_DECLS
+
+#endif  /* GOC_RECTANGLE_H */
diff --git a/goffice/canvas/goc-structs.h b/goffice/canvas/goc-structs.h
new file mode 100644
index 0000000..0a594c0
--- /dev/null
+++ b/goffice/canvas/goc-structs.h
@@ -0,0 +1,34 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-structs.h :  
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_STRUCTS_H
+#define GOC_STRUCTS_H
+
+typedef struct {
+	double x, y;
+} GocPoint;
+
+typedef struct {
+	double x, y;
+	double width, height;
+} GocRect;
+
+#endif  /* GOC_STRUCTS_H */
\ No newline at end of file
diff --git a/goffice/canvas/goc-styled-item.c b/goffice/canvas/goc-styled-item.c
new file mode 100644
index 0000000..8a7ac9e
--- /dev/null
+++ b/goffice/canvas/goc-styled-item.c
@@ -0,0 +1,219 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-styled-item.c :  
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+#include <string.h>
+
+enum {
+	STYLED_ITEM_PROP_0,
+	STYLED_ITEM_PROP_STYLE
+};
+
+enum {
+	STYLE_CHANGED,
+	LAST_SIGNAL
+};
+
+static void goc_styled_item_style_changed (GOStyledObject *obj);
+	
+static gulong goc_styled_item_signals [LAST_SIGNAL] = { 0, };
+static GObjectClass *parent_klass;
+
+static void
+goc_styled_item_set_property (GObject *obj, guint param_id,
+				GValue const *value, GParamSpec *pspec)
+{
+	GocStyledItem *gsi = GOC_STYLED_ITEM (obj);
+	gboolean resize = FALSE;
+
+	switch (param_id) {
+
+	case STYLED_ITEM_PROP_STYLE :
+		resize = go_styled_object_set_style (GO_STYLED_OBJECT (gsi), 
+	      			g_value_get_object (value));
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+		 return; /* NOTE : RETURN */
+	}
+	goc_item_invalidate (GOC_ITEM (obj));
+}
+
+static void
+goc_styled_item_get_property (GObject *obj, guint param_id,
+				GValue *value, GParamSpec *pspec)
+{
+	GocStyledItem *gsi = GOC_STYLED_ITEM (obj);
+
+	switch (param_id) {
+	case STYLED_ITEM_PROP_STYLE :
+		g_value_set_object (value, gsi->style);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+		 break;
+	}
+}
+
+static void
+goc_styled_item_finalize (GObject *obj)
+{
+	GocStyledItem *gsi = GOC_STYLED_ITEM (obj);
+
+	if (gsi->style != NULL) {
+		g_object_unref (gsi->style);
+		gsi->style = NULL;
+	}
+
+	(*parent_klass->finalize) (obj);
+}
+
+static void
+goc_styled_item_parent_changed (GocItem *item)
+{
+	GocStyledItem *gsi = GOC_STYLED_ITEM (item);
+	go_styled_object_apply_theme (GO_STYLED_OBJECT (gsi), gsi->style);
+}
+
+static void
+goc_styled_item_init_style (GocStyledItem *gsi, GOStyle *style)
+{
+	style->interesting_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL; /* default */
+}
+
+static void
+goc_styled_item_class_init (GocItemClass *goc_klass)
+{
+	GObjectClass *gobject_klass = (GObjectClass *) goc_klass;
+	GocStyledItemClass *style_klass = (GocStyledItemClass *) goc_klass;
+
+	goc_styled_item_signals [STYLE_CHANGED] = g_signal_new ("style-changed",
+		G_TYPE_FROM_CLASS (goc_klass),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (GocStyledItemClass, style_changed),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__OBJECT,
+		G_TYPE_NONE,
+		1, G_TYPE_OBJECT);
+
+	parent_klass = g_type_class_peek_parent (goc_klass);
+
+	gobject_klass->set_property = goc_styled_item_set_property;
+	gobject_klass->get_property = goc_styled_item_get_property;
+	gobject_klass->finalize	    = goc_styled_item_finalize;
+	goc_klass->parent_changed   = goc_styled_item_parent_changed;
+	style_klass->init_style	    = goc_styled_item_init_style;
+
+	g_object_class_install_property (gobject_klass, STYLED_ITEM_PROP_STYLE,
+		g_param_spec_object ("style", 
+			_("Style"),
+			_("A pointer to the GOStyle object"),
+			go_style_get_type (), 
+			GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+}
+
+static void
+goc_styled_item_init (GocStyledItem *gsi)
+{
+	gsi->style = GO_STYLE (g_object_new (go_style_get_type (), NULL)); /* use the defaults */
+}
+
+static gboolean
+goc_styled_item_set_style (GOStyledObject *gsi,
+			     GOStyle *style)
+{
+	gboolean resize;
+	GocStyledItem *ggsi;
+
+	g_return_val_if_fail (GO_IS_STYLED_OBJECT (gsi), FALSE);
+	ggsi = GOC_STYLED_ITEM (gsi);
+	if (ggsi->style == style)
+		return FALSE;
+	style = go_style_dup (style);
+
+	/* which fields are we interested in for this object */
+	go_styled_object_apply_theme (gsi, style);
+	resize = go_style_is_different_size (ggsi->style, style);
+	if (ggsi->style != NULL)
+		g_object_unref (ggsi->style);
+	ggsi->style = style;
+	go_styled_object_style_changed (gsi);
+
+	return resize;
+}
+
+static GOStyle *
+goc_styled_item_get_style (GOStyledObject *gsi)
+{
+	g_return_val_if_fail (GO_IS_STYLED_OBJECT (gsi), NULL);
+	return GOC_STYLED_ITEM (gsi)->style;
+}
+
+static GOStyle *
+goc_styled_item_get_auto_style (GOStyledObject *gsi)
+{
+	GOStyle *res = go_style_dup (GOC_STYLED_ITEM (gsi)->style);
+	go_style_force_auto (res);
+	go_styled_object_apply_theme (gsi, res);
+	return res;
+}
+
+static void
+goc_styled_item_apply_theme (GOStyledObject *gsi, GOStyle *style)
+{
+	/* FIXME: do we need themes? */
+	GocStyledItemClass *klass = GOC_STYLED_ITEM_GET_CLASS (gsi);
+	(klass->init_style) (GOC_STYLED_ITEM (gsi), style);
+}
+
+static void
+goc_styled_item_style_changed (GOStyledObject *gsi)
+{
+	g_signal_emit (G_OBJECT (gsi),
+		goc_styled_item_signals [STYLE_CHANGED], 0, GOC_STYLED_ITEM (gsi)->style);
+}
+
+static GODoc*
+goc_styled_item_get_document (GOStyledObject *gsi)
+{
+	return goc_canvas_get_document (GOC_ITEM (gsi)->canvas);
+}
+
+static void
+goc_styled_item_so_init (GOStyledObjectClass *iface)
+{
+	iface->set_style = goc_styled_item_set_style;
+	iface->get_style = goc_styled_item_get_style;
+	iface->get_auto_style = goc_styled_item_get_auto_style;
+	iface->style_changed = goc_styled_item_style_changed;
+	iface->apply_theme = goc_styled_item_apply_theme;
+	iface->get_document = goc_styled_item_get_document;
+}
+
+GSF_CLASS_FULL (GocStyledItem, goc_styled_item, NULL, NULL,
+	   goc_styled_item_class_init, NULL, goc_styled_item_init,
+	   GOC_TYPE_ITEM, 0,
+	   GSF_INTERFACE (goc_styled_item_so_init, GO_TYPE_STYLED_OBJECT))
diff --git a/goffice/canvas/goc-styled-item.h b/goffice/canvas/goc-styled-item.h
new file mode 100644
index 0000000..45d4276
--- /dev/null
+++ b/goffice/canvas/goc-styled-item.h
@@ -0,0 +1,55 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-styled-item.h :  
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_STYLED_ITEM_H
+#define GOC_STYLED_ITEM_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+struct _GocStyledItem {
+	GocItem	base;
+
+	GOStyle	*style;
+};
+
+typedef struct {
+	GocItemClass base;
+
+	/* virtual */
+	void	  (*init_style)     	(GocStyledItem *item, GOStyle *style);
+
+	/* signal */
+	void (*style_changed) (GocStyledItem *item, GOStyle const *new_style);
+} GocStyledItemClass;
+
+#define GOC_TYPE_STYLED_ITEM	(goc_styled_item_get_type ())
+#define GOC_STYLED_ITEM(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_STYLED_ITEM, GocStyledItem))
+#define GOC_IS_STYLED_ITEM(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_STYLED_ITEM))
+#define GOC_STYLED_ITEM_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GOC_TYPE_STYLED_ITEM, GocStyledItemClass))
+
+GType     goc_styled_item_get_type (void);
+
+G_END_DECLS
+
+#endif  /* GOC_STYLED_ITEM_H */
diff --git a/goffice/canvas/goc-text.c b/goffice/canvas/goc-text.c
new file mode 100644
index 0000000..ef61e1d
--- /dev/null
+++ b/goffice/canvas/goc-text.c
@@ -0,0 +1,370 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-text.c:
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <gsf/gsf-impl-utils.h>
+#include <glib/gi18n-lib.h>
+
+enum {
+	TEXT_PROP_0,
+	TEXT_PROP_X,
+	TEXT_PROP_Y,
+	TEXT_PROP_ROTATION,
+	TEXT_PROP_ANCHOR,
+	TEXT_PROP_TEXT,
+	TEXT_PROP_ATTRIBUTES
+};
+
+struct _GocText {
+	GocStyledItem base;
+
+	double rotation; /* rotation around the center in radians */
+	double x, y, w, h;
+	char *text;
+	GtkAnchorType anchor;
+	PangoAttrList *attributes;
+	PangoLayout *layout;
+};
+
+typedef GocStyledItemClass GocTextClass;
+static GocItemClass *parent_class;
+
+static void
+goc_text_set_property (GObject *gobject, guint param_id,
+				    GValue const *value, GParamSpec *pspec)
+{
+	GocText *text = GOC_TEXT (gobject);
+
+	switch (param_id) {
+	case TEXT_PROP_X:
+		text->x = g_value_get_double (value);
+		break;
+
+	case TEXT_PROP_Y:
+		text->y = g_value_get_double (value);
+		break;
+
+	case TEXT_PROP_ROTATION:
+		text->rotation = g_value_get_double (value);
+		break;
+
+	case TEXT_PROP_ANCHOR:
+		text->anchor =  (GtkAnchorType) g_value_get_enum (value);
+		break;
+
+	case TEXT_PROP_TEXT:
+		g_free (text->text);
+		text->text = g_value_dup_string (value);
+		if (text->layout)
+			pango_layout_set_text (text->layout, text->text, -1);
+		break;
+
+	case TEXT_PROP_ATTRIBUTES: {
+		PangoAttrList *attrs = (PangoAttrList *) g_value_get_boxed (value);
+		if (text->attributes)
+			pango_attr_list_unref (text->attributes);
+		text->attributes = (attrs)? pango_attr_list_copy (attrs): pango_attr_list_new ();
+		if (text->layout)
+			pango_layout_set_attributes (text->layout, text->attributes);
+		break;
+	}
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+	goc_item_bounds_changed (GOC_ITEM (gobject));
+
+}
+
+static void
+goc_text_get_property (GObject *gobject, guint param_id,
+				    GValue *value, GParamSpec *pspec)
+{
+	GocText *text = GOC_TEXT (gobject);
+
+	switch (param_id) {
+	case TEXT_PROP_X:
+		g_value_set_double (value, text->x);
+		break;
+
+	case TEXT_PROP_Y:
+		g_value_set_double (value, text->y);
+		break;
+
+	case TEXT_PROP_ROTATION:
+		g_value_set_double (value, text->rotation);
+		break;
+
+	case TEXT_PROP_ANCHOR:
+		g_value_set_enum (value, text->anchor);
+		break;
+
+	case TEXT_PROP_TEXT:
+		if (text->text)
+			g_value_set_string (value, text->text);
+		break;
+
+	case TEXT_PROP_ATTRIBUTES:
+		if (text->attributes)
+			g_value_set_boxed (value, text->attributes);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+}
+
+static void
+goc_text_realize (GocItem *item)
+{
+	GocText *text = GOC_TEXT (item);
+
+	if (parent_class->realize)
+		(*parent_class->realize) (item);
+
+	text->layout = pango_layout_new (gtk_widget_get_pango_context (GTK_WIDGET (item->canvas)));
+	pango_layout_set_text (text->layout, text->text, -1);
+	if (text->attributes)
+		pango_layout_set_attributes (text->layout, text->attributes);
+	goc_item_bounds_changed (item);
+}
+
+static void
+goc_text_unrealize (GocItem *item)
+{
+	GocText *text = GOC_TEXT (item);
+
+	if (text->layout)
+		g_object_unref (text->layout);
+	text->layout = NULL;
+
+	if (parent_class->unrealize)
+		(*parent_class->unrealize) (item);
+}
+
+static void
+goc_text_finalize (GObject *gobject)
+{
+	GocText *text = GOC_TEXT (gobject);
+
+	g_free (text->text);
+	if (text->attributes)
+		pango_attr_list_unref (text->attributes);
+	((GObjectClass *) parent_class)->finalize (gobject);
+}
+
+static void
+goc_text_update_bounds (GocItem *item)
+{
+	GocText *text = GOC_TEXT (item);
+	PangoRectangle rect;
+	if (!text->layout)
+		return;
+	pango_layout_get_extents (text->layout, NULL, &rect);
+	text->w = (double) rect.width / PANGO_SCALE;
+	text->h = (double) rect.height / PANGO_SCALE;
+	item->x0 = text->x;
+	item->y0 = text->y;
+	/* adjust horizontally */
+	switch (text->anchor) {
+	case GTK_ANCHOR_CENTER:
+	case GTK_ANCHOR_NORTH:
+	case GTK_ANCHOR_SOUTH:
+		item->x0 -= text->w / 2.;
+		break;
+	case GTK_ANCHOR_NORTH_WEST:
+	case GTK_ANCHOR_SOUTH_WEST:
+	case GTK_ANCHOR_WEST:
+		break;
+	case GTK_ANCHOR_NORTH_EAST:
+	case GTK_ANCHOR_SOUTH_EAST:
+	case GTK_ANCHOR_EAST:
+		item->x0 -= text->w;
+		break;
+	default: /* should not occur */
+		break;
+	}
+	/* adjust vertically */
+	switch (text->anchor) {
+	case GTK_ANCHOR_NORTH:
+	case GTK_ANCHOR_NORTH_WEST:
+	case GTK_ANCHOR_NORTH_EAST:
+		break;
+	case GTK_ANCHOR_CENTER:
+	case GTK_ANCHOR_WEST:
+	case GTK_ANCHOR_EAST:
+		item->y0 -= text->h / 2.;
+		break;
+	case GTK_ANCHOR_SOUTH:
+	case GTK_ANCHOR_SOUTH_WEST:
+	case GTK_ANCHOR_SOUTH_EAST:
+		item->y0 -= text->h;
+		break;
+	default: /* should not occur */
+		break;
+	}
+	item->x1 = item->x0 + text->w;
+	item->y1 = item->y0 + text->h;
+	/* FIXME: take rotation into account */
+}
+
+static double
+goc_text_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+	/* FIXME: take rotation into account */
+	double dx, dy;
+	if (x < item->x0)
+		dx = item->x0 - x;
+	else if (x > item->x1)
+		dx = item->x1 - x;
+	else
+		dx = 0.;
+	if (y < item->y0)
+		dy = item->y0 - y;
+	else if (y > item->y1)
+		dy = item->y1 - y;
+	else
+		dy = 0.;
+	*near_item = item;
+	return hypot (dx, dy);
+}
+
+static void
+goc_text_draw (GocItem const *item, cairo_t *cr)
+{
+	GocText *text = GOC_TEXT (item);
+	double x = text->x, y = text->y;
+	PangoLayout *pl = pango_cairo_create_layout (cr);
+	pango_layout_set_text (pl, text->text, -1);
+	if (text->attributes)
+		pango_layout_set_attributes (pl, text->attributes);
+	/* FIXME: take rotation into account */
+	/* adjust horizontally */
+	switch (text->anchor) {
+	case GTK_ANCHOR_CENTER:
+	case GTK_ANCHOR_NORTH:
+	case GTK_ANCHOR_SOUTH:
+		x -= text->w / 2.;
+		break;
+	case GTK_ANCHOR_NORTH_WEST:
+	case GTK_ANCHOR_SOUTH_WEST:
+	case GTK_ANCHOR_WEST:
+		break;
+	case GTK_ANCHOR_NORTH_EAST:
+	case GTK_ANCHOR_SOUTH_EAST:
+	case GTK_ANCHOR_EAST:
+		x -= text->w;
+		break;
+	default: /* should not occur */
+		break;
+	}
+	/* adjust vertically */
+	switch (text->anchor) {
+	case GTK_ANCHOR_NORTH:
+	case GTK_ANCHOR_NORTH_WEST:
+	case GTK_ANCHOR_NORTH_EAST:
+		break;
+	case GTK_ANCHOR_CENTER:
+	case GTK_ANCHOR_WEST:
+	case GTK_ANCHOR_EAST:
+		y -= text->h / 2.;
+		break;
+	case GTK_ANCHOR_SOUTH:
+	case GTK_ANCHOR_SOUTH_WEST:
+	case GTK_ANCHOR_SOUTH_EAST:
+		y -= text->h;
+		break;
+	default: /* should not occur */
+		break;
+	}
+	cairo_save (cr);
+	goc_group_cairo_transform (item->parent, cr, x, y);
+	cairo_move_to (cr, 0., 0.);
+	pango_cairo_show_layout (cr, pl);
+	cairo_restore (cr);
+	g_object_unref (pl);
+}
+
+static void
+goc_text_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
+{
+	style->interesting_fields = GO_STYLE_FONT;
+	/* we might add more to display some extra decoration
+	  without using a separate rectangle item */
+}
+
+static void
+goc_text_class_init (GocItemClass *item_klass)
+{
+	GObjectClass *obj_klass = (GObjectClass *) item_klass;
+	GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+	parent_class = g_type_class_peek_parent (item_klass);
+
+	obj_klass->finalize = goc_text_finalize;
+	obj_klass->get_property = goc_text_get_property;
+	obj_klass->set_property = goc_text_set_property;
+	g_object_class_install_property (obj_klass, TEXT_PROP_X,
+		g_param_spec_double ("x",
+			_("x"),
+			_("The text horizontal position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, TEXT_PROP_Y,
+		g_param_spec_double ("y",
+			_("y"),
+			_("The text position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, TEXT_PROP_ROTATION,
+		g_param_spec_double ("rotation", 
+			_("Rotation"),
+			_("The rotation around the anchor"),
+			0., 2 * M_PI, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, TEXT_PROP_ANCHOR,
+		g_param_spec_enum ("anchor", 
+			_("Anchor"),
+			_("The anchor point for the text"),
+			GTK_TYPE_ANCHOR_TYPE, GTK_ANCHOR_CENTER,
+		        GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, TEXT_PROP_TEXT,
+		g_param_spec_string ("text", 
+			_("Text"),
+			_("The text to display"), NULL,
+ 			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+       g_object_class_install_property (obj_klass, TEXT_PROP_ATTRIBUTES,
+                 g_param_spec_boxed ("attributes", _("Attributes"), _("The attributes list as a PangoAttrList"),
+			PANGO_TYPE_ATTR_LIST,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+	gsi_klass->init_style = goc_text_init_style;
+
+	item_klass->update_bounds = goc_text_update_bounds;
+	item_klass->distance = goc_text_distance;
+	item_klass->draw = goc_text_draw;
+	item_klass->realize = goc_text_realize;
+	item_klass->unrealize = goc_text_unrealize;
+}
+
+GSF_CLASS (GocText, goc_text,
+	   goc_text_class_init, NULL,
+	   GOC_TYPE_STYLED_ITEM)
diff --git a/goffice/canvas/goc-text.h b/goffice/canvas/goc-text.h
new file mode 100644
index 0000000..7822b71
--- /dev/null
+++ b/goffice/canvas/goc-text.h
@@ -0,0 +1,38 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-text.h:
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_TEXT_H
+#define GOC_TEXT_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_TEXT	(goc_text_get_type ())
+#define GOC_TEXT(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_TEXT, GocText))
+#define GOC_IS_TEXT(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_TEXT))
+
+GType goc_text_get_type (void);
+
+G_END_DECLS
+
+#endif  /* GOC_TEXT_H */
diff --git a/goffice/canvas/goc-utils.c b/goffice/canvas/goc-utils.c
new file mode 100644
index 0000000..8f12c5b
--- /dev/null
+++ b/goffice/canvas/goc-utils.c
@@ -0,0 +1,65 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-utils.c :  
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/canvas/goc-utils.h>
+
+GocPoints *
+goc_points_new (unsigned n)
+{
+	GocPoints *points = g_new (GocPoints, 1);
+	points->n = n;
+	points->refs = 1;
+	points->points = g_new0 (GocPoint, n);
+	return points;
+}
+
+GocPoints *
+goc_points_ref (GocPoints *points)
+{
+	points->refs++;
+	return points;
+}
+
+void
+goc_points_unref (GocPoints *points)
+{
+	points->refs--;
+	if (points->refs == 0) {
+		g_free (points->points);
+		points->points = NULL;
+		g_free (points);
+	}
+}
+
+GType
+goc_points_get_type (void)
+{
+    static GType type_points = 0;
+
+    if (!type_points)
+	type_points = g_boxed_type_register_static
+	    ("GocPoints",
+	     (GBoxedCopyFunc) goc_points_ref,
+	     (GBoxedFreeFunc) goc_points_unref);
+
+    return type_points;
+}
diff --git a/goffice/canvas/goc-utils.h b/goffice/canvas/goc-utils.h
new file mode 100644
index 0000000..3281767
--- /dev/null
+++ b/goffice/canvas/goc-utils.h
@@ -0,0 +1,40 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-utils.h :  
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_UTILS_H
+#define GOC_UTILS_H
+
+#include <goffice/goffice.h>
+
+typedef struct {
+	unsigned n;
+	unsigned refs;
+	GocPoint *points;
+} GocPoints;
+
+GType goc_points_get_type (void);
+#define GOC_TYPE_POINTS goc_points_get_type ()
+
+GocPoints       *goc_points_new (unsigned n);
+GocPoints	*goc_points_ref (GocPoints *points);
+void		 goc_points_unref (GocPoints *points);
+
+#endif  /* GOC_UTILS_H */
\ No newline at end of file
diff --git a/goffice/canvas/goc-widget-impl.h b/goffice/canvas/goc-widget-impl.h
new file mode 100644
index 0000000..66a05e9
--- /dev/null
+++ b/goffice/canvas/goc-widget-impl.h
@@ -0,0 +1,40 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-widget-impl.h :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_WIDGET_IMPL_H
+#define GOC_WIDGET_IMPL_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+struct _GocWidget {
+	GocItem base;
+
+	double x, y, w, h;
+	GtkWidget *widget;
+};
+
+typedef GocItemClass GocWidgetClass;
+
+G_END_DECLS
+
+#endif  /* GOC_WIDGET_IMPL_H */
\ No newline at end of file
diff --git a/goffice/canvas/goc-widget.c b/goffice/canvas/goc-widget.c
new file mode 100644
index 0000000..7c1da33
--- /dev/null
+++ b/goffice/canvas/goc-widget.c
@@ -0,0 +1,258 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-widget.c :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+
+#include <math.h>
+
+enum {
+	WIDGET_PROP_0,
+	WIDGET_PROP_WIDGET,
+	WIDGET_PROP_X,
+	WIDGET_PROP_Y,
+	WIDGET_PROP_W,
+	WIDGET_PROP_H
+};
+
+static void
+goc_widget_notify_scrolled (GocItem *item)
+{
+	GocGroup const *parent;
+	double x0, y0, x1, y1;
+	GocWidget *widget = GOC_WIDGET (item);
+
+	parent = item->parent;
+	if (!item->cached_bounds)
+		goc_item_update_bounds (GOC_ITEM (item)); /* don't care about const */
+	x0 = item->x0;
+	y0 = item->y0;
+	x1 = item->x1;
+	y1 = item->y1;
+	while (parent) {
+		goc_group_adjust_bounds (parent, &x0, &y0, &x1, &y1);
+		parent = parent->base.parent;
+	}
+	x0 = (x0 - item->canvas->scroll_x1) * item->canvas->pixels_per_unit;
+	y0 = (y0 - item->canvas->scroll_y1) * item->canvas->pixels_per_unit;
+	x1 = (x1 - item->canvas->scroll_x1) * item->canvas->pixels_per_unit;
+	y1 = (y1 - item->canvas->scroll_y1) * item->canvas->pixels_per_unit;
+	gtk_widget_set_size_request (widget->widget, x1 - x0, y1 - y0);
+	/* ensure we don't wrap throught he infinite */
+	if (x0 < G_MININT)
+		x0 = G_MININT;
+	else if (x1 > G_MAXINT)
+		x0 -= x1 - G_MAXINT;
+	if (y0 < G_MININT)
+		y0 = G_MININT;
+	else if (y1 > G_MAXINT)
+		y0 -= y1 - G_MAXINT;
+	gtk_layout_move (GTK_LAYOUT (item->canvas), widget->widget, x0, y0);
+}
+
+static void
+goc_widget_set_property (GObject *obj, guint param_id,
+				    GValue const *value, GParamSpec *pspec)
+{
+	GocWidget *item = GOC_WIDGET (obj);
+
+	switch (param_id) {
+	case WIDGET_PROP_WIDGET: {
+		GtkWidget *widget = GTK_WIDGET (g_value_get_object (value));
+		if (widget == item->widget)
+			return;
+		if (item->widget) {
+			gtk_widget_destroy (item->widget);
+		}
+		item->widget = widget;
+		gtk_widget_show (widget);
+		gtk_layout_put (GTK_LAYOUT (GOC_ITEM (item)->canvas), widget, item->x, item->y);
+		goc_widget_notify_scrolled (GOC_ITEM (item));
+		return;
+	}
+	case WIDGET_PROP_X:
+		item->x = g_value_get_double (value);
+		break;
+
+	case WIDGET_PROP_Y:
+		item->y = g_value_get_double (value);
+		break;
+
+	case WIDGET_PROP_W:
+		item->w = g_value_get_double (value);
+		break;
+
+	case WIDGET_PROP_H:
+		item->h = g_value_get_double (value);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+	if (item->widget) {
+		goc_item_bounds_changed (GOC_ITEM (item));
+		goc_widget_notify_scrolled (GOC_ITEM (item));
+	}
+	
+}
+
+static void
+goc_widget_get_property (GObject *obj, guint param_id,
+				    GValue *value, GParamSpec *pspec)
+{
+	GocWidget *item = GOC_WIDGET (obj);
+
+	switch (param_id) {
+	case WIDGET_PROP_WIDGET:
+		g_value_set_object (value, item->widget);
+	case WIDGET_PROP_X:
+		g_value_set_double (value, item->x);
+		break;
+
+	case WIDGET_PROP_Y:
+		g_value_set_double (value, item->y);
+		break;
+
+	case WIDGET_PROP_W:
+		g_value_set_double (value, item->w);
+		break;
+
+	case WIDGET_PROP_H:
+		g_value_set_double (value, item->h);
+		break;
+
+	default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+		return; /* NOTE : RETURN */
+	}
+}
+
+static double
+goc_widget_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+	GocWidget *widget = GOC_WIDGET (item);
+	double dx, dy;
+	if (x < widget->x) {
+		dx = widget->x - x;
+	} else if (x < widget->x + widget->w) {
+		dx = 0;
+	} else {
+		dx = x - widget->x - widget->w;
+	}
+	if (y < widget->y) {
+		dy = widget->y - y;
+	} else if (x < widget->y + widget->h) {
+		dy = 0;
+	} else {
+		dy = y - widget->y - widget->h;
+	}
+	*near_item = item;
+	return hypot (dx, dy);
+}
+
+static void
+goc_widget_draw (GocItem const *item, cairo_t *cr)
+{
+	GocWidget *widget = GOC_WIDGET (item);
+	if (item->canvas->cur_event == NULL)
+		return; /* we do not draw for off-screen rendering, at least until this is implemented in gtk+ */
+	 gtk_container_propagate_expose (GTK_CONTAINER (item->canvas),
+					widget->widget,
+					(GdkEventExpose *) goc_canvas_get_cur_event (item->canvas));
+}
+
+static void
+goc_widget_update_bounds (GocItem *item)
+{
+	GocWidget *widget = GOC_WIDGET (item);
+	item->x0 = widget->x;
+	item->y0 = widget->y;
+	item->x1 = widget->x + widget->w;
+	item->y1 = widget->y + widget->h;
+}
+
+static void
+goc_widget_class_init (GocItemClass *item_klass)
+{
+	GObjectClass *obj_klass = (GObjectClass *) item_klass;
+
+	obj_klass->get_property = goc_widget_get_property;
+	obj_klass->set_property = goc_widget_set_property;
+	
+	g_object_class_install_property (obj_klass, WIDGET_PROP_WIDGET,
+		g_param_spec_object ("widget", 
+			_("Widget"),
+			_("A pointer to the embedded widget"),
+			GTK_TYPE_WIDGET, 
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, WIDGET_PROP_X,
+		g_param_spec_double ("x", 
+			_("x"),
+			_("The widget left position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, WIDGET_PROP_Y,
+		g_param_spec_double ("y", 
+			_("y"),
+			_("The widget top position"),
+			-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	/* Setting max size to 2048 which should be enough for all uses */
+	g_object_class_install_property (obj_klass, WIDGET_PROP_W,
+		g_param_spec_double ("width", 
+			_("Width"),
+			_("The widget width"),
+			0., 2048., 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+	g_object_class_install_property (obj_klass, WIDGET_PROP_H,
+		g_param_spec_double ("height", 
+			_("Height"),
+			_("The widget height"),
+			0., 2048., 0.,
+			GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+	item_klass->distance = goc_widget_distance;
+	item_klass->draw = goc_widget_draw;
+	item_klass->update_bounds = goc_widget_update_bounds;
+	item_klass->notify_scrolled = goc_widget_notify_scrolled;
+}
+
+GSF_CLASS (GocWidget, goc_widget,
+	   goc_widget_class_init, NULL,
+	   GOC_TYPE_ITEM)
+
+void
+goc_widget_set_bounds (GocWidget *widget, double left, double top, double width, double height)
+{
+	GocItem *item = GOC_ITEM (widget);
+	goc_item_invalidate (item);
+	widget->x = left;
+	widget->y = top;
+	widget->w = width;
+	widget->h = height;
+	goc_item_bounds_changed (item);
+	if (widget->widget)
+		goc_widget_notify_scrolled (item);
+	goc_item_invalidate (item);
+}
+
diff --git a/goffice/canvas/goc-widget.h b/goffice/canvas/goc-widget.h
new file mode 100644
index 0000000..ddaefd9
--- /dev/null
+++ b/goffice/canvas/goc-widget.h
@@ -0,0 +1,39 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-widget.h :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOC_WIDGET_H
+#define GOC_WIDGET_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_WIDGET	(goc_widget_get_type ())
+#define GOC_WIDGET(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_WIDGET, GocWidget))
+#define GOC_IS_WIDGET(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_WIDGET))
+
+GType goc_widget_get_type (void);
+
+void	 goc_widget_set_bounds (GocWidget *widget, double left, double top, double width, double height);
+
+G_END_DECLS
+
+#endif  /* GOC_WIDGET_H */
diff --git a/goffice/canvas/goffice-canvas.h b/goffice/canvas/goffice-canvas.h
new file mode 100644
index 0000000..3052bfb
--- /dev/null
+++ b/goffice/canvas/goffice-canvas.h
@@ -0,0 +1,73 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goffice-canvas.h :  
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOFFICE_CANVAS_H
+#define GOFFICE_CANVAS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GocCanvas		GocCanvas;
+typedef struct _GocItem			GocItem;
+typedef struct _GocGroup		GocGroup;
+typedef struct _GocLine			GocLine;
+typedef struct _GocPixbuf		GocPixbuf;
+typedef struct _GocPolygon		GocPolygon;
+typedef struct _GocRectangle	GocRectangle;
+typedef struct _GocCircle		GocCircle;
+typedef struct _GocEllipse		GocEllipse;
+typedef struct _GocStyledItem	GocStyledItem;
+typedef struct _GocText			GocText;
+typedef struct _GocWidget		GocWidget;
+typedef struct _GocGraph		GocGraph;
+
+G_END_DECLS
+
+#include <goffice/goffice.h>
+
+#include <goffice/canvas/goc-canvas.h>
+#include <goffice/canvas/goc-canvas-impl.h>
+#include <goffice/canvas/goc-item-impl.h>
+#include <goffice/canvas/goc-item.h>
+#include <goffice/canvas/goc-styled-item.h>
+#include <goffice/canvas/goc-structs.h>
+#include <goffice/canvas/goc-utils.h>
+
+#include <goffice/canvas/goc-circle.h>
+#include <goffice/canvas/goc-circle-impl.h>
+#include <goffice/canvas/goc-ellipse.h>
+#include <goffice/canvas/goc-graph.h>
+#include <goffice/canvas/goc-group.h>
+#include <goffice/canvas/goc-group-impl.h>
+#include <goffice/canvas/goc-line.h>
+#include <goffice/canvas/goc-pixbuf.h>
+#include <goffice/canvas/goc-polygon.h>
+#include <goffice/canvas/goc-polygon-impl.h>
+#include <goffice/canvas/goc-rectangle.h>
+#include <goffice/canvas/goc-rectangle-impl.h>
+#include <goffice/canvas/goc-text.h>
+#include <goffice/canvas/goc-widget.h>
+#include <goffice/canvas/goc-widget-impl.h>
+
+#endif  /* GOFFICE_CANVAS_H */
diff --git a/goffice/canvas/goffice-canvas.h~ b/goffice/canvas/goffice-canvas.h~
new file mode 100644
index 0000000..207e40f
--- /dev/null
+++ b/goffice/canvas/goffice-canvas.h~
@@ -0,0 +1,75 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goffice-canvas.h :  
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU General Public License as 
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+ * USA
+ */
+
+#ifndef GOFFICE_CANVAS_H
+#define GOFFICE_CANVAS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GocCanvas		GocCanvas;
+typedef struct _GocItem			GocItem;
+typedef struct _GocGroup		GocGroup;
+typedef struct _GocLine			GocLine;
+typedef struct _GocPixbuf		GocPixbuf;
+typedef struct _GocPolygon		GocPolygon;
+typedef struct _GocRectangle	GocRectangle;
+typedef struct _GocCircle		GocCircle;
+typedef struct _GocEllipse		GocEllipse;
+typedef struct _GocStyledItem	GocStyledItem;
+typedef struct _GocText			GocText;
+typedef struct _GocWidget		GocWidget;
+typedef struct _GocGraph		GocGraph;
+
+G_END_DECLS
+
+#include <goffice/goffice.h>
+
+#include <goffice/canvas/goc-canvas.h>
+#include <goffice/canvas/goc-canvas-impl.h>
+#include <goffice/canvas/goc-item-impl.h>
+#include <goffice/canvas/goc-item.h>
+#include <goffice/canvas/goc-styled-item.h>
+#include <goffice/canvas/goc-structs.h>
+#include <goffice/canvas/goc-utils.h>
+
+#include <goffice/canvas/goc-circle.h>
+#include <goffice/canvas/goc-circle-impl.h>
+#include <goffice/canvas/goc-component.h>
+#include <goffice/canvas/goc-ellipse.h>
+#include <goffice/canvas/goc-graph.h>
+#include <goffice/canvas/goc-group.h>
+#include <goffice/canvas/goc-group-impl.h>
+#include <goffice/canvas/goc-line.h>
+#include <goffice/canvas/goc-pixbuf.h>
+#include <goffice/canvas/goc-polygon.h>
+#include <goffice/canvas/goc-polygon-impl.h>
+#include <goffice/canvas/goc-polyline.h>
+#include <goffice/canvas/goc-rectangle.h>
+#include <goffice/canvas/goc-rectangle-impl.h>
+#include <goffice/canvas/goc-text.h>
+#include <goffice/canvas/goc-widget.h>
+#include <goffice/canvas/goc-widget-impl.h>
+
+#endif  /* GOFFICE_CANVAS_H */
diff --git a/goffice/goffice.h b/goffice/goffice.h
index 848e37c..7e23670 100644
--- a/goffice/goffice.h
+++ b/goffice/goffice.h
@@ -48,6 +48,7 @@
 #include <goffice/math/goffice-math.h>
 #ifdef GOFFICE_WITH_GTK
 #include <goffice/gtk/goffice-gtk.h>
+#include <goffice/canvas/goffice-canvas.h>
 #endif
 #include <goffice/graph/goffice-graph.h>
 
diff --git a/goffice/graph/gog-guru.c b/goffice/graph/gog-guru.c
index 21233f9..713ea43 100644
--- a/goffice/graph/gog-guru.c
+++ b/goffice/graph/gog-guru.c
@@ -23,28 +23,11 @@
 #include <goffice/goffice-config.h>
 #include <goffice/goffice-priv.h>
 
-#include <goffice/app/go-doc-control.h>
-#include <goffice/graph/gog-guru.h>
-#include <goffice/graph/gog-object.h>
-#include <goffice/graph/gog-graph.h>
-#include <goffice/graph/gog-object.h>
-#include <goffice/graph/gog-chart.h>
-#include <goffice/graph/gog-plot.h>
-#include <goffice/graph/gog-trend-line.h>
-#include <goffice/graph/gog-view.h>
-#include <goffice/graph/gog-plot-engine.h>
-#include <goffice/graph/gog-data-allocator.h>
-#include <goffice/graph/gog-control-foocanvas.h>
-#include <goffice/graph/gog-child-button.h>
-#include <goffice/gtk/go-pixbuf.h>
-#include <goffice/gtk/goffice-gtk.h>
+#include <goffice/goffice.h>
 
 #include <glib/gi18n-lib.h>
 
 #include <libxml/parser.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-pixbuf.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-rect-ellipse.h>
 #include <gdk/gdkkeysyms.h>
 #include <gtk/gtk.h>
 #include <string.h>
@@ -72,9 +55,9 @@ struct _GraphGuruState {
 	GtkNotebook *steps;
 	GtkWidget   *delete_button;
 
-	FooCanvasItem	  *sample_graph_item;
-	FooCanvasItem	  *sample_graph_frame;
-	FooCanvasItem	  *sample_graph_shadow;
+	GocItem	  *sample_graph_item;
+	GocItem	  *sample_graph_frame;
+	GocItem	  *sample_graph_shadow;
 
 	GtkContainer  	  *prop_container;
 	GtkTreeSelection  *prop_selection;
@@ -109,19 +92,19 @@ struct _GraphGuruTypeSelector {
 	GtkLabel	*label;
 	GtkTreeView	*list_view;
 	GtkListStore	*model;
-	FooCanvasItem *selector;
+	GocItem *selector;
 
-	FooCanvasItem *sample_graph_item;
+	GocItem *sample_graph_item;
 
 	GraphGuruState *state;
 
-	FooCanvasGroup *graph_group;
+	GocGroup *graph_group;
 
 	xmlNode const *plots;
 	GogPlotFamily	*current_family;
 	GogPlotType	*current_type;
-	FooCanvasGroup const *current_family_item;
-	FooCanvasItem const  *current_minor_item;
+	GocGroup const *current_family_item;
+	GocItem const  *current_minor_item;
 
 	int max_priority_so_far;
 };
@@ -165,7 +148,7 @@ get_pos (int col, int row, double *x, double *y)
  * Assumes that the item is visible
  */
 static void
-graph_typeselect_minor (GraphGuruTypeSelector *typesel, FooCanvasItem *item)
+graph_typeselect_minor (GraphGuruTypeSelector *typesel, GocItem *item)
 {
 	GraphGuruState *s = typesel->state;
 	GogPlotType *type;
@@ -182,10 +165,10 @@ graph_typeselect_minor (GraphGuruTypeSelector *typesel, FooCanvasItem *item)
 
 	typesel->current_type = type;
 	typesel->current_minor_item = item;
-	foo_canvas_item_get_bounds (item, &x1, &y1, &x2, &y2);
-	foo_canvas_item_set (FOO_CANVAS_ITEM (typesel->selector),
-		"x1", x1-1., "y1", y1-1.,
-		"x2", x2+1., "y2", y2+1.,
+	goc_item_get_bounds (item, &x1, &y1, &x2, &y2);
+	goc_item_set (GOC_ITEM (typesel->selector),
+		"x", x1-1., "y", y1-1.,
+		"width", x2-x1+2., "height", y2-y1+2.,
 		NULL);
 	gtk_label_set_text (typesel->label, _(type->description));
 	gtk_widget_set_sensitive (typesel->sample_button, TRUE);
@@ -219,13 +202,13 @@ static gboolean
 graph_typeselect_minor_x_y (GraphGuruTypeSelector *typesel,
 			    double x, double y)
 {
-	FooCanvasItem *item = foo_canvas_get_item_at (
-		FOO_CANVAS (typesel->canvas), x, y);
+	GocItem *item = goc_canvas_get_item_at (
+		GOC_CANVAS (typesel->canvas), x, y);
 
 	if (item != NULL) {
 		if(item != typesel->selector)
 			graph_typeselect_minor (typesel, item);
-		foo_canvas_item_grab_focus (item);
+	//	goc_item_grab (item);
 		return TRUE;
 	}
 
@@ -283,14 +266,8 @@ static gint
 cb_button_press_event (GtkWidget *widget, GdkEventButton *event,
 		       GraphGuruTypeSelector *typesel)
 {
-	if (event->button == 1) {
-		FooCanvas *c = FOO_CANVAS (widget);
-		double x, y;
-
-		foo_canvas_window_to_world (c, event->x, event->y, &x, &y);
-
-		graph_typeselect_minor_x_y (typesel, x, y);
-	}
+	if (event->button == 1)
+		graph_typeselect_minor_x_y (typesel, event->x, event->y);
 
 	return FALSE;
 }
@@ -300,35 +277,35 @@ cb_selection_changed (GraphGuruTypeSelector *typesel)
 {
 	GtkTreeSelection *selection = gtk_tree_view_get_selection (typesel->list_view);
 	GtkTreeIter  iter;
-	FooCanvasItem *item;
-	FooCanvasGroup *group;
+	GocItem *item;
+	GocGroup *group;
 
 	if (typesel->current_family_item != NULL)
-		foo_canvas_item_hide (FOO_CANVAS_ITEM (typesel->current_family_item));
+		goc_item_hide (GOC_ITEM (typesel->current_family_item));
 	if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
 		return;
 	gtk_tree_model_get (GTK_TREE_MODEL (typesel->model), &iter,
 		PLOT_FAMILY_TYPE_CANVAS_GROUP, &group,
 		-1);
 
-	foo_canvas_item_show (FOO_CANVAS_ITEM (group));
+	goc_item_show (GOC_ITEM (group));
 	typesel->current_family_item = group;
 
-	foo_canvas_item_hide (FOO_CANVAS_ITEM (typesel->selector));
+	goc_item_hide (GOC_ITEM (typesel->selector));
 	item = g_object_get_data (G_OBJECT (group), FIRST_MINOR_TYPE);
 	if (item != NULL)
 		graph_typeselect_minor (typesel, item);
-	foo_canvas_item_show (FOO_CANVAS_ITEM (typesel->selector));
+	goc_item_show (GOC_ITEM (typesel->selector));
 }
 
 static void
-cb_typesel_sample_plot_resize (FooCanvas *canvas,
+cb_typesel_sample_plot_resize (GocCanvas *canvas,
 			       GtkAllocation *alloc, GraphGuruTypeSelector *typesel)
 {
 	if (typesel->sample_graph_item != NULL)
-		foo_canvas_item_set (typesel->sample_graph_item,
-			"w", (double)alloc->width,
-			"h", (double)alloc->height,
+		goc_item_set (typesel->sample_graph_item,
+			"width", (double)alloc->width,
+			"height", (double)alloc->height,
 			NULL);
 }
 
@@ -340,19 +317,19 @@ cb_sample_pressed (GraphGuruTypeSelector *typesel)
 
 	if (typesel->sample_graph_item == NULL) {
 		GtkAllocation *size = &GTK_WIDGET (typesel->canvas)->allocation;
-		typesel->sample_graph_item = foo_canvas_item_new (typesel->graph_group,
-			GOG_TYPE_CONTROL_FOOCANVAS,
-			"model", typesel->state->graph,
+		typesel->sample_graph_item = goc_item_new (typesel->graph_group,
+			GOC_TYPE_GRAPH,
+			"graph", typesel->state->graph,
 			NULL);
-		cb_typesel_sample_plot_resize (FOO_CANVAS (typesel->canvas),
+		cb_typesel_sample_plot_resize (GOC_CANVAS (typesel->canvas),
 					       size, typesel);
 
 		g_return_if_fail (typesel->sample_graph_item != NULL);
 	}
 
-	foo_canvas_item_hide (FOO_CANVAS_ITEM (typesel->current_family_item));
-	foo_canvas_item_hide (FOO_CANVAS_ITEM (typesel->selector));
-	foo_canvas_item_show (FOO_CANVAS_ITEM (typesel->graph_group));
+	goc_item_hide (GOC_ITEM (typesel->current_family_item));
+	goc_item_hide (GOC_ITEM (typesel->selector));
+	goc_item_show (GOC_ITEM (typesel->graph_group));
 }
 
 static void
@@ -361,15 +338,15 @@ cb_sample_released (GraphGuruTypeSelector *typesel)
 	if (typesel->current_family_item == NULL)
 		return;
 
-	foo_canvas_item_hide (FOO_CANVAS_ITEM (typesel->graph_group));
-	foo_canvas_item_show (FOO_CANVAS_ITEM (typesel->current_family_item));
-	foo_canvas_item_show (FOO_CANVAS_ITEM (typesel->selector));
+	goc_item_hide (GOC_ITEM (typesel->graph_group));
+	goc_item_show (GOC_ITEM (typesel->current_family_item));
+	goc_item_show (GOC_ITEM (typesel->selector));
 }
 
 typedef struct {
 	GraphGuruTypeSelector	*typesel;
-	FooCanvasGroup		*group;
-	FooCanvasItem		*current_item;
+	GocGroup		*group;
+	GocItem		*current_item;
 	GogPlotType 		*current_type;
 	int col, row;
 } type_list_closure;
@@ -379,7 +356,7 @@ cb_plot_types_init (char const *id, GogPlotType *type,
 		    type_list_closure *closure)
 {
 	double x1, y1, w, h;
-	FooCanvasItem *item;
+	GocItem *item;
 	int col, row;
 	GdkPixbuf *image = go_pixbuf_get_from_cache (type->sample_image_file);
 
@@ -395,12 +372,11 @@ cb_plot_types_init (char const *id, GogPlotType *type,
 	if (h > MINOR_PIXMAP_HEIGHT)
 		h = MINOR_PIXMAP_HEIGHT;
 
-	item = foo_canvas_item_new (closure->group,
-		foo_canvas_pixbuf_get_type (),
+	item = goc_item_new (closure->group,
+		goc_pixbuf_get_type (),
 		"x",	 x1,	"y",	  y1,
 		"width", w,	"height", h,
 		"pixbuf",	image,
-		"point_ignores_alpha", TRUE,
 		NULL);
 	g_object_set_data (G_OBJECT (item), PLOT_TYPE_KEY, (gpointer)type);
 
@@ -418,7 +394,7 @@ static void
 cb_plot_families_init (char const *id, GogPlotFamily *family,
 		       GraphGuruTypeSelector *typesel)
 {
-	FooCanvasGroup		*group;
+	GocGroup		*group;
 	GtkTreeIter		 iter;
 	type_list_closure	 closure;
 
@@ -426,13 +402,13 @@ cb_plot_families_init (char const *id, GogPlotFamily *family,
 		return;
 
 	/* Define a canvas group for all the minor types */
-	group = FOO_CANVAS_GROUP (foo_canvas_item_new (
-		foo_canvas_root (FOO_CANVAS (typesel->canvas)),
-		foo_canvas_group_get_type (),
+	group = GOC_GROUP (goc_item_new (
+		goc_canvas_get_root (GOC_CANVAS (typesel->canvas)),
+		goc_group_get_type (),
 		"x", 0.0,
 		"y", 0.0,
 		NULL));
-	foo_canvas_item_hide (FOO_CANVAS_ITEM (group));
+	goc_item_hide (GOC_ITEM (group));
 
 	gtk_list_store_append (typesel->model, &iter);
 	gtk_list_store_set (typesel->model, &iter,
@@ -786,7 +762,7 @@ populate_graph_item_list (GogObject *obj, GogObject *select, GraphGuruState *s,
 }
 
 static gint
-cb_canvas_select_item (FooCanvas *canvas, GdkEvent *event,
+cb_canvas_select_item (GocCanvas *canvas, GdkEvent *event,
 		       GraphGuruState *s)
 {
 	double item_x, item_y;
@@ -797,7 +773,7 @@ cb_canvas_select_item (FooCanvas *canvas, GdkEvent *event,
 		case GDK_MOTION_NOTIFY:
 		case GDK_BUTTON_RELEASE:
 
-			g_return_val_if_fail (FOO_IS_CANVAS (canvas), FALSE);
+			g_return_val_if_fail (GOC_IS_CANVAS (canvas), FALSE);
 
 			g_object_get (G_OBJECT(s->sample_graph_item), "x", &item_x, "y", &item_y, NULL);
 			gog_graph_view_handle_event (s->graph_view, (GdkEvent *) event, 
@@ -813,44 +789,60 @@ cb_canvas_select_item (FooCanvas *canvas, GdkEvent *event,
 }
 
 static void
-cb_sample_plot_resize (FooCanvas *canvas,
+cb_sample_plot_resize (GocCanvas *canvas,
 		       GtkAllocation *alloc, GraphGuruState *state)
 {
 	double aspect_ratio;
 	double width, height, x, y;
 
 	gog_graph_get_size (state->graph, &width, &height);
-       	aspect_ratio = width / height;
+    aspect_ratio = width / height;
 
 	if (alloc->width > alloc->height * aspect_ratio) {
 		height = alloc->height;
-		width = height * aspect_ratio;
-		x = (alloc->width - width) / 2.0;
+		width = floor (height * aspect_ratio + .5);
+		x = floor ((alloc->width - width) / 2.0 + .5);
 		y = 0.0;
 	} else {
 		width = alloc->width;
-		height = width / aspect_ratio;
+		height = floor (width / aspect_ratio + .5);
 		x = 0.0;
-		y = (alloc->height - height) / 2.0;
+		y = floor ((alloc->height - height) / 2.0 + .5);
 	}
-	
-	foo_canvas_item_set (state->sample_graph_item,
-		"w", width > 2 ? width - 2 : 0,
-		"h", height > 2 ? height - 2 : 0,
+
+	if (width > 2)
+		width -= 2;
+	else
+		width = 0;
+	if (height > 2)
+		height -= 2;
+	else
+		height = 0;
+	goc_item_set (state->sample_graph_item,
+		"width", width,
+		"height", height,
 		"x", x,
 		"y", y,
 		NULL);
-	foo_canvas_item_set (state->sample_graph_frame,
-		"x2", x + width - 3,
-		"y2", y + height - 3,
-		"x1", x,
-		"y1", y,
+	if (width > .5)
+		width -= 1.;
+	if (height > .5)
+		height -= 1.;
+	goc_item_set (state->sample_graph_frame,
+		"width", width,
+		"height", height,
+		"x", x,
+		"y", y,
 		NULL);
-	foo_canvas_item_set (state->sample_graph_shadow,
-		"x2", x + width - 1,
-		"y2", y + height - 1,
-		"x1", x + 3,
-		"y1", y + 3,
+	if (width > .5)
+		width -= 1.;
+	if (height > .5)
+		height -= 1.;
+	goc_item_set (state->sample_graph_shadow,
+		"width", width,
+		"height", height,
+		"x", x + 3,
+		"y", y + 3,
 		NULL);
 }
 
@@ -885,6 +877,7 @@ graph_guru_init_format_page (GraphGuruState *s)
 	GtkWidget *w, *canvas;
 	GtkTreeViewColumn *column;
 	GogRenderer *rend;
+	GOStyle *style;
 
 	if (s->fmt_page_initialized)
 		return;
@@ -921,25 +914,27 @@ graph_guru_init_format_page (GraphGuruState *s)
 
 	/* Load up the sample view and make it fill the entire canvas */
 	w = glade_xml_get_widget (s->gui, "sample-alignment");
-	canvas = foo_canvas_new ();
+	canvas = GTK_WIDGET (g_object_new (GOC_TYPE_CANVAS, NULL));
 	gtk_container_add (GTK_CONTAINER (w), canvas);
-	s->sample_graph_shadow = foo_canvas_item_new (foo_canvas_root (FOO_CANVAS (canvas)),
-						      FOO_TYPE_CANVAS_RECT,
-						      "width_pixels", 2,
-						      "outline_color_rgba", 0xa0a0a0ff,	/* grey */
+	s->sample_graph_shadow = goc_item_new (goc_canvas_get_root (GOC_CANVAS (canvas)),
+						      GOC_TYPE_RECTANGLE,
 						      NULL);
-	s->sample_graph_frame = foo_canvas_item_new (foo_canvas_root (FOO_CANVAS (canvas)),
-						     FOO_TYPE_CANVAS_RECT,
-						     "width_pixels", 1,
-						     "fill_color_rgba", 0xffffffff,	/* white */
-						     "outline_color_rgba", 0x707070ff,	/* grey */
+	style= go_styled_object_get_style (GO_STYLED_OBJECT (s->sample_graph_shadow));
+	style->outline.width = 2;
+	style->outline.color = 0xa0a0a0ff;	/* grey */
+	s->sample_graph_frame = goc_item_new (goc_canvas_get_root (GOC_CANVAS (canvas)),
+						     GOC_TYPE_RECTANGLE,
 						     NULL);
-	s->sample_graph_item = foo_canvas_item_new (foo_canvas_root (FOO_CANVAS (canvas)),
-						    GOG_TYPE_CONTROL_FOOCANVAS,
-						    "model", s->graph,
+	style= go_styled_object_get_style (GO_STYLED_OBJECT (s->sample_graph_frame));
+	style->outline.width = 1;
+	style->outline.color = 0x707070ff;	/* grey */
+	style->fill.pattern.back = 0xffffffff;	/* white */
+	s->sample_graph_item = goc_item_new (goc_canvas_get_root (GOC_CANVAS (canvas)),
+						    GOC_TYPE_GRAPH,
+						    "graph", s->graph,
 						    NULL);
 	gtk_widget_add_events (canvas, GDK_POINTER_MOTION_HINT_MASK);
-	cb_sample_plot_resize (FOO_CANVAS (canvas), &canvas->allocation, s);
+	cb_sample_plot_resize (GOC_CANVAS (canvas), &canvas->allocation, s);
 	g_signal_connect (G_OBJECT (canvas),
 			  "size_allocate",
 			  G_CALLBACK (cb_sample_plot_resize), s);
@@ -1097,15 +1092,17 @@ typesel_set_selection_color (GraphGuruTypeSelector *typesel)
 	GtkWidget *w = gtk_entry_new ();
 	GdkColor  *color = &w->style->base [GTK_WIDGET_HAS_FOCUS (typesel->canvas)
 		? GTK_STATE_SELECTED : GTK_STATE_ACTIVE];
-	guint32    select_color = 0;
+	GOColor    select_color;
+	GOStyle   *style;
 
-	select_color |= ((color->red >> 8) & 0xff)   << 24;
+	select_color = ((color->red >> 8) & 0xff)   << 24;
 	select_color |= ((color->green >> 8) & 0xff) << 16;
 	select_color |= ((color->blue >> 8) & 0xff)  << 8;
 	select_color |= 0x40; /* alpha of 25% */
-	foo_canvas_item_set (typesel->selector,
-		"fill_color_rgba",	select_color,
-		NULL);
+
+	style = go_styled_object_get_style (GO_STYLED_OBJECT (typesel->selector));
+	style->fill.pattern.back = select_color;
+	goc_item_invalidate (typesel->selector);
 	gtk_object_destroy (GTK_OBJECT (w));
 }
 
@@ -1116,6 +1113,7 @@ graph_guru_type_selector_new (GraphGuruState *s)
 	GraphGuruTypeSelector *typesel;
 	GtkWidget *selector;
 	GladeXML *gui;
+	GOStyle *style;
 
 	gui = go_glade_new ("gog-guru-type-selector.glade", "type_selector", GETTEXT_PACKAGE, s->cc);
 
@@ -1153,12 +1151,10 @@ graph_guru_type_selector_new (GraphGuruState *s)
 
 
 	/* Setup an canvas to display the sample image & the sample plot. */
-	typesel->canvas = foo_canvas_new ();
-	typesel->graph_group = FOO_CANVAS_GROUP (foo_canvas_item_new (
-		foo_canvas_root (FOO_CANVAS (typesel->canvas)),
-		foo_canvas_group_get_type (),
-		"x", 0.0,
-		"y", 0.0,
+	typesel->canvas = GTK_WIDGET (g_object_new (GOC_TYPE_CANVAS, NULL));
+	typesel->graph_group = GOC_GROUP (goc_item_new (
+		goc_canvas_get_root (GOC_CANVAS (typesel->canvas)),
+		goc_group_get_type (),
 		NULL));
 	g_object_connect (typesel->canvas,
 		"signal::realize", G_CALLBACK (cb_canvas_realized), typesel,
@@ -1171,7 +1167,6 @@ graph_guru_type_selector_new (GraphGuruState *s)
 	gtk_widget_set_size_request (typesel->canvas,
 		MINOR_PIXMAP_WIDTH*3 + BORDER*5,
 		MINOR_PIXMAP_HEIGHT*3 + BORDER*5);
-	foo_canvas_scroll_to (FOO_CANVAS (typesel->canvas), 0, 0);
 	gtk_container_add (GTK_CONTAINER (glade_xml_get_widget (gui, "canvas_container")), 
 			   typesel->canvas);
 
@@ -1186,12 +1181,13 @@ graph_guru_type_selector_new (GraphGuruState *s)
 		G_CALLBACK (cb_selection_changed), typesel);
 
 	/* The alpha blended selection box */
-	typesel->selector = foo_canvas_item_new (
-		foo_canvas_root (FOO_CANVAS (typesel->canvas)),
-		foo_canvas_rect_get_type (),
-		"outline_color_rgba",	0x000000ff,	/* black */
-		"width_pixels", 1,
+	typesel->selector = goc_item_new (
+		goc_canvas_get_root (GOC_CANVAS (typesel->canvas)),
+		GOC_TYPE_RECTANGLE,
 		NULL);
+	style= go_styled_object_get_style (GO_STYLED_OBJECT (typesel->selector));
+	style->outline.width = 1;
+	style->outline.color = 0x000000ff;	/* black */
 	typesel_set_selection_color (typesel);
 
 	/* Setup the description label */
diff --git a/goffice/gtk/go-3d-rotation-sel.c b/goffice/gtk/go-3d-rotation-sel.c
index 21a5f71..07eb2ff 100644
--- a/goffice/gtk/go-3d-rotation-sel.c
+++ b/goffice/gtk/go-3d-rotation-sel.c
@@ -21,12 +21,11 @@
 #include <goffice/goffice-config.h>
 #include <goffice/goffice.h>
 
-#include <goffice/cut-n-paste/foocanvas/foo-canvas.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-util.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-line.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-widget.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-rect-ellipse.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-polygon.h>
+#include <goffice/canvas/goc-canvas.h>
+#include <goffice/canvas/goc-item.h>
+#include <goffice/canvas/goc-circle.h>
+#include <goffice/canvas/goc-polygon.h>
+#include <goffice/canvas/goc-structs.h>
 
 #include <gsf/gsf-impl-utils.h>
 #include <glib/gi18n-lib.h>
@@ -55,10 +54,10 @@ struct _GO3DRotationSel {
 	double		 bank;
 	g3d_point	*cube_points;
 	int 	 	*cube_faces;
-	FooCanvas       *rotate_canvas;
-	FooCanvasItem   *dial;
-	FooCanvasItem	*bank_dial;
-	FooCanvasItem	*cube_polygons[6];
+	GocCanvas       *rotate_canvas;
+	GocItem		*dial;
+	GocItem		*bank_dial;
+	GocItem		*cube_polygons[6];
 	gulong		 motion_handle;
 };
 
@@ -99,7 +98,6 @@ cb_rotation_changed (GO3DRotationSel *g3d)
 	double mgn = g3d->margin - 2;
 	double r = g3d->radius;
 	double d = 2 * r;
-	double dr = g3d->bank_dial_r;
 	double dx = g3d->bank_dial_x = mgn + r * (1 - sin (g3d->bank));
 	double dy = g3d->bank_dial_y = mgn + r * (1 - cos (g3d->bank));
 
@@ -124,16 +122,9 @@ cb_rotation_changed (GO3DRotationSel *g3d)
 	};
 	int i;
 
-	if (g3d->dial) {
-		foo_canvas_item_set (g3d->dial,
-			"x1", mgn, "y1", mgn,
-			"x2", mgn + d, "y2", mgn + d, NULL);
-	}
-
 	if (g3d->bank_dial) {
-		foo_canvas_item_set (g3d->bank_dial,
-			"x1", dx - dr, "y1", dy - dr,
-			"x2", dx + dr, "y2", dy + dr, NULL);
+		goc_item_set (g3d->bank_dial,
+			"x", dx, "y", dy, NULL);
 	}
 
 	for (i = 0; i < 8; ++i) {
@@ -145,23 +136,22 @@ cb_rotation_changed (GO3DRotationSel *g3d)
 	}
 
 	for (i = 0; i < 6; ++i) {
-		FooCanvasPoints *points;
+		GocPoints *points;
+		GOStyle *style;
 		double cx = mgn + r;
 		double mean_y;
 		if (g3d->cube_polygons[i] == NULL)
 			continue;
 
-		points = foo_canvas_points_new (5);
-		points->coords[0] = cp[cf[4 * i + 0]].x + cx;
-		points->coords[1] = -cp[cf[4 * i + 0]].z + cx;
-		points->coords[2] = cp[cf[4 * i + 1]].x + cx;
-		points->coords[3] = -cp[cf[4 * i + 1]].z + cx;
-		points->coords[4] = cp[cf[4 * i + 2]].x + cx;
-		points->coords[5] = -cp[cf[4 * i + 2]].z + cx;
-		points->coords[6] = cp[cf[4 * i + 3]].x + cx;
-		points->coords[7] = -cp[cf[4 * i + 3]].z + cx;
-		points->coords[8] = cp[cf[4 * i + 0]].x + cx;
-		points->coords[9] = -cp[cf[4 * i + 0]].z + cx;
+		points = goc_points_new (4);
+		points->points[0].x = cp[cf[4 * i + 0]].x + cx;
+		points->points[0].y = -cp[cf[4 * i + 0]].z + cx;
+		points->points[1].x = cp[cf[4 * i + 1]].x + cx;
+		points->points[1].y = -cp[cf[4 * i + 1]].z + cx;
+		points->points[2].x = cp[cf[4 * i + 2]].x + cx;
+		points->points[2].y = -cp[cf[4 * i + 2]].z + cx;
+		points->points[3].x = cp[cf[4 * i + 3]].x + cx;
+		points->points[3].y = -cp[cf[4 * i + 3]].z + cx;
 
 		/* NOTE: This back face culling method works only with
 		 * a cube in parallel projection*/
@@ -169,11 +159,16 @@ cb_rotation_changed (GO3DRotationSel *g3d)
 		mean_y += cp[cf[4 * i + 1]].y;
 		mean_y += cp[cf[4 * i + 2]].y;
 		mean_y += cp[cf[4 * i + 3]].y;
-		foo_canvas_item_set (g3d->cube_polygons[i], "points", points,
-		                     "width_units", (mean_y < 0) ? 4. : 0.5, 
-				     "fill-color", (i == 1)? "light blue" : "none",
-				     NULL);
-		foo_canvas_points_free (points);
+		style = go_styled_object_get_style (GO_STYLED_OBJECT (g3d->cube_polygons[i]));
+		style->fill.auto_type = FALSE;
+		style->fill.type = GO_STYLE_FILL_PATTERN;
+		style->fill.auto_back = FALSE;
+		/* set the background light blue or transparent */
+		style->fill.pattern.back = (i == 1)? RGBA_TO_UINT (0xad, 0xd8, 0xe6, 0xff): 0;
+		style->outline.width = (mean_y < 0) ? 4. : 0.5;
+		goc_item_set (g3d->cube_polygons[i], "points", points,
+		              "style", style, NULL);
+		goc_points_unref (points);
 	}
 	go_matrix3x3_to_euler (&g3d->mat, &g3d->psi, &g3d->theta, &g3d->phi);
 
@@ -199,31 +194,45 @@ cb_fov_changed (GtkRange *range, GdkEventButton *event, GO3DRotationSel *g3d)
 }
 
 static void
-cb_rotate_canvas_realize (FooCanvas *canvas, GO3DRotationSel *g3d)
+cb_rotate_canvas_realize (GocCanvas *canvas, GO3DRotationSel *g3d)
 {
-	FooCanvasGroup  *group = FOO_CANVAS_GROUP (foo_canvas_root (canvas));
+	GocGroup  *group = GOC_GROUP (goc_canvas_get_root (canvas));
 	GtkStyle *style = gtk_style_copy (GTK_WIDGET (canvas)->style);
 	int i;
+	GOStyle *go_style;
+	double mgn = g3d->margin - 2 + g3d->radius;
 	style->bg[GTK_STATE_NORMAL] = style->white;
 	gtk_widget_set_style (GTK_WIDGET (canvas), style);
 	g_object_unref (style);
 
-	foo_canvas_set_scroll_region (canvas, 0, 0, 220, 220);
-	foo_canvas_scroll_to (canvas, 0, 0);
-
 	for (i = 0; i < 6; ++i) {
-		g3d->cube_polygons[i] = foo_canvas_item_new (group,
-			FOO_TYPE_CANVAS_POLYGON, "outline-color", "black",
-			NULL);
+		g3d->cube_polygons[i] = goc_item_new (group,
+		        GOC_TYPE_POLYGON, NULL);
+		go_style = go_styled_object_get_style (GO_STYLED_OBJECT (g3d->cube_polygons[i]));
+		go_style->outline.auto_color = FALSE;
+		go_style->outline.color = RGBA_BLACK;
+		go_style->outline.miter_limit = 1.414;
 	}
 
-	g3d->dial = foo_canvas_item_new (group,
-        	FOO_TYPE_CANVAS_ELLIPSE, "outline_color", "black",
-		"width_units", 2., NULL);
-
-	g3d->bank_dial = foo_canvas_item_new (group,
-		FOO_TYPE_CANVAS_ELLIPSE, "outline_color", "black",
-		"fill_color", "white", "width_units", 3., NULL);
+	g3d->dial = goc_item_new (group, GOC_TYPE_CIRCLE,
+	                          "x", mgn, "y", mgn, "radius", (double) g3d->radius, NULL);
+	go_style = go_styled_object_get_style (GO_STYLED_OBJECT (g3d->dial));
+	go_style->outline.auto_color = FALSE;
+	go_style->outline.color = RGBA_BLACK;
+	go_style->outline.width = 2.;
+	go_style->fill.auto_type = FALSE;
+	go_style->fill.type = GO_STYLE_FILL_NONE;
+		
+	g3d->bank_dial = goc_item_new (group,
+		GOC_TYPE_CIRCLE, "radius", (double) g3d->bank_dial_r, NULL);
+	go_style = go_styled_object_get_style (GO_STYLED_OBJECT (g3d->bank_dial));
+	go_style->outline.auto_color = FALSE;
+	go_style->outline.color = RGBA_BLACK;
+	go_style->outline.width = 3.;
+	go_style->fill.auto_type = FALSE;
+	go_style->fill.type = GO_STYLE_FILL_PATTERN;
+	go_style->fill.auto_back = FALSE;
+	go_style->fill.pattern.back = RGBA_WHITE;
 
 	cb_rotation_changed(g3d);	
 }
@@ -339,7 +348,7 @@ g3d_init (GO3DRotationSel *g3d)
 	g3d->dial = NULL;
 	g3d->bank_dial = NULL;
 	memset (g3d->cube_polygons, 0, sizeof (g3d->cube_polygons));
-	g3d->rotate_canvas = FOO_CANVAS (foo_canvas_new ());
+	g3d->rotate_canvas = GOC_CANVAS (g_object_new (GOC_TYPE_CANVAS, NULL));
 	gtk_container_add (GTK_CONTAINER (glade_xml_get_widget (g3d->gui,
 	                   "rotate_canvas")),
 	                   GTK_WIDGET (g3d->rotate_canvas));
diff --git a/goffice/gtk/go-font-sel.c b/goffice/gtk/go-font-sel.c
index 8f7a898..063c27e 100644
--- a/goffice/gtk/go-font-sel.c
+++ b/goffice/gtk/go-font-sel.c
@@ -11,9 +11,6 @@
 #include <goffice/goffice-config.h>
 #include <goffice/goffice.h>
 
-#include <goffice/cut-n-paste/foocanvas/foo-canvas.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-text.h>
-
 #include <gsf/gsf-impl-utils.h>
 #include <glib/gi18n-lib.h>
 #include <errno.h>
@@ -32,8 +29,8 @@ struct _GOFontSel {
 	GtkTreeView	*font_style_list;
 	GtkTreeView	*font_size_list;
 
-	FooCanvas	*font_preview_canvas;
-	FooCanvasItem	*font_preview_text;
+	GocCanvas	*font_preview_canvas;
+	GocItem		*font_preview_text;
 
 	GOFont		*base, *current;
 	PangoAttrList	*modifications;
@@ -74,7 +71,7 @@ go_font_sel_emit_changed (GOFontSel *gfs)
 {
 	g_signal_emit (G_OBJECT (gfs),
 		gfs_signals [FONT_CHANGED], 0, gfs->modifications);
-	foo_canvas_item_set (gfs->font_preview_text,
+	goc_item_set (gfs->font_preview_text,
 		"attributes",  gfs->modifications,
 		NULL);
 }
@@ -326,13 +323,10 @@ canvas_size_changed (G_GNUC_UNUSED GtkWidget *widget,
 	int width  = allocation->width - 1;
 	int height = allocation->height - 1;
 
-	foo_canvas_item_set (gfs->font_preview_text,
+	goc_item_set (gfs->font_preview_text,
 		"x", (double)width/2.,
 		"y", (double)height/2.,
 		NULL);
-
-	foo_canvas_set_scroll_region (gfs->font_preview_canvas, 0, 0,
-				      width, height);
 }
 
 static void
@@ -356,18 +350,16 @@ gfs_init (GOFontSel *gfs)
 	gfs->font_style_list = GTK_TREE_VIEW (glade_xml_get_widget (gfs->gui, "font-style-list"));
 	gfs->font_size_list  = GTK_TREE_VIEW (glade_xml_get_widget (gfs->gui, "font-size-list"));
 
-	w = foo_canvas_new ();
-	gfs->font_preview_canvas = FOO_CANVAS (w);
-	foo_canvas_set_scroll_region (gfs->font_preview_canvas, -1, -1, INT_MAX/2, INT_MAX/2);
-	foo_canvas_scroll_to (gfs->font_preview_canvas, 0, 0);
+	w = GTK_WIDGET (g_object_new (GOC_TYPE_CANVAS, NULL));
+	gfs->font_preview_canvas = GOC_CANVAS (w);
 	gtk_widget_show_all (w);
 	w = glade_xml_get_widget (gfs->gui, "font-preview-frame");
 	gtk_container_add (GTK_CONTAINER (w), GTK_WIDGET (gfs->font_preview_canvas));
 
-	gfs->font_preview_text = FOO_CANVAS_ITEM (foo_canvas_item_new (
-		foo_canvas_root (gfs->font_preview_canvas),
-		FOO_TYPE_CANVAS_TEXT,
-		NULL));
+	gfs->font_preview_text = goc_item_new (
+		goc_canvas_get_root (gfs->font_preview_canvas),
+		GOC_TYPE_TEXT,
+		NULL);
 	go_font_sel_set_sample_text (gfs, NULL); /* init to default */
 
 	g_signal_connect (G_OBJECT (gfs->font_preview_canvas),
@@ -456,7 +448,7 @@ void
 go_font_sel_set_sample_text (GOFontSel *gfs, char const *text)
 {
 	g_return_if_fail (GO_IS_FONT_SEL (gfs));
-	foo_canvas_item_set (gfs->font_preview_text,
+	goc_item_set (gfs->font_preview_text,
 		/* xgettext: This text is used as a sample when selecting a font
 		 * please choose a translation that would produce common
 		 * characters specific to the target alphabet. */
diff --git a/goffice/gtk/go-rotation-sel.c b/goffice/gtk/go-rotation-sel.c
index ed97090..5c297cf 100644
--- a/goffice/gtk/go-rotation-sel.c
+++ b/goffice/gtk/go-rotation-sel.c
@@ -20,12 +20,6 @@
 #include <goffice/goffice-config.h>
 #include <goffice/goffice.h>
 
-#include <goffice/cut-n-paste/foocanvas/foo-canvas.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-util.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-line.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-widget.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-rect-ellipse.h>
-
 #include <gsf/gsf-impl-utils.h>
 #include <glib/gi18n-lib.h>
 #include <string.h>
@@ -36,11 +30,11 @@ struct _GORotationSel {
 	int		 angle;
 
 	GtkSpinButton	*rotate_spinner;
-	FooCanvas       *rotate_canvas;
-	FooCanvasItem   *rotate_marks[13];
-	FooCanvasItem   *line;
+	GocCanvas       *rotate_canvas;
+	GocItem		*rotate_marks[13];
+	GocItem		*line;
 	GtkWidget       *text_widget;
-	FooCanvasItem   *text;
+	GocItem		*text;
 	int		 rot_width, rot_height;
 	gulong		 motion_handle;
 };
@@ -61,7 +55,7 @@ static GObjectClass *grs_parent_class;
 static void
 cb_rotate_changed (GORotationSel *grs)
 {
-	char const *colour;
+	GOColor colour;
 	int i;
 
 	go_rotation_sel_set_rotation (grs,
@@ -69,67 +63,72 @@ cb_rotate_changed (GORotationSel *grs)
 
 	for (i = 0 ; i <= 12 ; i++)
 		if (grs->rotate_marks[i] != NULL) {
-			colour = (grs->angle == (i-6)*15) ? "green" : "black";
-			foo_canvas_item_set (grs->rotate_marks[i], "fill-color", colour, NULL);
+			GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (grs->rotate_marks[i]));
+			colour = (grs->angle == (i-6)*15) ? RGBA_GREEN : RGBA_BLACK;
+			if (style->fill.pattern.back != colour){
+				style->fill.pattern.back = colour;
+				goc_item_invalidate (grs->rotate_marks[i]);
+			}
 		}
 
 	if (grs->line != NULL) {
-		FooCanvasPoints *points = foo_canvas_points_new (2);
 		double rad = grs->angle * M_PI / 180.;
-		points->coords[0] =  15 + cos (rad) * grs->rot_width;
-		points->coords[1] = 100 - sin (rad) * grs->rot_width;
-		points->coords[2] =  15 + cos (rad) * 72.;
-		points->coords[3] = 100 - sin (rad) * 72.;
-		foo_canvas_item_set (grs->line, "points", points, NULL);
-		foo_canvas_points_free (points);
+		goc_item_set (grs->line, 
+		              "x0", 15 + cos (rad) * grs->rot_width,
+		              "y0", 100 - sin (rad) * grs->rot_width,
+		              "x1", 15 + cos (rad) * 72.,
+		              "y1", 100 - sin (rad) * 72.,
+		              NULL);
 	}
 
 	if (grs->text) {
 		double x = 15.0;
 		double y = 100.0;
 		double rad = grs->angle * M_PI / 180.;
+		double w = grs->rot_width * cos (fabs (rad)) + grs->rot_height * sin (fabs (rad));
+		double h = grs->rot_width * sin (fabs (rad)) + grs->rot_height * cos (fabs (rad));
 		x -= grs->rot_height * sin (fabs (rad)) / 2;
 		y -= grs->rot_height * cos (rad) / 2;
 		if (rad >= 0)
 			y -= grs->rot_width * sin (rad);
-		foo_canvas_item_set (grs->text, "x", x, "y", y, NULL);
+		goc_item_set (grs->text, "x", x, "y", y,
+		              "width", w, "height", h, NULL);
 		gtk_label_set_angle (GTK_LABEL (grs->text_widget),
 			(grs->angle + 360) % 360);
 	}
 }
 
 static void
-cb_rotate_canvas_realize (FooCanvas *canvas, GORotationSel *grs)
+cb_rotate_canvas_realize (GocCanvas *canvas, GORotationSel *grs)
 {
-	FooCanvasGroup  *group = FOO_CANVAS_GROUP (foo_canvas_root (canvas));
+	GocGroup  *group = goc_canvas_get_root (canvas);
 	int i;
+	GOStyle *go_style;
 	GtkStyle *style = gtk_style_copy (GTK_WIDGET (canvas)->style);
 	style->bg[GTK_STATE_NORMAL] = style->white;
 	gtk_widget_set_style (GTK_WIDGET (canvas), style);
 	g_object_unref (style);
 
-	foo_canvas_set_scroll_region (canvas, 0, 0, 100, 200);
-	foo_canvas_scroll_to (canvas, 0, 0);
-
 	for (i = 0 ; i <= 12 ; i++) {
 		double rad = (i-6) * M_PI / 12.;
 		double x = 15 + cos (rad) * 80.;
 		double y = 100 - sin (rad) * 80.;
 		double size = (i % 3) ? 3.0 : 4.0;
-		FooCanvasItem *item = foo_canvas_item_new (group,
-			FOO_TYPE_CANVAS_ELLIPSE,
-			"x1", x-size,	"y1", y-size,
-			"x2", x+size,	"y2", y+size,
-			"width-pixels", (int) 1,
-			"outline-color","black",
-			"fill-color",	"black",
+		GocItem *item = goc_item_new (group,
+			GOC_TYPE_CIRCLE,
+			"x", x,	"y", y,
+			"radius", size,
 			NULL);
+		go_style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+		go_style->outline.width = 1.;
+		go_style->outline.color = RGBA_BLACK;
+		go_style->fill.pattern.back = RGBA_BLACK;
 		grs->rotate_marks[i] = item;
 	}
-	grs->line = foo_canvas_item_new (group, FOO_TYPE_CANVAS_LINE,
-		"fill-color",	"black",
-		"width_units",	2.,
-		NULL);
+	grs->line = goc_item_new (group, GOC_TYPE_LINE, NULL);
+	go_style = go_styled_object_get_style (GO_STYLED_OBJECT (grs->line));
+	go_style->outline.width = 2.;
+	go_style->outline.color = RGBA_BLACK;
 
 	{
 		int w, h;
@@ -152,7 +151,7 @@ cb_rotate_canvas_realize (FooCanvas *canvas, GORotationSel *grs)
 		grs->rot_width  = w;
 		grs->rot_height = h;
 
-		grs->text = foo_canvas_item_new (group, FOO_TYPE_CANVAS_WIDGET,
+		grs->text = goc_item_new (group, GOC_TYPE_WIDGET,
 			"widget", tw, NULL);
 		gtk_widget_show (tw);
 	}
@@ -161,10 +160,9 @@ cb_rotate_canvas_realize (FooCanvas *canvas, GORotationSel *grs)
 }
 
 static void
-set_rot_from_point (GORotationSel *grs, FooCanvas *canvas, double x, double y)
+set_rot_from_point (GORotationSel *grs, double x, double y)
 {
 	double degrees;
-	foo_canvas_window_to_world (canvas, x, y, &x, &y);
 	x -= 15.;	if (x < 0.) x = 0.;
 	y -= 100.;
 
@@ -175,20 +173,20 @@ set_rot_from_point (GORotationSel *grs, FooCanvas *canvas, double x, double y)
 }
 
 static gboolean
-cb_rotate_motion_notify_event (FooCanvas *canvas, GdkEventMotion *event,
+cb_rotate_motion_notify_event (G_GNUC_UNUSED GocCanvas *canvas, GdkEventMotion *event,
 			       GORotationSel *grs)
 {
-	set_rot_from_point (grs, canvas, event->x, event->y);
+	set_rot_from_point (grs,  event->x, event->y);
 	return TRUE;
 }
 
 static gboolean
-cb_rotate_canvas_button (FooCanvas *canvas, GdkEventButton *event, GORotationSel *grs)
+cb_rotate_canvas_button (GocCanvas *canvas, GdkEventButton *event, GORotationSel *grs)
 {
 	if (event->type == GDK_BUTTON_PRESS) {
-		set_rot_from_point (grs, canvas, event->x, event->y);
+		set_rot_from_point (grs, event->x, event->y);
 		if (grs->motion_handle == 0) {
-			gdk_pointer_grab (canvas->layout.bin_window, FALSE,
+			gdk_pointer_grab (canvas->base.bin_window, FALSE,
 				GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
 				NULL, NULL, event->time);
 
@@ -221,7 +219,7 @@ grs_init (GORotationSel *grs)
 	grs->line  = NULL;
 	grs->text  = NULL;
 	grs->text_widget = NULL;
-	grs->rotate_canvas = FOO_CANVAS (foo_canvas_new ());
+	grs->rotate_canvas = GOC_CANVAS (g_object_new (GOC_TYPE_CANVAS, NULL));
 	gtk_container_add (GTK_CONTAINER (glade_xml_get_widget (grs->gui,
 		"rotate_canvas_container")),
 		GTK_WIDGET (grs->rotate_canvas));
diff --git a/goffice/utils/go-style.c b/goffice/utils/go-style.c
index fbb5253..ab785fe 100644
--- a/goffice/utils/go-style.c
+++ b/goffice/utils/go-style.c
@@ -1176,8 +1176,10 @@ go_style_init (GOStyle *style)
 	style->disable_theming = 0;
 	go_style_force_auto (style);
 	style->line.dash_type = GO_LINE_SOLID;
-	style->outline.dash_type = GO_LINE_SOLID;
-	style->outline.width = 0;
+	style->line.width = 0;
+	style->line.cap = CAIRO_LINE_CAP_BUTT;
+	style->line.join = CAIRO_LINE_JOIN_MITER;
+	style->line.miter_limit = 10.;
 	style->fill.type = GO_STYLE_FILL_NONE;
 	style->fill.gradient.brightness = -1.;
 	go_pattern_set_solid (&style->fill.pattern, RGBA_BLACK);
diff --git a/goffice/utils/go-style.h b/goffice/utils/go-style.h
index 985b4a0..8b5d2ed 100644
--- a/goffice/utils/go-style.h
+++ b/goffice/utils/go-style.h
@@ -64,10 +64,15 @@ typedef struct {
 	float	 	 width;
 	GOLineDashType 	 dash_type;
 	gboolean	 auto_dash;
-	GOColor	 	 color;
+	GOColor	 	 color; /* color is used as background for compatibility
+						(pattern == 0 means filled with background color) */
+	GOColor	 	 fore;
 	gboolean 	 auto_color;
-	unsigned	 pattern_unimplemented_yet; /* TODO: implement. Not used
-				and must not be used before implementation */
+	gboolean 	 auto_fore;
+	GOPatternType	 pattern;
+	cairo_line_cap_t cap;
+	cairo_line_join_t join;
+	double		 miter_limit;
 } GOStyleLine;
 
 typedef struct {
@@ -83,7 +88,7 @@ struct _GOStyle {
 	GOStyleFlag	interesting_fields;
 	GOStyleFlag	disable_theming;
 
-	GOStyleLine	outline, line;
+	union {GOStyleLine	outline, line;};
 	struct {
 		GOStyleFill	type;
 		gboolean	auto_type;
diff --git a/goffice/utils/go-styled-object.c b/goffice/utils/go-styled-object.c
index 8c0d448..be4b610 100644
--- a/goffice/utils/go-styled-object.c
+++ b/goffice/utils/go-styled-object.c
@@ -139,3 +139,70 @@ go_styled_object_get_document (GOStyledObject *gso)
 	return (klass->get_document)?
 		klass->get_document (gso): NULL;
 }
+
+gboolean
+go_styled_object_set_cairo_line (GOStyledObject const *so, cairo_t *cr)
+{
+	GOStyle const *style;
+	double width;
+	GOLineDashSequence *line_dash;
+
+	g_return_val_if_fail (GO_IS_STYLED_OBJECT (so), FALSE);
+	style = go_styled_object_get_style (GO_STYLED_OBJECT (so));
+	if (style->line.dash_type == GO_LINE_NONE)
+		return FALSE;
+	width = (style->line.width)? style->line.width: 1.;
+	cairo_set_line_width (cr, width);
+	cairo_set_line_cap (cr, style->line.cap);
+	cairo_set_line_join (cr, style->line.join);
+	cairo_set_miter_limit (cr, style->line.miter_limit);
+	line_dash = go_line_dash_get_sequence (style->line.dash_type, width);
+	if (line_dash != NULL)
+		cairo_set_dash (cr,
+				line_dash->dash,
+				line_dash->n_dash,
+				line_dash->offset);
+	else
+		cairo_set_dash (cr, NULL, 0, 0);
+	switch (style->line.pattern) {
+	case GO_PATTERN_SOLID:
+		cairo_set_source_rgba (cr, GO_COLOR_TO_CAIRO (style->line.color));
+		break;
+	case GO_PATTERN_FOREGROUND_SOLID:
+		cairo_set_source_rgba (cr, GO_COLOR_TO_CAIRO (style->line.fore));
+		break;
+	default: {
+		GOPattern pat;
+		double scalex = 1., scaley = 1.;
+		cairo_pattern_t *cp;
+		cairo_matrix_t mat;
+		pat.fore = style->line.fore;
+		pat.back = style->line.color;
+		pat.pattern = style->line.pattern;
+		cp = go_pattern_create_cairo_pattern (&pat, cr);
+		cairo_user_to_device_distance (cr, &scalex, &scaley);
+		cairo_matrix_init_scale (&mat, scalex, scaley);
+		cairo_pattern_set_matrix (cp, &mat);
+		cairo_set_source (cr, cp);
+		break;
+	}
+	}
+	return TRUE;
+}
+
+gboolean
+go_styled_object_set_cairo_fill (GOStyledObject const *so, cairo_t *cr)
+{
+	GOStyle const *style;
+	cairo_pattern_t *pat = NULL;
+
+	g_return_val_if_fail (GO_IS_STYLED_OBJECT (so), FALSE);
+	style = go_styled_object_get_style (GO_STYLED_OBJECT (so));
+	pat = go_style_create_cairo_pattern (style, cr);
+	if (pat) {
+		cairo_set_source (cr, pat);
+		cairo_pattern_destroy (pat);
+	}
+	return TRUE;
+}
+
diff --git a/goffice/utils/go-styled-object.h b/goffice/utils/go-styled-object.h
index 10369b4..a8b75db 100644
--- a/goffice/utils/go-styled-object.h
+++ b/goffice/utils/go-styled-object.h
@@ -53,6 +53,8 @@ GOStyle	 *go_styled_object_get_auto_style  (GOStyledObject *gso);
 void	  go_styled_object_style_changed   (GOStyledObject *gso);
 void	  go_styled_object_apply_theme	   (GOStyledObject *gso, GOStyle *style);
 GODoc	 *go_styled_object_get_document	   (GOStyledObject *gso);
+gboolean  go_styled_object_set_cairo_line  (GOStyledObject const *so, cairo_t *cr);
+gboolean  go_styled_object_set_cairo_fill  (GOStyledObject const *so, cairo_t *cr);
 G_END_DECLS
 
 #endif



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