diff --git a/src/g_canvas.h b/src/g_canvas.h
index c30b6da0303d1268add1f459425b2067f58b2b8a..0206f3803a1aee97983bcd8cc6fb46accf569831 100644
--- a/src/g_canvas.h
+++ b/src/g_canvas.h
@@ -455,7 +455,7 @@ void canvas_deletelinesforio(t_canvas *x, t_text *text,
 extern int glist_amreloadingabstractions; /* stop GUI changes while reloading */ 
 
 /* -------------------- functions on texts ------------------------- */
-EXTERN void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize);
+EXTERN void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize, int pos);
 EXTERN void text_drawborder(t_text *x, t_glist *glist, char *tag,
     int width, int height, int firsttime);
 EXTERN void text_drawborder_withtag(t_text *x, t_glist *glist, char *tag,
diff --git a/src/g_editor.c b/src/g_editor.c
index 9eecaa7af22d67735153e09695a860a7d82fb98a..baa942198df9100c5956212476b54612768a6e3f 100644
--- a/src/g_editor.c
+++ b/src/g_editor.c
@@ -56,6 +56,8 @@ static int copiedfont;
 static void canvas_dofont(t_canvas *x, t_floatarg font, t_floatarg xresize,
     t_floatarg yresize);
 extern void canvas_setbounds(t_canvas *x, int x1, int y1, int x2, int y2);
+int canvas_apply_restore_original_position(t_canvas *x, int orig_pos);
+
 struct _outlet
 {
     t_object *o_owner;
@@ -281,6 +283,8 @@ static void glist_checkanddeselectall(t_glist *gl, t_gobj *g)
     glist_noselect(gl2);
 }
 
+int glist_getindex(t_glist *x, t_gobj *y);
+
     /* call this for selected objects only */
 void glist_deselect(t_glist *x, t_gobj *y)
 {
@@ -294,6 +298,10 @@ void glist_deselect(t_glist *x, t_gobj *y)
         t_selection *sel, *sel2;
         t_rtext *z = 0;
         if (!glist_isselected(x, y)) bug("glist_deselect");
+		// following information is for undo_apply
+		// we need info on the old object's position
+		// in the gl_list so that we can restore it
+		int pos = glist_getindex(glist_getcanvas(x), y);
         if (x->gl_editor->e_textedfor)
         {
 			//fprintf(stderr, "e_textedfor\n");
@@ -340,7 +348,7 @@ void glist_deselect(t_glist *x, t_gobj *y)
             int bufsize;
 
             rtext_gettext(z, &buf, &bufsize);
-            text_setto((t_text *)y, x, buf, bufsize);
+            text_setto((t_text *)y, x, buf, bufsize, pos);
             canvas_fixlinesfor(glist_getcanvas(x), (t_text *)y);
             x->gl_editor->e_textedfor = 0;
         }
@@ -889,6 +897,7 @@ void canvas_undo_move(t_canvas *x, void *z, int action)
 				cl = pd_class(&y->g_pd);
 		        if (cl == vinlet_class) resortin = 1;
 		        else if (cl == voutlet_class) resortout = 1;
+				glist_select(x, y);
             }
         }
 		if (resortin) canvas_resortinlets(x);
@@ -1030,7 +1039,7 @@ typedef struct _undo_apply
 	int u_index;				/* index of the previous object */
 } t_undo_apply;
 
-static void *canvas_undo_set_apply(t_canvas *x, int n)
+void *canvas_undo_set_apply(t_canvas *x, int n)
 {
     t_undo_apply *buf;
     t_gobj *y, *obj;
@@ -1073,7 +1082,7 @@ static void *canvas_undo_set_apply(t_canvas *x, int n)
     return (buf);
 }
 
