diff --git a/pd/src/d_ugen.c b/pd/src/d_ugen.c
index 13fbea175ac9c2ddaabe9765a42fc09c34d90cbe..55213566ec0aa6c3a209036f29d06630ca786588 100644
--- a/pd/src/d_ugen.c
+++ b/pd/src/d_ugen.c
@@ -11,17 +11,14 @@
     interconnections.
 */
 
-
 #include "m_pd.h"
 #include "m_imp.h"
 #include <stdlib.h>
 #include <stdarg.h>
 
-extern t_class *vinlet_class, *voutlet_class, *canvas_class;
+extern t_class *vinlet_class, *voutlet_class, *canvas_class, *text_class;
 t_float *obj_findsignalscalar(t_object *x, int m);
 static int ugen_loud;
-static t_int *dsp_chain;
-static int dsp_chainsize;
 
 EXTERN_STRUCT _vinlet;
 EXTERN_STRUCT _voutlet;
@@ -40,7 +37,7 @@ t_int *zero_perform(t_int *w)   /* zero out a vector */
 {
     t_sample *out = (t_sample *)(w[1]);
     int n = (int)(w[2]);
-    while (n--) *out++ = 0; 
+    while (n--) *out++ = 0;
     return (w+3);
 }
 
@@ -48,7 +45,7 @@ t_int *zero_perf8(t_int *w)
 {
     t_sample *out = (t_sample *)(w[1]);
     int n = (int)(w[2]);
-    
+
     for (; n; n -= 8, out += 8)
     {
         out[0] = 0;
@@ -67,7 +64,7 @@ void dsp_add_zero(t_sample *out, int n)
 {
     if (n&7)
         dsp_add(zero_perform, 2, out, n);
-    else        
+    else
         dsp_add(zero_perf8, 2, out, n);
 }
 
@@ -219,11 +216,11 @@ static void block_float(t_block *x, t_floatarg f)
 
 static void block_bang(t_block *x)
 {
-    if (x->x_switched && !x->x_switchon)
+    if (x->x_switched && !x->x_switchon && pd_this->pd_dspchain)
     {
         t_int *ip;
         x->x_return = 1;
-        for (ip = dsp_chain + x->x_chainonset; ip; )
+        for (ip = pd_this->pd_dspchain + x->x_chainonset; ip; )
             ip = (*(t_perfroutine)(*ip))(ip);
         x->x_return = 0;
     }
@@ -284,7 +281,7 @@ void block_tilde_setup(void)
             sizeof(t_block), 0, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
     class_addcreator((t_newmethod)switch_new, gensym("switch~"),
         A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
-    class_addmethod(block_class, (t_method)block_set, gensym("set"), 
+    class_addmethod(block_class, (t_method)block_set, gensym("set"),
         A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
     class_addmethod(block_class, (t_method)block_dsp, gensym("dsp"), A_CANT, 0);
     class_addfloat(block_class, block_float);
@@ -300,40 +297,48 @@ static t_int dsp_done(t_int *w)
 
 void dsp_add(t_perfroutine f, int n, ...)
 {
-    int newsize = dsp_chainsize + n+1, i;
+    int newsize = pd_this->pd_dspchainsize + n+1, i;
     va_list ap;
 
-    dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
-        newsize * sizeof (t_int));
-    dsp_chain[dsp_chainsize-1] = (t_int)f;
+    pd_this->pd_dspchain = t_resizebytes(pd_this->pd_dspchain,
+        pd_this->pd_dspchainsize * sizeof (t_int), newsize * sizeof (t_int));
+    pd_this->pd_dspchain[pd_this->pd_dspchainsize-1] = (t_int)f;
+    if (ugen_loud)
+        post("add to chain: %lx",
+            pd_this->pd_dspchain[pd_this->pd_dspchainsize-1]);
     va_start(ap, n);
     for (i = 0; i < n; i++)
-        dsp_chain[dsp_chainsize + i] = va_arg(ap, t_int);
+    {
+        pd_this->pd_dspchain[pd_this->pd_dspchainsize + i] = va_arg(ap, t_int);
+        if (ugen_loud)
+            post("add to chain: %lx",
+                pd_this->pd_dspchain[pd_this->pd_dspchainsize + i]);
+    }
     va_end(ap);
-    dsp_chain[newsize-1] = (t_int)dsp_done;
-    dsp_chainsize = newsize;
+    pd_this->pd_dspchain[newsize-1] = (t_int)dsp_done;
+    pd_this->pd_dspchainsize = newsize;
 }
 
     /* at Guenter's suggestion, here's a vectorized version */
 void dsp_addv(t_perfroutine f, int n, t_int *vec)
 {
-    int newsize = dsp_chainsize + n+1, i;
-    
-    dsp_chain = t_resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int),
-        newsize * sizeof (t_int));
-    dsp_chain[dsp_chainsize-1] = (t_int)f;
+    int newsize = pd_this->pd_dspchainsize + n+1, i;
+
+    pd_this->pd_dspchain = t_resizebytes(pd_this->pd_dspchain,
+        pd_this->pd_dspchainsize * sizeof (t_int), newsize * sizeof (t_int));
+    pd_this->pd_dspchain[pd_this->pd_dspchainsize-1] = (t_int)f;
     for (i = 0; i < n; i++)
-        dsp_chain[dsp_chainsize + i] = vec[i];
-    dsp_chain[newsize-1] = (t_int)dsp_done;
-    dsp_chainsize = newsize;
+        pd_this->pd_dspchain[pd_this->pd_dspchainsize + i] = vec[i];
+    pd_this->pd_dspchain[newsize-1] = (t_int)dsp_done;
+    pd_this->pd_dspchainsize = newsize;
 }
 
 void dsp_tick(void)
 {
-    if (dsp_chain)
+    if (pd_this->pd_dspchain)
     {
         t_int *ip;
-        for (ip = dsp_chain; ip; ) ip = (*(t_perfroutine)(*ip))(ip);
+        for (ip = pd_this->pd_dspchain; ip; ) ip = (*(t_perfroutine)(*ip))(ip);
         dsp_phase++;
     }
 }
@@ -356,17 +361,15 @@ int ilog2(int n)
 static t_signal *signal_freelist[MAXLOGSIG+1];
     /* list of reusable "borrowed" signals (which don't own sample buffers) */
 static t_signal *signal_freeborrowed;
-    /* list of all signals allocated (not including "borrowed" ones) */
-static t_signal *signal_usedlist;
 
     /* call this when DSP is stopped to free all the signals */
 void signal_cleanup(void)
 {
-    t_signal *sig;
+    t_signal **svec, *sig, *sig2;
     int i;
-    while (sig = signal_usedlist)
+    while ((sig = pd_this->pd_signals))
     {
-        signal_usedlist = sig->s_nextused;
+        pd_this->pd_signals = sig->s_nextused;
         if (!sig->s_isborrowed)
             t_freebytes(sig->s_vec, sig->s_vecsize * sizeof (*sig->s_vec));
         t_freebytes(sig, sizeof *sig);
@@ -429,8 +432,9 @@ void signal_makereusable(t_signal *sig)
 
 t_signal *signal_new(int n, t_float sr)
 {
-    int logn, vecsize = 0;
+    int logn, n2, vecsize = 0;
     t_signal *ret, **whichlist;
+    t_sample *fp;
     logn = ilog2(n);
     if (n)
     {
@@ -444,7 +448,7 @@ t_signal *signal_new(int n, t_float sr)
         whichlist = &signal_freeborrowed;
 
         /* first try to reclaim one from the free list */
-    if (ret = *whichlist)
+    if ((ret = *whichlist))
         *whichlist = ret->s_nextfree;
     else
     {
@@ -460,15 +464,15 @@ t_signal *signal_new(int n, t_float sr)
             ret->s_vec = 0;
             ret->s_isborrowed = 1;
         }
-        ret->s_nextused = signal_usedlist;
-        signal_usedlist = ret;
+        ret->s_nextused = pd_this->pd_signals;
+        pd_this->pd_signals = ret;
     }
     ret->s_n = n;
     ret->s_vecsize = vecsize;
     ret->s_sr = sr;
     ret->s_refcount = 0;
     ret->s_borrowedfrom = 0;
-    if (ugen_loud) post("new %lx: %d", ret, ret->s_isborrowed);
+    if (ugen_loud) post("new %lx: %lx", ret, ret->s_vec);
     return (ret);
 }
 
@@ -487,6 +491,7 @@ void signal_setborrowed(t_signal *sig, t_signal *sig2)
     sig->s_vec = sig2->s_vec;
     sig->s_n = sig2->s_n;
     sig->s_vecsize = sig2->s_vecsize;
+    if (ugen_loud) post("set borrowed %lx: %lx", sig, sig->s_vec);
 }
 
 int signal_compatible(t_signal *s1, t_signal *s2)
@@ -544,7 +549,7 @@ struct _dspcontext
     char dc_toplevel;       /* true if "iosigs" is invalid. */
     char dc_reblock;        /* true if we have to reblock inlets/outlets */
     char dc_switched;       /* true if we're switched */
-    
+
 };
 
 #define t_dspcontext struct _dspcontext
@@ -552,24 +557,34 @@ struct _dspcontext
 static int ugen_sortno = 0;
 static t_dspcontext *ugen_currentcontext;
 
+    /* get a new signal for the current context - used by clone~ object */
+t_signal *signal_newfromcontext(int borrowed)
+{
+    return (signal_new((borrowed? 0 : ugen_currentcontext->dc_calcsize),
+        ugen_currentcontext->dc_srate));
+}
+
 void ugen_stop(void)
 {
-    if (dsp_chain)
+    t_signal *s;
+    int i;
+    if (pd_this->pd_dspchain)
     {
-        freebytes(dsp_chain, dsp_chainsize * sizeof (t_int));
-        dsp_chain = 0;
+        freebytes(pd_this->pd_dspchain,
+            pd_this->pd_dspchainsize * sizeof (t_int));
+        pd_this->pd_dspchain = 0;
     }
     signal_cleanup();
-    
+
 }
 
 void ugen_start(void)
 {
     ugen_stop();
     ugen_sortno++;
-    dsp_chain = (t_int *)getbytes(sizeof(*dsp_chain));
-    dsp_chain[0] = (t_int)dsp_done;
-    dsp_chainsize = 1;
+    pd_this->pd_dspchain = (t_int *)getbytes(sizeof(*pd_this->pd_dspchain));
+    pd_this->pd_dspchain[0] = (t_int)dsp_done;
+    pd_this->pd_dspchainsize = 1;
     if (ugen_currentcontext) bug("ugen_start");
 }
 
@@ -578,12 +593,12 @@ int ugen_getsortno(void)
     return (ugen_sortno);
 }
 
-#if 0
+#if 1
 void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
 {
     int i, count;
     t_signal *sig;
-    for (count = 0, sig = signal_usedlist; sig;
+    for (count = 0, sig = pd_this->pd_signals; sig;
         count++, sig = sig->s_nextused)
             ;
     post("used signals %d", count);
@@ -600,7 +615,7 @@ void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
             ;
     post("free borrowed %d", count);
 
-    ugen_loud = argc;  
+    ugen_loud = argc;
 }
 #endif
 
@@ -609,9 +624,15 @@ t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp,
     int ninlets, int noutlets)
 {
     t_dspcontext *dc = (t_dspcontext *)getbytes(sizeof(*dc));
+    int parent_vecsize, vecsize;
 
     if (ugen_loud) post("ugen_start_graph...");
 
+    /* protect against invalid numsignals.  This might happen if we have
+    an abstraction with inlet~/outlet~  opened as a toplevel patch */
+    if (toplevel)
+        ninlets = noutlets = 0;
+
     dc->dc_ugenlist = 0;
     dc->dc_toplevel = toplevel;
     dc->dc_iosigs = sp;
@@ -629,7 +650,7 @@ void ugen_add(t_dspcontext *dc, t_object *obj)
     int i;
     t_sigoutlet *uout;
     t_siginlet *uin;
-    
+
     x->u_next = dc->dc_ugenlist;
     dc->dc_ugenlist = x;
     x->u_obj = obj;
@@ -643,9 +664,6 @@ void ugen_add(t_dspcontext *dc, t_object *obj)
         uout->o_connections = 0, uout->o_nconnect = 0;
 }
 
-extern t_class *text_class;
-#include <stdio.h>
-
     /* and then this to make all the connections. */
 void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, t_object *x2,
     int inno)
@@ -664,6 +682,10 @@ void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, t_object *x2,
     for (u2 = dc->dc_ugenlist; u2 && u2->u_obj != x2; u2 = u2->u_next);
     if (!u1 || !u2 || siginno < 0)
     {
+        if (!u1)
+            error("object with signal outlets but no DSP method?");
+                /* check if it's a "text" (i.e., object wasn't created) -
+                if so fail silently */
         t_text *t2 = (t_text *)x2;
         // The following only happens if the DAC is on while connecting
         // objects. If this is not yet initialized object we don't
@@ -705,6 +727,7 @@ static int ugen_index(t_dspcontext *dc, t_ugenbox *x)
         if (u == x) return (ret);
     return (-1);
 }
+extern t_class *clone_class;
 
     /* put a ugenbox on the chain, recursively putting any others on that
     this one might uncover. */
@@ -712,7 +735,7 @@ static void ugen_doit(t_dspcontext *dc, t_ugenbox *u)
 {
     t_sigoutlet *uout;
     t_siginlet *uin;
-    t_sigoutconnect *oc;
+    t_sigoutconnect *oc, *oc2;
     t_class *class = pd_class(&u->u_obj->ob_pd);
     int i, n;
         /* suppress creating new signals for the outputs of signal
@@ -721,16 +744,16 @@ static void ugen_doit(t_dspcontext *dc, t_ugenbox *u)
         we delay new signal creation, which will be handled by calling
         signal_setborrowed in the ugen_done_graph routine below. */
     int nonewsigs = (class == canvas_class || 
-        (class == vinlet_class) && !(dc->dc_reblock));
+        ((class == vinlet_class) && !(dc->dc_reblock)));
         /* when we encounter a subcanvas or a signal outlet, suppress freeing
         the input signals as they may be "borrowed" for the super or sub
         patch; same exception as above, but also if we're "switched" we
         have to do a copy rather than a borrow.  */
-    int nofreesigs = (class == canvas_class || 
-        (class == voutlet_class) &&  !(dc->dc_reblock || dc->dc_switched));
+    int nofreesigs = (class == canvas_class || class == clone_class ||
+        ((class == voutlet_class) &&  !(dc->dc_reblock || dc->dc_switched)));
     t_signal **insig, **outsig, **sig, *s1, *s2, *s3;
     t_ugenbox *u2;
-    
+
     if (ugen_loud) post("doit %s %d %d", class_getname(class), nofreesigs,
         nonewsigs);
     for (i = 0, uin = u->u_in; i < u->u_nin; i++, uin++)
@@ -738,10 +761,10 @@ static void ugen_doit(t_dspcontext *dc, t_ugenbox *u)
         if (!uin->i_nconnect)
         {
             t_float *scalar;
-            s3 = signal_new(dc->dc_vecsize, dc->dc_srate);
+            s3 = signal_new(dc->dc_calcsize, dc->dc_srate);
             /* post("%s: unconnected signal inlet set to zero",
                 class_getname(u->u_obj->ob_pd)); */
-            if (scalar = obj_findsignalscalar(u->u_obj, i))
+            if ((scalar = obj_findsignalscalar(u->u_obj, i)))
                 dsp_add_scalarcopy(scalar, s3->s_vec, s3->s_n);
             else
                 dsp_add_zero(s3->s_vec, s3->s_n);
@@ -781,14 +804,14 @@ static void ugen_doit(t_dspcontext *dc, t_ugenbox *u)
                 signal_new(0, dc->dc_srate);
         }
         else
-            *sig = uout->o_signal = signal_new(dc->dc_vecsize, dc->dc_srate);
+            *sig = uout->o_signal = signal_new(dc->dc_calcsize, dc->dc_srate);
         (*sig)->s_refcount = uout->o_nconnect;
     }
         /* now call the DSP scheduling routine for the ugen.  This
         routine must fill in "borrowed" signal outputs in case it's either
         a subcanvas or a signal inlet. */
     mess1(&u->u_obj->ob_pd, gensym("dsp"), insig);
