From b4a6be96165113755203c5563edb6a300969210d Mon Sep 17 00:00:00 2001
From: Ivica Ico Bukvic <ico@vt.edu>
Date: Mon, 19 Aug 2013 02:10:21 -0400
Subject: [PATCH] *fixed cursor position bug when pasting/extending text into
 second line *fixed cord redrawing when objects got resized due to cut/paste
 of object's text *ctrlleft,ctrlright, and shift variants all now properly
 navigate messages during editing, including single character atoms *fixed
 regression where clicking on iemgui labels of gop-embedded iemgui objects
 also counts as a click on the object itself (e.g. toggle being toggled
 on/off) *fixed regression when dynamically changing iemgui properties within
 gop as to when to hide and when to show it *proper redrawing and reordering
 logic for arrange and dynamic changes to iemgui objects inside gop *committed
 http://sourceforge.net/p/pure-data/pure-data/ci/97851b3c44b2b3839069928d90ca6185de4455c5/

---
 pd/src/g_all_guis.c |  59 +++++++++++++++++++++++++-
 pd/src/g_canvas.c   |  51 ++++++++++++++--------
 pd/src/g_editor.c   |  37 ++++++++--------
 pd/src/g_graph.c    |   5 +++
 pd/src/g_rtext.c    | 100 ++++++++++++++++++++++++++++++--------------
 pd/src/g_text.c     |  25 +++++++----
 pd/src/g_toggle.c   |   8 ++--
 7 files changed, 203 insertions(+), 82 deletions(-)

