diff --git a/pd/nw/pd_canvas.js b/pd/nw/pd_canvas.js index d5d133b897fe29db113afafb439f90cbc9d57cc6..f15b358327598dd07338fa92b4af3c9b5036f3ea 100644 --- a/pd/nw/pd_canvas.js +++ b/pd/nw/pd_canvas.js @@ -1329,6 +1329,9 @@ function register_window_id(cid, attr_array) { // we check the title_queue to see if our title now contains an asterisk // (which is the visual cue for "dirty") + // Enable/disable the warning for multiple dirty instances + pdgui.gui_canvas_multipledirty(cid, attr_array.multipledirty); + // Two possibilities for handling this better: // have a representation of canvas attys in pdgui.js (editmode, dirty, etc.) // or @@ -1338,8 +1341,6 @@ function register_window_id(cid, attr_array) { nw.Window.get().title = kludge_title; } pdgui.free_title_queue(cid); - - if(attr_array.muldirty) pdgui.gui_canvas_multipledirty(cid, 1); } function create_popup_menu(name) { diff --git a/pd/nw/pdgui.js b/pd/nw/pdgui.js index 6c5bd3063a1e78c1b0b96cece3c447580e7a5a62..5aa5975c7d8e295908a4ae04c18a01e457f0ec97 100644 --- a/pd/nw/pdgui.js +++ b/pd/nw/pdgui.js @@ -1607,7 +1607,7 @@ function create_window(cid, type, width, height, xpos, ypos, attr_array) { } // create a new canvas -function gui_canvas_new(cid, width, height, geometry, zoom, editmode, name, dir, dirty_flag, muldirty, hide_scroll, hide_menu, has_toplevel_scalars, cargs) { +function gui_canvas_new(cid, width, height, geometry, zoom, editmode, name, dir, dirty_flag, multipledirty, hide_scroll, hide_menu, has_toplevel_scalars, cargs) { // hack for buggy tcl popups... should go away for node-webkit //reset_ctrl_on_popup_window @@ -1661,7 +1661,7 @@ function gui_canvas_new(cid, width, height, geometry, zoom, editmode, name, dir, name: name, dir: dir, dirty: dirty_flag, - muldirty: muldirty, + multipledirty: multipledirty, args: cargs, zoom: zoom, editmode: editmode, @@ -2665,13 +2665,13 @@ function gui_gobj_dirty(cid, tag, state) { var border = e.querySelector(".border"); border.classList.remove("dirty"); border.classList.remove("subdirty"); - if(state == 1) border.classList.add("dirty"); - else if(state == 2) border.classList.add("subdirty"); + if(state === 1) border.classList.add("dirty"); + else if(state === 2) border.classList.add("subdirty"); }); } function gui_canvas_multipledirty(cid, state) { - var warning = patchwin[cid].window.document.getElementById("dirtywarning"); + var warning = get_item(cid, "dirtywarning"); if (state !== 0) warning.style.setProperty("display", "inline"); else warning.style.setProperty("display", "none"); } diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c index 933584cad529599fb03b255928bed49b5c535e80..0c447657823e93863a767c7c0965e5f1f9d1161e 100644 --- a/pd/src/g_canvas.c +++ b/pd/src/g_canvas.c @@ -221,9 +221,12 @@ t_symbol *canvas_getcurrentdir(void) return (canvas_getdir(canvas_getcurrent())); } +/* ** refactored function, check for errors */ t_symbol *canvas_getdir(t_canvas *x) { x = canvas_getrootfor(x); + /* in the case the root is an ab instance, we borrow the + dir from the main root canvas (where the definition is stored) */ if(x->gl_isab) x = x->gl_absource->ad_owner; t_canvasenvironment *e = canvas_getenv(x); return (e->ce_dir); @@ -473,8 +476,9 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) else x->gl_env = 0; x->gl_abdefs = 0; - if(canvas_newabsource) /* if absource is set means that this canvas is - going to be an ab instance */ + /* if canvas_newabsource is set means that + this canvas is going to be an ab instance */ + if(canvas_newabsource) { x->gl_isab = 1; x->gl_absource = canvas_newabsource; @@ -533,6 +537,8 @@ t_canvas *canvas_new(void *dummy, t_symbol *sel, int argc, t_atom *argv) canvas_field_vec = NULL; canvas_field_gp = NULL; + /* in the case it is an abstraction (gl_env is not null) + get the number of dirty instances of this same abstraction */ if(x->gl_env) { if(!x->gl_isab) @@ -798,15 +804,20 @@ void canvas_reflecttitle(t_canvas *x) /* --------------------- */ +/* the following functions are used to broadcast messages to all instances of + a specific abstraction (either file-based or ab). + the state of these instances change accoring to the message sent. */ + void clone_iterate(t_pd *z, t_canvas_iterator it, void* data); int clone_match(t_pd *z, t_symbol *name, t_symbol *dir); +/* packed data passing structure for canvas_dirty_broadcast */ typedef struct _dirty_broadcast_data { t_symbol *name; t_symbol *dir; int mess; - int *res; + int *res; /* return value */ } t_dirty_broadcast_data; static void canvas_dirty_deliver_packed(t_canvas *x, t_dirty_broadcast_data *data) @@ -831,10 +842,11 @@ static int canvas_dirty_broadcast(t_canvas *x, t_symbol *name, t_symbol *dir, in && ((t_canvas *)g)->gl_name == name && canvas_getdir((t_canvas *)g) == dir) { - res += (((t_canvas *)g)->gl_dirty > 0); - ((t_canvas *)g)->gl_dirties += mess; - if(((t_canvas *)g)->gl_havewindow) - canvas_multipledirty((t_canvas *)g, (((t_canvas *)g)->gl_dirties > 1)); + t_canvas *z = (t_canvas *)g; + res += (z->gl_dirty > 0); + z->gl_dirties += mess; + if(z->gl_havewindow) + canvas_multipledirty(z, (z->gl_dirties > 1)); } else res += canvas_dirty_broadcast((t_canvas *)g, name, dir, mess); @@ -902,10 +914,11 @@ static int canvas_dirty_broadcast_ab(t_canvas *x, t_ab_definition *abdef, int me if(canvas_isabstraction((t_canvas *)g) && ((t_canvas *)g)->gl_isab && ((t_canvas *)g)->gl_absource == abdef) { - res += (((t_canvas *)g)->gl_dirty > 0); - ((t_canvas *)g)->gl_dirties += mess; - if(((t_canvas *)g)->gl_havewindow) - canvas_multipledirty((t_canvas *)g, (((t_canvas *)g)->gl_dirties > 1)); + t_canvas *z = (t_canvas *)g; + res += (z->gl_dirty > 0); + z->gl_dirties += mess; + if(z->gl_havewindow) + canvas_multipledirty(z, (z->gl_dirties > 1)); } else res += canvas_dirty_broadcast_ab((t_canvas *)g, abdef, mess); @@ -943,6 +956,10 @@ int canvas_dirty_broadcast_ab_all(t_ab_definition *abdef, int mess) return (res); } +/* --------------------- */ + +/* climbs up to the root canvas while enabling or disabling visual markings for dirtiness + of traversed canvases */ void canvas_dirtyclimb(t_canvas *x, int n) { if (x->gl_owner) @@ -972,8 +989,12 @@ void canvas_dirty(t_canvas *x, t_floatarg n) if (x2->gl_havewindow) canvas_reflecttitle(x2); + /* set dirtiness visual markings */ canvas_dirtyclimb(x2, (unsigned)n); + /* in the case it is an abstraction, we tell all other + instances that there is eiher one more dirty instance or + one less dirty instance */ if(canvas_isabstraction(x2) && (x2->gl_owner || x2->gl_isclone)) { @@ -1214,7 +1235,21 @@ void canvas_free(t_canvas *x) { //fprintf(stderr,"canvas_free %lx\n", (t_int)x); - if(x->gl_dirty) + /* crude hack. in the case it was a clone instance, it shouldn't have an owner. + For ab instances, we have set the owner inside clone_free because we need it + in order to deregister the dependencies. + here we set it to NULL again to prevent any error in the functions called bellow */ + t_canvas *aux; + if(x->gl_isclone) + { + aux = x->gl_owner; + x->gl_owner = 0; + } + + /* in the case it is a dirty abstraction, we tell all other + instances that there is one less dirty instance */ + if(canvas_isabstraction(x) && x->gl_dirty + && (x->gl_owner || x->gl_isclone)) { if(!x->gl_isab) canvas_dirty_broadcast_all(x->gl_name, canvas_getdir(x), -1); @@ -1264,7 +1299,8 @@ void canvas_free(t_canvas *x) if(x->gl_isab) { x->gl_absource->ad_numinstances--; - canvas_deregister_ab(x->gl_owner, x->gl_absource); + canvas_deregister_ab((x->gl_isclone ? aux : x->gl_owner), + x->gl_absource); } /* free stored ab definitions */ @@ -2144,9 +2180,10 @@ t_canvas *canvas_getrootfor_ab(t_canvas *x) return (canvas_getrootfor_ab(x->gl_owner)); } -/* check if the dependency graph has a cycle, assuming an new edge between parent and current nodes - if there is a cycle, a visual scheme of the cycle is stored in 'res' */ -static int ab_check_cycle(t_ab_definition *current, t_ab_definition *parent, int pathlen, char *path, char *res) +/* check if the dependency graph has a cycle, assuming an new edge between parent and + current nodes if there is a cycle, a visual scheme of the cycle is stored in 'res' */ +static int ab_check_cycle(t_ab_definition *current, t_ab_definition *parent, int pathlen, + char *path, char *res) { if(current == parent) { @@ -2156,7 +2193,7 @@ static int ab_check_cycle(t_ab_definition *current, t_ab_definition *parent, int } else { - /* if it is a local private abstraction, get rid of class member-like names (only used internally) */ + /* if it is a local private abstraction, get rid of classmember-like names (only used internally) */ char *hash = strrchr(current->ad_name->s_name, '#'); if(!hash) hash = current->ad_name->s_name; else hash += 1; @@ -2174,7 +2211,7 @@ static int ab_check_cycle(t_ab_definition *current, t_ab_definition *parent, int } /* try to register a new dependency into the dependency graph, - returns 0 and the scheme in 'res', if a dependency issue is found */ + returns 0 and the scheme in 'res' if a dependency issue is found */ static int canvas_register_ab(t_canvas *x, t_ab_definition *a, char *res) { /* climb to closest ab */ @@ -2268,7 +2305,7 @@ static t_ab_definition *canvas_find_ab(t_canvas *x, t_symbol *name) return 0; } -/* adds a new ab definition. returns the definition if it has been added, 0 otherwise */ +/* tries to add a new ab definition. returns the definition if it has been added, 0 otherwise */ static t_ab_definition *canvas_add_ab(t_canvas *x, t_symbol *name, t_binbuf *source) { if(!canvas_find_ab(x, name)) @@ -2410,6 +2447,7 @@ static void canvas_abpush(t_canvas *x, t_symbol *s, int argc, t_atom *argv) pd_free(&x->gl_pd); } +/* extends the name for a local ab, using a classmember-like format */ static t_symbol *ab_extend_name(t_canvas *x, t_symbol *s) { char res[MAXPDSTRING]; diff --git a/pd/src/g_canvas.h b/pd/src/g_canvas.h index aab227d02ffec0c7c19f0444ce4f81d7c513e1b6..26c492e5ffe3e8314ee70f8abec4ad009db559f0 100644 --- a/pd/src/g_canvas.h +++ b/pd/src/g_canvas.h @@ -165,19 +165,19 @@ typedef struct _tick /* where to put ticks on x or y axes */ } t_tick; /* the t_ab_definition structure holds an ab definiton and all the attributes we need - to handle them */ + to handle it */ typedef struct _ab_definition { t_symbol *ad_name; /* id for the ab definition */ - t_binbuf *ad_source; /* binbuf where source is stored */ - int ad_numinstances; /* the num of instances of this abstraction */ - struct _ab_definition *ad_next; /* next ab definition */ - t_canvas *ad_owner; + t_binbuf *ad_source; /* binbuf where the source is stored */ + int ad_numinstances; /* number of instances */ + struct _ab_definition *ad_next; /* next ab definition */ + t_canvas *ad_owner; /* canvas that stores this definition */ /* dependency graph stuff */ int ad_numdep; /* number of other ab definitions that it depends on */ struct _ab_definition **ad_dep; /* the actual ab defintitions */ - int *ad_deprefs; + int *ad_deprefs; /* number of instances that define the dependency */ int ad_visflag; /* visited flag for topological sort algorithm */ } t_ab_definition; @@ -251,8 +251,8 @@ struct _glist t_word *gl_vec; /* for "canvas" data type */ t_gpointer gl_gp; /* parent for "canvas" data type */ - unsigned int gl_subdirties; /* number of descending dirty abstractions */ - int gl_dirties; /* number of diry instances of this type */ + int gl_subdirties; /* number of descending dirty abstractions */ + int gl_dirties; /* number of diry instances, for multiple dirty warning */ unsigned int gl_isab:1; /* is an ab instance */ t_ab_definition *gl_absource; /* ab definition pointer, @@ -601,7 +601,6 @@ EXTERN t_gobj *canvas_findhitbox(t_canvas *x, int xpos, int ypos, int *x1p, int *y1p, int *x2p, int *y2p); EXTERN int canvas_setdeleting(t_canvas *x, int flag); EXTERN int canvas_hasarray(t_canvas *x); - EXTERN void canvas_multipledirty(t_canvas *x, int on); #define LB_LOAD 0 /* "loadbang" actions - 0 for original meaning */ diff --git a/pd/src/g_clone.c b/pd/src/g_clone.c index 7dc43a9a5ffec568a6067f680a66b4c2ce3a9ebb..d5ba76414de9c785cf1e71efc617c821f3da4c27 100644 --- a/pd/src/g_clone.c +++ b/pd/src/g_clone.c @@ -63,9 +63,11 @@ typedef struct _clone int x_phase; int x_startvoice; /* number of first voice, 0 by default */ int x_suppressvoice; /* suppress voice number as $1 arg */ - t_canvas *x_owner; + t_canvas *x_owner; /* clone owner */ } t_clone; +/* the given 'it' function is executed over each of the underlying canvases + (they are passed as first parameter). 'data' is passed as second argument */ void clone_iterate(t_pd *z, t_canvas_iterator it, void* data) { t_clone *x = (t_clone *)z; @@ -199,8 +201,13 @@ static void clone_free(t_clone *x) for (i = 0; i < x->x_n; i++) { canvas_closebang(x->x_vec[i].c_gl); - if(x->x_vec[i].c_gl->gl_isab) //only for abs? + if(x->x_vec[i].c_gl->gl_isab) + { + /* crude hack. since clones don't have owner, + we set it manually to allow the clone to + deregister the dependencies */ x->x_vec[i].c_gl->gl_owner = x->x_owner; + } pd_free(&x->x_vec[i].c_gl->gl_pd); t_freebytes(x->x_outvec[i], x->x_nout * sizeof(*x->x_outvec[i])); @@ -254,6 +261,7 @@ void clone_setn(t_clone *x, t_floatarg f) { t_canvas *c; t_out *outvec; + /* in the case they are [ab]s, the instance number is one atom beyond */ SETFLOAT((x->x_vec[0].c_gl->gl_isab ? x->x_argv+1 : x->x_argv), x->x_startvoice + i); if (!(c = clone_makeone(x->x_s, x->x_argc - x->x_suppressvoice, x->x_argv + x->x_suppressvoice))) @@ -380,7 +388,7 @@ static void clone_dsp(t_clone *x, t_signal **sp) } } -static int clone_newab = 0; +static int clone_newabclone = 0; static void *clone_new(t_symbol *s, int argc, t_atom *argv) { t_clone *x = (t_clone *)pd_new(clone_class); @@ -420,7 +428,10 @@ static void *clone_new(t_symbol *s, int argc, t_atom *argv) else goto usage; /* store a copy of the argmuents with an extra space (argc+1) for supplying an instance number, which we'll bash as we go. */ - if(clone_newab) + if(clone_newabclone) + /* we are creating a clone from an [ab] definition, we use the same creation + method as for normal clones but the name we pass to objectmaker is + 'ab <name>' instead of just '<name>' */ { x->x_argc = argc; x->x_argv = getbytes(x->x_argc * sizeof(*x->x_argv)); @@ -429,7 +440,7 @@ static void *clone_new(t_symbol *s, int argc, t_atom *argv) SETFLOAT(x->x_argv+1, x->x_startvoice); x->x_s = gensym("ab"); x->x_owner = canvas_getcurrent(); - clone_newab = 0; + clone_newabclone = 0; } else { @@ -485,9 +496,10 @@ fail: return (0); } +/* creator for [ab]-based clones */ static void *abclone_new(t_symbol *s, int argc, t_atom *argv) { - clone_newab = 1; + clone_newabclone = 1; return clone_new(s, argc, argv); } diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c index 519f577353e2fee83830cbd0b62855e0919c45b7..29feb81d1f3557c8d24346bb3f80c87c6543e3d1 100644 --- a/pd/src/g_editor.c +++ b/pd/src/g_editor.c @@ -1294,6 +1294,7 @@ int clone_match(t_pd *z, t_symbol *name, t_symbol *dir); int clone_isab(t_pd *z); int clone_matchab(t_pd *z, t_ab_definition *source); +/* packed data passing structure for glist_doreload */ typedef struct _reload_data { t_symbol *n; @@ -1327,7 +1328,7 @@ static void glist_doreload(t_glist *gl, t_symbol *name, t_symbol *dir, ((t_canvas *)g)->gl_name == name && canvas_getdir((t_canvas *)g) == dir); - /* set dirty to 0 to remove the dirty markings*/ + /* remove dirtiness visual markings */ if(remakeit && ((t_canvas *)g)->gl_dirty) canvas_dirtyclimb((t_canvas *)g, 0); @@ -1398,6 +1399,9 @@ static void glist_doreload(t_glist *gl, t_symbol *name, t_symbol *dir, ) glist_doreload((t_canvas *)g, name, dir, except); + /* also reload the instances within ab-based clone objects + *COMMENT: missing recursive case for abstraction-based clone + objects that don't match with the one we are reloading? */ if(pd_class(&g->g_pd) == clone_class && clone_isab(&g->g_pd)) { t_reload_data d; @@ -1432,6 +1436,7 @@ void canvas_reload(t_symbol *name, t_symbol *dir, t_gobj *except) canvas_resume_dsp(dspwas); } +/* packed data passing structure for glist_doreload_ab */ typedef struct _reload_ab_data { t_ab_definition *a; @@ -1452,7 +1457,7 @@ static void glist_doreload_ab(t_canvas *x, t_ab_definition *a, t_gobj *e) remakeit = (g != e && pd_class(&g->g_pd) == canvas_class && canvas_isabstraction((t_canvas *)g) && ((t_canvas *)g)->gl_isab && ((t_canvas *)g)->gl_absource == a); - /* set dirty to 0 to remove the dirty markings*/ + /* remove dirtiness visual markings */ if(remakeit && ((t_canvas *)g)->gl_dirty) canvas_dirtyclimb((t_canvas *)g, 0); @@ -1468,6 +1473,7 @@ static void glist_doreload_ab(t_canvas *x, t_ab_definition *a, t_gobj *e) } glist_select(x, g); } + /* since this one won't be reloaded, we need to trigger initbang manually */ else if(g == e) canvas_initbang((t_canvas *)g); g = g->g_next; @@ -1485,6 +1491,7 @@ static void glist_doreload_ab(t_canvas *x, t_ab_definition *a, t_gobj *e) || (((t_canvas *)g)->gl_isab && (((t_canvas *)g)->gl_absource != a)))) glist_doreload_ab((t_canvas *)g, a, e); + /* also reload the instances within ab-based clone objects */ if(pd_class(&g->g_pd) == clone_class && clone_isab(&g->g_pd) && !clone_matchab(&g->g_pd, a)) { @@ -1492,7 +1499,6 @@ static void glist_doreload_ab(t_canvas *x, t_ab_definition *a, t_gobj *e) d.a = a; d.e = e; clone_iterate(&g->g_pd, glist_doreload_ab_packed, &d); } - g = g->g_next; } } @@ -1513,6 +1519,9 @@ void canvas_reload_ab(t_canvas *x) glist_doreload_ab(c, x->gl_absource, &x->gl_gobj); glist_amreloadingabstractions = 0; canvas_resume_dsp(dspwas); + /* we set the dirty flag of the root canvas (where the ab definitions + are stored) because its file contents (in this case, the definition + for an specific ab) has been edited */ canvas_dirty(c, 1); } @@ -5962,12 +5971,15 @@ static void gobj_emphasize(t_glist *g, t_gobj *x) gui_vmess("gui_gobj_emphasize", "xs", g, rtext_gettag(y)); } + /* tell the gui to mark a gobj as dirty (change border color) */ void gobj_dirty(t_gobj *x, t_glist *g, int state) { t_rtext *y = glist_findrtext(g, (t_text *)x); gui_vmess("gui_gobj_dirty", "xsi", g, rtext_gettag(y), state); } + /* tell the gui to display a warning about the existence of + multiple dirty instances of the same abstraction */ void canvas_multipledirty(t_canvas *x, int on) { gui_vmess("gui_canvas_multipledirty", "xi", x, (on > 0)); diff --git a/pd/src/g_readwrite.c b/pd/src/g_readwrite.c index 9c591dbf8c1cbae251a7c4ba182964370fb01a04..007dcc0ee3f156ce1a686233496b4a1154912ac8 100644 --- a/pd/src/g_readwrite.c +++ b/pd/src/g_readwrite.c @@ -982,7 +982,7 @@ static void canvas_savetofile(t_canvas *x, t_symbol *filename, t_symbol *dir, void canvas_reload_ab(t_canvas *x); -/* updates the shared ab definition and reloads all the instances */ +/* updates the shared ab definition and reloads all instances */ static void canvas_save_ab(t_canvas *x, t_floatarg fdestroy) { if(!x->gl_absource) bug("canvas_save_ab"); diff --git a/pd/src/g_text.c b/pd/src/g_text.c index 501dd0b0cb296d1537fba474d689dd562f6fbe31..6c875164c9ca8ffcaa0423aa8571fc642f4f7a8e 100644 --- a/pd/src/g_text.c +++ b/pd/src/g_text.c @@ -2122,6 +2122,8 @@ static void text_vis(t_gobj *z, t_glist *glist, int vis) rtext_width(y), rtext_height(y), 1); rtext_draw(y); + /* check whether we have to tell the gui to mark + (border color) the gobj as dirty or not */ if(pd_class(&x->te_pd) == canvas_class) { if (((t_canvas *)x)->gl_dirty)