-    
+
         /* if any output signals aren't connected to anyone, free them
         now; otherwise they'll either get freed when the reference count
         goes back to zero, or even later as explained above. */
@@ -800,14 +823,14 @@ static void ugen_doit(t_dspcontext *dc, t_ugenbox *u)
     }
     if (ugen_loud)
     {
-        if (u->u_nin + u->u_nout == 0) post("put %s %d", 
+        if (u->u_nin + u->u_nout == 0) post("put %s %d",
             class_getname(u->u_obj->ob_pd), ugen_index(dc, u));
-        else if (u->u_nin + u->u_nout == 1) post("put %s %d (%lx)", 
+        else if (u->u_nin + u->u_nout == 1) post("put %s %d (%lx)",
             class_getname(u->u_obj->ob_pd), ugen_index(dc, u), sig[0]);
-        else if (u->u_nin + u->u_nout == 2) post("put %s %d (%lx %lx)", 
+        else if (u->u_nin + u->u_nout == 2) post("put %s %d (%lx %lx)",
             class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
                 sig[0], sig[1]);
-        else post("put %s %d (%lx %lx %lx ...)", 
+        else post("put %s %d (%lx %lx %lx ...)",
             class_getname(u->u_obj->ob_pd), ugen_index(dc, u),
                 sig[0], sig[1], sig[2]);
     }
@@ -821,7 +844,7 @@ static void ugen_doit(t_dspcontext *dc, t_ugenbox *u)
             u2 = oc->oc_who;
             uin = &u2->u_in[oc->oc_inno];
                 /* if there's already someone here, sum the two */
-            if (s2 = uin->i_signal)
+            if ((s2 = uin->i_signal))
             {
                 s1->s_refcount--;
                 s2->s_refcount--;
@@ -865,7 +888,7 @@ static void ugen_doit(t_dspcontext *dc, t_ugenbox *u)
 
 void ugen_done_graph(t_dspcontext *dc)
 {
-    t_ugenbox *u;
+    t_ugenbox *u, *u2;
     t_sigoutlet *uout;
     t_siginlet *uin;
     t_sigoutconnect *oc, *oc2;
@@ -874,7 +897,7 @@ void ugen_done_graph(t_dspcontext *dc)
     t_dspcontext *parent_context = dc->dc_parentcontext;
     t_float parent_srate;
     int parent_vecsize;
-    int period, frequency, vecsize, calcsize;
+    int period, frequency, phase, vecsize, calcsize;
     t_float srate;
     int chainblockbegin;    /* DSP chain onset before block prolog code */
     int chainblockend;      /* and after block epilog code */
@@ -882,7 +905,7 @@ void ugen_done_graph(t_dspcontext *dc)
     int reblock = 0, switched;
     int downsample = 1, upsample = 1;
     /* debugging printout */
-    
+
     if (ugen_loud)
     {
         post("ugen_done_graph...");
@@ -898,7 +921,7 @@ void ugen_done_graph(t_dspcontext *dc)
             }
         }
     }
-    
+
         /* search for an object of class "block~" */
     for (u = dc->dc_ugenlist, blk = 0; u; u = u->u_next)
     {
@@ -941,6 +964,7 @@ void ugen_done_graph(t_dspcontext *dc)
             (parent_vecsize * realoverlap * upsample);
         frequency = (parent_vecsize * realoverlap * upsample)/
             (vecsize * downsample);
+        phase = blk->x_phase;
         srate = parent_srate * realoverlap * upsample / downsample;
         if (period < 1) period = 1;
         if (frequency < 1) frequency = 1;
@@ -948,7 +972,7 @@ void ugen_done_graph(t_dspcontext *dc)
         blk->x_period = period;
         blk->x_phase = dsp_phase & (period - 1);
         if (! parent_context || (realoverlap != 1) ||
-            (vecsize != parent_vecsize) || 
+            (vecsize != parent_vecsize) ||
                 (downsample != 1) || (upsample != 1))
                     reblock = 1;
         switched = blk->x_switched;
@@ -960,6 +984,7 @@ void ugen_done_graph(t_dspcontext *dc)
         calcsize = (parent_context ? parent_context->dc_calcsize : vecsize);
         downsample = upsample = 1;
         period = frequency = 1;
+        phase = 0;
         if (!parent_context) reblock = 1;
         switched = 0;
     }
@@ -968,7 +993,7 @@ void ugen_done_graph(t_dspcontext *dc)
     dc->dc_srate = srate;
     dc->dc_vecsize = vecsize;
     dc->dc_calcsize = calcsize;
-    
+
         /* if we're reblocking or switched, we now have to create output
         signals to fill in for the "borrowed" ones we have now.  This
         is also possibly true even if we're not blocked/switched, in
@@ -1003,29 +1028,29 @@ void ugen_done_graph(t_dspcontext *dc)
         pointers to their corresponding inlets/outlets on the box we're inside,
         if any.  Outlets will also need pointers, unless we're switched, in
         which case outlet epilog code will kick in. */
-        
+
     for (u = dc->dc_ugenlist; u; u = u->u_next)
     {
         t_pd *zz = &u->u_obj->ob_pd;
-        t_signal **outsigs = dc->dc_iosigs;
+        t_signal **insigs = dc->dc_iosigs, **outsigs = dc->dc_iosigs;
         if (outsigs) outsigs += dc->dc_ninlets;
 
         if (pd_class(zz) == vinlet_class)
-            vinlet_dspprolog((struct _vinlet *)zz, 
+            vinlet_dspprolog((struct _vinlet *)zz,
                 dc->dc_iosigs, vecsize, calcsize, dsp_phase, period, frequency,
                     downsample, upsample, reblock, switched);
         else if (pd_class(zz) == voutlet_class)
-            voutlet_dspprolog((struct _voutlet *)zz, 
+            voutlet_dspprolog((struct _voutlet *)zz,
                 outsigs, vecsize, calcsize, dsp_phase, period, frequency,
                     downsample, upsample, reblock, switched);
-    }    
-    chainblockbegin = dsp_chainsize;
+    }
+    chainblockbegin = pd_this->pd_dspchainsize;
 
     if (blk && (reblock || switched))   /* add the block DSP prolog */
     {
         dsp_add(block_prolog, 1, blk);
-        blk->x_chainonset = dsp_chainsize - 1;
-    }   
+        blk->x_chainonset = pd_this->pd_dspchainsize - 1;
+    }
         /* Initialize for sorting */
     for (u = dc->dc_ugenlist; u; u = u->u_next)
     {
@@ -1035,7 +1060,7 @@ void ugen_done_graph(t_dspcontext *dc)
         for (uin = u->u_in, i = u->u_nin; i--; uin++)
             uin->i_ngot = 0, uin->i_signal = 0;
    }
-    
+
         /* Do the sort */
 
     for (u = dc->dc_ugenlist; u; u = u->u_next)
@@ -1051,9 +1076,9 @@ void ugen_done_graph(t_dspcontext *dc)
 
         /* check for a DSP loop, which is evidenced here by the presence
         of ugens not yet scheduled. */
-        
+
     for (u = dc->dc_ugenlist; u; u = u->u_next)
-        if (!u->u_done) 
+        if (!u->u_done)
     {
         t_signal **sigp;
         pd_error(u->u_obj,
@@ -1079,7 +1104,7 @@ void ugen_done_graph(t_dspcontext *dc)
 
     if (blk && (reblock || switched))    /* add block DSP epilog */
         dsp_add(block_epilog, 1, blk);
-    chainblockend = dsp_chainsize;
+    chainblockend = pd_this->pd_dspchainsize;
 
         /* add epilogs for outlets.  */
 
@@ -1090,13 +1115,13 @@ void ugen_done_graph(t_dspcontext *dc)
         {
             t_signal **iosigs = dc->dc_iosigs;
             if (iosigs) iosigs += dc->dc_ninlets;
-            voutlet_dspepilog((struct _voutlet *)zz, 
+            voutlet_dspepilog((struct _voutlet *)zz,
                 iosigs, vecsize, calcsize, dsp_phase, period, frequency,
                     downsample, upsample, reblock, switched);
         }
     }
 
-    chainafterall = dsp_chainsize;
+    chainafterall = pd_this->pd_dspchainsize;
     if (blk)
     {
         blk->x_blocklength = chainblockend - chainblockbegin;
@@ -1108,8 +1133,9 @@ void ugen_done_graph(t_dspcontext *dc)
     {
         t_int *ip;
         if (!dc->dc_parentcontext)
-            for (i = dsp_chainsize, ip = dsp_chain; i--; ip++)
-                post("chain %lx", *ip);
+            for (i = pd_this->pd_dspchainsize, ip = pd_this->pd_dspchain;
+                i--; ip++)
+                    post("chain %lx", *ip);
         post("... ugen_done_graph done.");
     }
         /* now delete everything. */
@@ -1169,8 +1195,8 @@ static void samplerate_tilde_bang(t_samplerate *x)
     while (canvas)
     {
         t_block *b = (t_block *)canvas_getblock(block_class, &canvas);
-        if (b) 
-            srate *= (t_float)(b->x_upsample) / (t_float)(b->x_downsample); 
+        if (b)
+            srate *= (t_float)(b->x_upsample) / (t_float)(b->x_downsample);
     }
     outlet_float(x->x_obj.ob_outlet, srate);
 }
@@ -1192,7 +1218,7 @@ static void samplerate_tilde_setup(void)
 
 /* -------------------- setup routine -------------------------- */
 
-void d_ugen_setup(void) 
+void d_ugen_setup(void)
 {
     block_tilde_setup();
     samplerate_tilde_setup();
diff --git a/pd/src/g_array.c b/pd/src/g_array.c
index 929563a7faa4900015ad0c946683b7f19f0f31dd..a3e2d41b3498be1210418dcac2fdef27fa986f35 100644
--- a/pd/src/g_array.c
+++ b/pd/src/g_array.c
@@ -22,7 +22,7 @@ two, but how? */
     which can't send symbols starting with '$' (because the Pd message
     interpreter would change them!) */
 
-static t_symbol *sharptodollar(t_symbol *s)
+t_symbol *sharptodollar(t_symbol *s)
 {
     if (*s->s_name == '#')
     {
@@ -85,7 +85,7 @@ void array_resize(t_array *x, int n)
     x->a_valid = ++glist_valid;
 }
 
-static void array_resize_and_redraw(t_array *array, t_glist *glist, int n)
+void array_resize_and_redraw(t_array *array, t_glist *glist, int n)
 {
     //fprintf(stderr,"array_resize_and_redraw\n");
     t_array *a2 = array;
@@ -93,10 +93,10 @@ static void array_resize_and_redraw(t_array *array, t_glist *glist, int n)
     while (a2->a_gp.gp_stub->gs_which == GP_ARRAY)
         a2 = a2->a_gp.gp_stub->gs_un.gs_array;
     if (vis)
-        gobj_vis(a2->a_gp.gp_un.gp_gobj, glist, 0);
+        gobj_vis(&a2->a_gp.gp_un.gp_gobj, glist, 0);
     array_resize(array, n);
     if (vis)
-        gobj_vis(a2->a_gp.gp_un.gp_gobj, glist, 1);
+        gobj_vis(&a2->a_gp.gp_un.gp_gobj, glist, 1);
 }
 
 void word_free(t_word *wp, t_template *template);
@@ -264,6 +264,18 @@ int garray_joc(t_garray *x)
     return (x->x_joc);
 }
 
+    /* get a garray's containing glist */
+t_glist *garray_getglist(t_garray *x)
+{
+    return (x->x_glist);
+}
+
+    /* get a garray's associated scalar */
+t_scalar *garray_getscalar(t_garray *x)
+{
+    return (x->x_scalar);
+}
+
     /* helper function for fittograph to see if the same GOP has multiple
         arrays in which case take length of the largest one */
 static int garray_get_largest_array(t_garray *x)
@@ -1403,7 +1415,7 @@ static int garray_click(t_gobj *z, t_glist *glist,
 
 #define ARRAYWRITECHUNKSIZE 1000
 
-static void garray_save(t_gobj *z, t_binbuf *b)
+void garray_save(t_gobj *z, t_binbuf *b)
 {
     int filestyle;
     t_garray *x = (t_garray *)z;
diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c
index b0f6885ae1ab517c5c6d0188dfa06e23128c4f2b..df58baad248aa275a70e2164a3f6fd1aec3efd61 100644
--- a/pd/src/g_canvas.c
+++ b/pd/src/g_canvas.c
@@ -59,6 +59,7 @@ static void canvas_pop(t_canvas *x, t_floatarg fvis);
 static int canvas_should_bind(t_canvas *x);
 static void canvas_bind(t_canvas *x);
 static void canvas_unbind(t_canvas *x);
+void canvas_declare(t_canvas *x, t_symbol *s, int argc, t_atom *argv);
 
 /* --------- functions to handle the canvas environment ----------- */
 
@@ -94,19 +95,19 @@ void canvas_updatewindowlist( void)
     /* add a glist the list of "root" canvases (toplevels without parents.) */
 static void canvas_addtolist(t_canvas *x)
 {
-    x->gl_next = canvas_list;
-    canvas_list = x;
+    x->gl_next = pd_this->pd_canvaslist;
+    pd_this->pd_canvaslist = x;
 }
 
 static void canvas_takeofflist(t_canvas *x)
 {
         /* take it off the window list */
-    if (x == canvas_list) canvas_list = x->gl_next;
+    if (x == pd_this->pd_canvaslist) pd_this->pd_canvaslist = x->gl_next;
     else
     {
         t_canvas *z;
-        for (z = canvas_list; z->gl_next != x; z = z->gl_next)
-            ;
+        for (z = pd_this->pd_canvaslist; z->gl_next != x; z = z->gl_next)
+            if (!z->gl_next) return;
         z->gl_next = x->gl_next;
     }
 }
@@ -424,6 +425,7 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv)
     x->gl_y2 = 1;
     canvas_setbounds(x, xloc, yloc, xloc + width, yloc + height);
     x->gl_owner = owner;
+    x->gl_isclone = 0;
     x->gl_name = (*s->s_name ? s : 
         (canvas_newfilename ? canvas_newfilename : gensym("Pd")));
     canvas_bind(x);
@@ -929,7 +931,7 @@ void canvas_free(t_canvas *x)
     freebytes(x->gl_ylabel, x->gl_nylabels * sizeof(*(x->gl_ylabel)));
     gstub_cutoff(x->gl_stub);
     gfxstub_deleteforkey(x);        /* probably unnecessary */
-    if (!x->gl_owner)
+    if (!x->gl_owner && !x->gl_isclone)
         canvas_takeofflist(x);
     if (x->gl_svg)                   /* for groups, free the data */
         canvas_group_free(x->gl_svg);
@@ -1117,7 +1119,7 @@ void canvas_loadbangsubpatches(t_canvas *x, t_symbol *s)
             zgetfn(&y->g_pd, s))
         {
             //fprintf(stderr,"%lx s:obj_loadbang %s\n",x,s->s_name);
-            pd_vmess(&y->g_pd, s, "");
+            pd_vmess(&y->g_pd, s, "f", (t_floatarg)LB_LOAD);
         }
 }
 
@@ -1167,20 +1169,22 @@ void canvas_initbang(t_canvas *x)
     t_symbol *s = gensym("initbang");
     /* run "initbang" for all subpatches, but NOT for the child abstractions */
     for (y = x->gl_list; y; y = y->g_next)
-      if (pd_class(&y->g_pd) == canvas_class)
+    {
+        if (pd_class(&y->g_pd) == canvas_class)
         {
-          if (!canvas_isabstraction((t_canvas *)y))
-            canvas_initbang((t_canvas *)y);
+            if (!canvas_isabstraction((t_canvas *)y))
+                canvas_initbang((t_canvas *)y);
         }
+    }
 
     /* call the initbang()-method for objects that have one */
     for (y = x->gl_list; y; y = y->g_next)
-      {
+    {
         if ((pd_class(&y->g_pd) != canvas_class) && zgetfn(&y->g_pd, s))
-          {
-            pd_vmess(&y->g_pd, s, "");
-          }
-      }
+        {
+            pd_vmess(&y->g_pd, s, "f", (t_floatarg)LB_INIT);
+        }
+    }
 }
 /* JMZ:
  * closebang is emitted before the canvas is destroyed
@@ -1196,12 +1200,12 @@ void canvas_closebang(t_canvas *x)
      * from g_graph:glist_delete()
      */
     for (y = x->gl_list; y; y = y->g_next)
-      {
+    {
         if ((pd_class(&y->g_pd) != canvas_class) && zgetfn(&y->g_pd, s))
-          {
-            pd_vmess(&y->g_pd, s, "");
-          }
-      }
+        {
+            pd_vmess(&y->g_pd, s, "f", (t_floatarg)LB_CLOSE);
+        }
+    }
 }
 
 // we use this function to check if the canvas that has sent out the <config>
@@ -1443,16 +1447,6 @@ static void canvas_unbind(t_canvas *x)
         pd_unbind(&x->gl_pd, canvas_makebindsym(x->gl_name));
 }
 
-    /* return true if the "canvas" object is a "table". */
-int canvas_istable(t_canvas *x)
-{
-    t_atom *argv = (x->gl_obj.te_binbuf? binbuf_getvec(x->gl_obj.te_binbuf):0);
-    int argc = (x->gl_obj.te_binbuf? binbuf_getnatom(x->gl_obj.te_binbuf) : 0);
-    int istable = (argc && argv[0].a_type == A_SYMBOL &&
-        argv[0].a_w.w_symbol == gensym("table"));
-    return (istable);
-}
-
     /* return true if the "canvas" object should be treated as a text
     object.  This is true for abstractions but also for "table"s... */
 /* JMZ: add a flag to gop-abstractions to hide the title */
@@ -1495,7 +1489,7 @@ void ugen_done_graph(t_dspcontext *dc);
     canvases, but is also called from the "dsp" method for sub-
     canvases, which are treated almost like any other tilde object.  */
 
-static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp)
+void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp)
 {
     t_linetraverser t;
     t_outconnect *oc;
@@ -1548,25 +1542,29 @@ static void canvas_dsp(t_canvas *x, t_signal **sp)
 static void canvas_start_dsp(void)
 {
     t_canvas *x;
-    if (canvas_dspstate)
+    if (pd_this->pd_dspstate)
         ugen_stop();
     else
         gui_vmess("gui_pd_dsp", "i", 1);
     ugen_start();
-    
-    for (x = canvas_list; x; x = x->gl_next)
+
+    for (x = pd_getcanvaslist(); x; x = x->gl_next)
         canvas_dodsp(x, 1, 0);
     
-    canvas_dspstate = 1;
+    canvas_dspstate = pd_this->pd_dspstate = 1;
+    if (gensym("pd-dsp-started")->s_thing)
+        pd_bang(gensym("pd-dsp-started")->s_thing);
 }
 
 static void canvas_stop_dsp(void)
 {
-    if (canvas_dspstate)
+    if (pd_this->pd_dspstate)
     {
         ugen_stop();
         gui_vmess("gui_pd_dsp", "i", 0);
-        canvas_dspstate = 0;
+        canvas_dspstate = pd_this->pd_dspstate = 0;
+        if (gensym("pd-dsp-stopped")->s_thing)
+            pd_bang(gensym("pd-dsp-stopped")->s_thing);
     }
 }
 
@@ -1577,8 +1575,8 @@ static void canvas_stop_dsp(void)
 
 int canvas_suspend_dsp(void)
 {
-    int rval = canvas_dspstate;
     //fprintf(stderr,"canvas_suspend_dsp %d\n", rval);
+    int rval = pd_this->pd_dspstate;
     if (rval) canvas_stop_dsp();
     return (rval);
 }
@@ -1592,27 +1590,36 @@ void canvas_resume_dsp(int oldstate)
     /* this is equivalent to suspending and resuming in one step. */
 void canvas_update_dsp(void)
 {
-    if (canvas_dspstate) canvas_start_dsp();
+    if (pd_this->pd_dspstate) canvas_start_dsp();
 }
 
+/* the "dsp" message to pd starts and stops DSP computation, and, if
+appropriate, also opens and closes the audio device.  On exclusive-access
+APIs such as ALSA, MMIO, and ASIO (I think) it's appropriate to close the
+audio devices when not using them; but jack behaves better if audio I/O
+simply keeps running.  This is wasteful of CPU cycles but we do it anyway
+and can perhaps regard this is a design flaw in jack that we're working around
+here.  The function audio_shouldkeepopen() is provided by s_audio.c to tell
+us that we should elide the step of closing audio when DSP is turned off.*/
+
 void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv)
 {
     int newstate;
     if (argc)
     {
         newstate = atom_getintarg(0, argc, argv);
-        if (newstate && !canvas_dspstate)
+        if (newstate && !pd_this->pd_dspstate)
         {
             sys_set_audio_state(1);
             canvas_start_dsp();
         }
-        else if (!newstate && canvas_dspstate)
+        else if (!newstate && pd_this->pd_dspstate)
         {
             canvas_stop_dsp();
             sys_set_audio_state(0);
         }
     }
-    else post("dsp state %d", canvas_dspstate);
+    else post("dsp state %d", pd_this->pd_dspstate);
 }
 
 void *canvas_getblock(t_class *blockclass, t_canvas **canvasp)