diff --git a/pd/src/g_all_guis.c b/pd/src/g_all_guis.c
index bf2fd2bbe..fb984b008 100644
--- a/pd/src/g_all_guis.c
+++ b/pd/src/g_all_guis.c
@@ -464,8 +464,20 @@ void iemgui_label_font(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *a
 //Helvetica: 70 x 10 (14) -> 5 x 10 -> 0.83333
 //Times: 61 x 10 (14) -> 4.357 x 10 -> 0.72619; 0.735 appears to work better
 
+// We use this global var to check when getrect should report label:
+// It should report it when drawing inside gop to see if we truly fit.
+// Otherwise we should not report it while inside gop to avoid label being
+// misinterpreted as part of the "hot" area of a widget (e.g. toggle)
+extern int gop_redraw;
+
 void iemgui_label_getrect(t_iemgui x_gui, t_glist *x, int *xp1, int *yp1, int *xp2, int *yp2)
 {
+	//fprintf(stderr,"gop_redraw = %d\n", gop_redraw);
+	if (!gop_redraw) {
+		//fprintf(stderr,"ignoring label\n");
+		return;
+	}
+
 	t_float width_multiplier;
 	int label_length;	
 	int label_x1;
@@ -533,12 +545,55 @@ void iemgui_label_getrect(t_iemgui x_gui, t_glist *x, int *xp1, int *yp1, int *x
 
 void iemgui_shouldvis(void *x, t_iemgui *iemgui, int mode)
 {
-	if(gobj_shouldvis(x, glist_getcanvas(iemgui->x_glist))) {
+	gop_redraw = 1;
+	if(gobj_shouldvis(x, iemgui->x_glist)) {
 		if (!iemgui->x_vis) {
 			//fprintf(stderr,"draw new %d\n", mode);
     		(*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_NEW);
     		canvas_fixlinesfor(glist_getcanvas(iemgui->x_glist), (t_text*)x);
 			iemgui->x_vis = 1;
+			if (iemgui->x_glist != glist_getcanvas(iemgui->x_glist)) {
+				// if we are inside gop and just have had our object's properties changed
+				// we'll adjust our layer position to ensure that ordering is honored
+				t_canvas *canvas = glist_getcanvas(iemgui->x_glist);
+				t_gobj *y = (t_gobj *)iemgui->x_glist;
+				gobj_vis(y, canvas, 0);
+				gobj_vis(y, canvas, 1);
+				// reorder it visually
+				glist_redraw(canvas);
+				/* some day when the object tagging is properly done for all GUI objects
+				glist_noselect(canvas);
+				glist_select(canvas, y);
+				t_gobj *yy = canvas->gl_list;
+				if (yy != y) {
+					fprintf(stderr,"not bottom\n");
+					while (yy && yy->g_next != y) {
+						fprintf(stderr,"+\n");
+						yy = yy->g_next;
+					}
+					// now we have yy which is right before our y graph
+					t_object *ob = NULL;
+					t_rtext *yr = NULL;
+					if (yy) {
+						yr = glist_findrtext(canvas, (t_text *)yy);
+					}
+					if (yr) {
+						fprintf(stderr,"lower\n");
+						sys_vgui(".x%lx.c lower selected %s\n", canvas, rtext_gettag(yr));
+						sys_vgui(".x%lx.c raise selected %s\n", canvas, rtext_gettag(yr));
+						//sys_vgui(".x%lx.c raise all_cords\n", canvas);
+					} else {
+						// fall back to legacy redraw for objects that are not patchable
+						fprintf(stderr,"lower fallback redraw\n");
+						canvas_redraw(canvas);
+					}
+				} else {
+					// we get here if we are supposed to go all the way to the bottom
+					fprintf(stderr,"lower to the bottom\n");
+					sys_vgui(".x%lx.c lower selected\n", canvas);
+				}
+				glist_noselect(canvas);*/
+			}
 		}
 		//fprintf(stderr,"draw move iemgui->x_w=%d\n", iemgui->x_w);
 	    (*iemgui->x_draw)(x, iemgui->x_glist, mode);
@@ -548,6 +603,7 @@ void iemgui_shouldvis(void *x, t_iemgui *iemgui, int mode)
 		(*iemgui->x_draw)(x, iemgui->x_glist, IEM_GUI_DRAW_MODE_ERASE);
 		iemgui->x_vis = 0;
 	}
+	gop_redraw = 0;
 }
 
 void iemgui_size(void *x, t_iemgui *iemgui)
@@ -564,6 +620,7 @@ void iemgui_delta(void *x, t_iemgui *iemgui, t_symbol *s, int ac, t_atom *av)
     iemgui->x_obj.te_ypix += (int)atom_getintarg(1, ac, av);
     if(glist_isvisible(iemgui->x_glist))
     {
+		//fprintf(stderr,"iemgui_delta->shouldvis\n");
         iemgui_shouldvis(x, iemgui, IEM_GUI_DRAW_MODE_MOVE);
     }
 }
diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c
index e2269e2e0..dd92ecc03 100644
--- a/pd/src/g_canvas.c
+++ b/pd/src/g_canvas.c
@@ -54,6 +54,9 @@ void canvas_reflecttitle(t_canvas *x);
 static void canvas_addtolist(t_canvas *x);
 static void canvas_takeofflist(t_canvas *x);
 static void canvas_pop(t_canvas *x, t_floatarg fvis);
+static int canvas_should_bind(t_canvas *x);
+static void canvas_bind(t_canvas *x);
+static void canvas_unbind(t_canvas *x);
 
 /* --------- functions to handle the canvas environment ----------- */
 
@@ -238,11 +241,9 @@ void canvas_makefilename(t_canvas *x, char *file, char *result, int resultsize)
 
 void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir)
 {
-    if (strcmp(x->gl_name->s_name, "Pd"))
-        pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name));
+    canvas_unbind(x);
     x->gl_name = s;
-    if (strcmp(x->gl_name->s_name, "Pd"))
-        pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
+    canvas_bind(x);
     if (glist_isvisible(x))
     if (x->gl_havewindow) //was glist_isvisible(x)
         canvas_reflecttitle(x);
@@ -414,8 +415,7 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv)
     x->gl_owner = owner;
     x->gl_name = (*s->s_name ? s : 
         (canvas_newfilename ? canvas_newfilename : gensym("Pd")));
-    if (strcmp(x->gl_name->s_name, "Pd"))
-        pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
+    canvas_bind(x);
     x->gl_loading = 1;
 	//fprintf(stderr,"loading = 1 .x%lx owner=.x%lx\n", (t_int)x, (t_int)x->gl_owner);
     x->gl_goprect = 0;      /* no GOP rectangle unless it's turned on later */
