diff --git a/pd/nw/pd_canvas.html b/pd/nw/pd_canvas.html
index 4f739817ef8a57d510a94f796731caf9c98f5623..80ab738821172a2cdcbd89342bbed297eb370eab 100644
--- a/pd/nw/pd_canvas.html
+++ b/pd/nw/pd_canvas.html
@@ -34,19 +34,6 @@
 
     var last_keydown = "";
 
-    // This gets called from the nw_create_window function in index.html
-    // It provides us with our canvas id from the C side.  Once we have it
-    // we can create the menu and register event callbacks
-    function register_canvas_id(cid) {
-console.log("fuck you");
-        create_popup_menu(cid);
-        add_events(cid);
-        nw_create_patch_window_menus(cid);
-        pdgui.canvas_map(cid);
-    }
-
-
-
 // This could probably be in pdgui.js
 function add_keymods(key, evt) {
     var shift = evt.shiftKey ? "Shift" : "";
@@ -54,46 +41,141 @@ function add_keymods(key, evt) {
     return shift + ctrl + key;
 }
 
-function create_popup_menu(name) {
-    // The right-click popup menu
-    var popup_menu = new nw.Menu();
-    pdgui.add_popup(name, popup_menu);
-
-    popup_menu.append(new nw.MenuItem({
-        label: 'Properties',
-        click: function() {
-            pdgui.popup_action(name, 0);
-        }
-    }));
-    popup_menu.append(new nw.MenuItem({
-        label: 'Open',
-        click: function() {
-            pdgui.popup_action(name, 1);
-        }
-    }));
-    popup_menu.append(new nw.MenuItem({
-        label: 'Help',
-        click: function() {
-            pdgui.popup_action(name, 2);
+var canvas_events = (function() {
+    var name,
+        mousemove = function(evt) {
+            //pdgui.gui_post("x: " + evt.pageX + " y: " + evt.pageY +
+            //    " modifier: " + (evt.shiftKey + (evt.ctrlKey << 1)));
+            pdgui.pdsend(name +
+            " motion " + evt.pageX + " " + evt.pageY + " " +
+            (evt.shiftKey + (evt.ctrlKey << 1)));
+            evt.stopPropagation();
+            evt.preventDefault();
+            return false;
+        },
+        mousedown = function(evt) {
+            // tk events are one greater than html5...
+            var b = evt.button + 1;
+            var mod;
+            // For some reason right-click sends a modifier value of "8",
+            // and canvas_doclick in g_editor.c depends on that value to
+            // do the right thing.  So let's hack...
+            if (b === 3) { // right-click
+                mod = 8;
+            } else {
+                mod = (evt.shiftKey + (evt.ctrlKey << 1)); 
+            }
+            pdgui.pdsend(name + " mouse " + evt.pageX + " " + evt.pageY + " " +
+                b + " " + mod);
+            //evt.stopPropagation();
+            evt.preventDefault();
+        },
+        mouseup = function(evt) {
+            //pdgui.gui_post("mouseup: x: " + evt.pageX + " y: " + evt.pageY +
+            //    " button: " + (evt.button + 1));
+            pdgui.pdsend(name +
+                " mouseup " + evt.pageX + " " + evt.pageY + " " +
+                (evt.button + 1));
+            evt.stopPropagation();
+            evt.preventDefault();
+        },
+        keydown = function(evt) {
+            var key_code = evt.keyCode; 
+            var hack = null; // hack for unprintable ascii codes
+            switch(key_code) {
+                case 8:
+                case 9:
+                case 10:
+                case 27:
+                //case 32:
+                case 127: hack = key_code; break;
+                case 37: hack = add_keymods('Left', evt); break;
+                case 38: hack = add_keymods('Up', evt); break;
+                case 39: hack = add_keymods('Right', evt); break;
+                case 40: hack = add_keymods('Down', evt); break;
+                case 33: hack = add_keymods('Prior', evt); break;
+                case 34: hack = add_keymods('Next', evt); break;
+                case 35: hack = add_keymods('End', evt); break;
+                case 36: hack = add_keymods('Home', evt); break;
+
+                // Need to handle Control key, Alt
+
+                case 16: hack = 'Shift'; break;
+                case 17: hack = 'Control'; break;
+                case 18: hack = 'Alt'; break;
+            }
+            if (hack !== null) {
+                pdgui.gui_canvas_sendkey(name, 1, evt, hack);
+                pdgui.set_keymap(key_code, hack);
+            }
+            pdgui.gui_post("keydown time: keycode is " + evt.keyCode);
+            last_keydown = evt.keyCode;
+            //evt.stopPropagation();
+            //evt.preventDefault();
+        },
+        keypress = function(evt) {
+            pdgui.gui_canvas_sendkey(name, 1, evt, evt.charCode);
+            pdgui.set_keymap(last_keydown, evt.charCode);
+            pdgui.gui_post("keypress time: charcode is " + evt.charCode);
+            // Don't do things like scrolling on space, arrow keys, etc.
+            //evt.stopPropagation();
+            evt.preventDefault();
+        },
+        keyup = function(evt) {
+            var my_char_code = pdgui.get_char_code(evt.keyCode);
+            pdgui.gui_canvas_sendkey(name, 0, evt, my_char_code);
+            pdgui.gui_post("keyup time: charcode is: " + my_char_code);
+            evt.stopPropagation();
+            evt.preventDefault();
+        },
+        text_mousemove = function(evt) {
+            evt.stopPropagation();    
+            //evt.preventDefault();
+            return false;
+        },
+        text_mousedown = function(evt) {
+            evt.stopPropagation();    
+            //evt.preventDefault();
+            return false;
+        },
+        text_mouseup = function(evt) {
+            evt.stopPropagation();    
+            //evt.preventDefault();
+            return false;
+        },
+        text_keydown = function(evt) {
+            evt.stopPropagation();    
+            //evt.preventDefault();
+            return false;
+        },
+        text_keyup = function(evt) {
+            evt.stopPropagation();    
+            //evt.preventDefault();
+            return false;
+        },
+        text_keypress = function(evt) {
+            evt.stopPropagation();    
+            //evt.preventDefault();
+            return false;
         }
-    }));
-}
-
-function add_events(name) {
-    document.querySelector("#saveDialog").addEventListener("change", function(evt) {
-        pdgui.saveas_callback(name, this.value);
-        console.log("tried to open something");
-    }, false);
-
-
-    document.querySelector("#fileDialog").addEventListener("change", function(evt) {
-        var file_array = this.value;
-        // reset value so that we can open the same file twice
-        this.value = null;
-        pdgui.menu_open(file_array);
-        console.log("tried to open something");
-    }, false);
+    ;
 
+    // Dialog events
+    document.querySelector("#saveDialog").addEventListener("change",
+        function(evt) {
+            pdgui.saveas_callback(name, this.value);
+            console.log("tried to open something");
+        }, false
+    );
+    document.querySelector("#fileDialog").addEventListener("change",
+        function(evt) {
+            var file_array = this.value;
+            // reset value so that we can open the same file twice
+            this.value = null;
+            pdgui.menu_open(file_array);
+            console.log("tried to open something");
+        }, false
+    );
     document.querySelector("#openpanel_dialog").addEventListener("change",
         function(evt) {
             var file_string = this.value;
@@ -103,7 +185,6 @@ function add_events(name) {
             console.log("tried to openpanel something");
         }, false
     );
-
     document.querySelector("#savepanel_dialog").addEventListener("change",
         function(evt) {
             var file_string = this.value;
@@ -115,106 +196,89 @@ function add_events(name) {
     );
 
 
-    document.addEventListener("mousemove", function(evt) {
-        //pdgui.gui_post("x: " + evt.pageX + " y: " + evt.pageY +
-        //    " modifier: " + (evt.shiftKey + (evt.ctrlKey << 1)));
-        pdgui.pdsend(name + " motion " + evt.pageX + " " + evt.pageY + " " +
-            (evt.shiftKey + (evt.ctrlKey << 1)));
-        evt.stopPropagation();
-//        evt.preventDefault();
-        return false;
-    });
-
-    document.addEventListener("keydown", function(evt) {
-        var key_code = evt.keyCode; 
-        var hack = null; // hack for unprintable ascii codes
-        switch(key_code) {
-            case 8:
-            case 9:
-            case 10:
-            case 27:
-//            case 32:
-            case 127: hack = key_code; break;
-
-
-            case 37: hack = add_keymods('Left', evt); break;
-            case 38: hack = add_keymods('Up', evt); break;
-            case 39: hack = add_keymods('Right', evt); break;
-            case 40: hack = add_keymods('Down', evt); break;
-            case 33: hack = add_keymods('Prior', evt); break;
-            case 34: hack = add_keymods('Next', evt); break;
-            case 35: hack = add_keymods('End', evt); break;
-            case 36: hack = add_keymods('Home', evt); break;
-
-            // Need to handle Control key, Alt
-
-            case 16: hack = 'Shift'; break;
-            case 17: hack = 'Control'; break;
-            case 18: hack = 'Alt'; break;
-        }
-        if (hack !== null) {
-            pdgui.gui_canvas_sendkey(name, 1, evt, hack);
-            pdgui.set_keymap(key_code, hack);
-        }
-        pdgui.gui_post("keydown time: keycode is " + evt.keyCode);
-        last_keydown = evt.keyCode;
-        evt.stopPropagation();
-    });
-
-    document.addEventListener("keypress", function(evt) {
-        pdgui.gui_canvas_sendkey(name, 1, evt, evt.charCode);
-        pdgui.set_keymap(last_keydown, evt.charCode);
-        pdgui.gui_post("keypress time: charcode is " + evt.charCode);
-        // Don't do things like scrolling on space, arrow keys, etc.
-        evt.stopPropagation();
-        evt.preventDefault();
-    });
-
-    document.addEventListener("keyup", function(evt) {
-        var my_char_code = pdgui.get_char_code(evt.keyCode);
-        pdgui.gui_canvas_sendkey(name, 0, evt, my_char_code);
-        pdgui.gui_post("keyup time: charcode is: " + my_char_code);
+    // closing the Window
+    // this isn't actually closing the window yet
+    nw.Window.get().on("close", function() {
+        pdgui.pdsend(name + " menuclose 0");
     });
 
-    // just left-clicks for the moment
-    document.onmousedown = function(evt) {
-        //pdgui.gui_post("mousedown: x: " + evt.pageX + " y: " + evt.pageY +
-        //    " button: " + (evt.button + 1) + " modifier: " + (evt.shiftKey + (evt.ctrlKey << 1)));
-        // tk events are one greater than html5...
-        var b = evt.button + 1;
-        var mod;
-        // For some reason right-click sends a modifier value of "8", and canvas_doclick in
-        // g_editor.c depends on that value to do the right thing.  So let's hack...
-        if (b === 3) { // right-click
-            mod = 8;
-        } else {
-            mod = (evt.shiftKey + (evt.ctrlKey << 1)); 
+    return {
+        normal: function() {
+            document.removeEventListener("mousemove", text_mousemove, false);
+            document.removeEventListener("keydown", text_keydown, false);
+            document.removeEventListener("keypress", text_keypress, false);
+            document.removeEventListener("keyup", text_keyup, false);
+            document.removeEventListener("mousedown", text_mousedown, false);
+            document.removeEventListener("mouseup", text_mouseup, false);
+
+            document.addEventListener("mousemove", mousemove, false);
+            document.addEventListener("keydown", keydown, false);
+            document.addEventListener("keypress", keypress, false);
+            document.addEventListener("keyup", keyup, false);
+            document.addEventListener("mousedown", mousedown, false);
+            document.addEventListener("mouseup", mouseup, false);
+        },
+        text: function() {
+            document.removeEventListener("mousemove", mousemove, false);
+            document.removeEventListener("keydown", keydown, false);
+            document.removeEventListener("keypress", keypress, false);
+            document.removeEventListener("keyup", keyup, false);
+            document.removeEventListener("mousedown", mousedown, false);
+            document.removeEventListener("mouseup", mouseup, false);
+
+            document.addEventListener("mousemove", text_mousemove, false);
+            document.addEventListener("keydown", text_keydown, false);
+            document.addEventListener("keypress", text_keypress, false);
+            document.addEventListener("keyup", text_keyup, false);
+            document.addEventListener("mousedown", text_mousedown, false);
+            document.addEventListener("mouseup", mouseup, false);
+        },
+        register: function(n) {
+            name = n;
         }
-        pdgui.pdsend(name + " mouse " + evt.pageX + " " + evt.pageY + " " +
-            b + " " + mod);
-        evt.stopPropagation();
-        evt.preventDefault();
     }
+}());
 
-    document.onmouseup = function(evt) {
-        //pdgui.gui_post("mouseup: x: " + evt.pageX + " y: " + evt.pageY +
-        //    " button: " + (evt.button + 1));
-        pdgui.pdsend(name + " mouseup " + evt.pageX + " " + evt.pageY + " " +
-            (evt.button + 1));
-    }
 
 
+    // This gets called from the nw_create_window function in index.html
+    // It provides us with our canvas id from the C side.  Once we have it
+    // we can create the menu and register event callbacks
+    function register_canvas_id(cid) {
+console.log("fuck you");
+        create_popup_menu(cid);
+        canvas_events.register(cid);
+        canvas_events.normal();
+        nw_create_patch_window_menus(cid);
+        pdgui.canvas_map(cid);
+    }
 
 
-    // let's handle some events for this window...
 
-    // closing the Window
-    // this isn't actually closing the window yet
-    nw.Window.get().on("close", function() {
-        pdgui.pdsend(name + " menuclose 0");
-    });
 
+function create_popup_menu(name) {
+    // The right-click popup menu
+    var popup_menu = new nw.Menu();
+    pdgui.add_popup(name, popup_menu);
 
+    popup_menu.append(new nw.MenuItem({
+        label: 'Properties',
+        click: function() {
+            pdgui.popup_action(name, 0);
+        }
+    }));
+    popup_menu.append(new nw.MenuItem({
+        label: 'Open',
+        click: function() {
+            pdgui.popup_action(name, 1);
+        }
+    }));
+    popup_menu.append(new nw.MenuItem({
+        label: 'Help',
+        click: function() {
+            pdgui.popup_action(name, 2);
+        }
+    }));
 }
 
 
@@ -222,6 +286,7 @@ function add_events(name) {
 
 
 
+
 //nw_create_patch_window_menus(name);
 
         function menu_generic () {
diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js
index 460958622cfc1fce75d64427db712370d0241d82..2fd515699ae545987eb4fdfe6d194085b64479d1 100644
--- a/pd/nw/pdgui.js
+++ b/pd/nw/pdgui.js
@@ -3395,3 +3395,29 @@ exports.skin = (function () {
         }
     };
 }());
+
+function gui_textarea(cid, tag, x, y, font_size, state) {
+    gui_post("x/y is " + x + '/' + y);
+    if (state === 1) {
+        var p = patchwin[cid].window.document.createElement('p');
+        configure_item(p, {
+            id: 'new_object_textentry'
+        });
+        p.contentEditable = 'true';
+        p.style.setProperty('left', x + 'px');
+        p.style.setProperty('top', y + 'px');
+        p.style.setProperty('font-size', font_size + 'px');
+        p.textContent = "Fuck Butts";
+        patchwin[cid].window.document.body.appendChild(p);
+        p.focus();
+        patchwin[cid].window.canvas_events.text();
+        /* here we need to make sure that events inside the
+           <p> don't propogate down to the svg below... */
+    } else {
+        var p = patchwin[cid].window.document.getElementById('new_object_textentry');
+        if (p !== null) {
+            p.parentNode.removeChild(p);
+        }
+        patchwin[cid].window.canvas_events.normal();
+    }
+}
diff --git a/pd/nw/todo.txt b/pd/nw/todo.txt
index 6e5c2609b11e3d73671c47368b2955a707e4d1a3..5e7d09edcc9ae5d444904148766bfe78fa126d58 100644
--- a/pd/nw/todo.txt
+++ b/pd/nw/todo.txt
@@ -18,12 +18,12 @@ Node-webkit stuff:
 4) (probably) present working directory
 5) command line argv
 
-Everything else: (A [*] means we've fixed it)
+Everything else: (A [x] means we've fixed it)
 [ ] packaging as app, setting correct appname, etc
 [ ] get -unique to work (relied on tcl [send] command)
 [ ] check if patch windows with screenposition (0,0) get stuck underneath Ubuntu/OSX menu.  If so,
 [ ] Node-webkit has a "screen" interface to retrieve the "workable" area of the screen
-[*] choosing the same directory multiple times doesn't work (see dialog API page)
+[x] choosing the same directory multiple times doesn't work (see dialog API page)
 [ ] "Save As" on an overwrite doesn't seem to clear the dirty flag
 [ ] figure out why there is a "pd_opendir" global var
 [ ] pass k12 mode arg
@@ -142,10 +142,10 @@ Everything else: (A [*] means we've fixed it)
 [ ] getting the sense that glist_isselected should _always_ have
     glist_getcanvas(x) as its first parameter
 [x] get rid of the old tcl specific sys_get_audio_apis
-[ ] have a single function to set t_svg_attr
-[ ] change x_x1..y2 to simple x_bbox[4], and change current x_bbox to
+[x] have a single function to set t_svg_attr
+[ ] t_svg: change x_x1..y2 to simple x_bbox[4], and change current x_bbox to
     x_cachebbox (or something like that)
-[ ] figure out why gatom_retext sends a fill color to GUI
+[x] figure out why gatom_retext sends a fill color to GUI
 [ ] look into changing 'x' format specifier from \"x%.6lx\" to more generic
     \"%.6lx\". (Not exactly sure what good the "x" does there.)  It's only
     specified in s_inter and in editor_new, so it should be easy to amend
diff --git a/pd/src/g_rtext.c b/pd/src/g_rtext.c
index d14c840c6339155e3e483a9bf262418e0cd0ce2a..c82c9be14cf0732ef3582e12da9888f3f223c9e2 100644
--- a/pd/src/g_rtext.c
+++ b/pd/src/g_rtext.c
@@ -532,6 +532,7 @@ void rtext_displace(t_rtext *x, int dx, int dy)
 /* Not sure if this is still used */
 void rtext_select(t_rtext *x, int state)
 {
+post("selected an rtext");
     t_glist *glist = x->x_glist;
     t_canvas *canvas = glist_getcanvas(glist);
     if (glist_istoplevel(glist))
@@ -551,7 +552,7 @@ void rtext_select(t_rtext *x, int state)
 
 void rtext_activate(t_rtext *x, int state)
 {
-    //fprintf(stderr,"rtext_activate\n");
+    fprintf(stderr,"rtext_activate state=%d\n", state);
     int w = 0, h = 0, indx;
     t_glist *glist = x->x_glist;
     t_canvas *canvas = glist_getcanvas(glist);
@@ -562,7 +563,7 @@ void rtext_activate(t_rtext *x, int state)
     //if (state == x->x_active) return; // avoid excess calls
     if (state)
     {
-        sys_vgui(".x%lx.c focus %s\n", canvas, x->x_tag);
+        //sys_vgui(".x%lx.c focus %s\n", canvas, x->x_tag);
         glist->gl_editor->e_textedfor = x;
         glist->gl_editor->e_textdirty = 0;
         x->x_dragfrom = x->x_selstart = 0;
@@ -571,13 +572,22 @@ void rtext_activate(t_rtext *x, int state)
     }
     else
     {
-        sys_vgui("selection clear .x%lx.c\n", canvas);
-        sys_vgui(".x%lx.c focus \"\"\n", canvas);
+        //sys_vgui("selection clear .x%lx.c\n", canvas);
+        //sys_vgui(".x%lx.c focus \"\"\n", canvas);
         if (glist->gl_editor->e_textedfor == x)
             glist->gl_editor->e_textedfor = 0;
         x->x_active = 0;
     }
+    /* so I guess the following would need to be commented out
+       if we want to use the textarea junk to feed to Pd... */
     rtext_senditup(x, SEND_UPDATE, &w, &h, &indx);
+    gui_vmess("gui_textarea", "xsiiii",
+        canvas,
+        x->x_tag,
+        x->x_text->te_xpix,
+        x->x_text->te_ypix,
+        sys_hostfontsize(glist_getfont(glist)),
+        state);
 }
 
 // outputs 1 if found one of the special chars
diff --git a/pd/src/g_text.c b/pd/src/g_text.c
index df0898f9b4ef3db3953bb12958ca0d8f5f5dfec8..05de05aa4607474a8c0b078def76507e2c85e007 100644
--- a/pd/src/g_text.c
+++ b/pd/src/g_text.c
@@ -355,7 +355,9 @@ void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
         int connectme, xpix, ypix, indx, nobj;
         canvas_howputnew(gl, &connectme, &xpix, &ypix, &indx, &nobj);
         pd_vmess(&gl->gl_pd, gensym("editmode"), "i", 1);
-        canvas_objtext(gl, xpix, ypix, 0, 1, b);
+        canvas_objtext(gl,
+            connectme ? xpix : xpix - 8,
+            connectme ? ypix : ypix - 8, 0, 1, b);
         if (connectme == 1)
         {
             //fprintf(stderr,"canvas_obj calls canvas_connect\n");
@@ -366,7 +368,7 @@ void canvas_obj(t_glist *gl, t_symbol *s, int argc, t_atom *argv)
         else if (connectme == 0)
         {
             //fprintf(stderr,"canvas_obj calls canvas_startmotion\n");
-            canvas_displaceselection(glist_getcanvas(gl), -8, -8);
+//            canvas_displaceselection(glist_getcanvas(gl), -8, -8);
             canvas_startmotion(glist_getcanvas(gl));
         }
         //canvas_setundo(glist_getcanvas(gl),