We've found that some callbacks for
ObjectData::Message(GeListNode* node, Int32 type, void* data)
is no longer executed on the main thread at least some messages like:
Since our plugin requires third-party communications executing some functions on the main thread is necessary.
Is there any way to force that call on the main thread for the newer versions?
(Notice that these calls were executed on the main thread in R25 and older versions).
Thank you for reaching out to us. While I am fairly confident that I understand your question, I am going to be very literal in my answer to avoid some ambiguities.
You state that '[your] plugin requires third-party communications' and therefore assert that 'executing some functions on the main thread is necessary' for you. I do not understand what you mean by that. You should describe more precisely what you want to do in that message function.
What the right solution is for you depends heavily on what you want to do. What however is not possible, is to force your ::Message method only being called from the main thread.
To do that, you should use a lock/semaphore, so that only one entity/thread at a time can access your data, e.g., write to a global log file or send data to a server. There are classic API and maxon API types which can help you with that. It is strongly recommend to use them over similar functions of the std library.
You must defer the execution of your code to the main thread here. There are in principle two ways to achieve that.
Defer by waiting: The simplest pattern is to simply store the notion that you want to do X on the main thread when you encounter the the state Y in a non-main thread. In the simplest form this could be a private field Bool _doX; on your object hook which you then set to true. The next time ::Message is being called and you are on the main thread, you then simply carry out doing X and then set the field back to false. The disadvantage of this approach is that you have no control over when X is actually carried out, as you must wait for something else calling your object hook on the main thread. The advantage is that you do not hold up everything else as with the second method.
Defer with ExecuteOnMainThread: With this function you defer the execution of a lambda/delegate to the main thread. The advantage of this approach is that the changes are carried out immediately (at least relatively) and you can directly 'carry on' in your code. The disadvantage is that that the function is based on maxon::JobInterface, i.e., there is a queue of jobs on the main thread which are solved sequentially, and you might not be first in line. Also, this is by definition blocking. So, when you are inside a thread Y which has been optimized for speed, and you then defer the computationally heavy task X to the main thread, first wait for other things to be done, and then do your task X, the thread Y is waiting all that time for you and with it everything that relies on that thread. This does not mean that you should not use the function, but you should be careful.
It could look something like this (untested pseudo-code):
MyObjectData::Message(GeListNode* node, Int32 type, void* data)
// The #something event has happened, and we are not on the main thread.
if ((type == ID_SOMETHING) && !GeIsMainThreadAndNoDrawThread())
// We add a cube to the document of #node from the main thread.
BaseDocument* const doc = node.GetDocument();
BaseObject* const cube = BaseObject::Alloc(Ocube);
if (!doc || !cube)
doc->InsertObject(cube, nullptr, nullptr);
// Other code ...
return SUPER::Message(node, type, data);
You could also use other more complex approaches here, but they are always just a variation of these two (e.g., use a MessageData or SceneHookData plugin).