@@ -555,9 +555,8 @@ t_glist *glist_addglist(t_glist *g, t_symbol *sym,
     x->gl_screenx1 = x->gl_screeny1 = 0;
     x->gl_screenx2 = 450;
     x->gl_screeny2 = 300;
-    if (strcmp(x->gl_name->s_name, "Pd"))
-        pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
     x->gl_owner = g;
+	canvas_bind(x);
     x->gl_isgraph = 1;
     x->gl_goprect = 0;
     x->gl_obj.te_binbuf = binbuf_new();
@@ -698,6 +697,7 @@ void canvas_draw_gop_resize_hooks(t_canvas* x)
 	if(x->gl_edit && glist_isvisible(x) && glist_istoplevel(x) && x->gl_goprect && !x->gl_editor->e_selection) {
 		
 		//Drawing and Binding Resize_Blob for GOP
+		//fprintf(stderr,"draw_gop_resize_hooks %lx %lx\n", (t_int)x, (t_int)glist_getcanvas(x));
 		sprintf(sh->h_pathname, ".x%lx.h%lx", (t_int)x, (t_int)sh);
 		sys_vgui("destroy %s\n", sh->h_pathname);	
 		sys_vgui(".x%lx.c delete GOP_resblob\n", x);	
@@ -737,9 +737,9 @@ void canvas_draw_gop_resize_hooks(t_canvas* x)
 
 	}
 	else{
-		if (sh)
+		if (sh && sh->h_pathname)
 			sys_vgui("destroy %s\n", sh->h_pathname);
-		if (mh)
+		if (mh && mh->h_pathname)
 			sys_vgui("destroy %s\n", mh->h_pathname);
 		sys_vgui(".x%lx.c delete GOP_resblob ; .x%lx.c delete GOP_movblob ;\n", x, x);					//delete the GOP_resblob and GOP_movblob	
 	}
@@ -905,14 +905,9 @@ void canvas_free(t_canvas *x)
         glist_delete(x, y);
     if (x == glist_getcanvas(x))
         canvas_vis(x, 0);
-
-	if (x->gl_editor)
-		canvas_destroy_editor(x);
-
-    if (strcmp(x->gl_name->s_name, "Pd")) {
-		//fprintf(stderr,"canvas_free calling pd_unbind\n");
-        pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name));
-	}
+     if (x->gl_editor)
+         canvas_destroy_editor(x);   /* bug workaround; should already be gone*/
+	canvas_unbind(x);
     if (x->gl_env)
     {
         freebytes(x->gl_env->ce_argv, x->gl_env->ce_argc * sizeof(t_atom));
@@ -1325,6 +1320,26 @@ int canvas_isabstraction(t_canvas *x)
     return (x->gl_env != 0);
 }
 
+    /* return true if the "canvas" object should be bound to a name */
+static int canvas_should_bind(t_canvas *x)
+{
+        /* FIXME should have a "backwards compatible" mode */
+        /* not named "Pd" && (is top level || is subpatch) */
+    return strcmp(x->gl_name->s_name, "Pd") && (!x->gl_owner || !x->gl_env);
+}
+
+static void canvas_bind(t_canvas *x)
+{
+    if (canvas_should_bind(x))
+        pd_bind(&x->gl_pd, canvas_makebindsym(x->gl_name));
+}
+
+static void canvas_unbind(t_canvas *x)
+{
+    if (canvas_should_bind(x))
+        pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name));
+}
+
     /* return true if the "canvas" object is a "table". */
 int canvas_istable(t_canvas *x)
 {
diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c
index a147e1bb0..0728564ba 100644
--- a/pd/src/g_editor.c
+++ b/pd/src/g_editor.c
@@ -882,6 +882,7 @@ void canvas_undo_cut(t_canvas *x, void *z, int action)
 						//now put the moved object at the beginning of the cue
 						y->g_next = glist_nth(x, 0);
 						x->gl_list = y;
+						//LATER when objects are properly tagged lower y here
 					}
 					//if the object is supposed to be at the current end of gl_list	
 					//can this ever happen???
@@ -902,10 +903,12 @@ void canvas_undo_cut(t_canvas *x, void *z, int action)
 
 						y_prev->g_next = y;
 						y->g_next = y_next;
+						//LATER when objects are properly tagged lower y here
 					}
 				}
 			}
 			do_not_redraw -= 1;
+			//LATER disable redrawing here
 			canvas_redraw(x);
 			if (x->gl_owner && glist_isvisible(x->gl_owner)) {
 				gobj_vis((t_gobj *)x, x->gl_owner, 0);
@@ -1406,8 +1409,9 @@ void canvas_undo_arrange(t_canvas *x, void *z, int action)
 				x->gl_list = y;
 			}
 
