[cairo-commit] goocanvas/demo mv-demo-arrowhead.c, NONE, 1.1 mv-demo-events.c, NONE, 1.1 mv-demo-features.c, NONE, 1.1 mv-demo-fifteen.c, NONE, 1.1 mv-demo-focus.c, NONE, 1.1 mv-demo-grabs.c, NONE, 1.1 mv-demo-paths.c, NONE, 1.1 mv-demo-scalability.c, NONE, 1.1 mv-demo.c, NONE, 1.1 mv-simple-demo.c, NONE, 1.1 widgets-demo.c, NONE, 1.1

Damon Chaplin commit at pdx.freedesktop.org
Wed Nov 29 10:27:09 PST 2006


Committed by: damon

Update of /cvs/cairo/goocanvas/demo
In directory kemper:/tmp/cvs-serv29333/demo

Added Files:
	mv-demo-arrowhead.c mv-demo-events.c mv-demo-features.c 
	mv-demo-fifteen.c mv-demo-focus.c mv-demo-grabs.c 
	mv-demo-paths.c mv-demo-scalability.c mv-demo.c 
	mv-simple-demo.c widgets-demo.c 
Log Message:
added bunch of new files, part of new model/view architecture


--- NEW FILE: mv-demo-arrowhead.c ---
#include <config.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <goocanvas.h>

#define LEFT    50.0
#define RIGHT  350.0
#define MIDDLE 150.0
#define DEFAULT_WIDTH   2
#define DEFAULT_SHAPE_A 4
#define DEFAULT_SHAPE_B 5
#define DEFAULT_SHAPE_C 4


static void
set_dimension (GooCanvas *canvas, char *arrow_name, char *text_name,
	       double x1, double y1, double x2, double y2,
	       double tx, double ty, int dim)
{
	GooCanvasPoints *points;
	char buf[100];

	points = goo_canvas_points_new (2);
	points->coords[0] = x1;
	points->coords[1] = y1;
	points->coords[2] = x2;
	points->coords[3] = y2;

	g_object_set (g_object_get_data (G_OBJECT (canvas), arrow_name),
		      "points", points,
		      NULL);

	sprintf (buf, "%d", dim);
	g_object_set (g_object_get_data (G_OBJECT (canvas), text_name),
		      "text", buf,
		      "x", tx,
		      "y", ty,
		      NULL);

	goo_canvas_points_unref (points);
}

static void
move_drag_box (GooCanvasItem *item, double x, double y)
{
	g_object_set (item,
		      "x", x - 5.0,
		      "y", y - 5.0,
		      NULL);
}


static void
set_arrow_shape (GooCanvas *canvas)
{
	int width;
	int shape_a, shape_b, shape_c;
	GooCanvasPoints *points;
	char buf[100];

	width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (canvas), "width"));
	shape_a = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (canvas), "shape_a"));
	shape_b = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (canvas), "shape_b"));
	shape_c = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (canvas), "shape_c"));

	/* Big arrow */

	g_object_set (g_object_get_data (G_OBJECT (canvas), "big_arrow"),
		      "line-width", 10.0 * width,
		      "arrow-tip-length", (double) (shape_a),
		      "arrow-length", (double) (shape_b),
		      "arrow-width", (double) (shape_c),
		      NULL);

	/* Outline */

	points = goo_canvas_points_new (5);
	points->coords[0] = RIGHT - 10 * shape_a * width;
	points->coords[1] = MIDDLE - 10 * width / 2;
	points->coords[2] = RIGHT - 10 * shape_b * width;
	points->coords[3] = MIDDLE - 10 * (shape_c * width / 2.0);
	points->coords[4] = RIGHT;
	points->coords[5] = MIDDLE;
	points->coords[6] = points->coords[2];
	points->coords[7] = MIDDLE + 10 * (shape_c * width / 2.0);
	points->coords[8] = points->coords[0];
	points->coords[9] = MIDDLE + 10 * width / 2;
	g_object_set (g_object_get_data (G_OBJECT (canvas), "outline"),
		      "points", points,
		      NULL);
	goo_canvas_points_unref (points);

	/* Drag boxes */

	move_drag_box (g_object_get_data (G_OBJECT (canvas), "width_drag_box"),
		       LEFT,
		       MIDDLE - 10 * width / 2.0);

	move_drag_box (g_object_get_data (G_OBJECT (canvas), "shape_a_drag_box"),
		       RIGHT - 10 * shape_a * width,
		       MIDDLE);

	move_drag_box (g_object_get_data (G_OBJECT (canvas), "shape_b_c_drag_box"),
		       RIGHT - 10 * shape_b * width,
		       MIDDLE - 10 * (shape_c * width / 2.0));

	/* Dimensions */

	set_dimension (canvas, "width_arrow", "width_text",
		       LEFT - 10,
		       MIDDLE - 10 * width / 2.0,
		       LEFT - 10,
		       MIDDLE + 10 * width / 2.0,
		       LEFT - 15,
		       MIDDLE,
		       width);

	set_dimension (canvas, "shape_a_arrow", "shape_a_text",
		       RIGHT - 10 * shape_a * width,
		       MIDDLE + 10 * (shape_c * width / 2.0) + 10,
		       RIGHT,
		       MIDDLE + 10 * (shape_c * width / 2.0) + 10,
		       RIGHT - 10 * shape_a * width / 2.0,
		       MIDDLE + 10 * (shape_c * width / 2.0) + 15,
		       shape_a);

	set_dimension (canvas, "shape_b_arrow", "shape_b_text",
		       RIGHT - 10 * shape_b * width,
		       MIDDLE + 10 * (shape_c * width / 2.0) + 35,
		       RIGHT,
		       MIDDLE + 10 * (shape_c * width / 2.0) + 35,
		       RIGHT - 10 * shape_b * width / 2.0,
		       MIDDLE + 10 * (shape_c * width / 2.0) + 40,
		       shape_b);

	set_dimension (canvas, "shape_c_arrow", "shape_c_text",
		       RIGHT + 10,
		       MIDDLE - 10 * shape_c * width / 2.0,
		       RIGHT + 10,
		       MIDDLE + 10 * shape_c * width / 2.0,
		       RIGHT + 15,
		       MIDDLE,
		       shape_c);

	/* Info */

	sprintf (buf, "line-width: %d", width);
	g_object_set (g_object_get_data (G_OBJECT (canvas), "width_info"),
		      "text", buf,
		      NULL);

	sprintf (buf, "arrow-tip-length: %d (* line-width)", shape_a);
	g_object_set (g_object_get_data (G_OBJECT (canvas), "shape_a_info"),
		      "text", buf,
		      NULL);

	sprintf (buf, "arrow-length: %d (* line-width)", shape_b);
	g_object_set (g_object_get_data (G_OBJECT (canvas), "shape_b_info"),
		      "text", buf,
		      NULL);
	sprintf (buf, "arrow-width: %d (* line-width)", shape_c);
	g_object_set (g_object_get_data (G_OBJECT (canvas), "shape_c_info"),
		      "text", buf,
		      NULL);

	/* Sample arrows */

	g_object_set (g_object_get_data (G_OBJECT (canvas), "sample_1"),
		      "line-width", (double) width,
		      "arrow-tip-length", (double) shape_a,
		      "arrow-length", (double) shape_b,
		      "arrow-width", (double) shape_c,
		      NULL);
	g_object_set (g_object_get_data (G_OBJECT (canvas), "sample_2"),
		      "line-width", (double) width,
		      "arrow-tip-length", (double) shape_a,
		      "arrow-length", (double) shape_b,
		      "arrow-width", (double) shape_c,
		      NULL);
	g_object_set (g_object_get_data (G_OBJECT (canvas), "sample_3"),
		      "line-width", (double) width,
		      "arrow-tip-length", (double) shape_a,
		      "arrow-length", (double) shape_b,
		      "arrow-width", (double) shape_c,
		      NULL);
}


static void
create_drag_box (GtkWidget *canvas,
		 GooCanvasItemModel *root,
		 char *box_name)
{
	GooCanvasItemModel *box;

	box = goo_canvas_rect_model_new (root, 0, 0, 10, 10,
					 "fill_color", "black",
					 "stroke_color", "black",
					 "line_width", 1.0,
					 NULL);
	g_object_set_data (G_OBJECT (canvas), box_name, box);
}


static void
create_dimension (GtkWidget *canvas,
		  GooCanvasItemModel *root,
		  char *arrow_name,
		  char *text_name,
		  GtkAnchorType anchor)
{
	GooCanvasItemModel *item;

	item = goo_canvas_polyline_model_new (root, FALSE, 0,
					      "fill_color", "black",
					      "start-arrow", TRUE,
					      "end-arrow", TRUE,
					      NULL);
	g_object_set_data (G_OBJECT (canvas), arrow_name, item);

	item = goo_canvas_text_model_new (root, NULL, 0, 0, -1, anchor,
					  "fill_color", "black",
					  "font", "Sans 12",
					  NULL);
	g_object_set_data (G_OBJECT (canvas), text_name, item);
}

static void
create_info (GtkWidget *canvas,
	     GooCanvasItemModel *root,
	     char *info_name,
	     double x,
	     double y)
{
	GooCanvasItemModel *item;

	item = goo_canvas_text_model_new (root, NULL, x, y, -1, GTK_ANCHOR_NW,
					  "fill_color", "black",
					  "font", "Sans 14",
					  NULL);
	g_object_set_data (G_OBJECT (canvas), info_name, item);
}

static void
create_sample_arrow (GtkWidget *canvas,
		     GooCanvasItemModel *root,
		     char *sample_name,
		     double x1,
		     double y1,
		     double x2,
		     double y2)
{
	GooCanvasItemModel *item;

	item = goo_canvas_polyline_model_new_line (root, x1, y1, x2, y2,
						   "start-arrow", TRUE,
						   "end-arrow", TRUE,
						   NULL);
	g_object_set_data (G_OBJECT (canvas), sample_name, item);
}


static gboolean
on_enter_notify (GooCanvasItem *item,
		 GooCanvasItem *target,
		 GdkEventCrossing *event,
		 gpointer data)
{
  GooCanvasItemModel *model = goo_canvas_item_get_model (target);

  g_object_set (model,
		"fill_color", "red",
		NULL);

  return TRUE;
}


