diff --git a/externals/miXed/cyclone/sickle/Scope.c b/externals/miXed/cyclone/sickle/Scope.c
index b5c6aa5e91ea8db22bd2fa5cb0df4ee54cef621a..33b8b76f2298d7776a021366a11f8a8cebe963e4 100644
--- a/externals/miXed/cyclone/sickle/Scope.c
+++ b/externals/miXed/cyclone/sickle/Scope.c
@@ -106,9 +106,8 @@ typedef struct _scope
     int        x_frozen;
     t_clock   *x_clock;
     t_pd      *x_handle;
-
-	int			scale_offset_x;
-	int			scale_offset_y;
+    int	      scale_offset_x;
+    int       scale_offset_y;
 } t_scope;
 
 typedef struct _scopehandle
@@ -118,6 +117,9 @@ typedef struct _scopehandle
     t_symbol  *h_bindsym;
     char       h_pathname[64];
     char       h_outlinetag[64];
+    int        h_adjust_x;
+    int        h_adjust_y;
+    int        h_constrain;
     int        h_dragon;
     int        h_dragx;
     int        h_dragy;
@@ -992,49 +994,16 @@ static void scope_tick(t_scope *x)
     scope_clear(x, 1);
 }
 
-static void scopehandle__clickhook(t_scopehandle *sh, t_floatarg f, t_floatarg xxx, t_floatarg yyy)
+extern void canvas_apply_setundo(t_canvas *x, t_gobj *y);
+static void scopehandle__clickhook(t_scopehandle *sh, t_floatarg f,
+    t_floatarg xxx, t_floatarg yyy)
 {
-
     t_scope *x = sh->h_master;
-
-    //if (xxx) x->scale_offset_x = xxx;
-    //if (yyy) x->scale_offset_y = yyy;
-
-    //int newstate = (int)f;
-    //if (sh->h_dragon && newstate == 0)
-    //{
-    //    /* done dragging */
-    //    t_canvas *cv;
-    //    if (sh->h_dragx || sh->h_dragy)
-    //    {
-    //        x->x_width = x->x_width + sh->h_dragx - x->scale_offset_x;
-    //        x->x_height = x->x_height + sh->h_dragy - x->scale_offset_y;
-    //    }
-    //    if (cv = scope_isvisible(x))
-    //    {
-    //        sys_vgui(".x%x.c delete %s\n", cv, sh->h_outlinetag);
-    //        scope_revis(x, cv);
-    //        sys_vgui("destroy %s\n", sh->h_pathname);
-    //        scope_select((t_gobj *)x, x->x_glist, 1);
-    //        canvas_fixlinesfor(x->x_glist, (t_text *)x);  /* 2nd inlet */
-    //    }
-    //}
-    //else if (!sh->h_dragon && newstate)
-    //{
-    //    /* dragging */
-    //    t_canvas *cv;
-    //    if (cv = scope_isvisible(x))
-    //    {
-    //        int x1, y1, x2, y2;
-    //        scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2);
-    //        sys_vgui("lower %s\n", sh->h_pathname);
-    //        sys_vgui(".x%x.c create rectangle %d %d %d %d\
-    //            -outline $select_color -width %f -tags %s\n",
-    //        cv, x1, y1, x2, y2, SCOPE_SELBDWIDTH, sh->h_outlinetag);
-    //    }
-    //    sh->h_dragx = 0;
-    //    sh->h_dragy = 0;
-    //}
+    /* Use constrained dragging. See g_canvas.c clickhook */
+    sh->h_constrain = (int)f;
+    sh->h_adjust_x = xxx - (((t_object *)x)->te_xpix + x->x_width);
+    sh->h_adjust_y = yyy - (((t_object *)x)->te_ypix + x->x_height);
+    canvas_apply_setundo(x->x_glist, (t_gobj *)x);
     sh->h_dragon = f;
 }
 
@@ -1042,10 +1011,13 @@ static void scopehandle__motionhook(t_scopehandle *sh,
 				    t_floatarg mouse_x, t_floatarg mouse_y)
 {
     t_scope *x = (t_scope *)(sh->h_master);
-    int x1, y1, x2, y2, width, height;
-    scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2);
-    width = mouse_x - x1;
-    height = mouse_y - y1;
+    int width = (sh->h_constrain == CURSOR_EDITMODE_RESIZE_Y) ?
+        x->x_width :
+        (int)mouse_x - text_xpix((t_text *)x, x->x_glist) - sh->h_adjust_x;
+    int height = (sh->h_constrain == CURSOR_EDITMODE_RESIZE_X) ?
+        x->x_height :
+        (int)mouse_y - text_ypix((t_text *)x, x->x_glist) - sh->h_adjust_y;
+
     x->x_width =  width < SCOPE_MINWIDTH ? SCOPE_MINWIDTH : width;
     x->x_height = height < SCOPE_MINHEIGHT ? SCOPE_MINHEIGHT : height;
 
@@ -1058,25 +1030,6 @@ static void scopehandle__motionhook(t_scopehandle *sh,
         scope_vis((t_gobj *)x, x->x_glist, 0);
         scope_vis((t_gobj *)x, x->x_glist, 1);
     }
-    //if (sh->h_dragon)
-    //{
-    //    t_scope *x = sh->h_master;
-    //    int dx = (int)f1, dy = (int)f2;
-    //    int x1, y1, x2, y2, newx, newy;
-    //    scope_getrect((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2);
-    //    newx = x2 - x->scale_offset_x + dx;
-    //    newy = y2 - x->scale_offset_y + dy;
-
-    //    if (newx > x1 + SCOPE_MINWIDTH && newy > y1 + SCOPE_MINHEIGHT)
-    //    {
-    //        t_canvas *cv;
-    //        if (cv = scope_isvisible(x))
-    //            sys_vgui(".x%x.c coords %s %d %d %d %d\n",
-    //                cv, sh->h_outlinetag, x1, y1, newx, newy);
-    //        sh->h_dragx = dx;
-    //        sh->h_dragy = dy;
-    //    }
-    //}
 }
 
 /* wrapper method for forwarding "scopehandle" data */
@@ -1157,8 +1110,8 @@ static void *scope_new(t_symbol *s, int ac, t_atom *av)
     sprintf(sh->h_outlinetag, "h%x", (int)sh);
     sh->h_dragon = 0;
 
-	x->scale_offset_x = 0;
-	x->scale_offset_y = 0;
+    x->scale_offset_x = 0;
+    x->scale_offset_y = 0;
 
     return (x);
 }
