diff --git a/pd/src/g_scalar.c b/pd/src/g_scalar.c
index 3483758fa0a2ac54e4cee17bdf12c6cac07f364f..02d2e78b1dc3d592fac20fcfbf729d106adcceaa 100644
--- a/pd/src/g_scalar.c
+++ b/pd/src/g_scalar.c
@@ -712,13 +712,16 @@ static void scalar_vis(t_gobj *z, t_glist *owner, int vis)
         /* we translate the .scalar%lx group to displace it on the tk side.
            This is the outermost group for the scalar, something like a
            poor man's viewport.
-           Also, the default stroke is supposed to be "none" and default
-           fill is supposed to be black. Unfortunately tkpath does the
-           opposite.  To fix this, we set the correct fill/stroke options
-           here on the .scalar%lx group. Notice also that tkpath doesn't
-           understand "None"-- instead we must send an empty symbol. */
+           Also:
+             * the default stroke is supposed to be "none"
+             * default fill is supposed to be black.
+             * stroke-linejoin should be "miter", not "round"  
+           To fix these, we set the correct fill/stroke/strokelinjoin options
+           here on the .scalar%lx group. (Notice also that tkpath doesn't
+           understand "None"-- instead we must send an empty symbol.) */
         sys_vgui(".x%lx.c create group -tags {.scalar%lx %s} "
-            "-matrix { {%g %g} {%g %g} {%d %d} } -stroke \"\" -fill black\n",
+            "-matrix { {%g %g} {%g %g} {%d %d} } "
+            "-stroke \"\" -fill black -strokelinejoin miter\n",
             glist_getcanvas(owner), x->sc_vec,
             (glist_isselected(owner, &x->sc_gobj) ? "scalar_selected" : ""),
             xscale, 0.0, 0.0, yscale, (int)glist_xtopixels(owner, basex),
@@ -787,6 +790,68 @@ void scalar_redraw(t_scalar *x, t_glist *glist)
         //sys_queuegui(x, glist, scalar_doredraw);
 }
 
+/* here we call the parentclickfns for drawing commands.
+   We recurse all the way to the end of the glist (and, for the
+   groups, as deep as they go) and then call the functions from the bottom up.
+   This way the clicks can "bubble" up from the bottom.  This has the effect
+   that the shape visually closest to the front gets called first.
+
+   This is called "event bubbling" in the HTML5 DOM.  You can also call
+   events in top down order in HTML5/SVG as well (called "capturing" or
+   "trickling"). But because some old version of Internet Explorer only did
+   bubbling, that is the most widely used model today, and the only one
+   I decided to implement here.
+
+   However, [group] doesn't yet have an outlet to report events. Only a
+   single [draw] should report a click here atm.
+*/
+int scalar_groupclick(struct _glist *groupcanvas,
+    t_word *data, t_template *template, t_scalar *sc,
+    t_array *ap, struct _glist *owner,
+    t_float xloc, t_float yloc, int xpix, int ypix,
+    int shift, int alt, int dbl, int doit, t_float basex, t_float basey,
+    t_gobj *obj)
+{
+    int hit = 0;
+    t_gobj *nextobj = obj->g_next;
+    /* let's skip over any objects that aren't drawing instructions
+       or groups */
+    while (nextobj &&
+           !class_isdrawcommand(pd_class((t_pd *)nextobj)) &&
+           !(pd_class(&nextobj->g_pd) == canvas_class &&
+               ((t_glist *)nextobj)->gl_svg))
+        nextobj = nextobj->g_next;
+    /* If there's another link in the list go ahead and recurse with it */
+    if (nextobj)
+    {
+        hit = (scalar_groupclick(groupcanvas, data, template, sc, ap,
+            owner, xloc, yloc, xpix, ypix,
+            shift, alt, dbl, doit, basex, basey, nextobj));
+        if (hit) return hit;
+    }
+    /* recurse inside a [group] object to look for more objects */
+    if (pd_class(&obj->g_pd) == canvas_class && ((t_glist *)obj)->gl_svg)
+    {
+            t_canvas *cnv = (t_canvas *)obj;
+            obj = cnv->gl_list;
+            if (obj)
+                return (scalar_groupclick(cnv, data, template, sc, ap,
+                owner, xloc, yloc, xpix, ypix,
+                shift, alt, dbl, doit, basex, basey, obj));
+    }
+    else /* finally, try to call the parent click function ... */
+    {
+        t_parentwidgetbehavior *wb = pd_getparentwidget(&obj->g_pd);
+        if (!wb) return hit;
+        if ((*wb->w_parentclickfn)(obj, owner,
+            data, template, sc, ap, basex + xloc, basey + yloc,
+            xpix, ypix, shift, alt, dbl, doit))
+                hit = 1;
+    }
+    return (hit);
+}
+
+/*
 int scalar_groupclick(struct _glist *groupcanvas,
     t_word *data, t_template *template, t_scalar *sc,
     t_array *ap, struct _glist *owner,
@@ -818,6 +883,7 @@ int scalar_groupclick(struct _glist *groupcanvas,
     }
     return 0;
 }
+*/
 
 int scalar_doclick(t_word *data, t_template *template, t_scalar *sc,
     t_array *ap, struct _glist *owner,
@@ -827,6 +893,7 @@ int scalar_doclick(t_word *data, t_template *template, t_scalar *sc,
     int hit = 0;
     t_canvas *templatecanvas = template_findcanvas(template);
     t_atom at[2];
+    t_gobj *obj;
     t_float basex = template_getfloat(template, gensym("x"), data, 0);
     t_float basey = template_getfloat(template, gensym("y"), data, 0);
     //fprintf(stderr,"=================scalar_doclick %f %f %f %f %d\n",
@@ -851,9 +918,12 @@ int scalar_doclick(t_word *data, t_template *template, t_scalar *sc,
     }
 
     if (templatecanvas)
+    {
+        if (!(obj = templatecanvas->gl_list)) return 0;
         hit = scalar_groupclick(templatecanvas, data, template, sc, ap,
                     owner, xloc, yloc, xpix, ypix,
-                    shift, alt, dbl, doit, basex, basey);
+                    shift, alt, dbl, doit, basex, basey, obj);
+    }
     return hit;
 }
 