static gboolean
on_leave_notify (GooCanvasItem *item,
		 GooCanvasItem *target,
		 GdkEvent *event,
		 gpointer data)
{
  GooCanvasItemModel *model = goo_canvas_item_get_model (target);

  g_object_set (model,
		"fill_color", "black",
		NULL);

  return TRUE;
}


static gboolean
on_button_press (GooCanvasItem *item,
		 GooCanvasItem *target,
		 GdkEventButton *event,
		 gpointer data)
{
  GooCanvas *canvas;
  GdkCursor *fleur;

  fleur = gdk_cursor_new (GDK_FLEUR);
  canvas = goo_canvas_item_get_canvas (item);
  goo_canvas_pointer_grab (canvas, item,
			   GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
			   fleur,
			   event->time);
  gdk_cursor_unref (fleur);

  return TRUE;
}


static gboolean
on_button_release (GooCanvasItem *item,
		   GooCanvasItem *target,
		   GdkEventButton *event,
		   gpointer data)
{
  GooCanvas *canvas;

  canvas = goo_canvas_item_get_canvas (item);
  goo_canvas_pointer_ungrab (canvas, item, event->time);

  return TRUE;
}


static gboolean
on_motion (GooCanvasItem *item,
	   GooCanvasItem *target,
	   GdkEventMotion *event,
	   gpointer data)
{
  GooCanvas *canvas = goo_canvas_item_get_canvas (item);
  GooCanvasItemModel *model = goo_canvas_item_get_model (target);
  int x, y, width, shape_a, shape_b, shape_c;
  gboolean change = FALSE;

  if (!(event->state & GDK_BUTTON1_MASK))
    return FALSE;

  if (model == g_object_get_data (G_OBJECT (canvas), "width_drag_box"))
    {
      y = event->y;
      width = (MIDDLE - y) / 5;
      if (width < 0)
	return FALSE;
      g_object_set_data (G_OBJECT (canvas), "width", GINT_TO_POINTER (width));
      set_arrow_shape (canvas);
    }
  else if (model == g_object_get_data (G_OBJECT (canvas), "shape_a_drag_box"))
    {
      x = event->x;
      width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (canvas), "width"));
      shape_a = (RIGHT - x) / 10 / width;
      if ((shape_a < 0) || (shape_a > 30))
	return FALSE;
      g_object_set_data (G_OBJECT (canvas), "shape_a",
			 GINT_TO_POINTER (shape_a));
      set_arrow_shape (canvas);
    }
  else if (model == g_object_get_data (G_OBJECT (canvas), "shape_b_c_drag_box"))
    {
      width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (canvas), "width"));

      x = event->x;
      shape_b = (RIGHT - x) / 10 / width;
      if ((shape_b >= 0) && (shape_b <= 30)) {
	g_object_set_data (G_OBJECT (canvas), "shape_b",
			   GINT_TO_POINTER (shape_b));
	change = TRUE;
      }

      y = event->y;
      shape_c = (MIDDLE - y) * 2 / 10 / width;
      if (shape_c >= 0) {
	g_object_set_data (G_OBJECT (canvas), "shape_c",
			   GINT_TO_POINTER (shape_c));
	change = TRUE;
      }

      if (change)
	set_arrow_shape (canvas);
    }

  return TRUE;
}


static void
on_item_created (GooCanvas          *canvas,
		 GooCanvasItem      *item,
		 GooCanvasItemModel *model,
		 gpointer            data)
{
  if (GOO_IS_CANVAS_RECT_MODEL (model))
    {
      g_signal_connect (item, "enter_notify_event",
			(GtkSignalFunc) on_enter_notify,
			NULL);
      g_signal_connect (item, "leave_notify_event",
			(GtkSignalFunc) on_leave_notify,
			NULL);
      g_signal_connect (item, "button_press_event",
			(GtkSignalFunc) on_button_press,
			NULL);
      g_signal_connect (item, "button_release_event",
			(GtkSignalFunc) on_button_release,
			NULL);
      g_signal_connect (item, "motion_notify_event",
			(GtkSignalFunc) on_motion,
			NULL);
    }
}


GtkWidget *
create_canvas_arrowhead (void)
{
	GtkWidget *vbox;
	GtkWidget *w;
	GtkWidget *frame;
	GtkWidget *canvas;
	GooCanvasItemModel *root, *item;

	vbox = gtk_vbox_new (FALSE, 4);
	gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
	gtk_widget_show (vbox);

	w = gtk_label_new ("This demo allows you to edit arrowhead shapes.  Drag the little boxes\n"
			   "to change the shape of the line and its arrowhead.  You can see the\n"
			   "arrows at their normal scale on the right hand side of the window.");
	gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0);
	gtk_widget_show (w);

	w = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
	gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0);
	gtk_widget_show (w);

	frame = gtk_frame_new (NULL);
	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
	gtk_container_add (GTK_CONTAINER (w), frame);
	gtk_widget_show (frame);

	canvas = goo_canvas_new ();

	g_signal_connect (canvas, "item_created",
			  (GtkSignalFunc) on_item_created, NULL);

	root = goo_canvas_group_model_new (NULL, NULL);
	goo_canvas_set_root_item_model (GOO_CANVAS (canvas), root);
	g_object_unref (root);

	gtk_widget_set_size_request (canvas, 500, 350);
	goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 500, 350);
	gtk_container_add (GTK_CONTAINER (frame), canvas);
	gtk_widget_show (canvas);


	g_object_set_data (G_OBJECT (canvas), "width",
			   GINT_TO_POINTER (DEFAULT_WIDTH));
	g_object_set_data (G_OBJECT (canvas), "shape_a",
			   GINT_TO_POINTER (DEFAULT_SHAPE_A));
	g_object_set_data (G_OBJECT (canvas), "shape_b",
			   GINT_TO_POINTER (DEFAULT_SHAPE_B));
	g_object_set_data (G_OBJECT (canvas), "shape_c",
			   GINT_TO_POINTER (DEFAULT_SHAPE_C));

	/* Big arrow */

	item = goo_canvas_polyline_model_new_line (root,
						   LEFT, MIDDLE, RIGHT, MIDDLE,
						   "stroke_color", "mediumseagreen",
						   "end-arrow", TRUE,
						   NULL);
	g_object_set_data (G_OBJECT (canvas), "big_arrow", item);

	/* Arrow outline */

	item = goo_canvas_polyline_model_new (root, TRUE, 0,
					      "stroke_color", "black",
					      "line-width", 2.0,
					      "line-cap", CAIRO_LINE_CAP_ROUND,
					      "line-join", CAIRO_LINE_JOIN_ROUND,
					      NULL);
	g_object_set_data (G_OBJECT (canvas), "outline", item);

	/* Drag boxes */

	create_drag_box (canvas, root, "width_drag_box");
	create_drag_box (canvas, root, "shape_a_drag_box");
	create_drag_box (canvas, root, "shape_b_c_drag_box");

	/* Dimensions */

	create_dimension (canvas, root, "width_arrow", "width_text", GTK_ANCHOR_E);
	create_dimension (canvas, root, "shape_a_arrow", "shape_a_text", GTK_ANCHOR_N);
	create_dimension (canvas, root, "shape_b_arrow", "shape_b_text", GTK_ANCHOR_N);
	create_dimension (canvas, root, "shape_c_arrow", "shape_c_text", GTK_ANCHOR_W);

	/* Info */

	create_info (canvas, root, "width_info", LEFT, 260);
	create_info (canvas, root, "shape_a_info", LEFT, 280);
	create_info (canvas, root, "shape_b_info", LEFT, 300);
	create_info (canvas, root, "shape_c_info", LEFT, 320);

	/* Division line */

	goo_canvas_polyline_model_new_line (root, RIGHT + 50, 0, RIGHT + 50, 1000,
					    "fill_color", "black",
					    "line-width", 2.0,
					    NULL);

	/* Sample arrows */

	create_sample_arrow (canvas, root, "sample_1",
			     RIGHT + 100, 30, RIGHT + 100, MIDDLE - 30);
	create_sample_arrow (canvas, root, "sample_2",
			     RIGHT + 70, MIDDLE, RIGHT + 130, MIDDLE);
	create_sample_arrow (canvas, root, "sample_3",
			     RIGHT + 70, MIDDLE + 30, RIGHT + 130, MIDDLE + 120);

	/* Done! */
	
	set_arrow_shape (GOO_CANVAS (canvas));
	return vbox;
}

--- NEW FILE: mv-demo-events.c ---
#include <config.h>
#include <string.h>
#include <gtk/gtk.h>
#include <goocanvas.h>


static gboolean
on_motion_notify (GooCanvasItem *item,
		  GooCanvasItem *target,
		  GdkEventMotion *event,
		  gpointer data)
{
  GooCanvasItemModel *model = NULL;
  char *item_id = NULL;

  if (target)
    model = goo_canvas_item_get_model (target);

  if (model)
    item_id = g_object_get_data (G_OBJECT (model), "id");

  if (item_id)
    g_print ("%s item received 'motion-notify' signal\n", item_id);

  return FALSE;
}


static void
on_item_created (GooCanvas          *view,
		 GooCanvasItem      *item,
		 GooCanvasItemModel *model,
		 gpointer            data)
{
  g_signal_connect (item, "motion_notify_event",
		    (GtkSignalFunc) on_motion_notify, NULL);
}