-			// and finally redraw canvas--we have to redraw canvas since
-			// there is no consistent naming of objects
+			// and finally redraw canvas
+			canvas_redraw(x);
+			/* some day when the object tagging is properly done for all GUI objects
 			t_object *ob = NULL;
 			t_rtext *yr = NULL;
 			if (prev) {
@@ -1427,9 +1431,9 @@ void canvas_undo_arrange(t_canvas *x, void *z, int action)
 				sys_vgui(".x%lx.c lower selected\n", x);
 			} else {
 				// fall back to legacy redraw for objects that are not patchable
-				//fprintf(stderr,"fallback redraw\n");
+				//fprintf(stderr,"lower fallback redraw\n");
 				canvas_redraw(x);
-			}
+			}*/
 
 			glob_preset_node_list_check_loc_and_update();
 		}
@@ -1451,6 +1455,8 @@ void canvas_undo_arrange(t_canvas *x, void *z, int action)
 			y->g_next = next;
 
 			// and finally redraw canvas
+			canvas_redraw(x);
+			/* some day when the object tagging is properly done for all GUI objects
 			t_object *ob = NULL;
 			t_rtext *yr = NULL;
 			if (prev) {
@@ -1469,9 +1475,9 @@ void canvas_undo_arrange(t_canvas *x, void *z, int action)
 				sys_vgui(".x%lx.c raise selected\n", x);
 			} else {
 				// fall back to legacy redraw for objects that are not patchable
-				//fprintf(stderr,"fallback redraw\n");
+				//fprintf(stderr,"raise fallback redraw\n");
 				canvas_redraw(x);
-			}
+			}*/
 
 			glob_preset_node_list_check_loc_and_update();
 		}
