diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js
index e83185024d4adafbe1de61240b4dbaa16fa5a1fc..9434f198ebdbf9b850844ce53889bca7e3b8a10e 100644
--- a/pd/nw/pdgui.js
+++ b/pd/nw/pdgui.js
@@ -2178,6 +2178,10 @@ function gui_text_new(canvasname, myname, type, isselected, x, y, text, font) {
         id: myname + 'text'
     });
 
+    // trim off any extraneous leading/trailing whitespace. Because of
+    // the way binbuf_gettext works we almost always have a trailing
+    // whitespace.
+    text = text.trim();
     // fill svg_text with tspan content by splitting on '\n'
     text_to_tspans(canvasname, svg_text, text);
 
@@ -3721,6 +3725,7 @@ function select_text(cid, elem) {
 function gui_textarea(cid, tag, type, x, y, max_char_width, text, font_size, state) {
     //gui_post("x/y is " + x + '/' + y);
     //gui_post("state? " + state);
+console.log("fuck butts... do we have a trailing space? " + ((text.slice(-1) === ' ') ? "Yes" : "No"));
     gui_post("tag is " + tag);
     var range, svg_view;
     var gobj = get_gobj(cid, tag);
diff --git a/pd/src/g_rtext.c b/pd/src/g_rtext.c
index 2865cfcfaac82085a6dcec5b3050b2fd5b883a8a..37ec63ebf5cd512d7dd8455f0d36225e6bc4fbf7 100644
--- a/pd/src/g_rtext.c
+++ b/pd/src/g_rtext.c
@@ -334,7 +334,12 @@ static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
         }
         else ncolumns = widthspec_c;
 
-        // add a null character at the end of the string (for u8_charnum)
+        // add a null character at the end of the string --for u8_charnum
+        // _and_ for the new gui_vmess calls which don't use the %.*s syntax.
+        // Because of the way binbuf_gettext works, we should always have
+        // a space before this null character. But I'm not 100% sure this
+        // space is guaranteed to be there, so we'll just filter it out on
+        // the GUI side for now.
         tempbuf[outchars_b++] = '\0';
 
         // The following is an enormous hack to get the box width to match size 12px