static void
create_events_area (GooCanvasItemModel     *root,
		    gint                    area_num,
		    GooCanvasPointerEvents  pointer_events,
		    gchar                  *label)
{
  gint row = area_num / 3, col = area_num % 3;
  gdouble x = col * 200, y = row * 150;
  GooCanvasItemModel *rect;
  char *view_id;
  GooCanvasLineDash *dash;

  dash = goo_canvas_line_dash_new (2, 5.0, 5.0);

  /* Create invisible item. */
  rect = goo_canvas_rect_model_new (root, x + 45, y + 35, 30, 30,
				    "fill-color", "red",
				    "visibility", GOO_CANVAS_ITEM_INVISIBLE,
				    "line-width", 5.0,
				    "pointer-events", pointer_events,
				    NULL);
  view_id = g_strdup_printf ("%s invisible", label);
  g_object_set_data_full (G_OBJECT (rect), "id", view_id, g_free);

  /* Display a thin rect around it to indicate it is there. */
#if 1
  rect = goo_canvas_rect_model_new (root, x + 42.5, y + 32.5, 36, 36,
				    "line-dash", dash,
				    "line-width", 1.0,
				    "stroke-color", "gray",
				    NULL);
#endif

  /* Create unpainted item. */
  rect = goo_canvas_rect_model_new (root, x + 85, y + 35, 30, 30,
				    "stroke-pattern", NULL,
				    "line-width", 5.0,
				    "pointer-events", pointer_events,
				    NULL);
  view_id = g_strdup_printf ("%s unpainted", label);
  g_object_set_data_full (G_OBJECT (rect), "id", view_id, g_free);

  /* Display a thin rect around it to indicate it is there. */
#if 1
  rect = goo_canvas_rect_model_new (root, x + 82.5, y + 32.5, 36, 36,
				    "line-dash", dash,
				    "line-width", 1.0,
				    "stroke-color", "gray",
				    NULL);
#endif

  /* Create stroked item. */
  rect = goo_canvas_rect_model_new (root, x + 125, y + 35, 30, 30,
				    "line-width", 5.0,
				    "pointer-events", pointer_events,
				    NULL);
  view_id = g_strdup_printf ("%s stroked", label);
  g_object_set_data_full (G_OBJECT (rect), "id", view_id, g_free);

  /* Create filled item. */
  rect = goo_canvas_rect_model_new (root, x + 60, y + 75, 30, 30,
				    "fill-color", "red",
				    "stroke-pattern", NULL,
				    "line-width", 5.0,
				    "pointer-events", pointer_events,
				    NULL);
  view_id = g_strdup_printf ("%s filled", label);
  g_object_set_data_full (G_OBJECT (rect), "id", view_id, g_free);

  /* Create stroked & filled item. */
  rect = goo_canvas_rect_model_new (root, x + 100, y + 75, 30, 30,
				    "fill-color", "red",
				    "line-width", 5.0,
				    "pointer-events", pointer_events,
				    NULL);
  view_id = g_strdup_printf ("%s stroked & filled", label);
  g_object_set_data_full (G_OBJECT (rect), "id", view_id, g_free);

  goo_canvas_text_model_new (root, label, x + 100, y + 130, -1,
			     GTK_ANCHOR_CENTER,
			     "font", "Sans 12",
			     "fill-color", "blue",
			     NULL);

  goo_canvas_line_dash_unref (dash);
}


GtkWidget *
create_events_page (void)
{
  GtkWidget *vbox, *alignment, *frame, *label, *canvas;
  GooCanvasItemModel *root;

  vbox = gtk_vbox_new (FALSE, 4);
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  gtk_widget_show (vbox);

  /* Instructions */

  label = gtk_label_new ("Move the mouse over the items to check they receive the right motion events.\nThe first 2 items in each group are 1) invisible and 2) visible but unpainted.");
  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  gtk_widget_show (label);

  /* Frame and canvas */

  alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
  gtk_widget_show (alignment);

  frame = gtk_frame_new (NULL);
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  gtk_container_add (GTK_CONTAINER (alignment), frame);
  gtk_widget_show (frame);

  canvas = goo_canvas_new ();

  g_signal_connect (canvas, "item_created",
		    (GtkSignalFunc) on_item_created, NULL);

  root = goo_canvas_group_model_new (NULL, NULL);

  gtk_widget_set_size_request (canvas, 600, 450);
  goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 600, 450);
  gtk_container_add (GTK_CONTAINER (frame), canvas);
  gtk_widget_show (canvas);

  create_events_area (root, 0, GOO_CANVAS_EVENTS_NONE, "none");
  create_events_area (root, 1, GOO_CANVAS_EVENTS_VISIBLE_PAINTED, "visible-painted");
  create_events_area (root, 2, GOO_CANVAS_EVENTS_VISIBLE_FILL, "visible-fill");
  create_events_area (root, 3, GOO_CANVAS_EVENTS_VISIBLE_STROKE, "visible-stroke");
  create_events_area (root, 4, GOO_CANVAS_EVENTS_VISIBLE, "visible");
  create_events_area (root, 5, GOO_CANVAS_EVENTS_PAINTED, "painted");
  create_events_area (root, 6, GOO_CANVAS_EVENTS_FILL, "fill");
  create_events_area (root, 7, GOO_CANVAS_EVENTS_STROKE, "stroke");
  create_events_area (root, 8, GOO_CANVAS_EVENTS_ALL, "all");

  goo_canvas_set_root_item_model (GOO_CANVAS (canvas), root);
  g_object_unref (root);

  return vbox;
}

--- NEW FILE: mv-demo-features.c ---
#include <config.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <goocanvas.h>


static gboolean
on_button_press (GooCanvasItem *item,
		 GooCanvasItem *target,
		 GdkEventButton *event,
		 gpointer data)
{
  GooCanvasItemModel *model = goo_canvas_item_get_model (item);
  GooCanvasItemModel *parent1, *parent2, *parent;
  int child_num;

  if (event->button != 1 || event->type != GDK_BUTTON_PRESS)
    return FALSE;

  parent1 = g_object_get_data (G_OBJECT (model), "parent1");
  parent2 = g_object_get_data (G_OBJECT (model), "parent2");

  parent = goo_canvas_item_model_get_parent (model);
  g_object_ref (model);
  child_num = goo_canvas_item_model_find_child (parent, model);
  goo_canvas_item_model_remove_child (parent, child_num);
  if (parent == parent1)
    goo_canvas_item_model_add_child (parent2, model, -1);
  else
    goo_canvas_item_model_add_child (parent1, model, -1);
  g_object_unref (model);

  return TRUE;
}


static void
on_item_created (GooCanvas          *canvas,
		 GooCanvasItem      *item,
		 GooCanvasItemModel *model,
		 gpointer            data)
{
  if (g_object_get_data (G_OBJECT (model), "parent1"))
    {
      g_signal_connect (item, "button_press_event",
			(GtkSignalFunc) on_button_press, NULL);
    }
}


GtkWidget *
create_canvas_features (void)
{
	GtkWidget *vbox;
	GtkWidget *w;
	GtkWidget *alignment;
	GtkWidget *frame;
	GtkWidget *canvas;
	GooCanvasItemModel *root, *item;
	GooCanvasItemModel *parent1;
	GooCanvasItemModel *parent2;
	GooCanvasItemModel *group;

	vbox = gtk_vbox_new (FALSE, 4);
	gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
	gtk_widget_show (vbox);

	/* Instructions */

	w = gtk_label_new ("Reparent test:  click on the items to switch them between parents");
	gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0);
	gtk_widget_show (w);

	/* Frame and canvas */

	alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
	gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
	gtk_widget_show (alignment);

	frame = gtk_frame_new (NULL);
	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
	gtk_container_add (GTK_CONTAINER (alignment), frame);
	gtk_widget_show (frame);

	canvas = goo_canvas_new ();

	g_signal_connect (canvas, "item_created",
			  (GtkSignalFunc) on_item_created, NULL);

	root = goo_canvas_group_model_new (NULL, NULL);

	gtk_widget_set_size_request (canvas, 400, 200);
	goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 300, 200);
	gtk_container_add (GTK_CONTAINER (frame), canvas);
	gtk_widget_show (canvas);

	/* First parent and box */

	parent1 = goo_canvas_group_model_new (root, NULL);

	goo_canvas_rect_model_new (parent1, 0, 0, 200, 200,
				   "fill_color", "tan",
				   NULL);

	/* Second parent and box */

	parent2 = goo_canvas_group_model_new (root, NULL);
	goo_canvas_item_model_translate (parent2, 200, 0);

	goo_canvas_rect_model_new (parent2, 0, 0, 200, 200,
				   "fill_color", "#204060",
				   NULL);

	/* Big circle to be reparented */

	item = goo_canvas_ellipse_model_new (parent1, 100, 100, 90, 90,
					     "stroke_color", "black",
					     "fill_color", "mediumseagreen",
					     "line-width", 3.0,
					     NULL);
	g_object_set_data (G_OBJECT (item), "parent1", parent1);
	g_object_set_data (G_OBJECT (item), "parent2", parent2);
#if 0
	g_signal_connect (G_OBJECT (item), "event",
			  (GtkSignalFunc) item_event,
			  NULL);
#endif

	/* A group to be reparented */

	group = goo_canvas_group_model_new (parent2, NULL);
	goo_canvas_item_model_translate (group, 100, 100);

	goo_canvas_ellipse_model_new (group, 0, 0, 50, 50,
				      "stroke_color", "black",
				      "fill_color", "wheat",
				      "line_width", 3.0,
				      NULL);
	goo_canvas_ellipse_model_new (group, 0, 0, 25, 25,
				      "fill_color", "steelblue",
				      NULL);

	g_object_set_data (G_OBJECT (group), "parent1", parent1);
	g_object_set_data (G_OBJECT (group), "parent2", parent2);
#if 0
	g_signal_connect (G_OBJECT (group), "event",
			    (GtkSignalFunc) item_event,
			    NULL);
#endif

	goo_canvas_set_root_item_model (GOO_CANVAS (canvas), root);
	g_object_unref (root);

	/* Done */

	return vbox;
}

--- NEW FILE: mv-demo-fifteen.c ---
#include <config.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <goocanvas.h>


#define PIECE_SIZE 50


static void
free_stuff (GtkObject *obj, gpointer data)
{
	g_free (data);
}

static void
test_win (GooCanvasItemModel **board)
{
	int i;
#if 0
	GtkWidget *dlg;
#endif

	for (i = 0; i < 15; i++)
		if (!board[i] || (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (board[i]), "piece_num")) != i))
			return;

#if 0
	dlg=gnome_ok_dialog ("You stud, you win!");
	gtk_window_set_modal(GTK_WINDOW(dlg),TRUE);
	gnome_dialog_run (GNOME_DIALOG (dlg));
#endif
}

static char *
get_piece_color (int piece)
{
	static char buf[50];
	int x, y;
	int r, g, b;

	y = piece / 4;
	x = piece % 4;

	r = ((4 - x) * 255) / 4;
	g = ((4 - y) * 255) / 4;
	b = 128;

	sprintf (buf, "#%02x%02x%02x", r, g, b);

	return buf;
}

static gboolean
piece_enter_notify (GooCanvasItem *item,
		    GooCanvasItem *target,
		    GdkEventCrossing *event,
		    gpointer data)
{
  GooCanvasItemModel *model, *text;

#if 0
  g_print ("In piece_enter_notify\n");
#endif

  model = goo_canvas_item_get_model (item);
  text = g_object_get_data (G_OBJECT (model), "text");

  g_object_set (text,
		"fill_color", "white",
		NULL);

  return FALSE;
}


