How to refer to a coll from custom external

Luigi Castelli's icon

Hi folks,

I am writing a custom UI external that manages lists of values.
It would be great to give the user the ability to use coll features to manipulate the list.

So, what I want to do is to refer to an existing coll object from inside my external.
Please note that I don't mean creating a NOBOX coll object inside my external.
What I mean is that if there is already a coll instantiated in the patch I want to be able to connect to it.

Ideally, I would like to create a state where my external and the coll are sync'd to each other, so that if you change the content of one the changes are reflected in the other. Similar to what jit.cellblock does with - precisely - the 'refer' message.

I know how to send remote messages from my object to the coll, so that I can update its state with the state of my object. I also know how to attach my object to the coll, so that I can receive coll's notifications. However that's where I am having problems...

In code:

void myobj_refer(t_myobj *x, t_symbol *sym)
{
    t_object *thing = sym->s_thing;

    if (thing == NULL)
        return;
    if (NOGOOD(thing))
        return;
    if (!object_classname_compare(thing, gensym("xcoll")))
        return;

    object_attach_byptr_register((t_object *)x, thing, CLASS_BOX);
    x->xcoll = thing;
}

t_max_err myobj_notify(t_myobj *x, t_symbol *sym, t_symbol *msg, void *sender, void *data)
{
    if (x->xcoll == sender) {
        if (msg == _sym_free) {
            object_detach_byptr((t_object *)x, x->xcoll);
            x->xcoll = NULL;
        }

        object_post((t_object *)x, "msg: %s", msg->s_name);
    }
    return jbox_notify((t_jbox *)x, sym, msg, sender, data);
}

Now xcoll is a pointer to the coll object instantiated in the patch and I am able to receive notifications from it. Great!
Problem is that the only notification I receive from coll is a _sym_free message when the coll is deleted from the patch. Any other operation performed directly on the coll (such as inserting or sorting) I am not able to detect. Also, I am not receiving any notifications if I change the 'embed' attribute, which is the only attribute coll has. Normally, I should receive a _sym_attr_modified message.
Last but not least, any message that I send remotely generates an error in the max window such as:
xcoll: doesn't understand "insert"

Please, someone help... I am completely lost...

Thank you so much.

- Luigi

Timothy Place's icon

Hi Luigi,

xcoll doesn't have any attributes at all, and provides no notifications of anything but freeing (only because all objects notify about freeing). So that's why you don't get any notifications. the embed attribute is an attribute of the coll object.

There isn't a way to get a callback from coll or xcoll when the contents have changed. You'll have to poll it with a clock.

Cheers

Luigi Castelli's icon

Thanks for your reply, Tim...

so I understand that coll is just a wrapper for xcoll basically.
The real action happens in xcoll, but coll acts as a shell providing attributes and messages to xcoll.

So - to begin with - how do I bind to coll and not xcoll?

- Luigi

Luigi Castelli's icon

The easiest way that I have found to bind to coll is to use the #T symbol.
It seems that all colls are automagically bound to that symbol.
So, if there is a coll instantiated in the patch, the following code binds you to it without the need of iterating through the patcher:

x->coll_obj = gensym("#T")->s_thing;

Of course - since I found this out by trial and error - I don't know if that's the proper way to do it, or if it's just a hack that might work now and not tomorrow. Only C74 will be able to tell...

Also, I am completely clueless as to how to access coll's content once I am bound to it.
If someone (Tim?) could shed some light on this whole coll business, I will be forever grateful.

Cheers.

- Luigi

Timothy Place's icon

@vanille : try using object_attach_byptr_register() instead of object_attach_byptr()

Timothy Place's icon

Hi Luigi,

You are right to bind to xcoll for the data, and if you were able to bind to coll it wouldn't really help you. Sorry I confused you with my previous response.

Accessing the contents of a coll is not really supported, anything you do with this could break in the future.

To reflect this, the source code for coll (which is in the Max 4.5.5 SDK) is not in the Max 5 SDK.

Unfortunately, the struct for xcoll has changed in Max 5 too. The second member of the struct is a t_linklist* that contains the data -- however, the use of this is completely unsupported. It is unlikely you'll get much more assistance with this problem since 3rd-party coll access isn't considered to be part of the Max API.

Good luck

Johannes's icon

Hi,

I tried to combine the info of this thread to a valid external, but it is crashing all the time...
Is there a result of this discussion how to use a named coll inside an external?

Best,
Johannes

Timothy Place's icon

Hi Johannes,

For the next major version of Max we will be providing a much better API for dealing with structured data access. Unfortunately, as mentioned in this thread, accessing data from coll in Max 5 is not supported.

best,
Tim

Peter Castine's icon

About binding to gensym("#T")… I would just note that there is no guarantee that anything bound to that symbol is necessarily a coll. I seem to recall that tables also (used to?) bind to that symbol, and I know of at least one 3rd-Party object that binds to #T, too.

Binding to a symbol was a technique for reading embedded coll/table/whatever data in the patcher file on Max4 (cf the thread https://cycling74.com/forums/distinguishing-between-maxpat-and-pat-mxb-mxt-in-my-instantiation-routine ). The symbol could be any arbitrary symbol, but the sample code all seemed to use #T, so that's what I used when I built an object that embedded data into patcher files. Other people may have done so, too, for the same reason.

Also, even if the symbol is bound to a coll, there may be multiple colls open in Max at any one time, so there's no guarantee which coll you're binding to.

Luigi Castelli's icon

You are absolutely right, Peter.
that was a hack to see how far I could go exploring something unsupported.

Gotta wait for Max 6...

Best.

- Luigi