diff --git a/externals/unauthorized/grid.c b/externals/unauthorized/grid.c
index da3c56ab1ea165cef34ecd6829ef457ef494156e..557436d7b482190d06ce4b57c5167e09907f2dfb 100644
--- a/externals/unauthorized/grid.c
+++ b/externals/unauthorized/grid.c
@@ -696,39 +696,43 @@ static void grid_bang(t_grid *x) {
 static void grid__clickhook(t_scalehandle *sh, int newstate)
 {
     t_grid *x = (t_grid *)(sh->h_master);
-    if (newstate)
-    {
-        canvas_apply_setundo(x->x_glist, (t_gobj *)x);
-    }
+    /* Use constrained dragging-- see g_canvas.c clickhook */
+    sh->h_constrain = newstate;
+    sh->h_adjust_x = sh->h_offset_x -
+        (((t_object *)x)->te_xpix + x->x_width);
+    sh->h_adjust_y = sh->h_offset_y -
+        (((t_object *)x)->te_ypix + x->x_height);
+    canvas_apply_setundo(x->x_glist, (t_gobj *)x);
     sh->h_dragon = newstate;
 }
 
 static void grid__motionhook(t_scalehandle *sh,
     t_floatarg mouse_x, t_floatarg mouse_y)
 {
-    if (sh->h_scale)
+    t_grid *x = (t_grid *)(sh->h_master);
+    int width = (sh->h_constrain == CURSOR_EDITMODE_RESIZE_Y) ?
+        x->x_width :
+        (int)mouse_x - text_xpix(&x->x_obj, x->x_glist) - sh->h_adjust_x;
+    int height = (sh->h_constrain == CURSOR_EDITMODE_RESIZE_X) ?
+        x->x_height :
+        (int)mouse_y - text_ypix(&x->x_obj, x->x_glist) - sh->h_adjust_y;
+    int minw = MIN_GRID_WIDTH,
+        minh = MIN_GRID_HEIGHT;
+    x->x_width = width < minw ? minw : width;
+    x->x_height = height < minh ? minh : height;
+    if (glist_isvisible(x->x_glist))
     {
-        t_grid *x = (t_grid *)(sh->h_master);
-        int width = mouse_x - text_xpix(&x->x_obj, x->x_glist),
-            height = mouse_y - text_ypix(&x->x_obj, x->x_glist),
-            minw = MIN_GRID_WIDTH,
-            minh = MIN_GRID_HEIGHT;
-        x->x_width = width < minw ? minw : width;
-        x->x_height = height < minh ? minh : height;
-        if (glist_isvisible(x->x_glist))
-        {
-            grid_draw_configure(x, x->x_glist);
-            //scalehandle_unclick_scale(sh);
-        }
+        grid_draw_configure(x, x->x_glist);
+        //scalehandle_unclick_scale(sh);
+    }
 
-        int properties = gfxstub_haveproperties((void *)x);
-        if (properties)
-        {
-            int new_w = x->x_width + sh->h_dragx;
-            int new_h = x->x_height + sh->h_dragy;
-            properties_set_field_int(properties,"width",new_w);
-            properties_set_field_int(properties,"height",new_h);
-        }
+    int properties = gfxstub_haveproperties((void *)x);
+    if (properties)
+    {
+        int new_w = x->x_width + sh->h_dragx;
+        int new_h = x->x_height + sh->h_dragy;
+        properties_set_field_int(properties,"width",new_w);
+        properties_set_field_int(properties,"height",new_h);
     }
 }
 
@@ -737,8 +741,9 @@ static void grid_click_for_resizing(t_grid *x, t_floatarg f,
     t_floatarg xxx, t_floatarg yyy)
 {
     t_scalehandle *sh = (t_scalehandle *)x->x_handle;
+    sh->h_offset_x = (int)xxx;
+    sh->h_offset_y = (int)yyy;
     grid__clickhook(sh, f);
-//    grid__clickhook(sh, f, xxx, yyy);
 }
 
 /* another wrapper for forwarding "scalehandle" motion data */
diff --git a/pd/nw/pd_canvas.js b/pd/nw/pd_canvas.js
index db54bda82cc9a561b3f0fe2187b9920661862f20..1e9c770a326da00b48b7bd5e1f77a5c35706dc0d 100644
--- a/pd/nw/pd_canvas.js
+++ b/pd/nw/pd_canvas.js
@@ -233,25 +233,50 @@ var canvas_events = (function() {
                 return false;
             },
             mousedown: function(evt) {
-                var target_id;
+                var target_id, resize_type;
                 if (target_is_scrollbar(evt)) {
                     return;
-                } else if (evt.target.classList.contains("clickable_resize_handle")) {
+                } else if (evt.target.parentNode &&
+                    evt.target.parentNode.classList
+                        .contains("clickable_resize_handle")) {
                     draggable_label =
-                        evt.target.classList.contains("move_handle");
+                        evt.target.parentNode.classList.contains("move_handle");
 
                     // get id ("x123456etcgobj" without the "x" or "gobj")
                     target_id = (draggable_label ? "_l" : "_s") +
-                        evt.target.parentNode.id.slice(0,-4).slice(1);
+                        evt.target.parentNode.parentNode.id.slice(0,-4).slice(1);
                     last_draggable_x = evt.pageX + svg_view.x;
                     last_draggable_y = evt.pageY + svg_view.y;
-                    pdgui.pdsend(target_id, "_click", 1,
+
+                    // Nasty-- we have to forward magic values from g_canvas.h
+                    // defines in order to get the correct constrain behavior.
+                    if (evt.target.classList.contains("constrain_top_right")) {
+                        resize_type = 7; // CURSOR_EDITMODE_RESIZE_X
+                    } else if (evt.target.classList
+                        .contains("constrain_bottom_right")) {
+                        resize_type = 10; // CURSOR_EDITMODE_RESIZE_Y
+                    } else if (draggable_label) {
+                        resize_type = 11; // CURSOR_EDITMODE_MOVE
+                    } else {
+                        resize_type = 8; // CURSOR_EDITMODE_RESIZE
+                    }
+
+                    // Even nastier-- we now must turn off the cursor styles
+                    // so that moving the pointer outside the hotspot doesn't
+                    // cause the cursor to change. This happens for the
+                    // drag handle to move the gop red rectangle. Unlike
+                    // the label handles, it doesn't get immediately
+                    // destroyed upon receiving its callback below.
+                    pdgui.toggle_drag_handle_cursors(evt.target.parentNode,
+                        !!draggable_label, false);
+
+                    pdgui.pdsend(target_id, "_click", resize_type,
                         (evt.pageX + svg_view.x),
                         (evt.pageY + svg_view.y));
                     canvas_events.iemgui_label_drag();
                     return;
                 }
-                // tk events (and, therefore, Pd evnets) are one greater
+                // tk events (and, therefore, Pd events) are one greater
                 // than html5...
                 var b = evt.button + 1;
                 var mod, match_elem;
@@ -472,16 +497,6 @@ var canvas_events = (function() {
                 last_draggable_x = evt.pageX + svg_view.x;
                 last_draggable_y = evt.pageY + svg_view.y;
 
-                if (!is_canvas_gop_rect) {
-                    // This is bad-- we should be translating
-                    // here so that the logic doesn't depend on the shape
-                    // type we chose in pdgui (here, it's "line").
-                    handle_elem.x1.baseVal.value += dx;
-                    handle_elem.y1.baseVal.value += dy;
-                    handle_elem.x2.baseVal.value += dx;
-                    handle_elem.y2.baseVal.value += dy;
-                }
-
                 pdgui.pdsend(target_id, "_motion",
                     (evt.pageX + svg_view.x),
                     (evt.pageY + svg_view.y));
@@ -491,6 +506,19 @@ var canvas_events = (function() {
                 // Set last state (none doesn't count as a state)
                 //pdgui.post("previous state is "
                 //    + canvas_events.get_previous_state());
+                var label_handle = document.querySelector(".move_handle");
+                var cnv_resize_handle =
+                    document.querySelector(".cnv_resize_handle");
+                // Restore our cursor bindings for any drag handles that
+                // happen to exist
+                if (label_handle) {
+                    pdgui.toggle_drag_handle_cursors(label_handle,
+                        true, true);
+                }
+                if (cnv_resize_handle) {
+                    pdgui.toggle_drag_handle_cursors(cnv_resize_handle,
+                        false, true);
+                }
                 canvas_events[canvas_events.get_previous_state()]();
             },
             dropdown_menu_keydown: function(evt) {
diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js
index 97d0fa3a013323cee5624eadf55911722285334c..260ace1ea2a0c7e0dfccc8c5f09a700554ad5cfc 100644
--- a/pd/nw/pdgui.js
+++ b/pd/nw/pdgui.js
@@ -1472,11 +1472,18 @@ function gui_canvas_cursor(cid, pd_event_type) {
             case "cursor_editmode_resize":
                 c = "ew-resize";
                 break;
-            case "cursor_editmode_resize_bottom_right": c = "se-resize";
+            case "cursor_editmode_resize_bottom_right":
+                c = "se-resize";
                 break;
             case "cursor_scroll":
                 c = "all-scroll";
                 break;
+            case "cursor_editmode_resize_vert":
+                c = "ns-resize";
+                break;
+            case "cursor_editmode_move":
+                c = "move";
+                break;
         }
         patch.style.cursor = c;
     });
@@ -2021,7 +2028,7 @@ var gui = (function() {
         return {
             append: !w ? null_fn: function(cb) {
                 var frag = w.window.document.createDocumentFragment();
-                frag = cb(frag, w.window);
+                frag = cb(frag, w.window, c[cid]);
                 last_thing.appendChild(frag);
                 return c[cid];
             },
@@ -3239,12 +3246,29 @@ function gui_iemgui_label_font(cid, tag, fontname, fontweight, fontsize) {
     });
 }
 
+function toggle_drag_handle_cursors(e, is_label, state) {
+    e.querySelector(".constrain_top_right").style.cursor =
+        state ? "ew-resize" : "";
+    e.querySelector(".constrain_bottom_right").style.cursor =
+        state ? "ns-resize" : "";
+    e.querySelector(".unconstrained").style.cursor =
+        state ? (is_label ? "move" : "se-resize") : "";
+}
+
+exports.toggle_drag_handle_cursors = toggle_drag_handle_cursors;
+
 // Show or hide little handle for dragging around iemgui labels
 function gui_iemgui_label_show_drag_handle(cid, tag, state, x, y, cnv_resize) {
     if (state !== 0) {
         gui(cid).get_gobj(tag)
-        .append(function(frag) {
-            var rect;
+        .append(function(frag, w) {
+            var g, rect, top_right, bottom_right;
+            g = create_item(cid, "g", {
+                class: (cid === tag) ? "gop_drag_handle move_handle border" :
+                    cnv_resize !== 0 ? "cnv_resize_handle border" :
+                    "label_drag_handle move_handle border",
+                transform: "matrix(1, 0, 0, 1, 0, 0)"
+            });
             // Here we use a "line" shape so that we can control its color
             // using the "border" class (for iemguis) or the "gop_rect" class
             // for the graph-on-parent rectangle anchor. In both cases the
@@ -3252,28 +3276,59 @@ function gui_iemgui_label_show_drag_handle(cid, tag, state, x, y, cnv_resize) {
             // to define than a "rect" for that case.
             rect = create_item(cid, "line", {
                 x1: x,
-                y1: y + 3,
+                y1: y,
                 x2: x,
-                y2: y + 10,
-                "stroke-width": 7,
-                class: (cid === tag) ? "gop_drag_handle move_handle gop_rect" :
-                    cnv_resize !== 0 ? "cnv_resize_handle border" :
-                    "label_drag_handle move_handle border"
+                y2: y + 14,
+                "stroke-width": 14,
+                class: "unconstrained"
+            });
+            g.classList.add("clickable_resize_handle");
+            top_right = create_item(cid, "rect", {
+                x: x + 1.5,
+                y: y + 0.5,
+                width: 5,
+                height: 7,
+                fill: "black",
+                "fill-opacity": "0",
+                class: "constrain_top_right"
             });
-            rect.classList.add("clickable_resize_handle");
-            frag.appendChild(rect);
+            bottom_right = create_item(cid, "rect", {
+                x: x - 6.5,
+                y: y + 8.5,
+                width: 7,
+                height: 5,
+                fill: "black",
+                "fill-opacity": "0",
+                class: "constrain_bottom_right"
+            });
+            g.appendChild(rect);
+            g.appendChild(top_right);
+            g.appendChild(bottom_right);
+
+            // Quick hack for cursors on mouse-over. We only add them if
+            // we're not already dragging a label or resizing an iemgui.
+            // Apparently I didn't register all these edge-case event states
+            // in canvas_events. States like "iemgui_label_drag" actually
+            // just get registered as state "none". So we just check for "none"
+            // here and assume it means we're in the middle of dragging.
+            // If not we go ahead and set our cursor styles.
+            if (w.canvas_events.get_state() != "none") {
+                toggle_drag_handle_cursors(g, cnv_resize === 0, true);
+            }
+
+            frag.appendChild(g);
             return frag;
         });
     } else {
         gui(cid).get_gobj(tag, function(e) {
-            var rect =
+            var g =
                 e.getElementsByClassName((cid === tag) ? "gop_drag_handle" :
                     cnv_resize !== 0 ? "cnv_resize_handle" :
                         "label_drag_handle")[0];
             //rect = get_item(cid, "clickable_resize_handle");
             // Need to check for null here...
-            if (rect) {
-                rect.parentNode.removeChild(rect);
+            if (g) {
+                g.parentNode.removeChild(g);
             } else {
                 post("error: couldn't delete the iemgui drag handle!");
             }
@@ -3281,6 +3336,15 @@ function gui_iemgui_label_show_drag_handle(cid, tag, state, x, y, cnv_resize) {
     }
 }
 
+function gui_iemgui_label_displace_drag_handle(cid, tag, dx, dy) {
+    gui(cid).get_gobj(tag)
+    .q(".label_drag_handle", function(e) {
+        var t = e.transform.baseVal.getItem(0);
+        t.matrix.e += dx;
+        t.matrix.f += dy;
+    });
+}
+
 function gui_mycanvas_new(cid,tag,color,x1,y1,x2_vis,y2_vis,x2,y2) {
     gui(cid).get_gobj(tag)
     .append(function(frag) {
diff --git a/pd/src/g_all_guis.c b/pd/src/g_all_guis.c
index c2381e0f12f3d6d283868cf82e2c936143a31ef7..e7701ab1eeea56ed29098ecfb3ab040f2b7f2ad3 100644
--- a/pd/src/g_all_guis.c
+++ b/pd/src/g_all_guis.c
@@ -246,7 +246,7 @@ void iemgui_label_pos(t_iemgui *x, t_symbol *s, int ac, t_atom *av)
 {
     x->x_ldx = atom_getintarg(0, ac, av);
     x->x_ldy = atom_getintarg(1, ac, av);
-    if(glist_isvisible(x->x_glist))
+    if (glist_isvisible(x->x_glist))
     {
         int x1 = x->x_ldx;
         int y1 = x->x_ldy;
@@ -474,7 +474,7 @@ void iemgui_pos(t_iemgui *x, t_symbol *s, int ac, t_atom *av)
 {
     x->x_obj.te_xpix = atom_getintarg(0, ac, av);
     x->x_obj.te_ypix = atom_getintarg(1, ac, av);
-    if(glist_isvisible(x->x_glist))
+    if (glist_isvisible(x->x_glist))
         iemgui_shouldvis(x, IEM_GUI_DRAW_MODE_MOVE);
 }
 
@@ -488,7 +488,7 @@ void iemgui_color(t_iemgui *x, t_symbol *s, int ac, t_atom *av)
     }
     else
         x->x_lcol = iemgui_compatible_col(atom_getintarg(1, ac, av));
-    if(glist_isvisible(x->x_glist))
+    if (glist_isvisible(x->x_glist))
     {
         x->x_draw(x, x->x_glist, IEM_GUI_DRAW_MODE_CONFIG);
         iemgui_label_draw_config(x);
@@ -713,7 +713,7 @@ void scalehandle_draw_select2(t_iemgui *x)
 {
     t_canvas *canvas=glist_getcanvas(x->x_glist);
     t_class *c = pd_class((t_pd *)x);
-    int sx,sy;
+    int sx, sy;
     if (c == my_canvas_class)
     {
         t_my_canvas *y = (t_my_canvas *)x;
@@ -722,24 +722,27 @@ void scalehandle_draw_select2(t_iemgui *x)
     }
     else
     {
-        int x1,y1,x2,y2;
-        c->c_wb->w_getrectfn((t_gobj *)x,canvas,&x1,&y1,&x2,&y2);
+        int x1, y1, x2, y2;
+        c->c_wb->w_getrectfn((t_gobj *)x,canvas, &x1, &y1, &x2, &y2);
         //iemgui_getrect_draw(x, &x1, &y1, &x2, &y2);
-        sx=x2-x1; sy=y2-y1;
+        sx = x2 - x1; sy = y2 - y1;
     }
     /* we're not drawing the scalehandle for the actual iemgui-- just
-       the one for the label. */
+       the one for the label. Special case for [cnv] which for some reason
+       allows a smaller selection area than its painted rectangle. */
     if (c == my_canvas_class)
-        scalehandle_draw_select(x->x_handle,sx+8,sy+3);
+        scalehandle_draw_select(x->x_handle,
+            (int)(sx + SCALEHANDLE_WIDTH * 1.5) + 1,
+            sy + SCALEHANDLE_HEIGHT);
     if (x->x_lab != s_empty)
-        scalehandle_draw_select(x->x_lhandle,x->x_ldx,x->x_ldy);
+        scalehandle_draw_select(x->x_lhandle, x->x_ldx + 5, x->x_ldy + 10);
 }
 
 void scalehandle_draw_erase(t_scalehandle *h)
 {
     //t_canvas *canvas = glist_getcanvas(h->h_glist);
     if (!h->h_vis) return;
-    gui_vmess("gui_iemgui_label_show_drag_handle", "xxiiii",
+    gui_vmess("gui_iemgui_label_show_drag_handle", "xxiiiii",
         h->h_glist, h->h_master, 0, 0, 0, h->h_scale);
     h->h_vis = 0;
 }
@@ -783,7 +786,10 @@ t_scalehandle *scalehandle_new(t_object *x, t_glist *glist, int scale,
     h->h_scale = scale;
     h->h_offset_x = 0;
     h->h_offset_y = 0;
+    h->h_adjust_x = 0;
+    h->h_adjust_y = 0;
     h->h_vis = 0;
+    h->h_constrain = 0;
     sprintf(h->h_pathname, ".x%lx.h%lx", (t_int)h->h_glist, (t_int)h);
     h->h_clickfn = chf;
     h->h_motionfn = mhf;
@@ -814,8 +820,10 @@ void scalehandle_dragon_label(t_scalehandle *h, float mouse_x, float mouse_y)
     if (h->h_dragon && !h->h_scale)
     {
         t_iemgui *x = (t_iemgui *)(h->h_master);
-        int dx = (int)mouse_x - (int)h->h_offset_x,
-            dy = (int)mouse_y - (int)h->h_offset_y;
+        int dx = (h->h_constrain == CURSOR_EDITMODE_RESIZE_Y) ? 0 :
+            (int)mouse_x - (int)h->h_offset_x,
+        dy = (h->h_constrain == CURSOR_EDITMODE_RESIZE_X) ? 0 :
+            (int)mouse_y - (int)h->h_offset_y;
         h->h_dragx = dx;
         h->h_dragy = dy;
 
@@ -841,6 +849,11 @@ void scalehandle_dragon_label(t_scalehandle *h, float mouse_x, float mouse_y)
                 x,
                 x->x_ldx,
                 x->x_ldy);
+            gui_vmess("gui_iemgui_label_displace_drag_handle", "xxii",
+                canvas,
+                x,
+                dx,
+                dy);
         }
     }
 }
@@ -914,15 +927,25 @@ void scalehandle_drag_scale(t_scalehandle *h) {
 static void scalehandle_clickhook(t_scalehandle *h, t_floatarg f,
     t_floatarg xxx, t_floatarg yyy)
 {
-    h->h_offset_x=xxx;
-    h->h_offset_y=yyy;
-    h->h_clickfn(h,f);
+    /* The label scalehandles do an end run around canvas_doclick,
+       which is where the cursor gets set. So we go ahead and set
+       the cursor here, too. "f" is our cursor number as defined
+       by the CURSOR_* macros in canvas.h */
+    canvas_setcursor(h->h_glist, (int)f);
+    /* We also go ahead and set h_constrain here so we don't have
+       to do it separately for each widget. Any widget that wants
+       to constrain movement along an axis can just check that
+       field against the CURSOR_* values in the motionhook callback. */
+    h->h_constrain = f;
+    h->h_offset_x = xxx;
+    h->h_offset_y = yyy;
+    h->h_clickfn(h, f);
 }
 
 static void scalehandle_motionhook(t_scalehandle *h,
     t_floatarg f1, t_floatarg f2)
 {
-    h->h_motionfn(h,f1,f2);
+    h->h_motionfn(h, f1, f2);
     // Now set the offset to the new mouse position
     h->h_offset_x = f1;
     h->h_offset_y = f2;
@@ -948,7 +971,8 @@ static void scalehandle_check_and_redraw(t_iemgui *x)
 //----------------------------------------------------------------
 // IEMGUI refactor (by Mathieu)
 
-void iemgui_tag_selected(t_iemgui *x) {
+void iemgui_tag_selected(t_iemgui *x)
+{
     t_canvas *canvas=glist_getcanvas(x->x_glist);
     if (x->x_selected)
         gui_vmess("gui_gobj_select", "xx", canvas, x);
@@ -956,7 +980,8 @@ void iemgui_tag_selected(t_iemgui *x) {
         gui_vmess("gui_gobj_deselect", "xx", canvas, x);
 }
 
-void iemgui_label_draw_new(t_iemgui *x) {
+void iemgui_label_draw_new(t_iemgui *x)
+{
     char col[8];
     t_canvas *canvas=glist_getcanvas(x->x_glist);
     int x1=text_xpix(&x->x_obj, x->x_glist)+x->legacy_x;
@@ -994,7 +1019,8 @@ void iemgui_label_draw_move(t_iemgui *x)
         x->x_ldy + x->legacy_y);
 }
 
-void iemgui_label_draw_config(t_iemgui *x) {
+void iemgui_label_draw_config(t_iemgui *x)
+{
     char col[8];
     t_canvas *canvas=glist_getcanvas(x->x_glist);
     if (x->x_selected == canvas && x->x_glist == canvas)
@@ -1036,14 +1062,15 @@ void iemgui_label_draw_config(t_iemgui *x) {
     if (x->x_selected == canvas && x->x_glist == canvas)
     {
         t_scalehandle *lh = (t_scalehandle *)(x->x_lhandle);
-        if (x->x_lab==s_empty)    
+        if (x->x_lab == s_empty)
             scalehandle_draw_erase(x->x_lhandle);
         else if (lh->h_vis == 0)
             scalehandle_draw_select(lh,x->x_ldx,x->x_ldy);
     }
 }
 
-void iemgui_label_draw_select(t_iemgui *x) {
+void iemgui_label_draw_select(t_iemgui *x)
+{
     t_canvas *canvas=glist_getcanvas(x->x_glist);
     if (x->x_selected == canvas && x->x_glist == canvas)
     {
@@ -1070,9 +1097,10 @@ void iemgui_draw_io(t_iemgui *x, int old_sr_flags)
     t_canvas *canvas=glist_getcanvas(x->x_glist);
     if (x->x_glist != canvas) return; // is gop
     t_class *c = pd_class((t_pd *)x);
-    if (c==my_numbox_class && ((t_my_numbox *)x)->x_hide_frame > 1) return; //sigh
-
-    if (!(old_sr_flags&4) && !glist_isvisible(canvas)) {
+    if (c == my_numbox_class && ((t_my_numbox *)x)->x_hide_frame > 1)
+        return; //sigh
+    if (!(old_sr_flags&4) && !glist_isvisible(canvas))
+    {
         return;
     }
     if (c==my_canvas_class) return;
@@ -1087,7 +1115,9 @@ void iemgui_draw_io(t_iemgui *x, int old_sr_flags)
         n = 0;
     int a=old_sr_flags&IEM_GUI_OLD_SND_FLAG;
     int b=x->x_snd!=s_empty;
-    //fprintf(stderr,"%lx SND: old_sr_flags=%d SND_FLAG=%d || OUTCOME: OLD_SND_FLAG=%d not_empty=%d\n", (t_int)x, old_sr_flags, IEM_GUI_OLD_SND_FLAG, a, b);
+    //fprintf(stderr, "%lx SND: old_sr_flags=%d SND_FLAG=%d || "
+    //                "OUTCOME: OLD_SND_FLAG=%d not_empty=%d\n",
+    //  (t_int)x, old_sr_flags, IEM_GUI_OLD_SND_FLAG, a, b);
     
     if (a && !b)
     {
@@ -1136,7 +1166,8 @@ void iemgui_draw_io(t_iemgui *x, int old_sr_flags)
     }
 }
 
-void iemgui_io_draw_move(t_iemgui *x) {
+void iemgui_io_draw_move(t_iemgui *x)
+{
     char tagbuf[MAXPDSTRING];
     t_canvas *canvas=glist_getcanvas(x->x_glist);
     t_class *c = pd_class((t_pd *)x);
@@ -1180,13 +1211,15 @@ void iemgui_io_draw_move(t_iemgui *x) {
     }
 }
 
-void iemgui_base_draw_new(t_iemgui *x) {
+void iemgui_base_draw_new(t_iemgui *x)
+{
     t_canvas *canvas=glist_getcanvas(x->x_glist);
     t_class *c = pd_class((t_pd *)x);
-    int x1,y1,x2,y2,gr=gop_redraw; gop_redraw=0;
-    c->c_wb->w_getrectfn((t_gobj *)x,x->x_glist,&x1,&y1,&x2,&y2);
+    int x1, y1, x2, y2, gr = gop_redraw;
+    gop_redraw = 0;
+    c->c_wb->w_getrectfn((t_gobj *)x, x->x_glist, &x1, &y1, &x2, &y2);
     //iemgui_getrect_draw(x, &x1, &y1, &x2, &y2); 
-    gop_redraw=gr;
+    gop_redraw = gr;
     char colorbuf[MAXPDSTRING];
     sprintf(colorbuf, "#%6.6x", x->x_bcol);
     gui_vmess("gui_gobj_new", "xxsiii", canvas, x,
@@ -1203,7 +1236,8 @@ void iemgui_base_draw_new(t_iemgui *x) {
         canvas, x, colorbuf);
 }
 
-void iemgui_base_draw_move(t_iemgui *x) {
+void iemgui_base_draw_move(t_iemgui *x)
+{
     t_canvas *canvas=glist_getcanvas(x->x_glist);
     t_class *c = pd_class((t_pd *)x);
     int x1,y1,x2,y2,gr=gop_redraw; gop_redraw=0;
@@ -1214,8 +1248,8 @@ void iemgui_base_draw_move(t_iemgui *x) {
         canvas, x, x1, y1, x2, y2);
 }
 
-void iemgui_base_draw_config(t_iemgui *x) {
-    
+void iemgui_base_draw_config(t_iemgui *x)
+{
     t_canvas *canvas=glist_getcanvas(x->x_glist);
     char fcol[8]; sprintf(fcol,"#%6.6x", x->x_fcol);
     char tagbuf[MAXPDSTRING];
@@ -1225,44 +1259,52 @@ void iemgui_base_draw_config(t_iemgui *x) {
         canvas, x, bcol); 
 }
 
-void iemgui_draw_update(t_iemgui *x, t_glist *glist) {
+void iemgui_draw_update(t_iemgui *x, t_glist *glist)
+{
     x->x_draw(x, x->x_glist, IEM_GUI_DRAW_MODE_UPDATE);
 }
 
-void iemgui_draw_new(t_iemgui *x) {
+void iemgui_draw_new(t_iemgui *x)
+{
     x->x_draw(x, x->x_glist, IEM_GUI_DRAW_MODE_NEW);
     iemgui_label_draw_new(x);
     iemgui_draw_io(x,7);
-    canvas_raise_all_cords(glist_getcanvas(x->x_glist)); // used to be inside x_draw
+    // used to be inside x_draw...
+    canvas_raise_all_cords(glist_getcanvas(x->x_glist));
 }
 
-void iemgui_draw_config(t_iemgui *x) {
+void iemgui_draw_config(t_iemgui *x)
+{
     x->x_draw(x, x->x_glist, IEM_GUI_DRAW_MODE_CONFIG);
     iemgui_label_draw_config(x);
     //iemgui_base_draw_config(x); // can't
 }
 
-void iemgui_draw_move(t_iemgui *x) {
+void iemgui_draw_move(t_iemgui *x)
+{
     x->x_draw(x, x->x_glist, IEM_GUI_DRAW_MODE_MOVE);
     iemgui_label_draw_move(x);
     //iemgui_base_draw_move(x); // can't
     iemgui_io_draw_move(x);
 }
 
-void iemgui_draw_erase(t_iemgui *x) {
+void iemgui_draw_erase(t_iemgui *x)
+{
     t_canvas *canvas=glist_getcanvas(x->x_glist);
     gui_vmess("gui_gobj_erase", "xx", canvas, x);
     scalehandle_draw_erase2(x);
 }
 
-void scrollbar_update(t_glist *glist) {
+void scrollbar_update(t_glist *glist)
+{
     //ico@bukvic.net 100518 update scrollbars when object potentially
     //exceeds window size
     t_canvas *canvas=(t_canvas *)glist_getcanvas(glist);
     canvas_getscroll(canvas);
 }
 
-void wb_init(t_widgetbehavior *wb, t_getrectfn gr, t_clickfn cl) {
+void wb_init(t_widgetbehavior *wb, t_getrectfn gr, t_clickfn cl)
+{
     wb->w_getrectfn = gr;
     wb->w_displacefn = iemgui_displace;
     wb->w_selectfn = iemgui_select;
@@ -1273,13 +1315,15 @@ void wb_init(t_widgetbehavior *wb, t_getrectfn gr, t_clickfn cl) {
     wb->w_displacefnwtag = iemgui_displace_withtag;
 }
 
-const char *iemgui_typeface(t_iemgui *x) {
+const char *iemgui_typeface(t_iemgui *x)
+{
     int f = x->x_font_style;
     if(f == 0) return sys_font;
     if(f == 1) return "helvetica";
     if(f == 2) return "times";
     return "invalid-font";
 }
+
 // this uses a static buffer, so don't use it twice in the same sys_vgui.
 // the static buffer could be replaced by a malloc when sys_vgui is replaced
 // by something that frees that memory.
@@ -1287,7 +1331,9 @@ const char *iemgui_typeface(t_iemgui *x) {
    separate arg so we don't have to parse on the gui side.
    Once we check to make sure all iemguis work without it we can safely
    remove it */
-const char *iemgui_font(t_iemgui *x) {
+
+const char *iemgui_font(t_iemgui *x)
+{
     static char buf[64];
     sprintf(buf, "{{%s} -%d %s}", iemgui_typeface(x), x->x_fontsize, sys_fontweight);
     return buf;
@@ -1295,7 +1341,8 @@ const char *iemgui_font(t_iemgui *x) {
 
 void iemgui_init(t_iemgui *x, t_floatarg f) {x->x_loadinit = f!=0.0;}
 
-void iemgui_class_addmethods(t_class *c) {
+void iemgui_class_addmethods(t_class *c)
+{
     class_addmethod(c, (t_method)iemgui_delta,
         gensym("delta"), A_GIMME, 0);
     class_addmethod(c, (t_method)iemgui_pos,
@@ -1314,7 +1361,8 @@ void iemgui_class_addmethods(t_class *c) {
         gensym("label_font"), A_GIMME, 0);
 }
 
-void g_iemgui_setup (void) {
+void g_iemgui_setup (void)
+{
     s_empty = gensym("empty");
     scalehandle_class = class_new(gensym("_scalehandle"), 0, 0,
                   sizeof(t_scalehandle), CLASS_PD, 0);
@@ -1330,16 +1378,21 @@ const char *border_color = "$pd_colors(iemgui_border)";
 #define GET_OUTLET t_outlet *out = x->x_obj.ob_outlet; /* can't use int o because there's not obj_nth_outlet function */
 #define SEND_BY_SYMBOL (iemgui_has_snd(x) && x->x_snd->s_thing && (!chk_putin || x->x_put_in2out))
 
-void iemgui_out_bang(t_iemgui *x, int o, int chk_putin) {
+void iemgui_out_bang(t_iemgui *x, int o, int chk_putin)
+{
     GET_OUTLET outlet_bang(out);
     if(SEND_BY_SYMBOL) pd_bang(x->x_snd->s_thing);
 }
-void iemgui_out_float(t_iemgui *x, int o, int chk_putin, t_float f) {
+
+void iemgui_out_float(t_iemgui *x, int o, int chk_putin, t_float f)
+{
     GET_OUTLET outlet_float(out,f);
     if(SEND_BY_SYMBOL) pd_float(x->x_snd->s_thing,f);
 }
-void iemgui_out_list(t_iemgui *x, int o, int chk_putin, t_symbol *s, int argc, t_atom *argv) {
-    GET_OUTLET outlet_list(out,s,argc,argv);
-    if(SEND_BY_SYMBOL) pd_list(x->x_snd->s_thing,s,argc,argv);
-}
 
+void iemgui_out_list(t_iemgui *x, int o, int chk_putin, t_symbol *s,
+    int argc, t_atom *argv)
+{
+    GET_OUTLET outlet_list(out, s, argc, argv);
+    if (SEND_BY_SYMBOL) pd_list(x->x_snd->s_thing, s, argc, argv);
+}
diff --git a/pd/src/g_all_guis.h b/pd/src/g_all_guis.h
index 81549d3e194f97f19ae2c3c3e0fc3ffd134f3dfc..a9d6768a01fd1c9b5504d2ffa4fd38840f53097a 100644
--- a/pd/src/g_all_guis.h
+++ b/pd/src/g_all_guis.h
@@ -27,10 +27,10 @@
 #define SCALE_NUM_MINHEIGHT 8
 #define SCALE_GOP_MINWIDTH 12
 #define SCALE_GOP_MINHEIGHT 12
-#define SCALEHANDLE_WIDTH   5
-#define SCALEHANDLE_HEIGHT  5
-#define LABELHANDLE_WIDTH   5
-#define LABELHANDLE_HEIGHT  5
+#define SCALEHANDLE_WIDTH   14
+#define SCALEHANDLE_HEIGHT  14
+#define LABELHANDLE_WIDTH   14
+#define LABELHANDLE_HEIGHT  14
 
 typedef void (*t_iemfunptr)(void *x, t_glist *glist, int mode);
 
@@ -46,7 +46,7 @@ typedef struct _scalehandle
     t_object  *h_master;
     t_glist   *h_glist; // this is the canvas to draw on. Note that when objects are edited, "glist" and "canvas" mean the same.
     t_symbol  *h_bindsym;
-    int        h_scale; // bool
+    int        h_scale;
     char       h_pathname[37]; // max size for ".x%lx.h%lx" = 5+4*sizeof(long)
     char       h_outlinetag[18]; // max size for "h%lx" = 2+2*sizeof(long)
     int        h_dragon; // bool
@@ -54,6 +54,9 @@ typedef struct _scalehandle
     int        h_dragy;
     int        h_offset_x;
     int        h_offset_y;
+    int        h_adjust_x;
+    int        h_adjust_y;
+    int        h_constrain;
     int        h_vis; // bool
     t_clickhandlefn h_clickfn;
     t_motionhandlefn h_motionfn;
diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c
index 47b5ebfcd446dca1ebdeea6dff22508db1ee8c5b..00cb8c93d8fec11e10074c66682756c512f6bdba 100644
--- a/pd/src/g_canvas.c
+++ b/pd/src/g_canvas.c
@@ -340,6 +340,10 @@ void linetraverser_skipobject(t_linetraverser *t)
 /* -------------------- the canvas object -------------------------- */
 int glist_valid = 10000;
 
+void canvasgop__clickhook(t_scalehandle *sh, int newstate);
+void canvasgop__motionhook(t_scalehandle *sh,t_floatarg f1, t_floatarg f2);
+extern void glist_setlastxy(t_glist *gl, int xval, int yval);
+
 void glist_init(t_glist *x)
 {
         /* zero out everyone except "pd" field */
@@ -348,11 +352,13 @@ void glist_init(t_glist *x)
     x->gl_valid = ++glist_valid;
     x->gl_xlabel = (t_symbol **)t_getbytes(0);
     x->gl_ylabel = (t_symbol **)t_getbytes(0);
-}
 
-void canvasgop__clickhook(t_scalehandle *sh, int newstate);
-void canvasgop__motionhook(t_scalehandle *sh,t_floatarg f1, t_floatarg f2);
-extern void glist_setlastxy(t_glist *gl, int xval, int yval);
+    //dpsaha@vt.edu gop resize (refactored by mathieu)
+    x->x_handle = scalehandle_new((t_object *)x, x, 1,
+        canvasgop__clickhook, canvasgop__motionhook);
+    x->x_mhandle = scalehandle_new((t_object *)x, x, 0,
+        canvasgop__clickhook, canvasgop__motionhook);
+}
 
 /* These globals are used to set state for the "canvas" field in a
    struct. We try below to make sure they only get set for the toplevel
@@ -488,10 +494,6 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv)
     x->gl_zoom = zoom;
     pd_pushsym(&x->gl_pd);
 
-    //dpsaha@vt.edu gop resize (refactored by mathieu)
-    x-> x_handle = scalehandle_new((t_object *)x,x,1,canvasgop__clickhook,canvasgop__motionhook);
-    x->x_mhandle = scalehandle_new((t_object *)x,x,0,canvasgop__clickhook,canvasgop__motionhook);
-
     x->u_queue = canvas_undo_init(x);
     //glist_setlastxy(x, 20, 20);
 
@@ -985,7 +987,7 @@ void canvas_free(t_canvas *x)
     if (x->gl_editor)
         canvas_destroy_editor(x);   /* bug workaround; should already be gone*/
 
-    if (x-> x_handle) scalehandle_free( x->x_handle);
+    if (x->x_handle) scalehandle_free(x->x_handle);
     if (x->x_mhandle) scalehandle_free(x->x_mhandle);
     
     canvas_unbind(x);
@@ -2318,108 +2320,50 @@ void canvasgop_checksize(t_canvas *x)
 void canvasgop__clickhook(t_scalehandle *sh, int newstate)
 {
     t_canvas *x = (t_canvas *)(sh->h_master);
-    if (sh->h_dragon && newstate == 0)
-    {
-        /* done dragging */
-        if(sh->h_scale) //enter if resize_gop hook
-        {
-            canvas_undo_add(x, 8, "apply", canvas_undo_set_canvas(x));
 
-            if (sh->h_dragx || sh->h_dragy) 
-            {
-                x->gl_pixwidth += sh->h_dragx;
-                x->gl_pixheight += sh->h_dragy;
-                // check if the text is not hidden. if so, make minimum
-                // width and height based retrieved from getrect.
-                if (!x->gl_hidetext)
-                {
-                    int x1=0, y1=0, x2=0, y2=0;
-                    if (x->gl_owner)
-                    {
-                        gobj_getrect((t_gobj*)x, x->gl_owner,
-                            &x1, &y1, &x2, &y2);
-                    }
-                    else
-                    {
-                        graph_checkgop_rect((t_gobj*)x, x, &x1, &y1, &x2, &y2);
-                    }
-                    if (x2-x1 > x->gl_pixwidth) x->gl_pixwidth = x2-x1;
-                    if (y2-y1 > x->gl_pixheight) x->gl_pixheight = y2-y1;
-                }
-                canvas_dirty(x, 1);
-            }
-
-            // can't remove this update because the text size check above is not in motionhook
-            int properties = gfxstub_haveproperties((void *)x);
-            if (properties)
-            {
-                properties_set_field_int(properties,"x_pix",x->gl_pixwidth);
-                properties_set_field_int(properties,"y_pix",x->gl_pixheight);
-            }
+    /* So ugly: if the user is dragging the bottom right-hand corner of
+       a gop subcanvas on the parent, we already set an undo event for it.
+       So we only add one here for resizing the gop red rectangle, or for
+       moving it with the red scalehandle. */
+    if (sh->h_scale != 1)
+        canvas_undo_add(x, 8, "apply", canvas_undo_set_canvas(x));
 
-            if (glist_isvisible(x))
-            {
-                /* Still not sure what this is doing... */
-                //sys_vgui(".x%x.c delete %s\n", x, sh->h_outlinetag);
-                canvasgop_draw_move(x,1);
-                canvas_fixlinesfor(x, (t_text *)x);
-                scrollbar_update(x);
-            }
-        }
-        else //enter if move_gop hook
-        {
-            // this block is similar to scalehandle_unclick_label but not enough
-            // We've actually removed scalehandle_unclick_label everywhere, so
-            // check to see whether this can be removed as well...
-            canvas_undo_add(x, 8, "apply", canvas_undo_set_canvas(x));
-            if (sh->h_dragx || sh->h_dragy) 
-            {
-                x->gl_xmargin += sh->h_dragx;
-                x->gl_ymargin += sh->h_dragy;
-                canvas_dirty(x, 1);
-            }
-            if (glist_isvisible(x))
-            {
-                canvasgop_draw_move(x,1);
-                canvas_fixlinesfor(x, (t_text *)x);
-                scrollbar_update(x);
-            }
-        }
+    /* We're abusing h_scale to differentiate between clicking gop red
+       rectangle and clicking the corner of a subcanvas on the parent */
+    if (sh->h_scale == 1) /* clicking corner of gop subcanvas on parent */
+    {
+        /* This is for clicking on the bottom right-hand corner of the
+           gop canvas when it's displayed on the parent canvas. */
+        sh->h_adjust_x = sh->h_offset_x -
+            (((t_object *)x)->te_xpix + x->gl_pixwidth);
+        sh->h_adjust_y = sh->h_offset_y -
+            (((t_object *)x)->te_ypix + x->gl_pixheight);
     }
-    else if (!sh->h_dragon && newstate)
+    else if (sh->h_scale == 2) /* resize gop hook for (red) gop rect */
     {
-        /* set undo */
-        canvas_undo_add(x, 8, "apply", canvas_undo_set_canvas(x));
+        /* Store an adjustment for difference between the initial
+           pointer position-- which is within five pixels or so-- and the
+           bottom right-hand corner. Otherwise we'd get a "jump" from the
+           the current dimensions to the pointer offset. Such a jump would
+           become noticeable with constrained dragging, as the constrained
+           dimension would initially jump to the pointer position.
 
-        if(sh->h_scale) //enter if resize_gop hook
-        {
-            /* We could port this, but it might be better to wait until we
-               just move the scalehandle stuff directly to the GUI... */
-            //sys_vgui("lower %s\n", sh->h_pathname);
-
-            //delete GOP rect where it started from
-            /* Doesn't look like we're using this anymore, so no need to
-               port it. */
-            //sys_vgui(".x%lx.c delete GOP\n", x);
-            //sys_vgui(".x%x.c create rectangle %d %d %d %d "
-            //     "-outline $pd_colors(selection) -width 1 -tags %s\n",
-            //     x, x->gl_xmargin, x->gl_ymargin,
-            //        x->gl_xmargin + x->gl_pixwidth,
-            //        x->gl_ymargin + x->gl_pixheight, sh->h_outlinetag);
-        }
-        else //enter if move_gop hook
-        {
-            //scalehandle_draw_erase(sh,x);
-            /* Same as above... */
-            //sys_vgui("lower %s\n", sh->h_pathname);
+           We could alternatively use dx/dy, but then the pointer position
+           would stray when the user attempts to drag past the minimum
+           width/height of the rectangle. */
 
-            //delete GOP_resblob when moving the whole GOP
-            //sys_vgui(".x%lx.c delete %lxSCALE\n", x, x);
-        }
-        sh->h_dragx = 0;
-        sh->h_dragy = 0;
+        sh->h_adjust_x = sh->h_offset_x - (x->gl_xmargin + x->gl_pixwidth);
+        sh->h_adjust_y = sh->h_offset_y - (x->gl_ymargin + x->gl_pixheight);
+
+        /* We could port this, but it might be better to wait until we
+           just move the scalehandle stuff directly to the GUI... */
+        //sys_vgui("lower %s\n", sh->h_pathname);
+    }
+    else /* move_gop hook */
+    {
+        /* Same as above... */
+        //sys_vgui("lower %s\n", sh->h_pathname);
     }
-    sh->h_dragon = newstate;
 }
 
 void canvasgop__motionhook(t_scalehandle *sh, t_floatarg mouse_x,
@@ -2428,51 +2372,111 @@ void canvasgop__motionhook(t_scalehandle *sh, t_floatarg mouse_x,
     t_canvas *x = (t_canvas *)(sh->h_master);
     int dx = (int)mouse_x - sh->h_offset_x,
         dy = (int)mouse_y - sh->h_offset_y;
-    
-    if (sh->h_dragon)
-    {
-        if (sh->h_scale) //enter if resize_gop hook
+
+    if (sh->h_scale == 1) /* resize the gop on the parent */
+    {
+        int tmpx1 = 0, tmpy1 = 0, tmpx2 = 0, tmpy2 = 0;
+        int tmp_x_final = 0, tmp_y_final = 0;
+        /* The member h_glist currently points our current glist x. I think
+           that is being used to draw the gop red rect move anchor atm. So
+           rather than muck around with that code, we just set a pointer to
+           whatever our toplevel is here: */
+        t_glist *owner = canvas_getrootfor(x);
+        /* Just unvis the object, then vis it once we've done our
+           mutation and checks */
+        gobj_vis((t_gobj *)x, owner, 0);
+        /* struct _glist has its own member e_xnew for storing our offset.
+           At some point we need to refactor since our t_scalehandle has
+           members for storing offsets already. */
+        x->gl_pixwidth = (sh->h_constrain == CURSOR_EDITMODE_RESIZE_Y) ?
+            x->gl_pixwidth :
+            (int)mouse_x - ((t_object *)x)->te_xpix - sh->h_adjust_x;
+        x->gl_pixheight = (sh->h_constrain == CURSOR_EDITMODE_RESIZE_X) ?
+            x->gl_pixheight :
+            (int)mouse_y - ((t_object *)x)->te_ypix - sh->h_adjust_y;
+        /* If the box text is not hidden then it sets a lower boundary for
+           box size... */
+        graph_checkgop_rect((t_gobj *)x, owner, &tmpx1, &tmpy1, &tmpx2,
+            &tmpy2);
+        tmpx1 = ((t_object *)x)->te_xpix;
+        tmpy1 = ((t_object *)x)->te_ypix;
+        //fprintf(stderr,"%d %d %d %d\n", tmpx1, tmpy1, tmpx2, tmpy2);
+        if (!x->gl_hidetext)
         {
-            int width = mouse_x - x->gl_xmargin,
-                height = mouse_y - x->gl_ymargin;
-            x->gl_pixwidth = width = maxi(SCALE_GOP_MINWIDTH, width);
-            x->gl_pixheight = height = maxi(SCALE_GOP_MINHEIGHT, height);
-            gui_vmess("gui_canvas_redrect_coords", "xiiii",
-                x,
-                x->gl_xmargin,
-                x->gl_ymargin,
-                x->gl_xmargin + width,
-                x->gl_ymargin + height);
-            int properties = gfxstub_haveproperties((void *)x);
-            if (properties)
-            {
-                properties_set_field_int(properties,
-                    "x_pix",x->gl_pixwidth + sh->h_dragx);
-                properties_set_field_int(properties,
-                    "y_pix",x->gl_pixheight + sh->h_dragy);
-            }
+            tmp_x_final = tmpx2 - tmpx1;
+            tmp_y_final = tmpy2 - tmpy1;
         }
-        else //enter if move_gop hook
+        else
         {
-            int properties = gfxstub_haveproperties((void *)x);
-            if (properties)
-            {
-                properties_set_field_int(properties,
-                    "x_margin",x->gl_xmargin + dx);
+            tmp_x_final = tmpx2;
+            tmp_y_final = tmpy2;
+        }
+        if (tmp_x_final > x->gl_pixwidth)
+            x->gl_pixwidth = tmp_x_final;
+        if (tmp_y_final > x->gl_pixheight)
+            x->gl_pixheight = tmp_y_final;
+        owner->gl_editor->e_xnew = mouse_x;
+        owner->gl_editor->e_ynew = mouse_y;
+        canvas_fixlinesfor(owner, (t_text *)x);
+        gobj_vis((t_gobj *)x, owner, 1);
+        canvas_dirty(owner, 1);
+
+        int properties = gfxstub_haveproperties((void *)x);
+        if (properties)
+        {
+            properties_set_field_int(properties,
+                "x_pix",x->gl_pixwidth + sh->h_dragx);
+            properties_set_field_int(properties,
+                "y_pix",x->gl_pixheight + sh->h_dragy);
+        }
+    }
+    else if (sh->h_scale == 2) /* resize_gop red rect hook */
+    {
+        int width = (sh->h_constrain == CURSOR_EDITMODE_RESIZE_Y) ?
+            x->gl_pixwidth :
+            (int)mouse_x - x->gl_xmargin - sh->h_adjust_x;
+        int height = (sh->h_constrain == CURSOR_EDITMODE_RESIZE_X) ?
+            x->gl_pixheight :
+            (int)mouse_y - x->gl_ymargin - sh->h_adjust_y;
+        x->gl_pixwidth = width = maxi(SCALE_GOP_MINWIDTH, width);
+        x->gl_pixheight = height = maxi(SCALE_GOP_MINHEIGHT, height);
+        gui_vmess("gui_canvas_redrect_coords", "xiiii",
+            x,
+            x->gl_xmargin,
+            x->gl_ymargin,
+            x->gl_xmargin + width,
+            x->gl_ymargin + height);
+        int properties = gfxstub_haveproperties((void *)x);
+        if (properties)
+        {
+            properties_set_field_int(properties,
+                "x_pix",x->gl_pixwidth + sh->h_dragx);
+            properties_set_field_int(properties,
+                "y_pix",x->gl_pixheight + sh->h_dragy);
+        }
+    }
+    else /* move_gop hook */
+    {
+        int properties = gfxstub_haveproperties((void *)x);
+        if (properties)
+        {
+            properties_set_field_int(properties,
+                "x_margin",x->gl_xmargin + dx);
                 properties_set_field_int(properties,
-                    "y_margin",x->gl_ymargin + dy);
-            }
+                "y_margin",x->gl_ymargin + dy);
+        }
+        if (sh->h_constrain != CURSOR_EDITMODE_RESIZE_Y)
             x->gl_xmargin += dx;
+        if (sh->h_constrain != CURSOR_EDITMODE_RESIZE_X)
             x->gl_ymargin += dy;
 
-            int x1 = x->gl_xmargin, x2 = x1+x->gl_pixwidth;
-            int y1 = x->gl_ymargin, y2 = y1+x->gl_pixheight;
+        int x1 = x->gl_xmargin, x2 = x1 + x->gl_pixwidth;
+        int y1 = x->gl_ymargin, y2 = y1 + x->gl_pixheight;
 
-            gui_vmess("gui_canvas_redrect_coords", "xiiii",
-                x, x1, y1, x2, y2);
-            sh->h_dragx = dx;
-            sh->h_dragy = dy;            
-        }
+        gui_vmess("gui_canvas_redrect_coords", "xiiii",
+            x, x1, y1, x2, y2);
+        sh->h_dragx = dx;
+        sh->h_dragy = dy;
     }
 }
 
diff --git a/pd/src/g_canvas.h b/pd/src/g_canvas.h
index a08ef13d6376186e2b7338957fa1219b352b35f2..3393d8017b9818df87611822609fd7262cf03a95 100644
--- a/pd/src/g_canvas.h
+++ b/pd/src/g_canvas.h
@@ -403,9 +403,11 @@ struct _parentwidgetbehavior
 #define CURSOR_EDITMODE_NOTHING 4
 #define CURSOR_EDITMODE_CONNECT 5
 #define CURSOR_EDITMODE_DISCONNECT 6
-#define CURSOR_EDITMODE_RESIZE 7
-#define CURSOR_EDITMODE_RESIZE_BOTTOM_RIGHT 8
+#define CURSOR_EDITMODE_RESIZE_X 7
+#define CURSOR_EDITMODE_RESIZE 8
 #define CURSOR_SCROLL 9
+#define CURSOR_EDITMODE_RESIZE_Y 10
+#define CURSOR_EDITMODE_MOVE 11
 EXTERN void canvas_setcursor(t_glist *x, unsigned int cursornum);
 
 extern t_canvas *canvas_editing;    /* last canvas to start text edting */ 
diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c
index 1dbcad0b6468e50b2e63b971aff515a98fedf5af..f22c8db010dd58218c0c27cd1ad7d05c07d5891b 100644
--- a/pd/src/g_editor.c
+++ b/pd/src/g_editor.c
@@ -2190,7 +2190,9 @@ static char *cursorlist[] = {
     "cursor_editmode_disconnect",
     "cursor_editmode_resize",
     "cursor_editmode_resize_bottom_right",
-    "cursor_scroll"
+    "cursor_scroll",
+    "cursor_editmode_resize_vert",
+    "cursor_editmode_move"
 };
 
 void canvas_setcursor(t_canvas *x, unsigned int cursornum)
@@ -3128,6 +3130,69 @@ void canvas_done_popup(t_canvas *x, t_float which, t_float xpos,
         open_via_helppath("intro.pd", canvas_getdir((t_canvas *)x)->s_name);
 }
 
+extern t_class *my_canvas_class; // for ignoring runtime clicks and resizing
+
+/* For triggering text_widgetbehavior objects, graphs, atom/dropdown, iemgui and
+   comment resizing */
+static int text_resizing_hotspot(t_canvas *x, t_object *ob, int xpos, int ypos,
+    int x1, int y1, int x2, int y2, int *typep)
+{
+    /* No resizing anchor in k12 mode, plus sanity checks */
+    if (sys_k12_mode || !ob || x->gl_editor->e_textedfor || xpos > x2 ||
+        ypos > y2)
+        return 0;
+    *typep = 0;
+        /* objects that can only be resized along x-axis: regular text
+           objects, atom boxes, and canvas without gop checked */
+    if (ob->te_pd->c_wb == &text_widgetbehavior ||
+        ob->te_type == T_ATOM ||
+        (ob->ob_pd == canvas_class && !((t_canvas *)ob)->gl_isgraph))
+    {
+        if (xpos >= x2 - 4 && ypos < y2 - 4 && ypos > y1 + 4)
+        {
+            *typep = 1;
+            return CURSOR_EDITMODE_RESIZE_X;
+        }
+    }
+
+        /* gop canvases, gop red rectangle, scope, grid, iemguis except [cnv] */
+    if ((ob->te_iemgui && ob->ob_pd != my_canvas_class) ||
+        ob->ob_pd == canvas_class ||
+        ob->ob_pd->c_name == gensym("Scope~") ||
+        ob->ob_pd->c_name == gensym("grid"))
+    {
+            /* stay out of the way of outlet in the bottom right-hand corner */
+        int offset = (obj_noutlets(ob) > 1) ? -4 : 0;
+            /* We want to disable horiz and vert anchors for [bng], [tgl],
+               [hradio] and [vradio]. These widgets only have one
+               dimension that can be resized-- the other is handled
+               automatically. */
+        int can_resize_x = (ob->ob_pd->c_name != gensym("bng") &&
+            ob->ob_pd->c_name != gensym("tgl") &&
+            ob->ob_pd->c_name != gensym("hradio") &&
+            ob->ob_pd->c_name != gensym("vradio"));
+
+        int can_resize_y = can_resize_x &&
+            (ob->ob_pd->c_name != gensym("vsl") || x2 - x1 > 15) &&
+            (ob->ob_pd->c_name != gensym("hsl") || x2 - x1 > 15);
+
+        if (can_resize_x &&
+            xpos >= x2 - 4 && ypos <= y2 + offset - 10 && ypos > y2 + offset - 24)
+            return CURSOR_EDITMODE_RESIZE_X;
+        else if (xpos >= x2 - 4 && ypos <= y2 + offset && ypos > y2 + offset - 10)
+            return CURSOR_EDITMODE_RESIZE;
+        else if (can_resize_y &&
+                 xpos >= x2 - 12 &&
+                 ypos >= y2 + offset - 5 &&
+                 ypos <= y2 + offset)
+            return CURSOR_EDITMODE_RESIZE_Y;
+        else
+            return 0;
+    }
+    else
+        return 0;
+}
+
 #define NOMOD 0
 #define SHIFTMOD 1
 #define CTRLMOD 2
@@ -3138,8 +3203,6 @@ static double canvas_upclicktime;
 static int canvas_upx, canvas_upy;
 #define DCLICKINTERVAL 0.25
 
-extern t_class *my_canvas_class; // for ignoring runtime clicks
-
     /* mouse click */
 void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
     int mod, int doit)
@@ -3151,7 +3214,8 @@ void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
     array_garray = NULL;
 
     t_gobj *y;
-    int shiftmod, runmode, altmod, doublemod = 0, rightclick;
+    int shiftmod, runmode, altmod, doublemod = 0, rightclick,
+        in_text_resizing_hotspot, default_type;
     int x1=0, y1=0, x2=0, y2=0, clickreturned = 0;
     t_gobj *yclick = NULL;
     t_object *ob;
@@ -3282,14 +3346,34 @@ void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
         }
         return;
     }
+
         /* if in editmode click, fall here. */
-    if (y = canvas_findhitbox(x, xpos, ypos, &x1, &y1, &x2, &y2))
+        /* check you're in the rectangle */
+    y = canvas_findhitbox(x, xpos, ypos, &x1, &y1, &x2, &y2);
+        /* We've got a special case for handling the gop red rectangle. In that
+           case we want all other click actions to take precedence, so we run
+           the checks here first so we can keep the same conditional ordering
+           we've had for ages. */
+    if (y)
     {
-            /* check you're in the rectangle */
         ob = pd_checkobject(&y->g_pd);
+        in_text_resizing_hotspot = text_resizing_hotspot(x, ob, xpos, ypos,
+            x1, y1, x2, y2, &default_type);
+    }
+    else
+    {
+        in_text_resizing_hotspot = text_resizing_hotspot(x, &x->gl_obj,
+            xpos, ypos, x->gl_xmargin, x->gl_ymargin,
+            x->gl_xmargin + x->gl_pixwidth,
+            x->gl_ymargin + x->gl_pixheight, &default_type);
+    }
+
+    if (y)
+    {
         if (rightclick)
             canvas_rightclick(x, xpos, ypos, y);
-        else if (shiftmod && x->gl_editor->canvas_cnct_outlet_tag[0] == 0)
+        else if (shiftmod &&
+            x->gl_editor->canvas_cnct_outlet_tag[0] == 0)
         {
             //selection (only if we are not hovering above an outlet)
             if (doit)
@@ -3332,74 +3416,64 @@ void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
                    extends well past the bounds of the bbox. For that reason
                    we have a virtual waterfall of conditionals flowing all
                    the way to the GUI just handle resizing a stupid rectangle.
-
-                   Also, the following conditional is way too complex.
                 */
-            if (ob && (ob->te_iemgui
-                 && pd_class((t_pd *)ob) != my_canvas_class
-                 || pd_class(&ob->te_pd)->c_name == gensym("Scope~")
-                 || pd_class(&ob->te_pd)->c_name == gensym("grid"))
-                && xpos >= x2-4 && ypos > y2-6)
+            if (in_text_resizing_hotspot)
             {
                 if (doit)
                 {
-                    x->gl_editor->e_onmotion = MA_RESIZE;
-                    x->gl_editor->e_xwas = x1;
-                    x->gl_editor->e_ywas = y1;
-                    x->gl_editor->e_xnew = xpos;
-                    x->gl_editor->e_ynew = ypos;
-                    if (ob->te_iemgui)
-                    {
-                        t_pd *sh = (t_pd *)((t_iemgui *)ob)->x_handle;
-                        pd_vmess(sh, gensym("_click"), "fff",
-                            (t_float)1, (t_float)xpos, (t_float)ypos);
-                    }
-                    else
-                    {
-                        pd_vmess((t_pd *)ob, gensym("_click_for_resizing"),
-                           "fff", (t_float)1, (t_float)xpos, (t_float)ypos);
-                    }
-                }
-                else
-                {
-                    canvas_setcursor(x,
-                        CURSOR_EDITMODE_RESIZE_BOTTOM_RIGHT);
-                }
-                canvas_check_nlet_highlights(x);
-            }
-            else if (!sys_k12_mode && ob && !x->gl_editor->e_textedfor &&
-                (ob->te_pd->c_wb == &text_widgetbehavior ||
-                 ob->te_type == T_ATOM ||
-                 ob->ob_pd == canvas_class) &&
-                 xpos >= x2-4 && ypos < y2-4 && ypos > y1+4)
-            {
-                if (doit)
-                {
-                    if (!glist_isselected(x, y) || x->gl_editor->e_selection->sel_next)
+                    if (!glist_isselected(x, y) ||
+                        x->gl_editor->e_selection->sel_next)
                     {
                         glist_noselect(x);
                         glist_select(x, y);
                     }
+
                     x->gl_editor->e_onmotion = MA_RESIZE;
                     x->gl_editor->e_xwas = x1;
                     x->gl_editor->e_ywas = y1;
                     x->gl_editor->e_xnew = xpos;
                     x->gl_editor->e_ynew = ypos;
-                    canvas_undo_add(x, 6, "resize",
-                        canvas_undo_set_apply(x, glist_getindex(x, y)));
-                }                                   
-                else
-                {
-                    if (ob->ob_pd != canvas_class ||
-                        !((t_canvas *)ob)->gl_isgraph)
+                    /* For normal text objects/atom boxes, subpatches and
+                       graphs we just go ahead and set an undo point here.
+                       GUI objects have their own click callback where they
+                       do this. */
+                    int isgraph = (ob->ob_pd == canvas_class &&
+                        ((t_canvas *)ob)->gl_isgraph);
+
+                    if (default_type || isgraph)
+                        canvas_undo_add(x, 6, "resize",
+                            canvas_undo_set_apply(x, glist_getindex(x, y)));
+
+                    /* Scalehandle callbacks */
+                    if (isgraph)
                     {
-                        canvas_setcursor(x, CURSOR_EDITMODE_RESIZE);
+                        t_scalehandle *sh = ((t_canvas *)ob)->x_handle;
+                        /* Special case: we're abusing the value of h_scale
+                           to differentiate between this case and the case
+                           of clicking the red gop rectangle. */
+                        sh->h_scale = 1;
+                        pd_vmess(&sh->h_pd, gensym("_click"), "fff",
+                            (t_float)in_text_resizing_hotspot,
+                            (t_float)xpos, (t_float)ypos);
                     }
-                    else
+                    else if (ob->te_iemgui)
                     {
-                        canvas_setcursor(x,
-                            CURSOR_EDITMODE_RESIZE_BOTTOM_RIGHT);
+                        t_scalehandle *sh = ((t_iemgui *)ob)->x_handle;
+                        pd_vmess(&sh->h_pd, gensym("_click"), "fff",
+                            (t_float)in_text_resizing_hotspot,
+                            (t_float)xpos, (t_float)ypos);
                     }
+                    else if (!default_type)
+                    {
+                        /* Scope~ and grid */
+                        pd_vmess(&ob->ob_pd, gensym("_click_for_resizing"),
+                           "fff", (t_float)in_text_resizing_hotspot,
+                           (t_float)xpos, (t_float)ypos);
+                    }
+                }
+                else
+                {
+                    canvas_setcursor(x, in_text_resizing_hotspot);
                     canvas_check_nlet_highlights(x);
                 }
             }
@@ -3616,13 +3690,9 @@ void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
             // end jsarlo
         }
         return;
-    } else if (x->gl_isgraph && x->gl_goprect &&
-               xpos <= x->gl_xmargin + x->gl_pixwidth + 4 &&
-               xpos >= x->gl_xmargin + x->gl_pixwidth - 2 &&
-               ypos <= x->gl_ymargin + x->gl_pixheight + 4 &&
-               ypos > x->gl_ymargin + x->gl_pixheight - 2)
+    }
+    else if (in_text_resizing_hotspot) /* red gop rectangle */
     {
-        // refactor the if into a function call...
         if (doit)
         {
             x->gl_editor->e_onmotion = MA_RESIZE;
@@ -3630,14 +3700,18 @@ void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
             x->gl_editor->e_ywas = y1;
             x->gl_editor->e_xnew = xpos;
             x->gl_editor->e_ynew = ypos;
-            t_pd *sh = (t_pd *)x->x_handle; // scale handle
+            t_pd *sh = (t_pd *)((t_canvas *)x)->x_handle; // scale handle
+            /* Special case-- we abuse the value of h_scale to differentiate
+               between clicking the corner of a subcanvas and resizing a
+               red gop rectangle. */
+            ((t_scalehandle *)sh)->h_scale = 2;
             pd_vmess(sh, gensym("_click"), "fff",
-                (t_float)1, (t_float)xpos, (t_float)ypos);
+                (t_float)in_text_resizing_hotspot, (t_float)xpos,
+                (t_float)ypos);
         }
         else
         {
-            canvas_setcursor(x,
-                CURSOR_EDITMODE_RESIZE_BOTTOM_RIGHT);
+            canvas_setcursor(x, in_text_resizing_hotspot);
         }
         canvas_check_nlet_highlights(x);
         return;
@@ -5192,7 +5266,7 @@ void canvas_key(t_canvas *x, t_symbol *s, int ac, t_atom *av)
     pd_vmess(&x->gl_pd, gensym("motion"), "fff",
         (double)canvas_last_glist_x,
         (double)canvas_last_glist_y,
-        (double)(glob_shift+glob_ctrl*2+glob_alt*4));
+        (double)(glob_shift + glob_ctrl * 2 + glob_alt * 4));
 }
 
 extern void graph_checkgop_rect(t_gobj *z, t_glist *glist,
@@ -5293,35 +5367,9 @@ void canvas_motion(t_canvas *x, t_floatarg xpos, t_floatarg ypos,
             }
             else if (ob && ob->ob_pd == canvas_class)
             {
-                int tmpx1 = 0, tmpy1 = 0, tmpx2 = 0, tmpy2 = 0;
-                int tmp_x_final = 0, tmp_y_final = 0;
-                gobj_vis(y1, x, 0);
-                ((t_canvas *)ob)->gl_pixwidth += xpos - x->gl_editor->e_xnew;
-                ((t_canvas *)ob)->gl_pixheight += ypos - x->gl_editor->e_ynew;
-                graph_checkgop_rect((t_gobj *)ob, x, &tmpx1, &tmpy1, &tmpx2,
-                    &tmpy2);
-                tmpx1 = ob->te_xpix;
-                tmpy1 = ob->te_ypix;
-                //fprintf(stderr,"%d %d %d %d\n", tmpx1, tmpy1, tmpx2, tmpy2);
-                if (!((t_canvas *)ob)->gl_hidetext)
-                {
-                    tmp_x_final = tmpx2 - tmpx1;
-                    tmp_y_final    = tmpy2 - tmpy1;
-                }
-                else
-                {
-                    tmp_x_final = tmpx2;
-                    tmp_y_final = tmpy2;
-                }
-                if (tmp_x_final > ((t_canvas *)ob)->gl_pixwidth)
-                    ((t_canvas *)ob)->gl_pixwidth = tmp_x_final;
-                if (tmp_y_final > ((t_canvas *)ob)->gl_pixheight)
-                    ((t_canvas *)ob)->gl_pixheight = tmp_y_final;
-                x->gl_editor->e_xnew = xpos;
-                x->gl_editor->e_ynew = ypos;
-                canvas_fixlinesfor(x, ob);
-                gobj_vis(y1, x, 1);
-                canvas_dirty(x, 1);
+                t_pd *sh = (t_pd *)((t_canvas *)ob)->x_handle;
+                pd_vmess(sh, gensym("_motion"), "ff", (t_float)xpos,
+                    (t_float)ypos);
             }
             else if (ob && ob->te_iemgui)
             {
diff --git a/pd/src/g_mycanvas.c b/pd/src/g_mycanvas.c
index d33cb46edb3a060e810644b868d4e71d685cc435..16acb2533a14793b12c55cb79956f9b5dcf33ae8 100644
--- a/pd/src/g_mycanvas.c
+++ b/pd/src/g_mycanvas.c
@@ -69,6 +69,15 @@ static void my_canvas__clickhook(t_scalehandle *sh, int newstate)
         if (!sh->h_scale)
             scalehandle_click_label(sh);
     }
+    if (sh->h_scale)
+    {
+        sh->h_adjust_x = sh->h_offset_x -
+            (((t_object *)x)->te_xpix + x->x_vis_w);
+        sh->h_adjust_y = sh->h_offset_y -
+            (((t_object *)x)->te_ypix + x->x_vis_h);
+        /* Hack to set the cursor since we're doing and end-run
+           around canas_doclick here */
+    }
     sh->h_dragon = newstate;
 }
 
@@ -77,16 +86,19 @@ static void my_canvas__motionhook(t_scalehandle *sh, t_floatarg mouse_x, t_float
     if (sh->h_scale)
     {
         t_my_canvas *x = (t_my_canvas *)(sh->h_master);
-        int dx = (int)(mouse_x - sh->h_offset_x),
-            dy = (int)(mouse_y - sh->h_offset_y);
-        dx = maxi(dx,1-x->x_vis_w);
-        dy = maxi(dy,1-x->x_vis_h);        
-        sh->h_dragx = dx;
-        sh->h_dragy = dy;
-        scalehandle_drag_scale(sh);
 
-        x->x_vis_w += dx;
-        x->x_vis_h += dy;
+        int width = (sh->h_constrain == CURSOR_EDITMODE_RESIZE_Y) ?
+            x->x_vis_w :
+            (int)mouse_x - text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist) -
+                sh->h_adjust_x;
+        int height = (sh->h_constrain == CURSOR_EDITMODE_RESIZE_X) ?
+            x->x_vis_h :
+            (int)mouse_y - text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist) -
+                sh->h_adjust_y;
+        x->x_vis_w = maxi(width, IEM_GUI_MINSIZE);
+        x->x_vis_h = maxi(height, IEM_GUI_MINSIZE);
+
+        scalehandle_drag_scale(sh);
 
         if (glist_isvisible(x->x_gui.x_glist))
         {
@@ -97,19 +109,11 @@ static void my_canvas__motionhook(t_scalehandle *sh, t_floatarg mouse_x, t_float
         int properties = gfxstub_haveproperties((void *)x);
         if (properties)
         {
-            int new_w = x->x_vis_w + sh->h_dragx;
-            int new_h = x->x_vis_h + sh->h_dragy;
-            properties_set_field_int(properties,"rng.min_ent",new_w);
-            properties_set_field_int(properties,"rng.max_ent",new_h);
-
-            int min = (new_w < new_h ? new_w : new_h);
-            if (min <= x->x_gui.x_w)
-            {
-                properties_set_field_int(properties,"dim.w_ent",min);
-            }
+            properties_set_field_int(properties,"rng.min_ent",width);
+            properties_set_field_int(properties,"rng.max_ent",height);
         }
     }
-    scalehandle_dragon_label(sh,mouse_x, mouse_y);
+    scalehandle_dragon_label(sh, mouse_x, mouse_y);
 }
 
 void my_canvas_draw(t_my_canvas *x, t_glist *glist, int mode)
diff --git a/pd/src/g_slider.c b/pd/src/g_slider.c
index 5421df81fdaaff18954b9f6e56194c9b144c4ad4..320a45a99320d997f135484076d29538380e6a34 100644
--- a/pd/src/g_slider.c
+++ b/pd/src/g_slider.c
@@ -113,25 +113,36 @@ static void slider_draw_config(t_slider *x, t_glist *glist)
 static void slider__clickhook(t_scalehandle *sh, int newstate)
 {
     t_slider *x = (t_slider *)(sh->h_master);
-    if (newstate)
+    if (sh->h_scale)
     {
-        canvas_apply_setundo(x->x_gui.x_glist, (t_gobj *)x);
-        if (!sh->h_scale)
-            scalehandle_click_label(sh);
+        sh->h_adjust_x = sh->h_offset_x -
+            (((t_object *)x)->te_xpix + x->x_gui.x_w);
+        sh->h_adjust_y = sh->h_offset_y -
+            (((t_object *)x)->te_ypix + x->x_gui.x_h);
     }
+    else
+        scalehandle_click_label(sh);
+    canvas_apply_setundo(x->x_gui.x_glist, (t_gobj *)x);
     sh->h_dragon = newstate;
 }
 
 void slider_check_length(t_slider *x, int w);
 
-static void slider__motionhook(t_scalehandle *sh, t_floatarg mouse_x, t_floatarg mouse_y)
+static void slider__motionhook(t_scalehandle *sh, t_floatarg mouse_x,
+    t_floatarg mouse_y)
 {
     if (sh->h_scale)
     {
         t_slider *x = (t_slider *)(sh->h_master);
-        int width = mouse_x - text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist),
-            height = mouse_y - text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist),
-            minx = x->x_orient ? IEM_GUI_MINSIZE : IEM_SL_MINSIZE,
+        int width = (sh->h_constrain == CURSOR_EDITMODE_RESIZE_Y) ?
+            x->x_gui.x_w :
+            (int)mouse_x - text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist) -
+                sh->h_adjust_x;
+        int height = (sh->h_constrain == CURSOR_EDITMODE_RESIZE_X) ?
+            x->x_gui.x_h :
+            (int)mouse_y - text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist) -
+                sh->h_adjust_y;
+        int minx = x->x_orient ? IEM_GUI_MINSIZE : IEM_SL_MINSIZE,
             miny = x->x_orient ? IEM_SL_MINSIZE : IEM_GUI_MINSIZE;
         x->x_gui.x_w = maxi(width, minx);
         x->x_gui.x_h = maxi(height, miny);
diff --git a/pd/src/g_vumeter.c b/pd/src/g_vumeter.c
index 0d6e7f5dcd5a52e26682820dabc9f2d8219da49e..d1693a08a7301963780c8fd23a32e8b75d395206 100644
--- a/pd/src/g_vumeter.c
+++ b/pd/src/g_vumeter.c
@@ -265,12 +265,16 @@ static void vu_draw_select(t_vu* x,t_glist* glist)
 static void vu__clickhook(t_scalehandle *sh, int newstate)
 {
     t_vu *x = (t_vu *)(sh->h_master);
-    if (newstate)
+    if (sh->h_scale)
     {
-        canvas_apply_setundo(x->x_gui.x_glist, (t_gobj *)x);
-        if (!sh->h_scale)
-            scalehandle_click_label(sh);
+        sh->h_adjust_x = sh->h_offset_x -
+            (((t_object *)x)->te_xpix + x->x_gui.x_w);
+        sh->h_adjust_y = sh->h_offset_y -
+            (((t_object *)x)->te_ypix + x->x_gui.x_h);
     }
+    else
+        scalehandle_click_label(sh);
+    canvas_apply_setundo(x->x_gui.x_glist, (t_gobj *)x);
     sh->h_dragon = newstate;
 }
 
@@ -279,10 +283,14 @@ static void vu__motionhook(t_scalehandle *sh, t_floatarg mouse_x, t_floatarg mou
     if (sh->h_scale)
     {
         t_vu *x = (t_vu *)(sh->h_master);
-        int width = ((int)mouse_x) -
-                text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist),
-            height = ((int)mouse_y) -
-                text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist);
+        int width = (sh->h_constrain == CURSOR_EDITMODE_RESIZE_Y) ?
+            x->x_gui.x_w :
+            (int)mouse_x - text_xpix(&x->x_gui.x_obj, x->x_gui.x_glist) -
+                sh->h_adjust_x;
+        int height = (sh->h_constrain == CURSOR_EDITMODE_RESIZE_X) ?
+            x->x_gui.x_h :
+            (int)mouse_y - text_ypix(&x->x_gui.x_obj, x->x_gui.x_glist) -
+                sh->h_adjust_y;
 
         width = maxi(width, 8);