diff --git a/pd/src/g_template.c b/pd/src/g_template.c
index b106a95d4fb5fe02445e99acb8631ecf3ec67efc..08fba1d1ec2acb4b9fefd880dbeae4ddd03c5425 100644
--- a/pd/src/g_template.c
+++ b/pd/src/g_template.c
@@ -1042,12 +1042,39 @@ t_class *draw_class;
 
 t_class *svg_class;
 
+/* this is a wrapper around t_fielddesc-- it adds a flag for two reasons:
+   1) tkpath defaults to inheriting values for options from the parent until
+      you specify them-- after that, there's no way to get back to "inherit".
+      We set the flag to "0" to mean "inherit"-- that way we don't send a tcl
+      string for that option.  There's still the bug that the user can't set
+      an attribute back to "inherit" after they've set something explicitly,
+      however.
+   2) This might be generally useful even with Qt, so that if the user calls
+      a method for an attribute without any arguments, Qt goes back to
+      inheriting the value from the parent.  That gives us a way to
+      differentiate "inherit" from fielddescriptors, the value "none" and
+      "".  (Similar to the way "set" resets a message box.)
+*/
 typedef struct _svg_attr
 {
     int a_flag;
     t_fielddesc a_attr;
 } t_svg_attr;
 
+/* events on which to output a notification from the outlet of [draw] */
+typedef struct _svg_event
+{
+    t_fielddesc e_focusin,
+                e_focusout,
+                e_activate,
+                e_click,
+                e_mousedown,
+                e_mouseup,
+                e_mouseover,
+                e_mousemove,
+                e_mouseout;
+} t_svg_event;
+
 /* svg attributes */
 typedef struct _svg
 {
@@ -1063,6 +1090,9 @@ typedef struct _svg
     int x_stroketype;
     int x_ndash;
     t_fielddesc *x_strokedasharray; /* array of lengths */
+    t_svg_event x_events;
+    t_fielddesc x_drag; /* convenience event, not part of the svg spec */
+    t_svg_attr x_pointerevents;
     t_svg_attr x_strokelinecap;
     t_svg_attr x_strokelinejoin;
     t_svg_attr x_strokemiterlimit;
@@ -1074,6 +1104,7 @@ typedef struct _svg
     t_fielddesc *x_transform;
     t_fielddesc x_width;
     t_svg_attr x_vis;
+    t_fielddesc x_bbox; /* turn bbox calculation on or off */
     int x_pathrect_cache; /* 0 to recalc on next draw_getrect call
                              1 for cached
                             -1 to turn off caching */
@@ -1112,6 +1143,18 @@ typedef struct _drawimage
     t_pd *x_attr;
 } t_drawimage;
 