-static void canvas_undo_apply(t_canvas *x, void *z, int action)
+void canvas_undo_apply(t_canvas *x, void *z, int action)
 {
     t_undo_apply *buf = z;
     if (action == UNDO_UNDO || action == UNDO_REDO)
@@ -1091,10 +1100,8 @@ static void canvas_undo_apply(t_canvas *x, void *z, int action)
 		/* replace it with previous instance */
         canvas_dopaste(x, buf->u_objectbuf);
 
-		/* change previous instance with current one */
-		//TODO: test this		
+		/* change previous instance with current one */		
 		buf->u_objectbuf = tmp;
-		//buf->u_index = glist_selectionindex(x, 0, 0);
 
 		/* connections should stay the same */
         pd_bind(&x->gl_pd, gensym("#X"));
@@ -1102,48 +1109,8 @@ static void canvas_undo_apply(t_canvas *x, void *z, int action)
         pd_unbind(&x->gl_pd, gensym("#X"));
 
 		//now we need to reposition the object to its original place
-		t_gobj *y, *y_prev, *y_next;
-		//get the last object
-		y = glist_nth(x, glist_getindex(x, 0) - 1);
-		/*for (y = x->gl_list; y; y = y->g_next)
-			if (!y->g_next)
-				break;*/
-		if (glist_getindex(x, y) != buf->u_index) {
-			//fprintf(stderr,"not in the right place\n");
-			y_prev = glist_nth(x, buf->u_index-1);
-			y_next = glist_nth(x, buf->u_index);
-			//if the object is supposed to be first in the gl_list
-			if (buf->u_index == 0) {
-				if (y_prev && y_next) {
-					y_prev->g_next = y_next;
-				}
-				else if (y_prev && !y_next)
-					y_prev->g_next = NULL;
-				//now put the moved object at the beginning of the cue
-				y->g_next = glist_nth(x, 0);
-				x->gl_list = y;
-			}
-			//if the object is supposed to be at the current end of gl_list	
-			//can this ever happen???
-			/*else if (!glist_nth(x,buf->p_a[i])) {
-
-			}*/
-			//if the object is supposed to be in the middle of gl_list
-			else {
-				if (y_prev && y_next) {
-					y_prev->g_next = y_next;
-				}
-				else if (y_prev && !y_next) {
-					y_prev->g_next = NULL;
-				}
-				//now put the moved object in its right place
-				y_prev = glist_nth(x, buf->u_index-1);
-				y_next = glist_nth(x, buf->u_index);
-
-				y_prev->g_next = y;
-				y->g_next = y_next;
-			}
-		}
+		if (canvas_apply_restore_original_position(x, buf->u_index))
+			canvas_redraw(x);
     }
     else if (action == UNDO_FREE)
     {
@@ -1155,9 +1122,37 @@ static void canvas_undo_apply(t_canvas *x, void *z, int action)
     }
 }
 
-void canvas_apply_setundo(t_canvas *x, int n)
+//legacy wrapper
+void canvas_apply_setundo(t_canvas *x, t_gobj *y)
 {
-	canvas_setundo(x, canvas_undo_apply, canvas_undo_set_apply(x, n), "apply");
+	canvas_undo_add(x, 6, "apply", canvas_undo_set_apply(x, glist_getindex(x,y)));
+}
+
+int canvas_apply_restore_original_position(t_canvas *x, int orig_pos)
+{
+	t_gobj *y, *y1, *y_prev, *y_next;
+	//get the last object
+	y = glist_nth(x, glist_getindex(x, 0) - 1);
+	if (glist_getindex(x, y) != orig_pos) {
+		//first make the object prior to the pasted one the end of the list
+		y_prev = glist_nth(x, glist_getindex(x, 0) - 2);
+		if (y_prev)
+			y_prev->g_next = NULL;
+		//if the object is supposed to be first in the gl_list
+		if (orig_pos == 0) {
+			y->g_next = glist_nth(x, 0);
+			x->gl_list = y;
+		}
+		//if the object is supposed to be in the middle of the gl_list
+		else {
+			y_prev = glist_nth(x, orig_pos-1);
+			y_next = y_prev->g_next;
+			y_prev->g_next = y;
+			y->g_next = y_next;
+		}
+		return(1);
+	}
+	return(0);
 }
 
 /* --------- 7. arrange (to front/back)  ----------- */
@@ -1576,14 +1571,14 @@ void canvas_undo_create(t_canvas *x, void *z, int action)
 
 //recreate uses t_undo_create struct
 
