[goocanvas/new-api] 2010-06-28 Damon Chaplin <damon gnome org>



commit b86d6011579af3acf52a21de58ea974c55ba537c
Author: Damon Chaplin <damon gnome org>
Date:   Mon Jun 28 12:21:33 2010 +0100

    2010-06-28  Damon Chaplin  <damon gnome org>
    
    	    * Made GooCanvasItemSimple implement the group methods, so all
    	    subclasses can have child items.
    
    	    Added "Groups" demo page to test this.
    
    	    Removed "Scalability" demo page as it wasn't very useful and we have
    	    the separate scalability test app which is a better scalability test.

 ChangeLog                 |   10 +
 demo/Makefile.am          |    2 +-
 demo/demo-groups.c        |  281 ++++++++++++++++++++++++++++
 demo/demo-scalability.c   |   95 ----------
 demo/demo.c               |   35 +++-
 demo/scalability-demo.c   |    8 +-
 src/goocanvasgroup.c      |  320 +++++---------------------------
 src/goocanvasgroup.h      |    4 -
 src/goocanvasitemsimple.c |  443 +++++++++++++++++++++++++++++++++++++++++++--
 src/goocanvasitemsimple.h |    4 +
 src/goocanvastable.c      |   78 +++++---
 11 files changed, 859 insertions(+), 421 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 0237317..4dde2eb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 2010-06-28  Damon Chaplin  <damon gnome org>
 
+	* Made GooCanvasItemSimple implement the group methods, so all
+	subclasses can have child items.
+
+	Added "Groups" demo page to test this.
+
+	Removed "Scalability" demo page as it wasn't very useful and we have
+	the separate scalability test app which is a better scalability test.
+
+2010-06-28  Damon Chaplin  <damon gnome org>
+
 	* src/goocanvasgroup.c (goo_canvas_group_paint): use the scale
 	argument rather than the canvas scale.
 
diff --git a/demo/Makefile.am b/demo/Makefile.am
index 2dada07..b9db404 100644
--- a/demo/Makefile.am
+++ b/demo/Makefile.am
@@ -14,7 +14,7 @@ DEMO_LIBS = $(top_builddir)/src/libgoocanvas-2.0.la @PACKAGE_LIBS@ $(INTLLIBS)
 noinst_PROGRAMS = demo table-demo generic-position-demo simple-demo scalability-demo units-demo widgets-demo
 
 demo_SOURCES = \
-	demo.c demo-fifteen.c demo-scalability.c demo-grabs.c \
+	demo.c demo-fifteen.c demo-groups.c demo-grabs.c \
 	demo-arrowhead.c demo-features.c demo-events.c \
 	demo-paths.c demo-focus.c demo-item.h demo-item.c demo-animation.c \
 	demo-clipping.c demo-table.c demo-large-line.h demo-large-line.c \
diff --git a/demo/demo-groups.c b/demo/demo-groups.c
new file mode 100644
index 0000000..2e69f58
--- /dev/null
+++ b/demo/demo-groups.c
@@ -0,0 +1,281 @@
+#include <config.h>
+#include <gtk/gtk.h>
+#include <goocanvas.h>
+
+
+static gboolean dragging = FALSE;
+static double drag_x, drag_y;
+
+static gboolean
+on_button_press (GooCanvasItem *item,
+		 GooCanvasItem *target,
+		 GdkEventButton *event,
+		 gpointer data)
+{
+  GooCanvas *canvas;
+  GdkCursor *fleur;
+  GList *items, *elem;
+
+  g_print ("%p received 'button-press' signal at %g, %g (root: %g, %g)\n",
+	   item, event->x, event->y, event->x_root, event->y_root);
+
+  canvas = goo_canvas_item_get_canvas (item);
+  items = goo_canvas_get_items_at (canvas, event->x_root, event->y_root,
+				   TRUE);
+  for (elem = items; elem; elem = elem->next)
+    g_print ("  found items: %p\n", elem->data);
+  g_list_free (items);
+
+  switch (event->button)
+    {
+    case 1:
+      if (event->state & GDK_SHIFT_MASK)
+	{
+	  goo_canvas_item_remove (item);
+	}
+      else
+	{
+	  drag_x = event->x;
+	  drag_y = event->y;
+
+	  fleur = gdk_cursor_new (GDK_FLEUR);
+	  goo_canvas_pointer_grab (canvas, item,
+				   GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_RELEASE_MASK,
+				   fleur,
+				   event->time);
+	  gdk_cursor_unref (fleur);
+	  dragging = TRUE;
+	}
+      break;
+
+    case 2:
+      goo_canvas_item_lower (item, NULL);
+      break;
+
+    case 3:
+      goo_canvas_item_raise (item, NULL);
+      break;
+
+    default:
+      break;
+    }
+
+  return TRUE;
+}
+
+
+static gboolean
+on_motion_notify (GooCanvasItem *item,
+		  GooCanvasItem *target,
+		  GdkEventMotion *event,
+		  gpointer data)
+{
+#if 0
+  g_print ("received 'motion-notify' signal at %g, %g\n",
+	   event->x, event->y);
+#endif
+
+  if (dragging && (event->state & GDK_BUTTON1_MASK))
+    {
+      double new_x = event->x;
+      double new_y = event->y;
+
+      goo_canvas_item_translate (item, new_x - drag_x, new_y - drag_y);
+    }
+
+  return TRUE;
+}
+
+
+static gboolean
+on_button_release (GooCanvasItem *item,
+		   GooCanvasItem *target,
+		   GdkEventButton *event,
+		   gpointer data)
+{
+  GooCanvas *canvas;
+
+#if 0
+  g_print ("received 'button-release' signal\n");
+#endif
+
+  canvas = goo_canvas_item_get_canvas (item);
+  goo_canvas_pointer_ungrab (canvas, item, event->time);
+  dragging = FALSE;
+
+  return TRUE;
+}
+
+
+static void
+setup_item_signals (GooCanvasItem *item)
+{
+  g_signal_connect (item, "motion_notify_event",
+		    G_CALLBACK (on_motion_notify), NULL);
+  g_signal_connect (item, "button_press_event",
+		    G_CALLBACK (on_button_press), NULL);
+  g_signal_connect (item, "button_release_event",
+		    G_CALLBACK (on_button_release), NULL);
+}
+
+
+static void
+set_item_id (GooCanvasItem *item,
+	     gchar         *group_name,
+	     gchar         *item_name)
+{
+  gchar *id = g_strdup_printf ("%s - %s", group_name, item_name);
+  g_object_set_data_full (G_OBJECT (item), "id", id, g_free);
+}
+
+
+static GooCanvasItem*
+create_group (GooCanvasItem *parent,
+	      gdouble        x,
+	      gdouble        y,
+	      gdouble        width,
+	      gdouble        height,
+	      gchar         *clip_path,
+	      gchar         *group_name)
+{
+  GooCanvasItem *group, *child;
+  gdouble handle_width = 20, handle_height = 20;
+  gdouble half_handle_width = handle_width / 2;
+  gdouble half_handle_height = handle_height / 2;
+
+  group = goo_canvas_rect_new (parent, x, y, width, height,
+			       "fill-color", "blue",
+			       "line-width", 4.0,
+			       "clip-path", clip_path,
+			       NULL);
+  setup_item_signals (group);
+  set_item_id (group, group_name, "group");
+
+  child = goo_canvas_rect_new (group,
+			       x - half_handle_width,
+			       y - half_handle_height,
+			       handle_width, handle_height,
+			      "fill-color", "orange",
+			      NULL);
+  setup_item_signals (child);
+  set_item_id (child, group_name, "Item1");
+
+  child = goo_canvas_rect_new (group,
+			       x + width - half_handle_width,
+			       y - half_handle_height,
+			       handle_width, handle_height,
+			      "fill-color", "orange",
+			      NULL);
+  setup_item_signals (child);
+  set_item_id (child, group_name, "Item2");
+#if 1
+  goo_canvas_item_rotate (child, 30, x + width, y);
+#endif
+
+  child = goo_canvas_rect_new (group,
+			       x - half_handle_width,
+			       y + height - half_handle_height,
+			       handle_width, handle_height,
+			      "fill-color", "orange",
+			      "tooltip", "Child of Medium Sea Green stippled rectangle",
+			      NULL);
+  setup_item_signals (child);
+  set_item_id (child, group_name, "Item3");
+
+  child = goo_canvas_rect_new (group,
+			       x + width - half_handle_width,
+			       y + height - half_handle_height,
+			       handle_width, handle_height,
+			      "fill-color", "orange",
+			      "tooltip", "Child of Medium Sea Green stippled rectangle",
+			      NULL);
+  setup_item_signals (child);
+  set_item_id (child, group_name, "Item4");
+
+  return group;
+}
+
+
+static GooCanvasItem*
+create_table_group (GooCanvasItem *table,
+		    gint           row,
+		    gint           column,
+		    gchar         *group_name)
+{
+  GooCanvasItem *group;
+
+  group = create_group (table, 0, 0, 50, 50, NULL, group_name);
+
+  goo_canvas_item_set_child_properties (table, group,
+					"row", row,
+					"column", column,
+					NULL);
+
+  return group;
+}
+
+
+GtkWidget *
+create_canvas_groups (void)
+{
+  GtkWidget *vbox;
+  GtkWidget *scrolled_win, *canvas;
+  GooCanvasItem *root, *group, *table;
+
+  vbox = gtk_vbox_new (FALSE, 4);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
+  gtk_widget_show (vbox);
+
+  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win),
+				       GTK_SHADOW_IN);
+  gtk_widget_show (scrolled_win);
+  gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
+
+  canvas = goo_canvas_new ();
+  gtk_widget_set_size_request (canvas, 600, 450);
+  goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 1000, 1000);
+  gtk_widget_show (canvas);
+  gtk_container_add (GTK_CONTAINER (scrolled_win), canvas);
+
+  root = goo_canvas_get_root_item (GOO_CANVAS (canvas));
+
+#if 1
+  group = create_group (root, 100, 100, 50, 50, NULL, NULL);
+  group = create_group (root, 300, 100, 80, 40,
+			"M300,100 l80,0 l0,20 l-80,20 z", NULL);
+  group = create_group (root, 500, 100, 80, 40,
+			"M500,100 l80,0 l0,20 l-80,20 z", NULL);
+  goo_canvas_item_rotate (group, 45, 540, 120);
+#endif
+
+  table = goo_canvas_table_new (root,
+#if 1
+				"x", 200.0,
+				"y", 250.0,
+#endif
+				"row-spacing", 4.0,
+				"column-spacing", 4.0,
+				NULL);
+  group = create_table_group (table, 0, 0, "Group1");
+  group = create_table_group (table, 0, 1, "Group2");
+  goo_canvas_item_rotate (group, 45, 0, 0);
+  group = create_table_group (table, 0, 2, "Group3");
+
+  group = create_table_group (table, 1, 0, "Group1");
+  goo_canvas_item_rotate (group, 45, 0, 0);
+  group = create_table_group (table, 1, 1, "Group2");
+  group = create_table_group (table, 1, 2, "Group3");
+  goo_canvas_item_rotate (group, 45, 0, 0);
+
+  group = create_table_group (table, 2, 0, "Group1");
+  group = create_table_group (table, 2, 1, "Group2");
+  goo_canvas_item_rotate (group, 45, 0, 0);
+  group = create_table_group (table, 2, 2, "Group3");
+
+#if 1
+  goo_canvas_item_rotate (table, 45, 300, 350);
+#endif
+
+  return vbox;
+}
diff --git a/demo/demo.c b/demo/demo.c
index 7094ea4..e15c0cd 100644
--- a/demo/demo.c
+++ b/demo/demo.c
@@ -26,7 +26,7 @@ static void setup_canvas (GooCanvas *canvas);
 GtkWidget *create_canvas_fifteen (void);
 GtkWidget *create_canvas_features (void);
 GtkWidget *create_canvas_arrowhead (void);