+void draw_notifyforscalar(t_draw *x, t_glist *owner,
+    t_scalar *sc, t_symbol *s, int argc, t_atom *argv)
+{
+    t_gpointer gp;
+    gpointer_init(&gp);
+    gpointer_setglist(&gp, owner, &sc->sc_gobj);
+    SETPOINTER(argv, &gp);
+    if (x)
+        outlet_anything(x->x_obj.ob_outlet, s, argc, argv);
+    gpointer_unset(&gp);
+}
+
 static int is_svgpath_cmd(t_symbol *s)
 {
     /* 1 for absolute cmd, 2 for relative */
@@ -1248,9 +1291,13 @@ void *svg_new(t_pd *parent, t_symbol *s, int argc, t_atom *argv)
     }
     if (argc & 1 && x->x_type != gensym("path"))
         fielddesc_setfloat_const(fd, 0);
+    fielddesc_setfloat_const(&x->x_bbox, 1);
+    fielddesc_setfloat_const(&x->x_drag, 0);
     x->x_filltype = 0;
     x->x_fillopacity.a_flag = 0;
     x->x_fillrule.a_flag = 0;
+    fielddesc_setfloat_const(&x->x_pointerevents.a_attr, 1);
+    x->x_pointerevents.a_flag = 0;
     x->x_stroketype = 0;
     x->x_strokelinecap.a_flag = 0;
     x->x_strokelinejoin.a_flag = 0;
@@ -1268,6 +1315,16 @@ void *svg_new(t_pd *parent, t_symbol *s, int argc, t_atom *argv)
     x->x_transform_n = 0;
     x->x_transform = (t_fielddesc *)t_getbytes(x->x_transform_n *
         sizeof(t_fielddesc));
+    /* initialize events */
+    fielddesc_setfloat_const(&x->x_events.e_focusin, 0);
+    fielddesc_setfloat_const(&x->x_events.e_focusout, 0);
+    fielddesc_setfloat_const(&x->x_events.e_activate, 0);
+    fielddesc_setfloat_const(&x->x_events.e_click, 0);
+    fielddesc_setfloat_const(&x->x_events.e_mousedown, 0);
+    fielddesc_setfloat_const(&x->x_events.e_mouseup, 0);
+    fielddesc_setfloat_const(&x->x_events.e_mouseover, 0);
+    fielddesc_setfloat_const(&x->x_events.e_mousemove, 0);
+    fielddesc_setfloat_const(&x->x_events.e_mouseout, 0);
     return (x);
 }
 
@@ -1312,6 +1369,9 @@ static void *draw_new(t_symbol *classsym, t_int argc, t_atom *argv)
 
     t_draw *x = (t_draw *)pd_new(draw_class);
 
+    /* outlet for event notifications */
+    outlet_new(&x->x_obj, &s_anything);
+
     /* create a proxy for drawing/svg attributes */
     if (!(x->x_attr = (t_pd *)svg_new((t_pd *)x, type, argc, argv)))
     {
@@ -1422,7 +1482,9 @@ void svg_sendupdate(t_svg *x, t_canvas *c, t_symbol *s,
             (long unsigned int)x->x_parent,
             (long unsigned int)data);
     }