static gboolean
piece_leave_notify (GooCanvasItem *item,
		    GooCanvasItem *target,
		    GdkEvent *event,
		    gpointer data)
{
  GooCanvasItemModel *model, *text;

#if 0
  g_print ("In piece_leave_notify\n");
#endif

  model = goo_canvas_item_get_model (item);
  text = g_object_get_data (G_OBJECT (model), "text");

  g_object_set (text,
		"fill_color", "black",
		NULL);

  return FALSE;
}


static gboolean
piece_button_press (GooCanvasItem *item,
		    GooCanvasItem *target,
		    GdkEventButton *event,
		    gpointer data)
{
        GooCanvas *canvas;
	GooCanvasItemModel **board;
	GooCanvasItemModel *model, *text;
	int num, pos, newpos;
	int x, y;
	double dx = 0.0, dy = 0.0;
	int move;

	model = goo_canvas_item_get_model (item);
	canvas = goo_canvas_item_get_canvas (item);
	board = g_object_get_data (G_OBJECT (canvas), "board");
	num = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model), "piece_num"));
	pos = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model), "piece_pos"));
	text = g_object_get_data (G_OBJECT (model), "text");

#if 0
	g_print ("In piece_event pos: %i,%i num: %i\n", pos % 4, pos / 4,
		 num + 1);
#endif

	y = pos / 4;
	x = pos % 4;

	move = TRUE;

	if ((y > 0) && (board[(y - 1) * 4 + x] == NULL)) {
	  dx = 0.0;
	  dy = -1.0;
	  y--;
	} else if ((y < 3) && (board[(y + 1) * 4 + x] == NULL)) {
	  dx = 0.0;
	  dy = 1.0;
	  y++;
	} else if ((x > 0) && (board[y * 4 + x - 1] == NULL)) {
	  dx = -1.0;
	  dy = 0.0;
	  x--;
	} else if ((x < 3) && (board[y * 4 + x + 1] == NULL)) {
	  dx = 1.0;
	  dy = 0.0;
	  x++;
	} else
	  move = FALSE;

	if (move) {
	  newpos = y * 4 + x;
	  board[pos] = NULL;
	  board[newpos] = model;
	  g_object_set_data (G_OBJECT (model), "piece_pos", GINT_TO_POINTER (newpos));
	  goo_canvas_item_model_translate (model, dx * PIECE_SIZE,
					   dy * PIECE_SIZE);
	  test_win (board);
	}

	return FALSE;
}


static void
on_item_created (GooCanvas          *canvas,
		 GooCanvasItem      *item,
		 GooCanvasItemModel *model,
		 gpointer            data)
{
  if (goo_canvas_item_model_get_parent (model)
      && GOO_IS_CANVAS_GROUP_MODEL (model))
    {
      g_signal_connect (item, "enter_notify_event",
			(GtkSignalFunc) piece_enter_notify,
			NULL);
      g_signal_connect (item, "leave_notify_event",
			(GtkSignalFunc) piece_leave_notify,
			NULL);
      g_signal_connect (item, "button_press_event",
			(GtkSignalFunc) piece_button_press,
			NULL);
    }
}


#define SCRAMBLE_MOVES 256

static void
scramble (GtkObject *object, gpointer data)
{
	GooCanvas *canvas;
	GooCanvasItemModel **board;
	int i;
	int pos, oldpos;
	int dir;
	int x, y;

	srand (time (NULL));

	canvas = data;
	board = g_object_get_data (G_OBJECT (canvas), "board");

	/* First, find the blank spot */

	for (pos = 0; pos < 16; pos++)
		if (board[pos] == NULL)
			break;

	/* "Move the blank spot" around in order to scramble the pieces */

	for (i = 0; i < SCRAMBLE_MOVES; i++) {
retry_scramble:
		dir = rand () % 4;

		x = y = 0;

		if ((dir == 0) && (pos > 3)) /* up */
			y = -1;
		else if ((dir == 1) && (pos < 12)) /* down */
			y = 1;
		else if ((dir == 2) && ((pos % 4) != 0)) /* left */
			x = -1;
		else if ((dir == 3) && ((pos % 4) != 3)) /* right */
			x = 1;
		else
			goto retry_scramble;

		oldpos = pos + y * 4 + x;
		board[pos] = board[oldpos];
		board[oldpos] = NULL;
		g_object_set_data (G_OBJECT (board[pos]), "piece_pos",
				   GINT_TO_POINTER (pos));

		goo_canvas_item_model_translate (board[pos], -x * PIECE_SIZE,
						 -y * PIECE_SIZE);
		pos = oldpos;
	}
}

GtkWidget *
create_canvas_fifteen (void)
{
	GtkWidget *vbox;
	GtkWidget *alignment;
	GtkWidget *frame;
	GtkWidget *canvas;
	GtkWidget *button;
	GooCanvasItemModel **board;
	GooCanvasItemModel *root, *rect, *text;
	int i, x, y;
	char buf[20];

	vbox = gtk_vbox_new (FALSE, 4);
	gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
	gtk_widget_show (vbox);

	alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
	gtk_box_pack_start (GTK_BOX (vbox), alignment, TRUE, TRUE, 0);
	gtk_widget_show (alignment);

	frame = gtk_frame_new (NULL);
	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
	gtk_container_add (GTK_CONTAINER (alignment), frame);
	gtk_widget_show (frame);

	/* Create the canvas and board */

	canvas = goo_canvas_new ();

	g_signal_connect (canvas, "item_created",
			  (GtkSignalFunc) on_item_created, NULL);

	root = goo_canvas_group_model_new (NULL, NULL);
	goo_canvas_set_root_item_model (GOO_CANVAS (canvas), root);
	g_object_unref (root);

	gtk_widget_set_size_request (canvas,
				     PIECE_SIZE * 4 + 1, PIECE_SIZE * 4 + 1);
	goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0,
			       PIECE_SIZE * 4 + 1, PIECE_SIZE * 4 + 1);
	gtk_container_add (GTK_CONTAINER (frame), canvas);
	gtk_widget_show (canvas);

	board = g_new (GooCanvasItemModel *, 16);
	g_object_set_data (G_OBJECT (canvas), "board", board);
	g_signal_connect (canvas, "destroy",
			  (GtkSignalFunc) free_stuff, board);

	for (i = 0; i < 15; i++) {
		y = i / 4;
		x = i % 4;

		board[i] = goo_canvas_group_model_new (root, NULL);
		goo_canvas_item_model_translate (board[i], x * PIECE_SIZE,
						 y * PIECE_SIZE);

		rect = goo_canvas_rect_model_new (board[i], 0, 0,
						  PIECE_SIZE, PIECE_SIZE,
						  "fill_color", get_piece_color (i),
						  "stroke_color", "black",
						  "line-width", 1.0,
						  NULL);

		sprintf (buf, "%d", i + 1);

		text = goo_canvas_text_model_new (board[i], buf,
						  PIECE_SIZE / 2.0, PIECE_SIZE / 2.0,
						  -1, GTK_ANCHOR_CENTER,
						  "font", "Sans bold 24",
						  "fill_color", "black",
						  NULL);

		g_object_set_data (G_OBJECT (board[i]), "text", text);

		g_object_set_data (G_OBJECT (board[i]), "piece_num", GINT_TO_POINTER (i));
		g_object_set_data (G_OBJECT (board[i]), "piece_pos", GINT_TO_POINTER (i));

	}

	board[15] = NULL;

	/* Scramble button */

	button = gtk_button_new_with_label ("Scramble");
	gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
	g_object_set_data (G_OBJECT (button), "board", board);
	g_signal_connect (button, "clicked",
			  (GtkSignalFunc) scramble,
			  canvas);
	gtk_widget_show (button);

	return vbox;
}

--- NEW FILE: mv-demo-focus.c ---
#include <config.h>
#include <string.h>
#include <gtk/gtk.h>
#include <goocanvas.h>


static gboolean
on_focus_in (GooCanvasItem *item,
	     GooCanvasItem *target,
	     GdkEventFocus *event,
	     gpointer data)
{
  GooCanvasItemModel *model = goo_canvas_item_get_model (item);
  gchar *id = g_object_get_data (G_OBJECT (model), "id");

  g_print ("%s received focus-in event\n", id ? id : "unknown");

  /* Note that this is only for testing. Setting item properties to indicate
     focus isn't a good idea for real apps, as there may be multiple views. */
  g_object_set (model, "stroke-color", "black", NULL);

  return FALSE;
}


static gboolean
on_focus_out (GooCanvasItem *item,
	      GooCanvasItem *target,
	      GdkEventFocus *event,
	      gpointer data)
{
  GooCanvasItemModel *model = goo_canvas_item_get_model (item);
  gchar *id = g_object_get_data (G_OBJECT (model), "id");

  g_print ("%s received focus-out event\n", id ? id : "unknown");

  /* Note that this is only for testing. Setting item properties to indicate
     focus isn't a good idea for real apps, as there may be multiple views. */
  g_object_set (model, "stroke-pattern", NULL, NULL);

  return FALSE;
}


static gboolean
on_button_press (GooCanvasItem *item,
		 GooCanvasItem *target,
		 GdkEventButton *event,
		 gpointer data)
{
  GooCanvasItemModel *model = goo_canvas_item_get_model (item);
  gchar *id = g_object_get_data (G_OBJECT (model), "id");
  GooCanvas *canvas;

  g_print ("%s received button-press event\n", id ? id : "unknown");

  canvas = goo_canvas_item_get_canvas (item);
  goo_canvas_grab_focus (canvas, item);

  return TRUE;
}


static gboolean
on_key_press (GooCanvasItem *item,
	      GooCanvasItem *target,
	      GdkEventKey *event,
	      gpointer data)
{
  GooCanvasItemModel *model = goo_canvas_item_get_model (item);
  gchar *id = g_object_get_data (G_OBJECT (model), "id");

  g_print ("%s received key-press event\n", id ? id : "unknown");

  return FALSE;
}


