// arg is subscriber name void jcom_core_subscriber_new_common(t_jcom_core_subscriber_common *x, t_symbol *name, t_symbol *subscriber_type) { t_atom a; x->subscriber_type = subscriber_type; x->custom_subscribe = NULL; x->hub = NULL; x->module_name = _sym_nothing; // we call the function directly here rather than use object_attr_setvalueof() // because parameters with pattr bindings don't actually have their own 'name' attribute atom_setsym(&a, name); jcom_core_subscriber_attribute_common_setname(x, NULL, 1, &a); x->container = jamoma_object_getpatcher((t_object*)x); // set up the jcom.receive the listens to broadcast messages from the hub atom_setsym(&a, jps_jcom_broadcast_fromHub); }
// TODO: When running in the debugger, it seems like we are iterating through this function a whole bunch of times! // Can we put it in a qelem or something so that it only gets called once? [TAP] // But actually, maybe it is just a Max 4.6 funky Runtime thing? Let's take a look again when we get to Max 5 void hub_examine_context(t_hub *x) { AtomCount argc = 0; AtomPtr argv = NULL; SymbolPtr context = jamoma_patcher_getcontext(x->container); // Try to get OSC Name of module from an argument jamoma_patcher_getargs(x->container, &argc, &argv); // <-- this call allocates memory for argv if(argc){ x->osc_name = atom_getsym(argv+(argc-1)); sysmem_freeptr(argv); } else x->osc_name = _sym_nothing; // Try to get OSC Name of module from scripting name if(x->osc_name == _sym_nothing) x->osc_name = jamoma_patcher_getvarname(x->container); // In this case we overwrite whatever happened above if(context == gensym("toplevel")){ x->osc_name = gensym("/editing_this_module"); x->editing = true; } else{ t_object* patcher = jamoma_object_getpatcher((t_object*)x); t_object* box = object_attr_getobj(patcher, jps_box); t_object* ui = NULL; t_symbol* objclass = NULL; x->editing = false; ui = object_attr_getobj(patcher, gensym("firstobject")); while(ui){ objclass = object_attr_getsym(ui, gensym("maxclass")); if(objclass == gensym("jcom.ui")) break; ui = object_attr_getobj(ui, gensym("nextobject")); } if(ui){ t_rect boxRect; t_rect uiRect; if(context == gensym("bpatcher")){ object_attr_get_rect(ui, _sym_presentation_rect, &uiRect); object_attr_get_rect(box, _sym_patching_rect, &boxRect); boxRect.width = uiRect.width; boxRect.height = uiRect.height; object_attr_set_rect(box, _sym_patching_rect, &boxRect); object_attr_get_rect(box, _sym_presentation_rect, &boxRect); boxRect.width = uiRect.width; boxRect.height = uiRect.height; object_attr_set_rect(box, _sym_presentation_rect, &boxRect); } else if(context == gensym("subpatcher")){ object_attr_get_rect(ui, _sym_presentation_rect, &uiRect); object_attr_get_rect(patcher, _sym_defrect, &boxRect); boxRect.width = uiRect.width; boxRect.height = uiRect.height; object_attr_set_rect(patcher, _sym_defrect, &boxRect); object_attr_setchar(patcher, _sym_toolbarvisible, 0); } } } object_attr_setsym(x, _sym_name, x->osc_name); hub_subscriptions_refresh(x); hub_internals_create(x); qelem_unset(x->init_qelem); // clear the last thing to make sure we don't call into this a bunch of times qelem_set(x->init_qelem); // flag the queue for initialization }
void *hub_new(t_symbol *s, long argc, t_atom *argv) { short i; long attrstart = attr_args_offset(argc, argv); t_hub *x = (t_hub *)object_alloc(s_hub_class); t_symbol *name = _sym_nothing; t_atom a[2]; if(attrstart && argv) atom_arg_getsym(&name, 0, attrstart, argv); else{ t_object* patcher = jamoma_object_getpatcher((t_object*)x); t_symbol* filepath = object_attr_getsym(patcher, _sym_filepath); char pathstr[MAX_PATH_CHARS]; char* filename = 0; strncpy_zero(pathstr, filepath->s_name, MAX_PATH_CHARS); filename = strrchr(pathstr, '.'); if(filename) { *filename = 0; // strip the suffix by setting '.' to terminating NULL char filename = strrchr(pathstr, '/'); if (filename) { // Our module name is the patchers name since the patcher is typically located // at /some/where/nameToUseForModule.maxpat filename++; // get rid of slash name = gensym(filename); } else name = gensym(pathstr); } else { // We are an unnamed jcom.hub inserted into an unsaved max patcher which has // no '.' in it's filename. Just leave as untitled, at least until it is saved. name = gensym("Untitled"); } } if(x){ for(i=k_num_outlets; i > 0; i--) x->outlets[i-1] = outlet_new(x, 0); object_obex_store((void *)x, _sym_dumpout, (t_object *)x->outlets[k_outlet_dumpout]); x->init_qelem = qelem_new(x, (method)hub_qfn_init); // set default attributes x->attr_name = name; x->osc_name = _sym_nothing; x->attr_type = jps_control; x->attr_description = _sym_nothing; x->attr_algorithm_type = jps_default; // poly for audio, jitter for video, control for control x->attr_size = jps_1U_half; x->attr_inspector = 0; x->using_wildcard = false; x->in_object = NULL; // module MUST have a jcom.in object x->out_object = NULL; // the jcom.out object is optional x->gui_object = NULL; // jcom.remote in the gui x->num_parameters = 0; for(i=0; i<MAX_NUM_CHANNELS; i++) x->meter_object[i] = NULL; x->preset = new presetList; // begin with no presets x->subscriber = new subscriberList; // ... and no subscribers attr_args_process(x, argc, argv); // handle attribute args x->jcom_send = NULL; x->jcom_receive = NULL; atom_setsym(a, jps_jcom_remote_fromModule); x->jcom_send = (t_object*)object_new_typed(_sym_box, jps_jcom_send, 1, a); atom_setsym(a, jps_jcom_remote_toModule); x->jcom_receive = (t_object*)object_new_typed(_sym_box, jps_jcom_receive, 1, a); object_method(x->jcom_receive, jps_setcallback, &hub_receive_callback, x); if(!g_jcom_send_notifications){ atom_setsym(a, gensym("notifications")); g_jcom_send_notifications = (t_object*)object_new_typed(_sym_box, jps_jcom_send, 1, a); } x->container = jamoma_object_getpatcher((t_object*)x); // The following must be deferred because we have to interrogate our box, // and our box is not yet valid until we have finished instantiating the object. // Trying to use a loadbang method instead is also not fully successful (as of Max 5.0.6) defer_low(x, (method)hub_examine_context, 0, 0, 0); } return x; }