-void *canvas_undo_set_recreate(t_canvas *x, t_gobj *y)
+void *canvas_undo_set_recreate(t_canvas *x, t_gobj *y, int pos)
 {
     t_linetraverser t;
     t_outconnect *oc;
 	int issel1, issel2;
 
     t_undo_create *buf = (t_undo_create *)getbytes(sizeof(*buf));
-    buf->u_index = glist_getindex(x, y);
+    buf->u_index = pos;
     int nnotsel= glist_selectionindex(x, 0, 0) - 1; // - 1 is a critical difference from the create
 	//fprintf(stderr,"buf->u_index=%d nnotsel=%d\n", buf->u_index, nnotsel);
     buf->u_objectbuf = binbuf_new();
@@ -1621,7 +1616,11 @@ void canvas_undo_recreate(t_canvas *x, void *z, int action)
 	//fprintf(stderr,"canvas_undo_recreate\n");
 
     t_undo_create *buf = z;
-    t_gobj *y = glist_nth(x, buf->u_index);
+	t_gobj *y = NULL;
+	if (action == UNDO_UNDO)
+		y = glist_nth(x, glist_getindex(x, 0) - 1);
+	else if (action == UNDO_REDO)
+		y = glist_nth(x, buf->u_index);
 
 	//fprintf(stderr,"canvas = %lx buf->u_index = %d\n", (t_int)x, buf->u_index);
 
@@ -1633,35 +1632,17 @@ void canvas_undo_recreate(t_canvas *x, void *z, int action)
 		int issel1, issel2;
 
 		t_undo_create *buf2 = (t_undo_create *)getbytes(sizeof(*buf));
-		buf2->u_index = glist_getindex(x, y);
+		//buf2->u_index = glist_getindex(x, y);
+		buf2->u_index = buf->u_index;
 		int nnotsel= glist_selectionindex(x, 0, 0) - 1; // - 1 is a critical difference from the create
-		//fprintf(stderr,"buf2->u_index=%d nnotsel=%d\n", buf2->u_index, nnotsel);
+		//fprintf(stderr,"buf2->u_index=%d nnotsel=%d y_getindex=%d\n", buf2->u_index, nnotsel, glist_getindex(x, y));
 		buf2->u_objectbuf = binbuf_new();
 		//fprintf(stderr,"undo_set_recreate: gobj_save\n");
 		gobj_save(y, buf2->u_objectbuf);
 
-		buf2->u_reconnectbuf = binbuf_new();
-		linetraverser_start(&t, x);
-		while (oc = linetraverser_next(&t))
-		{
-			issel1 = ( &t.tr_ob->ob_g == y ? 1 : 0);
-			issel2 = ( &t.tr_ob2->ob_g == y ? 1 : 0);
-			//fprintf(stderr,"undo_set_recreate linetraverser %d %d\n", issel1, issel2);
-			if (issel1 != issel2)
-			{
-				//fprintf(stderr,"undo_set_recreate store connection\n");
-				binbuf_addv(buf2->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);
-			}
-		}
+		buf2->u_reconnectbuf = binbuf_duplicate(buf->u_reconnectbuf);
 
-		// now then cut the existing object
+		// now cut the existing object
 		glist_noselect(x);
         glist_select(x, y);
         canvas_doclear(x);
@@ -1685,56 +1666,19 @@ void canvas_undo_recreate(t_canvas *x, void *z, int action)
 		buf = buf2;
 
 		// reposition object to its original place
-		t_gobj *y_prev, *y_next;
-		//get the last object
-		y = glist_nth(x, glist_getindex(x, 0) - 1);
-		/*for (y = x->gl_list; y; y = y->g_next)
-			if (!y->g_next)
-				break;*/
-		// first check if we are in the same position already
-		if (glist_getindex(x, y) != buf->u_index) {
-			//fprintf(stderr,"not in the right place\n");
-			y_prev = glist_nth(x, buf->u_index-1);
-			y_next = glist_nth(x, buf->u_index);
-			//if the object is supposed to be first in the gl_list
-			if (buf->u_index == 0) {
-				if (y_prev && y_next) {
-					y_prev->g_next = y_next;
-				}
-				else if (y_prev && !y_next)
-					y_prev->g_next = NULL;
-				//now put the moved object at the beginning of the cue
-				y->g_next = glist_nth(x, 0);
-				x->gl_list = y;
-			}
-			//if the object is supposed to be at the current end of gl_list	
-			//can this ever happen???
-			/*else if (!glist_nth(x,buf->p_a[i])) {
-
-			}*/
-			//if the object is supposed to be in the middle of gl_list
-			else {
-				if (y_prev && y_next) {
-					y_prev->g_next = y_next;
-				}
-				else if (y_prev && !y_next) {
-					y_prev->g_next = NULL;
-				}
-				//now put the moved object in its right place
-				y_prev = glist_nth(x, buf->u_index-1);
-				y_next = glist_nth(x, buf->u_index);
-
-				y_prev->g_next = y;
-				y->g_next = y_next;
-			}
-		}
+		if (action == UNDO_UNDO)
+			if (canvas_apply_restore_original_position(x, buf->u_index))
+				canvas_redraw(x);
 
 		// send a loadbang
         if (newest && pd_class(newest) == canvas_class)
         	canvas_loadbang((t_canvas *)newest);
 
 		// select
-        y = glist_nth(x, buf->u_index);
+		if (action == UNDO_REDO)
+			y = glist_nth(x, glist_getindex(x, 0) - 1);
+		else
+	        y = glist_nth(x, buf->u_index);
         glist_select(x, y);
     }
 	else if (action == UNDO_FREE) {
@@ -2144,7 +2088,7 @@ static void canvas_donecanvasdialog(t_glist *x,
 
 	/* parent windows are treated differently than applies to individual objects */
 	if (glist_getcanvas(x) != x && !canvas_isabstraction(x)) {
-		canvas_apply_setundo(glist_getcanvas(x), glist_getindex(glist_getcanvas(x),(t_gobj *)x));
+		canvas_apply_setundo(glist_getcanvas(x), (t_gobj *)x);
 	}
 	else /*if (x1!=x->gl_x1 || x2!=x->gl_x2 || y1!=x->gl_y1 || y2!=x->gl_y2 ||
 			graphme!=(x->gl_isgraph+2*x->gl_hidetext) || x->gl_pixwidth!=xpix ||
@@ -4032,6 +3976,7 @@ static void canvas_paste_atmouse(t_canvas *x)
 extern void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv);
 extern void canvas_howputnew(t_canvas *x, int *connectp, int *xpixp, int *ypixp,
     int *indexp, int *totalp);
+extern int we_are_undoing;
 
 static void canvas_dopaste(t_canvas *x, t_binbuf *b)
 {
@@ -4126,7 +4071,8 @@ static void canvas_dopaste(t_canvas *x, t_binbuf *b)
 	//if we are copying from external buffer and the current canvas is not empty
 	else if (canvas_undo_name && !strcmp(canvas_undo_name, "paste") && !copyfromexternalbuffer ||
 		copyfromexternalbuffer && !canvas_empty) {
-		canvas_paste_atmouse(x);
+		if (!copyfromexternalbuffer) canvas_paste_xyoffset(x);
+		if (!we_are_undoing) canvas_paste_atmouse(x);
 		//fprintf(stderr,"doing a paste\n");
 	}
 	//else let's provide courtesy offset
diff --git a/src/g_text.c b/src/g_text.c
index d1658c3b622aea4bdd3dfe347a3d6efdc902535f..bd9e04944cdfdedb18b7f0acb854e5153a0e1553 100644
--- a/src/g_text.c
+++ b/src/g_text.c
@@ -832,6 +832,9 @@ static void gatom_click(t_gatom *x,
     }
 }
 
+EXTERN int glist_getindex(t_glist *x, t_gobj *y);
+EXTERN int canvas_apply_restore_original_position(t_canvas *x, int pos);
+
     /* message back from dialog window */
 static void gatom_param(t_gatom *x, t_symbol *sel, int argc, t_atom *argv)
 {
@@ -1782,9 +1785,7 @@ void text_eraseborder(t_text *x, t_glist *glist, char *tag)
     /* change text; if T_OBJECT, remake it.  LATER we'll have an undo buffer
     which should be filled in here before making the change. */
 
-EXTERN int check_for_redundant_typed_undo(t_canvas *x, void *data);
-
-void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize)
+void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize, int pos)
 {
 	char *c1, *c2;
 	int i1, i2;
@@ -1810,10 +1811,11 @@ void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize)
 			binbuf_gettext(b, &c2, &i2);
 			if (strcmp(c1, c2)) {
 				canvas_undo_add(glist_getcanvas(glist), 10, "recreate",
-					(void *)canvas_undo_set_recreate(glist_getcanvas(glist), &x->te_g));
+					(void *)canvas_undo_set_recreate(glist_getcanvas(glist), &x->te_g, pos));
 		        typedmess(&x->te_pd, gensym("rename"), natom2-1, vec2+1);
 		        binbuf_free(x->te_binbuf);
 		        x->te_binbuf = b;
+				//canvas_apply_restore_original_position(glist_getcanvas(glist), pos);
 			}
         }
         else  /* normally, just destroy the old one and make a new one. */