@@ -1718,7 +1725,6 @@ saved,  we throw early messages to the canvas to set the environment
 before any objects are created in it. */
 
 static t_class *declare_class;
-extern t_class *import_class;
 
 typedef struct _declare
 {
@@ -1733,6 +1739,12 @@ static void *declare_new(t_symbol *s, int argc, t_atom *argv)
     x->x_useme = 1;
     x->x_canvas = canvas_getcurrent();
         /* LATER update environment and/or load libraries */
+    if (!x->x_canvas->gl_loading)
+    {
+        /* the object is created by the user (not by loading a patch),
+         * so update canvas's properties on the fly */
+        canvas_declare(x->x_canvas, s, argc, argv);
+    }
     return (x);
 }
 
@@ -1754,23 +1766,12 @@ void canvas_savedeclarationsto(t_canvas *x, t_binbuf *b)
             binbuf_addbinbuf(b, ((t_declare *)y)->x_obj.te_binbuf);
             binbuf_addv(b, ";");
         }
-        else if (pd_class(&y->g_pd) == import_class)
-        {
-            int i, argc;
-            t_atom *argv;
-            binbuf_addv(b, "s", gensym("#X"));
-            binbuf_addv(b, "s", gensym("declare"));
-            argc = binbuf_getnatom(((t_object *)y)->te_binbuf) - 1;
-            argv = binbuf_getvec(((t_object *)y)->te_binbuf) + 1;
-            for(i = 0; i < argc; ++i)
-            {
-                binbuf_addv(b, "s", gensym("-lib"));
-                binbuf_add(b, 1, argv + i);
-            }
-            binbuf_addv(b, ";");
-        }
-        else if (pd_class(&y->g_pd) == canvas_class)
-            canvas_savedeclarationsto((t_canvas *)y, b);
+            /* before 0.47 we also allowed abstractions to write out to the
+            parent's declarations; now we only allow non-abstraction subpatches
+            to do so. */
+        else if (pd_checkglist(&y->g_pd) &&
+            (pd_compatibilitylevel < 47 || !canvas_isabstraction((t_canvas *)y)))
+                canvas_savedeclarationsto((t_canvas *)y, b);
     }
 }
 