-GtkWidget *create_canvas_scalability (void);
+GtkWidget *create_canvas_groups (void);
 GtkWidget *create_grabs_page (void);
 GtkWidget *create_events_page (void);
 GtkWidget *create_paths_page (void);
@@ -844,7 +844,7 @@ create_stipple (const char *color_name, guchar stipple_data[16])
 static void
 setup_rectangles (GooCanvasItem *root)
 {
-  GooCanvasItem *item;
+  GooCanvasItem *item, *child;
   cairo_pattern_t *pattern;
   static guchar stipple_data[16] = {
     0, 0, 0, 255,   0, 0, 0, 0,   0, 0, 0, 0,     0, 0, 0, 255
@@ -867,6 +867,32 @@ setup_rectangles (GooCanvasItem *root)
   cairo_pattern_destroy (pattern);
   setup_item_signals (item);
 
+  child = goo_canvas_rect_new (item, 80, 30, 20, 20,
+			      "fill-color", "orange",
+			      "tooltip", "Child of Medium Sea Green stippled rectangle",
+			      NULL);
+  setup_item_signals (child);
+
+  child = goo_canvas_rect_new (item, 170, 30, 20, 20,
+			      "fill-color", "orange",
+			      "tooltip", "Child of Medium Sea Green stippled rectangle",
+			      NULL);
+  setup_item_signals (child);
+
+  child = goo_canvas_rect_new (item, 80, 90, 20, 20,
+			      "fill-color", "orange",
+			      "tooltip", "Child of Medium Sea Green stippled rectangle",
+			      NULL);
+  setup_item_signals (child);
+
+  child = goo_canvas_rect_new (item, 170, 90, 20, 20,
+			      "fill-color", "orange",
+			      "tooltip", "Child of Medium Sea Green stippled rectangle",
+			      NULL);
+  setup_item_signals (child);
+
+
+
   item = goo_canvas_rect_new (root, 10, 80, 70, 60,
 			      "fill-color", "steelblue",
 			      /*"fill-pattern", NULL,*/
@@ -1554,6 +1580,7 @@ create_window ()
 		    NULL);
 
   notebook = gtk_notebook_new ();
+  gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
   gtk_widget_show (notebook);
   gtk_container_add (GTK_CONTAINER (window), notebook);
 
@@ -1579,8 +1606,8 @@ create_window ()
 #endif
 #if 1
   gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
-			    create_canvas_scalability (),
-			    gtk_label_new ("Scalability"));
+			    create_canvas_groups (),
+			    gtk_label_new ("Groups"));
 #endif
 #if 1
   gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
diff --git a/demo/scalability-demo.c b/demo/scalability-demo.c
index b507060..67d72b5 100644
--- a/demo/scalability-demo.c
+++ b/demo/scalability-demo.c
@@ -36,6 +36,10 @@
 #define USE_TEXT
 #endif
 
+#if 1
+#define SET_IDS
+#endif
+
 #if 0
 #define USE_PIXMAP 
 #endif
@@ -181,7 +185,7 @@ setup_canvas (GtkWidget *canvas)
 		  goo_canvas_item_set_transform (item, &item_matrix);
 #endif
 #endif
-#if 1
+#ifdef SET_IDS
 		  g_object_set_qdata (G_OBJECT (item), id_quark,
 				      ids[id_item_num]);
 #endif
@@ -289,7 +293,9 @@ create_canvas (void)
   left_offset = -total_width / 2;
   top_offset = -total_height / 2;
 
+#ifdef SET_IDS
   init_ids ();
+#endif
 
   /* Create the canvas. */
   canvas = goo_canvas_new ();