@@ -2513,20 +2519,9 @@ static void canvas_doarrange(t_canvas *x, t_float which, t_gobj *oldy, t_gobj *o
 		else x->gl_list = oldy_next;
 
 		// and finally redraw
-		t_object *ob = NULL;
-		t_rtext *yr = NULL;
-		ob = pd_checkobject(&y_end->g_pd);
-		if (ob) {
-			yr = glist_findrtext(x, (t_text *)&ob->ob_g);
-		}
-		if (yr) {
-			//fprintf(stderr,"raise\n");
-			sys_vgui(".x%lx.c raise selected %s\n", x, rtext_gettag(yr));
-			//sys_vgui(".x%lx.c raise all_cords\n", x);
-		} else {
-			//fprintf(stderr,"redraw\n");
-			canvas_redraw(x);
-		}
+		//fprintf(stderr,"raise\n");
+		sys_vgui(".x%lx.c raise selected\n", x);
+		sys_vgui(".x%lx.c raise all_cords\n", x);
 	}
 	if (which == 4) /* to back */
 	{
@@ -5005,6 +5000,7 @@ static void canvas_cut(t_canvas *x)
 	/* if we are cutting text */
     else if (x->gl_editor && x->gl_editor->e_textedfor)
     {
+		//fprintf(stderr,"canvas_cut textedfor\n");
         char *buf;
         int bufsize;
         rtext_getseltext(x->gl_editor->e_textedfor, &buf, &bufsize);
@@ -5012,6 +5008,7 @@ static void canvas_cut(t_canvas *x)
             return;
         canvas_copy(x);
         rtext_key(x->gl_editor->e_textedfor, 127, &s_);
+		canvas_fixlinesfor(x,(t_text*) x->gl_editor->e_selection->sel_what);
         canvas_dirty(x, 1);
     }
 	/* else we are cutting objects */
diff --git a/pd/src/g_graph.c b/pd/src/g_graph.c
index c3742c519..a29c3f33a 100644
--- a/pd/src/g_graph.c
+++ b/pd/src/g_graph.c
@@ -27,6 +27,7 @@ void graph_checkgop_rect(t_gobj *z, t_glist *glist,
     int *xp1, int *yp1, int *xp2, int *yp2);
 
 extern int do_not_redraw;
+int gop_redraw = 0;
 
 /* -------------------- maintaining the list -------------------- */
 
@@ -954,7 +955,11 @@ static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis)
 
             /* draw contents of graph as glist */
         for (g = x->gl_list; g; g = g->g_next) {
+			gop_redraw = 1;
+			//fprintf(stderr,"drawing gop objects\n");
             gobj_vis(g, x, 1);
+			//fprintf(stderr,"done\n");
+			gop_redraw = 0;
 		}
 		/* reselect it upon redrawing if it was selected before */
         glist_drawiofor(parent_glist, &x->gl_obj, 1,
diff --git a/pd/src/g_rtext.c b/pd/src/g_rtext.c
index 0de03b6ff..ebde12b90 100644
--- a/pd/src/g_rtext.c
+++ b/pd/src/g_rtext.c
@@ -196,7 +196,7 @@ extern int sys_oldtclversion;
 static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
     int *indexp)
 {
-	//fprintf(stderr,"rtext_senditup\n");
+	//fprintf(stderr,"rtext_senditup %d %d\n", *widthp, *heightp);
 	if (x) {
 		t_float dispx, dispy;
 		char smallbuf[200], *tempbuf;
@@ -205,12 +205,12 @@ static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
 		int reportedindex = 0;
 		t_canvas *canvas = glist_getcanvas(x->x_glist);
 
-		int widthspec_c = x->x_text->te_width;
-		int widthlimit_c = (widthspec_c ? widthspec_c : BOXWIDTH);
-		int inindex_b = 0;
-		int inindex_c = 0;
-		int selstart_b = 0, selend_b = 0;
-		int x_bufsize_c = u8_charnum(x->x_buf, x->x_bufsize);
+		int widthspec_c = x->x_text->te_width; // width if any specified
+		int widthlimit_c = (widthspec_c ? widthspec_c : BOXWIDTH); // width limit in chars
+		int inindex_b = 0; // index location in the buffer
+		int inindex_c = 0; // index location in the u8 chars
+		int selstart_b = 0, selend_b = 0; // selection start and end
+		int x_bufsize_c = u8_charnum(x->x_buf, x->x_bufsize); // buffer size in u8 chars
 		    /* if we're a GOP (the new, "goprect" style) borrow the font size
 		    from the inside to preserve the spacing */
 		if (pd_class(&x->x_text->te_pd) == canvas_class &&
@@ -220,7 +220,7 @@ static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
 		else font = glist_getfont(x->x_glist);
 		fontwidth = sys_fontwidth(font);
 		fontheight = sys_fontheight(font);
-		findx = (*widthp + (fontwidth/2)) / fontwidth;
+		findx = (*widthp + (fontwidth/2)) / fontwidth; // calculating x and y in pixels
 		findy = *heightp / fontheight;
 		if (x->x_bufsize >= 100)
 		     tempbuf = (char *)t_getbytes(2 * x->x_bufsize + 1);
@@ -240,7 +240,7 @@ static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
 			if ((foundit_bv < foundit_b && foundit_bv != -1) || (foundit_b == -1 && foundit_bv != -1)) foundit_b = foundit_bv;
 
 			int foundit_c;
-			if (foundit_b < 0)
+			if (foundit_b < 0) //if we did not find an \n
 		    { 
 		        if (inchars_c > widthlimit_c)
 		        {
@@ -271,6 +271,7 @@ static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
 		        *indexp = inindex_b + u8_offset(x->x_buf + inindex_b, actualx);
 		        reportedindex = 1;
 		    }
+			//fprintf(stderr,"eatchar %d <%s>\n", eatchar, tempbuf);
 		    strncpy(tempbuf+outchars_b, x->x_buf + inindex_b, foundit_b);
 		    if (x->x_selstart >= inindex_b &&
 		        x->x_selstart <= inindex_b + foundit_b + eatchar)
@@ -283,9 +284,9 @@ static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
 		    inindex_c += (foundit_c + eatchar);
 		    if (inindex_b < x->x_bufsize)
 		        tempbuf[outchars_b++] = '\n';
-		    if (foundit_c > ncolumns)
+		    if (foundit_c > ncolumns) // if we found a row that is longer than previous (total width)
 		        ncolumns = foundit_c;
-		    nlines++;
+			nlines++;
 		}
 		if (!reportedindex)
 		    *indexp = outchars_b;
@@ -335,9 +336,9 @@ static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
 		        if (selend_b > selstart_b)
 		        {
 		            sys_vgui(".x%lx.c select from %s %d\n", canvas, 
-		                x->x_tag, u8_charnum(x->x_buf, selstart_b));
+		                x->x_tag, u8_charnum(tempbuf, selstart_b));
 		            sys_vgui(".x%lx.c select to %s %d\n", canvas, 
-		                x->x_tag, u8_charnum(x->x_buf, selend_b)
+		                x->x_tag, u8_charnum(tempbuf, selend_b)
 					  	+ (sys_oldtclversion ? 0 : -1));
 		            sys_vgui(".x%lx.c focus \"\"\n", canvas);        
 		        }
@@ -345,7 +346,7 @@ static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
 		        {
 		            sys_vgui(".x%lx.c select clear\n", canvas);
 		            sys_vgui(".x%lx.c icursor %s %d\n", canvas, x->x_tag,
-		                u8_charnum(x->x_buf, selstart_b));
+		                u8_charnum(tempbuf, selstart_b));
 		            sys_vgui(".x%lx.c focus %s\n", canvas, x->x_tag);        
 		        }
 		    }
