diff --git a/src/g_editor.c b/src/g_editor.c
index 607e39b171504b519fb911cfc37cba17d8e8d54c..2b192e7e3eec48d2c5a0927b69c97e2f46390698 100644
--- a/src/g_editor.c
+++ b/src/g_editor.c
@@ -67,6 +67,20 @@ struct _outlet
     t_symbol *o_sym;
 };
 
+/* ----------- 11. selection -------------- */
+typedef struct _undo_sel
+{
+    int u_index;
+    struct _undo_sel *sel_next;
+} t_undo_sel;
+
+typedef struct _undo_redo_sel
+{
+    t_undo_sel *u_undo;
+    t_undo_sel *u_redo;
+} t_undo_redo_sel;
+/* ---------------------------------------- */
+
 /* used for new duplicate behavior where we can "duplicate" into new window */
 static t_canvas *c_selection;
 
@@ -1709,6 +1723,72 @@ void canvas_undo_recreate(t_canvas *x, void *z, int action)
 	}
 }
 
+/* ----------- 11. selection -------------- */
+
+//structs are defined at the top of the file due to unusual undo/redo design of the selection
+
+void *canvas_undo_set_selection(t_canvas *x)
+{
+	t_undo_sel *u_sel = (t_undo_sel *)getbytes(sizeof(*u_sel));
+	u_sel->u_index = -1;
+	if (x->gl_editor->e_selection) {
+		t_gobj *g = x->gl_list;
+		int index = 0;
+		t_undo_sel *tmp = u_sel;
+
+		while (g) {
+			if (glist_isselected(x, g)) {
+				tmp->u_index = index;
+				if (g->g_next) {
+					t_undo_sel *u_sel_next = (t_undo_sel *)getbytes(sizeof(*u_sel_next));
+					u_sel_next->u_index = -1;
+					tmp->sel_next = u_sel_next;
+					tmp = u_sel_next;
+				}
+			}
+			index++;
+			g = g->g_next;
+		}
+	}
+    return (u_sel);
+}
+
+void canvas_undo_selection(t_canvas *x, void *z, int action)
+{
+    t_undo_redo_sel *u_main = z;
+	t_undo_sel *u_sel;
+
+    if (action == UNDO_UNDO || action == UNDO_REDO) 
+    {
+		if (action == UNDO_UNDO) u_sel = u_main->u_undo;
+		else u_sel = u_main->u_redo;
+
+		glist_noselect(x);
+
+		while(u_sel) {
+			if (u_sel->u_index > -1)
+				glist_select(x, glist_nth(x, u_sel->u_index));
+			u_sel = u_sel->sel_next;
+		}
+    }
+    else if (action == UNDO_FREE)
+    {
+		u_sel = u_main->u_undo;
+		while (u_sel) {
+			t_undo_sel *destroy = u_sel;
+			u_sel = u_sel->sel_next;
+		    freebytes(destroy, sizeof(*destroy));
+		}
+		u_sel = u_main->u_redo;
+		while (u_sel) {
+			t_undo_sel *destroy = u_sel;
+			u_sel = u_sel->sel_next;
+		    freebytes(destroy, sizeof(*destroy));
+		}
+		freebytes(u_main, sizeof(*u_main));
+    }
+}
+
 /* ------------------------ event handling ------------------------ */
 
 static char *cursorlist[] = {
@@ -2495,9 +2575,15 @@ void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
                 }
                 else
                 {
+					t_undo_redo_sel *buf = (t_undo_redo_sel *)getbytes(sizeof(*buf));
+					buf->u_undo = (t_undo_sel *)canvas_undo_set_selection(x);
+
                     if (glist_isselected(x, y))
                         glist_deselect(x, y);
                     else glist_select(x, y);
+
+					buf->u_redo = (t_undo_sel *)canvas_undo_set_selection(x);
+					canvas_undo_add(x, 11, "selection", buf);
                 }
             }
         }
@@ -2586,8 +2672,14 @@ void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
                         /* otherwise select and drag to displace */
                     if (!glist_isselected(x, y))
                     {
+						t_undo_redo_sel *buf = (t_undo_redo_sel *)getbytes(sizeof(*buf));
+						buf->u_undo = (t_undo_sel *)canvas_undo_set_selection(x);
+
                         glist_noselect(x);
                         glist_select(x, y);
+
+						buf->u_redo = (t_undo_sel *)canvas_undo_set_selection(x);
+						canvas_undo_add(x, 11, "selection", buf);
                     }
 					//toggle_moving = 1;
 					//sys_vgui("pdtk_update_xy_tooltip .x%lx %d %d\n", x, (int)xpos, (int)ypos);
