diff --git a/pd/src/g_graph.c b/pd/src/g_graph.c index 3c9473b89ce1f68b324540c46790106420d951d6..a70e0a6323334ce95ab230a97f96df7e4552c979 100644 --- a/pd/src/g_graph.c +++ b/pd/src/g_graph.c @@ -202,7 +202,10 @@ void glist_delete(t_glist *x, t_gobj *y) if (drawcommand) { tmpl = template_findbydrawcommand(y); - canvas_redrawallfortemplate(tmpl, 2); + if (!(canvas_isgroup(canvas) && canvas->gl_isdeleting)) + { + canvas_redrawallfortemplate(tmpl, 2); + } } if (glist_isvisible(canvas)) gobj_vis(y, x, 0); @@ -234,7 +237,10 @@ void glist_delete(t_glist *x, t_gobj *y) pd_free(&y->g_pd); if (chkdsp) canvas_update_dsp(); if (drawcommand) - canvas_redrawallfortemplate(tmpl, 1); + { + if (!(canvas_isgroup(canvas) && canvas->gl_isdeleting)) + canvas_redrawallfortemplate(tmpl, 1); + } canvas_setdeleting(canvas, wasdeleting); x->gl_valid = ++glist_valid; if (late_rtext_free) diff --git a/pd/src/g_scalar.c b/pd/src/g_scalar.c index bfa611d3a04b485df7f705e10a22c70428c2eb5a..3c75a8a5c99794560df7e7c10e325ca7771a5029 100644 --- a/pd/src/g_scalar.c +++ b/pd/src/g_scalar.c @@ -137,24 +137,65 @@ int template_hasxy(t_template *template) return 0; } -int template_cancreate(t_template *template) +int template_check_array_fields(t_symbol *structname, t_template *template) { + /* We're calling this from template_cancreate as well as + gtemplate_cancreate. + With gtemplate_cancreate, the t_template doesn't exist yet. + So we send the struct name to see if it matches the name of any + array field templates that our gtemplate will depend on. If we find + a match we will refuse to create the gtemplate. + However, template_cancreate starts from the struct name for a template + that already exists. So on the first time through this recursive + function, there isn't a containing structname yet. + So we suppress this conditional the first + time through the recursive loop, and then set the structname for + all subsequent iterations through the loop. */ + if (structname && structname == template->t_sym) + { + return 0; + } int i, nitems = template->t_n; t_dataslot *datatypes = template->t_vec; t_template *elemtemplate; for (i = 0; i < nitems; i++, datatypes++) - if (datatypes->ds_type == DT_ARRAY && - (!(elemtemplate = template_findbyname(datatypes->ds_arraytemplate)) - || !template_cancreate(elemtemplate))) { - t_object *ob = template_getstruct(template); - pd_error(ob, "%s: no such template", - datatypes->ds_arraytemplate->s_name); - return (0); + if (datatypes->ds_type == DT_ARRAY) + { + elemtemplate = template_findbyname(datatypes->ds_arraytemplate); + if (!(elemtemplate)) + { + t_object *ob = template_getstruct(template); + pd_error(ob, "%s: no such template", + datatypes->ds_arraytemplate->s_name); + return (0); + } + else if (elemtemplate->t_sym == structname) + { + t_object *ob = template_getstruct(template); + pd_error(ob, "%s: circular dependency", + datatypes->ds_arraytemplate->s_name); + return (0); + } + else + { + if (!structname) + { + structname = template->t_sym; + } + return (template_check_array_fields(structname, elemtemplate)); + } + } } return (1); } +int template_cancreate(t_template *template) +{ + /* we send "0" for the structname since there is no container struct */ + return (template_check_array_fields(0, template)); +} + /* make a new scalar and add to the glist. We create a "gp" here which will be used for array items to point back here. This gp doesn't do reference counting or "validation" updates though; the parent won't go away diff --git a/pd/src/g_template.c b/pd/src/g_template.c index b3aa5f0213cb1dc2394c266f77b0725684d5181f..1b053d817c130538fe19f997aacb7ace3b9ee043 100644 --- a/pd/src/g_template.c +++ b/pd/src/g_template.c @@ -580,6 +580,8 @@ instructions for the template. The template doesn't go away when the "struct" is deleted, so that you can replace it with another one to add new fields, for example. */ +static void gtemplate_free(t_gtemplate *x); + static void *gtemplate_donew(t_symbol *sym, int argc, t_atom *argv) { t_canvas *cur = canvas_getcurrent(); @@ -626,16 +628,6 @@ static void *gtemplate_donew(t_symbol *sym, int argc, t_atom *argv) our own and conform it. */ t_template *y = template_new(&s_, argc, argv); - /* I'm not _exactly_ sure about this. It's possible - that the user could screw up a nested array construction - and end up with scalars that aren't able to conform. On - the other hand, this keeps us from crashing if a non- - existent array template is typed into the box. */ - if (!template_cancreate(y)) - { - return 0; - } - canvas_redrawallfortemplate(t, 2); /* Unless the new template is different from the old one, there's nothing to do. */ @@ -656,17 +648,66 @@ static void *gtemplate_donew(t_symbol *sym, int argc, t_atom *argv) /* otherwise make a new one and we're the only struct on it. */ x->x_template = t = template_new(sym, argc, argv); t->t_list = x; - } + } outlet_new(&x->x_obj, 0); return (x); } +int template_check_array_fields(t_symbol *structname, t_template *template); + +/* probably duplicating some code from template_new here... */ +int gtemplate_cancreate(t_symbol *templatename, int argc, t_atom *argv) +{ + while (argc > 1) + { + t_symbol *typesym = argv[0].a_w.w_symbol; + if (typesym == &s_float || typesym == &s_symbol) + { + argc -= 2; + argv += 2; + } + else if (typesym == gensym("array")) + { + if (argc > 2 && argv[2].a_type == A_SYMBOL) + { + /* check for cancreation here */ + t_template *elemtemplate = + template_findbyname(canvas_makebindsym(argv[2].a_w.w_symbol)); + if (!elemtemplate || + !template_check_array_fields( + canvas_makebindsym(templatename), elemtemplate)) + { + return 0; + } + argc -= 3; + argv += 3; + } + else + { + argc -= 2; + argv += 2; + } + } + else + { + argc -= 2; + argv += 2; + } + } + return 1; +} + static void *gtemplate_new(t_symbol *s, int argc, t_atom *argv) { t_symbol *sym = atom_getsymbolarg(0, argc, argv); if (argc >= 1) argc--; argv++; - return (gtemplate_donew(canvas_makebindsym(sym), argc, argv)); + if (gtemplate_cancreate(sym, argc, argv)) + { + return (gtemplate_donew(canvas_makebindsym(sym), argc, argv)); + } + else + return 0; } /* old version (0.34) -- delete 2003 or so */