diff --git a/src/g_editor.c b/src/g_editor.c
index 38a4cbf28dd48534ee0a96cd11e17c402db0f8d1..80b484e67ef1eeb581c5b34843ed7a1c83db513d 100644
--- a/src/g_editor.c
+++ b/src/g_editor.c
@@ -431,6 +431,8 @@ static const char *canvas_undo_name;
 void canvas_setundo(t_canvas *x, t_undofn undofn, void *buf,
     const char *name)
 {
+	//fprintf(stderr,"canvas_setundo %lx\n", (t_int)x);
+
     int hadone = 0;
         /* blow away the old undo information.  In one special case the
         old undo info is re-used; if so we shouldn't free it here. */
@@ -1318,6 +1320,86 @@ void canvas_canvas_setundo(t_canvas *x)
 	canvas_setundo(x, canvas_undo_canvas_apply, canvas_undo_set_canvas(x), "apply");
 }
 
+/* --------- 8. create ----------- */
+
+typedef struct _undo_create      
+{
+    int u_index;    /* index of the created object object */
+    t_binbuf *u_objectbuf;      /* the object cleared or typed into */
+    t_binbuf *u_reconnectbuf;   /* connections into and out of object */
+} t_undo_create;
+
+void *canvas_undo_set_create(t_canvas *x)
+{
+    t_gobj *y, *last;
+    t_linetraverser t;
+    t_outconnect *oc;
+
+    t_undo_create *buf = (t_undo_create *)getbytes(sizeof(*buf));
+    buf->u_index = glist_getindex(x, 0) - 1;
+    int nnotsel= glist_selectionindex(x, 0, 0);
+
+    buf->u_objectbuf = binbuf_new();
+    for (y = x->gl_list; y; y = y->g_next)
+    {
+        if (glist_isselected(x, y)) {
+			//fprintf(stderr,"saving object\n");
+            gobj_save(y, buf->u_objectbuf);
+		}
+    }
+    buf->u_reconnectbuf = binbuf_new();
+    linetraverser_start(&t, x);
+    while (oc = linetraverser_next(&t))
+    {
+        int issel1 = glist_isselected(x, &t.tr_ob->ob_g);
+        int issel2 = glist_isselected(x, &t.tr_ob2->ob_g);
+        if (issel1 != issel2)
+        {
+            binbuf_addv(buf->u_reconnectbuf, "ssiiii;",
+                gensym("#X"), gensym("connect"),
+                (issel1 ? nnotsel : 0)
+                    + glist_selectionindex(x, &t.tr_ob->ob_g, issel1),
+                t.tr_outno,
+                (issel2 ? nnotsel : 0) +
+                    glist_selectionindex(x, &t.tr_ob2->ob_g, issel2),
+                t.tr_inno);
+        }
+    }
+    return (buf);
+}
+
+void canvas_undo_create(t_canvas *x, void *z, int action)
+{
+    t_undo_create *buf = z;
+    t_gobj *y;
+
+	//fprintf(stderr,"canvas = %lx buf->u_index = %d\n", (t_int)x, buf->u_index);
+
+    if (action == UNDO_UNDO)
+    {
+        glist_noselect(x);
+        y = glist_nth(x, buf->u_index);
+        glist_select(x, y);
+        canvas_doclear(x);
+    }
+    else if (action == UNDO_REDO)
+    {
+        pd_bind(&x->gl_pd, gensym("#X"));
+   		binbuf_eval(buf->u_objectbuf, 0, 0, 0);
+    	pd_unbind(&x->gl_pd, gensym("#X"));
+        pd_bind(&x->gl_pd, gensym("#X"));
+   		binbuf_eval(buf->u_reconnectbuf, 0, 0, 0);
+    	pd_unbind(&x->gl_pd, gensym("#X"));
+        y = glist_nth(x, buf->u_index);
+        glist_select(x, y);
+    }
+	else if (action == UNDO_FREE) {
+		binbuf_free(buf->u_objectbuf);
+		binbuf_free(buf->u_reconnectbuf);
+        t_freebytes(buf, sizeof(*buf));
+	}
+}
+
 /* ------------------------ event handling ------------------------ */
 
 static char *cursorlist[] = {
@@ -3229,49 +3311,31 @@ void canvas_restoreconnections(t_canvas *x)
 
 static t_binbuf *canvas_docopy(t_canvas *x)
 {
-	//fprintf(stderr,"docopy\n");
+	//fprintf(stderr,"canvas_docopy\n");
     t_gobj *y, *last;
     t_linetraverser t;
     t_outconnect *oc;
     t_binbuf *b = binbuf_new();
-	//int c = 0;
     for (y = x->gl_list; y; y = y->g_next)
     {
         if (glist_isselected(x, y)) {
-			//c++;
-			//fprintf(stderr, "saving object num %d\n", c);
-			//fprintf(stderr, "saving object >.x%lx<\n", (t_int)y);
-			/* introduce redundant comment to avoid recreation of old abstractions
-			   with the same canvas id which results in all commands being registered
-			   multiple times--apparently after much searching it appears that this
-			   is yet another bug in tcl/tk which means that canvas tries to do some
-			   kind of caching behind the curtains resulting in objects not always
-			   having unique ids, contrary to tcl/tk's canvas man page */
-			/*if (c==1) {
-            	binbuf_addv(b, "ssiis;", gensym("#X"), gensym("text"),
-                (int)((t_text *)y)->te_xpix-30, (int)((t_text *)y)->te_ypix-30, gensym("tcltksucks"));
-			}*/
+			//fprintf(stderr,"saving object\n");
             gobj_save(y, b);
 		}
     }
-	//fprintf(stderr,"done saving objects\n");
     linetraverser_start(&t, x);
-	//c = 0;
     while (oc = linetraverser_next(&t))
     {
+		//fprintf(stderr,"found some lines %d %d\n", glist_isselected(x, &t.tr_ob->ob_g), glist_isselected(x, &t.tr_ob2->ob_g));
         if (glist_isselected(x, &t.tr_ob->ob_g)
             && glist_isselected(x, &t.tr_ob2->ob_g))
         {
-			//fprintf(stderr, "lines need to be copied\n");
-			//c = 1;
+			//fprintf(stderr,"saving lines leading into selected object\n");
             binbuf_addv(b, "ssiiii;", gensym("#X"), gensym("connect"),
                 glist_selectionindex(x, &t.tr_ob->ob_g, 1), t.tr_outno,
                 glist_selectionindex(x, &t.tr_ob2->ob_g, 1), t.tr_inno);
-//                glist_selectionindex(x, &t.tr_ob->ob_g, 1)+1, t.tr_outno,
-//                glist_selectionindex(x, &t.tr_ob2->ob_g, 1)+1, t.tr_inno);
         }
     }
-	//if (!c) fprintf(stderr, "no lines copied\n");
     return (b);
 }
 
@@ -3290,7 +3354,7 @@ static void canvas_copyfromexternalbuffer(t_canvas *x, t_symbol *s, int ac, t_at
 			binbuf_add(copy_binbuf, ac, av);
 			binbuf_addsemi(copy_binbuf);
 		} else {
-			//probably should resize window size here...
+			//probably should resize window size and position here...
 			//fprintf(stderr,"ignoring canvas\n");
 		}
 	}