diff --git a/src/goocanvasgroup.c b/src/goocanvasgroup.c
index bb3c68a..fa34f8b 100644
--- a/src/goocanvasgroup.c
+++ b/src/goocanvasgroup.c
@@ -59,8 +59,6 @@ G_DEFINE_TYPE (GooCanvasGroup, goo_canvas_group, GOO_TYPE_CANVAS_ITEM_SIMPLE)
 static void
 goo_canvas_group_init (GooCanvasGroup *group)
 {
-  group->items = g_ptr_array_sized_new (8);
-
   group->x = 0.0;
   group->y = 0.0;
   group->width = -1.0;
@@ -108,37 +106,6 @@ goo_canvas_group_new (GooCanvasItem *parent,
 
 
 static void
-goo_canvas_group_dispose (GObject *object)
-{
-  GooCanvasGroup *group = (GooCanvasGroup*) object;
-  gint i;
-
-  /* Unref all the items in the group. */
-  for (i = 0; i < group->items->len; i++)
-    {
-      GooCanvasItem *item = group->items->pdata[i];
-      goo_canvas_item_set_parent (item, NULL);
-      g_object_unref (item);
-    }
-
-  g_ptr_array_set_size (group->items, 0);
-
-  G_OBJECT_CLASS (goo_canvas_group_parent_class)->dispose (object);
-}
-
-
-static void
-goo_canvas_group_finalize (GObject *object)
-{
-  GooCanvasGroup *group = (GooCanvasGroup*) object;
-
-  g_ptr_array_free (group->items, TRUE);
-
-  G_OBJECT_CLASS (goo_canvas_group_parent_class)->finalize (object);
-}
-
-
-static void
 goo_canvas_group_get_property (GObject               *object,
                                guint                  prop_id,
                                GValue                *value,
@@ -200,191 +167,6 @@ goo_canvas_group_set_property (GObject                  *object,
 
 
 static void
-goo_canvas_group_add_child     (GooCanvasItem  *item,
-				GooCanvasItem  *child,
-				gint            position)
-{
-  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
-  GooCanvasGroup *group = (GooCanvasGroup*) item;
-  AtkObject *atk_obj, *child_atk_obj;
-
-  g_object_ref (child);
-
-  if (position >= 0)
-    {
-      goo_canvas_util_ptr_array_insert (group->items, child, position);
-    }
-  else
-    {
-      position = group->items->len;
-      g_ptr_array_add (group->items, child);
-    }
-
-  goo_canvas_item_set_parent (child, item);
-  goo_canvas_item_set_is_static (child, simple->is_static);
-
-  /* Emit the "children_changed" ATK signal, if ATK is enabled. */
-  atk_obj = atk_gobject_accessible_for_object (G_OBJECT (item));
-  if (!ATK_IS_NO_OP_OBJECT (atk_obj))
-    {
-      child_atk_obj = atk_gobject_accessible_for_object (G_OBJECT (child));
-      g_signal_emit_by_name (atk_obj, "children_changed::add",
-			     position, child_atk_obj);
-    }
-
-  goo_canvas_item_request_update (item);
-}
-
-
-static void
-goo_canvas_group_move_child    (GooCanvasItem  *item,
-				gint	        old_position,
-				gint            new_position)
-{
-  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
-  GooCanvasGroup *group = (GooCanvasGroup*) item;
-  GooCanvasItem *child;
-  GooCanvasBounds bounds;
-
-  /* Request a redraw of the item's bounds. */
-  child = group->items->pdata[old_position];
-  if (simple->canvas)
-    {
-      goo_canvas_item_get_bounds (child, &bounds);
-      goo_canvas_request_item_redraw (simple->canvas, &bounds,
-				      simple->is_static);
-    }
-
-  goo_canvas_util_ptr_array_move (group->items, old_position, new_position);
-
-  goo_canvas_item_request_update (item);
-}
-
-
-static void
-goo_canvas_group_remove_child  (GooCanvasItem  *item,
-				gint            child_num)
-{
-  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
-  GooCanvasGroup *group = (GooCanvasGroup*) item;
-  GooCanvasItem *child;
-  GooCanvasBounds bounds;
-  AtkObject *atk_obj, *child_atk_obj;
-
-  g_return_if_fail (child_num < group->items->len);
-
-  /* Request a redraw of the item's bounds. */
-  child = group->items->pdata[child_num];
-  if (simple->canvas)
-    {
-      goo_canvas_item_get_bounds (child, &bounds);
-      goo_canvas_request_item_redraw (simple->canvas, &bounds,
-				      simple->is_static);
-    }
-
-  /* Emit the "children_changed" ATK signal, if ATK is enabled. */
-  atk_obj = atk_gobject_accessible_for_object (G_OBJECT (item));
-  if (!ATK_IS_NO_OP_OBJECT (atk_obj))
-    {
-      child_atk_obj = atk_gobject_accessible_for_object (G_OBJECT (child));
-      g_signal_emit_by_name (atk_obj, "children_changed::remove",
-			     child_num, child_atk_obj);
-    }
-
-  g_ptr_array_remove_index (group->items, child_num);
-
-  goo_canvas_item_set_parent (child, NULL);
-  g_object_unref (child);
-
-  goo_canvas_item_request_update (item);
-}
-
-
-static gint
-goo_canvas_group_get_n_children (GooCanvasItem  *item)
-{
-  GooCanvasGroup *group = (GooCanvasGroup*) item;
-
-  return group->items->len;
-}
-
-
-static GooCanvasItem*
-goo_canvas_group_get_child   (GooCanvasItem       *item,
-			      gint                 child_num)
-{
-  GooCanvasGroup *group = (GooCanvasGroup*) item;
-
-  if (child_num < group->items->len)
-    return group->items->pdata[child_num];
-  return NULL;
-}
-
-
-/* This is only used to set the canvas of the root group. It isn't normally
-   needed by apps. */
-static void
-goo_canvas_group_set_canvas  (GooCanvasItem *item,
-			      GooCanvas     *canvas)
-{
-  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
-  GooCanvasGroup *group = (GooCanvasGroup*) item;
-  gint i;
-
-  if (simple->canvas == canvas)
-    return;
-
-  simple->canvas = canvas;
-
-  /* Recursively set the canvas of all child items. */
-  for (i = 0; i < group->items->len; i++)
-    {
-      GooCanvasItem *item = group->items->pdata[i];
-      goo_canvas_item_set_canvas (item, canvas);
-    }
-}
-
-
-static void
-goo_canvas_group_set_is_static  (GooCanvasItem *item,
-				 gboolean       is_static)
-{
-  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
-  GooCanvasGroup *group = (GooCanvasGroup*) item;
-  gint i;
-
-  if (simple->is_static == is_static)
-    return;
-
-  simple->is_static = is_static;
-
-  /* Recursively set the canvas of all child items. */
-  for (i = 0; i < group->items->len; i++)
-    {
-      GooCanvasItem *item = group->items->pdata[i];
-      goo_canvas_item_set_is_static (item, is_static);
-    }
-}
-
-
-static void
-goo_canvas_group_request_update  (GooCanvasItem *item)
-{
-  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
-
-  if (!simple->need_update)
-    {
-      simple->need_update = TRUE;
-
-      if (simple->parent)
-	goo_canvas_item_request_update (simple->parent);
-      else if (simple->canvas)
-	goo_canvas_request_update (simple->canvas);
-    }
-}
-
-
-static void
 goo_canvas_group_update  (GooCanvasItem   *item,
 			  gboolean         entire_tree,
 			  cairo_t         *cr,
@@ -407,41 +189,44 @@ goo_canvas_group_update  (GooCanvasItem   *item,
       simple->bounds.x1 = simple->bounds.y1 = 0.0;
       simple->bounds.x2 = simple->bounds.y2 = 0.0;
 
-      cairo_save (cr);
-      if (simple->transform)
-        cairo_transform (cr, simple->transform);
+      if (simple->children)
+	{
+	  cairo_save (cr);
+	  if (simple->transform)
+	    cairo_transform (cr, simple->transform);
 
-      cairo_translate (cr, group->x, group->y);
+	  cairo_translate (cr, group->x, group->y);
 
-      for (i = 0; i < group->items->len; i++)
-        {
-          GooCanvasItem *child = group->items->pdata[i];
+	  for (i = 0; i < simple->children->len; i++)
+	    {
+	      GooCanvasItem *child = simple->children->pdata[i];
 
-          goo_canvas_item_update (child, entire_tree, cr, &child_bounds);
+	      goo_canvas_item_update (child, entire_tree, cr, &child_bounds);
           
-          /* If the child has non-empty bounds, compute the union. */
-          if (child_bounds.x1 < child_bounds.x2
-              && child_bounds.y1 < child_bounds.y2)
-            {
-              if (initial_bounds)
-                {
-                  simple->bounds.x1 = child_bounds.x1;
-                  simple->bounds.y1 = child_bounds.y1;
-                  simple->bounds.x2 = child_bounds.x2;
-                  simple->bounds.y2 = child_bounds.y2;
-                  initial_bounds = FALSE;
-                }
-              else
-                {
-                  simple->bounds.x1 = MIN (simple->bounds.x1, child_bounds.x1);
-                  simple->bounds.y1 = MIN (simple->bounds.y1, child_bounds.y1);
-                  simple->bounds.x2 = MAX (simple->bounds.x2, child_bounds.x2);
-                  simple->bounds.y2 = MAX (simple->bounds.y2, child_bounds.y2);
-                }
-            }
-        }
-
-      cairo_restore (cr);
+	      /* If the child has non-empty bounds, compute the union. */
+	      if (child_bounds.x1 < child_bounds.x2
+		  && child_bounds.y1 < child_bounds.y2)
+		{
+		  if (initial_bounds)
+		    {
+		      simple->bounds.x1 = child_bounds.x1;
+		      simple->bounds.y1 = child_bounds.y1;
+		      simple->bounds.x2 = child_bounds.x2;
+		      simple->bounds.y2 = child_bounds.y2;
+		      initial_bounds = FALSE;
+		    }
+		  else
+		    {
+		      simple->bounds.x1 = MIN (simple->bounds.x1, child_bounds.x1);
+		      simple->bounds.y1 = MIN (simple->bounds.y1, child_bounds.y1);
+		      simple->bounds.x2 = MAX (simple->bounds.x2, child_bounds.x2);
+		      simple->bounds.y2 = MAX (simple->bounds.y2, child_bounds.y2);
+		    }
+		}
+	    }
+
+	  cairo_restore (cr);
+	}
     }
 
   *bounds = simple->bounds;
@@ -518,14 +303,18 @@ goo_canvas_group_get_items_at (GooCanvasItem  *item,
 
   /* Step up from the bottom of the children to the top, adding any items
      found to the start of the list. */
-  for (i = 0; i < group->items->len; i++)
+  if (simple->children)
     {
-      GooCanvasItem *child = group->items->pdata[i];
+      for (i = 0; i < simple->children->len; i++)
+	{
+	  GooCanvasItem *child = simple->children->pdata[i];
 
-      found_items = goo_canvas_item_get_items_at (child, x, y, cr,
-						  is_pointer_event, visible,
-						  found_items);
+	  found_items = goo_canvas_item_get_items_at (child, x, y, cr,
+						      is_pointer_event, visible,
+						      found_items);
+	}
     }
+
   cairo_restore (cr);
 
   return found_items;
@@ -574,11 +363,15 @@ goo_canvas_group_paint (GooCanvasItem         *item,
       cairo_clip (cr);
     }
 
-  for (i = 0; i < group->items->len; i++)
+  if (simple->children)
     {
-      GooCanvasItem *child = group->items->pdata[i];
-      goo_canvas_item_paint (child, cr, bounds, scale);
+      for (i = 0; i < simple->children->len; i++)
+	{
+	  GooCanvasItem *child = simple->children->pdata[i];
+	  goo_canvas_item_paint (child, cr, bounds, scale);
+	}
     }
+
   cairo_restore (cr);
 }
 
@@ -589,26 +382,13 @@ goo_canvas_group_class_init (GooCanvasGroupClass *klass)
   GObjectClass *gobject_class = (GObjectClass*) klass;
   GooCanvasItemClass *item_class = (GooCanvasItemClass*) klass;
 
-  gobject_class->dispose  = goo_canvas_group_dispose;
-  gobject_class->finalize = goo_canvas_group_finalize;
   gobject_class->get_property = goo_canvas_group_get_property;
   gobject_class->set_property = goo_canvas_group_set_property;
 
-  item_class->set_canvas     = goo_canvas_group_set_canvas;
-  item_class->get_n_children = goo_canvas_group_get_n_children;
-  item_class->get_child      = goo_canvas_group_get_child;
-  item_class->request_update = goo_canvas_group_request_update;
-
-  item_class->add_child      = goo_canvas_group_add_child;
-  item_class->move_child     = goo_canvas_group_move_child;
-  item_class->remove_child   = goo_canvas_group_remove_child;
-
   item_class->get_items_at   = goo_canvas_group_get_items_at;
   item_class->update         = goo_canvas_group_update;
   item_class->paint          = goo_canvas_group_paint;
 
-  item_class->set_is_static  = goo_canvas_group_set_is_static;
-
   /* Register our accessible factory, but only if accessibility is enabled. */
   if (!ATK_IS_NO_OP_OBJECT_FACTORY (atk_registry_get_factory (atk_get_default_registry (), GTK_TYPE_WIDGET)))
     {
diff --git a/src/goocanvasgroup.h b/src/goocanvasgroup.h
index aa0e189..0ceb981 100644
--- a/src/goocanvasgroup.h
+++ b/src/goocanvasgroup.h
@@ -35,10 +35,6 @@ struct _GooCanvasGroup
 {
   GooCanvasItemSimple parent_object;
 
-  /* An array of pointers to GooCanvasItems. The first element is at the
-     bottom of the display stack and the last element is at the top. */
-  GPtrArray *items;
-
   gdouble x, y, width, height;
 };
 
diff --git a/src/goocanvasitemsimple.c b/src/goocanvasitemsimple.c
index 7522427..6581ea1 100644
--- a/src/goocanvasitemsimple.c
+++ b/src/goocanvasitemsimple.c
@@ -87,6 +87,16 @@ enum {
 
 static gboolean accessibility_enabled = FALSE;
 
+#define HORZ 0
+#define VERT 1
+
+typedef struct _GooCanvasItemSimpleChildLayoutData GooCanvasItemSimpleChildLayoutData;
+struct _GooCanvasItemSimpleChildLayoutData
+{
+  gdouble requested_position[2];
+  gdouble requested_size[2];
+};
+
 
 G_DEFINE_TYPE (GooCanvasItemSimple, goo_canvas_item_simple,
 	       GOO_TYPE_CANVAS_ITEM)
@@ -110,6 +120,19 @@ static void
 goo_canvas_item_simple_dispose (GObject *object)
 {
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
+  gint i;
+
+  /* Unref all the items in the group. */
+  if (simple->children)
+    {
+      for (i = 0; i < simple->children->len; i++)
+	{
+	  GooCanvasItem *item = simple->children->pdata[i];
+	  goo_canvas_item_set_parent (item, NULL);
+	  g_object_unref (item);
+	}
+      g_ptr_array_set_size (simple->children, 0);
+    }
 
   if (simple->style)
     {
@@ -131,6 +154,18 @@ goo_canvas_item_simple_dispose (GObject *object)
 
 
 static void
+goo_canvas_item_simple_finalize (GObject *object)
+{
+  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
+
+  if (simple->children)
+    g_ptr_array_free (simple->children, TRUE);
+
+  G_OBJECT_CLASS (goo_canvas_item_simple_parent_class)->finalize (object);
+}
+
+
+static void
 goo_canvas_item_simple_get_property (GObject              *object,
 				     guint                 prop_id,
 				     GValue               *value,
@@ -457,7 +492,22 @@ goo_canvas_item_simple_set_canvas  (GooCanvasItem *item,
 				    GooCanvas     *canvas)
 {
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
+  gint i;
+
+  if (simple->canvas == canvas)
+    return;
+
   simple->canvas = canvas;
+
+  /* Recursively set the canvas of all child items. */
+  if (simple->children)
+    {
+      for (i = 0; i < simple->children->len; i++)
+	{
+	  GooCanvasItem *item = simple->children->pdata[i];
+	  goo_canvas_item_set_canvas (item, canvas);
+	}
+    }
 }
 
 
@@ -580,9 +630,10 @@ goo_canvas_item_simple_get_items_at (GooCanvasItem  *item,
 {
   GooCanvasItemSimpleClass *class = GOO_CANVAS_ITEM_SIMPLE_GET_CLASS (item);
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
-  double user_x = x, user_y = y;
+  double user_x = x, user_y = y, old_x0, old_y0;
   cairo_matrix_t matrix;
-  gboolean add_item = FALSE;
+  gboolean visible = parent_visible;
+  gint i;
 
   if (simple->need_update)
     goo_canvas_item_ensure_updated (item);
@@ -592,18 +643,17 @@ goo_canvas_item_simple_get_items_at (GooCanvasItem  *item,
       || simple->bounds.y1 > y || simple->bounds.y2 < y)
     return found_items;
 
+  if (simple->visibility <= GOO_CANVAS_ITEM_INVISIBLE
+      || (simple->visibility == GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD
+	  && simple->canvas->scale < simple->visibility_threshold))
+    visible = FALSE;
+
   /* Check if the item should receive events. */
-  if (is_pointer_event)
-    {
-      if (simple->pointer_events == GOO_CANVAS_EVENTS_NONE)
-	return found_items;
-      if (simple->pointer_events & GOO_CANVAS_EVENTS_VISIBLE_MASK
-	  && (!parent_visible
-	      || simple->visibility <= GOO_CANVAS_ITEM_INVISIBLE
-	      || (simple->visibility == GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD
-		  && simple->canvas->scale < simple->visibility_threshold)))
-	return found_items;
-    }
+  if (is_pointer_event
+      && (simple->pointer_events == GOO_CANVAS_EVENTS_NONE
+	  || ((simple->pointer_events & GOO_CANVAS_EVENTS_VISIBLE_MASK)
+	      && !visible)))
+    return found_items;
 
   cairo_save (cr);
   if (simple->transform)
@@ -613,6 +663,8 @@ goo_canvas_item_simple_get_items_at (GooCanvasItem  *item,
 
   /* Remove any current translation, to avoid the 16-bit cairo limit. */
   cairo_get_matrix (cr, &matrix);
+  old_x0 = matrix.x0;
+  old_y0 = matrix.y0;
   matrix.x0 = matrix.y0 = 0.0;
   cairo_set_matrix (cr, &matrix);
 
@@ -628,15 +680,30 @@ goo_canvas_item_simple_get_items_at (GooCanvasItem  *item,
 	}
     }
 
-  add_item = class->simple_is_item_at (simple, user_x, user_y, cr,
-                                       is_pointer_event);
+  if (class->simple_is_item_at (simple, user_x, user_y, cr, is_pointer_event))
+    found_items = g_list_prepend (found_items, item);
+
+  /* Step up from the bottom of the children to the top, adding any items
+     found to the start of the list. */
+  if (simple->children)
+    {
+      matrix.x0 = old_x0;
+      matrix.y0 = old_y0;
+      cairo_set_matrix (cr, &matrix);
+
+      for (i = 0; i < simple->children->len; i++)
+	{
+	  GooCanvasItem *child = simple->children->pdata[i];
+
+	  found_items = goo_canvas_item_get_items_at (child, x, y, cr,
+						      is_pointer_event, visible,
+						      found_items);
+	}
+    }
 
   cairo_restore (cr);
 
-  if (add_item)
-    return g_list_prepend (found_items, item);
-  else
-    return found_items;
+  return found_items;
 }
 
 
@@ -703,8 +770,39 @@ goo_canvas_item_simple_set_is_static  (GooCanvasItem   *item,
 				       gboolean         is_static)
 {
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
+  gint i;
+
+  if (simple->is_static == is_static)
+    return;
 
   simple->is_static = is_static;
+
+  /* Recursively set the canvas of all child items. */
+  if (simple->children)
+    {
+      for (i = 0; i < simple->children->len; i++)
+	{
+	  GooCanvasItem *item = simple->children->pdata[i];
+	  goo_canvas_item_set_is_static (item, is_static);
+	}
+    }
+}
+
+
+static void
+goo_canvas_item_simple_request_update  (GooCanvasItem *item)
+{
+  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
+
+  if (!simple->need_update)
+    {
+      simple->need_update = TRUE;
+
+      if (simple->parent)
+	goo_canvas_item_request_update (simple->parent);
+      else if (simple->canvas)
+	goo_canvas_request_update (simple->canvas);
+    }
 }
 
 
@@ -766,11 +864,17 @@ goo_canvas_item_simple_update  (GooCanvasItem   *item,
 				GooCanvasBounds *bounds)
 {
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
+  GooCanvasBounds child_bounds;
   cairo_matrix_t matrix;
   double x_offset, y_offset;
+  gint i;
 
   if (entire_tree || simple->need_update)
     {
+      if (simple->need_entire_subtree_update)
+	entire_tree = TRUE;
+      simple->need_entire_subtree_update = FALSE;
+
       /* Request a redraw of the existing bounds. */
       goo_canvas_request_item_redraw (simple->canvas, &simple->bounds, simple->is_static);
 
@@ -800,6 +904,32 @@ goo_canvas_item_simple_update  (GooCanvasItem   *item,
 
       /* Request a redraw of the new bounds. */
       goo_canvas_request_item_redraw (simple->canvas, &simple->bounds, simple->is_static);
+
+      /* Now handle any children. */
+      if (simple->children)
+	{
+	  cairo_save (cr);
+	  if (simple->transform)
+	    cairo_transform (cr, simple->transform);
+
+	  for (i = 0; i < simple->children->len; i++)
+	    {
+	      GooCanvasItem *child = simple->children->pdata[i];
+
+	      goo_canvas_item_update (child, entire_tree, cr, &child_bounds);
+          
+	      /* If the child has non-empty bounds, compute the union. */
+	      if (child_bounds.x1 < child_bounds.x2
+		  && child_bounds.y1 < child_bounds.y2)
+		{
+		  simple->bounds.x1 = MIN (simple->bounds.x1, child_bounds.x1);
+		  simple->bounds.y1 = MIN (simple->bounds.y1, child_bounds.y1);
+		  simple->bounds.x2 = MAX (simple->bounds.x2, child_bounds.x2);
+		  simple->bounds.y2 = MAX (simple->bounds.y2, child_bounds.y2);
+		}
+	    }
+	  cairo_restore (cr);
+	}
     }
 
   *bounds = simple->bounds;
@@ -812,8 +942,11 @@ goo_canvas_item_simple_get_requested_area (GooCanvasItem    *item,
 					   GooCanvasBounds  *requested_area)
 {
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
+  GooCanvasItemSimpleChildLayoutData *layout_data;
+  GooCanvasBounds bounds;
   cairo_matrix_t matrix;
   double x_offset, y_offset;
+  gint i;
 
   /* Request a redraw of the existing bounds. */
   goo_canvas_request_item_redraw (simple->canvas, &simple->bounds, simple->is_static);
@@ -831,6 +964,9 @@ goo_canvas_item_simple_get_requested_area (GooCanvasItem    *item,
 
   goo_canvas_item_simple_update_internal (simple, cr);
 
+  /* FIXME: Should we make sure the children get updated even if we are
+     hidden? If we don't, we need to ensure they do get updated if the
+     visibility changes. */
   if (simple->visibility == GOO_CANVAS_ITEM_HIDDEN)
     {
       simple->bounds.x1 = simple->bounds.x2 = 0.0;
@@ -861,6 +997,57 @@ goo_canvas_item_simple_get_requested_area (GooCanvasItem    *item,
   cairo_device_to_user (cr, &simple->bounds.x1, &simple->bounds.y1);
   cairo_device_to_user (cr, &simple->bounds.x2, &simple->bounds.y2);
 
+  /* Handle any children. */
+  if (simple->children && simple->children->len)
+    {
+      layout_data = g_new (GooCanvasItemSimpleChildLayoutData,
+			   simple->children->len);
+      g_object_set_data_full ((GObject*) simple, "child-layout-data",
+			      layout_data, g_free);
+
+#if 0
+      g_print ("Simple '%s' base requested area: %g, %g  %g x %g\n",
+	       g_object_get_data (G_OBJECT (simple), "id"),
+	       simple->bounds.x1, simple->bounds.y1,
+	       simple->bounds.x2 - simple->bounds.x1,
+	       simple->bounds.y2 - simple->bounds.y1);
+#endif
+
+      for (i = 0; i < simple->children->len; i++)
+	{
+	  GooCanvasItem *child = simple->children->pdata[i];
+
+	  /* Children will return FALSE if they don't need space allocated. */
+	  if (goo_canvas_item_get_requested_area (child, cr, &bounds))
+	    {
+	      /* Remember the requested position and size of the child. */
+	      layout_data[i].requested_position[HORZ] = bounds.x1;
+	      layout_data[i].requested_position[VERT] = bounds.y1;
+	      layout_data[i].requested_size[HORZ] = bounds.x2 - bounds.x1;
+	      layout_data[i].requested_size[VERT] = bounds.y2 - bounds.y1;
+
+#if 0
+	      g_print ("Child '%s' requested area: %g, %g  %g x %g\n",
+		       g_object_get_data (G_OBJECT (child), "id"),
+		       layout_data[i].requested_position[HORZ],
+		       layout_data[i].requested_position[VERT],
+		       layout_data[i].requested_size[HORZ],
+		       layout_data[i].requested_size[VERT]);
+#endif
+	      simple->bounds.x1 = MIN (simple->bounds.x1, bounds.x1);
+	      simple->bounds.y1 = MIN (simple->bounds.y1, bounds.y1);
+	      simple->bounds.x2 = MAX (simple->bounds.x2, bounds.x2);
+	      simple->bounds.y2 = MAX (simple->bounds.y2, bounds.y2);
+	    }
+	  else
+	    {
+	      layout_data[i].requested_position[HORZ] = 0.0;
+	      layout_data[i].requested_position[VERT] = 0.0;
+	      layout_data[i].requested_size[HORZ] = -1.0;
+	      layout_data[i].requested_size[VERT] = -1.0;
+	    }
+	}
+    }
 
   /* Copy the user bounds to the requested area. */
   *requested_area = simple->bounds;
@@ -873,6 +1060,14 @@ goo_canvas_item_simple_get_requested_area (GooCanvasItem    *item,
 
   cairo_restore (cr);
 
+#if 0
+  if (simple->children && simple->children->len)
+    g_print ("Total requested area: %g, %g  %g x %g\n",
+	     requested_area->x1, requested_area->y1,
+	     requested_area->x2 - requested_area->x1,
+	     requested_area->y2 - requested_area->y1);
+#endif
+
   return TRUE;
 }
 
@@ -886,6 +1081,11 @@ goo_canvas_item_simple_allocate_area      (GooCanvasItem         *item,
 					   gdouble                y_offset)
 {
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
+  GooCanvasItemSimpleChildLayoutData *layout_data;
+  GooCanvasBounds child_requested_area, child_allocated_area;
+  gdouble child_x_offset = x_offset, child_y_offset = y_offset;
+  gdouble width, height;
+  gint i;
 
   /* Simple items can't resize at all, so we just adjust the bounds x & y
      positions here, and let the item be clipped if necessary. */
@@ -896,6 +1096,59 @@ goo_canvas_item_simple_allocate_area      (GooCanvasItem         *item,
 
   /* Request a redraw of the new bounds. */
   goo_canvas_request_item_redraw (simple->canvas, &simple->bounds, simple->is_static);
+
+  /* Now handle any children. */
+  if (simple->children && simple->children->len)
+    {
+      layout_data = g_object_get_data ((GObject*) simple, "child-layout-data");
+
+      cairo_save (cr);
+      if (simple->transform)
+	cairo_transform (cr, simple->transform);
+
+      /* Convert the offsets to our coordinate space. */
+      cairo_device_to_user (cr, &child_x_offset, &child_y_offset);
+
+      for (i = 0; i < simple->children->len; i++)
+	{
+	  GooCanvasItem *child = simple->children->pdata[i];
+
+	  width = layout_data[i].requested_size[HORZ];
+	  height = layout_data[i].requested_size[VERT];
+
+	  /* We use the requested area we saved in get_requested_area(). */
+	  child_requested_area.x1 = layout_data[i].requested_position[HORZ];
+	  child_requested_area.y1 = layout_data[i].requested_position[VERT];
+	  child_requested_area.x2 = child_requested_area.x1 + width;
+	  child_requested_area.y2 = child_requested_area.y1 + height;
+
+	  /* For the allocated area, we use the requested area shifted by the
+	     offsets in this item's coordinate space. */
+	  child_allocated_area.x1 = child_requested_area.x1;
+	  child_allocated_area.y1 = child_requested_area.y1;
+	  child_allocated_area.x1 += child_x_offset;
+	  child_allocated_area.y1 += child_y_offset;
+	  child_allocated_area.x2 = child_allocated_area.x1 + width;
+	  child_allocated_area.y2 = child_allocated_area.y1 + height;
+
+#if 0
+	  g_print ("Child '%s' allocated area: %g, %g  %g x %g\n",
+		   g_object_get_data (G_OBJECT (child), "id"),
+		   child_allocated_area.x1, child_allocated_area.y1,
+		   child_allocated_area.x2 - child_allocated_area.x1,
+		   child_allocated_area.y2 - child_allocated_area.y1);
+#endif
+	  goo_canvas_item_allocate_area (child, cr, &child_requested_area,
+					 &child_allocated_area,
+					 x_offset, y_offset);
+
+	}
+
+      /* Free the layout data. */
+      g_object_set_data ((GObject*) simple, "child-layout-data", NULL);
+
+      cairo_restore (cr);
+    }
 }
 
 
@@ -907,6 +1160,7 @@ goo_canvas_item_simple_paint (GooCanvasItem         *item,
 {
   GooCanvasItemSimpleClass *class = GOO_CANVAS_ITEM_SIMPLE_GET_CLASS (item);
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
+  gint i;
 
   /* Skip the item if the bounds don't intersect the expose rectangle. */
   if (simple->bounds.x1 > bounds->x2 || simple->bounds.x2 < bounds->x1
@@ -933,6 +1187,16 @@ goo_canvas_item_simple_paint (GooCanvasItem         *item,
 
   class->simple_paint (simple, cr, bounds);
 
+  /* Paint the children. */
+  if (simple->children)
+    {
+      for (i = 0; i < simple->children->len; i++)
+	{
+	  GooCanvasItem *child = simple->children->pdata[i];
+	  goo_canvas_item_paint (child, cr, bounds, scale);
+	}
+    }
+
   cairo_restore (cr);
 }
 
@@ -1383,12 +1647,146 @@ goo_canvas_item_simple_set_fill_options (GooCanvasItemSimple   *simple,
 
 
 static void
+goo_canvas_item_simple_add_child     (GooCanvasItem  *item,
+				      GooCanvasItem  *child,
+				      gint            position)
+{
+  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
+  AtkObject *atk_obj, *child_atk_obj;
+
+  g_object_ref (child);
+
+  if (!simple->children)
+    simple->children = g_ptr_array_sized_new (8);
+
+  if (position >= 0)
+    {
+      goo_canvas_util_ptr_array_insert (simple->children, child, position);
+    }
+  else
+    {
+      position = simple->children->len;
+      g_ptr_array_add (simple->children, child);
+    }
+
+  goo_canvas_item_set_parent (child, item);
+  goo_canvas_item_set_is_static (child, simple->is_static);
+
+  /* Emit the "children_changed" ATK signal, if ATK is enabled. */
+  if (accessibility_enabled)
+    {
+      atk_obj = atk_gobject_accessible_for_object (G_OBJECT (item));
+      if (!ATK_IS_NO_OP_OBJECT (atk_obj))
+	{
+	  child_atk_obj = atk_gobject_accessible_for_object (G_OBJECT (child));
+	  g_signal_emit_by_name (atk_obj, "children_changed::add",
+				 position, child_atk_obj);
+	}
+    }
+
+  goo_canvas_item_request_update (item);
+}
+
+
+static void
+goo_canvas_item_simple_move_child    (GooCanvasItem  *item,
+				      gint	      old_position,
+				      gint            new_position)
+{
+  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
+  GooCanvasItem *child;
+  GooCanvasBounds bounds;
+
+  g_return_if_fail (simple->children != NULL);
+  g_return_if_fail (old_position < simple->children->len);
+  g_return_if_fail (new_position < simple->children->len);
+
+  /* Request a redraw of the item's bounds. */
+  child = simple->children->pdata[old_position];
+  if (simple->canvas)
+    {
+      goo_canvas_item_get_bounds (child, &bounds);
+      goo_canvas_request_item_redraw (simple->canvas, &bounds,
+				      simple->is_static);
+    }
+
+  goo_canvas_util_ptr_array_move (simple->children, old_position, new_position);
+
+  goo_canvas_item_request_update (item);
+}
+
+
+static void
+goo_canvas_item_simple_remove_child  (GooCanvasItem  *item,
+				      gint            child_num)
+{
+  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
+  GooCanvasItem *child;
+  GooCanvasBounds bounds;
+  AtkObject *atk_obj, *child_atk_obj;
+
+  g_return_if_fail (simple->children != NULL);
+  g_return_if_fail (child_num < simple->children->len);
+
+  /* Request a redraw of the item's bounds. */
+  child = simple->children->pdata[child_num];
+  if (simple->canvas)
+    {
+      goo_canvas_item_get_bounds (child, &bounds);
+      goo_canvas_request_item_redraw (simple->canvas, &bounds,
+				      simple->is_static);
+    }
+
+  /* Emit the "children_changed" ATK signal, if ATK is enabled. */
+  if (accessibility_enabled)
+    {
+      atk_obj = atk_gobject_accessible_for_object (G_OBJECT (item));
+      if (!ATK_IS_NO_OP_OBJECT (atk_obj))
+	{
+	  child_atk_obj = atk_gobject_accessible_for_object (G_OBJECT (child));
+	  g_signal_emit_by_name (atk_obj, "children_changed::remove",
+				 child_num, child_atk_obj);
+	}
+    }
+
+  g_ptr_array_remove_index (simple->children, child_num);
+
+  goo_canvas_item_set_parent (child, NULL);
+  g_object_unref (child);
+
+  goo_canvas_item_request_update (item);
+}
+
+
+static gint
+goo_canvas_item_simple_get_n_children (GooCanvasItem  *item)
+{
+  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
+
+  return simple->children ? simple->children->len : 0;
+}
+
+
+static GooCanvasItem*
+goo_canvas_item_simple_get_child   (GooCanvasItem       *item,
+				    gint                 child_num)
+{
+  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
+
+  if (simple->children && child_num < simple->children->len)
+    return simple->children->pdata[child_num];
+  return NULL;
+}
+
+
+static void
 goo_canvas_item_simple_class_init (GooCanvasItemSimpleClass *klass)
 {
   GObjectClass *gobject_class = (GObjectClass*) klass;
   GooCanvasItemClass *item_class = (GooCanvasItemClass*) klass;
 
   gobject_class->dispose  = goo_canvas_item_simple_dispose;
+  gobject_class->finalize = goo_canvas_item_simple_finalize;
 
   gobject_class->get_property = goo_canvas_item_simple_get_property;
   gobject_class->set_property = goo_canvas_item_simple_set_property;
@@ -1396,10 +1794,17 @@ goo_canvas_item_simple_class_init (GooCanvasItemSimpleClass *klass)
   item_class->get_canvas         = goo_canvas_item_simple_get_canvas;
   item_class->set_canvas         = goo_canvas_item_simple_set_canvas;
 
+  item_class->add_child          = goo_canvas_item_simple_add_child;
+  item_class->move_child         = goo_canvas_item_simple_move_child;
+  item_class->remove_child       = goo_canvas_item_simple_remove_child;
+  item_class->get_n_children     = goo_canvas_item_simple_get_n_children;
+  item_class->get_child          = goo_canvas_item_simple_get_child;
+
   item_class->get_parent	 = goo_canvas_item_simple_get_parent;
   item_class->set_parent	 = goo_canvas_item_simple_set_parent;
   item_class->get_bounds         = goo_canvas_item_simple_get_bounds;
   item_class->get_items_at	 = goo_canvas_item_simple_get_items_at;
+  item_class->request_update     = goo_canvas_item_simple_request_update;
   item_class->update             = goo_canvas_item_simple_update;
   item_class->get_requested_area = goo_canvas_item_simple_get_requested_area;
   item_class->allocate_area      = goo_canvas_item_simple_allocate_area;
diff --git a/src/goocanvasitemsimple.h b/src/goocanvasitemsimple.h
index 9fd7380..77dd4c0 100644
--- a/src/goocanvasitemsimple.h
+++ b/src/goocanvasitemsimple.h
@@ -66,6 +66,10 @@ struct _GooCanvasItemSimple
   GArray *clip_path_commands;
   gchar *tooltip;
 
+  /* An array of pointers to GooCanvasItems. The first element is at the
+     bottom of the display stack and the last element is at the top. */
+  GPtrArray *children;
+
   GooCanvasBounds bounds;
 
   gdouble visibility_threshold;
diff --git a/src/goocanvastable.c b/src/goocanvastable.c
index 1199527..e5b0b22 100644
--- a/src/goocanvastable.c
+++ b/src/goocanvastable.c
@@ -745,7 +745,7 @@ goo_canvas_table_add_child     (GooCanvasItem  *item,
 
   goo_canvas_table_add_child_internal (table, position);
 
-  /* Let the parent GooCanvasGroup code do the rest. */
+  /* Let the parent GooCanvasItemSimple code do the rest. */
   GOO_CANVAS_ITEM_CLASS (goo_canvas_table_parent_class)->add_child (item, child, position);
 }
 
@@ -798,7 +798,7 @@ goo_canvas_table_move_child    (GooCanvasItem  *item,
   goo_canvas_table_move_child_internal (table, old_position,
 					new_position);
 
-  /* Let the parent GooCanvasGroup code do the rest. */
+  /* Let the parent GooCanvasItemSimple code do the rest. */
   GOO_CANVAS_ITEM_CLASS (goo_canvas_table_parent_class)->move_child (item, old_position, new_position);
 }
 
@@ -807,14 +807,13 @@ static void
 goo_canvas_table_remove_child  (GooCanvasItem  *item,
 				gint            child_num)
 {
-  GooCanvasGroup *group = (GooCanvasGroup*) item;
   GooCanvasTable *table = (GooCanvasTable*) item;
 
-  g_return_if_fail (child_num < group->items->len);
+  g_return_if_fail (child_num < table->children->len);
 
   g_array_remove_index (table->children, child_num);
 
-  /* Let the parent GooCanvasGroup code do the rest. */
+  /* Let the parent GooCanvasItemSimple code do the rest. */
   GOO_CANVAS_ITEM_CLASS (goo_canvas_table_parent_class)->remove_child (item, child_num);
 }
 
@@ -891,14 +890,14 @@ goo_canvas_table_get_child_property (GooCanvasItem     *item,
 				     GValue            *value,
 				     GParamSpec        *pspec)
 {
-  GooCanvasGroup *group = (GooCanvasGroup*) item;
+  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
   GooCanvasTable *table = (GooCanvasTable*) item;
   GooCanvasTableChild *table_child;
   gint child_num;
 
-  for (child_num = 0; child_num < group->items->len; child_num++)
+  for (child_num = 0; child_num < simple->children->len; child_num++)
     {
-      if (group->items->pdata[child_num] == child)
+      if (simple->children->pdata[child_num] == child)
 	{
 	  table_child = &g_array_index (table->children,
 					GooCanvasTableChild, child_num);
@@ -1009,14 +1008,13 @@ goo_canvas_table_set_child_property (GooCanvasItem     *item,
 				     GParamSpec        *pspec)
 {
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
-  GooCanvasGroup *group = (GooCanvasGroup*) item;
   GooCanvasTable *table = (GooCanvasTable*) item;
   GooCanvasTableChild *table_child;
   gint child_num;
 
-  for (child_num = 0; child_num < group->items->len; child_num++)
+  for (child_num = 0; child_num < simple->children->len; child_num++)
     {
-      if (group->items->pdata[child_num] == child)
+      if (simple->children->pdata[child_num] == child)
 	{
 	  table_child = &g_array_index (table->children,
 					GooCanvasTableChild, child_num);
@@ -1137,7 +1135,7 @@ static void
 goo_canvas_table_size_request_init (GooCanvasTable *table,
 				    cairo_t        *cr)
 {
-  GooCanvasGroup *group = (GooCanvasGroup*) table;
+  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) table;
   GooCanvasTableLayoutData *layout_data = table->layout_data;
   GooCanvasTableDimension *dimension;
   GooCanvasTableDimensionLayoutData *dldata;
@@ -1151,7 +1149,7 @@ goo_canvas_table_size_request_init (GooCanvasTable *table,
   for (i = 0; i < table->children->len; i++)
     {
       child = &g_array_index (table->children, GooCanvasTableChild, i);
-      child_item = group->items->pdata[i];
+      child_item = simple->children->pdata[i];
 
       /* Children will return FALSE if they don't need space allocated. */
       allocate = goo_canvas_item_get_requested_area (child_item, cr, &bounds);
@@ -1170,6 +1168,15 @@ goo_canvas_table_size_request_init (GooCanvasTable *table,
       layout_data->children[i].requested_size[HORZ] = bounds.x2 - bounds.x1;
       layout_data->children[i].requested_size[VERT] = bounds.y2 - bounds.y1;
 
+#if 0
+      g_print ("Table Child '%s' requested area: %g, %g  %g x %g\n",
+	       g_object_get_data (G_OBJECT (child_item), "id"),
+	       layout_data->children[i].requested_position[HORZ],
+	       layout_data->children[i].requested_position[VERT],
+	       layout_data->children[i].requested_size[HORZ],
+	       layout_data->children[i].requested_size[VERT]);
+#endif
+
       layout_data->children[i].start_pad[HORZ] = child->start_pad[HORZ];
       layout_data->children[i].end_pad[HORZ] = child->end_pad[HORZ];
       layout_data->children[i].start_pad[VERT] = child->start_pad[VERT];
@@ -1635,7 +1642,6 @@ goo_canvas_table_size_allocate_pass3 (GooCanvasTable *table,
 				      gdouble         table_y_offset)
 {
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) table;
-  GooCanvasGroup *group = (GooCanvasGroup*) table;
   GooCanvasTableLayoutData *layout_data = table->layout_data;
   GooCanvasTableDimensionLayoutData *rows = layout_data->dldata[VERT];
   GooCanvasTableDimensionLayoutData *columns = layout_data->dldata[HORZ];
@@ -1652,10 +1658,15 @@ goo_canvas_table_size_allocate_pass3 (GooCanvasTable *table,
   if (simple->canvas)
     direction = gtk_widget_get_direction (GTK_WIDGET (simple->canvas));
 
+  /* FIXME: Testing. This doesn't work for the clipped shapes in the demo. */
+#if 0
+  direction = GTK_TEXT_DIR_RTL;
+#endif
+
   for (i = 0; i < table->children->len; i++)
     {
       child = &g_array_index (table->children, GooCanvasTableChild, i);
-      child_item = group->items->pdata[i];
+      child_item = simple->children->pdata[i];
       child_data = &layout_data->children[i];
 
       requested_width = child_data->requested_size[HORZ];
@@ -1696,7 +1707,7 @@ goo_canvas_table_size_allocate_pass3 (GooCanvasTable *table,
 	}
 
       if (direction == GTK_TEXT_DIR_RTL)
-	x = layout_data->allocated_size[HORZ] - width;
+	x = layout_data->allocated_size[HORZ] - width - x;
 
       requested_area.x1 = layout_data->children[i].requested_position[HORZ];
       requested_area.y1 = layout_data->children[i].requested_position[VERT];
@@ -1721,6 +1732,14 @@ goo_canvas_table_size_allocate_pass3 (GooCanvasTable *table,
       x_offset += table_x_offset;
       y_offset += table_y_offset;
 
+#if 0
+      g_print ("Table Child '%s' allocated area: %g, %g  %g x %g\n",
+	       g_object_get_data (G_OBJECT (child_item), "id"),
+	       allocated_area.x1, allocated_area.y1,
+	       allocated_area.x2 - allocated_area.x1,
+	       allocated_area.y2 - allocated_area.y1);
+#endif
+
       goo_canvas_item_allocate_area (child_item, cr, &requested_area,
 				     &allocated_area, x_offset, y_offset);
 
@@ -1733,7 +1752,7 @@ static void
 goo_canvas_table_update_requested_heights (GooCanvasItem       *item,
 					   cairo_t	       *cr)
 {
-  GooCanvasGroup *group = (GooCanvasGroup*) item;
+  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
   GooCanvasTable *table = (GooCanvasTable*) item;
   GooCanvasTableLayoutData *layout_data = table->layout_data;
   GooCanvasTableDimensionLayoutData *rows = layout_data->dldata[VERT];
@@ -1759,7 +1778,7 @@ goo_canvas_table_update_requested_heights (GooCanvasItem       *item,
   for (i = 0; i < table->children->len; i++)
     {
       child = &g_array_index (table->children, GooCanvasTableChild, i);
-      child_item = group->items->pdata[i];
+      child_item = simple->children->pdata[i];
       child_data = &layout_data->children[i];
 
       requested_width = child_data->requested_size[HORZ];
@@ -1816,6 +1835,10 @@ goo_canvas_table_get_requested_area (GooCanvasItem        *item,
   gdouble width = 0.0, height = 0.0;
   gint row, column, end;
 
+#if 0
+  g_print ("\nIn Table get_requested_area\n");
+#endif
+
   /* Request a redraw of the existing bounds */
   goo_canvas_request_item_redraw (simple->canvas, &simple->bounds, simple->is_static);
   
@@ -1968,6 +1991,10 @@ goo_canvas_table_allocate_area (GooCanvasItem         *item,
   gdouble requested_width, requested_height, allocated_width, allocated_height;
   gdouble width_proportion, height_proportion, min_proportion;
 
+#if 0
+  g_print ("\nIn Table allocate_area\n");
+#endif
+
   requested_width = requested_area->x2 - requested_area->x1;
   requested_height = requested_area->y2 - requested_area->y1;
   allocated_width = allocated_area->x2 - allocated_area->x1;
@@ -2076,7 +2103,6 @@ goo_canvas_table_paint (GooCanvasItem         *item,
 			gdouble                scale)
 {
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
-  GooCanvasGroup *group = (GooCanvasGroup*) item;
   GooCanvasTable *table = (GooCanvasTable*) item;
   GooCanvasTableLayoutData *layout_data = table->layout_data;
   GooCanvasTableDimensionLayoutData *rows = layout_data->dldata[VERT];
@@ -2297,9 +2323,9 @@ goo_canvas_table_paint (GooCanvasItem         *item,
 
   cairo_restore (cr);
 
-  for (i = 0; i < group->items->len; i++)
+  for (i = 0; i < simple->children->len; i++)
     {
-      child = group->items->pdata[i];
+      child = simple->children->pdata[i];
 
       table_child = &g_array_index (children, GooCanvasTableChild, i);
       clip = FALSE;
@@ -2375,7 +2401,6 @@ goo_canvas_table_get_items_at (GooCanvasItem  *item,
 			       GList          *found_items)
 {
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
-  GooCanvasGroup *group = (GooCanvasGroup*) item;
   GooCanvasTable *table = (GooCanvasTable*) item;
   GooCanvasTableLayoutData *layout_data = table->layout_data;
   GooCanvasTableDimensionLayoutData *rows = layout_data->dldata[VERT];
@@ -2435,9 +2460,9 @@ goo_canvas_table_get_items_at (GooCanvasItem  *item,
 
   /* Step up from the bottom of the children to the top, adding any items
      found to the start of the list. */
-  for (i = 0; i < group->items->len; i++)
+  for (i = 0; i < simple->children->len; i++)
     {
-      child = group->items->pdata[i];
+      child = simple->children->pdata[i];
 
       table_child = &g_array_index (children, GooCanvasTableChild, i);
 
@@ -2491,7 +2516,6 @@ goo_canvas_table_get_transform_for_child  (GooCanvasItem  *item,
 					   cairo_matrix_t *transform)
 {
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
-  GooCanvasGroup *group = (GooCanvasGroup*) item;
   GooCanvasTable *table = (GooCanvasTable*) item;
   GooCanvasTableChild *table_child;
   gboolean has_transform = FALSE;
@@ -2507,9 +2531,9 @@ goo_canvas_table_get_transform_for_child  (GooCanvasItem  *item,
       cairo_matrix_init_identity (transform);
     }
 
-  for (child_num = 0; child_num < group->items->len; child_num++)
+  for (child_num = 0; child_num < simple->children->len; child_num++)
     {
-      if (group->items->pdata[child_num] == child)
+      if (simple->children->pdata[child_num] == child)
 	{
 	  table_child = &g_array_index (table->children,
 					GooCanvasTableChild, child_num);



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