static void
on_item_created (GooCanvas          *view,
		 GooCanvasItem      *item,
		 GooCanvasItemModel *model,
		 gpointer            data)
{
  if (GOO_IS_CANVAS_RECT_MODEL (model))
    {
      g_object_set (model, "can-focus", TRUE, NULL);

      g_signal_connect (item, "focus_in_event",
			(GtkSignalFunc) on_focus_in, NULL);
      g_signal_connect (item, "focus_out_event",
			(GtkSignalFunc) on_focus_out, NULL);

      g_signal_connect (item, "button_press_event",
			(GtkSignalFunc) on_button_press, NULL);

      g_signal_connect (item, "key_press_event",
			(GtkSignalFunc) on_key_press, NULL);
    }
}


static void
create_focus_box (GtkWidget     *canvas,
		  gdouble        x,
		  gdouble        y,
		  gdouble        width,
		  gdouble        height,
		  gchar         *color)
{
  GooCanvasItemModel *root, *item;

  root = goo_canvas_get_root_item_model (GOO_CANVAS (canvas));
  item = goo_canvas_rect_model_new (root, x, y, width, height,
				    "stroke-pattern", NULL,
				    "fill-color", color,
				    "line-width", 5.0,
				    "can-focus", TRUE,
				    NULL);
  g_object_set_data (G_OBJECT (item), "id", color);
}


static void
setup_canvas (GtkWidget *canvas)
{
  GooCanvasItemModel *root;

  root = goo_canvas_group_model_new (NULL, NULL);
  goo_canvas_set_root_item_model (GOO_CANVAS (canvas), root);
  g_object_unref (root);

  create_focus_box (canvas, 110, 80, 50, 30, "red");
  create_focus_box (canvas, 300, 160, 50, 30, "orange");
  create_focus_box (canvas, 500, 50, 50, 30, "yellow");
  create_focus_box (canvas, 70, 400, 50, 30, "blue");
  create_focus_box (canvas, 130, 200, 50, 30, "magenta");
  create_focus_box (canvas, 200, 160, 50, 30, "green");
  create_focus_box (canvas, 450, 450, 50, 30, "cyan");
  create_focus_box (canvas, 300, 350, 50, 30, "grey");
  create_focus_box (canvas, 900, 900, 50, 30, "gold");
  create_focus_box (canvas, 800, 150, 50, 30, "thistle");
  create_focus_box (canvas, 600, 800, 50, 30, "azure");
  create_focus_box (canvas, 700, 250, 50, 30, "moccasin");
  create_focus_box (canvas, 500, 100, 50, 30, "cornsilk");
  create_focus_box (canvas, 200, 750, 50, 30, "plum");
  create_focus_box (canvas, 400, 800, 50, 30, "orchid");
}


GtkWidget *
create_focus_page (void)
{
  GtkWidget *vbox, *label, *scrolled_win, *canvas;

  vbox = gtk_vbox_new (FALSE, 4);
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  gtk_widget_show (vbox);

  label = gtk_label_new ("Use Tab, Shift+Tab or the arrow keys to move the keyboard focus between the canvas items.");
  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  gtk_widget_show (label);

  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_container_add (GTK_CONTAINER (vbox), scrolled_win);

  canvas = goo_canvas_new ();
  GTK_WIDGET_SET_FLAGS (canvas, GTK_CAN_FOCUS);
  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);

  g_signal_connect (canvas, "item_created",
		    (GtkSignalFunc) on_item_created, NULL);

  setup_canvas (canvas);

  return vbox;
}

--- NEW FILE: mv-demo-grabs.c ---
#include <config.h>
#include <string.h>
#include <gtk/gtk.h>
#include <goocanvas.h>


static gboolean
on_widget_expose (GtkWidget *widget,
		  GdkEventExpose *event,
		  char *item_id)
{
  g_print ("%s received 'expose' signal\n", item_id);

  gtk_paint_box (widget->style, widget->window, GTK_STATE_NORMAL,
		 GTK_SHADOW_IN, &event->area, widget, NULL, 0, 0,
		 widget->allocation.width, widget->allocation.height);

  return FALSE;
}


static gboolean
on_widget_enter_notify (GtkWidget *widget,
			GdkEventCrossing *event,
			char *item_id)
{
  g_print ("%s received 'enter-notify' signal\n", item_id);
  return TRUE;
}


static gboolean
on_widget_leave_notify (GtkWidget *widget,
			GdkEventCrossing *event,
			char *item_id)
{
  g_print ("%s received 'leave-notify' signal\n", item_id);
  return TRUE;
}


static gboolean
on_widget_motion_notify (GtkWidget *widget,
			 GdkEventMotion *event,
			 char *item_id)
{
  g_print ("%s received 'motion-notify' signal (window: %p)\n", item_id,
	   event->window);

  if (event->is_hint)
    gdk_window_get_pointer (event->window, NULL, NULL, NULL);

  return TRUE;
}


static gboolean
on_widget_button_press (GtkWidget *widget,
			GdkEventButton *event,
			char *item_id)
{
  g_print ("%s received 'button-press' signal\n", item_id);

  if (strstr (item_id, "explicit"))
    {
      GdkGrabStatus status;
      GdkEventMask mask = GDK_BUTTON_PRESS_MASK
	| GDK_BUTTON_RELEASE_MASK
	| GDK_POINTER_MOTION_MASK
	| GDK_POINTER_MOTION_HINT_MASK
	| GDK_ENTER_NOTIFY_MASK
	| GDK_LEAVE_NOTIFY_MASK;

      status = gdk_pointer_grab (widget->window, FALSE, mask, FALSE, NULL,
				 event->time);
      if (status == GDK_GRAB_SUCCESS)
	g_print ("grabbed pointer\n");
      else
	g_print ("pointer grab failed\n");
    }

  return TRUE;
}


static gboolean
on_widget_button_release (GtkWidget *widget,
			  GdkEventButton *event,
			  char *item_id)
{
  g_print ("%s received 'button-release' signal\n", item_id);

  if (strstr (item_id, "explicit"))
    {
      GdkDisplay *display;

      display = gtk_widget_get_display (widget);
      gdk_display_pointer_ungrab (display, event->time);
      g_print ("released pointer grab\n");
    }

  return TRUE;
}




static gboolean
on_enter_notify (GooCanvasItem *item,
		 GooCanvasItem *target,
		 GdkEventCrossing *event,
		 gpointer data)
{
  GooCanvasItemModel *model = goo_canvas_item_get_model (target);
  char *item_id = g_object_get_data (G_OBJECT (model), "id");

  g_print ("%s received 'enter-notify' signal\n", item_id);
  return FALSE;
}


static gboolean
on_leave_notify (GooCanvasItem *item,
		 GooCanvasItem *target,
		 GdkEventCrossing *event,
		 gpointer data)
{
  GooCanvasItemModel *model = goo_canvas_item_get_model (target);
  char *item_id = g_object_get_data (G_OBJECT (model), "id");

  g_print ("%s received 'leave-notify' signal\n", item_id);
  return FALSE;
}


static gboolean
on_motion_notify (GooCanvasItem *item,
		  GooCanvasItem *target,
		  GdkEventMotion *event,
		  gpointer data)
{
  GooCanvasItemModel *model = goo_canvas_item_get_model (target);
  char *item_id = g_object_get_data (G_OBJECT (model), "id");

  g_print ("%s received 'motion-notify' signal\n", item_id);
  return FALSE;
}


static gboolean
on_button_press (GooCanvasItem *item,
		 GooCanvasItem *target,
		 GdkEventButton *event,
		 gpointer data)
{
  GooCanvasItemModel *model = goo_canvas_item_get_model (target);
  char *item_id = g_object_get_data (G_OBJECT (model), "id");

  g_print ("%s received 'button-press' signal\n", item_id);

  if (strstr (item_id, "explicit"))
    {
      GooCanvas *canvas;
      GdkGrabStatus status;
      GdkEventMask mask = GDK_BUTTON_PRESS_MASK
	| GDK_BUTTON_RELEASE_MASK
	| GDK_POINTER_MOTION_MASK
	| GDK_POINTER_MOTION_HINT_MASK
	| GDK_ENTER_NOTIFY_MASK
	| GDK_LEAVE_NOTIFY_MASK;

      canvas = goo_canvas_item_get_canvas (item);
      status = goo_canvas_pointer_grab (canvas, item, mask, NULL, event->time);
      if (status == GDK_GRAB_SUCCESS)
	g_print ("grabbed pointer\n");
      else
	g_print ("pointer grab failed\n");
    }

  return FALSE;
}


static gboolean
on_button_release (GooCanvasItem *item,
		   GooCanvasItem *target,
		   GdkEventButton *event,
		   gpointer data)
{
  GooCanvasItemModel *model = goo_canvas_item_get_model (target);
  char *item_id = g_object_get_data (G_OBJECT (model), "id");

  g_print ("%s received 'button-release' signal\n", item_id);

  if (strstr (item_id, "explicit"))
    {
      GooCanvas *canvas;

      canvas = goo_canvas_item_get_canvas (item);
      goo_canvas_pointer_ungrab (canvas, item, event->time);
      g_print ("released pointer grab\n");
    }

  return FALSE;
}


