aboutsummaryrefslogtreecommitdiff
path: root/toxy
diff options
context:
space:
mode:
Diffstat (limited to 'toxy')
-rw-r--r--toxy/Makefile4
-rw-r--r--toxy/Makefile.objects20
-rw-r--r--toxy/Makefile.sources3
-rw-r--r--toxy/build_counter2
-rw-r--r--toxy/plustot.c2020
-rw-r--r--toxy/plustot.env.c150
-rw-r--r--toxy/plustot.h81
-rw-r--r--toxy/plustot.in.c126
-rw-r--r--toxy/plustot.out.c71
-rw-r--r--toxy/plustot.print.c90
-rw-r--r--toxy/plustot.qlist.c212
-rw-r--r--toxy/plustot.var.c130
-rw-r--r--toxy/tot.c8
-rw-r--r--toxy/toxy-shared.include4
-rw-r--r--toxy/widget.c225
-rw-r--r--toxy/widgettype.c147
-rw-r--r--toxy/widgettype.h5
17 files changed, 3151 insertions, 147 deletions
diff --git a/toxy/Makefile b/toxy/Makefile
index fc022be..1718111 100644
--- a/toxy/Makefile
+++ b/toxy/Makefile
@@ -1,2 +1,6 @@
ROOT_DIR = ..
+redefault: default.wiq default
+default.wiq: $(ROOT_DIR)/test/toxy/default.wid
+ $(ROOT_DIR)/quoteinitializer $< \
+ '"puts [concat loading built-in widget definitions]\n"' > $@
include $(ROOT_DIR)/Makefile.common
diff --git a/toxy/Makefile.objects b/toxy/Makefile.objects
index fde293c..f063097 100644
--- a/toxy/Makefile.objects
+++ b/toxy/Makefile.objects
@@ -7,6 +7,26 @@ hammer/gui.o \
common/props.o \
toxy/scriptlet.o
+PLUSTOT_OBJECTS = \
+unstable/fragile.o \
+unstable/forky.o \
+common/loud.o \
+common/grow.o \
+hammer/file.o \
+common/props.o \
+toxy/scriptlet.o \
+toxy/plusbob.o
+
+PLUSTOT_PRIVATEOBJECTS = \
+plustot.env.o \
+plustot.in.o \
+plustot.var.o \
+plustot.out.o \
+plustot.qlist.o \
+plustot.print.o
+
+PLUSTOT_LIBS = $(TCL_LIB)
+
TOW_OBJECTS = \
common/loud.o \
unstable/loader.o
diff --git a/toxy/Makefile.sources b/toxy/Makefile.sources
index b0f3646..1626cd6 100644
--- a/toxy/Makefile.sources
+++ b/toxy/Makefile.sources
@@ -1,5 +1,6 @@
-TYPES = TOT TOW WIDGET
+TYPES = TOT TOW WIDGET PLUSTOT
TOT_SOURCES = tot.c
TOW_SOURCES = tow.c
WIDGET_SOURCES = widget.c
+PLUSTOT_SOURCES = plustot.c
diff --git a/toxy/build_counter b/toxy/build_counter
index 5774bf7..a4b640c 100644
--- a/toxy/build_counter
+++ b/toxy/build_counter
@@ -1,3 +1,3 @@
#define TOXY_VERSION "0.1"
#define TOXY_RELEASE "alpha"
-#define TOXY_BUILD 1
+#define TOXY_BUILD 2
diff --git a/toxy/plustot.c b/toxy/plustot.c
new file mode 100644
index 0000000..bfaeb32
--- /dev/null
+++ b/toxy/plustot.c
@@ -0,0 +1,2020 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "common/loud.h"
+#include "common/grow.h"
+#include "hammer/file.h"
+#include "common/props.h"
+#include "toxy/scriptlet.h"
+#include "toxy/plusbob.h"
+#include "plustot.h"
+#include "build_counter"
+
+#define PLUSTOT_VERBOSE
+#define PLUSTOT_DEBUG
+//#define PLUSTOT_DEBUGREFCOUNTS
+
+#ifdef PLUSTOT_DEBUG
+# define PLUSDEBUG_ENDPOST(fn) endpost()
+#else
+# define PLUSDEBUG_ENDPOST(fn)
+#endif
+
+#ifdef PLUSTOT_DEBUGREFCOUNTS
+# define PLUSDEBUG_INCRREFCOUNT(ob, fn) \
+ {post("++ %x "fn, (int)(ob)); Tcl_IncrRefCount(ob);}
+# define PLUSDEBUG_DECRREFCOUNT(ob, fn) \
+ {post("-- %x "fn, (int)(ob)); Tcl_DecrRefCount(ob);}
+#else
+# define PLUSDEBUG_INCRREFCOUNT(ob, fn) Tcl_IncrRefCount(ob)
+# define PLUSDEBUG_DECRREFCOUNT(ob, fn) Tcl_DecrRefCount(ob)
+#endif
+
+static t_symbol *plusps_tot;
+static t_symbol *plusps_env;
+static t_symbol *plusps_in;
+static t_symbol *plusps_var;
+static t_symbol *plusps_out;
+static t_symbol *plusps_qlist;
+static t_symbol *plusps_print;
+static t_symbol *totps_query;
+
+static void plusloud_tcldirty(t_pd *caller, char *fnname)
+{
+ loud_warning((caller == PLUSBOB_OWNER ? 0 : caller),
+ "(%s) tcl plays dirty tricks, sorry", fnname);
+}
+
+void plusloud_tclerror(t_pd *caller, Tcl_Interp *interp, char *msg)
+{
+ Tcl_Obj *ob = Tcl_GetObjResult(interp);
+ loud_error((caller == PLUSBOB_OWNER ? 0 : caller), msg);
+ if (ob)
+ {
+ int len;
+ char *res = Tcl_GetStringFromObj(ob, &len);
+ if (res && len > 0)
+ {
+ char buf[MAXPDSTRING];
+ if (len > (MAXPDSTRING-2))
+ {
+ len = (MAXPDSTRING-2);
+ buf[MAXPDSTRING-2] = '*';
+ buf[MAXPDSTRING-1] = 0;
+ }
+ else buf[len] = 0;
+ strncpy(buf, res, len);
+ loud_errand((caller == PLUSBOB_OWNER ? 0 : caller),
+ "(tcl) %s", buf);
+ }
+ else ob = 0;
+ Tcl_ResetResult(interp);
+ }
+ if (!ob) loud_errand((caller == PLUSBOB_OWNER ? 0 : caller),
+ "unknown error (probably a bug)");
+}
+
+/* Plustin (aka +Ti) is a Tcl_Interp wrapped as a +bob.
+ This is a glist-based flavor of Plusenv. */
+
+struct _plustin
+{
+ t_plusenv tin_env;
+ t_glist *tin_glist;
+ Tcl_Interp *tin_interp;
+};
+
+static t_plustype *plustin_basetype;
+static t_plustype *plustin_type;
+static t_plustin *plustin_default = 0;
+
+/* To be called from derived constructors or plustin's provider. */
+t_plustin *plustin_create(t_plustype *tp, t_plusbob *parent, t_symbol *id)
+{
+ t_plustin *tin = 0;
+ Tcl_Interp *interp = Tcl_CreateInterp();
+ if (interp && (tin = (t_plustin *)plusenv_create(tp, parent, id)))
+ {
+#ifdef PLUSTOT_DEBUG
+ post("plustin_create '%s' over %x",
+ (id ? id->s_name : "default"), (int)interp);
+#endif
+ tin->tin_interp = interp;
+ Tcl_Preserve(interp);
+ if (Tcl_Init(interp) == TCL_ERROR)
+ plusloud_tclerror(0, interp, "interpreter initialization failed");
+ Tcl_Release(interp);
+ }
+ else loud_error(0, "failed attempt to create an interpreter");
+ return (tin);
+}
+
+/* To be registered for calling from plusbob_release().
+ Should never be called explicitly. */
+static void plustin_delete(t_plustin *tin)
+{
+#ifdef PLUSTOT_DEBUG
+ t_symbol *id = plusenv_getid((t_plusenv *)tin);
+ post("plustin_delete '%s' over %x",
+ (id ? id->s_name : "default"), (int)tin->tin_interp);
+#endif
+ Tcl_Preserve(tin->tin_interp);
+ if (!Tcl_InterpDeleted(tin->tin_interp))
+ Tcl_DeleteInterp(tin->tin_interp);
+ Tcl_Release(tin->tin_interp);
+}
+
+Tcl_Interp *plustin_getinterp(t_plustin *tin)
+{
+ return (tin->tin_interp);
+}
+
+t_symbol *plustin_glistid(t_glist *gl)
+{
+ char buf[32];
+ sprintf(buf, "+ti%x", (int)gl);
+ return (gensym(buf));
+}
+
+t_plustin *plustin_glistfind(t_glist *gl, int mode)
+{
+ t_plustin *tin = 0;
+ if (mode == PLUSTIN_GLIST_UP)
+ {
+ gl = gl->gl_owner;
+ mode = PLUSTIN_GLIST_ANY;
+ }
+ if (mode == PLUSTIN_GLIST_THIS)
+ return ((t_plustin *)plusenv_find(plustin_glistid(gl),
+ (t_plusenv *)plustin_default));
+ else
+ {
+ while (gl)
+ {
+ char buf[32];
+ sprintf(buf, "+ti%x", (int)gl);
+ if (tin = (t_plustin *)plusenv_find(gensym(buf),
+ (t_plusenv *)plustin_default))
+ break;
+ gl = gl->gl_owner;
+ }
+ return (tin ? tin : plustin_default);
+ }
+}
+
+/* To be called from client code, instead of plustin_create().
+ Preserving is caller's responsibility.
+ Never returns null, even when called with create == 0:
+ if requested id not found, default returned, created if necessary. */
+t_plustin *plustin_glistprovide(t_glist *gl, int mode, int create)
+{
+ t_plustin *tin = 0;
+ t_plusbob *parent = plusenv_getparent(plustin_type);
+ if (mode == PLUSTIN_GLIST_UP)
+ {
+ gl = gl->gl_owner;
+ mode = PLUSTIN_GLIST_ANY;
+ }
+ tin = plustin_glistfind(gl, mode);
+ if (!tin && create)
+ {
+ if (tin = plustin_create(plustin_type, parent, plustin_glistid(gl)))
+ tin->tin_glist = gl;
+ }
+ if (!tin)
+ {
+ if (!plustin_default)
+ plustin_default = plustin_create(plustin_type, parent, 0);
+ tin = plustin_default;
+ }
+ return (tin);
+}
+
+t_symbol *plustin_getglistname(t_plustin *tin)
+{
+ return (tin->tin_glist ? tin->tin_glist->gl_name : 0);
+}
+
+/* Plustob (aka +To) is a Tcl_Obj wrapped as a +bob. */
+
+/* LATER rethink the plustob/plusvar rules, measure performance.
+ There are two cases:
+
+ `Bobbing' is taking an object from its wrapping bob, wrapping it into
+ another bob and, optionally, setting a variable to it.
+
+ The main deal of bobbing design is not to Tcl_DuplicateObj while passing
+ bobs around.
+
+ `Messing' is converting a Pd message (float, symbol or list) to an object,
+ wrapping it and, optionally, setting a variable to it.
+
+ The obvious sequence of {Decr(old), New, Incr(new), SetVar(new)}, which
+ is currently used, involves picking a new object (New), while returning
+ an old one to the pool (by SetVar or Decr, depending on a third party
+ changing or not the tcl variable's value in the meantime). I guess
+ the overhead is negligible, unless we hit at the bottom of the pool.
+ Moreover, we can reduce the sequence to just {Set(old), SetVar(old)},
+ in the case when old is not shared (referenced neither by a variable,
+ nor by a third party). The main advantage is being consistent with
+ the way Tcl itself was designed.
+
+ An alternative: in the original messing design, the trick was to:
+
+ . call Set on a prepicked object, instead of New
+ . call SetVar on a preserved object, as usual (var would not own its value)
+ . alternate between two prepicked objects in order to avoid calling UnsetVar
+
+ So, the sequence was just {Set(v1), SetVar(v1)}, then {Set(v2), SetVar(v2)},
+ again {Set(v1), SetVar(v1)}, and so on, unless a third party (other than
+ plusvar and a tcl variable) referenced our prepicked object. */
+
+#define PLUSTOB_INIELBUFSIZE 128 /* LATER rethink */
+
+struct _plustob
+{
+ t_plusbob tob_bob;
+ Tcl_Obj *tob_value;
+ t_plustin *tob_tin; /* redundant, LATER rethink */
+ t_plusifsharedfn tob_ifsharedfn;
+ int tob_elbufsize;
+ Tcl_Obj **tob_elbuf;
+ Tcl_Obj *tob_elbufini[PLUSTOB_INIELBUFSIZE];
+};
+
+static t_plustype *plustob_type;
+
+/* To be called from derived constructors.
+ Preserving is caller's responsibility. */
+t_plustob *plustob_create(t_plustype *tp, t_plustin *tin, Tcl_Obj *ob)
+{
+ t_plustob *tob = 0;
+ if (tin && (ob != PLUSTOB_MAKEIT || (ob = Tcl_NewObj()))
+ && (tob = (t_plustob *)plusbob_create(tp, (t_plusbob *)tin)))
+ {
+ if (ob) PLUSDEBUG_INCRREFCOUNT(ob, "plustob_create");
+ plusbob_preserve((t_plusbob *)tin);
+ tob->tob_value = ob;
+ tob->tob_tin = tin;
+ tob->tob_ifsharedfn = 0;
+ tob->tob_elbufsize = PLUSTOB_INIELBUFSIZE;
+ tob->tob_elbuf = tob->tob_elbufini;
+ }
+ return (tob);
+}
+
+/* To be registered for calling from plusbob_release().
+ Should never be called explicitly. */
+static void plustob_delete(t_plustob *tob)
+{
+ if (tob->tob_tin)
+ plusbob_release((t_plusbob *)tob->tob_tin);
+ if (tob->tob_value)
+ PLUSDEBUG_DECRREFCOUNT(tob->tob_value, "plustob_delete");
+ if (tob->tob_elbuf != tob->tob_elbufini)
+ freebytes(tob->tob_elbuf, tob->tob_elbufsize * sizeof(*tob->tob_elbuf));
+}
+
+/* To be registered for calling from plusbob_attach().
+ Should never be called explicitly. */
+static void plustob_attach(t_plustob *tob)
+{
+ t_plustin *tin;
+ if (tin = (t_plustin *)plusbob_getparent((t_plusbob *)tob))
+ {
+ if (tob->tob_tin)
+ plusbob_release((t_plusbob *)tob->tob_tin);
+ tob->tob_tin = tin;
+ plusbob_preserve((t_plusbob *)tin);
+ }
+ else bug("plustob_attach");
+}
+
+/* To be called from client code.
+ Preserving is caller's responsibility. */
+t_plustob *plustob_new(t_plustin *tin, Tcl_Obj *ob)
+{
+ return (plustob_create(plustob_type, tin, ob));
+}
+
+void plustob_setifshared(t_plustob *tob, t_plusifsharedfn ifsharedfn)
+{
+ tob->tob_ifsharedfn = ifsharedfn;
+}
+
+int plustob_isshared(t_plustob *tob)
+{
+ return (tob->tob_value && Tcl_IsShared(tob->tob_value));
+}
+
+Tcl_Obj *plustob_getvalue(t_plustob *tob)
+{
+ return (tob->tob_value);
+}
+
+/* silent, if caller is empty */
+t_plustin *plustag_tobtin(t_symbol *tag, t_pd *caller)
+{
+ return (plustag_validroot(tag, plusps_To, caller)
+ ? ((t_plustob *)tag)->tob_tin : 0);
+}
+
+/* silent, if caller is empty */
+Tcl_Obj *plustag_tobvalue(t_symbol *tag, t_pd *caller)
+{
+ return (plustag_validroot(tag, plusps_To, caller)
+ ? ((t_plustob *)tag)->tob_value : 0);
+}
+
+/* silent, if caller is empty */
+Tcl_Obj *plusatom_tobvalue(t_atom *ap, t_pd *caller)
+{
+ if (ap->a_type == A_SYMBOL)
+ return (plustag_tobvalue(ap->a_w.w_symbol, caller));
+ else if (caller)
+ {
+ char buf[80];
+ atom_string(ap, buf, 80);
+ loud_error((caller == PLUSBOB_OWNER ? 0 : caller),
+ "+tot does not understand '%s' (check object connections)", buf);
+ }
+ return (0);
+}
+
+Tcl_Obj *plustob_set(t_plustob *tob, t_plustin *tin, Tcl_Obj *ob)
+{
+ if (tin != tob->tob_tin)
+ {
+ /* FIXME */
+ loud_warning(0, "+To: environment mismatch");
+ return (0);
+ }
+ if (ob != tob->tob_value)
+ {
+ if (tob->tob_value)
+ PLUSDEBUG_DECRREFCOUNT(tob->tob_value, "plustob_set");
+ if (ob)
+ {
+ PLUSDEBUG_INCRREFCOUNT(ob, "plustob_set");
+ if (Tcl_IsShared(ob))
+ {
+ /* FIXME */
+ }
+ }
+ tob->tob_value = ob;
+ }
+ return (ob);
+}
+
+Tcl_Obj *plustob_setfloat(t_plustob *tob, t_float f)
+{
+ Tcl_Obj *ob = tob->tob_value;
+ if (!ob || Tcl_IsShared(ob))
+ {
+ Tcl_Obj *tmp;
+ int i = (int)f;
+ if (ob && tob->tob_ifsharedfn)
+ {
+ if ((*tob->tob_ifsharedfn)((t_plusbob *)tob, ob) == 0)
+ return (0);
+ }
+ if (f == i) /* LATER rethink */
+ tmp = Tcl_NewIntObj(i);
+ else
+ tmp = Tcl_NewDoubleObj((double)f);
+ if (tmp)
+ {
+ if (ob) PLUSDEBUG_DECRREFCOUNT(ob, "plustob_setfloat");
+ tob->tob_value = ob = tmp;
+ PLUSDEBUG_INCRREFCOUNT(ob, "plustob_setfloat");
+ }
+ else return (0);
+ }
+ else
+ {
+ int i = (int)f;
+ if (f == i) /* LATER rethink */
+ Tcl_SetIntObj(ob, i);
+ else
+ Tcl_SetDoubleObj(ob, (double)f);
+ }
+ return (ob);
+}
+
+Tcl_Obj *plustob_setsymbol(t_plustob *tob, t_symbol *s)
+{
+ if (plustag_isvalid(s, 0))
+ {
+ if (plustag_validroot(s, plusps_To, PLUSBOB_OWNER))
+ {
+ t_plustob *from = (t_plustob *)s;
+ return (plustob_set(tob, from->tob_tin, from->tob_value));
+ }
+ else return (0);
+ }
+ else
+ {
+ Tcl_Obj *ob = tob->tob_value;
+ if (!ob || Tcl_IsShared(ob))
+ {
+ Tcl_Obj *tmp;
+ if (ob && tob->tob_ifsharedfn)
+ {
+ if ((*tob->tob_ifsharedfn)((t_plusbob *)tob, ob) == 0)
+ return (0);
+ }
+ if (tmp = Tcl_NewStringObj(s->s_name, -1))
+ {
+ if (ob) PLUSDEBUG_DECRREFCOUNT(ob, "plustob_setsymbol");
+ tob->tob_value = ob = tmp;
+ PLUSDEBUG_INCRREFCOUNT(ob, "plustob_setsymbol");
+ }
+ else return (0);
+ }
+ else Tcl_SetStringObj(ob, s->s_name, -1);
+ return (ob);
+ }
+}
+
+Tcl_Obj *plustob_setlist(t_plustob *tob, int ac, t_atom *av)
+{
+ if (ac == 1)
+ {
+ if (av->a_type == A_FLOAT)
+ return (plustob_setfloat(tob, av->a_w.w_float));
+ else if (av->a_type == A_SYMBOL)
+ return (plustob_setsymbol(tob, av->a_w.w_symbol));
+ }
+ else if (ac > 1)
+ {
+ Tcl_Obj *ob = tob->tob_value;
+ int count;
+ t_atom *ap;
+ for (count = 0, ap = av; count < ac; count++, ap++)
+ if (ap->a_type != A_FLOAT && ap->a_type != A_SYMBOL)
+ break;
+ if (count > tob->tob_elbufsize)
+ {
+#ifdef PLUSTOT_DEBUG
+ post("growing +To %d -> %d", tob->tob_elbufsize, count);
+#endif
+ tob->tob_elbuf =
+ grow_nodata(&count, &tob->tob_elbufsize, tob->tob_elbuf,
+ PLUSTOB_INIELBUFSIZE, tob->tob_elbufini,
+ sizeof(*tob->tob_elbuf));
+ }
+ if (count > 0)
+ {
+ int i;
+ Tcl_Obj **elp;
+ for (i = 0, elp = tob->tob_elbuf; i < count; i++, elp++, av++)
+ {
+ if (av->a_type == A_FLOAT)
+ *elp = Tcl_NewDoubleObj((double)av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+ *elp = Tcl_NewStringObj(av->a_w.w_symbol->s_name, -1);
+ }
+ if (!ob || Tcl_IsShared(ob))
+ {
+ Tcl_Obj *tmp;
+ if (ob && tob->tob_ifsharedfn)
+ {
+ if ((*tob->tob_ifsharedfn)((t_plusbob *)tob, ob) == 0)
+ return (0);
+ }
+ if (tmp = Tcl_NewListObj(count, tob->tob_elbuf))
+ {
+ if (ob) PLUSDEBUG_DECRREFCOUNT(ob, "plustob_setlist");
+ tob->tob_value = ob = tmp;
+ PLUSDEBUG_INCRREFCOUNT(ob, "plustob_setlist");
+ }
+ else return (0);
+ }
+ else Tcl_SetListObj(ob, count, tob->tob_elbuf);
+ return (ob);
+ }
+ }
+ return (0); /* count == 0, LATER rethink */
+}
+
+static int plustob_parseatoms(int ac, t_atom *av, int *natomsp, int *nlistsp,
+ Tcl_Obj **listobs, Tcl_Obj **atomobs)
+{
+ int i, natoms = 0, nlists = 0, start = 1;
+ t_atom *ap;
+ int atomcnt = 0;
+ Tcl_Obj **atomptr = atomobs;
+ for (i = 0, ap = av; i < ac; i++, ap++)
+ {
+ if (ap->a_type == A_SEMI || ap->a_type == A_COMMA)
+ {
+ /* empty lists are filtered out, LATER rethink */
+ if (!start)
+ {
+ if (listobs)
+ {
+ if (listobs[nlists] = Tcl_NewListObj(atomcnt, atomptr))
+ {
+ atomptr += atomcnt;
+ atomcnt = 0;
+ }
+ else goto parsefailed;
+ }
+ nlists++;
+ }
+ start = 1;
+ }
+ else
+ {
+ /* other types are ignored, LATER rethink */
+ start = 0;
+ if (ap->a_type == A_FLOAT || ap->a_type == A_SYMBOL)
+ {
+ if (atomobs)
+ {
+ if (!(atomobs[natoms] =
+ (ap->a_type == A_FLOAT ?
+ Tcl_NewDoubleObj((double)ap->a_w.w_float) :
+ Tcl_NewStringObj(ap->a_w.w_symbol->s_name, -1))))
+ goto parsefailed;
+ atomcnt++;
+ }
+ natoms++;
+ }
+ }
+ }
+ if (natoms && !start)
+ {
+ if (listobs &&
+ !(listobs[nlists] = Tcl_NewListObj(atomcnt, atomptr)))
+ goto parsefailed;
+ nlists++;
+ }
+ if (natomsp) *natomsp = natoms;
+ if (nlistsp) *nlistsp = nlists;
+ return (1);
+parsefailed:
+ /* FIXME cleanup */
+ return (0);
+}
+
+Tcl_Obj *plustob_setbinbuf(t_plustob *tob, t_binbuf *bb)
+{
+ int ac = binbuf_getnatom(bb);
+ if (ac)
+ {
+ t_atom *av = binbuf_getvec(bb);
+ Tcl_Obj *ob = tob->tob_value;
+ int count, natoms, nlists;
+ plustob_parseatoms(ac, av, &natoms, &nlists, 0, 0);
+ count = natoms + nlists;
+ if (count > tob->tob_elbufsize)
+ {
+ int n = count;
+#ifdef PLUSTOT_DEBUG
+ post("growing +To %d -> %d", tob->tob_elbufsize, count);
+#endif
+ tob->tob_elbuf =
+ grow_nodata(&n, &tob->tob_elbufsize, tob->tob_elbuf,
+ PLUSTOB_INIELBUFSIZE, tob->tob_elbufini,
+ sizeof(*tob->tob_elbuf));
+ if (n < count)
+ goto setbbfailed;
+ }
+ if (!plustob_parseatoms(ac, av, 0, 0,
+ tob->tob_elbuf, tob->tob_elbuf + nlists))
+ goto setbbfailed;
+ if (!ob || Tcl_IsShared(ob))
+ {
+ Tcl_Obj *tmp;
+ if (ob && tob->tob_ifsharedfn)
+ {
+ if ((*tob->tob_ifsharedfn)((t_plusbob *)tob, ob) == 0)
+ goto setbbfailed;
+ }
+ if (tmp = Tcl_NewListObj(nlists, tob->tob_elbuf))
+ {
+ if (ob) PLUSDEBUG_DECRREFCOUNT(ob, "plustob_setbinbuf");
+ tob->tob_value = ob = tmp;
+ PLUSDEBUG_INCRREFCOUNT(ob, "plustob_setbinbuf");
+ }
+ else goto setbbfailed;
+ }
+ else Tcl_SetListObj(ob, nlists, tob->tob_elbuf);
+ return (ob);
+ }
+setbbfailed:
+ return (0);
+}
+
+Tcl_Obj *plustob_grabresult(t_plustob *tob)
+{
+ Tcl_Interp *interp = tob->tob_tin->tin_interp;
+ Tcl_Obj *rob;
+ if (rob = Tcl_GetObjResult(interp))
+ {
+ if (rob == tob->tob_value)
+ Tcl_ResetResult(interp);
+ else
+ {
+ PLUSDEBUG_INCRREFCOUNT(rob, "plustob_grabresult");
+ Tcl_ResetResult(interp);
+ if (Tcl_IsShared(rob))
+ {
+ /* FIXME */
+ }
+ if (tob->tob_value)
+ PLUSDEBUG_DECRREFCOUNT(tob->tob_value, "plustob_grabresult");
+ tob->tob_value = rob;
+ }
+ }
+ else plusloud_tcldirty(plusbob_getowner((t_plusbob *)tob),
+ "plustob_grabresult");
+ return (rob);
+}
+
+Tcl_Obj *plustob_evalob(t_plustob *tob, Tcl_Obj *ob)
+{
+ Tcl_Interp *interp = tob->tob_tin->tin_interp;
+ Tcl_Obj *rob;
+ Tcl_Preserve(interp);
+ if (Tcl_EvalObj(interp, ob) == TCL_OK)
+ rob = plustob_grabresult(tob);
+ else
+ {
+ plusloud_tclerror(plusbob_getowner((t_plusbob *)tob), interp,
+ "immediate command failed");
+ rob = 0;
+ }
+ Tcl_Release(interp);
+ return (rob);
+}
+
+/* Plusvar (aka +Tv) is a plustob with a one-way link to a tcl variable.
+ Whenever plusvar's value changes, the variable is set to it (the opposite
+ update requires explicitly calling the plusvar_pull() request).
+ This is different from one-way linking by passing TCL_LINK_READ_ONLY flag
+ to Tcl_LinkVar(): plusvar's variable is not forced to be read-only,
+ and its value's form and internal representation are not constrained. */
+
+struct _plusvar
+{
+ t_plustob var_tob;
+ char *var_name;
+ char *var_index;
+ Tcl_Obj *var_part1;
+ Tcl_Obj *var_part2;
+};
+
+static t_plustype *plusvar_type;
+
+/* Since tcl always uses a hash table of string indices for array element
+ lookup, there are never any gains when using integer indices. */
+
+/* To be called from derived constructors.
+ Preserving is caller's responsibility. */
+t_plusvar *plusvar_create(t_plustype *tp, t_plustin *tin, Tcl_Obj *ob,
+ char *name, char *index)
+{
+ t_plusvar *var = 0;
+ Tcl_Obj *ntob = 0;
+ Tcl_Obj *itob = 0;
+ if (name && *name)
+ {
+ if (ntob = Tcl_NewStringObj(name, -1))
+ {
+ PLUSDEBUG_INCRREFCOUNT(ntob, "plusvar_create");
+ }
+ else goto varfailed1;
+ }
+ else
+ {
+ bug("plusvar_create");
+ goto varfailed2;
+ }
+ if (index)
+ {
+ if (itob = Tcl_NewStringObj(index, -1))
+ {
+ PLUSDEBUG_INCRREFCOUNT(itob, "plusvar_create");
+ }
+ else goto varfailed1;
+ }
+ if (var = (t_plusvar *)plustob_create(tp, tin, ob))
+ {
+ var->var_name = getbytes(strlen(name) + 1);
+ strcpy(var->var_name, name);
+ if (index)
+ {
+ var->var_index = getbytes(strlen(index) + 1);
+ strcpy(var->var_index, index);
+ }
+ else var->var_index = 0;
+ var->var_part1 = ntob;
+ var->var_part2 = itob;
+ }
+ else goto varfailed2;
+ return (var);
+varfailed1:
+ plusloud_tcldirty(0, "plusvar_create");
+varfailed2:
+ if (ntob) PLUSDEBUG_DECRREFCOUNT(ntob, "plusvar_create");
+ if (itob) PLUSDEBUG_DECRREFCOUNT(itob, "plusvar_create");
+ return (0);
+}
+
+/* To be registered for calling from plusbob_release().
+ Should never be called explicitly. */
+static void plusvar_delete(t_plusvar *var)
+{
+ freebytes(var->var_name, strlen(var->var_name) + 1);
+ if (var->var_index)
+ freebytes(var->var_index, strlen(var->var_index) + 1);
+ PLUSDEBUG_DECRREFCOUNT(var->var_part1, "plusvar_delete");
+ if (var->var_part2)
+ PLUSDEBUG_DECRREFCOUNT(var->var_part2, "plusvar_delete");
+}
+
+/* To be called from client code.
+ Preserving is caller's responsibility */
+t_plusvar *plusvar_new(char *name, char *index, t_plustin *tin)
+{
+ return (plusvar_create(plusvar_type, tin, 0, name, index));
+}
+
+/* not used yet */
+static int plusvar_ifshared(t_plusbob *bob, Tcl_Obj *ob)
+{
+ /* Shared means either the variable still holds our value, or the value
+ is referenced by a third party, or both. In either case, we have to
+ pick a new object.
+ LATER consider testing for illegal use of a pseudo-variable. */
+ return (1);
+}
+
+/* LATER try making it more efficient */
+static Tcl_Obj *plusvar_postset(t_plusvar *var)
+{
+ Tcl_Obj *rob;
+ t_plustob *tob = (t_plustob *)var;
+ Tcl_Interp *interp = tob->tob_tin->tin_interp;
+ Tcl_Preserve(interp);
+ if (tob->tob_value)
+ {
+ rob = Tcl_ObjSetVar2(interp, var->var_part1, var->var_part2,
+ tob->tob_value, 0);
+ if (!rob)
+ {
+ if (Tcl_UnsetVar2(interp, var->var_name, 0,
+ TCL_LEAVE_ERR_MSG) == TCL_OK)
+ rob = Tcl_ObjSetVar2(interp, var->var_part1, var->var_part2,
+ tob->tob_value, TCL_LEAVE_ERR_MSG);
+ }
+ if (rob)
+ {
+#ifdef PLUSTOT_DEBUGREFCOUNTS
+ if (var->var_index)
+ post("vv %x plusvar_postset [%s(%s)]",
+ (int)tob->tob_value, var->var_name, var->var_index);
+ else
+ post("vv %x plusvar_postset [%s]",
+ (int)tob->tob_value, var->var_name);
+#endif
+ }
+ else plusloud_tclerror(0, interp, "cannot set variable");
+ }
+ else
+ {
+ if (Tcl_UnsetVar2(interp, var->var_name, 0,
+ TCL_LEAVE_ERR_MSG) != TCL_OK)
+ plusloud_tclerror(0, interp, "cannot unset variable");
+ rob = 0;
+ }
+ Tcl_Release(interp);
+ return (rob);
+}
+
+Tcl_Obj *plusvar_push(t_plusvar *var)
+{
+ if (((t_plustob *)var)->tob_value)
+ return (plusvar_postset(var));
+ else
+ return (0);
+}
+
+Tcl_Obj *plusvar_pull(t_plusvar *var)
+{
+ Tcl_Obj *rob;
+ t_plustob *tob = (t_plustob *)var;
+ Tcl_Interp *interp = tob->tob_tin->tin_interp;
+ Tcl_Preserve(interp);
+ if (rob = Tcl_ObjGetVar2(interp, var->var_part1, var->var_part2,
+ TCL_LEAVE_ERR_MSG))
+ plustob_set(tob, tob->tob_tin, rob);
+ else
+ plusloud_tclerror(0, interp, "cannot read variable");
+ Tcl_Release(interp);
+ return (rob);
+}
+
+Tcl_Obj *plusvar_set(t_plusvar *var, Tcl_Obj *ob, int doit)
+{
+ t_plustob *tob = (t_plustob *)var;
+ if (plustob_set(tob, tob->tob_tin, ob))
+ return (doit ? plusvar_postset(var) : tob->tob_value);
+ else
+ return (0);
+}
+
+Tcl_Obj *plusvar_setfloat(t_plusvar *var, t_float f, int doit)
+{
+ t_plustob *tob = (t_plustob *)var;
+ if (plustob_setfloat(tob, f))
+ return (doit ? plusvar_postset(var) : tob->tob_value);
+ else
+ return (0);
+}
+
+Tcl_Obj *plusvar_setsymbol(t_plusvar *var, t_symbol *s, int doit)
+{
+ t_plustob *tob = (t_plustob *)var;
+ if (plustob_setsymbol(tob, s))
+ return (doit ? plusvar_postset(var) : tob->tob_value);
+ else
+ return (0);
+}
+
+Tcl_Obj *plusvar_setlist(t_plusvar *var, int ac, t_atom *av, int doit)
+{
+ t_plustob *tob = (t_plustob *)var;
+ if (plustob_setlist(tob, ac, av))
+ return (doit ? plusvar_postset(var) : tob->tob_value);
+ else
+ return (0);
+}
+
+/* LATER derive +string from +bob */
+
+typedef struct _plusstring
+{
+ int ps_len;
+ char *ps_buf;
+ int ps_refcount;
+} t_plusstring;
+
+/* Resolving dot-separators, unless script is empty. */
+t_plusstring *plusstring_fromatoms(int ac, t_atom *av, t_scriptlet *script)
+{
+ t_plusstring *ps = 0;
+ char *buf;
+ int length;
+ if (script)
+ {
+ char *start;
+ scriptlet_reset(script);
+ scriptlet_add(script, 1, 1, ac, av);
+ start = scriptlet_getcontents(script, &length);
+ buf = copybytes(start, length);
+ }
+ else
+ {
+ char *newbuf;
+ buf = getbytes(0);
+ length = 0;
+ while (ac--)
+ {
+ char string[MAXPDSTRING];
+ int newlength;
+ if ((av->a_type == A_SEMI || av->a_type == A_COMMA) &&
+ length && buf[length-1] == ' ') length--;
+ atom_string(av, string, MAXPDSTRING);
+ newlength = length + strlen(string) + 1;
+ if (!(newbuf = resizebytes(buf, length, newlength))) break;
+ buf = newbuf;
+ strcpy(buf + length, string);
+ length = newlength;
+ if (av->a_type == A_SEMI) buf[length-1] = '\n';
+ else buf[length-1] = ' ';
+ av++;
+ }
+ if (length && buf[length-1] == ' ')
+ {
+ if (newbuf = resizebytes(buf, length, length-1))
+ {
+ buf = newbuf;
+ length--;
+ }
+ }
+ }
+ ps = getbytes(sizeof(*ps));
+ ps->ps_len = length;
+ ps->ps_buf = buf;
+ ps->ps_refcount = 0;
+ return (ps);
+}
+
+void plusstring_preserve(t_plusstring *ps)
+{
+ ps->ps_refcount++;
+}
+
+void plusstring_release(t_plusstring *ps)
+{
+ if (--ps->ps_refcount <= 0)
+ {
+ if (ps->ps_refcount == 0)
+ {
+ if (ps->ps_buf) freebytes(ps->ps_buf, ps->ps_len);
+ freebytes(ps, sizeof(*ps));
+ }
+ else bug("plusstring_release");
+ }
+}
+
+typedef struct _plusword
+{
+ int pw_type;
+ Tcl_Obj *pw_ob;
+ Tcl_Token *pw_ndxv; /* index part of this word (if array variable) */
+ int pw_ndxc; /* numComponents of the above */
+} t_plusword;
+
+#define PLUSTOT_MAXINLETS 256 /* LATER rethink */
+#define PLUSTOT_INIMAXWORDS 16
+
+/* LATER elaborate */
+#define PLUSTOT_ERRUNKNOWN -1
+#define PLUSTOT_ERROTHER -2
+
+typedef struct _plusproxy
+{
+ t_pd pp_pd;
+ t_pd *pp_master;
+ t_plusvar *pp_var;
+ int pp_ndx;
+ int pp_doit;
+ int pp_warned;
+} t_plusproxy;
+
+typedef struct _plustot
+{
+ t_object x_ob;
+ t_glist *x_glist;
+ t_plustob *x_tob; /* interpreter's result (after invocation) */
+ t_scriptlet *x_script;
+ Tcl_Obj *x_cname; /* command name, main validation flag */
+ Tcl_CmdInfo x_cinfo;
+ t_plusstring *x_ctail; /* command arguments, parse validation flag */
+ Tcl_Parse x_tailparse;
+ int x_maxwords; /* as allocated */
+ int x_nwords; /* as used, including command name */
+ t_plusword *x_words; /* arguments, not evaluated */
+ t_plusword x_wordsini[PLUSTOT_INIMAXWORDS];
+ int x_maxargs; /* == maxwords, except during growing */
+ int x_argc; /* 0 or nwords, except during evaluation */
+ Tcl_Obj **x_argv; /* command name and evaluated arguments */
+ Tcl_Obj *x_argvini[PLUSTOT_INIMAXWORDS];
+ int x_pseudoscalar;
+ int x_nproxies;
+ t_plusproxy **x_proxies;
+ t_plusproxy *x_mainproxy; /* == x_proxies[0], unless pseudo-scalar */
+ int x_grabwarned;
+} t_plustot;
+
+static t_class *plusproxy_class;
+static t_class *plustot_class;
+
+/* Create a variable here only for the main slot. Other slots are to be
+ filled during the second parsing pass, in order to fill only the slots
+ that are actually referenced. If ndx is negative, then create
+ a pseudo-scalar, otherwise this is a pseudo-array element. */
+static t_plusproxy *plusproxy_new(t_pd *master, int ndx, t_plustin *tin)
+{
+ t_plusproxy *pp = (t_plusproxy *)pd_new(plusproxy_class);
+ pp->pp_master = master;
+ pp->pp_var = (ndx > 0 ? 0 : plusvar_new("in", (ndx ? 0 : "0"), tin));
+ if (pp->pp_var)
+ {
+ plusbob_preserve((t_plusbob *)pp->pp_var);
+ plusbob_setowner((t_plusbob *)pp->pp_var, master);
+ }
+ pp->pp_ndx = ndx;
+ pp->pp_doit = (ndx < 1);
+ pp->pp_warned = 0;
+ return (pp);
+}
+
+static void plusproxy_free(t_plusproxy *pp)
+{
+#ifdef PLUSTOT_DEBUG
+ post("plusproxy_free (%s %d)",
+ (pp->pp_var ? pp->pp_var->var_name : "empty"), pp->pp_ndx);
+#endif
+ if (pp->pp_var)
+ plusbob_release((t_plusbob *)pp->pp_var);
+}
+
+static void plusproxy_emptyhit(t_plusproxy *pp)
+{
+ if (!pp->pp_warned)
+ {
+ loud_error(pp->pp_master, "empty slot hit");
+ pp->pp_warned = 1;
+ }
+}
+
+static void plusproxy_bang(t_plusproxy *pp)
+{
+ if (pp->pp_var)
+ plusvar_push(pp->pp_var);
+ else
+ plusproxy_emptyhit(pp);
+}
+
+static void plusproxy_float(t_plusproxy *pp, t_float f)
+{
+ if (pp->pp_var)
+ plusvar_setfloat(pp->pp_var, f, pp->pp_doit);
+ else
+ plusproxy_emptyhit(pp);
+}
+
+static void plusproxy_symbol(t_plusproxy *pp, t_symbol *s)
+{
+ if (pp->pp_var)
+ plusvar_setsymbol(pp->pp_var, s, pp->pp_doit);
+ else
+ plusproxy_emptyhit(pp);
+}
+
+static void plusproxy_list(t_plusproxy *pp, t_symbol *s, int ac, t_atom *av)
+{
+ if (pp->pp_var)
+ plusvar_setlist(pp->pp_var, ac, av, pp->pp_doit);
+ else
+ plusproxy_emptyhit(pp);
+}
+
+#ifdef PLUSTOT_DEBUG
+static void plusproxy_debug(t_plusproxy *pp)
+{
+ t_plustin *tin = ((t_plustob *)pp->pp_var)->tob_tin;
+ t_symbol *id = plusenv_getid((t_plusenv *)tin);
+ t_symbol *glname = plustin_getglistname(tin);
+ post("+proxy %d, glist %x",
+ pp->pp_ndx, (int)((t_plustot *)pp->pp_master)->x_glist);
+ post(" plustin '%s' (%s) over %x", (id ? id->s_name : "default"),
+ (glname ? glname->s_name : "<anonymous>"), (int)tin->tin_interp);
+}
+#endif
+
+/* First pass (!doit): determine number of slots.
+ Second pass (doit): create variables for non-empty slots. */
+static int plustot_usevariable(t_plustot *x, Tcl_Token *tp, int doit)
+{
+ int nc = tp->numComponents;
+ char *errmess = 0;
+ int errcode = PLUSTOT_ERRUNKNOWN;
+#ifdef PLUSTOT_DEBUG
+ if (!doit)
+ {
+ char buf[MAXPDSTRING];
+ int size = tp->size;
+ if (size > (MAXPDSTRING-2))
+ {
+ size = (MAXPDSTRING-2);
+ buf[MAXPDSTRING-2] = '*';
+ buf[MAXPDSTRING-1] = 0;
+ }
+ else buf[size] = 0;
+ strncpy(buf, tp->start, size);
+ startpost("%s ", buf);
+ }
+#endif
+ tp++;
+ if (nc && tp->type == TCL_TOKEN_TEXT)
+ {
+ if (strncmp(tp->start, "in", tp->size))
+ {
+ /* regular variable */
+ /* LATER consider tracing it (2nd pass) */
+ }
+ else
+ {
+ /* pseudo-variable */
+ int inno = -1;
+ tp++;
+ if (nc == 1)
+ {
+ if (x->x_nproxies && !x->x_pseudoscalar)
+ {
+ errmess = "mixed scalar and array forms of pseudo-variable";
+ errcode = PLUSTOT_ERROTHER;
+ goto badvariable;
+ }
+ inno = 0;
+ x->x_pseudoscalar = 1;
+ }
+ else if (nc == 2 && tp->type == TCL_TOKEN_TEXT)
+ {
+ int i;
+ char *p;
+ if (x->x_pseudoscalar)
+ {
+ errmess = "mixed scalar and array forms of pseudo-variable";
+ errcode = PLUSTOT_ERROTHER;
+ goto badvariable;
+ }
+ inno = 0;
+ for (i = 0, p = (char *)tp->start; i < tp->size; i++, p++)
+ {
+ if (*p < '0' || *p > '9')
+ {
+ errmess = "invalid inlet number in pseudo-variable";
+ errcode = PLUSTOT_ERROTHER;
+ goto badvariable;
+ }
+ inno = inno * 10 + (int)(*p - '0');
+ }
+ if (inno > PLUSTOT_MAXINLETS)
+ {
+ errmess = "inlet number too large in pseudo-variable";
+ errcode = PLUSTOT_ERROTHER;
+ goto badvariable;
+ }
+ }
+ else
+ {
+ errmess = "invalid index format in pseudo-variable";
+ errcode = PLUSTOT_ERROTHER;
+ goto badvariable;
+ }
+ if (inno >= 0)
+ {
+ if (!doit)
+ {
+#ifdef PLUSTOT_DEBUG
+ startpost("(inlet %d) ", inno);
+#endif
+ if (inno >= x->x_nproxies)
+ x->x_nproxies = inno + 1;
+ }
+ else if (inno < x->x_nproxies)
+ {
+ if (inno > 0 && !x->x_proxies[inno]->pp_var)
+ {
+ t_plusvar *var;
+ char buf[8];
+ sprintf(buf, "%d", inno);
+ var = plusvar_new("in", buf, x->x_tob->tob_tin);
+ plusbob_preserve((t_plusbob *)var);
+ plusbob_setowner((t_plusbob *)var, (t_pd *)x);
+ x->x_proxies[inno]->pp_var = var;
+ }
+ }
+ else
+ {
+ PLUSDEBUG_ENDPOST("plustot_usevariable");
+ bug("plustot_usevariable");
+ goto badvariable;
+ }
+ }
+ else
+ {
+ errmess = "invalid pseudo-variable";
+ errcode = PLUSTOT_ERROTHER;
+ goto badvariable;
+ }
+ }
+ return (1);
+ }
+ else plusloud_tcldirty((t_pd *)x, "plustot_usevariable");
+badvariable:
+ if (errmess)
+ {
+ PLUSDEBUG_ENDPOST("plustot_usevariable");
+ loud_error((t_pd *)x, errmess);
+ }
+ return (errcode);
+}
+
+static int plustot_doparsevariables(t_plustot *x, Tcl_Interp *interp,
+ const char *buf, int len,
+ Tcl_Parse *parsep, int doit)
+{
+ int nvars = 0;
+ int errcode = PLUSTOT_ERRUNKNOWN;
+ if (Tcl_ParseCommand(interp, buf, len, 0, parsep) == TCL_OK)
+ {
+ int ntok = parsep->numTokens;
+ Tcl_Token *tp = parsep->tokenPtr;
+ while (ntok--)
+ {
+ if (tp->type == TCL_TOKEN_VARIABLE)
+ {
+ int res = plustot_usevariable(x, tp, doit);
+ if (res > 0)
+ nvars++;
+ else
+ {
+ errcode = res;
+ goto parsefailed;
+ }
+ }
+ else if (tp->type == TCL_TOKEN_COMMAND)
+ {
+ if (tp->size > 2)
+ {
+ Tcl_Parse parse;
+ int res =
+ plustot_doparsevariables(x, interp, tp->start + 1,
+ tp->size - 2, &parse, doit);
+ if (res != PLUSTOT_ERRUNKNOWN)
+ Tcl_FreeParse(&parse);
+ if (res >= 0)
+ nvars += res;
+ else
+ {
+ errcode = res;
+ goto parsefailed;
+ }
+ }
+ }
+ else if (tp->type == TCL_TOKEN_SIMPLE_WORD
+ && tp->size > 2 && *tp->start == '{')
+ {
+ tp++;
+#if 0 && defined(PLUSTOT_DEBUG)
+ if (doit && tp->size > 0)
+ {
+ char buf[MAXPDSTRING+1];
+ int sz = (tp->size < MAXPDSTRING ? tp->size : MAXPDSTRING);
+ strncpy(buf, tp->start, sz);
+ buf[sz] = 0;
+ post("simple word's text: %s", buf);
+ }
+#endif
+ if (ntok-- && tp->type == TCL_TOKEN_TEXT && tp->size > 0)
+ {
+ Tcl_Parse parse;
+ int res =
+ plustot_doparsevariables(x, interp, tp->start,
+ tp->size, &parse, doit);
+ if (res != PLUSTOT_ERRUNKNOWN)
+ Tcl_FreeParse(&parse);
+ if (res >= 0)
+ nvars += res;
+ else
+ {
+ errcode = res;
+ goto parsefailed;
+ }
+ }
+ else
+ {
+ plusloud_tcldirty((t_pd *)x, "plustot_doparsevariables");
+ goto parsefailed;
+ }
+ }
+#if 0 && defined(PLUSTOT_DEBUG)
+ else if (doit && tp->size > 0)
+ {
+ char buf[MAXPDSTRING+1];
+ int sz = (tp->size < MAXPDSTRING ? tp->size : MAXPDSTRING);
+ strncpy(buf, tp->start, sz);
+ buf[sz] = 0;
+ post("other type (%d): %s", tp->type, buf);
+ }
+#endif
+ tp++;
+ }
+ }
+ else goto parsefailed;
+ return (nvars);
+parsefailed:
+ return (errcode);
+}
+
+static int plustot_parsevariables(t_plustot *x, Tcl_Interp *interp,
+ const char *buf, int len,
+ Tcl_Parse *parsep, int doit)
+{
+ int nvars;
+#ifdef PLUSTOT_DEBUG
+ if (!doit) startpost("variables: ");
+#endif
+ nvars = plustot_doparsevariables(x, interp, buf, len, parsep, doit);
+#ifdef PLUSTOT_DEBUG
+ if (!doit)
+ {
+ if (nvars > 0)
+ {
+ post("\n%d variable substitutions", nvars);
+ post("%d inlets requested", x->x_nproxies);
+ }
+ else if (nvars == 0) post("none");
+ }
+#endif
+ return (nvars);
+}
+
+static int plustot_makeproxies(t_plustot *x)
+{
+ Tcl_Interp *interp = x->x_tob->tob_tin->tin_interp;
+ if (interp)
+ {
+ if (x->x_nproxies == 1)
+ {
+ x->x_mainproxy =
+ plusproxy_new((t_pd *)x, (x->x_pseudoscalar ? -1 : 0),
+ x->x_tob->tob_tin);
+ }
+ else if (x->x_nproxies > 1 && !x->x_pseudoscalar)
+ {
+ if (x->x_proxies = getbytes(x->x_nproxies * sizeof(*x->x_proxies)))
+ {
+ int i;
+ for (i = 0; i < x->x_nproxies; i++)
+ x->x_proxies[i] =
+ plusproxy_new((t_pd *)x, i, x->x_tob->tob_tin);
+ for (i = 1; i < x->x_nproxies; i++)
+ inlet_new((t_object *)x, (t_pd *)x->x_proxies[i], 0, 0);
+ x->x_mainproxy = x->x_proxies[0];
+ /* second pass: traverse non-empty slots, create variables */
+ plustot_parsevariables(x, interp,
+ x->x_ctail->ps_buf, x->x_ctail->ps_len,
+ &x->x_tailparse, 1);
+ }
+ else goto proxiesfailed;
+ }
+ else
+ {
+ bug("plustot_makeproxies");
+ goto proxiesfailed;
+ }
+ return (1);
+ }
+proxiesfailed:
+ return (0);
+}
+
+static void plustot_initwords(t_plustot *x)
+{
+ if (x->x_words != x->x_wordsini)
+ freebytes(x->x_words, x->x_maxwords * sizeof(*x->x_words));
+ x->x_maxwords = PLUSTOT_INIMAXWORDS;
+ x->x_nwords = 0;
+ x->x_words = x->x_wordsini;
+}
+
+static void plustot_initargs(t_plustot *x)
+{
+ if (x->x_argv != x->x_argvini)
+ freebytes(x->x_argv, x->x_maxargs * sizeof(*x->x_argv));
+ x->x_maxargs = PLUSTOT_INIMAXWORDS;
+ x->x_argc = 0;
+ x->x_argv = x->x_argvini;
+ x->x_argv[0] = x->x_cname;
+}
+
+static int plustot_resetwords(t_plustot *x)
+{
+ int i;
+ for (i = 1; i < x->x_nwords; i++)
+ PLUSDEBUG_DECRREFCOUNT(x->x_words[i].pw_ob, "plustot_resetwords");
+ x->x_nwords = 0;
+ if (x->x_ctail)
+ {
+ int nwords = x->x_tailparse.numWords + 1;
+ if (nwords > x->x_maxwords)
+ {
+ int n = nwords;
+#ifdef PLUSTOT_DEBUG
+ post("growing words %d -> %d", x->x_maxwords, nwords);
+#endif
+ x->x_words = grow_nodata(&n, &x->x_maxwords, x->x_words,
+ PLUSTOT_INIMAXWORDS, x->x_wordsini,
+ sizeof(*x->x_words));
+ if (n != nwords)
+ return (0);
+ }
+ return (1);
+ }
+ else return (0);
+}
+
+static int plustot_resetargs(t_plustot *x)
+{
+ int i;
+ for (i = 1; i < x->x_argc; i++)
+ PLUSDEBUG_DECRREFCOUNT(x->x_argv[i], "plustot_resetargs");
+ x->x_argc = 0;
+ x->x_argv[0] = x->x_cname;
+ if (x->x_ctail)
+ {
+ int nargs = x->x_maxwords;
+ if (nargs > x->x_maxargs)
+ {
+ int n = nargs;
+#ifdef PLUSTOT_DEBUG
+ post("growing argv %d -> %d", x->x_maxargs, nargs);
+#endif
+ x->x_argv = grow_nodata(&n, &x->x_maxargs, x->x_argv,
+ PLUSTOT_INIMAXWORDS, x->x_argvini,
+ sizeof(*x->x_argv));
+ x->x_argv[0] = x->x_cname;
+ if (n != nargs)
+ {
+ plustot_initwords(x);
+ plustot_initargs(x);
+ return (0);
+ }
+ }
+ else if (nargs < x->x_maxargs)
+ {
+ bug("plustot_resetargs"); /* LATER rethink */
+ plustot_initwords(x);
+ plustot_initargs(x);
+ return (0);
+ }
+ return (1);
+ }
+ else return (0);
+}
+
+static int plustot_makewords(t_plustot *x)
+{
+ if (plustot_resetwords(x))
+ {
+ int i, ncomponents = 0, nwords = x->x_tailparse.numWords + 1;
+ Tcl_Token *tp;
+ int len;
+ char buf[TCL_UTF_MAX];
+#ifdef PLUSTOT_DEBUG
+ post("arguments:");
+#endif
+ for (i = 1, tp = x->x_tailparse.tokenPtr;
+ i < nwords; i++, tp += ncomponents)
+ {
+#ifdef PLUSTOT_DEBUG
+ post(" %s token: type %d[%d], having %d[%d] component%s",
+ loud_ordinal(i), tp->type, tp[1].type,
+ tp->numComponents, tp[1].numComponents,
+ (tp->numComponents > 1 ? "s" : ""));
+#endif
+ ncomponents = tp->numComponents;
+ tp++;
+ switch (x->x_words[i].pw_type = tp->type)
+ {
+ case TCL_TOKEN_TEXT:
+ x->x_words[i].pw_ob = Tcl_NewStringObj(tp->start, tp->size);
+ break;
+
+ case TCL_TOKEN_BS:
+ len = Tcl_UtfBackslash(tp->start, 0, buf);
+ x->x_words[i].pw_ob = Tcl_NewStringObj(buf, len);
+ break;
+
+ case TCL_TOKEN_COMMAND:
+ x->x_words[i].pw_ob = Tcl_NewStringObj(tp->start + 1,
+ tp->size - 2);
+ break;
+
+ case TCL_TOKEN_VARIABLE:
+ if (tp->numComponents > 1)
+ {
+ x->x_words[i].pw_ndxv = tp + 2;
+ x->x_words[i].pw_ndxc = tp->numComponents - 1;
+ }
+ else x->x_words[i].pw_ndxv = 0;
+ x->x_words[i].pw_ob = Tcl_NewStringObj(tp[1].start, tp[1].size);
+ break;
+
+ default:
+ plusloud_tcldirty((t_pd *)x,
+ "plustot_makewords (unexpected token type)");
+ goto wordsfailed;
+ }
+ PLUSDEBUG_INCRREFCOUNT(x->x_words[i].pw_ob, "plustot_makewords");
+ }
+ x->x_nwords = nwords;
+ return (1);
+wordsfailed:
+ x->x_nwords = i;
+ plustot_resetwords(x);
+ }
+ return (0);
+}
+
+static int plustot_argsfromwords(t_plustot *x, Tcl_Interp *interp)
+{
+ if (plustot_resetargs(x))
+ {
+ t_plusword *pw;
+ int i;
+ for (i = 1, pw = &x->x_words[1]; i < x->x_nwords; i++, pw++)
+ {
+ int result;
+ if (pw->pw_type == TCL_TOKEN_COMMAND)
+ {
+ result = Tcl_EvalObjEx(interp, pw->pw_ob, 0);
+ if (result == TCL_OK)
+ {
+ if (x->x_argv[i] = Tcl_GetObjResult(interp))
+ {
+ PLUSDEBUG_INCRREFCOUNT(x->x_argv[i],
+ "plustot_argsfromwords");
+ Tcl_ResetResult(interp);
+ }
+ else
+ {
+ plusloud_tcldirty((t_pd *)x, "plustot_argsfromwords");
+ goto evalfailed;
+ }
+ }
+ else
+ {
+ plusloud_tclerror((t_pd *)x, interp, "bad word (command)");
+ goto evalfailed;
+ }
+ }
+ else if (pw->pw_type == TCL_TOKEN_VARIABLE)
+ {
+ Tcl_Obj *indexp;
+ if (x->x_words[i].pw_ndxv)
+ {
+ /* FIXME */
+ int res = Tcl_EvalTokensStandard(interp,
+ x->x_words[i].pw_ndxv,
+ x->x_words[i].pw_ndxc);
+ if (res == TCL_OK)
+ {
+ indexp = Tcl_GetObjResult(interp);
+ PLUSDEBUG_INCRREFCOUNT(indexp,
+ "plustot_argsfromwords");
+ Tcl_ResetResult(interp);
+ }
+ else
+ {
+ plusloud_tclerror((t_pd *)x, interp, "bad index");
+ goto evalfailed;
+ }
+ }
+ else indexp = 0;
+ if (x->x_argv[i] = Tcl_ObjGetVar2(interp, pw->pw_ob, indexp,
+ TCL_LEAVE_ERR_MSG))
+ {
+ PLUSDEBUG_INCRREFCOUNT(x->x_argv[i],
+ "plustot_argsfromwords");
+ Tcl_ResetResult(interp);
+ }
+ else
+ {
+ plusloud_tclerror((t_pd *)x, interp, "bad word (variable)");
+ goto evalfailed;
+ }
+ }
+ else
+ {
+ x->x_argv[i] = pw->pw_ob;
+ /* refcount is 1 already (makewords), but we need to comply to
+ a general rule: args are decremented after use (resetargs) */
+ PLUSDEBUG_INCRREFCOUNT(x->x_argv[i], "plustot_argsfromwords");
+ }
+ }
+ x->x_argc = x->x_nwords;
+ return (1);
+evalfailed:
+ x->x_argc = i;
+ plustot_resetargs(x);
+ }
+ return (0); /* LATER find a proper way for passing a result */
+}
+
+static int plustot_argsfromtokens(t_plustot *x, Tcl_Interp *interp)
+{
+ if (plustot_resetargs(x))
+ {
+ int i, nwords = x->x_tailparse.numWords + 1;
+ Tcl_Token *tp;
+#ifdef PLUSTOT_DEBUG
+ post("arguments:");
+#endif
+ for (i = 1, tp = x->x_tailparse.tokenPtr;
+ i < nwords; i++, tp += (tp->numComponents + 1))
+ {
+ int result;
+#ifdef PLUSTOT_DEBUG
+ startpost(" %s token: type %d[%d], having %d component%s",
+ loud_ordinal(i), tp->type, tp[1].type,
+ tp->numComponents, (tp->numComponents > 1 ? "s" : ""));
+#endif
+ result = Tcl_EvalTokensStandard(interp, tp + 1, tp->numComponents);
+ if (result == TCL_OK)
+ {
+ if (x->x_argv[i] = Tcl_GetObjResult(interp))
+ {
+ PLUSDEBUG_INCRREFCOUNT(x->x_argv[i],
+ "plustot_argsfromwords");
+ Tcl_ResetResult(interp);
+#ifdef PLUSTOT_DEBUG
+ post(", %sshared: '%s'",
+ (Tcl_IsShared(x->x_argv[i]) ? "" : "not "),
+ Tcl_GetString(x->x_argv[i]));
+#endif
+ }
+ else
+ {
+ PLUSDEBUG_ENDPOST("plustot_argsfromtokens");
+ plusloud_tcldirty((t_pd *)x, "plustot_argsfromtokens");
+ }
+ }
+ else
+ {
+ PLUSDEBUG_ENDPOST("plustot_argsfromtokens");
+ plusloud_tclerror((t_pd *)x, interp, "bad token");
+ while (--i)
+ PLUSDEBUG_DECRREFCOUNT(x->x_argv[i],
+ "plustot_argsfromtokens");
+ return (0); /* LATER find a proper way for passing a result */
+ }
+ }
+ x->x_argc = nwords;
+ return (1);
+ }
+ else return (0);
+}
+
+/* not used yet */
+static int plustot_ifgrabshared(t_plustot *x, Tcl_Obj *ob)
+{
+ if (!x->x_grabwarned)
+ {
+ x->x_grabwarned = 1;
+ loud_warning((t_pd *)x, "shared result of a command '%s'",
+ (x->x_cname ? Tcl_GetString(x->x_cname) : "???"));
+ }
+ return (1);
+}
+
+static int plustot_push(t_plustot *x)
+{
+ if (x->x_proxies)
+ {
+ int i;
+ for (i = 1; i < x->x_nproxies; i++)
+ if (x->x_proxies[i]->pp_var)
+ if (!plusvar_push(x->x_proxies[i]->pp_var))
+ return (0);
+ }
+ return (1);
+}
+
+static int plustot_doit(t_plustot *x)
+{
+ int result = 0;
+ Tcl_Interp *interp = x->x_tob->tob_tin->tin_interp;
+ if (x->x_cname && plustot_push(x) &&
+ plustot_argsfromwords(x, interp))
+ {
+ if ((*x->x_cinfo.objProc)(x->x_cinfo.objClientData, interp,
+ x->x_argc, x->x_argv) == TCL_OK)
+ {
+ if (plustob_grabresult(x->x_tob))
+ result = 1;
+ }
+ else plusloud_tclerror((t_pd *)x, interp, "command failed");
+ /* Although args are to be reset in the next call to
+ plustot_argsfromwords(), however, plusvar_preset() will be called
+ first, so, unless reset is done here, $ins would be shared there.
+ LATER rethink. */
+ plustot_resetargs(x);
+ }
+ return (result);
+}
+
+static void plustot_eval(t_plustot *x)
+{
+ plustot_doit(x);
+}
+
+static void plustot_get(t_plustot *x)
+{
+ if (x->x_tob->tob_value)
+ outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob);
+}
+
+/* set in(0), no evaluation */
+static void plustot_set(t_plustot *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_mainproxy)
+ {
+ if (ac == 1)
+ {
+ if (av->a_type == A_FLOAT)
+ plusproxy_float(x->x_mainproxy, av->a_w.w_float);
+ else if (av->a_type == A_SYMBOL)
+ plusproxy_symbol(x->x_mainproxy, av->a_w.w_symbol);
+ }
+ else plusproxy_list(x->x_mainproxy, s, ac, av);
+ }
+}
+
+static void plustot_bang(t_plustot *x)
+{
+ if (x->x_mainproxy)
+ plusproxy_bang(x->x_mainproxy);
+ if (plustot_doit(x))
+ outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob);
+}
+
+static void plustot_float(t_plustot *x, t_float f)
+{
+ if (x->x_mainproxy)
+ plusproxy_float(x->x_mainproxy, f);
+ if (plustot_doit(x))
+ outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob);
+}
+
+static void plustot_symbol(t_plustot *x, t_symbol *s)
+{
+ if (x->x_mainproxy)
+ plusproxy_symbol(x->x_mainproxy, s);
+ if (plustot_doit(x))
+ outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob);
+}
+
+static void plustot_list(t_plustot *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (x->x_mainproxy)
+ plusproxy_list(x->x_mainproxy, s, ac, av);
+ if (plustot_doit(x))
+ outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob);
+}
+
+static void plustot_tot(t_plustot *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (ac)
+ {
+ Tcl_Obj *ob;
+ char *start;
+ int len;
+ scriptlet_reset(x->x_script);
+ scriptlet_add(x->x_script, 1, 1, ac, av);
+ start = scriptlet_getcontents(x->x_script, &len);
+ if (len > 0 && (ob = Tcl_NewStringObj(start, len)))
+ {
+ /* LATER set a persistent ob, rather than create a new one */
+ PLUSDEBUG_INCRREFCOUNT(ob, "plustot_tot");
+ if (plustob_evalob(x->x_tob, ob) && s == totps_query)
+ outlet_plusbob(((t_object *)x)->ob_outlet,
+ (t_plusbob *)x->x_tob);
+ PLUSDEBUG_DECRREFCOUNT(ob, "plustot_tot");
+ }
+ }
+}
+
+#ifdef PLUSTOT_DEBUG
+static void plustot_debug(t_plustot *x)
+{
+ t_plustin *tin = x->x_tob->tob_tin;
+ t_symbol *id = plusenv_getid((t_plusenv *)tin);
+ t_symbol *glname = plustin_getglistname(tin);
+ post("+tot, glist %x", (int)x->x_glist);
+ post(" plustin '%s' (%s) over %x", (id ? id->s_name : "default"),
+ (glname ? glname->s_name : "<anonymous>"), (int)tin->tin_interp);
+ if (x->x_mainproxy)
+ plusproxy_debug(x->x_mainproxy);
+}
+#endif
+
+static void plustot_free(t_plustot *x)
+{
+ int i;
+ plusbob_release((t_plusbob *)x->x_tob);
+ if (x->x_cname) PLUSDEBUG_DECRREFCOUNT(x->x_cname, "plustot_free");
+ if (x->x_ctail)
+ {
+ for (i = 1; i < x->x_nwords; i++)
+ PLUSDEBUG_DECRREFCOUNT(x->x_words[i].pw_ob, "plustot_free");
+ for (i = 1; i < x->x_argc; i++)
+ PLUSDEBUG_DECRREFCOUNT(x->x_argv[i], "plustot_free");
+ if (x->x_words != x->x_wordsini)
+ freebytes(x->x_words, x->x_maxwords * sizeof(*x->x_words));
+ if (x->x_argv != x->x_argvini)
+ freebytes(x->x_argv, x->x_maxwords * sizeof(*x->x_argv));
+ Tcl_FreeParse(&x->x_tailparse);
+ plusstring_release(x->x_ctail);
+ }
+ if (x->x_mainproxy) pd_free((t_pd *)x->x_mainproxy);
+ if (x->x_proxies)
+ {
+ for (i = 1; i < x->x_nproxies; i++)
+ pd_free((t_pd *)x->x_proxies[i]);
+ freebytes(x->x_proxies, x->x_nproxies * sizeof(*x->x_proxies));
+ }
+ if (x->x_script) scriptlet_free(x->x_script);
+}
+
+static void *plustot_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_plustot *x = 0;
+ t_plusstring *ctail = 0;
+ t_symbol *cmdname = 0; /* command name or +selector */
+ t_glist *glist = canvas_getcurrent();
+ t_plustin *tin = 0;
+ t_plustob *tob = 0;
+ t_scriptlet *script = scriptlet_new(0, 0, 0, 0, glist, 0);
+ if (ac && av->a_type == A_SYMBOL)
+ {
+ cmdname = av->a_w.w_symbol;
+ ac--; av++;
+ if (*cmdname->s_name == '+')
+ {
+ if (cmdname == plusps_env)
+ return (plustot_env_new(cmdname, ac, av));
+ else if (cmdname == plusps_in)
+ return (plustot_in_new(cmdname, ac, av));
+ else if (cmdname == plusps_var)
+ return (plustot_var_new(cmdname, ac, av));
+ else if (cmdname == plusps_out)
+ return (plustot_out_new(cmdname, ac, av));
+ else if (cmdname == plusps_qlist)
+ return (plustot_qlist_new(cmdname, ac, av));
+ else if (cmdname == plusps_print)
+ return (plustot_print_new(cmdname, ac, av));
+ else
+ {
+ loud_error(0, "unknown +tot's subclass");
+ return (0);
+ }
+ }
+ if (ac)
+ {
+ ctail = plusstring_fromatoms(ac, av, script);
+ plusstring_preserve(ctail);
+ }
+ }
+ if ((tin = plustin_glistprovide(glist, PLUSTIN_GLIST_ANY, 0)) &&
+ (tob = plustob_new(tin, 0)))
+ {
+ x = (t_plustot *)pd_new(plustot_class);
+ /* tin already preserved (plustob_new() did it) */
+ plusbob_preserve((t_plusbob *)tob);
+ plusbob_setowner((t_plusbob *)tob, (t_pd *)x);
+ x->x_glist = glist;
+ x->x_tob = tob;
+ scriptlet_setowner(script, (t_pd *)x);
+ x->x_script = script;
+ x->x_cname = 0;
+ x->x_ctail = 0;
+ x->x_words = x->x_wordsini;
+ plustot_initwords(x);
+ x->x_argv = x->x_argvini;
+ plustot_initargs(x);
+ x->x_pseudoscalar = 0;
+ x->x_nproxies = 0;
+ x->x_proxies = 0;
+ x->x_mainproxy = 0;
+ x->x_grabwarned = 0;
+ if (cmdname && *cmdname->s_name)
+ {
+ Tcl_Interp *interp = tin->tin_interp;
+ if (interp)
+ {
+ if (Tcl_GetCommandInfo(interp, cmdname->s_name, &x->x_cinfo))
+ {
+ if (x->x_cinfo.isNativeObjectProc)
+ {
+ x->x_cname = Tcl_NewStringObj(cmdname->s_name, -1);
+ PLUSDEBUG_INCRREFCOUNT(x->x_cname, "plustot_new");
+ x->x_argv[0] = x->x_cname;
+ }
+ else loud_error((t_pd *)x, "'%s' is not an object command",
+ cmdname->s_name);
+ }
+ else loud_error((t_pd *)x, "command '%s' does not exist",
+ cmdname->s_name);
+ if (x->x_cname && ctail)
+ {
+ int nvars =
+ plustot_parsevariables(x, interp,
+ ctail->ps_buf, ctail->ps_len,
+ &x->x_tailparse, 0);
+ if (nvars >= 0)
+ {
+ int res = 1;
+ x->x_ctail = ctail;
+ if (x->x_nproxies)
+ res = plustot_makeproxies(x);
+ if (res)
+ res = plustot_makewords(x);
+ if (!res)
+ x->x_ctail = 0;
+ Tcl_FreeParse(&x->x_tailparse);
+ }
+ else
+ {
+ if (nvars == PLUSTOT_ERRUNKNOWN)
+ plusloud_tclerror((t_pd *)x, interp,
+ "parsing command arguments failed");
+ else
+ Tcl_FreeParse(&x->x_tailparse);
+ PLUSDEBUG_DECRREFCOUNT(x->x_cname, "plustot_new");
+ x->x_cname = 0;
+ }
+ }
+ }
+ }
+ outlet_new((t_object *)x, &s_symbol);
+ }
+ else
+ {
+ loud_error(0, "+tot: cannot initialize");
+ if (tin)
+ {
+ plusbob_preserve((t_plusbob *)tin);
+ plusbob_release((t_plusbob *)tin);
+ }
+ if (script) scriptlet_free(script);
+ }
+ if (ctail && !(x && x->x_ctail))
+ plusstring_release(ctail);
+ return (x);
+}
+
+void plustot_setup(void)
+{
+ post("beware! this is plustot %s, %s %s build...",
+ TOXY_VERSION, loud_ordinal(TOXY_BUILD), TOXY_RELEASE);
+ plustot_class = class_new(gensym("+tot"),
+ (t_newmethod)plustot_new,
+ (t_method)plustot_free,
+ sizeof(t_plustot), 0, A_GIMME, 0);
+ class_addcreator((t_newmethod)plustot_new,
+ gensym("plustot"), A_GIMME, 0);
+ class_addbang(plustot_class, plustot_bang);
+ class_addfloat(plustot_class, plustot_float);
+ class_addsymbol(plustot_class, plustot_symbol);
+ class_addlist(plustot_class, plustot_list);
+ class_addmethod(plustot_class, (t_method)plustot_eval,
+ gensym("eval"), 0);
+ class_addmethod(plustot_class, (t_method)plustot_set,
+ gensym("set"), A_GIMME, 0);
+ class_addmethod(plustot_class, (t_method)plustot_get,
+ gensym("get"), 0);
+ class_addmethod(plustot_class, (t_method)plustot_tot,
+ gensym("tot"), A_GIMME, 0);
+ class_addmethod(plustot_class, (t_method)plustot_tot,
+ gensym("query"), A_GIMME, 0);
+#ifdef PLUSTOT_DEBUG
+ class_addmethod(plustot_class, (t_method)plustot_debug,
+ gensym("debug"), 0);
+#endif
+
+ plusproxy_class = class_new(gensym("+tot proxy"), 0,
+ (t_method)plusproxy_free,
+ sizeof(t_plusproxy), CLASS_PD, 0);
+ class_addfloat(plusproxy_class, plusproxy_float);
+ class_addsymbol(plusproxy_class, plusproxy_symbol);
+ class_addlist(plusproxy_class, plusproxy_list);
+#ifdef PLUSTOT_DEBUG
+ class_addmethod(plusproxy_class, (t_method)plusproxy_debug,
+ gensym("debug"), 0);
+#endif
+
+ plusps_tot = gensym("+tot");
+ plusps_env = gensym("+env");
+ plusps_in = gensym("+in");
+ plusps_var = gensym("+var");
+ plusps_out = gensym("+out");
+ plusps_qlist = gensym("+qlist");
+ plusps_print = gensym("+print");
+ plusps_Ti = gensym("+Ti");
+ plusps_To = gensym("+To");
+ plusps_Tv = gensym("+Tv");
+ totps_query = gensym("query");
+
+ plustin_basetype = plusenv_setup();
+ plustin_type = plustype_new(plustin_basetype, plusps_Ti,
+ sizeof(t_plustin),
+ (t_plustypefn)plustin_delete, 0, 0, 0);
+ plustob_type = plustype_new(0, plusps_To,
+ sizeof(t_plustob),
+ (t_plustypefn)plustob_delete, 0, 0,
+ (t_plustypefn)plustob_attach);
+ plusvar_type = plustype_new(plustob_type, plusps_Tv,
+ sizeof(t_plusvar),
+ (t_plustypefn)plusvar_delete, 0, 0, 0);
+
+ plustot_env_setup();
+ plustot_in_setup();
+ plustot_var_setup();
+ plustot_out_setup();
+ plustot_qlist_setup();
+ plustot_print_setup();
+}
diff --git a/toxy/plustot.env.c b/toxy/plustot.env.c
new file mode 100644
index 0000000..c1dbfe2
--- /dev/null
+++ b/toxy/plustot.env.c
@@ -0,0 +1,150 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#ifdef NT
+#include <io.h>
+#endif
+#include "m_pd.h"
+#include "g_canvas.h"
+#include "common/loud.h"
+#include "hammer/file.h"
+#include "toxy/plusbob.h"
+#include "plustot.h"
+
+typedef struct _plustot_env
+{
+ t_object x_ob;
+ t_plustin *x_tin;
+ t_glist *x_glist;
+ t_hammerfile *x_filehandle;
+} t_plustot_env;
+
+static t_class *plustot_env_class;
+
+static void plustot_env_takeover(t_glist *glist, t_plusbob *defparent,
+ t_plusbob *newparent)
+{
+ t_gobj *g;
+ for (g = glist->gl_list; g; g = g->g_next)
+ {
+ if (pd_class(&g->g_pd) == canvas_class)
+ {
+ if (!plustin_glistfind((t_glist *)g, PLUSTIN_GLIST_THIS))
+ plustot_env_takeover((t_glist *)g, defparent, newparent);
+ }
+ else plusbob_detachownedchildren(defparent, newparent, (t_pd *)g);
+ }
+}
+
+static void plustot_env_evalfile(t_plustot_env *x, t_symbol *fname)
+{
+ char buf1[MAXPDSTRING], buf2[MAXPDSTRING], *nameptr, *dir;
+ int fd;
+ dir = canvas_getdir(x->x_glist)->s_name;
+ if ((fd = open_via_path(dir, fname->s_name, "",
+ buf1, &nameptr, MAXPDSTRING, 0)) < 0)
+ {
+ loud_error((t_pd *)x, "file '%s' not found", fname->s_name);
+ }
+ else
+ {
+ Tcl_Interp *interp = plustin_getinterp(x->x_tin);
+ FILE *fp;
+ close(fd);
+ strcpy(buf2, buf1);
+ strcat(buf2, "/");
+ strcat(buf2, nameptr);
+ sys_bashfilename(buf2, buf2);
+ Tcl_Preserve(interp);
+ if (Tcl_EvalFile(interp, buf2) != TCL_OK)
+ {
+ strcpy(buf1, "evaluation failed (");
+ strncat(buf1, buf2, MAXPDSTRING - strlen(buf1) - 2);
+ strcat(buf1, ")");
+ plusloud_tclerror((t_pd *)x, interp, buf1);
+ }
+ Tcl_Release(interp);
+ }
+}
+
+static void plustot_env_evalfilehook(t_pd *z, t_symbol *fn, int ac, t_atom *av)
+{
+ plustot_env_evalfile((t_plustot_env *)z, fn);
+}
+
+static void plustot_env_bang(t_plustot_env *x)
+{
+ outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tin);
+}
+
+static void plustot_env_source(t_plustot_env *x, t_symbol *s)
+{
+ if (s && s != &s_)
+ plustot_env_evalfile(x, s);
+ else
+ hammerpanel_open(x->x_filehandle, 0);
+}
+
+static void plustot_env_free(t_plustot_env *x)
+{
+ t_plustin *tin = plustin_glistprovide(x->x_glist, PLUSTIN_GLIST_UP, 0);
+ plusbob_detachchildren((t_plusbob *)x->x_tin, (t_plusbob *)tin);
+ plusbob_release((t_plusbob *)x->x_tin);
+ hammerfile_free(x->x_filehandle);
+}
+
+void *plustot_env_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_plustot_env *x = 0;
+ t_glist *gl = canvas_getcurrent();
+ t_plustin *oldtin = plustin_glistfind(gl, PLUSTIN_GLIST_THIS);
+ t_plustin *deftin = (oldtin ? 0 : plustin_glistfind(gl, PLUSTIN_GLIST_ANY));
+ t_plustin *tin = 0;
+ if ((tin = oldtin)
+ || (tin = plustin_glistprovide(gl, PLUSTIN_GLIST_THIS, 1)))
+ {
+ int warned = 0;
+ x = (t_plustot_env *)pd_new(plustot_env_class);
+ x->x_tin = tin;
+ plusbob_preserve((t_plusbob *)tin);
+ x->x_glist = gl;
+ outlet_new((t_object *)x, &s_symbol);
+ if (deftin)
+ /* true if both oldtin == 0 (we are first in this glist)
+ and plustin_default != 0 (bobs exist already) */
+ plustot_env_takeover(x->x_glist,
+ (t_plusbob *)deftin, (t_plusbob *)tin);
+ x->x_filehandle = hammerfile_new((t_pd *)x, 0,
+ plustot_env_evalfilehook, 0, 0);
+ while (ac--)
+ {
+ if (av->a_type == A_SYMBOL)
+ plustot_env_evalfile(x, av->a_w.w_symbol);
+ else if (!warned)
+ {
+ loud_warning((t_pd *)x, "bad atom");
+ warned = 1;
+ }
+ av++;
+ }
+ }
+ else loud_error(0, "+env: cannot initialize");
+ return (x);
+}
+
+void plustot_env_setup(void)
+{
+ plustot_env_class = class_new(gensym("+env"), 0,
+ (t_method)plustot_env_free,
+ sizeof(t_plustot_env), 0, 0);
+ class_addbang(plustot_env_class, plustot_env_bang);
+ class_addmethod(plustot_env_class, (t_method)plustot_env_source,
+ gensym("source"), A_DEFSYM, 0);
+ hammerfile_setup(plustot_env_class, 0);
+}
diff --git a/toxy/plustot.h b/toxy/plustot.h
new file mode 100644
index 0000000..e08e7b0
--- /dev/null
+++ b/toxy/plustot.h
@@ -0,0 +1,81 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#ifndef __PLUSTOT_H__
+#define __PLUSTOT_H__
+
+#define PD_EXTERN EXTERN
+#undef EXTERN
+#include <tcl.h>
+#undef EXTERN
+#define EXTERN PD_EXTERN
+#undef PD_EXTERN
+
+EXTERN_STRUCT _plustin;
+#define t_plustin struct _plustin
+EXTERN_STRUCT _plustob;
+#define t_plustob struct _plustob
+EXTERN_STRUCT _plusvar;
+#define t_plusvar struct _plusvar
+
+t_symbol *plusps_Ti;
+t_symbol *plusps_To;
+t_symbol *plusps_Tv;
+
+#define PLUSTOB_MAKEIT ((Tcl_Obj *)-1)
+
+typedef int (*t_plusifsharedfn)(t_plusbob *, Tcl_Obj *);
+
+enum { PLUSTIN_GLIST_THIS, PLUSTIN_GLIST_ANY, PLUSTIN_GLIST_UP };
+
+void plusloud_tclerror(t_pd *caller, Tcl_Interp *interp, char *msg);
+
+t_plustin *plustin_create(t_plustype *tp, t_plusbob *parent, t_symbol *id);
+Tcl_Interp *plustin_getinterp(t_plustin *tin);
+t_symbol *plustin_glistid(t_glist *gl);
+t_plustin *plustin_glistfind(t_glist *gl, int mode);
+t_plustin *plustin_glistprovide(t_glist *gl, int mode, int create);
+t_symbol *plustin_getglistname(t_plustin *tin);
+
+t_plustob *plustob_create(t_plustype *tp, t_plustin *tin, Tcl_Obj *ob);
+t_plustob *plustob_new(t_plustin *tin, Tcl_Obj *ob);
+void plustob_setifshared(t_plustob *tob, t_plusifsharedfn ifsharedfn);
+int plustob_isshared(t_plustob *tob);
+Tcl_Obj *plustob_getvalue(t_plustob *tob);
+t_plustin *plustag_tobtin(t_symbol *s, t_pd *caller);
+Tcl_Obj *plustag_tobvalue(t_symbol *s, t_pd *caller);
+Tcl_Obj *plusatom_tobvalue(t_atom *ap, t_pd *caller);
+Tcl_Obj *plustob_set(t_plustob *tob, t_plustin *tin, Tcl_Obj *ob);
+Tcl_Obj *plustob_setfloat(t_plustob *tob, t_float f);
+Tcl_Obj *plustob_setsymbol(t_plustob *tob, t_symbol *s);
+Tcl_Obj *plustob_setlist(t_plustob *tob, int ac, t_atom *av);
+Tcl_Obj *plustob_setbinbuf(t_plustob *tob, t_binbuf *bb);
+Tcl_Obj *plustob_grabresult(t_plustob *tob);
+Tcl_Obj *plustob_evalob(t_plustob *tob, Tcl_Obj *ob);
+
+t_plusvar *plusvar_create(t_plustype *tp, t_plustin *tin, Tcl_Obj *ob,
+ char *name, char *index);
+t_plusvar *plusvar_new(char *name, char *index, t_plustin *tin);
+Tcl_Obj *plusvar_push(t_plusvar *var);
+Tcl_Obj *plusvar_pull(t_plusvar *var);
+Tcl_Obj *plusvar_set(t_plusvar *var, Tcl_Obj *ob, int doit);
+Tcl_Obj *plusvar_setfloat(t_plusvar *var, t_float f, int doit);
+Tcl_Obj *plusvar_setsymbol(t_plusvar *var, t_symbol *s, int doit);
+Tcl_Obj *plusvar_setlist(t_plusvar *var, int ac, t_atom *av, int doit);
+
+void plustot_env_setup(void);
+void plustot_in_setup(void);
+void plustot_var_setup(void);
+void plustot_out_setup(void);
+void plustot_qlist_setup(void);
+void plustot_print_setup(void);
+
+void *plustot_env_new(t_symbol *s, int ac, t_atom *av);
+void *plustot_in_new(t_symbol *s, int ac, t_atom *av);
+void *plustot_var_new(t_symbol *s, int ac, t_atom *av);
+void *plustot_out_new(t_symbol *s, int ac, t_atom *av);
+void *plustot_qlist_new(t_symbol *s, int ac, t_atom *av);
+void *plustot_print_new(t_symbol *s, int ac, t_atom *av);
+
+#endif
diff --git a/toxy/plustot.in.c b/toxy/plustot.in.c
new file mode 100644
index 0000000..206b8b0
--- /dev/null
+++ b/toxy/plustot.in.c
@@ -0,0 +1,126 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+#include "toxy/plusbob.h"
+#include "plustot.h"
+
+typedef struct _plusproxy_in
+{
+ t_pd pp_pd;
+ t_plustob *pp_tob;
+} t_plusproxy_in;
+
+typedef struct _plustot_in
+{
+ t_object x_ob;
+ t_glist *x_glist;
+ t_plustob *x_tob;
+ t_plusproxy_in *x_proxy;
+} t_plustot_in;
+
+static t_class *plusproxy_in_class;
+static t_class *plustot_in_class;
+
+static t_plusproxy_in *plusproxy_in_new(t_pd *master)
+{
+ t_plusproxy_in *pp = (t_plusproxy_in *)pd_new(plusproxy_in_class);
+ pp->pp_tob = ((t_plustot_in *)master)->x_tob;
+ return (pp);
+}
+
+static void plusproxy_in_float(t_plusproxy_in *pp, t_float f)
+{
+ plustob_setfloat(pp->pp_tob, f);
+}
+
+static void plusproxy_in_symbol(t_plusproxy_in *pp, t_symbol *s)
+{
+ plustob_setsymbol(pp->pp_tob, s);
+}
+
+static void plusproxy_in_list(t_plusproxy_in *pp,
+ t_symbol *s, int ac, t_atom *av)
+{
+ plustob_setlist(pp->pp_tob, ac, av);
+}
+
+static void plustot_in_bang(t_plustot_in *x)
+{
+ if (plustob_getvalue(x->x_tob))
+ outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob);
+}
+
+static void plustot_in_float(t_plustot_in *x, t_float f)
+{
+ if (plustob_setfloat(x->x_tob, f))
+ outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob);
+}
+
+static void plustot_in_symbol(t_plustot_in *x, t_symbol *s)
+{
+ if (plustob_setsymbol(x->x_tob, s))
+ outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob);
+}
+
+static void plustot_in_list(t_plustot_in *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (plustob_setlist(x->x_tob, ac, av))
+ outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_tob);
+}
+
+static void plustot_in_free(t_plustot_in *x)
+{
+ plusbob_release((t_plusbob *)x->x_tob);
+ if (x->x_proxy) pd_free((t_pd *)x->x_proxy);
+}
+
+void *plustot_in_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_plustot_in *x = 0;
+ t_glist *glist = canvas_getcurrent();
+ t_plustin *tin = 0;
+ t_plustob *tob = 0;
+ if ((tin = plustin_glistprovide(glist, PLUSTIN_GLIST_ANY, 0)) &&
+ (tob = plustob_new(tin, 0)))
+ {
+ x = (t_plustot_in *)pd_new(plustot_in_class);
+ plusbob_preserve((t_plusbob *)tob);
+ plusbob_setowner((t_plusbob *)tob, (t_pd *)x);
+ plustob_setlist(tob, ac, av);
+ x->x_glist = glist;
+ x->x_tob = tob;
+ x->x_proxy = plusproxy_in_new((t_pd *)x);
+ inlet_new((t_object *)x, (t_pd *)x->x_proxy, 0, 0);
+ outlet_new((t_object *)x, &s_symbol);
+ }
+ else
+ {
+ loud_error(0, "+in: cannot initialize");
+ if (tin)
+ {
+ plusbob_preserve((t_plusbob *)tin);
+ plusbob_release((t_plusbob *)tin);
+ }
+ }
+ return (x);
+}
+
+void plustot_in_setup(void)
+{
+ plustot_in_class = class_new(gensym("+in"), 0,
+ (t_method)plustot_in_free,
+ sizeof(t_plustot_in), 0, 0);
+ class_addbang(plustot_in_class, plustot_in_bang);
+ class_addfloat(plustot_in_class, plustot_in_float);
+ class_addsymbol(plustot_in_class, plustot_in_symbol);
+ class_addlist(plustot_in_class, plustot_in_list);
+
+ plusproxy_in_class = class_new(gensym("+in proxy"), 0, 0,
+ sizeof(t_plusproxy_in), CLASS_PD, 0);
+ class_addfloat(plusproxy_in_class, plusproxy_in_float);
+ class_addsymbol(plusproxy_in_class, plusproxy_in_symbol);
+ class_addlist(plusproxy_in_class, plusproxy_in_list);
+}
diff --git a/toxy/plustot.out.c b/toxy/plustot.out.c
new file mode 100644
index 0000000..9b70d55
--- /dev/null
+++ b/toxy/plustot.out.c
@@ -0,0 +1,71 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+#include "toxy/plusbob.h"
+#include "plustot.h"
+
+typedef struct _plustot_out
+{
+ t_object x_ob;
+ t_binbuf *x_bb;
+} t_plustot_out;
+
+static t_class *plustot_out_class;
+
+static void plustot_out_symbol(t_plustot_out *x, t_symbol *s)
+{
+ Tcl_Obj *ob = plustag_tobvalue(s, (t_pd *)x);
+ if (ob)
+ {
+ int len;
+ char *ptr;
+ Tcl_IncrRefCount(ob);
+ ptr = Tcl_GetStringFromObj(ob, &len);
+ if (ptr && len)
+ {
+ int ac;
+ binbuf_text(x->x_bb, ptr, len);
+ if (ac = binbuf_getnatom(x->x_bb))
+ {
+ t_atom *av = binbuf_getvec(x->x_bb);
+ if (av->a_type == A_SYMBOL)
+ outlet_anything(((t_object *)x)->ob_outlet,
+ av->a_w.w_symbol, ac - 1, av + 1);
+ else if (av->a_type == A_FLOAT)
+ {
+ if (ac > 1)
+ outlet_list(((t_object *)x)->ob_outlet,
+ &s_list, ac, av);
+ else
+ outlet_float(((t_object *)x)->ob_outlet,
+ av->a_w.w_float);
+ }
+ }
+ }
+ Tcl_DecrRefCount(ob);
+ }
+}
+
+static void plustot_out_free(t_plustot_out *x)
+{
+ binbuf_free(x->x_bb);
+}
+
+void *plustot_out_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_plustot_out *x = (t_plustot_out *)pd_new(plustot_out_class);
+ x->x_bb = binbuf_new();
+ outlet_new((t_object *)x, &s_anything);
+ return (x);
+}
+
+void plustot_out_setup(void)
+{
+ plustot_out_class = class_new(gensym("+out"), 0,
+ (t_method)plustot_out_free,
+ sizeof(t_plustot_out), 0, 0);
+ class_addsymbol(plustot_out_class, plustot_out_symbol);
+}
diff --git a/toxy/plustot.print.c b/toxy/plustot.print.c
new file mode 100644
index 0000000..42ef385
--- /dev/null
+++ b/toxy/plustot.print.c
@@ -0,0 +1,90 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+#include "toxy/plusbob.h"
+#include "plustot.h"
+
+typedef struct _plustot_print
+{
+ t_object x_ob;
+ t_symbol *x_label;
+ t_binbuf *x_bb;
+} t_plustot_print;
+
+static t_class *plustot_print_class;
+
+static void plustot_print_symbol(t_plustot_print *x, t_symbol *s)
+{
+ Tcl_Obj *ob = plustag_tobvalue(s, (t_pd *)x);
+ if (ob)
+ {
+ int len;
+ char *ptr;
+ Tcl_IncrRefCount(ob);
+ ptr = Tcl_GetStringFromObj(ob, &len);
+ if (ptr && len)
+ {
+ int ac;
+ binbuf_text(x->x_bb, ptr, len);
+ if (ac = binbuf_getnatom(x->x_bb))
+ {
+ t_plustin *tin = plustag_tobtin(s, (t_pd *)x);
+ t_symbol *glname = (tin ? plustin_getglistname(tin) : 0);
+ t_atom *av = binbuf_getvec(x->x_bb);
+ if (av->a_type == A_SYMBOL || av->a_type == A_FLOAT)
+ {
+ char *lstring =
+ (x->x_label ? x->x_label->s_name :
+ loud_symbolname(plustag_typename(s, 1, (t_pd *)x),
+ "???"));
+ if (glname)
+ startpost("%s (%s):", lstring, glname->s_name);
+ else
+ startpost("%s:", lstring);
+ }
+ /* FIXME {1.0, 1.0}, etc. */
+ if (av->a_type == A_SYMBOL)
+ {
+ startpost(" %s", av->a_w.w_symbol->s_name);
+ postatom(ac - 1, av + 1);
+ endpost();
+ }
+ else if (av->a_type == A_FLOAT)
+ {
+ if (ac > 1)
+ {
+ postatom(ac, av);
+ endpost();
+ }
+ else post(" %g", av->a_w.w_float);
+ }
+ }
+ /* LATER consider printing empty list as 'bang' */
+ }
+ Tcl_DecrRefCount(ob);
+ }
+}
+
+static void plustot_print_free(t_plustot_print *x)
+{
+ binbuf_free(x->x_bb);
+}
+
+void *plustot_print_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_plustot_print *x = (t_plustot_print *)pd_new(plustot_print_class);
+ x->x_label = (ac && av->a_type == A_SYMBOL ? av->a_w.w_symbol : 0);
+ x->x_bb = binbuf_new();
+ return (x);
+}
+
+void plustot_print_setup(void)
+{
+ plustot_print_class = class_new(gensym("+print"), 0,
+ (t_method)plustot_print_free,
+ sizeof(t_plustot_print), 0, 0);
+ class_addsymbol(plustot_print_class, plustot_print_symbol);
+}
diff --git a/toxy/plustot.qlist.c b/toxy/plustot.qlist.c
new file mode 100644
index 0000000..b49aeb1
--- /dev/null
+++ b/toxy/plustot.qlist.c
@@ -0,0 +1,212 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include <string.h>
+#include "m_pd.h"
+#include "unstable/fragile.h"
+#include "common/loud.h"
+#include "toxy/plusbob.h"
+#include "plustot.h"
+
+#define PLUSTOT_QLIST_DEBUG
+
+/* Need only an access to x_binbuf field. */
+typedef struct _qlist
+{
+ t_object x_ob;
+ t_outlet *x_bangout;
+ void *x_binbuf;
+} t_qlist;
+
+typedef struct _plusproxy_qlist
+{
+ t_pd pp_pd;
+ struct _plustot_qlist *pp_master;
+} t_plusproxy_qlist;
+
+typedef struct _plustot_qlist
+{
+ t_object x_ob;
+ t_glist *x_glist;
+ t_plustob *x_tob;
+ t_outlet *x_rightout;
+ t_plusproxy_qlist *x_proxy;
+} t_plustot_qlist;
+
+static t_class *plusproxy_qlist_class;
+static t_class *plustot_qlist_class;
+
+static t_binbuf *plustot_qlist_usurp(t_plustot_qlist *x)
+{
+ static t_symbol *types[2];
+ static int ntypes = 0;
+ t_object *booty;
+ if (ntypes == 0)
+ {
+ types[0] = gensym("qlist");
+ types[1] = gensym("textfile");
+ ntypes = 2;
+ }
+ if (booty = fragile_outlet_destination(
+ ((t_object *)x)->ob_outlet, ntypes, types,
+ (t_pd *)x, "(connect left outlet to a qlist or textfile)"))
+ {
+ t_binbuf *bb = ((t_qlist *)booty)->x_binbuf;
+#ifdef PLUSTOT_QLIST_DEBUG
+ post("booty '%s' at %x:", class_getname(*(t_pd *)booty), (int)booty);
+ binbuf_print(bb);
+#endif
+ return (bb);
+ }
+ else return (0);
+}
+
+static t_plusproxy_qlist *plusproxy_qlist_new(t_plustot_qlist *master)
+{
+ t_plusproxy_qlist *pp = (t_plusproxy_qlist *)pd_new(plusproxy_qlist_class);
+ pp->pp_master = master;
+ return (pp);
+}
+
+static void plusproxy_qlist_symbol(t_plusproxy_qlist *pp, t_symbol *s)
+{
+ t_plustot_qlist *x = pp->pp_master;
+ Tcl_Interp *interp = 0;
+ if (plustag_isvalid(s, 0))
+ {
+ t_plustin *tin;
+ Tcl_Obj *ob;
+ if ((tin = plustag_tobtin(s, PLUSBOB_OWNER)) &&
+ (ob = plustob_getvalue((t_plustob *)s)))
+ {
+ t_binbuf *bb;
+ if (bb = plustot_qlist_usurp(x))
+ {
+ int nlists;
+ Tcl_Obj **lists;
+ interp = plustin_getinterp(tin);
+ if (Tcl_ListObjGetElements(interp, ob,
+ &nlists, &lists) == TCL_OK)
+ {
+ int lc;
+ Tcl_Obj **lp;
+ binbuf_clear(bb);
+ for (lc = 0, lp = lists; lc < nlists; lc++, lp++)
+ {
+ int natoms;
+ Tcl_Obj **atoms;
+ if (Tcl_ListObjGetElements(interp, *lp,
+ &natoms, &atoms) == TCL_OK)
+ {
+ int ac;
+ Tcl_Obj **ap;
+ for (ac = 0, ap = atoms; ac < natoms; ac++, ap++)
+ {
+ double d;
+ int len;
+ char *ptr;
+ Tcl_IncrRefCount(*ap);
+ if (Tcl_GetDoubleFromObj(interp,
+ *ap, &d) == TCL_OK)
+ {
+ t_atom at;
+ SETFLOAT(&at, (float)d);
+ binbuf_add(bb, 1, &at);
+ }
+ else if ((ptr = Tcl_GetStringFromObj(*ap, &len))
+ && len)
+ {
+ t_atom at;
+ if (ptr[len - 1])
+ {
+ char buf[MAXPDSTRING];
+ if (len > MAXPDSTRING - 1)
+ len = MAXPDSTRING - 1;
+ strncpy(buf, ptr, len);
+ buf[len] = 0;
+ ptr = buf;
+ }
+ SETSYMBOL(&at, gensym(ptr));
+ binbuf_add(bb, 1, &at);
+ }
+ /* FIXME else */
+ Tcl_DecrRefCount(*ap);
+ }
+ binbuf_addsemi(bb);
+ }
+ else
+ {
+ binbuf_clear(bb);
+ goto notalist;
+ }
+ }
+ }
+ else goto notalist;
+ }
+ }
+ }
+ return;
+notalist:
+ if (interp) plusloud_tclerror((t_pd *)x, interp, "not a list");
+}
+
+static void plustot_qlist_bang(t_plustot_qlist *x)
+{
+ t_binbuf *bb;
+ if (bb = plustot_qlist_usurp(x))
+ {
+ if (plustob_setbinbuf(x->x_tob, bb))
+ outlet_plusbob(x->x_rightout, (t_plusbob *)x->x_tob);
+ }
+}
+
+static void plustot_qlist_free(t_plustot_qlist *x)
+{
+ plusbob_release((t_plusbob *)x->x_tob);
+ if (x->x_proxy) pd_free((t_pd *)x->x_proxy);
+}
+
+void *plustot_qlist_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_plustot_qlist *x = 0;
+ t_glist *glist = canvas_getcurrent();
+ t_plustin *tin = 0;
+ t_plustob *tob = 0;
+ if ((tin = plustin_glistprovide(glist, PLUSTIN_GLIST_ANY, 0)) &&
+ (tob = plustob_new(tin, 0)))
+ {
+ x = (t_plustot_qlist *)pd_new(plustot_qlist_class);
+ plusbob_preserve((t_plusbob *)tob);
+ plusbob_setowner((t_plusbob *)tob, (t_pd *)x);
+ plustob_setlist(tob, ac, av);
+ x->x_glist = glist;
+ x->x_tob = tob;
+ x->x_proxy = plusproxy_qlist_new(x);
+ inlet_new((t_object *)x, (t_pd *)x->x_proxy, 0, 0);
+ outlet_new((t_object *)x, &s_anything);
+ x->x_rightout = outlet_new((t_object *)x, &s_symbol);
+ }
+ else
+ {
+ loud_error(0, "+qlist: cannot initialize");
+ if (tin)
+ {
+ plusbob_preserve((t_plusbob *)tin);
+ plusbob_release((t_plusbob *)tin);
+ }
+ }
+ return (x);
+}
+
+void plustot_qlist_setup(void)
+{
+ plustot_qlist_class = class_new(gensym("+qlist"), 0,
+ (t_method)plustot_qlist_free,
+ sizeof(t_plustot_qlist), 0, 0);
+ class_addbang(plustot_qlist_class, plustot_qlist_bang);
+
+ plusproxy_qlist_class = class_new(gensym("+qlist proxy"), 0, 0,
+ sizeof(t_plusproxy_qlist), CLASS_PD, 0);
+ class_addsymbol(plusproxy_qlist_class, plusproxy_qlist_symbol);
+}
diff --git a/toxy/plustot.var.c b/toxy/plustot.var.c
new file mode 100644
index 0000000..a5f36a7
--- /dev/null
+++ b/toxy/plustot.var.c
@@ -0,0 +1,130 @@
+/* Copyright (c) 2003 krzYszcz and others.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "m_pd.h"
+#include "common/loud.h"
+#include "toxy/plusbob.h"
+#include "plustot.h"
+
+typedef struct _plusproxy_var
+{
+ t_pd pp_pd;
+ t_plusvar *pp_var;
+} t_plusproxy_var;
+
+typedef struct _plustot_var
+{
+ t_object x_ob;
+ t_glist *x_glist;
+ t_plusvar *x_var;
+ t_plusproxy_var *x_proxy;
+} t_plustot_var;
+
+static t_class *plusproxy_var_class;
+static t_class *plustot_var_class;
+
+static t_plusproxy_var *plusproxy_var_new(t_pd *master)
+{
+ t_plusproxy_var *pp = (t_plusproxy_var *)pd_new(plusproxy_var_class);
+ pp->pp_var = ((t_plustot_var *)master)->x_var;
+ return (pp);
+}
+
+static void plusproxy_var_float(t_plusproxy_var *pp, t_float f)
+{
+ plusvar_setfloat(pp->pp_var, f, 1);
+}
+
+static void plusproxy_var_symbol(t_plusproxy_var *pp, t_symbol *s)
+{
+ plusvar_setsymbol(pp->pp_var, s, 1);
+}
+
+static void plusproxy_var_list(t_plusproxy_var *pp,
+ t_symbol *s, int ac, t_atom *av)
+{
+ plusvar_setlist(pp->pp_var, ac, av, 1);
+}
+
+static void plustot_var_bang(t_plustot_var *x)
+{
+ if (plusvar_pull(x->x_var))
+ outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_var);
+}
+
+static void plustot_var_float(t_plustot_var *x, t_float f)
+{
+ if (plusvar_setfloat(x->x_var, f, 1))
+ outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_var);
+}
+
+static void plustot_var_symbol(t_plustot_var *x, t_symbol *s)
+{
+ if (plusvar_setsymbol(x->x_var, s, 1))
+ outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_var);
+}
+
+static void plustot_var_list(t_plustot_var *x, t_symbol *s, int ac, t_atom *av)
+{
+ if (plusvar_setlist(x->x_var, ac, av, 1))
+ outlet_plusbob(((t_object *)x)->ob_outlet, (t_plusbob *)x->x_var);
+}
+
+static void plustot_var_free(t_plustot_var *x)
+{
+ plusbob_release((t_plusbob *)x->x_var);
+ if (x->x_proxy) pd_free((t_pd *)x->x_proxy);
+}
+
+void *plustot_var_new(t_symbol *s, int ac, t_atom *av)
+{
+ t_plustot_var *x = 0;
+ t_glist *glist = canvas_getcurrent();
+ t_plustin *tin = 0;
+ t_plusvar *var = 0;
+ if (ac && av->a_type == A_SYMBOL &&
+ (tin = plustin_glistprovide(glist, PLUSTIN_GLIST_ANY, 0)) &&
+ (var = plusvar_new(av->a_w.w_symbol->s_name, 0, tin)))
+ {
+ x = (t_plustot_var *)pd_new(plustot_var_class);
+ plusbob_preserve((t_plusbob *)var);
+ plusbob_setowner((t_plusbob *)var, (t_pd *)x);
+ plusvar_setlist(var, ac - 1, av + 1, 1);
+ x->x_glist = glist;
+ x->x_var = var;
+ x->x_proxy = plusproxy_var_new((t_pd *)x);
+ inlet_new((t_object *)x, (t_pd *)x->x_proxy, 0, 0);
+ outlet_new((t_object *)x, &s_symbol);
+ }
+ else
+ {
+ if (!ac || av->a_type != A_SYMBOL)
+ loud_error(0, "+var: missing name of a variable");
+ else
+ loud_error(0, "+var: cannot initialize");
+ if (tin)
+ {
+ plusbob_preserve((t_plusbob *)tin);
+ plusbob_release((t_plusbob *)tin);
+ }
+ }
+ return (x);
+}
+
+void plustot_var_setup(void)
+{
+ plustot_var_class = class_new(gensym("+var"), 0,
+ (t_method)plustot_var_free,
+ sizeof(t_plustot_var), 0, 0);
+ class_addbang(plustot_var_class, plustot_var_bang);
+ class_addfloat(plustot_var_class, plustot_var_float);
+ class_addsymbol(plustot_var_class, plustot_var_symbol);
+ class_addlist(plustot_var_class, plustot_var_list);
+
+ plusproxy_var_class = class_new(gensym("+var proxy"), 0, 0,
+ sizeof(t_plusproxy_var), CLASS_PD, 0);
+ class_addfloat(plusproxy_var_class, plusproxy_var_float);
+ class_addsymbol(plusproxy_var_class, plusproxy_var_symbol);
+ class_addlist(plusproxy_var_class, plusproxy_var_list);
+}
diff --git a/toxy/tot.c b/toxy/tot.c
index 0bddfc3..385618c 100644
--- a/toxy/tot.c
+++ b/toxy/tot.c
@@ -456,11 +456,11 @@ static void *tot_new(t_symbol *s1, t_symbol *s2)
char buf[64];
sprintf(buf, "tot%x", (int)x);
pd_bind((t_pd *)x, x->x_target = gensym(buf));
- x->x_transient =
- scriptlet_new((t_pd *)x, x->x_target, x->x_target, 0, tot_cvhook);
- x->x_persistent =
- scriptlet_new((t_pd *)x, x->x_target, x->x_target, 0, tot_cvhook);
x->x_glist = canvas_getcurrent();
+ x->x_transient = scriptlet_new((t_pd *)x, x->x_target, x->x_target,
+ 0, x->x_glist, tot_cvhook);
+ x->x_persistent = scriptlet_new((t_pd *)x, x->x_target, x->x_target,
+ 0, x->x_glist, tot_cvhook);
if (s1 && s1 != &s_ && strcmp(s1->s_name, "."))
{
x->x_cvremote = canvas_makebindsym(x->x_cvname = s1);
diff --git a/toxy/toxy-shared.include b/toxy/toxy-shared.include
index e831217..ec6c42c 100644
--- a/toxy/toxy-shared.include
+++ b/toxy/toxy-shared.include
@@ -9,6 +9,8 @@ shared/hammer/file.c
shared/hammer/file.h
shared/hammer/gui.c
shared/hammer/gui.h
+shared/unstable/fragile.c
+shared/unstable/fragile.h
shared/unstable/forky.c
shared/unstable/forky.h
shared/unstable/loader.c
@@ -16,5 +18,7 @@ shared/unstable/loader.h
shared/unstable/pd_imp.h
shared/common/props.c
shared/common/props.h
+shared/toxy/plusbob.c
+shared/toxy/plusbob.h
shared/toxy/scriptlet.c
shared/toxy/scriptlet.h
diff --git a/toxy/widget.c b/toxy/widget.c
index 253b649..a7a983a 100644
--- a/toxy/widget.c
+++ b/toxy/widget.c
@@ -23,7 +23,7 @@ static t_class *makeshift_class;
//#define WIDGET_DEBUG
//#define TOW_DEBUG
-enum { WIDGET_NOUPDATE = 0, WIDGET_RECONFIG, WIDGET_REVIS };
+enum { WIDGET_NOVIS = 0, WIDGET_PUSHVIS, WIDGET_REVIS };
typedef struct _towentry
{
@@ -62,9 +62,9 @@ typedef struct _widget
int x_height;
t_symbol *x_background;
int x_hasstate;
- int x_update; /* see widget_update() */
- int x_selected;
int x_disabled;
+ int x_selected;
+ int x_update; /* see widget_update() */
int x_vised;
t_clock *x_transclock;
t_towentry *x_towlist;
@@ -95,10 +95,12 @@ static t_symbol *widgetps_motion;
static t_symbol *widgetps_atbang;
static t_symbol *widgetps_atfloat;
static t_symbol *widgetps_atsymbol;
+static t_symbol *widgetps_atstore;
+static t_symbol *widgetps_atrestore;
-static char *widget_propsresolver(t_pd *z, int ac, t_atom *av)
+static char *widget_propsresolver(t_pd *owner, int ac, t_atom *av)
{
- t_widget *x = (t_widget *)z;
+ t_widget *x = (t_widget *)owner;
int len;
scriptlet_reset(x->x_auxscript);
if (scriptlet_add(x->x_auxscript, 1, 0, ac, av))
@@ -107,9 +109,9 @@ static char *widget_propsresolver(t_pd *z, int ac, t_atom *av)
return (0);
}
-static t_canvas *widget_cvhook(t_pd *z)
+static t_canvas *widget_cvhook(t_pd *caller)
{
- return (glist_getcanvas(((t_widget *)z)->x_glist));
+ return (glist_getcanvas(((t_widget *)caller)->x_glist));
}
/* LATER move to scriptlet.c, use the scriptlet interface (.^) */
@@ -165,14 +167,14 @@ static void widget_transedit(t_widget *x)
{
t_text *newt, *oldt = (t_text *)x;
t_binbuf *bb = binbuf_new();
- int nopt, nbnd, narg;
+ int nopt, nhnd, narg;
t_atom *opt = props_getall(x->x_options, &nopt);
- t_atom *bnd = props_getall(x->x_handlers, &nbnd);
+ t_atom *hnd = props_getall(x->x_handlers, &nhnd);
t_atom *arg = props_getall(x->x_arguments, &narg);
binbuf_addv(bb, "sss", gensym("widget"), x->x_type, x->x_name);
if (narg) binbuf_add(bb, narg, arg);
if (nopt) binbuf_add(bb, nopt, opt);
- if (nbnd) binbuf_add(bb, nbnd, bnd);
+ if (nhnd) binbuf_add(bb, nhnd, hnd);
canvas_setcurrent(x->x_glist);
newt = (t_text *)pd_new(makeshift_class);
newt->te_width = 0;
@@ -211,6 +213,10 @@ static void widget_displace(t_gobj *z, t_glist *glist, int dx, int dy)
{
t_widget *x = (t_widget *)z;
t_text *t = (t_text *)z;
+#if 0
+ post("displace %d %d (%d %d -> %d %d)",
+ dx, dy, t->te_xpix, t->te_ypix, t->te_xpix + dx, t->te_ypix + dy);
+#endif
t->te_xpix += dx;
t->te_ypix += dy;
if (glist_isvisible(glist))
@@ -219,11 +225,11 @@ static void widget_displace(t_gobj *z, t_glist *glist, int dx, int dy)
canvas_fixlinesfor(glist_getcanvas(glist), t);
}
-static void widget_select(t_gobj *z, t_glist *glist, int state)
+static void widget_select(t_gobj *z, t_glist *glist, int flag)
{
t_widget *x = (t_widget *)z;
char *mypathname = widget_getmypathname(x, glist)->s_name;
- if (state)
+ if (flag)
{
sys_vgui("%s config -bg blue %s\n", mypathname,
(x->x_hasstate ? "-state disabled" : ""));
@@ -235,7 +241,7 @@ static void widget_select(t_gobj *z, t_glist *glist, int state)
sys_vgui("%s config -bg %s\n", mypathname,
(x->x_background ? x->x_background->s_name : "gray"));
else
- sys_vgui("%s config -bg %s\n", mypathname,
+ sys_vgui("%s config -bg %s %s\n", mypathname,
(x->x_background ? x->x_background->s_name : "gray"),
(x->x_hasstate ? "-state normal" : ""));
x->x_selected = 0;
@@ -290,13 +296,20 @@ static void widget_pushinits(t_widget *x)
bug("widget_pushinits (instance)");
}
+static void widget_getconfig(t_widget *x)
+{
+ sys_vgui("::toxy::itemgetconfig %s %s\n",
+ widget_getmypathname(x, x->x_glist)->s_name,
+ x->x_cbtarget->s_name);
+}
+
static void widget_vis(t_gobj *z, t_glist *glist, int vis)
{
t_widget *x = (t_widget *)z;
t_text *t = (t_text *)z;
char *cvpathname = widget_getcvpathname(x, glist)->s_name;
char *mypathname = widget_getmypathname(x, glist)->s_name;
- x->x_update = WIDGET_NOUPDATE;
+ x->x_update = WIDGET_NOVIS;
if (vis)
{
float px1 = text_xpix((t_text *)x, glist);
@@ -318,11 +331,7 @@ static void widget_vis(t_gobj *z, t_glist *glist, int vis)
t_rtext *rt = glist_findrtext(glist, t);
if (rt) rtext_free(rt);
#endif
- if (x->x_vised)
- {
- sys_vgui("destroy %s\n", mypathname);
- x->x_vised = 0;
- }
+ x->x_vised = 0;
}
}
@@ -330,16 +339,16 @@ static void widget_save(t_gobj *z, t_binbuf *bb)
{
t_widget *x = (t_widget *)z;
t_text *t = (t_text *)x;
- int nopt, nbnd, narg;
+ int nopt, nhnd, narg;
t_atom *opt = props_getall(x->x_options, &nopt);
- t_atom *bnd = props_getall(x->x_handlers, &nbnd);
+ t_atom *hnd = props_getall(x->x_handlers, &nhnd);
t_atom *arg = props_getall(x->x_arguments, &narg);
binbuf_addv(bb, "ssiisss", gensym("#X"), gensym("obj"),
(int)t->te_xpix, (int)t->te_ypix, gensym("widget"),
x->x_type, x->x_name);
if (narg) binbuf_add(bb, narg, arg);
if (nopt) binbuf_add(bb, nopt, opt);
- if (nbnd) binbuf_add(bb, nbnd, bnd);
+ if (nhnd) binbuf_add(bb, nhnd, hnd);
binbuf_addsemi(bb);
}
@@ -405,27 +414,37 @@ static t_widgetbehavior widget_behavior =
FORKY_WIDGETPADDING
};
-static void widget_update(t_widget *x)
+static void widget_update(t_widget *x, t_props *op)
{
- t_atom *ap;
- int ac;
- scriptlet_reset(x->x_optscript);
- ap = props_getall(widgettype_getoptions(x->x_typedef), &ac);
- if (ac) scriptlet_add(x->x_optscript, 0, 0, ac, ap);
- ap = props_getall(x->x_options, &ac);
- if (ac) scriptlet_add(x->x_optscript, 0, 0, ac, ap);
- if (x->x_update &&
- glist_isvisible(x->x_glist)) /* FIXME the condition */
+ if (op == x->x_options)
{
- if (x->x_update == WIDGET_REVIS)
+ t_atom *ap;
+ int ac;
+ scriptlet_reset(x->x_optscript);
+ ap = props_getall(widgettype_getoptions(x->x_typedef), &ac);
+ if (ac) scriptlet_add(x->x_optscript, 0, 0, ac, ap);
+ ap = props_getall(x->x_options, &ac);
+ if (ac) scriptlet_add(x->x_optscript, 0, 0, ac, ap);
+ if (x->x_update &&
+ glist_isvisible(x->x_glist)) /* FIXME the condition */
{
- widget_vis((t_gobj *)x, x->x_glist, 0);
- widget_vis((t_gobj *)x, x->x_glist, 1);
+ if (x->x_update == WIDGET_REVIS)
+ {
+ widget_vis((t_gobj *)x, x->x_glist, 0);
+ widget_vis((t_gobj *)x, x->x_glist, 1);
+ }
+ else if (x->x_update == WIDGET_PUSHVIS)
+ {
+ widget_pushoptions(x, 1);
+ widget_getconfig(x);
+ }
+ x->x_update = WIDGET_NOVIS;
}
- else widget_pushoptions(x, 1);
- x->x_update = WIDGET_NOUPDATE;
}
- /* LATER cache handlers */
+ else
+ {
+ /* LATER cache handlers */
+ }
}
static t_symbol *widget_addprops(t_widget *x, t_props *op, int single,
@@ -438,7 +457,7 @@ static t_symbol *widget_addprops(t_widget *x, t_props *op, int single,
if (empty)
loud_error((t_pd *)x, "no value given for %s '%s'",
props_getname(op), empty->s_name);
- widget_update(x);
+ widget_update(x, op);
return (empty);
}
else
@@ -464,7 +483,7 @@ static void widget_anything(t_widget *x, t_symbol *s, int ac, t_atom *av)
if (*s->s_name == '-' || *s->s_name == '@' || *s->s_name == '#')
{
t_symbol *empty;
- x->x_update = WIDGET_RECONFIG;
+ x->x_update = WIDGET_PUSHVIS;
if (empty = widget_addmessage(x, s, ac, av))
loud_errand((t_pd *)x,
"(use 'remove %s' if that is what you want).",
@@ -558,16 +577,32 @@ static void widget_symbol(t_widget *x, t_symbol *s)
}
}
+static void widget_store(t_widget *x, t_symbol *s)
+{
+ if (s == &s_)
+ s = x->x_varname;
+ /* FIXME */
+}
+
+static void widget_restore(t_widget *x, t_symbol *s)
+{
+ if (s == &s_)
+ s = x->x_varname;
+ /* FIXME */
+}
+
static void widget_set(t_widget *x, t_symbol *s, int ac, t_atom *av)
{
t_symbol *prp;
if (ac && av->a_type == A_SYMBOL && (prp = av->a_w.w_symbol))
{
t_symbol *empty = 0;
- x->x_update = WIDGET_RECONFIG;
ac--; av++;
if (*prp->s_name == '-')
+ {
+ x->x_update = WIDGET_PUSHVIS;
empty = widget_addprops(x, x->x_options, 1, prp, ac, av);
+ }
else if (*prp->s_name == '@')
empty = widget_addprops(x, x->x_handlers, 1, prp, ac, av);
else if (*prp->s_name == '#')
@@ -595,8 +630,8 @@ static void widget_remove(t_widget *x, t_symbol *s)
op = 0;
if (op && props_remove(op, s))
{
- x->x_update = WIDGET_REVIS;
- widget_update(x);
+ if (op == x->x_options) x->x_update = WIDGET_REVIS;
+ widget_update(x, op);
}
else loud_warning((t_pd *)x, "%s %s has not been specified",
props_getname(op), s->s_name);
@@ -625,7 +660,9 @@ static void widget_tot(t_widget *x, t_symbol *s, int ac, t_atom *av)
static void widget_refresh(t_widget *x)
{
x->x_update = WIDGET_REVIS;
- widget_update(x);
+ widget_update(x, x->x_options);
+ widget_update(x, x->x_handlers);
+ widget_update(x, x->x_arguments);
}
static void widget__failure(t_widget *x, t_symbol *s, int ac, t_atom *av)
@@ -682,13 +719,13 @@ static void widget__callback(t_widget *x, t_symbol *s, int ac, t_atom *av)
else outlet_bang(((t_object *)x)->ob_outlet);
}
-/* FIXME this is a hack (see also widget_select) */
-/* FIXME why <Leave> is being issued on button press? */
+/* see also widget_select() */
static void widget__inout(t_widget *x, t_floatarg f)
{
+ int disable = (int)f && x->x_glist->gl_edit;
if (x->x_disabled)
{
- if (!x->x_glist->gl_edit)
+ if (!disable)
{
if (!x->x_selected)
{
@@ -699,54 +736,54 @@ static void widget__inout(t_widget *x, t_floatarg f)
x->x_disabled = 0;
}
}
- else if ((int)f && x->x_glist->gl_edit)
+ else if (disable)
{
- char *mypathname = widget_getmypathname(x, x->x_glist)->s_name;
- if (x->x_hasstate)
- sys_vgui("%s config -state disabled\n", mypathname);
+ if (!x->x_selected)
+ {
+ char *mypathname = widget_getmypathname(x, x->x_glist)->s_name;
+ if (x->x_hasstate)
+ sys_vgui("%s config -state disabled\n", mypathname);
+ }
x->x_disabled = 1;
}
}
-static void widget__click(t_widget *x, t_floatarg fx, t_floatarg fy,
- t_floatarg fb, t_floatarg fm)
+static void widget__click(t_widget *x, t_symbol *s, int ac, t_atom *av)
{
+ if (ac != 4)
+ {
+ loud_error((t_pd *)x, "bad arguments to the '%s' method", s->s_name);
+ return;
+ }
if (x->x_glist->gl_havewindow) /* LATER calculate on-parent coords */
{
- t_text *t = (t_text *)x;
- t_atom at[4];
- fx += t->te_xpix;
- fy += t->te_ypix;
- SETFLOAT(&at[0], fx);
- SETFLOAT(&at[1], fy);
- SETFLOAT(&at[2], fb);
- SETFLOAT(&at[3], fm);
if (x->x_cvtarget->s_thing)
/* LATER rethink */
- typedmess(x->x_cvtarget->s_thing, widgetps_mouse, 4, at);
+ typedmess(x->x_cvtarget->s_thing, widgetps_mouse, ac, av);
else
- typedmess((t_pd *)x->x_glist, widgetps_mouse, 4, at);
- widget__inout(x, 1.);
+ typedmess((t_pd *)x->x_glist, widgetps_mouse, ac, av);
+ widget__inout(x, 2.);
}
}
/* LATER think how to grab the mouse when dragging */
-static void widget__motion(t_widget *x, t_floatarg fx, t_floatarg fy)
+static void widget__motion(t_widget *x, t_symbol *s, int ac, t_atom *av)
{
+ if (ac != 3)
+ {
+ loud_error((t_pd *)x, "bad arguments to the '%s' method", s->s_name);
+ return;
+ }
if (x->x_glist->gl_havewindow) /* LATER calculate on-parent coords */
{
- t_text *t = (t_text *)x;
- t_atom at[3];
- fx += t->te_xpix;
- fy += t->te_ypix;
- SETFLOAT(&at[0], fx);
- SETFLOAT(&at[1], fy);
- SETFLOAT(&at[2], 0);
+#if 0
+ post("motion %g %g", av[0].a_w.w_float, av[1].a_w.w_float);
+#endif
if (x->x_cvtarget->s_thing)
/* LATER rethink */
- typedmess(x->x_cvtarget->s_thing, widgetps_motion, 3, at);
+ typedmess(x->x_cvtarget->s_thing, widgetps_motion, ac, av);
else
- typedmess((t_pd *)x->x_glist, widgetps_motion, 3, at);
+ typedmess((t_pd *)x->x_glist, widgetps_motion, ac, av);
}
}
@@ -799,6 +836,8 @@ static void widget_debug(t_widget *x)
post("type initializer (size %d):\n\"%s\"", sz, bp);
bp = scriptlet_getcontents(x->x_iniscript, &sz);
post("instance initializer (size %d):\n\"%s\"", sz, bp);
+ bp = masterwidget_getcontents(&sz);
+ post("setup definitions (size %d):\n\"%s\"", sz, bp);
}
#endif
@@ -815,6 +854,8 @@ static void gui_unbind(t_pd *x, t_symbol *s)
static void widget_free(t_widget *x)
{
+ sys_vgui("::toxy::itemdestroy %s %s\n",
+ widget_getmypathname(x, x->x_glist)->s_name, x->x_varname->s_name);
gui_unbind((t_pd *)x, x->x_cbtarget);
gui_unbind((t_pd *)x, x->x_rptarget);
props_freeall(x->x_options);
@@ -862,28 +903,28 @@ static void *widget_new(t_symbol *s, int ac, t_atom *av)
if (!(x->x_tkclass = widgettype_tkclass(x->x_typedef)))
x->x_tkclass = x->x_type;
+ x->x_glist = canvas_getcurrent();
+ sprintf(buf, ".x%x.c", (int)x->x_glist);
+ x->x_cvpathname = gensym(buf);
+ sprintf(buf, ".x%x", (int)x->x_glist);
+ x->x_cvtarget = gensym(buf);
+ sprintf(buf, "::toxy::v%x", (int)x);
+ x->x_varname = gensym(buf);
+
x->x_iniscript = scriptlet_new((t_pd *)x, x->x_rptarget, x->x_cbtarget,
- x->x_name, widget_cvhook);
+ x->x_name, x->x_glist, widget_cvhook);
x->x_optscript = scriptlet_new((t_pd *)x, x->x_rptarget, x->x_cbtarget,
- x->x_name, widget_cvhook);
+ x->x_name, x->x_glist, widget_cvhook);
x->x_auxscript = scriptlet_new((t_pd *)x, x->x_rptarget, x->x_cbtarget,
- x->x_name, widget_cvhook);
+ x->x_name, x->x_glist, widget_cvhook);
x->x_transient = scriptlet_new((t_pd *)x, x->x_rptarget, x->x_cbtarget,
- x->x_name, widget_cvhook);
+ x->x_name, x->x_glist, widget_cvhook);
x->x_options = props_new((t_pd *)x, "option", "-", 0, 0);
x->x_handlers = props_new((t_pd *)x, "handler", "@", x->x_options, 0);
x->x_arguments = props_new((t_pd *)x, "argument", "#", x->x_options,
widget_propsresolver);
- sprintf(buf, ".^.c.%s%x", x->x_name->s_name, (int)x);
- x->x_glist = canvas_getcurrent();
- sprintf(buf, ".x%x.c", (int)x->x_glist);
- x->x_cvpathname = gensym(buf);
- sprintf(buf, ".x%x", (int)x->x_glist);
- x->x_cvtarget = gensym(buf);
- sprintf(buf, "::toxy::v%x", (int)x);
- x->x_varname = gensym(buf);
outlet_new((t_object *)x, &s_anything);
/* LATER consider estimating these, based on widget class and options */
x->x_width = 50;
@@ -894,7 +935,7 @@ static void *widget_new(t_symbol *s, int ac, t_atom *av)
x->x_transclock = clock_new(x, (t_method)widget_transtick);
x->x_background = 0;
x->x_hasstate = 0;
- x->x_update = WIDGET_NOUPDATE;
+ x->x_update = WIDGET_NOVIS;
x->x_disabled = 0;
x->x_vised = 0;
widget_attach(x);
@@ -1153,6 +1194,8 @@ void widget_setup(void)
widgetps_atbang = gensym("@bang");
widgetps_atfloat = gensym("@float");
widgetps_atsymbol = gensym("@symbol");
+ widgetps_atstore = gensym("@store");
+ widgetps_atrestore = gensym("@restore");
widgettype_setup();
widget_class = class_new(gensym("widget"),
(t_newmethod)widget_new,
@@ -1165,6 +1208,10 @@ void widget_setup(void)
class_addfloat(widget_class, widget_float);
class_addsymbol(widget_class, widget_symbol);
class_addanything(widget_class, widget_anything);
+ class_addmethod(widget_class, (t_method)widget_store,
+ gensym("store"), A_DEFSYMBOL, 0);
+ class_addmethod(widget_class, (t_method)widget_restore,
+ gensym("restore"), A_DEFSYMBOL, 0);
class_addmethod(widget_class, (t_method)widget_set,
gensym("set"), A_GIMME, 0);
class_addmethod(widget_class, (t_method)widget_remove,
@@ -1187,9 +1234,9 @@ void widget_setup(void)
class_addmethod(widget_class, (t_method)widget__inout,
gensym("_inout"), A_FLOAT, 0);
class_addmethod(widget_class, (t_method)widget__click,
- gensym("_click"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, 0);
+ gensym("_click"), A_GIMME, 0);
class_addmethod(widget_class, (t_method)widget__motion,
- gensym("_motion"), A_FLOAT, A_FLOAT, 0);
+ gensym("_motion"), A_GIMME, 0);
#ifdef WIDGET_DEBUG
class_addmethod(widget_class, (t_method)widget_debug,
gensym("debug"), 0);
diff --git a/toxy/widgettype.c b/toxy/widgettype.c
index 5a5684f..3e04824 100644
--- a/toxy/widgettype.c
+++ b/toxy/widgettype.c
@@ -11,6 +11,10 @@
#include "toxy/scriptlet.h"
#include "widgettype.h"
+static char masterwidget_builtin[] =
+#include "default.wiq"
+;
+
#define WIDGETTYPE_VERBOSE
//#define WIDGETTYPE_DEBUG
@@ -42,7 +46,7 @@ static t_class *masterwidget_class;
static t_masterwidget *masterwidget = 0;
-static t_canvas *widgettype_cvhook(t_pd *z)
+static t_canvas *widgettype_cvhook(t_pd *caller)
{
return (0);
}
@@ -63,22 +67,22 @@ static t_widgettype *widgettype_new(t_masterwidget *mw,
wt->wt_handlers = props_new(0, "handler", "@", wt->wt_options, 0);
wt->wt_arguments = props_new(0, "argument", "#", wt->wt_options, 0);
wt->wt_iniscript = scriptlet_new((t_pd *)wt, mw->mw_target, mw->mw_target,
- 0, widgettype_cvhook);
+ 0, 0, widgettype_cvhook);
dict_bind(mw->mw_typemap, (t_pd *)wt, wt->wt_typekey);
return (wt);
}
-static t_canvas *masterwidget_cvhook(t_pd *z)
+static t_canvas *masterwidget_cvhook(t_pd *caller)
{
return (0);
}
-static t_scriptlet *masterwidget_cmnthook(t_pd *z, char *rc,
+static t_scriptlet *masterwidget_cmnthook(t_pd *caller, char *rc,
char sel, char *buf)
{
t_masterwidget *mw = masterwidget;
if (!*buf)
- return (0);
+ return (SCRIPTLET_UNLOCK);
if (sel == '>')
{
t_symbol *typekey;
@@ -90,23 +94,31 @@ static t_scriptlet *masterwidget_cmnthook(t_pd *z, char *rc,
cls = buf;
typekey = dict_key(mw->mw_typemap, buf);
typeval = (t_widgettype *)dict_value(mw->mw_typemap, typekey);
- if (z == (t_pd *)mw)
- { /* default.wid */
- if (typeval)
+ if (caller == (t_pd *)mw)
+ { /* default.wid or built-in defaults */
+ if (mw->mw_defaulttype)
+ { /* no default type in default.wid, extracting built-in one */
+ if (typeval != mw->mw_defaulttype)
+ return (SCRIPTLET_LOCK);
+ }
+ else
{
- /* LATER rethink */
- loud_warning((t_pd *)mw, "redefinition of '%s'\
+ if (typeval)
+ {
+ /* LATER rethink */
+ loud_warning((t_pd *)mw, "redefinition of '%s'\
in \"%s.wid\" file, ignored", buf, rc);
- return (0);
+ return (SCRIPTLET_LOCK);
+ }
}
}
else
{ /* <type>.wid */
- if (z != (t_pd *)typeval)
+ if (caller != (t_pd *)typeval)
{
loud_warning((t_pd *)mw, "alien definition of '%s'\
in \"%s.wid\" file, ignored", buf, rc);
- return (0);
+ return (SCRIPTLET_LOCK);
}
}
if (pkg)
@@ -150,7 +162,7 @@ static t_scriptlet *masterwidget_cmnthook(t_pd *z, char *rc,
}
}
}
- return (0);
+ return (SCRIPTLET_UNLOCK);
}
t_widgettype *widgettype_get(t_symbol *s)
@@ -170,13 +182,31 @@ t_widgettype *widgettype_get(t_symbol *s)
}
if (masterwidget->mw_parsedtype)
{
- if (scriptlet_rcload(wt->wt_iniscript, s->s_name, ".wid",
- masterwidget_cmnthook) == SCRIPTLET_OK)
+ t_scriptlet *mwsp =
+ scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target,
+ masterwidget->mw_target, 0, 0, 0);
+ if (scriptlet_rcload(mwsp, (t_pd *)wt,
+ s->s_name, ".wid", 0, masterwidget_cmnthook)
+ == SCRIPTLET_OK)
{
#ifdef WIDGETTYPE_VERBOSE
post("using %s's initializer", 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);
}
@@ -218,13 +248,6 @@ int widgettype_evaluate(t_widgettype *wt, t_scriptlet *outsp,
visedonly, ac, av, argprops));
}
-int masterwidget_evaluate(t_scriptlet *outsp, int visedonly,
- int ac, t_atom *av, t_props *argprops)
-{
- return (scriptlet_evaluate(masterwidget->mw_defaulttype->wt_iniscript,
- outsp, visedonly, ac, av, argprops));
-}
-
void widgettype_setup(void)
{
static int done = 0;
@@ -238,9 +261,21 @@ void widgettype_setup(void)
}
}
+int masterwidget_evaluate(t_scriptlet *outsp, int visedonly,
+ int ac, t_atom *av, t_props *argprops)
+{
+ return (scriptlet_evaluate(masterwidget->mw_defaulttype->wt_iniscript,
+ outsp, visedonly, ac, av, argprops));
+}
+
+char *masterwidget_getcontents(int *szp)
+{
+ return (scriptlet_getcontents(masterwidget->mw_setupscript, szp));
+}
+
void masterwidget_initialize(void)
{
- t_scriptlet *sp;
+ int rcresult;
t_symbol *typekey;
t_widgettype *typeval;
char buf[MAXPDSTRING];
@@ -253,14 +288,17 @@ void masterwidget_initialize(void)
masterwidget->mw_typemap = dict_new(0);
- sp = masterwidget->mw_setupscript =
+ masterwidget->mw_setupscript =
scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target,
- masterwidget->mw_target, 0, 0);
- masterwidget->mw_parsedtype = 0;
+ masterwidget->mw_target, 0, 0, 0);
masterwidget->mw_bb = binbuf_new();
+ masterwidget->mw_parsedtype = 0;
+ masterwidget->mw_defaulttype = 0;
- if (scriptlet_rcload(sp, "default", ".wid",
- masterwidget_cmnthook) == SCRIPTLET_OK)
+ rcresult =
+ scriptlet_rcload(masterwidget->mw_setupscript, 0, "default", ".wid",
+ masterwidget_builtin, masterwidget_cmnthook);
+ if (rcresult == SCRIPTLET_OK)
{
#ifdef WIDGETTYPE_VERBOSE
post("using file 'default.wid'");
@@ -268,33 +306,42 @@ void masterwidget_initialize(void)
}
else
{
- loud_warning((t_pd *)masterwidget, "missing file 'default.wid'");
-
- /* no setup scriptlet, LATER use built-in default */
-#if 0
- scriptlet_reset(sp);
- scriptlet_addstring(sp, ...
-#endif
+ loud_warning((t_pd *)masterwidget,
+ "no file 'default.wid'... using built-in defaults");
}
typekey = dict_key(masterwidget->mw_typemap, "default");
- if (typeval = (t_widgettype *)dict_value(masterwidget->mw_typemap, typekey))
+ if ((typeval = (t_widgettype *)dict_value(masterwidget->mw_typemap, typekey))
+ && !scriptlet_isempty(masterwidget->mw_setupscript))
+ {
masterwidget->mw_defaulttype = typeval;
- else
+ rcresult = SCRIPTLET_OK;
+ }
+ else if (rcresult == SCRIPTLET_OK)
{
- /* no master initializer, LATER use built-in default */
+ /* LATER think about adding only missing part to existing local defs */
+ loud_warning((t_pd *)masterwidget, "%s missing in file 'default.wid'",
+ (typeval ? "setup definitions" : "master initializer"));
masterwidget->mw_defaulttype =
widgettype_new(masterwidget, "default", 0, 0);
- sp = masterwidget->mw_defaulttype->wt_iniscript;
-#if 0
- scriptlet_reset(sp);
- scriptlet_addstring(sp, ...
-#endif
+ scriptlet_reset(masterwidget->mw_setupscript);
+ rcresult =
+ scriptlet_rcparse(masterwidget->mw_setupscript, 0, "default",
+ masterwidget_builtin, masterwidget_cmnthook);
}
- sp = scriptlet_new((t_pd *)masterwidget,
- masterwidget->mw_target, masterwidget->mw_target, 0, 0);
- if (scriptlet_evaluate(masterwidget->mw_setupscript, sp, 0, 0, 0, 0))
- scriptlet_push(sp);
else
- bug("masterwidget_initialize");
- scriptlet_free(sp);
+ {
+ bug("masterwidget_initialize 1");
+ rcresult = SCRIPTLET_BADFILE;
+ }
+ if (rcresult == SCRIPTLET_OK)
+ {
+ t_scriptlet *sp =
+ scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target,
+ masterwidget->mw_target, 0, 0, 0);
+ if (scriptlet_evaluate(masterwidget->mw_setupscript, sp, 0, 0, 0, 0))
+ scriptlet_push(sp);
+ else
+ bug("masterwidget_initialize 2");
+ scriptlet_free(sp);
+ }
}
diff --git a/toxy/widgettype.h b/toxy/widgettype.h
index 55c8e9d..d0df8c6 100644
--- a/toxy/widgettype.h
+++ b/toxy/widgettype.h
@@ -21,10 +21,11 @@ char *widgettype_propname(t_symbol *s);
char *widgettype_getcontents(t_widgettype *wt, int *szp);
int widgettype_evaluate(t_widgettype *wt, t_scriptlet *outsp,
int visedonly, int ac, t_atom *av, t_props *argprops);
+void widgettype_setup(void);
+
+char *masterwidget_getcontents(int *szp);
int masterwidget_evaluate(t_scriptlet *outsp, int visedonly,
int ac, t_atom *av, t_props *argprops);
void masterwidget_initialize(void);
-void widgettype_setup(void);
-
#endif