@@ -516,6 +517,16 @@ void rtext_activate(t_rtext *x, int state)
     rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
 }
 
+// outputs 1 if found one of the special chars
+// this function is used with traversal through rtext below
+// using ctrl+left/right and similar shortcuts
+static int rtext_compare_special_chars(const char c)
+{
+		if (c != '\n' && c != '\v' && c != ' ')
+			return 0;
+		return 1;
+}
+
 void rtext_key(t_rtext *x, int keynum, t_symbol *keysym)
 {
     int w = 0, h = 0, indx, i, newsize, ndel;
@@ -566,6 +577,7 @@ be printable in whatever 8-bit character set we find ourselves. */
 */
         if (n == '\n' || (n > 31 && n < 127))
         {
+			//fprintf(stderr,"return or 31-127\n");
             newsize = x->x_bufsize+1;
             x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize);
             for (i = x->x_bufsize; i > x->x_selstart; i--)
@@ -579,6 +591,7 @@ be printable in whatever 8-bit character set we find ourselves. */
 		/*--moo: check for unicode codepoints beyond 7-bit ASCII --*/
 		else if (n > 127)
 		{
+			//fprintf(stderr,">127\n");
             int ch_nbytes = u8_wc_nbytes(n);
             newsize = x->x_bufsize + ch_nbytes;
             x->x_buf = resizebytes(x->x_buf, x->x_bufsize, newsize);
@@ -659,16 +672,23 @@ be printable in whatever 8-bit character set we find ourselves. */
     }
     else if (!strcmp(keysym->s_name, "CtrlLeft"))
     {
+		//fprintf(stderr,"ctrleft\n");
 		/* first find first non-space char going back */
-		while (x->x_selstart > 0 && x->x_buf[x->x_selstart-1] == ' ')
+		while (x->x_selstart > 0 && rtext_compare_special_chars(x->x_buf[x->x_selstart-1])) {
+			//fprintf(stderr,"while 1 <%c>\n", x->x_buf[x->x_selstart-1]);
 			u8_dec(x->x_buf, &x->x_selstart);
+		}
 		/* now go back until you find another space or the beginning of the buffer */
         while (x->x_selstart > 0 &&
-		  x->x_buf[x->x_selstart] != '\n' &&
-		  x->x_buf[x->x_selstart-1] != ' ')
+		  !rtext_compare_special_chars(x->x_buf[x->x_selstart-1])) {
+			//fprintf(stderr,"while 2 <%c>\n", x->x_buf[x->x_selstart-1]);
             u8_dec(x->x_buf, &x->x_selstart);
-		if (x->x_buf[x->x_selstart+1] == ' ')
+		}
+		if (x->x_buf[x->x_selstart+1] == ' ' &&
+		  x->x_buf[x->x_selstart] == ' ') {
+			//fprintf(stderr,"go forward\n");
 			u8_inc(x->x_buf, &x->x_selstart);
+		}
 		x->x_selend = x->x_selstart;
     }
     else if (!strcmp(keysym->s_name, "CtrlRight"))
@@ -677,19 +697,19 @@ be printable in whatever 8-bit character set we find ourselves. */
 		if (x->x_selend < x->x_bufsize - 1)
 			u8_inc(x->x_buf, &x->x_selend);
         while (x->x_selend < x->x_bufsize &&
-          x->x_buf[x->x_selend] != '\n' &&
-		  x->x_buf[x->x_selend] != ' ')
+          !rtext_compare_special_chars(x->x_buf[x->x_selend]))
             u8_inc(x->x_buf, &x->x_selend);
 		/* now skip all the spaces and land before next word */