static void
create_fixed (GtkTable *table, gint row, gchar *text, gchar *id)
{
  GtkWidget *label, *fixed, *drawing_area;
  char *view_id;

  label = gtk_label_new (text);
  gtk_table_attach (table, label, 0, 1, row, row + 1,
		    0, 0, 0, 0);
  gtk_widget_show (label);

  fixed = gtk_fixed_new ();
  gtk_fixed_set_has_window (GTK_FIXED (fixed), TRUE);
  gtk_widget_set_events (fixed,
			 GDK_EXPOSURE_MASK
			 | GDK_BUTTON_PRESS_MASK
			 | GDK_BUTTON_RELEASE_MASK
			 | GDK_POINTER_MOTION_MASK
			 | GDK_POINTER_MOTION_HINT_MASK
			 | GDK_KEY_PRESS_MASK
			 | GDK_KEY_RELEASE_MASK
			 | GDK_ENTER_NOTIFY_MASK
			 | GDK_LEAVE_NOTIFY_MASK
			 | GDK_FOCUS_CHANGE_MASK);
  gtk_widget_set_size_request (fixed, 200, 100);
  gtk_table_attach (GTK_TABLE (table), fixed, 1, 2, row, row + 1,
		    0, 0, 0, 0);
  gtk_widget_show (fixed);

  view_id = g_strdup_printf ("%s-background", id);
  g_signal_connect (fixed, "expose_event",
		    (GtkSignalFunc) on_widget_expose, view_id);

  g_signal_connect (fixed, "enter_notify_event",
		    (GtkSignalFunc) on_widget_enter_notify, view_id);
  g_signal_connect (fixed, "leave_notify_event",
		    (GtkSignalFunc) on_widget_leave_notify, view_id);
  g_signal_connect (fixed, "motion_notify_event",
		    (GtkSignalFunc) on_widget_motion_notify, view_id);
  g_signal_connect (fixed, "button_press_event",
		    (GtkSignalFunc) on_widget_button_press, view_id);
  g_signal_connect (fixed, "button_release_event",
		    (GtkSignalFunc) on_widget_button_release, view_id);


  drawing_area = gtk_drawing_area_new ();
  gtk_widget_set_events (drawing_area,
			 GDK_EXPOSURE_MASK
			 | GDK_BUTTON_PRESS_MASK
			 | GDK_BUTTON_RELEASE_MASK
			 | GDK_POINTER_MOTION_MASK
			 | GDK_POINTER_MOTION_HINT_MASK
			 | GDK_KEY_PRESS_MASK
			 | GDK_KEY_RELEASE_MASK
			 | GDK_ENTER_NOTIFY_MASK
			 | GDK_LEAVE_NOTIFY_MASK
			 | GDK_FOCUS_CHANGE_MASK);
			 
  gtk_widget_set_size_request (drawing_area, 60, 60);
  gtk_fixed_put (GTK_FIXED (fixed), drawing_area, 20, 20);
  gtk_widget_show (drawing_area);

  view_id = g_strdup_printf ("%s-left", id);
  g_signal_connect (drawing_area, "expose_event",
		    (GtkSignalFunc) on_widget_expose, view_id);

  g_signal_connect (drawing_area, "enter_notify_event",
		    (GtkSignalFunc) on_widget_enter_notify, view_id);
  g_signal_connect (drawing_area, "leave_notify_event",
		    (GtkSignalFunc) on_widget_leave_notify, view_id);
  g_signal_connect (drawing_area, "motion_notify_event",
		    (GtkSignalFunc) on_widget_motion_notify, view_id);
  g_signal_connect (drawing_area, "button_press_event",
		    (GtkSignalFunc) on_widget_button_press, view_id);
  g_signal_connect (drawing_area, "button_release_event",
		    (GtkSignalFunc) on_widget_button_release, view_id);


  drawing_area = gtk_drawing_area_new ();
  gtk_widget_set_events (drawing_area,
			 GDK_EXPOSURE_MASK
			 | GDK_BUTTON_PRESS_MASK
			 | GDK_BUTTON_RELEASE_MASK
			 | GDK_POINTER_MOTION_MASK
			 | GDK_POINTER_MOTION_HINT_MASK
			 | GDK_KEY_PRESS_MASK
			 | GDK_KEY_RELEASE_MASK
			 | GDK_ENTER_NOTIFY_MASK
			 | GDK_LEAVE_NOTIFY_MASK
			 | GDK_FOCUS_CHANGE_MASK);
			 
  gtk_widget_set_size_request (drawing_area, 60, 60);
  gtk_fixed_put (GTK_FIXED (fixed), drawing_area, 120, 20);
  gtk_widget_show (drawing_area);

  view_id = g_strdup_printf ("%s-right", id);
  g_signal_connect (drawing_area, "expose_event",
		    (GtkSignalFunc) on_widget_expose, view_id);

  g_signal_connect (drawing_area, "enter_notify_event",
		    (GtkSignalFunc) on_widget_enter_notify, view_id);
  g_signal_connect (drawing_area, "leave_notify_event",
		    (GtkSignalFunc) on_widget_leave_notify, view_id);
  g_signal_connect (drawing_area, "motion_notify_event",
		    (GtkSignalFunc) on_widget_motion_notify, view_id);
  g_signal_connect (drawing_area, "button_press_event",
		    (GtkSignalFunc) on_widget_button_press, view_id);
  g_signal_connect (drawing_area, "button_release_event",
		    (GtkSignalFunc) on_widget_button_release, view_id);
}


static void
on_item_created (GooCanvas          *canvas,
		 GooCanvasItem      *item,
		 GooCanvasItemModel *model,
		 gpointer            data)
{
  if (GOO_IS_CANVAS_RECT (model))
    {
      g_signal_connect (item, "enter_notify_event",
			(GtkSignalFunc) on_enter_notify, NULL);
      g_signal_connect (item, "leave_notify_event",
			(GtkSignalFunc) on_leave_notify, NULL);
      g_signal_connect (item, "motion_notify_event",
			(GtkSignalFunc) on_motion_notify, NULL);
      g_signal_connect (item, "button_press_event",
			(GtkSignalFunc) on_button_press, NULL);
      g_signal_connect (item, "button_release_event",
			(GtkSignalFunc) on_button_release, NULL);
    }
}


static void
create_canvas (GtkTable *table, gint row, gchar *text, gchar *id)
{
  GtkWidget *label, *canvas;
  GooCanvasItemModel *root, *rect;
  char *view_id;

  label = gtk_label_new (text);
  gtk_table_attach (table, label, 0, 1, row, row + 1,
		    0, 0, 0, 0);
  gtk_widget_show (label);

  canvas = goo_canvas_new ();

  g_signal_connect (canvas, "item_created",
		    (GtkSignalFunc) on_item_created, NULL);

  gtk_widget_set_size_request (canvas, 200, 100);
  goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 200, 100);
  gtk_table_attach (table, canvas, 1, 2, row, row + 1, 0, 0, 0, 0);
  gtk_widget_show (canvas);

  root = goo_canvas_group_model_new (NULL, NULL);
  goo_canvas_set_root_item_model (GOO_CANVAS (canvas), root);
  g_object_unref (root);

  rect = goo_canvas_rect_model_new (root, 0, 0, 200, 100,
				    "stroke-pattern", NULL,
				    "fill-color", "yellow",
				    NULL);
  view_id = g_strdup_printf ("%s-yellow", id);
  g_object_set_data_full (G_OBJECT (rect), "id", view_id, g_free);

  rect = goo_canvas_rect_model_new (root, 20, 20, 60, 60,
				    "stroke-pattern", NULL,
				    "fill-color", "blue",
				    NULL);
  view_id = g_strdup_printf ("%s-blue", id);
  g_object_set_data_full (G_OBJECT (rect), "id", view_id, g_free);

  rect = goo_canvas_rect_model_new (root, 120, 20, 60, 60,
				    "stroke-pattern", NULL,
				    "fill-color", "red",
				    NULL);
  view_id = g_strdup_printf ("%s-red", id);
  g_object_set_data_full (G_OBJECT (rect), "id", view_id, g_free);
}


GtkWidget *
create_grabs_page (void)
{
  GtkWidget *table, *label;

  table = gtk_table_new (5, 2, FALSE);
  gtk_container_set_border_width (GTK_CONTAINER (table), 12);
  gtk_table_set_row_spacings (GTK_TABLE (table), 12);
  gtk_table_set_col_spacings (GTK_TABLE (table), 12);
  gtk_widget_show (table);

  label = gtk_label_new ("Move the mouse over the widgets and canvas items on the right to see what events they receive.\nClick buttons to start explicit or implicit pointer grabs and see what events they receive now.\n(They should all receive the same events.)");
  gtk_table_attach (GTK_TABLE (table), label, 0, 2, 0, 1, 0, 0, 0, 0);
  gtk_widget_show (label);

  /* Drawing area with explicit grabs. */
  create_fixed (GTK_TABLE (table), 1,
		"Widget with Explicit Grabs:",
		"widget-explicit");

  /* Drawing area with implicit grabs. */
  create_fixed (GTK_TABLE (table), 2,
		"Widget with Implicit Grabs:",
		"widget-implicit");

  /* Canvas with explicit grabs. */
  create_canvas (GTK_TABLE (table), 3,
		 "Canvas with Explicit Grabs:",
		 "canvas-explicit");

  /* Canvas with implicit grabs. */
  create_canvas (GTK_TABLE (table), 4,
		 "Canvas with Implicit Grabs:",
		 "canvas-implicit");

  return table;
}

--- NEW FILE: mv-demo-paths.c ---
#include <config.h>
#include <string.h>
#include <gtk/gtk.h>
#include <goocanvas.h>


static GooCanvasItemModel*
create_canvas_model (void)
{
  GooCanvasItemModel *root, *path;

  root = goo_canvas_group_model_new (NULL, NULL);

  /* Test the simple commands like moveto and lineto: MmZzLlHhVv. */
  path = goo_canvas_path_model_new (root, "M 20 20 L 40 40", NULL);
  path = goo_canvas_path_model_new (root, "M30 20 l20, 20", NULL);
  path = goo_canvas_path_model_new (root, "M 60 20 H 80", NULL);
  path = goo_canvas_path_model_new (root, "M60 40 h20", NULL);
  path = goo_canvas_path_model_new (root, "M 100,20 V 40", NULL);
  path = goo_canvas_path_model_new (root, "M 120 20 v 20", NULL);
  path = goo_canvas_path_model_new (root, "M 140 20 h20 v20 h-20 z", NULL);
  path = goo_canvas_path_model_new (root,
				    "M 180 20 h20 v20 h-20 z m 5,5 h10 v10 h-10 z",
				    "fill-color", "red",
				    "fill-rule", CAIRO_FILL_RULE_EVEN_ODD,
				    NULL);

  path = goo_canvas_path_model_new (root, "M 220 20 L 260 20 L 240 40 z",
				    "fill-color", "red",
				    "stroke-color", "blue",
				    "line-width", 3.0,
				    NULL);

  /* Test the bezier curve commands: CcSsQqTt. */
  path = goo_canvas_path_model_new (root,
				    "M20,100 C20,50 100,50 100,100 S180,150 180,100",
				    NULL);

  path = goo_canvas_path_model_new (root,
				    "M220,100 c0,-50 80,-50 80,0 s80,50 80,0",
				    NULL);

  path = goo_canvas_path_model_new (root,
				    "M20,200 Q60,130 100,200 T180,200",
				    NULL);

  path = goo_canvas_path_model_new (root,
				    "M220,200 q40,-70 80,0 t80,0",
				    NULL);

  /* Test the elliptical arc commands: Aa. */
  path = goo_canvas_path_model_new (root,
				    "M200,500 h-150 a150,150 0 1,0 150,-150 z",
				    "fill-color", "red",
				    "stroke-color", "blue",
				    "line-width", 5.0,
				    NULL);

  path = goo_canvas_path_model_new (root,
				    "M175,475 v-150 a150,150 0 0,0 -150,150 z",
				    "fill-color", "yellow",
				    "stroke-color", "blue",
				    "line-width", 5.0,
				    NULL);

  path = goo_canvas_path_model_new (root,
				    "M400,600 l 50,-25 "
				    "a25,25 -30 0,1 50,-25 l 50,-25 "
				    "a25,50 -30 0,1 50,-25 l 50,-25 "
				    "a25,75 -30 0,1 50,-25 l 50,-25 "
				    "a25,100 -30 0,1 50,-25 l 50,-25",
				    "stroke-color", "red",
				    "line-width", 5.0,
				    NULL);

  path = goo_canvas_path_model_new (root,
				    "M 525,75 a100,50 0 0,0 100,50",
				    "stroke-color", "red",
				    "line-width", 5.0,
				    NULL);
  path = goo_canvas_path_model_new (root,
				    "M 725,75 a100,50 0 0,1 100,50",
				    "stroke-color", "red",
				    "line-width", 5.0,
				    NULL);
  path = goo_canvas_path_model_new (root,
				    "M 525,200 a100,50 0 1,0 100,50",
				    "stroke-color", "red",
				    "line-width", 5.0,
				    NULL);
  path = goo_canvas_path_model_new (root,
				    "M 725,200 a100,50 0 1,1 100,50",
				    "stroke-color", "red",
				    "line-width", 5.0,
				    NULL);

  return root;
}