diff --git a/src/g_graph.c b/src/g_graph.c
index 3ac48c68ac35fa8bf38ac6b41da882e459f011b9..fdf21f25e6f7f24b52a184ab7ca8b159b318432b 100644
--- a/src/g_graph.c
+++ b/src/g_graph.c
@@ -29,17 +29,27 @@ void canvas_drawredrect(t_canvas *x, int doit);
 
 void glist_add(t_glist *x, t_gobj *y)
 {
-    t_object *ob;
+	//fprintf(stderr,"glist_add %lx %d\n", (t_int)x, (x->gl_editor ? 1 : 0));    
+	t_object *ob;
     y->g_next = 0;
+	int index = 0;
+
     if (!x->gl_list) x->gl_list = y;
     else
     {
         t_gobj *y2;
-        for (y2 = x->gl_list; y2->g_next; y2 = y2->g_next);
+        for (y2 = x->gl_list; y2->g_next; y2 = y2->g_next)
+			index++;
         y2->g_next = y;
     }
-    if (x->gl_editor && (ob = pd_checkobject(&y->g_pd)))
+    if (x->gl_editor && (ob = pd_checkobject(&y->g_pd))) {
         rtext_new(x, ob);
+		//let's now set up create undo
+		//glist_select(x, y);
+		//canvas_setundo(x, canvas_undo_create, canvas_undo_set_create(x, index),
+        //    "create");
+		//glist_noselect(x);
+	}
     if (x->gl_editor && x->gl_isgraph && !x->gl_goprect
         && pd_checkobject(&y->g_pd))
     {
diff --git a/src/g_text.c b/src/g_text.c
index 0ff6a3980e6c0aa3f06484f6916fabc791319e08..b40af744621302c064b06341bd83fbb91cf0939c 100644
--- a/src/g_text.c
+++ b/src/g_text.c
@@ -30,7 +30,10 @@ t_widgetbehavior text_widgetbehavior;
 
 static char *invalid_fill = "\"#ffdddd\"";
 
-EXTERN void canvas_apply_setundo(t_canvas *x, t_gobj *y);
+extern void canvas_apply_setundo(t_canvas *x, t_gobj *y);
+extern void canvas_setundo(t_canvas *x, t_undofn undofn, void *buf, const char *name);
+extern void *canvas_undo_set_create(t_canvas *x);
+extern void canvas_undo_create(t_canvas *x, void *z, int action);
 
 /* ----------------- the "text" object.  ------------------ */
 
@@ -89,7 +92,7 @@ void canvas_getargs(int *argcp, t_atom **argvp);
 static void canvas_objtext(t_glist *gl, int xpix, int ypix, int selected,
     t_binbuf *b)
 {
-	//fprintf(stderr,"objtext\n");
+	//fprintf(stderr,"canvas_objtext\n");
     t_text *x;
     int argc;
     t_atom *argv;
@@ -202,6 +205,7 @@ void canvas_howputnew(t_canvas *x, int *connectp, int *xpixp, int *ypixp,
 
 void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
 {
+	//fprintf(stderr,"canvas_obj\n");
     t_text *x;
     if (argc >= 2)
     {
@@ -224,6 +228,7 @@ void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
         if (connectme)
             canvas_connect(gl, indx, 0, nobj, 0);
         else canvas_startmotion(glist_getcanvas(gl));
+		canvas_setundo(gl, canvas_undo_create, canvas_undo_set_create(gl), "create");
     }
 }
 
@@ -265,6 +270,7 @@ void canvas_iemguis(t_glist *gl, t_symbol *guiobjname)
     //glist_getnextxy(gl, &xpix, &ypix);
     //canvas_objtext(gl, xpix, ypix, 1, b);
     else canvas_startmotion(glist_getcanvas(gl));
+	canvas_setundo(gl, canvas_undo_create, canvas_undo_set_create(gl), "create");
 }
 
 void canvas_bng(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
@@ -535,6 +541,7 @@ void canvas_msg(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
         if (connectme)
             canvas_connect(gl, indx, 0, nobj, 0);
         else canvas_startmotion(glist_getcanvas(gl));
+		canvas_setundo(gl, canvas_undo_create, canvas_undo_set_create(gl), "create");
     }
 }
 
@@ -921,6 +928,7 @@ static void gatom_vis(t_gobj *z, t_glist *glist, int vis)
 void canvas_atom(t_glist *gl, t_atomtype type,
     t_symbol *s, int argc, t_atom *argv)
 {
+	//fprintf(stderr,"canvas_atom\n");
     t_gatom *x = (t_gatom *)pd_new(gatom_class);
     t_atom at;
     x->a_text.te_width = 0;                        /* don't know it yet. */
@@ -993,6 +1001,7 @@ void canvas_atom(t_glist *gl, t_atomtype type,
         if (connectme)
             canvas_connect(gl, indx, 0, nobj, 0);
         else canvas_startmotion(glist_getcanvas(gl));
+		canvas_setundo(gl, canvas_undo_create, canvas_undo_set_create(gl), "create");
     }
 }