diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c
index e0b3f53e0798c019caa6774f2beb17be72fc7a6b..038d0fa545a5c00a8bd1b3505f6740de253c7ef3 100644
--- a/pd/src/g_editor.c
+++ b/pd/src/g_editor.c
@@ -44,6 +44,7 @@ static void canvas_done_popup(t_canvas *x, t_float which, t_float xpos, t_float
 static void canvas_doarrange(t_canvas *x, t_float which, t_gobj *oldy, t_gobj *oldy_prev, t_gobj *oldy_next);
 static void canvas_paste_xyoffset(t_canvas *x);
 void canvas_setgraph(t_glist *x, int flag, int nogoprect);
+void canvas_mouseup(t_canvas *x, t_floatarg fxpos, t_floatarg fypos, t_floatarg fwhich);
 static char canvas_cnct_inlet_tag[4096];
 static char canvas_cnct_outlet_tag[4096];
 static int outlet_issignal = 0;
@@ -75,6 +76,10 @@ int old_displace = 0;	   // for legacy displaces within gop that are not visible
 int connect_exception = 0; // used when autopatching to bypass check whether one is trying to connect signal with non-signal nlet
 						   // since this is impossible to figure out when the newly created object is an empty one
 
+// used to test whether the shift is pressed and if so, handle various connection exceptions (e.g. multiconnect)
+int glob_lmclick = 0;
+int glob_shift = 0;
+
 struct _outlet
 {
     t_object *o_owner;
@@ -2589,6 +2594,12 @@ void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
     altmod = (mod & ALTMOD);
     rightclick = (mod & RIGHTCLICK);
 
+	if (!rightclick) glob_lmclick = doit;
+	if (x->gl_editor->e_onmotion == MA_CONNECT && glob_shift) {
+		//fprintf(stderr,"MA_CONNECT + glob_shift--> mouse_doclick returning\n");
+		return;
+	}
+
     canvas_undo_already_set_move = 0;
 
             /* if keyboard was grabbed, notify grabber and cancel the grab */
@@ -2650,9 +2661,9 @@ void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
         ob = pd_checkobject(&y->g_pd);
         if (rightclick)
             canvas_rightclick(x, xpos, ypos, y);
-        else if (shiftmod)
+        else if (shiftmod && canvas_cnct_outlet_tag[0] == 0)
         {
-			//selection
+			//selection (only if we are not hovering above an nlet)
             if (doit)
             {
                 t_rtext *rt;
@@ -2695,7 +2706,7 @@ void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
                 {
                     if (doit)
                     {
-
+						//fprintf(stderr,"start connection\n");
                         int issignal = obj_issignaloutlet(ob, closest);
                         x->gl_editor->e_onmotion = MA_CONNECT;
                         x->gl_editor->e_xwas = xpos;
@@ -3038,16 +3049,567 @@ int canvas_isconnected (t_canvas *x, t_text *ob1, int n1,
     return (0);
 }
 
+void canvas_sort_selection_according_to_location(t_canvas *x)
+{
+	int n_selected = glist_selectionindex(x, 0, 1); // get all selected objects
+	//fprintf(stderr,"n_selected = %d\n", n_selected);
+	t_selection *traverse, *sel[n_selected];
+	int map[n_selected];
+	int already_mapped = 0;
+	int i = 0, j = 0, k = 0, leftmost = 99999, topmost = 99999;
+	t_text *yt;
+	for (traverse = x->gl_editor->e_selection; traverse; traverse = traverse->sel_next) {
+		sel[i] = traverse;
+		map[i] = -1;
+		i++;
+	}
+	for (i = 0; i < n_selected; i++) {
+		for (j = 0; j < n_selected; j++) {
+			yt = (t_text *)(sel[j]->sel_what);
+			if ((yt->te_xpix < leftmost) ||
+				(yt->te_xpix == leftmost && yt->te_ypix <= topmost)) {
+				for (k = 0; k < n_selected; k++) {
+					if (map[k] == j) {
+						already_mapped = 1;
+					}
+				}
+				if (!already_mapped) {
+					map[i] = j;
+					leftmost = yt->te_xpix;
+					topmost = yt->te_ypix;
+				}
+				already_mapped = 0;
+			}
+		}
+		leftmost = 99999;
+		topmost = 99999;
+	}
+	/*
+	// debug
+	for (i = 0; i < n_selected; i++) {
+		yt = (t_text *)(sel[map[i]]->sel_what);
+		fprintf(stderr,"sorted: %d (%d) x=%d y=%d\n", i, map[i], yt->te_xpix, yt->te_ypix);
+	}*/
+	x->gl_editor->e_selection = sel[map[0]];
+	for (i = 0; i < n_selected-1; i++) {
+		sel[map[i]]->sel_next = sel[map[i+1]];
+	}
+	sel[map[n_selected-1]]->sel_next = 0;
+
+	/*
+	// debug
+	i = 0;
+	for (traverse = x->gl_editor->e_selection; traverse; traverse = traverse->sel_next) {
+		yt = (t_text *)(traverse->sel_what);
+		fprintf(stderr,"final: %d x=%d y=%d\n", i, yt->te_xpix, yt->te_ypix);
+		i++;
+	}*/
+}
+
+int canvas_doconnect_doit(t_canvas *x, t_gobj *y1, t_gobj *y2, int closest1, int closest2, int multi, int create_undo)
+{
+    int x11=0, y11=0, x12=0, y12=0;
+    int x21=0, y21=0, x22=0, y22=0;
+	int lx1, lx2, ly1, ly2;
+    int noutlet1, ninlet2;
+	t_object *ob1, *ob2;
+	t_outconnect *oc, *oc2;
+
+    ob1 = pd_checkobject(&y1->g_pd);
+    ob2 = pd_checkobject(&y2->g_pd);
+    noutlet1 = obj_noutlets(ob1);
+    ninlet2 = obj_ninlets(ob2);
+	gobj_getrect(y1, x, &x11, &y11, &x12, &y12);
+	gobj_getrect(y2, x, &x21, &y21, &x22, &y22);
+
+    if (canvas_isconnected (x, ob1, closest1, ob2, closest2))
+    {
+		if(x->gl_magic_glass) {                
+			magicGlass_unbind(x->gl_magic_glass);
+        	magicGlass_hide(x->gl_magic_glass);
+		}
+		if (!multi)
+            canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
+        return(1);
+    }
+    if (obj_issignaloutlet(ob1, closest1) &&
+        !obj_issignalinlet(ob2, closest2))
+    {
+        error("cannot connect signal outlet to control inlet");
+       	if(x->gl_magic_glass) {
+			magicGlass_unbind(x->gl_magic_glass);
+            magicGlass_hide(x->gl_magic_glass);
+		}
+        if (!multi)
+            canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
+        return(1);
+    }
+
+	// if the first object is preset_node, check if the object we are connecting to
+	// is supported. If not, disallow connection
+	
+	if (pd_class(&y1->g_pd) == preset_node_class) {
+		if (pd_class(&y2->g_pd) == message_class) {
+			error("preset_node does not work with messages.");
+			return(1);
+		}
+	}
+
+	// now check if explicit user-made connection into preset_node is other than message
+	// messages may be used to change node's operation
+	if (pd_class(&y2->g_pd) == preset_node_class && pd_class(&y1->g_pd) != message_class) {
+		error("preset node only accepts messages as input to adjust its settings...\n");
+		return(1);
+	}
+
+    int issignal = obj_issignaloutlet(ob1, closest1);
+    oc = obj_connect(ob1, closest1, ob2, closest2);
+	outconnect_setvisible(oc, 1);
+    lx1 = x11 + (noutlet1 > 1 ?
+            ((x12-x11-IOWIDTH) * closest1)/(noutlet1-1) : 0)
+                 + IOMIDDLE;
+    ly1 = y12;
+    lx2 = x21 + (ninlet2 > 1 ?
+            ((x22-x21-IOWIDTH) * closest2)/(ninlet2-1) : 0)
+                + IOMIDDLE;
+    ly2 = y21;
+    sys_vgui(".x%lx.c create line %d %d %d %d -fill %s -width %s -tags {l%lx all_cords}\n",
+        glist_getcanvas(x),
+            lx1, ly1, lx2, ly2,
+        (issignal ? "$signal_cord" : "$msg_cord"),
+        (issignal ? "$signal_cord_width" : "$msg_cord_width"), 
+        oc);
+    if (canvas_cnct_inlet_tag[0] != 0)
+    {
+        sys_vgui(".x%x.c itemconfigure %s -outline %s -fill %s -width 1\n",
+               	x, canvas_cnct_inlet_tag,
+				(last_inlet_filter ? "black" : (obj_issignaloutlet(ob1, closest1) ? "$signal_cord" : "$msg_cord")),
+				(inlet_issignal ? "$signal_nlet" : "$msg_nlet"));
+		if (objtooltip) {
+			objtooltip = 0;
+			sys_vgui("pdtk_canvas_leaveitem .x%x.c;\n", x);
+		}
+        canvas_cnct_inlet_tag[0] = 0;                  
+    }
+    if (canvas_cnct_outlet_tag[0] != 0)
+    {
+        sys_vgui(".x%x.c itemconfigure %s -outline %s -fill %s -width 1\n",
+               	x, canvas_cnct_outlet_tag,
+				(last_outlet_filter ? "black" : (outlet_issignal ? "$signal_cord" : "$msg_cord")),
+				(outlet_issignal ? "$signal_nlet" : "$msg_nlet"));
+		if (objtooltip) {
+			objtooltip = 0;
+			sys_vgui("pdtk_canvas_leaveitem .x%x.c;\n", x);
+		}
+        canvas_cnct_outlet_tag[0] = 0;                  
+    }
+    // end jsarlo
+    canvas_dirty(x, 1);
+    /*canvas_setundo(x, canvas_undo_connect,
+        canvas_undo_set_connect(x, 
+            canvas_getindex(x, &ob1->ob_g), closest1,
+            canvas_getindex(x, &ob2->ob_g), closest2),
+            "connect");*/
+	if (create_undo) {
+		canvas_undo_add(x, 1, "connect", canvas_undo_set_connect(x, 
+		        canvas_getindex(x, &ob1->ob_g), closest1,
+		        canvas_getindex(x, &ob2->ob_g), closest2));
+	}
+
+	// add auto-connect back to preset_node object
+	// (by this time we know we are connecting only to legal objects who have at least one outlet)
+	if (pd_class(&y1->g_pd) == preset_node_class) {
+		//fprintf(stderr,"gotta do auto-connect back to preset_node\n");
+		if (!canvas_isconnected(x, ob2, 0, ob1, 0) && pd_class(&y2->g_pd) != print_class) {
+			oc2 = obj_connect(ob2, 0, ob1, 0);
+			outconnect_setvisible(oc2, 0);
+		}
+		//else
+		//	fprintf(stderr,"error: already connected (this happens when loading from file and is ok)\n");
+	}
+	return(0);
+}
+
+int canvas_trymulticonnect(t_canvas *x, int xpos, int ypos, int which, int doit)
+{
+	//fprintf(stderr,"canvas_trymulticonnect\n");
+    int x11=0, y11=0, x12=0, y12=0;
+    t_gobj *y1;
+    int x21=0, y21=0, x22=0, y22=0;
+    t_gobj *y2;
+    int xwas = x->gl_editor->e_xwas,
+        ywas = x->gl_editor->e_ywas;
+	t_object *ob1, *ob2;
+	int noutlet1, ninlet2;
+	int i;
+	int return_val = 1;
+
+    if (!glob_shift) sys_vgui(".x%lx.c delete x\n", x);
+
+	if ((y1 = canvas_findhitbox(x, xwas, ywas, &x11, &y11, &x12, &y12))
+		    && (y2 = canvas_findhitbox(x, xpos, ypos, &x21, &y21, &x22, &y22)))
+	{
+		// FIRST OPTION: if two objects are selected and the one that is originating
+		// is one of the selected objects try multi-connecting all outlets into
+		// all inlets starting with the user-made one as an offset
+		if (!x->gl_editor->e_selection->sel_next->sel_next && glist_isselected(x, y1) && glist_isselected(x, y2))
+		{
+			//fprintf(stderr,"first option\n");
+		    ob1 = pd_checkobject(&y1->g_pd);
+		    ob2 = pd_checkobject(&y2->g_pd);
+		    if (ob1 && ob2 && ob1 != ob2 &&
+		        (noutlet1 = obj_noutlets(ob1))
+		        && (ninlet2 = obj_ninlets(ob2)))
+		    {
+		        int width1 = x12 - x11, closest1, hotspot1;
+		        int width2 = x22 - x21, closest2, hotspot2;
+		        int lx1, lx2, ly1, ly2;
+		        t_outconnect *oc, *oc2;
+
+		        if (noutlet1 > 1)
+		        {
+		            closest1 = ((xwas-x11) * (noutlet1-1) + width1/2)/width1;
+		            hotspot1 = x11 +
+		                (width1 - IOWIDTH) * closest1 / (noutlet1-1);
+		        }
+		        else closest1 = 0, hotspot1 = x11;
+
+		        if (ninlet2 > 1)
+		        {
+		            closest2 = ((xpos-x21) * (ninlet2-1) + width2/2)/width2;
+		            hotspot2 = x21 +
+		                (width2 - IOWIDTH) * closest2 / (ninlet2-1);
+		        }
+		        else closest2 = 0, hotspot2 = x21;
+
+		        if (closest1 >= noutlet1)
+		            closest1 = noutlet1 - 1;
+		        if (closest2 >= ninlet2)
+		            closest2 = ninlet2 - 1;
+
+				int nconnections = ( noutlet1 - closest1 < ninlet2 - closest2 ? noutlet1 - closest1 : ninlet2 - closest2 );
+				for (i = 0; i < nconnections; i++) {
+					return_val = canvas_doconnect_doit(x, y1, y2, closest1 + i, closest2 + i, 1, 1);
+				}
+			}
+			return(return_val);
+		// end of FIRST OPTION
+		}
+		// SECOND OPTION: if more than two objects are selected and the one that is originating
+		// is not one of the selected, connect originating to all selected objects' the outlets
+		// specified by the first connection
+		else if (x->gl_editor->e_selection->sel_next && !glist_isselected(x, y1) && glist_isselected(x, y2))
+		{
+			//fprintf(stderr,"second option\n");
+		    ob1 = pd_checkobject(&y1->g_pd);
+		    ob2 = pd_checkobject(&y2->g_pd);
+		    int noutlet1, ninlet2;
+		    if (ob1 && ob2 && ob1 != ob2 &&
+		        (noutlet1 = obj_noutlets(ob1))
+		        && (ninlet2 = obj_ninlets(ob2)))
+		    {
+		        int width1 = x12 - x11, closest1, hotspot1;
+		        int width2 = x22 - x21, closest2, hotspot2;
+		        int lx1, lx2, ly1, ly2;
+		        t_outconnect *oc, *oc2;
+
+		        if (noutlet1 > 1)
+		        {
+		            closest1 = ((xwas-x11) * (noutlet1-1) + width1/2)/width1;
+		            hotspot1 = x11 +
+		                (width1 - IOWIDTH) * closest1 / (noutlet1-1);
+		        }
+		        else closest1 = 0, hotspot1 = x11;
+
+		        if (ninlet2 > 1)
+		        {
+		            closest2 = ((xpos-x21) * (ninlet2-1) + width2/2)/width2;
+		            hotspot2 = x21 +
+		                (width2 - IOWIDTH) * closest2 / (ninlet2-1);
+		        }
+		        else closest2 = 0, hotspot2 = x21;
+
+		        if (closest1 >= noutlet1)
+		            closest1 = noutlet1 - 1;
+		        if (closest2 >= ninlet2)
+		            closest2 = ninlet2 - 1;
+
+				return_val = canvas_doconnect_doit(x, y1, y2, closest1, closest2, 1, 1);
+
+				// now that we made the initial connection and know where to begin and where to connect to, let's connect the rest
+				t_selection *sel;
+    			for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next) {
+					// do this only with objects that have not been connected as of yet
+					if (sel->sel_what != y1 && sel->sel_what != y2) {
+						ob2 = pd_checkobject(&sel->sel_what->g_pd);
+						ninlet2 = obj_ninlets(ob2);
+						if (closest2 < ninlet2) {
+							return_val = canvas_doconnect_doit(x, y1, sel->sel_what, closest1, closest2, 1, 1);
+						}
+					}
+				}	
+			}
+			return(return_val);
+		// end of SECOND OPTION
+		}
+
+		// THIRD OPTION: if more than two objects are selected and the one that is receiving connection
+		// is one of the selected, and the target object is selected, connect nth outlet (as specified by
+		// the first connection) from all selected objects into the inlet of the unselected one
+		else if (x->gl_editor->e_selection->sel_next->sel_next && glist_isselected(x, y1) && !glist_isselected(x, y2))
+		{
+			//fprintf(stderr,"third option\n");
+		    ob1 = pd_checkobject(&y1->g_pd);
+		    ob2 = pd_checkobject(&y2->g_pd);
+		    int noutlet1, ninlet2;
+		    if (ob1 && ob2 && ob1 != ob2 &&
+		        (noutlet1 = obj_noutlets(ob1))
+		        && (ninlet2 = obj_ninlets(ob2)))
+		    {
+		        int width1 = x12 - x11, closest1, hotspot1;
+		        int width2 = x22 - x21, closest2, hotspot2;
+		        int lx1, lx2, ly1, ly2;
+		        t_outconnect *oc, *oc2;
+
+		        if (noutlet1 > 1)
+		        {
+		            closest1 = ((xwas-x11) * (noutlet1-1) + width1/2)/width1;
+		            hotspot1 = x11 +
+		                (width1 - IOWIDTH) * closest1 / (noutlet1-1);
+		        }
+		        else closest1 = 0, hotspot1 = x11;
+
+		        if (ninlet2 > 1)
+		        {
+		            closest2 = ((xpos-x21) * (ninlet2-1) + width2/2)/width2;
+		            hotspot2 = x21 +
+		                (width2 - IOWIDTH) * closest2 / (ninlet2-1);
+		        }
+		        else closest2 = 0, hotspot2 = x21;
+
+		        if (closest1 >= noutlet1)
+		            closest1 = noutlet1 - 1;
+		        if (closest2 >= ninlet2)
+		            closest2 = ninlet2 - 1;
+
+				return_val = canvas_doconnect_doit(x, y1, y2, closest1, closest2, 1, 1);
+
+				// now that we made the initial connection and know where to begin and where to connect to, let's connect the rest
+				t_selection *sel;
+    			for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next) {
+					// do this only with objects that have not been connected as of yet
+					if (sel->sel_what != y1 && sel->sel_what != y2) {
+						ob2 = pd_checkobject(&sel->sel_what->g_pd);
+						noutlet1 = obj_noutlets(ob2);
+						if (closest1 < noutlet1) {
+							return_val = canvas_doconnect_doit(x, sel->sel_what, y2, closest1, closest2, 1, 1);
+						}
+					}
+				}	
+			}
+			return(return_val);
+		// end of THIRD OPTION
+		}
+
+		// FOURTH OPTION: if more than two objects are selected and both y1 and y2 are selected
+		// connect each originating object's outlet to each of the outgoing objects' inlets until you run
+		// out of objects or outlets. This one is tricky as there is no guarrantee that objects will be selected
+		// in proper visual order, so we order the selection from left to right and top to bottom
+		// to ensure proper visual pairing. This option has two variants, A and B.
+
+		// OPTION A VS B: we either connect outgoing to each of other objects (A) or incoming to all other objects (B). We
+		// determine which one of the two options is selected based on which condition will yield more successful connections.
+		else if (x->gl_editor->e_selection->sel_next->sel_next && glist_isselected(x, y1) && glist_isselected(x, y2))
+		{
+			//fprintf(stderr,"fourth option\n");
+		    ob1 = pd_checkobject(&y1->g_pd);
+		    ob2 = pd_checkobject(&y2->g_pd);
+		    int noutlet1, ninlet2;
+		    if (ob1 && ob2 && ob1 != ob2 &&
+		        (noutlet1 = obj_noutlets(ob1))
+		        && (ninlet2 = obj_ninlets(ob2)))
+		    {
+		        int width1 = x12 - x11, closest1, hotspot1;
+		        int width2 = x22 - x21, closest2, hotspot2;
+		        int lx1, lx2, ly1, ly2;
+		        t_outconnect *oc, *oc2;
+
+		        if (noutlet1 > 1)
+		        {
+		            closest1 = ((xwas-x11) * (noutlet1-1) + width1/2)/width1;
+		            hotspot1 = x11 +
+		                (width1 - IOWIDTH) * closest1 / (noutlet1-1);
+		        }
+		        else closest1 = 0, hotspot1 = x11;
+
+		        if (ninlet2 > 1)
+		        {
+		            closest2 = ((xpos-x21) * (ninlet2-1) + width2/2)/width2;
+		            hotspot2 = x21 +
+		                (width2 - IOWIDTH) * closest2 / (ninlet2-1);
+		        }
+		        else closest2 = 0, hotspot2 = x21;
+
+		        if (closest1 >= noutlet1)
+		            closest1 = noutlet1 - 1;
+		        if (closest2 >= ninlet2)
+		            closest2 = ninlet2 - 1;
+
+				return_val = canvas_doconnect_doit(x, y1, y2, closest1, closest2, 1, 1);
+
+				// now that we made the initial connection and know where to begin and where to connect to, let's connect the rest
+				t_selection *sel;
+				// resort selection
+				canvas_sort_selection_according_to_location(x);
+				// now check for OPTION A vs. B (see description above)
+				int successA = 0;
+				int successB = 0;
+				int do_count;
+
+				// try option A
+				int tmp_closest1 = closest1;
+				int tmp_closest2 = closest2;
+				t_object *tmp_ob1 = ob1;
+				t_object *tmp_ob2 = ob2;
+				int tmp_noutlet1 = noutlet1;
+				int tmp_ninlet2 = ninlet2;
+				for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next) {
+					if (sel->sel_what != y1 && sel->sel_what != y2) {
+						tmp_ob2 = pd_checkobject(&sel->sel_what->g_pd);
+						tmp_ninlet2 = obj_ninlets(tmp_ob2);
+						tmp_closest1++;
+						if (tmp_closest1 >= tmp_noutlet1) {
+							break;
+						}
+						else if (tmp_closest2 < tmp_ninlet2) {
+							do_count = 1;
+							if (canvas_isconnected (x, tmp_ob1, tmp_closest1, tmp_ob2, tmp_closest2))
+							{
+								do_count = 0;
+							}
+							if (obj_issignaloutlet(ob1, closest1) &&
+								!obj_issignalinlet(ob2, closest2))
+							{
+								do_count = 0;
+							}	
+							if (pd_class(&tmp_ob1->ob_pd) == preset_node_class) {
+								if (pd_class(&tmp_ob2->ob_pd) == message_class) {
+									do_count = 0;
+								}
+							}
+							if (pd_class(&tmp_ob2->ob_pd) == preset_node_class && pd_class(&tmp_ob1->ob_pd) != message_class) {
+								do_count = 0;
+							}
+							successA += do_count;
+						}
+					}
+				}
+				//fprintf(stderr,"successA %d\n", successA);
+
+				// try option B
+				tmp_closest1 = closest1;
+				tmp_closest2 = closest2;
+				tmp_ob1 = ob1;
+				tmp_ob2 = ob2;
+				tmp_noutlet1 = noutlet1;
+				tmp_ninlet2 = ninlet2;
+				for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next) {
+					if (sel->sel_what != y1 && sel->sel_what != y2) {
+						tmp_ob1 = pd_checkobject(&sel->sel_what->g_pd);
+						tmp_noutlet1 = obj_noutlets(tmp_ob1);
+						tmp_closest2++;
+						if (tmp_closest2 >= tmp_ninlet2) {
+							break;
+						}
+						else if (tmp_closest1 < tmp_noutlet1) {
+							do_count = 1;
+							if (canvas_isconnected (x, tmp_ob1, tmp_closest1, tmp_ob2, tmp_closest2))
+							{
+								do_count = 0;
+							}
+							if (obj_issignaloutlet(ob1, closest1) &&
+								!obj_issignalinlet(ob2, closest2))
+							{
+								do_count = 0;
+							}	
+							if (pd_class(&tmp_ob1->ob_pd) == preset_node_class) {
+								if (pd_class(&tmp_ob2->ob_pd) == message_class) {
+									do_count = 0;
+								}
+							}
+							if (pd_class(&tmp_ob2->ob_pd) == preset_node_class && pd_class(&tmp_ob1->ob_pd) != message_class) {
+								do_count = 0;
+							}
+							successB += do_count;
+						}
+					}
+				}
+				//fprintf(stderr,"successB %d\n", successB);
+				
+				// now decide which one is better (we give preference to option A if both are equal)
+				if (successA >= successB)
+				{
+					// OPTION A (see description above)
+					for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
+					{
+						// do this only with objects that have not been connected as of yet
+						if (sel->sel_what != y1 && sel->sel_what != y2) {
+							ob2 = pd_checkobject(&sel->sel_what->g_pd);
+							ninlet2 = obj_ninlets(ob2);
+							closest1++;
+							if (closest1 >= noutlet1) {
+								break;
+							}
+							else if (closest2 < ninlet2) {
+								return_val = canvas_doconnect_doit(x, y1, sel->sel_what, closest1, closest2, 1, 1);
+							}
+						}
+					}
+				}
+				else
+				{
+					// OPTION B (see description above)
+					for (sel = x->gl_editor->e_selection; sel; sel = sel->sel_next)
+					{
+						// do this only with objects that have not been connected as of yet
+						if (sel->sel_what != y1 && sel->sel_what != y2) {
+							ob1 = pd_checkobject(&sel->sel_what->g_pd);
+							noutlet1 = obj_ninlets(ob1);
+							closest2++;
+							if (closest2 >= ninlet2) {
+								break;
+							}
+							else if (closest1 < noutlet1) {
+								return_val = canvas_doconnect_doit(x, sel->sel_what, y2, closest1, closest2, 1, 1);
+							}
+						}
+					}
+				}			
+			}			
+			return(return_val);
+		// end of FOURTH OPTION
+		}
+	}
+
+	return(1);
+}
+
 void canvas_doconnect(t_canvas *x, int xpos, int ypos, int which, int doit)
 {
 	//fprintf(stderr,"canvas_doconnect\n");
+	if (doit && x->gl_editor->e_selection && x->gl_editor->e_selection->sel_next) {
+		int result = canvas_trymulticonnect(x, xpos, ypos, which, doit);
+		if (!result) {
+			return;
+		}
+	}
     int x11=0, y11=0, x12=0, y12=0;
     t_gobj *y1;
     int x21=0, y21=0, x22=0, y22=0;
     t_gobj *y2;
     int xwas = x->gl_editor->e_xwas,
         ywas = x->gl_editor->e_ywas;
-    if (doit) sys_vgui(".x%lx.c delete x\n", x);
+    if (doit && !glob_shift) sys_vgui(".x%lx.c delete x\n", x);
     else {
 
 		sys_vgui(".x%lx.c coords x %d %d %d %d\n",
@@ -3092,113 +3654,9 @@ void canvas_doconnect(t_canvas *x, int xpos, int ypos, int which, int doit)
             if (closest2 >= ninlet2)
                 closest2 = ninlet2 - 1;
 
-            if (canvas_isconnected (x, ob1, closest1, ob2, closest2))
-            {
-                // jsarlo
-				if(x->gl_magic_glass) {                
-					magicGlass_unbind(x->gl_magic_glass);
-                	magicGlass_hide(x->gl_magic_glass);
-				}
-                // end jsarlo
-                canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
-                return;
-            }
-            if (obj_issignaloutlet(ob1, closest1) &&
-                !obj_issignalinlet(ob2, closest2))
-            {
-                if (doit)
-                    error("cannot connect signal outlet to control inlet");
-                // jsarlo
-               	if(x->gl_magic_glass) {
-					magicGlass_unbind(x->gl_magic_glass);
-	                magicGlass_hide(x->gl_magic_glass);
-				}
-                // end jsarlo
-                canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
-                return;
-            }
             if (doit)
             {
-				// if the first object is preset_node, check if the object we are connecting to
-				// is supported. If not, disallow connection
-				
-				if (pd_class(&y1->g_pd) == preset_node_class) {
-					if (pd_class(&y2->g_pd) == message_class) {
-						error("preset_node does not work with messages.");
-						return;
-					}
-				}
-
-				// now check if explicit user-made connection into preset_node if kind other than message
-				// messages may be used to change node's operation
-				if (pd_class(&y2->g_pd) == preset_node_class && pd_class(&y1->g_pd) != message_class) {
-					error("preset node only accepts messages as input to adjust its settings...\n");
-					return;
-				}
-
-                int issignal = obj_issignaloutlet(ob1, closest1);
-                oc = obj_connect(ob1, closest1, ob2, closest2);
-				outconnect_setvisible(oc, 1);
-                lx1 = x11 + (noutlet1 > 1 ?
-                        ((x12-x11-IOWIDTH) * closest1)/(noutlet1-1) : 0)
-                             + IOMIDDLE;
-                ly1 = y12;
-                lx2 = x21 + (ninlet2 > 1 ?
-                        ((x22-x21-IOWIDTH) * closest2)/(ninlet2-1) : 0)
-                            + IOMIDDLE;
-                ly2 = y21;
-                sys_vgui(".x%lx.c create line %d %d %d %d -fill %s -width %s -tags {l%lx all_cords}\n",
-                    glist_getcanvas(x),
-                        lx1, ly1, lx2, ly2,
-                    (issignal ? "$signal_cord" : "$msg_cord"),
-                    (issignal ? "$signal_cord_width" : "$msg_cord_width"), 
-                    oc);
-                if (canvas_cnct_inlet_tag[0] != 0)
-                {
-                    sys_vgui(".x%x.c itemconfigure %s -outline %s -fill %s -width 1\n",
-                           	x, canvas_cnct_inlet_tag,
-							(last_inlet_filter ? "black" : (obj_issignaloutlet(ob1, closest1) ? "$signal_cord" : "$msg_cord")),
-							(inlet_issignal ? "$signal_nlet" : "$msg_nlet"));
-					if (objtooltip) {
-						objtooltip = 0;
-						sys_vgui("pdtk_canvas_leaveitem .x%x.c;\n", x);
-					}
-                    canvas_cnct_inlet_tag[0] = 0;                  
-                }
-                if (canvas_cnct_outlet_tag[0] != 0)
-                {
-                    sys_vgui(".x%x.c itemconfigure %s -outline %s -fill %s -width 1\n",
-                           	x, canvas_cnct_outlet_tag,
-							(last_outlet_filter ? "black" : (outlet_issignal ? "$signal_cord" : "$msg_cord")),
-							(outlet_issignal ? "$signal_nlet" : "$msg_nlet"));
-					if (objtooltip) {
-						objtooltip = 0;
-						sys_vgui("pdtk_canvas_leaveitem .x%x.c;\n", x);
-					}
-                    canvas_cnct_outlet_tag[0] = 0;                  
-                }
-                // end jsarlo
-                canvas_dirty(x, 1);
-                /*canvas_setundo(x, canvas_undo_connect,
-                    canvas_undo_set_connect(x, 
-                        canvas_getindex(x, &ob1->ob_g), closest1,
-                        canvas_getindex(x, &ob2->ob_g), closest2),
-                        "connect");*/
-				canvas_undo_add(x, 1, "connect", canvas_undo_set_connect(x, 
-                        canvas_getindex(x, &ob1->ob_g), closest1,
-                        canvas_getindex(x, &ob2->ob_g), closest2));
-
-				// add auto-connect back to preset_node object
-				// (by this time we know we are connecting only to legal objects who have at least one outlet)
-				if (pd_class(&y1->g_pd) == preset_node_class) {
-					//fprintf(stderr,"gotta do auto-connect back to preset_node\n");
-					if (!canvas_isconnected(x, ob2, 0, ob1, 0) && pd_class(&y2->g_pd) != print_class) {
-						oc2 = obj_connect(ob2, 0, ob1, 0);
-						outconnect_setvisible(oc2, 0);
-					}
-					//else
-					//	fprintf(stderr,"error: already connected (this happens when loading from file and is ok)\n");
-				}
+				canvas_doconnect_doit(x, y1, y2, closest1, closest2, 0, 1);
             }
     	    else 
             // jsarlo
@@ -3255,7 +3713,7 @@ void canvas_doconnect(t_canvas *x, int xpos, int ypos, int which, int doit)
     	magicGlass_hide(x->gl_magic_glass);
 	}
     // end jsarlo
-    canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
+	canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
 }
 
 void canvas_selectinrect(t_canvas *x, int lox, int loy, int hix, int hiy)
@@ -3362,6 +3820,7 @@ void canvas_mouseup(t_canvas *x,
     canvas_upclicktime = sys_getrealtime();
     canvas_upx = xpos;
     canvas_upy = ypos;
+	glob_lmclick = 0;
 
     if (x->gl_editor->e_onmotion == MA_CONNECT)
         canvas_doconnect(x, xpos, ypos, which, 1);
@@ -3432,7 +3891,8 @@ void canvas_mouseup(t_canvas *x,
 		canvas_cnct_inlet_tag[0] = 0;                  
 	}
     
-    x->gl_editor->e_onmotion = MA_NONE;
+	if (!x->gl_editor->e_onmotion == MA_CONNECT || !glob_shift)
+	    x->gl_editor->e_onmotion = MA_NONE;
 }
 
     /* displace the selection by (dx, dy) pixels */
@@ -3510,6 +3970,14 @@ void canvas_key(t_canvas *x, t_symbol *s, int ac, t_atom *av)
     canvas_undo_already_set_move = 0;
     down = (atom_getfloat(av) != 0);  /* nonzero if it's a key down */
     shift = (atom_getfloat(av+2) != 0);  /* nonzero if shift-ed */
+	glob_shift = shift;
+	//fprintf(stderr,"%d %d %d %d\n", (x->gl_editor != NULL ? 1 : 0), (x->gl_editor->e_onmotion == MA_CONNECT ? 1 : 0), glob_shift, glob_lmclick);
+	// check if user released shift while trying manual multi-connect
+	if (x->gl_editor && x->gl_editor->e_onmotion == MA_CONNECT && !glob_shift && !glob_lmclick) {
+		//fprintf(stderr,"shift released during connect\n");
+		sys_vgui(".x%lx.c delete x\n", x);
+		canvas_mouseup(x, x->gl_editor->e_xwas, x->gl_editor->e_ywas, 0);
+	}
     if (av[1].a_type == A_SYMBOL) {
         gotkeysym = av[1].a_w.w_symbol;
 	}