GtkWidget *
create_paths_page (void)
{
  GtkWidget *vbox, *scrolled_win, *canvas;
  GooCanvasItemModel *root;

  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_container_add (GTK_CONTAINER (vbox), scrolled_win);

  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 = create_canvas_model ();
  goo_canvas_set_root_item_model (GOO_CANVAS (canvas), root);
  g_object_unref (root);

  return vbox;
}

--- NEW FILE: mv-demo-scalability.c ---
#include <config.h>
#include <math.h>
#include <gtk/gtk.h>
#include <goocanvas.h>


#define N_COLS 5
#define N_ROWS 20
#define PADDING 10

#if 1
#define USE_PIXMAP 
#endif

GtkWidget *
create_canvas_scalability (void)
{
	GtkWidget *vbox;
	GtkWidget *frame;
	GtkWidget *scrolled_win, *canvas;
	GtkWidget *table;
	GdkPixbuf *pixbuf;
	GooCanvasItemModel *root, *item;
	int i, j, width, height;

	vbox = gtk_vbox_new (FALSE, 4);
	gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
	gtk_widget_show (vbox);

	table = gtk_table_new (2, 2, FALSE);
	gtk_table_set_row_spacings (GTK_TABLE (table), 4);
	gtk_table_set_col_spacings (GTK_TABLE (table), 4);
	gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
	gtk_widget_show (table);
	
	frame = gtk_frame_new (NULL);
	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
	gtk_table_attach (GTK_TABLE (table), frame,
			  0, 1, 0, 1,
			  GTK_EXPAND | GTK_FILL | GTK_SHRINK,
			  GTK_EXPAND | GTK_FILL | GTK_SHRINK,
			  0, 0);
	gtk_widget_show (frame);

	/* Create the canvas and board */

	pixbuf = gdk_pixbuf_new_from_file("toroid.png", NULL);
#ifdef USE_PIXMAP
	width = gdk_pixbuf_get_width (pixbuf) + 3;
	height = gdk_pixbuf_get_height (pixbuf) +1;
#else
	width = 37;
	height = 19;
#endif
	
	canvas = goo_canvas_new ();
	root = goo_canvas_group_model_new (NULL, NULL);
	goo_canvas_set_root_item_model (GOO_CANVAS (canvas), root);
	g_object_unref (root);

	gtk_widget_set_size_request (canvas, 600, 450);
	goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0,
			       N_COLS * (width + PADDING),
			       N_ROWS * (height + PADDING));
	gtk_widget_show (canvas);


	scrolled_win = gtk_scrolled_window_new (NULL, NULL);
	gtk_widget_show (scrolled_win);
	gtk_container_add (GTK_CONTAINER (frame), scrolled_win);

	gtk_container_add (GTK_CONTAINER (scrolled_win), canvas);


	for (i = 0; i < N_COLS; i++) {
		for (j = 0; j < N_ROWS; j++) {
#ifdef USE_PIXMAP
		  item = goo_canvas_image_model_new (root, pixbuf,
						     i * (width + PADDING),
						     j * (height + PADDING),
						     NULL);
#else
		  item = goo_canvas_rect_model_new (root,
						    i * (width + PADDING),
						    j * (height + PADDING),
						    width, height);
		  g_object_set (item,
				"fill_color", (j%2)?"mediumseagreen":"steelblue",
				NULL);
#endif
			
		}
	}

	return vbox;
}

--- NEW FILE: mv-demo.c ---
/*
 * GooCanvas Demo. Copyright (C) 2005 Damon Chaplin.
 * Released under the GNU LGPL license. See COPYING for details.
 *
 * main.c - demo app.
 */
#include <config.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <cairo.h>
#if CAIRO_HAS_PDF_SURFACE
#include <cairo-pdf.h>
#endif
#include <goocanvas.h>

GooCanvasItemModel *ellipse2, *textitem;
[...1212 lines suppressed...]
{
  GooCanvasItemModel *model;
  GtkWidget *window;

  gtk_set_locale ();
  gtk_init (&argc, &argv);

  model = create_model ();

  /* Create 2 windows to show off multiple views. */
  window = create_window (model);
#if 1
  window = create_window (model);
#endif

  g_object_unref (model);

  gtk_main ();
  return 0;
}

--- NEW FILE: mv-simple-demo.c ---
#include <stdlib.h>
#include <goocanvas.h>


static gboolean on_rect_button_press (GooCanvasItem  *view,
				      GooCanvasItem  *target,
				      GdkEventButton *event,
				      gpointer        data);

static gboolean on_delete_event      (GtkWidget      *window,
				      GdkEvent       *event,
				      gpointer        unused_data);


int
main (int argc, char *argv[])
{
  GtkWidget *window, *scrolled_win, *canvas;
  GooCanvasItemModel *root, *rect_model, *text_model;
  GooCanvasItem *rect_item;

  /* Initialize GTK+. */
  gtk_set_locale ();
  gtk_init (&argc, &argv);

  /* Create the window and widgets. */
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_default_size (GTK_WINDOW (window), 640, 600);
  gtk_widget_show (window);
  g_signal_connect (window, "delete_event", (GtkSignalFunc) on_delete_event,
		    NULL);

  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_container_add (GTK_CONTAINER (window), scrolled_win);

  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_group_model_new (NULL, NULL);

  /* Add a few simple items. */
  rect_model = goo_canvas_rect_model_new (root, 100, 100, 400, 400,
					  "line-width", 10.0,
					  "radius-x", 20.0,
					  "radius-y", 10.0,
					  "stroke-color", "yellow",
					  "fill-color", "red",
					  NULL);

  text_model = goo_canvas_text_model_new (root, "Hello World", 300, 300, -1,
					  GTK_ANCHOR_CENTER,
					  "font", "Sans 24",
					  NULL);
  goo_canvas_item_model_rotate (text_model, 45, 300, 300);

  goo_canvas_set_root_item_model (GOO_CANVAS (canvas), root);

  /* Connect a signal handler for the rectangle item. */
  rect_item = goo_canvas_get_item (GOO_CANVAS (canvas), rect_model);
  g_signal_connect (rect_item, "button_press_event",
		    (GtkSignalFunc) on_rect_button_press, NULL);

  /* Pass control to the GTK+ main event loop. */
  gtk_main ();

  return 0;
}


/* This handles button presses in item views. We simply output a message to
   the console. */
static gboolean
on_rect_button_press (GooCanvasItem  *item,
		      GooCanvasItem  *target,
		      GdkEventButton *event,
		      gpointer        data)
{
  g_print ("rect item received button press event\n");
  return TRUE;
}


/* This is our handler for the "delete-event" signal of the window, which
   is emitted when the 'x' close button is clicked. We just exit here. */
static gboolean
on_delete_event (GtkWidget *window,
		 GdkEvent  *event,
		 gpointer   unused_data)
{
  exit (0);
}

--- NEW FILE: widgets-demo.c ---
#include <stdlib.h>
#include <goocanvas.h>


GtkWidget *canvas;
GooCanvasItem *move_item;
int num_added_widgets = 0;
GList *added_widget_items;

static void
add_widget_clicked (GtkWidget *button, gpointer data)
{
  GooCanvasItem *root, *witem;
  GtkWidget *widget;

  if (num_added_widgets % 2)
    widget = gtk_label_new ("Hello World");
  else
    widget = gtk_entry_new ();

  root = goo_canvas_get_root_item (GOO_CANVAS (canvas));
  witem = goo_canvas_widget_new (root, widget,
				 num_added_widgets * 50,
				 num_added_widgets * 50,
				 200, 50, NULL);

  added_widget_items = g_list_prepend (added_widget_items, witem);
  num_added_widgets++;
}


static void
remove_widget_clicked (GtkWidget *button, gpointer data)
{
  GooCanvasItem *root, *witem;
  GList *elem;

  if (!added_widget_items)
    return;

  witem = added_widget_items->data;
  root = goo_canvas_get_root_item (GOO_CANVAS (canvas));

  goo_canvas_item_remove_child (root,
				goo_canvas_item_find_child (root, witem));

  elem = added_widget_items;
  added_widget_items = added_widget_items->next;
  g_list_free1 (elem);
				
  num_added_widgets--;
}


static void
move_widget_clicked (GtkWidget *button, gpointer data)
{
  static gint move_index = 0;
  static gdouble moves[][4] = {
    { 50, 50, -1, -1 },
    { 300, 100, -1, -1 },
    { 200, 200, -1, -1 },
    { 400, 100, -1, -1 },
  };

  g_object_set (move_item,
		"x", moves[move_index][0],
		"y", moves[move_index][1],
		"width", moves[move_index][2],
		"height", moves[move_index][3],
		NULL);
  move_index = (move_index + 1) % 4;
}


static void
change_anchor_clicked (GtkWidget *button, gpointer data)
{
  static GtkAnchorType anchor = GTK_ANCHOR_CENTER;

  g_print ("Setting anchor to: %i\n", anchor);
  g_object_set (move_item,
		"anchor", anchor,
		NULL);
  anchor++;
  if (anchor > GTK_ANCHOR_EAST)
    anchor = GTK_ANCHOR_CENTER;
}