-        while (x->x_selend < x->x_bufsize &&
+        /*while (x->x_selend < x->x_bufsize &&
 		  x->x_buf[x->x_selend] == ' ')
             u8_inc(x->x_buf, &x->x_selend);
 		if (x->x_selend > 0 && x->x_buf[x->x_selend-1] == ' ')
-			u8_dec(x->x_buf, &x->x_selend);
+			u8_dec(x->x_buf, &x->x_selend);*/
 		x->x_selstart = x->x_selend;
     }
     else if (!strcmp(keysym->s_name, "CtrlShiftLeft"))
 	{
+		//fprintf(stderr,"ctrlshiftleft %d %d %d\n", last_sel, x->x_selstart, x->x_selend);
 		int swap = 0;
 		int *target;
 		if (!last_sel) last_sel = 1;
@@ -700,18 +720,24 @@ be printable in whatever 8-bit character set we find ourselves. */
 			target = &x->x_selstart;
 		}
 		/* first find first non-space char going back */
-		while (*target > 0 && x->x_buf[*target-1] == ' ')
+		while (*target > 0 && rtext_compare_special_chars(x->x_buf[*target-1])) {
 			u8_dec(x->x_buf, target);
 			//(*target)--;
+		}
+		//fprintf(stderr,"%d %d\n", x->x_selstart, x->x_selend);
 		/* now go back until you find another space or the beginning of the buffer */
         while (*target > 0 &&
-		  x->x_buf[*target] != '\n' &&
-		  x->x_buf[*target-1] != ' ')
+		  !rtext_compare_special_chars(x->x_buf[*target-1])) {
 			u8_dec(x->x_buf, target);
             //(*target)--;
-		if (x->x_buf[*target+1] == ' ')
+		}
+		//fprintf(stderr,"%d %d\n", x->x_selstart, x->x_selend);
+		if (x->x_buf[*target+1] == ' ' &&
+		  x->x_buf[x->x_selstart] == ' ') {
 			u8_inc(x->x_buf, target);
 			//(*target)++;
+		}
+		//fprintf(stderr,"%d %d\n", x->x_selstart, x->x_selend);
         if (x->x_selstart > x->x_selend) {
 			swap = x->x_selend;
 			x->x_selend = x->x_selstart;
@@ -721,6 +747,7 @@ be printable in whatever 8-bit character set we find ourselves. */
 	}
     else if (!strcmp(keysym->s_name, "CtrlShiftRight"))
 	{
+		//fprintf(stderr,"ctrlshiftright %d %d %d\n", last_sel, x->x_selstart, x->x_selend);
 		int swap = 0;
 		int *target;
 		if (!last_sel) last_sel = 2;
@@ -730,29 +757,38 @@ be printable in whatever 8-bit character set we find ourselves. */
 			last_sel = 2;
 			target = &x->x_selend;
 		}
+		//fprintf(stderr,"%d %d\n", x->x_selstart, x->x_selend);
 		/* now go forward until you find another space or the end of the buffer */
-		if (*target < x->x_bufsize - 1)
+		if (*target < x->x_bufsize - 1) {
+			//fprintf(stderr,"while 1 <%c>\n", x->x_buf[*target]);
 			u8_inc(x->x_buf, target);
 			//(*target)++;
+		}
+		//fprintf(stderr,"%d %d\n", x->x_selstart, x->x_selend);
         while (*target < x->x_bufsize &&
-          x->x_buf[*target] != '\n' &&
-		  x->x_buf[*target] != ' ')
+          !rtext_compare_special_chars(x->x_buf[*target])) {
+			//fprintf(stderr,"while 2 <%c>\n", x->x_buf[*target]);
 			u8_inc(x->x_buf, target);
             //(*target)++;
+		}
 		/* now skip all the spaces and land before next word */
-        while (*target < x->x_bufsize &&
-		  x->x_buf[*target] == ' ')
+        /*while (*target < x->x_bufsize &&
+		  x->x_buf[*target] == ' ') {
 			u8_inc(x->x_buf, target);
             //(*target)++;
-		if (*target > 0 && x->x_buf[*target-1] == ' ')
+		}
+		if (*target > 0 && x->x_buf[*target-1] == ' ') {
 			u8_dec(x->x_buf, target);
 			//(*target)--;
+		}*/
+		//fprintf(stderr,"%d %d\n", x->x_selstart, x->x_selend);
         if (x->x_selstart > x->x_selend) {
 			swap = x->x_selend;
 			x->x_selend = x->x_selstart;
 			x->x_selstart = swap;
 			last_sel = 2;
 		}
+		//fprintf(stderr,"%d %d\n", x->x_selstart, x->x_selend);
 	}
 
     rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