@@ -1824,7 +1826,7 @@ void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize)
 			if (strcmp(c1, c2)) {
 				fprintf(stderr,"text_setto calls canvas_undo_add\n");
 				canvas_undo_add(glist_getcanvas(glist), 10, "recreate",
-					(void *)canvas_undo_set_recreate(glist_getcanvas(glist), &x->te_g));
+					(void *)canvas_undo_set_recreate(glist_getcanvas(glist), &x->te_g, pos));
 		        int xwas = x->te_xpix, ywas = x->te_ypix;
 				canvas_eraselinesfor(glist, x);
 		        glist_delete(glist, &x->te_g);
@@ -1833,6 +1835,7 @@ void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize)
 		        if (newest && pd_class(newest) == canvas_class)
 		            canvas_loadbang((t_canvas *)newest);
 		        canvas_restoreconnections(glist_getcanvas(glist));
+				//canvas_apply_restore_original_position(glist_getcanvas(glist), pos);
 			}
         }
             /* if we made a new "pd" or changed a window name,
diff --git a/src/g_undo.c b/src/g_undo.c
index 6b7373bbde4a230d3762116af694238a62f6da28..c9dd628dfb5ed5d152297ec2ffe8cc06d29f0c3e 100644
--- a/src/g_undo.c
+++ b/src/g_undo.c
@@ -62,10 +62,11 @@ void canvas_undo_undo(t_canvas *x)
 		    case 3:	canvas_undo_cut(x, x->u_last->data, UNDO_UNDO); break; 			//cut
 		    case 4:	canvas_undo_move(x, x->u_last->data, UNDO_UNDO); break;			//move
 		    case 5:	canvas_undo_paste(x, x->u_last->data, UNDO_UNDO); break;		//paste
+		    case 6:	canvas_undo_apply(x, x->u_last->data, UNDO_UNDO); break;		//apply
 		    case 9:	canvas_undo_create(x, x->u_last->data, UNDO_UNDO); break;		//create
 		    case 10:canvas_undo_recreate(x, x->u_last->data, UNDO_UNDO); break;		//recreate
 		    default:
-		        error("canvas_undo_undo: unsupported undo command");
+		        error("canvas_undo_undo: unsupported undo command %d", x->u_last->type);
         }
 		x->u_last = x->u_last->prev;
 		char *undo_action = x->u_last->name;
@@ -92,10 +93,11 @@ void canvas_undo_redo(t_canvas *x)
 		    case 3:	canvas_undo_cut(x, x->u_last->data, UNDO_REDO); break; 			//cut
 		    case 4:	canvas_undo_move(x, x->u_last->data, UNDO_REDO); break;			//move
 		    case 5:	canvas_undo_paste(x, x->u_last->data, UNDO_REDO); break;		//paste
+		    case 6:	canvas_undo_apply(x, x->u_last->data, UNDO_REDO); break;		//apply
 		    case 9:	canvas_undo_create(x, x->u_last->data, UNDO_REDO); break;		//create
 		    case 10:canvas_undo_recreate(x, x->u_last->data, UNDO_REDO); break;		//recreate
 		    default:
-		        error("canvas_undo_redo: unsupported undo command");
+		        error("canvas_undo_redo: unsupported redo command %d", x->u_last->type);
         }
 		char *undo_action = x->u_last->name;
 		char *redo_action = (x->u_last->next ? x->u_last->next->name : "no");
@@ -113,7 +115,7 @@ void canvas_undo_rebranch(t_canvas *x)
 	if (x->u_last->next) {
 		t_undo_action *a;
 		for(a = x->u_last->next; a; a = a->next) {
-			fprintf(stderr,".");
+			//fprintf(stderr,".");
 		    switch(a->type)
 		    {
 				case 1:	canvas_undo_connect(x, a->data, UNDO_FREE); break; 		//connect
@@ -121,10 +123,11 @@ void canvas_undo_rebranch(t_canvas *x)
 				case 3:	canvas_undo_cut(x, a->data, UNDO_FREE); break; 			//cut
 				case 4:	canvas_undo_move(x, a->data, UNDO_FREE); break;			//move
 				case 5:	canvas_undo_paste(x, a->data, UNDO_FREE); break;		//paste
+				case 6:	canvas_undo_apply(x, a->data, UNDO_FREE); break;		//apply
 				case 9:	canvas_undo_create(x, a->data, UNDO_FREE); break;		//create
 				case 10:canvas_undo_recreate(x, a->data, UNDO_FREE); break;		//recreate
 				default:
-				    error("canvas_undo_rebranch: unsupported undo command");
+				    error("canvas_undo_rebranch: unsupported undo command %d", a->type);
 		    }
 			freebytes(a, sizeof(*a));
 		}
@@ -151,15 +154,17 @@ void canvas_undo_free(t_canvas *x)
 			//fprintf(stderr,".");
 		    switch(a->type)
 		    {
+				case 0: break;													//init
 				case 1:	canvas_undo_connect(x, a->data, UNDO_FREE); break; 		//connect
 				case 2:	canvas_undo_disconnect(x, a->data, UNDO_FREE); break; 	//disconnect
 				case 3:	canvas_undo_cut(x, a->data, UNDO_FREE); break; 			//cut
 				case 4:	canvas_undo_move(x, a->data, UNDO_FREE); break;			//move
 				case 5:	canvas_undo_paste(x, a->data, UNDO_FREE); break;		//paste
+				case 6:	canvas_undo_paste(x, a->data, UNDO_FREE); break;		//apply
 				case 9:	canvas_undo_create(x, a->data, UNDO_FREE); break;		//create
 				case 10:canvas_undo_recreate(x, a->data, UNDO_FREE); break;		//recreate
 				default:
-				    error("canvas_undo_rebranch: unsupported undo command");
+				    error("canvas_undo_free: unsupported undo command %d", a->type);
 		    }
 			freebytes(a, sizeof(*a));
 		}
diff --git a/src/g_undo.h b/src/g_undo.h
index 8dd13f6eaa61aa710e719da247798c89eabab0ba..61c2c96efb1976ec8018ae754a65009b7140dfef 100644
--- a/src/g_undo.h
+++ b/src/g_undo.h
@@ -90,6 +90,11 @@ EXTERN void canvas_undo_move(t_canvas *x, void *z, int action);
 EXTERN void *canvas_undo_set_paste(t_canvas *x, int offset);
 EXTERN void canvas_undo_paste(t_canvas *x, void *z, int action);
 
+/* --------- 6. apply ------------ */
+
+EXTERN void *canvas_undo_set_apply(t_canvas *x, int n);
+EXTERN void canvas_undo_apply(t_canvas *x, void *z, int action);
+
 /* --------- 9. create ----------- */
 
 EXTERN void canvas_undo_create(t_canvas *x, void *z, int action);
@@ -98,7 +103,7 @@ EXTERN void *canvas_undo_set_create(t_canvas *x);
 /* --------- 10. recreate -------- */
 
 EXTERN void canvas_undo_recreate(t_canvas *x, void *z, int action);
-EXTERN void *canvas_undo_set_recreate(t_canvas *x, t_gobj *y);
+EXTERN void *canvas_undo_set_recreate(t_canvas *x, t_gobj *y, int old_pos);
 
 /* ------------------------------- */