@@ -2712,7 +2804,15 @@ void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
     canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
     if (doit)
     {
-        if (!shiftmod) glist_noselect(x);
+        if (!shiftmod && x->gl_editor->e_selection) {
+			t_undo_redo_sel *buf = (t_undo_redo_sel *)getbytes(sizeof(*buf));
+			buf->u_undo = (t_undo_sel *)canvas_undo_set_selection(x);
+
+			glist_noselect(x);
+
+			buf->u_redo = (t_undo_sel *)canvas_undo_set_selection(x);
+			canvas_undo_add(x, 11, "selection", buf);
+		}
         sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags x -outline $select_color\n",
               x, xpos, ypos, xpos, ypos);
         x->gl_editor->e_xwas = xpos;
@@ -2909,17 +3009,29 @@ void canvas_doconnect(t_canvas *x, int xpos, int ypos, int which, int doit)
 
 void canvas_selectinrect(t_canvas *x, int lox, int loy, int hix, int hiy)
 {
+	//fprintf(stderr,"canvas_selectinrect\n");
     t_gobj *y;
+	t_undo_redo_sel *buf=NULL;
+	int selection_changed = 0;
     for (y = x->gl_list; y; y = y->g_next)
     {
         int x1, y1, x2, y2;
         gobj_getrect(y, x, &x1, &y1, &x2, &y2);
         if (hix >= x1 && lox <= x2 && hiy >= y1 && loy <= y2) {
+			if (!selection_changed) {
+				buf = (t_undo_redo_sel *)getbytes(sizeof(*buf));
+				buf->u_undo = (t_undo_sel *)canvas_undo_set_selection(x);
+				selection_changed = 1;
+			}
 			if (!glist_isselected(x, y))
 		    	glist_select(x, y);
 			else glist_deselect(x, y);
 		}
     }
+	if (buf) {
+		buf->u_redo = (t_undo_sel *)canvas_undo_set_selection(x);
+		canvas_undo_add(x, 11, "selection", buf);
+	}
 }
 
 static void canvas_doregion(t_canvas *x, int xpos, int ypos, int doit)
diff --git a/src/g_undo.c b/src/g_undo.c
index 22f106774c94d9f7ea6573e2b4f0e13c85978864..e30a0c87b879aa27c97e65ad08195b4f5fa075d9 100644
--- a/src/g_undo.c
+++ b/src/g_undo.c
@@ -67,6 +67,7 @@ void canvas_undo_undo(t_canvas *x)
 		    case 8:	canvas_undo_canvas_apply(x, x->u_last->data, UNDO_UNDO); break;	//canvas 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
+			case 11:canvas_undo_selection(x, x->u_last->data, UNDO_UNDO); break;	//selection
 		    default:
 		        error("canvas_undo_undo: unsupported undo command %d", x->u_last->type);
         }
@@ -100,6 +101,7 @@ void canvas_undo_redo(t_canvas *x)
 		    case 8:	canvas_undo_canvas_apply(x, x->u_last->data, UNDO_REDO); break;	//canvas 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
+			case 11:canvas_undo_selection(x, x->u_last->data, UNDO_REDO); break;	//selection
 		    default:
 		        error("canvas_undo_redo: unsupported redo command %d", x->u_last->type);
         }
@@ -132,6 +134,7 @@ void canvas_undo_rebranch(t_canvas *x)
 			    case 8:	canvas_undo_canvas_apply(x, a->data, UNDO_FREE); break;	//canvas 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
+				case 11:canvas_undo_selection(x, a->data, UNDO_FREE); break;	//selection
 				default:
 				    error("canvas_undo_rebranch: unsupported undo command %d", a->type);
 		    }
@@ -171,6 +174,7 @@ void canvas_undo_free(t_canvas *x)
 			    case 8:	canvas_undo_canvas_apply(x, a->data, UNDO_FREE); break;	//canvas 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
+				case 11:canvas_undo_selection(x, a->data, UNDO_FREE); break;	//selection
 				default:
 				    error("canvas_undo_free: unsupported undo command %d", a->type);
 		    }
diff --git a/src/g_undo.h b/src/g_undo.h
index 7614758de27907d7a67cd15b78c4299285c28fa8..9fb1fb1932a7fc2786bc1480e9c1b50a7af060d3 100644
--- a/src/g_undo.h
+++ b/src/g_undo.h
@@ -115,6 +115,11 @@ EXTERN void *canvas_undo_set_create(t_canvas *x);
 EXTERN void canvas_undo_recreate(t_canvas *x, void *z, int action);
 EXTERN void *canvas_undo_set_recreate(t_canvas *x, t_gobj *y, int old_pos);
 
+/* --------- 11. selection ------- */
+
+EXTERN void canvas_undo_selection(t_canvas *x, void *z, int action);
+EXTERN void *canvas_undo_set_selection(t_canvas *x);
+
 /* ------------------------------- */
 
 #endif /* __g_undo_h_ */