diff --git a/pd/src/g_text.c b/pd/src/g_text.c
index fba272589..e68258deb 100644
--- a/pd/src/g_text.c
+++ b/pd/src/g_text.c
@@ -1996,6 +1996,7 @@ void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize, int pos)
 	char *c1, *c2;
 	int i1, i2;
 
+	//fprintf(stderr,"text_setto %d\n", x->te_type);
 
     if (x->te_type == T_OBJECT)
     {
@@ -2025,6 +2026,10 @@ void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize, int pos)
 		        binbuf_free(x->te_binbuf);
 		        x->te_binbuf = b;
 				//canvas_apply_restore_original_position(glist_getcanvas(glist), pos);
+			} else {
+				//just retext it
+				t_rtext *yr = glist_findrtext(glist, x);
+				if (yr) rtext_retext(yr);
 			}
         }
         else  /* normally, just destroy the old one and make a new one. */
@@ -2047,6 +2052,10 @@ void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize, int pos)
 		        canvas_restoreconnections(glist_getcanvas(glist));
 				glob_preset_node_list_seek_hub();
 				//canvas_apply_restore_original_position(glist_getcanvas(glist), pos);
+			} else {
+				//fprintf(stderr,"just retext it\n");
+				t_rtext *yr = glist_findrtext(glist, x);
+				if (yr) rtext_retext(yr);
 			}
         }
             /* if we made a new "pd" or changed a window name,
@@ -2055,13 +2064,15 @@ void text_setto(t_text *x, t_glist *glist, char *buf, int bufsize, int pos)
             && !strcmp(vec2[0].a_w.w_symbol->s_name, "pd"))
                 canvas_updatewindowlist();
     }
-    else {
-        char * c;
-        for(c = buf; *c != '\0'; c++) {
-            if(*c == '\n') {
-                *c = '\v';
-            }
-        }
+    else { // T_MESSAGE, T_TEXT, T_ATOM
+		if (x->te_type == T_TEXT) {
+		    char * c;
+		    for(c = buf; *c != '\0'; c++) {
+		        if(*c == '\n') {
+		            *c = '\v';
+		        }
+		    }
+		}
 		binbuf_gettext(x->te_binbuf, &c1, &i1);
 		t_binbuf *b = binbuf_new();
 		binbuf_text(b, buf, bufsize);
diff --git a/pd/src/g_toggle.c b/pd/src/g_toggle.c
index 37a1c9797..4735828df 100644
--- a/pd/src/g_toggle.c
+++ b/pd/src/g_toggle.c
@@ -239,18 +239,18 @@ void toggle_draw_io(t_toggle* x, t_glist* glist, int old_snd_rcv_flags)
 		else nlet_tag = "bogus";
 
 		if((old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && !x->x_gui.x_fsf.x_snd_able)
-		    sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags %lxTGL%so%d\n",
+		    sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags {%lxTGL%so%d %so%d %lxTGL outlet}\n",
 		         canvas, xpos,
 		         ypos + x->x_gui.x_h-1, xpos + IOWIDTH,
-		         ypos + x->x_gui.x_h, x, nlet_tag, 0);
+		         ypos + x->x_gui.x_h, x, nlet_tag, 0, nlet_tag, 0, x);
 		if(!(old_snd_rcv_flags & IEM_GUI_OLD_SND_FLAG) && x->x_gui.x_fsf.x_snd_able)
 		    sys_vgui(".x%lx.c delete %lxTGL%so%d\n", canvas, x, nlet_tag, 0);
 		if((old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && !x->x_gui.x_fsf.x_rcv_able)
-		    sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags {%lxTGL%so%d %so%d %lxTGL outlet}\n",
+		    sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags {%lxTGL%si%d %si%d %lxTGL outlet}\n",
 		         canvas, xpos, ypos,
 		         xpos + IOWIDTH, ypos+1, x, nlet_tag, 0, nlet_tag, 0, x);
 		if(!(old_snd_rcv_flags & IEM_GUI_OLD_RCV_FLAG) && x->x_gui.x_fsf.x_rcv_able)
-		    sys_vgui(".x%lx.c delete {%lxTGL%si%d %si%d %lxTGL outlet}\n", canvas, x, nlet_tag, 0, nlet_tag, 0, x);
+		    sys_vgui(".x%lx.c delete %lxTGL%si%d\n", canvas, x, nlet_tag, 0);
 	}
 }
 
-- 
GitLab