@@ -1782,15 +1783,99 @@ static void canvas_completepath(char *from, char *to, int bufsize)
     }
     else
     {   // if not absolute path, append Pd lib dir
-        strncpy(to, sys_libdir->s_name, bufsize-4);
-        to[bufsize-3] = '\0';
-        strcat(to, "/");
+        strncpy(to, sys_libdir->s_name, bufsize-10);
+        to[bufsize-9] = '\0';
+        strcat(to, "/extra/");
     }
     strncat(to, from, bufsize-strlen(to));
     to[bufsize-1] = '\0';
 }
 
-static void canvas_declare(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
+/* maybe we should rename check_exists() to sys_access() and move it to s_path */
+#ifdef _WIN32
+static int check_exists(const char*path)
+{
+    char pathbuf[MAXPDSTRING];
+    wchar_t ucs2path[MAXPDSTRING];
+    sys_bashfilename(path, pathbuf);
+    u8_utf8toucs2(ucs2path, MAXPDSTRING, pathbuf, MAXPDSTRING-1);
+    return (0 ==  _waccess(ucs2path, 0));
+}
+#else
+#include <unistd.h>
+static int check_exists(const char*path)
+{
+    char pathbuf[MAXPDSTRING];
+    sys_bashfilename(path, pathbuf);
+    return (0 == access(pathbuf, 0));
+}
+#endif
+
+//extern t_namelist *sys_staticpath;
+
+static void canvas_stdpath(t_canvasenvironment *e, char *stdpath)
+{
+    t_namelist*nl;
+    char strbuf[MAXPDSTRING];
+    if (sys_isabsolutepath(stdpath))
+    {
+        e->ce_path = namelist_append(e->ce_path, stdpath, 0);
+        return;
+    }
+    /* strip    "extra/"-prefix */
+    if (!strncmp("extra/", stdpath, 6))
+        stdpath+=6;
+
+        /* prefix full pd-path (including extra) */
+    canvas_completepath(stdpath, strbuf, MAXPDSTRING);
+    if (check_exists(strbuf))
+    {
+        e->ce_path = namelist_append(e->ce_path, strbuf, 0);
+        return;
+    }
+    /* check whether the given subdir is in one of the standard-paths */
+    for (nl=pd_extrapath; nl; nl=nl->nl_next)
+    {
+        snprintf(strbuf, MAXPDSTRING-1, "%s/%s/", nl->nl_string, stdpath);
+        strbuf[MAXPDSTRING-1]=0;
+        if (check_exists(strbuf))
+        {
+            e->ce_path = namelist_append(e->ce_path, strbuf, 0);
+            return;
+        }
+    }
+}
+static void canvas_stdlib(t_canvasenvironment *e, char *stdlib)
+{
+    t_namelist*nl;
+    char strbuf[MAXPDSTRING];
+    if (sys_isabsolutepath(stdlib))
+    {
+        sys_load_lib(0, stdlib);
+        return;
+    }
+
+        /* strip    "extra/"-prefix */
+    if (!strncmp("extra/", stdlib, 6))
+        stdlib+=6;
+
+        /* prefix full pd-path (including extra) */
+    canvas_completepath(stdlib, strbuf, MAXPDSTRING);
+    if (sys_load_lib(0, strbuf))
+        return;
+
+    /* check whether the given library is located in one of the standard-paths */
+    for (nl=pd_extrapath; nl; nl=nl->nl_next)
+    {
+        snprintf(strbuf, MAXPDSTRING-1, "%s/%s", nl->nl_string, stdlib);
+        strbuf[MAXPDSTRING-1]=0;
+        if (sys_load_lib(0, strbuf))
+            return;
+    }
+}
+
+
+void canvas_declare(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
 {
     int i;
     t_canvasenvironment *e = canvas_getenv(x);
@@ -1801,19 +1886,16 @@ static void canvas_declare(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
 #endif
     for (i = 0; i < argc; i++)
     {
-        char strbuf[FILENAME_MAX];
         char *flag = atom_getsymbolarg(i, argc, argv)->s_name;
         if ((argc > i+1) && !strcmp(flag, "-path"))
         {
-            e->ce_path = namelist_append(e->ce_path, 
+            e->ce_path = namelist_append(e->ce_path,
                 atom_getsymbolarg(i+1, argc, argv)->s_name, 0);
             i++;
         }
         else if ((argc > i+1) && !strcmp(flag, "-stdpath"))
         {
-            canvas_completepath(atom_getsymbolarg(i+1, argc, argv)->s_name,
-                strbuf, FILENAME_MAX);
-            e->ce_path = namelist_append(e->ce_path, strbuf, 0);
+            canvas_stdpath(e, atom_getsymbolarg(i+1, argc, argv)->s_name);
             i++;
         }
         else if ((argc > i+1) && !strcmp(flag, "-lib"))
@@ -1823,15 +1905,36 @@ static void canvas_declare(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
         }
         else if ((argc > i+1) && !strcmp(flag, "-stdlib"))
         {
-            canvas_completepath(atom_getsymbolarg(i+1, argc, argv)->s_name,
-                strbuf, FILENAME_MAX);
-            sys_load_lib(0, strbuf);
+            canvas_stdlib(e, atom_getsymbolarg(i+1, argc, argv)->s_name);
             i++;
         }
         else post("declare: %s: unknown declaration", flag);
     }
 }
 
+typedef struct _canvasopen
+{
+    const char *name;
+    const char *ext;
+    char *dirresult;
+    char **nameresult;
+    unsigned int size;
+    int bin;
+    int fd;
+} t_canvasopen;
+
+static int canvas_open_iter(const char *path, t_canvasopen *co)
+{
+    int fd;
+    if ((fd = sys_trytoopenone(path, co->name, co->ext,
+        co->dirresult, co->nameresult, co->size, co->bin)) >= 0)
+    {
+        co->fd = fd;
+        return 0;
+    }
+    return 1;
+}
+
     /* utility function to read a file, looking first down the canvas's search
     path (set with "declare" objects in the patch and recursively in calling
     patches), then down the system one.  The filename is the concatenation of
@@ -1841,28 +1944,111 @@ static void canvas_declare(t_canvas *x, t_symbol *s, int argc, t_atom *argv)
     be "size" bytes.  The "nameresult" pointer will be set somewhere in
     the interior of "dirresult" and will give the file basename (with
     slashes trimmed).  If "bin" is set a 'binary' open is
-    attempted, otherwise ASCII (this only matters on Microsoft.) 
+    attempted, otherwise ASCII (this only matters on Microsoft.)
     If "x" is zero, the file is sought in the directory "." or in the
     global path.*/
-
 int canvas_open(t_canvas *x, const char *name, const char *ext,
     char *dirresult, char **nameresult, unsigned int size, int bin)
+{
+    t_namelist *nl, thislist;
+    int fd = -1;
+    char listbuf[MAXPDSTRING];
+    t_canvas *y;
+    t_canvasopen co;
+
+        /* first check if "name" is absolute (and if so, try to open) */
+    if (sys_open_absolute(name, ext, dirresult, nameresult, size, bin, &fd))
+        return (fd);
+        /* otherwise "name" is relative; iterate over all the search-paths */
+    co.name = name;
+    co.ext = ext;
+    co.dirresult = dirresult;
+    co.nameresult = nameresult;
+    co.size = size;
+    co.bin = bin;
+    co.fd = -1;
+
+    canvas_path_iterate(x, (t_canvas_path_iterator)canvas_open_iter, &co);
+
+    return (co.fd);
+}
+
+int canvas_path_iterate(t_canvas*x, t_canvas_path_iterator fun, void *user_data)
+{
+    t_canvas *y = 0;
+    t_namelist *nl = 0;
+    int count = 0;
+    if (!fun)
+        return 0;
+        /* iterate through canvas-local paths */
+    for (y = x; y; y = y->gl_owner)
+        if (y->gl_env)
+    {
+        t_canvas *x2 = x;
+        char *dir;
+        while (x2 && x2->gl_owner)
+            x2 = x2->gl_owner;
+        dir = (x2 ? canvas_getdir(x2)->s_name : ".");
+        for (nl = y->gl_env->ce_path; nl; nl = nl->nl_next)
+        {
+            char realname[MAXPDSTRING];
+            if (sys_isabsolutepath(nl->nl_string))
+                realname[0] = '\0';
+            else
+            {   /* if not absolute path, append Pd lib dir */
+                strncpy(realname, dir, MAXPDSTRING);
+                realname[MAXPDSTRING-3] = 0;
+                strcat(realname, "/");
+            }
+            strncat(realname, nl->nl_string, MAXPDSTRING-strlen(realname));
+            realname[MAXPDSTRING-1] = 0;
+            if (!fun(realname, user_data))
+                return count+1;
+            count++;
+        }
+    }
+    /* try canvas dir */
+    if (!fun((x ? canvas_getdir(x)->s_name : "."), user_data))
+        return count+1;
+    count++;
+
+    /* now iterate through the global paths */
+    for (nl = sys_searchpath; nl; nl = nl->nl_next)
+    {
+        if (!fun(nl->nl_string, user_data))
+            return count+1;
+        count++;
+    }
+    /* and the default paths */
+    if (sys_usestdpath)
+        for (nl = pd_extrapath; nl; nl = nl->nl_next)
+        {
+            if (!fun(nl->nl_string, user_data))
+                return count+1;
+            count++;
+        }
+
+    return count;
+}
+
+/*int canvas_open(t_canvas *x, const char *name, const char *ext,
+    char *dirresult, char **nameresult, unsigned int size, int bin)
 {
     int fd = -1;
     int result = 0;
     t_canvas *y;
     char final_name[FILENAME_MAX];
 
-    /* first check for @pd_extra (and later possibly others)
-       and ~/ and replace */
+    // first check for @pd_extra (and later possibly others)
+    // and ~/ and replace
     sys_expandpathelems(name, final_name);
 
-    /* first check if "name" is absolute (and if so, try to open) */
+    // first check if "name" is absolute (and if so, try to open)
     if (sys_open_absolute(final_name, ext, dirresult, nameresult, size, bin, &fd))
         return (fd);
     
-    /* otherwise "name" is relative; start trying in directories named
-       in this and parent environments */
+    // otherwise "name" is relative; start trying in directories named
+    // in this and parent environments
     for (y = x; y; y = y->gl_owner)
         if (y->gl_env)
         {
@@ -1880,7 +2066,7 @@ int canvas_open(t_canvas *x, const char *name, const char *ext,
                     realname[0] = '\0';
                 }
                 else
-                {   /* if not absolute path, append Pd lib dir */
+                {   // if not absolute path, append Pd lib dir
                     strncpy(realname, dir, FILENAME_MAX);
                     realname[FILENAME_MAX-3] = 0;
                     strcat(realname, "/");
@@ -1895,7 +2081,7 @@ int canvas_open(t_canvas *x, const char *name, const char *ext,
     result = open_via_path((x ? canvas_getdir(x)->s_name : "."),
         final_name, ext, dirresult, nameresult, size, bin);
     return(result);
-}
+}*/
 
 extern t_symbol *last_typedmess; // see g_readwrite.c for the explanation of this ugly hack
 
@@ -2192,6 +2378,17 @@ void canvasgop__motionhook(t_scalehandle *sh, t_floatarg mouse_x,
     }
 }
 
+extern t_class *array_define_class;     /* LATER datum class too */
+
+    /* check if a pd can be treated as a glist - true if we're of any of
+    the glist classes, which all have 'glist' as the first item in struct */
+t_glist *pd_checkglist(t_pd *x)
+{
+    if (*x == canvas_class || *x == array_define_class)
+        return ((t_canvas *)x);
+    else return (0);
+}
+
 /* ------------------------------- setup routine ------------------------ */
 
     /* why are some of these "glist" and others "canvas"? */
@@ -2338,3 +2535,26 @@ void g_canvas_setup(void)
     g_editor_setup();
     g_readwrite_setup();
 }
+
+    /* functions to add basic gui (e.g., clicking but not editing) to things
+    based on canvases that aren't editable, like "array define" object */
+void canvas_editor_for_class(t_class *c);
+void g_graph_setup_class(t_class *c);
+void canvas_readwrite_for_class(t_class *c);
+
+void canvas_add_for_class(t_class *c)
+{
+    class_addmethod(c, (t_method)canvas_restore,
+        gensym("restore"), A_GIMME, 0);
+    class_addmethod(c, (t_method)canvas_click,
+        gensym("click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+    class_addmethod(c, (t_method)canvas_dsp,
+        gensym("dsp"), A_CANT, 0);
+    class_addmethod(c, (t_method)canvas_map,
+        gensym("map"), A_FLOAT, A_NULL);
+    class_addmethod(c, (t_method)canvas_setbounds,
+        gensym("setbounds"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+    canvas_editor_for_class(c);
+    canvas_readwrite_for_class(c);
+    /* g_graph_setup_class(c); */
+}