static void
change_widget_clicked (GtkWidget *button, gpointer data)
{
  GooCanvasItem *witem;
  GtkWidget *old_widget, *widget;

  if (!added_widget_items)
    return;

  witem = added_widget_items->data;

  g_object_get (witem, "widget", &old_widget, NULL);

  if (GTK_IS_ENTRY (old_widget))
    widget = gtk_label_new ("Hello World");
  else
    widget = gtk_entry_new ();

  g_object_set (witem, "widget", widget, NULL);
}


static void
hide_item_clicked (GtkWidget *button, gpointer data)
{
  g_object_set (move_item,
		"visibility", GOO_CANVAS_ITEM_INVISIBLE,
		NULL);
}


static void
show_item_clicked (GtkWidget *button, gpointer data)
{
  g_object_set (move_item,
		"visibility", GOO_CANVAS_ITEM_VISIBLE,
		NULL);
}


static void
hide_canvas_clicked (GtkWidget *button, gpointer data)
{
  gtk_widget_hide (canvas);
}


static void
show_canvas_clicked (GtkWidget *button, gpointer data)
{
  gtk_widget_show (canvas);
}


static void
change_transform_clicked (GtkWidget *button, gpointer data)
{
  goo_canvas_item_translate (move_item, 25.0, 25.0);
}


static gboolean
on_delete_event (GtkWidget *window,
		 GdkEvent  *event,
		 gpointer   unused_data)
{
  exit (0);
}


static gboolean
on_focus_in (GooCanvasItem *item,
	     GooCanvasItem *target,
	     GdkEventFocus *event,
	     gpointer data)
{
  gchar *id;

  id = g_object_get_data (G_OBJECT (item), "id");

  g_print ("%s received focus-in event\n", id ? id : "unknown");

  /* Note that this is only for testing. Setting item properties to indicate
     focus isn't a good idea for real apps, as there may be multiple views. */
  g_object_set (item, "stroke-color", "black", NULL);

  return FALSE;
}


static gboolean
on_focus_out (GooCanvasItem *item,
	      GooCanvasItem *target,
	      GdkEventFocus *event,
	      gpointer data)
{
  gchar *id;

  id = g_object_get_data (G_OBJECT (item), "id");

  g_print ("%s received focus-out event\n", id ? id : "unknown");

  /* Note that this is only for testing. Setting item properties to indicate
     focus isn't a good idea for real apps, as there may be multiple views. */
  g_object_set (item, "stroke-pattern", NULL, NULL);

  return FALSE;
}


static gboolean
on_button_press (GooCanvasItem *item,
		 GooCanvasItem *target,
		 GdkEventButton *event,
		 gpointer data)
{
  GooCanvas *canvas;
  gchar *id;

  id = g_object_get_data (G_OBJECT (item), "id");

  g_print ("%s received button-press event\n", id ? id : "unknown");

  canvas = goo_canvas_item_get_canvas (item);
  goo_canvas_grab_focus (canvas, item);

  return TRUE;
}


static gboolean
on_key_press (GooCanvasItem *item,
	      GooCanvasItem *target,
	      GdkEventKey *event,
	      gpointer data)
{
  gchar *id;

  id = g_object_get_data (G_OBJECT (item), "id");

  g_print ("%s received key-press event\n", id ? id : "unknown");

  return FALSE;
}


static void
create_focus_box (GtkWidget     *canvas,
		  gdouble        x,
		  gdouble        y,
		  gdouble        width,
		  gdouble        height,
		  gchar         *color)
{
  GooCanvasItem *root, *item;

  root = goo_canvas_get_root_item (GOO_CANVAS (canvas));
  item = goo_canvas_rect_new (root, x, y, width, height,
			      "stroke-pattern", NULL,
			      "fill-color", color,
			      "line-width", 5.0,
			      "can-focus", TRUE,
			      NULL);
  g_object_set_data (G_OBJECT (item), "id", color);

  g_signal_connect (item, "focus_in_event",
		    (GtkSignalFunc) on_focus_in, NULL);
  g_signal_connect (item, "focus_out_event",
		    (GtkSignalFunc) on_focus_out, NULL);

  g_signal_connect (item, "button_press_event",
		    (GtkSignalFunc) on_button_press, NULL);

  g_signal_connect (item, "key_press_event",
		    (GtkSignalFunc) on_key_press, NULL);
}


int
main (int argc, char *argv[])
{
  GtkWidget *window, *vbox, *hbox, *w, *scrolled_win;
  GtkWidget *label, *entry, *textview;
  GtkTextBuffer *buffer;
  GooCanvasItem *root, *witem;

  /* Initialize GTK+. */
  gtk_set_locale ();
  gtk_init (&argc, &argv);

  /* Create the window and widgets. */
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_default_size (GTK_WINDOW (window), 640, 600);
  gtk_widget_show (window);
  g_signal_connect (window, "delete_event", (GtkSignalFunc) on_delete_event,
		    NULL);

  vbox = gtk_vbox_new (FALSE, 4);
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  gtk_widget_show (vbox);
  gtk_container_add (GTK_CONTAINER (window), vbox);

  hbox = gtk_hbox_new (FALSE, 4);
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);

  w = gtk_button_new_with_label ("Add Widget");
  gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
  gtk_widget_show (w);
  g_signal_connect (w, "clicked", (GtkSignalFunc) add_widget_clicked, NULL);

  w = gtk_button_new_with_label ("Remove Widget");
  gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
  gtk_widget_show (w);
  g_signal_connect (w, "clicked", (GtkSignalFunc) remove_widget_clicked, NULL);

  w = gtk_button_new_with_label ("Move Widget");
  gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
  gtk_widget_show (w);
  g_signal_connect (w, "clicked", (GtkSignalFunc) move_widget_clicked, NULL);

  w = gtk_button_new_with_label ("Change Anchor");
  gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
  gtk_widget_show (w);
  g_signal_connect (w, "clicked", (GtkSignalFunc) change_anchor_clicked, NULL);

  w = gtk_button_new_with_label ("Change Widget");
  gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
  gtk_widget_show (w);
  g_signal_connect (w, "clicked", (GtkSignalFunc) change_widget_clicked, NULL);

  hbox = gtk_hbox_new (FALSE, 4);
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);

  w = gtk_button_new_with_label ("Hide Canvas");
  gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
  gtk_widget_show (w);
  g_signal_connect (w, "clicked", (GtkSignalFunc) hide_canvas_clicked, NULL);

  w = gtk_button_new_with_label ("Show Canvas");
  gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
  gtk_widget_show (w);
  g_signal_connect (w, "clicked", (GtkSignalFunc) show_canvas_clicked, NULL);

  w = gtk_button_new_with_label ("Hide Item");
  gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
  gtk_widget_show (w);
  g_signal_connect (w, "clicked", (GtkSignalFunc) hide_item_clicked, NULL);

  w = gtk_button_new_with_label ("Show Item");
  gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
  gtk_widget_show (w);
  g_signal_connect (w, "clicked", (GtkSignalFunc) show_item_clicked, NULL);

  w = gtk_button_new_with_label ("Change Transform");
  gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
  gtk_widget_show (w);
  g_signal_connect (w, "clicked", (GtkSignalFunc) change_transform_clicked, NULL);

  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_FLAGS (canvas, GTK_CAN_FOCUS);
  gtk_widget_set_size_request (canvas, 600, 450);
  goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 1000, 1000);
  gtk_container_add (GTK_CONTAINER (scrolled_win), canvas);

  root = goo_canvas_get_root_item (GOO_CANVAS (canvas));

  /* Add a few simple items. */
  label = gtk_label_new ("Hello World");
  witem = goo_canvas_widget_new (root, label, 50, 50, 200, 100, NULL);
  g_object_set_data (G_OBJECT (witem), "id", "hello");

  entry = gtk_entry_new ();
  move_item = goo_canvas_widget_new (root, entry, 50, 250, 200, 50, NULL);
  g_object_set_data (G_OBJECT (move_item), "id", "entry1");

  entry = gtk_entry_new ();
  gtk_entry_set_text (GTK_ENTRY (entry), "Size: -1 x -1");
  witem = goo_canvas_widget_new (root, entry, 50, 300, -1, -1, NULL);
  g_object_set_data (G_OBJECT (witem), "id", "entry2");

  entry = gtk_entry_new ();
  gtk_entry_set_text (GTK_ENTRY (entry), "Size: 100 x -1");
  witem = goo_canvas_widget_new (root, entry, 50, 350, 100, -1, NULL);
  g_object_set_data (G_OBJECT (witem), "id", "entry3");

  /* Use a textview so we can see the width & height of the widget. */
  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win),
				       GTK_SHADOW_IN);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
				  GTK_POLICY_NEVER, GTK_POLICY_NEVER);
  textview = gtk_text_view_new ();
  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
  gtk_text_buffer_set_text (GTK_TEXT_BUFFER (buffer), "Size: -1 x 100", -1);
  gtk_widget_show (textview);
  gtk_container_add (GTK_CONTAINER (scrolled_win), textview);
  gtk_widget_set_size_request (scrolled_win, 160, 50);
  witem = goo_canvas_widget_new (root, scrolled_win, 50, 400, -1, 100, NULL);
  g_object_set_data (G_OBJECT (witem), "id", "scrolledwin");

  /* Create a vbox item with several child entry widgets to check focus
     traversal.*/
  vbox = gtk_vbox_new (FALSE, 4);

  entry = gtk_entry_new ();
  gtk_widget_show (entry);
  gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);

  entry = gtk_entry_new ();
  gtk_widget_show (entry);
  gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);

  entry = gtk_entry_new ();
  gtk_widget_show (entry);
  gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);

  witem = goo_canvas_widget_new (root, vbox, 50, 600, -1, -1, NULL);
  g_object_set_data (G_OBJECT (witem), "id", "vbox");

  /* Create a few normal canvas items that take keyboard focus. */
  create_focus_box (canvas, 110, 80, 50, 30, "red");
  create_focus_box (canvas, 300, 160, 50, 30, "orange");
  create_focus_box (canvas, 500, 50, 50, 30, "yellow");


  gtk_widget_show (canvas);

  /* Pass control to the GTK+ main event loop. */
  gtk_main ();

  return 0;
}





More information about the cairo-commit mailing list