-    if (s == gensym("fill"))
+    if (s == gensym("bbox"))
+        *predraw_bbox = 1;
+    else if (s == gensym("fill"))
     {
         t_symbol *fill;
         t_fielddesc *fd = x->x_fill;
@@ -1466,6 +1528,8 @@ void svg_sendupdate(t_svg *x, t_canvas *c, t_symbol *s,
             glist_getcanvas(c), tag, (int)fielddesc_getcoord(
                 &x->x_fillrule.a_attr, template, data, 1) ?
                     "evenodd" : "nonzero");
+    else if (s == gensym("pointer-events"))
+        *predraw_bbox = 1;
     else if (s == gensym("stroke-linecap"))
         sys_vgui(".x%lx.c itemconfigure %s -strokelinecap %s\n",
             glist_getcanvas(c), tag, get_strokelinecap(
@@ -1648,7 +1712,7 @@ void svg_updatevec(t_canvas *c, t_word *data, t_template *template,
     t_template *target, void *parent, t_symbol *s, t_svg *x, t_scalar *sc,
     int *predraw_bbox)
 {
-    post("updateing vec...");
+    // post("updateing vec...");
     int i, j;
     for (i = 0; i < template->t_n; i++)
     {
@@ -1962,8 +2026,55 @@ void svg_stroke(t_svg *x, t_symbol *s, t_int argc, t_atom *argv)
     svg_update(x, s);
 }
 
-void svg_strokelinecap(t_svg *x, t_symbol *s,
-    t_int argc, t_atom *argv)
+/* "drag" is a convenience method-- to use it the user must turn on the
+   "mousedown" event, too. */
+void svg_drag(t_svg *x, t_symbol *s, int argc, t_atom *argv)
+{
+    if (argc > 0 && (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL))
+    {
+        fielddesc_setfloatarg(&x->x_drag, argc, argv);
+    }
+}
+
+void svg_event(t_svg *x, t_symbol *s, int argc, t_atom *argv)
+{
+    if (argc > 0 && (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL))
+    {
+        if (s == gensym("focusin"))
+            fielddesc_setfloatarg(&x->x_events.e_focusin, argc, argv);
+        else if (s == gensym("focusout"))
+            fielddesc_setfloatarg(&x->x_events.e_focusout, argc, argv);
+        else if (s == gensym("activate"))
+            fielddesc_setfloatarg(&x->x_events.e_activate, argc, argv);
+        else if (s == gensym("click"))
+            fielddesc_setfloatarg(&x->x_events.e_click, argc, argv);
+        else if (s == gensym("mousedown"))
+            fielddesc_setfloatarg(&x->x_events.e_mousedown, argc, argv);
+        else if (s == gensym("mouseup"))
+            fielddesc_setfloatarg(&x->x_events.e_mouseup, argc, argv);
+        else if (s == gensym("mouseover"))
+            fielddesc_setfloatarg(&x->x_events.e_mouseover, argc, argv);
+        else if (s == gensym("mousemove"))
+            fielddesc_setfloatarg(&x->x_events.e_mousemove, argc, argv);
+        else if (s == gensym("mouseout"))
+            fielddesc_setfloatarg(&x->x_events.e_mouseout, argc, argv);
+//        svg_update(x, s);
+    }
+}
+
+void svg_pointerevents(t_svg *x, t_symbol *s, t_int argc, t_atom *argv)
+{
+    if (argc < 1)
+        x->x_pointerevents.a_flag = 0;
+    else if (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL)
+    {
+        fielddesc_setfloatarg(&x->x_pointerevents.a_attr, argc, argv);
+        x->x_pointerevents.a_flag = 1;
+        svg_update(x, s);
+    }
+}
+
+void svg_strokelinecap(t_svg *x, t_symbol *s, t_int argc, t_atom *argv)
 {
     if (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL)
     {
@@ -2120,6 +2231,17 @@ void svg_rectpoints(t_svg *x, t_symbol *s, int argc, t_atom *argv)
     }
 }
 
+/* selectively do bbox calculation: 0 = off, 1 = on, instance variable per
+   instance */
+void svg_bbox(t_svg *x, t_symbol *s, t_int argc, t_atom *argv)
+{
+    if (argc > 0 && (argv[0].a_type == A_FLOAT || argv[0].a_type == A_SYMBOL))
+    {
+        fielddesc_setfloatarg(&x->x_bbox, argc, argv);
+        svg_update(x, s);
+    }
+}
+
 void svg_ellipsepoints(t_svg *x, t_symbol *s, int argc, t_atom *argv)
 {
     if (x->x_type == gensym("circle") || x->x_type == gensym("ellipse"))
@@ -2299,14 +2421,16 @@ void svg_parsetransform(t_svg *x, t_template *template, t_word *data,
         }
         else if (type == gensym("skewx"))
         {
-            t_float a = fielddesc_getfloat(fd++, template, data, 0);
+            t_float a = fielddesc_getfloat(fd++, template, data, 0) *
+                3.14159 / 180;
             argc--;
             mset(m2, 1, 0, tan(a), 1, 0, 0);
             mmult(m, m2, m);
         }
         else if (type == gensym("skewy"))
         {
-            t_float a = fielddesc_getfloat(fd++, template, data, 0);
+            t_float a = fielddesc_getfloat(fd++, template, data, 0) *
+                3.14159 / 180;
             argc--;
             mset(m2, 1, tan(a), 0, 1, 0, 0);
             mmult(m, m2, m);
@@ -3111,7 +3235,22 @@ static void draw_getrect(t_gobj *z, t_glist *glist,
 {
     t_draw *x = (t_draw *)z;
     t_svg *sa = (t_svg *)x->x_attr;
-    /* todo: put this after the var inits below */
+
+    /* So in the svg spec, the "display" attribute doesn't actually
+       calculate a bbox, whereas the "visibility" still calcs the bbox.
+       tkpath doesn't have a function for "display" so currently "vis"
+       is filling in for it
+
+    */
+    if (!fielddesc_getfloat(&sa->x_vis.a_attr, template, data, 0) ||
+        !fielddesc_getfloat(&sa->x_bbox, template, data, 0) ||
+        (sa->x_type == gensym("group")))
+    {
+        *xp1 = *yp1 = 0x7fffffff;
+        *xp2 = *yp2 = -0x7fffffff;
+        return;
+    }
+
     if (sa->x_pathrect_cache == 1)
     {
         *xp1 = glist_xtopixels(glist, basex + sa->x_x1);
@@ -3129,13 +3268,6 @@ static void draw_getrect(t_gobj *z, t_glist *glist,
     int i, n = sa->x_nargs;
     t_fielddesc *f = sa->x_vec;
     int x1 = 0x7fffffff, x2 = -0x7fffffff, y1 = 0x7fffffff, y2 = -0x7fffffff;
-    if (!fielddesc_getfloat(&sa->x_vis.a_attr, template, data, 0) ||
-        (sa->x_flags & NOMOUSE) || (sa->x_type == gensym("group")))
-    {
-        *xp1 = *yp1 = 0x7fffffff;
-        *xp2 = *yp2 = -0x7fffffff;
-        return;
-    }
 
     svg_groupmtx(sa, template, data, mtx1);
     if (sa->x_type == gensym("path"))
@@ -3592,6 +3724,70 @@ static t_gpointer draw_motion_gpointer;
     /* LATER protect against the template changing or the scalar disappearing
     probably by attaching a gpointer here ... */
 
+static void draw_motion(void *z, t_floatarg dx, t_floatarg dy)
+{
+    t_draw *x = (t_draw *)z;
+    t_svg *sa = (t_svg *)x->x_attr;
+    t_atom at[5];
+    SETFLOAT(at+1, (t_float)dx);
+    SETFLOAT(at+2, (t_float)dy);
+    t_float mtx1[3][3];
+    t_float mtx2[3][3];
+    t_float m1, m2, m3, m4, m5, m6, tdx, tdy;
+
+    /* might use this to output the ctm */
+    svg_groupmtx(sa, draw_motion_template, draw_motion_wp, mtx1);
+    svg_parsetransform(sa, draw_motion_template, draw_motion_wp,
+        &m1, &m2, &m3, &m4, &m5, &m6);
+    mset(mtx2, m1, m2, m3, m4, m5, m6);
+    mmult(mtx1, mtx2, mtx1);
+    minv(mtx1, mtx1);
+    /* get rid of translation so it doesn't factor
+       in to our deltas */
+    mtx1[0][2] = 0;
+    mtx1[1][2] = 0;
+    mset(mtx2, dx, dy, 0, 0, 0, 0);
+    mtx2[2][0] = 1;
+    mmult(mtx1, mtx2, mtx2);
+    tdx = mtx2[0][0];
+    tdy = mtx2[1][0];
+    SETFLOAT(at+3, tdx);
+    SETFLOAT(at+4, tdy);
+    t_fielddesc *f = sa->x_vec; //+ draw_motion_field;
+    if (!gpointer_check(&draw_motion_gpointer, 0))
+    {
+        post("draw_motion: scalar disappeared");
+        return;
+    }
+    draw_motion_xcumulative += dx;
+    draw_motion_ycumulative += dy;
+//    if (f->fd_var && (tdx != 0))
+//    {
+//        fielddesc_setcoord(f, draw_motion_template, draw_motion_wp,
+//            draw_motion_xbase + draw_motion_xcumulative * draw_motion_xper,
+//                1); 
+//    }
+//    if ((f+1)->fd_var && (tdy != 0))
+//    {
+//        fielddesc_setcoord(f+1, draw_motion_template, draw_motion_wp,
+//            draw_motion_ybase + draw_motion_ycumulative * draw_motion_yper,
+//                1); 
+//    }
+        /* LATER figure out what to do to notify for an array? */
+    if (draw_motion_scalar)
+    {
+        template_notifyforscalar(draw_motion_template, draw_motion_glist, 
+            draw_motion_scalar, gensym("change"), 1, at);
+        draw_notifyforscalar(x, draw_motion_glist, draw_motion_scalar,
+            gensym("drag"), 5, at);
+    }
+//    if (draw_motion_scalar)
+//        scalar_redraw(draw_motion_scalar, draw_motion_glist);
+//    if (draw_motion_array)
+//        array_redraw(draw_motion_array, draw_motion_glist);
+}
+
+/*
 static void draw_motion(void *z, t_floatarg dx, t_floatarg dy)
 {
     t_draw *x = (t_draw *)z;
@@ -3607,8 +3803,10 @@ static void draw_motion(void *z, t_floatarg dx, t_floatarg dy)
     mset(mtx2, m1, m2, m3, m4, m5, m6);
     mmult(mtx1, mtx2, mtx1);
     minv(mtx1, mtx1);
+    */
     /* get rid of translation so it doesn't factor
        in to our deltas */
+/* 
     mtx1[0][2] = 0;
     mtx1[1][2] = 0;
     mset(mtx2, dx, dy, 0, 0, 0, 0);
@@ -3637,7 +3835,9 @@ static void draw_motion(void *z, t_floatarg dx, t_floatarg dy)
             draw_motion_ybase + draw_motion_ycumulative * draw_motion_yper,
                 1); 
     }
+    */
         /* LATER figure out what to do to notify for an array? */
+    /*
     if (draw_motion_scalar)
         template_notifyforscalar(draw_motion_template, draw_motion_glist, 
             draw_motion_scalar, gensym("change"), 1, &at);
@@ -3646,12 +3846,94 @@ static void draw_motion(void *z, t_floatarg dx, t_floatarg dy)
     if (draw_motion_array)
         array_redraw(draw_motion_array, draw_motion_glist);
 }
+*/
+
+static int draw_click(t_gobj *z, t_glist *glist, 
+    t_word *data, t_template *template, t_scalar *sc, t_array *ap,
+    t_float basex, t_float basey,
+    int xpix, int ypix, int shift, int alt, int dbl, int doit)
+{
+    //fprintf(stderr,"draw_click %f %f %d %d %g %g %lx\n",
+    //    basex, basey, xpix, ypix, glist_xtopixels(glist, basex),
+    //    glist_ytopixels(glist, basey), (t_int)data);
+    t_draw *x = (t_draw *)z;
+    t_svg *sa = (t_svg *)x->x_attr;
+    int x1, y1, x2, y2;
+    /* don't register a click if we don't have an event listener, or
+       if our pointer-event is "none" */
+    if (!fielddesc_getfloat(&sa->x_pointerevents.a_attr, template, data, 1) ||
+         (!fielddesc_getfloat(&sa->x_events.e_mousedown, template, data, 1) &&
+          !fielddesc_getfloat(&sa->x_drag, template, data, 1)))
+        return 0;
+    draw_getrect(z, glist, data, template, basex, basey,
+        &x1, &y1, &x2, &y2);
+    if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2)
+    {
+        if (doit)
+        {
+            t_atom at[5];
+            SETFLOAT(at+1, xpix - glist_xtopixels(glist, basex));
+            SETFLOAT(at+2, ypix - glist_ytopixels(glist, basey));
+            t_float mtx1[3][3];
+            t_float mtx2[3][3];
+            t_float m1, m2, m3, m4, m5, m6, tdx, tdy;
+
+            t_svg *sa = (t_svg *)x->x_attr;
+            /* might use this to output the ctm */
+            svg_groupmtx(sa, template, data, mtx1);
+            svg_parsetransform(sa, template, data,
+                &m1, &m2, &m3, &m4, &m5, &m6);
+            mset(mtx2, m1, m2, m3, m4, m5, m6);
+            mmult(mtx1, mtx2, mtx1);
+            minv(mtx1, mtx1);
+            /* get rid of translation so it doesn't factor
+               in to our deltas */
+    //        mtx1[0][2] = 0;
+    //        mtx1[1][2] = 0;
+            /* maybe needs units per pixel here? */
+            mset(mtx2, xpix - glist_xtopixels(glist, basex),
+                ypix - glist_ytopixels(glist, basey), 0, 0, 0, 0);
+            mtx2[2][0] = 1;
+            mmult(mtx1, mtx2, mtx2);
+            SETFLOAT(at+3, mtx2[0][0]); /* user-coordinate x */
+            SETFLOAT(at+4, mtx2[1][0]); /* user-coordinate y */
+
+            if (fielddesc_getfloat(&sa->x_drag, template, data, 1))
+            {
+                draw_motion_xper = glist_pixelstox(glist, 1)
+                    - glist_pixelstox(glist, 0);
+                draw_motion_yper = glist_pixelstoy(glist, 1)
+                    - glist_pixelstoy(glist, 0);
+                draw_motion_xcumulative = 0;
+                draw_motion_ycumulative = 0;
+                draw_motion_glist = glist;
+                draw_motion_scalar = sc;
+                draw_motion_array = ap;
+                draw_motion_wp = data;
+        //        draw_motion_field = 2*bestn;
+                draw_motion_template = template;
+                if (draw_motion_scalar)
+                    gpointer_setglist(&draw_motion_gpointer, draw_motion_glist,
+                        &draw_motion_scalar->sc_gobj);
+                else gpointer_setarray(&draw_motion_gpointer,
+                        draw_motion_array, draw_motion_wp);
+                glist_grab(glist, z, draw_motion, 0, xpix, ypix);
+        //        outlet_anything(x->x_obj.ob_outlet, gensym("click"), 0, 0);
+            }
+            draw_notifyforscalar(x, glist, sc, gensym("mousedown"), 5, at);
+        }
+        return (1);
+    }
+    return (0);
+}
 
+/*
 static int draw_click(t_gobj *z, t_glist *glist, 
     t_word *data, t_template *template, t_scalar *sc, t_array *ap,
     t_float basex, t_float basey,
     int xpix, int ypix, int shift, int alt, int dbl, int doit)
 {
+    post("hello?");
     //fprintf(stderr,"draw_click %f %f %d %d %lx\n",
     //    basex, basey, xpix, ypix, (t_int)data);
     t_draw *x = (t_draw *)z;
@@ -3722,8 +4004,11 @@ static int draw_click(t_gobj *z, t_glist *glist,
                 draw_motion_array, draw_motion_wp);
         glist_grab(glist, z, draw_motion, 0, xpix, ypix);
     }
+    post("we got clicked");
+    outlet_anything(x->x_obj.ob_outlet, gensym("click"), 0, 0);
     return (1);
 }
+*/
 
 t_parentwidgetbehavior draw_widgetbehavior =
 {
@@ -3779,12 +4064,20 @@ static void draw_setup(void)
     /* methods for svg_class-- these will be accessible
        from the inlet of [draw] and the (rightmost) inlet of
        [group] */
+    /* I don't find anything in the spec that will render the
+       shape while turning off the bbox calculations-- i.e., something
+       like the "-n" flag of [drawcurve].  So I've introduced the
+       "bbox" method for this */
+    class_addmethod(svg_class, (t_method)svg_bbox,
+        gensym("bbox"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_ellipsepoints,
         gensym("cx"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_ellipsepoints,
         gensym("cy"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_data,
         gensym("data"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_drag,
+        gensym("drag"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_fill,
         gensym("fill"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_fillopacity,
@@ -3793,6 +4086,10 @@ static void draw_setup(void)
         gensym("fill-rule"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_rectpoints,
         gensym("height"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_event,
+        gensym("mousedown"), A_GIMME, 0);
+    class_addmethod(svg_class, (t_method)svg_pointerevents,
+        gensym("pointer-events"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_data,
         gensym("points"), A_GIMME, 0);
     class_addmethod(svg_class, (t_method)svg_r,