Update of /cvsroot/pure-data/externals/miXed/toxy
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5003/toxy
Modified Files:
build_counter widget.c widgettype.c widgettype.h
Log Message:
widget: redefine, version control, better kb
Index: widgettype.c
===================================================================
RCS file: /cvsroot/pure-data/externals/miXed/toxy/widgettype.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -C2 -d -r1.9 -r1.10
*** widgettype.c 10 Dec 2004 20:47:06 -0000 1.9
--- widgettype.c 21 Dec 2004 11:32:13 -0000 1.10
***************
*** 38,42 ****
t_scriptlet *mw_setupscript;
t_dict *mw_typemap;
- t_widgettype *mw_mastertype; /* contains master initializer */
t_widgettype *mw_parsedtype; /* the type currently parsed, if loading */
t_binbuf *mw_bb; /* auxiliary, LATER remove */
--- 38,41 ----
***************
*** 59,62 ****
--- 58,76 ----
}
+ #if 0
+ /* only for debugging (never call, unless certain that nobody references wt) */
+ static void widgettype_free(t_masterwidget *mw, t_widgettype *wt)
+ {
+ fprintf(stderr, "widgettype free... ");
+ dict_unbind(mw->mw_typemap, (t_pd *)wt, wt->wt_typekey);
+ props_freeall(wt->wt_options);
+ scriptlet_free(wt->wt_iniscript);
+ scriptlet_free(wt->wt_newscript);
+ scriptlet_free(wt->wt_freescript);
+ pd_free((t_pd *)wt);
+ fprintf(stderr, "done\n");
+ }
+ #endif
+
static t_widgettype *widgettype_new(t_masterwidget *mw,
char *typ, char *cls, char *pkg)
***************
*** 102,119 ****
if (caller == (t_pd *)mw)
{ /* setup.wid or built-in defaults */
! if (mw->mw_mastertype)
! { /* no master type in setup.wid, extracting built-in one */
! if (typeval != mw->mw_mastertype)
! return (SCRIPTLET_LOCK);
! }
! else
{
! if (typeval)
! {
! /* LATER rethink */
! loud_warning((t_pd *)mw, 0, "redefinition of '%s'\
in \"%s.wid\" file, ignored", buf, rc);
! return (SCRIPTLET_LOCK);
! }
}
}
--- 116,125 ----
if (caller == (t_pd *)mw)
{ /* setup.wid or built-in defaults */
! if (typeval)
{
! /* LATER rethink */
! loud_warning((t_pd *)mw, 0, "redefinition of '%s'\
in \"%s.wid\" file, ignored", buf, rc);
! return (SCRIPTLET_LOCK);
}
}
***************
*** 197,249 ****
}
! t_widgettype *widgettype_get(t_symbol *s)
{
! t_widgettype *wt;
! /* Design decision: setup.wid defs are NOT overridden by <type>.wid
! (sacrificing flexibility for feature stability). */
! if (wt = (t_widgettype *)dict_firstvalue(masterwidget->mw_typemap,
! dict_key(masterwidget->mw_typemap,
! s->s_name), 0))
! masterwidget->mw_parsedtype = 0;
! else
! {
! /* first instance of a type not defined in setup.wid */
! wt = widgettype_new(masterwidget, s->s_name, 0, 0);
! masterwidget->mw_parsedtype = wt;
! }
! if (masterwidget->mw_parsedtype)
{
- /* <type>.wid searched in the current patch's dir + pd_path,
- but not in `pwd` */
- t_scriptlet *mwsp =
- scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target,
- masterwidget->mw_target, 0,
- canvas_getcurrent(), 0);
- if (scriptlet_rcload(mwsp, (t_pd *)wt,
- s->s_name, ".wid", 0, masterwidget_cmnthook)
- == SCRIPTLET_OK)
- {
#ifdef WIDGETTYPE_VERBOSE
! post("using a separate %s's definition file", s->s_name);
#endif
! if (!scriptlet_isempty(mwsp))
{
! t_scriptlet *sp =
! scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target,
! masterwidget->mw_target, 0, 0, 0);
! if (scriptlet_evaluate(mwsp, sp, 0, 0, 0, 0))
! {
! scriptlet_push(sp);
! scriptlet_append(masterwidget->mw_setupscript, mwsp);
! }
! else bug("widgettype_get");
! scriptlet_free(sp);
}
}
! scriptlet_free(mwsp);
}
return (wt);
}
int widgettype_isdefined(t_widgettype *wt)
{
--- 203,274 ----
}
! static int widgettype_doload(t_widgettype *wt, t_symbol *s)
{
! int result = 0;
! /* <type>.wid searched in the current patch's dir + pd_path,
! but not in `pwd` */
! t_scriptlet *mwsp =
! scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target,
! masterwidget->mw_target, 0, canvas_getcurrent(), 0);
! masterwidget->mw_parsedtype = wt;
!
! if (scriptlet_rcload(mwsp, (t_pd *)wt,
! s->s_name, ".wid", 0, masterwidget_cmnthook)
! == SCRIPTLET_OK)
{
#ifdef WIDGETTYPE_VERBOSE
! post("using a separate %s's definition file", s->s_name);
#endif
! if (!scriptlet_isempty(mwsp))
! {
! t_scriptlet *sp =
! scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target,
! masterwidget->mw_target, 0, 0, 0);
! if (scriptlet_evaluate(mwsp, sp, 0, 0, 0, 0))
{
! scriptlet_push(sp);
! scriptlet_append(masterwidget->mw_setupscript, mwsp);
}
+ else bug("widgettype_doload");
+ scriptlet_free(sp);
}
! result = 1;
! }
! scriptlet_free(mwsp);
! return (result);
! }
!
! t_widgettype *widgettype_find(t_symbol *s)
! {
! return ((t_widgettype *)dict_firstvalue(masterwidget->mw_typemap,
! dict_key(masterwidget->mw_typemap,
! s->s_name), 0));
! }
!
! t_widgettype *widgettype_get(t_symbol *s)
! {
! t_widgettype *wt = widgettype_find(s);
! /* Design decision: default widget definitions are NOT implicitly
! overridden by <type>.wid (sacrificing flexibility for feature
! stability). */
! if (!wt)
! {
! /* first instance of a type not defined in setup.wid */
! wt = widgettype_new(masterwidget, s->s_name, 0, 0);
! widgettype_doload(wt, s);
}
return (wt);
}
+ t_widgettype *widgettype_reload(t_symbol *s)
+ {
+ t_widgettype *wt = widgettype_find(s);
+ if (!wt)
+ /* first instance of a type not defined in setup.wid */
+ wt = widgettype_new(masterwidget, s->s_name, 0, 0);
+ widgettype_doload(wt, s);
+ return (wt);
+ }
+
int widgettype_isdefined(t_widgettype *wt)
{
***************
*** 320,329 ****
}
- char *masterwidget_getinitializer(int *szp)
- {
- return (scriptlet_getcontents(masterwidget->mw_mastertype->wt_iniscript,
- szp));
- }
-
char *masterwidget_getcontents(int *szp)
{
--- 345,348 ----
***************
*** 331,346 ****
}
- int masterwidget_ievaluate(t_scriptlet *outsp, int visedonly,
- int ac, t_atom *av, t_props *argprops)
- {
- return (scriptlet_evaluate(masterwidget->mw_mastertype->wt_iniscript,
- outsp, visedonly, ac, av, argprops));
- }
-
void masterwidget_validate(void)
{
int rcresult;
- t_symbol *typekey;
- t_widgettype *typeval;
char buf[MAXPDSTRING];
if (masterwidget)
--- 350,356 ----
***************
*** 360,364 ****
masterwidget->mw_bb = binbuf_new();
masterwidget->mw_parsedtype = 0;
- masterwidget->mw_mastertype = 0;
rcresult =
--- 370,373 ----
***************
*** 373,394 ****
else
{
loud_warning((t_pd *)masterwidget, 0,
! "no file 'setup.wid'... using built-in defaults");
}
! typekey = dict_key(masterwidget->mw_typemap, "master");
! if ((typeval = (t_widgettype *)dict_firstvalue(masterwidget->mw_typemap,
! typekey, 0))
! && !scriptlet_isempty(masterwidget->mw_setupscript))
! {
! masterwidget->mw_mastertype = typeval;
rcresult = SCRIPTLET_OK;
- }
else if (rcresult == SCRIPTLET_OK)
{
! /* LATER think about adding only missing part to existing local defs */
! loud_warning((t_pd *)masterwidget, 0, "%s missing in file 'setup.wid'",
! (typeval ? "setup definitions" : "master initializer"));
! masterwidget->mw_mastertype =
! widgettype_new(masterwidget, "master", 0, 0);
scriptlet_reset(masterwidget->mw_setupscript);
rcresult =
--- 382,407 ----
else
{
+ char *msg;
+ if (rcresult == SCRIPTLET_NOFILE)
+ msg = "no";
+ else if (rcresult == SCRIPTLET_BADFILE)
+ msg = "corrupt";
+ else if (rcresult == SCRIPTLET_NOVERSION)
+ msg = "unknown version of";
+ else if (rcresult == SCRIPTLET_OLDERVERSION)
+ msg = "obsolete";
+ else if (rcresult == SCRIPTLET_NEWERVERSION)
+ msg = "incompatible";
+ else
+ msg = "cannot use";
loud_warning((t_pd *)masterwidget, 0,
! "%s file 'setup.wid'... using built-in defaults", msg);
}
! if (!scriptlet_isempty(masterwidget->mw_setupscript))
rcresult = SCRIPTLET_OK;
else if (rcresult == SCRIPTLET_OK)
{
! loud_warning((t_pd *)masterwidget, 0,
! "missing setup definitions in file 'setup.wid'");
scriptlet_reset(masterwidget->mw_setupscript);
rcresult =
***************
*** 398,402 ****
else
{
! bug("masterwidget_initialize 1");
rcresult = SCRIPTLET_BADFILE;
}
--- 411,415 ----
else
{
! bug("masterwidget_validate 1");
rcresult = SCRIPTLET_BADFILE;
}
***************
*** 409,413 ****
scriptlet_push(sp);
else
! bug("masterwidget_initialize 2");
scriptlet_free(sp);
}
--- 422,426 ----
scriptlet_push(sp);
else
! bug("masterwidget_validate 2");
scriptlet_free(sp);
}
Index: widgettype.h
===================================================================
RCS file: /cvsroot/pure-data/externals/miXed/toxy/widgettype.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** widgettype.h 10 Dec 2004 20:47:06 -0000 1.4
--- widgettype.h 21 Dec 2004 11:32:13 -0000 1.5
***************
*** 16,20 ****
--- 16,22 ----
#define t_masterwidget struct _masterwidget
+ t_widgettype *widgettype_find(t_symbol *s);
t_widgettype *widgettype_get(t_symbol *s);
+ t_widgettype *widgettype_reload(t_symbol *s);
int widgettype_isdefined(t_widgettype *wt);
t_symbol *widgettype_tkclass(t_widgettype *wt);
***************
*** 34,41 ****
void widgettype_setup(void);
- char *masterwidget_getinitializer(int *szp);
char *masterwidget_getcontents(int *szp);
- int masterwidget_ievaluate(t_scriptlet *outsp, int visedonly,
- int ac, t_atom *av, t_props *argprops);
void masterwidget_validate(void);
--- 36,40 ----
Index: build_counter
===================================================================
RCS file: /cvsroot/pure-data/externals/miXed/toxy/build_counter,v
retrieving revision 1.11
retrieving revision 1.12
diff -C2 -d -r1.11 -r1.12
*** build_counter 10 Dec 2004 20:47:06 -0000 1.11
--- build_counter 21 Dec 2004 11:32:13 -0000 1.12
***************
*** 1,7 ****
#define TOXY_VERSION "0.1"
#define TOXY_RELEASE "alpha"
! #define TOXY_BUILD 13
#if 0
! TOXY_SNAPSHOT = 0.1-alpha13
#endif
--- 1,7 ----
#define TOXY_VERSION "0.1"
#define TOXY_RELEASE "alpha"
! #define TOXY_BUILD 14
#if 0
! TOXY_SNAPSHOT = 0.1-alpha14
#endif
Index: widget.c
===================================================================
RCS file: /cvsroot/pure-data/externals/miXed/toxy/widget.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -C2 -d -r1.11 -r1.12
*** widget.c 10 Dec 2004 20:47:06 -0000 1.11
--- widget.c 21 Dec 2004 11:32:13 -0000 1.12
***************
*** 24,27 ****
--- 24,28 ----
//#define WIDGET_DEBUG
//#define TOW_DEBUG
+ //#define WIDGET_PROFILE
#endif
***************
*** 94,98 ****
t_symbol *x_type; /* 2nd creation arg: widget's type */
t_symbol *x_name; /* 3rd creation arg: widget's name */
- t_widgettype *x_typedef;
t_widgetentry *x_widgetlist;
struct _tow *x_next; /* next in the global towlist */
--- 95,98 ----
***************
*** 114,117 ****
--- 114,180 ----
static t_symbol *widgetps_atrestore;
+ #ifdef WIDGET_PROFILE
+ static double widgetprofile_lasttime;
+
+ static double widgetprofile_step(void)
+ {
+ double newtime = sys_getrealtime(),
+ delta = newtime - widgetprofile_lasttime;
+ widgetprofile_lasttime = newtime;
+ return (delta);
+ }
+
+ static int widgetprofile_handlerphase = 0;
+ static double widgetprofile_handlerslice[3];
+ static double widgetprofile_handlerdelta[2];
+
+ static void widgetprofile_handler_enter(void)
+ {
+ widgetprofile_handlerphase = 1;
+ widgetprofile_step();
+ }
+
+ static void widgetprofile_handler_eval(void)
+ {
+ widgetprofile_handlerphase = 2;
+ widgetprofile_handlerdelta[0] = widgetprofile_step();
+ }
+
+ static void widgetprofile_handler_push(void)
+ {
+ widgetprofile_handlerphase = 3;
+ widgetprofile_handlerdelta[1] = widgetprofile_step();
+ }
+
+ static void widgetprofile_handler_quit(void)
+ {
+ if (widgetprofile_handlerphase == 3)
+ {
+ widgetprofile_handlerslice[2] += widgetprofile_step();
+ widgetprofile_handlerslice[0] += widgetprofile_handlerdelta[0];
+ widgetprofile_handlerslice[1] += widgetprofile_handlerdelta[1];
+ }
+ widgetprofile_handlerphase = 0;
+ }
+
+ static void widget_profile(t_widget *x)
+ {
+ fputs("total time in ms:\n", stderr);
+ fprintf(stderr, "handler get %g\n", widgetprofile_handlerslice[0] * 1000.);
+ fprintf(stderr, "handler eval %g\n", widgetprofile_handlerslice[1] * 1000.);
+ fprintf(stderr, "handler push %g\n", widgetprofile_handlerslice[2] * 1000.);
+ }
+
+ #define WIDGETPROFILE_HANDLER_ENTER widgetprofile_handler_enter()
+ #define WIDGETPROFILE_HANDLER_EVAL widgetprofile_handler_eval()
+ #define WIDGETPROFILE_HANDLER_PUSH widgetprofile_handler_push()
+ #define WIDGETPROFILE_HANDLER_QUIT widgetprofile_handler_quit()
+ #else
+ #define WIDGETPROFILE_HANDLER_ENTER
+ #define WIDGETPROFILE_HANDLER_EVAL
+ #define WIDGETPROFILE_HANDLER_PUSH
+ #define WIDGETPROFILE_HANDLER_QUIT
+ #endif
+
static char *widget_propsresolver(t_pd *owner, int ac, t_atom *av)
{
***************
*** 223,226 ****
--- 286,292 ----
newt->te_xpix = oldt->te_xpix;
newt->te_ypix = oldt->te_ypix;
+ outlet_new(newt, &s_);
+ inlet_new(newt, &newt->ob_pd, &s_, &s_);
+ /* FIXME preserve connections */
glist_add(x->x_glist, &newt->te_g);
if (glist_isvisible(x->x_glist))
***************
*** 323,330 ****
static void widget_pushinits(t_widget *x)
{
- if (masterwidget_ievaluate(x->x_transient, 0, 0, 0, x->x_arguments))
- scriptlet_vpush(x->x_transient, "masterinit");
- else
- bug("widget_pushinits (master)");
if (widgettype_isdefined(x->x_typedef))
{
--- 389,392 ----
***************
*** 585,588 ****
--- 647,651 ----
t_symbol *sel;
char buf[MAXPDSTRING];
+ WIDGETPROFILE_HANDLER_ENTER;
buf[0] = '@';
strcpy(buf + 1, s->s_name);
***************
*** 593,603 ****
--- 656,671 ----
&& hlen > 1)
{
+ WIDGETPROFILE_HANDLER_EVAL;
scriptlet_reset(x->x_auxscript);
scriptlet_add(x->x_auxscript, 0, 0, hlen - 1, hp + 1);
if (scriptlet_evaluate(x->x_auxscript, x->x_transient, 1,
ac, av, x->x_arguments))
+ {
+ WIDGETPROFILE_HANDLER_PUSH;
scriptlet_push(x->x_transient);
+ }
}
else loud_nomethod((t_pd *)x, s);
+ WIDGETPROFILE_HANDLER_QUIT;
}
}
***************
*** 609,612 ****
--- 677,681 ----
int ac;
t_atom *av;
+ WIDGETPROFILE_HANDLER_ENTER;
if ((av = props_getone(x->x_handlers, widgetps_atbang, &ac)) ||
(av = props_getone(widgettype_gethandlers(x->x_typedef),
***************
*** 615,623 ****
--- 684,695 ----
if (ac > 1)
{
+ WIDGETPROFILE_HANDLER_EVAL;
scriptlet_reset(x->x_transient);
scriptlet_add(x->x_transient, 1, 1, ac - 1, av + 1);
+ WIDGETPROFILE_HANDLER_PUSH;
scriptlet_push(x->x_transient);
}
}
+ WIDGETPROFILE_HANDLER_QUIT;
}
***************
*** 627,630 ****
--- 699,703 ----
int ac;
t_atom *av;
+ WIDGETPROFILE_HANDLER_ENTER;
if ((av = props_getone(x->x_handlers, widgetps_atfloat, &ac)) ||
(av = props_getone(widgettype_gethandlers(x->x_typedef),
***************
*** 634,637 ****
--- 707,711 ----
{
t_atom at;
+ WIDGETPROFILE_HANDLER_EVAL;
SETFLOAT(&at, f);
scriptlet_reset(x->x_auxscript);
***************
*** 639,645 ****
--- 713,723 ----
if (scriptlet_evaluate(x->x_auxscript, x->x_transient, 1,
1, &at, x->x_arguments))
+ {
+ WIDGETPROFILE_HANDLER_PUSH;
scriptlet_push(x->x_transient);
+ }
}
}
+ WIDGETPROFILE_HANDLER_QUIT;
}
***************
*** 649,652 ****
--- 727,731 ----
int ac;
t_atom *av;
+ WIDGETPROFILE_HANDLER_ENTER;
if ((av = props_getone(x->x_handlers, widgetps_atsymbol, &ac)) ||
(av = props_getone(widgettype_gethandlers(x->x_typedef),
***************
*** 656,659 ****
--- 735,739 ----
{
t_atom at;
+ WIDGETPROFILE_HANDLER_EVAL;
SETSYMBOL(&at, s);
scriptlet_reset(x->x_auxscript);
***************
*** 661,667 ****
--- 741,751 ----
if (scriptlet_evaluate(x->x_auxscript, x->x_transient, 1,
1, &at, x->x_arguments))
+ {
+ WIDGETPROFILE_HANDLER_PUSH;
scriptlet_push(x->x_transient);
+ }
}
}
+ WIDGETPROFILE_HANDLER_QUIT;
}
***************
*** 755,758 ****
--- 839,866 ----
}
+ static int widget_resettype(t_widget *x, t_widgettype *wt)
+ {
+ if (wt == x->x_typedef)
+ {
+ if (!(x->x_tkclass = widgettype_tkclass(x->x_typedef)))
+ x->x_tkclass = x->x_type;
+ props_clone(x->x_arguments, widgettype_getarguments(x->x_typedef));
+ /* FIXME widget_addmessage(x, 0, ac, av); */
+ widget_pushconstructors(x);
+ widget_refresh(x);
+ return (1);
+ }
+ else
+ {
+ bug("widget_resettype");
+ return (0);
+ }
+ }
+
+ static void widget_redefine(t_widget *x)
+ {
+ widget_resettype(x, widgettype_reload(x->x_type));
+ }
+
static void widget__failure(t_widget *x, t_symbol *s, int ac, t_atom *av)
{
***************
*** 938,944 ****
fprintf(stderr, "type destructor (size %d):\n\"%s\"\n",
sz, (bp ? bp : bempty));
- bp = masterwidget_getinitializer(&sz);
- fprintf(stderr, "master initializer (size %d):\n\"%s\"\n",
- sz, (bp ? bp : bempty));
bp = widgettype_getinitializer(x->x_typedef, &sz);
fprintf(stderr, "type initializer (size %d):\n\"%s\"\n",
--- 1046,1049 ----
***************
*** 983,1012 ****
{
t_widget *x;
char buf[MAXPDSTRING];
if (widget_transforming)
return (0);
masterwidget_validate();
- x = (t_widget *)pd_new(widget_class);
- x->x_type = 0;
- x->x_name = 0;
if (ac && av->a_type == A_SYMBOL)
{
! x->x_type = av->a_w.w_symbol;
ac--; av++;
}
if (ac && av->a_type == A_SYMBOL)
{
! x->x_name = av->a_w.w_symbol;
ac--; av++;
}
/* LATER think about anonymous widgets (single arg, or '.') */
! if (!x->x_type || x->x_type == &s_ ||
! !x->x_name || x->x_name == &s_)
{
! loud_error((t_pd *)x, "bad arguments for a widget");
! loud_errand((t_pd *)x,
! "expecting \"widget <type> <name> [properties]\"");
return (0);
}
sprintf(buf, "%s%x", x->x_name->s_name, (int)x);
pd_bind((t_pd *)x, x->x_cbtarget = gensym(buf));
--- 1088,1118 ----
{
t_widget *x;
+ t_symbol *type = 0, *name = 0;
char buf[MAXPDSTRING];
if (widget_transforming)
return (0);
masterwidget_validate();
if (ac && av->a_type == A_SYMBOL)
{
! type = av->a_w.w_symbol;
ac--; av++;
}
if (ac && av->a_type == A_SYMBOL)
{
! name = av->a_w.w_symbol;
ac--; av++;
}
/* LATER think about anonymous widgets (single arg, or '.') */
! if (!type || type == &s_ || !name || name == &s_)
{
! loud_error(0, "bad arguments for a widget");
! loud_errand(0, "expecting \"widget <type> <name> [properties]\"");
return (0);
}
+
+ x = (t_widget *)pd_new(widget_class);
+ x->x_type = type;
+ x->x_name = name;
+
sprintf(buf, "%s%x", x->x_name->s_name, (int)x);
pd_bind((t_pd *)x, x->x_cbtarget = gensym(buf));
***************
*** 1099,1102 ****
--- 1205,1217 ----
}
+ static void tow_redefine(t_tow *x)
+ {
+ t_widgettype *wt = widgettype_reload(x->x_type);
+ t_widgetentry *we;
+ for (we = x->x_widgetlist; we; we = we->we_next)
+ if (!widget_resettype(we->we_widget, wt))
+ break;
+ }
+
static void tow__callback(t_tow *x, t_symbol *s, int ac, t_atom *av)
{
***************
*** 1363,1366 ****
--- 1478,1483 ----
class_addmethod(widget_class, (t_method)widget_refresh,
gensym("refresh"), 0);
+ class_addmethod(widget_class, (t_method)widget_redefine,
+ gensym("redefine"), 0);
class_addmethod(widget_class, (t_method)widget__failure,
gensym("_failure"), A_GIMME, 0);
***************
*** 1382,1389 ****
--- 1499,1511 ----
gensym("debug"), 0);
#endif
+ #ifdef WIDGET_PROFILE
+ class_addmethod(widget_class, (t_method)widget_profile,
+ gensym("profile"), 0);
+ #endif
hammerfile_setup(widget_class, 0);
makeshift_class = class_new(gensym("text"), 0, 0,
sizeof(t_text),
+ /* inlet added explicitly (cf text_class) */
CLASS_NOINLET | CLASS_PATCHABLE, 0);
***************
*** 1396,1399 ****
--- 1518,1523 ----
class_addsymbol(tow_class, tow_symbol);
class_addanything(tow_class, tow_anything);
+ class_addmethod(tow_class, (t_method)tow_redefine,
+ gensym("redefine"), 0);
class_addmethod(tow_class, (t_method)tow__callback,
gensym("_cb"), A_GIMME, 0);