Hi,
I know the subject sounds strange. Unfortunately I have not yet found the time to extract it into a small and clean example code. I am a bit under pressure with my timeline and already lost the entire day, trying to find cause and workaround for the issue.
I am only posting here, because I hope, it rings a bell with somebody and I get a "Duh, you dipshit, is this the first dialog you are writing? Of course you need to do it like so".
So, here's the issue. In a customer's plugin I have a quite complex asynchronous dialog (opened from a CommandData, pretty standard in this way).
Quite a lot relies on InitValues() properly being called.
Usually we get a sequence like this:
- CommandData.Execute() opens the dialog.
- CreateLayout()
- InitValues()
All fine.
Now, if the dialog is docked into the startup layout, the sequence changes slightly:
- CommandData.RestoreLayout()
- CreateLayout()
- InitValues()
All fine as well.
My problems start, if the dialog is docked into the layout and folded (e.g. by middle clicking it's title bar).
Now, if C4D starts up, it looks like so:
- CommandData.RestoreLayout()
- CreateLayout() (important to note, this runs after RestoreLayout() has run completely and exited).
And then nothing.
If the user now unfolds the dialog, still nothing. No call to InitValues().
So, I thought, I would need to come up with my own InitValues() call.
By now I have tried the following things:
a) I tried to send a CoreMessage from RestoreLayout(), right before exiting the function. This CoreMessage is never received.
b) EVMSG_CHANGE is also no option. It doesn't happen upon unfolding the dialog. Neither is it received before.
c) As i received no CoreMessage during this phase, I thought I'd pick an arbitrary message, which happens after CreateLayout() has been called and do a one time call to InitValues() there (basically with a flag, which is set in RestoreLayout and then reset after message got received). By this approach all hell break loose. Obviously CreateLayout runs in parallel to the thread calling my Message(), so i ended up with InitValues() being called, while CreateLayout was still running. The splatter in a Dario Argento moving is nothing compared to the results I received this way.
d) This is what I currently use as a workaround, but I deem it a pretty ugly solution. Basically a small state machine. In RestoreLayout a flag is set, saying "coming from restore". At the very end of CreateLayout() in case we are "coming from restore" a flag is set "done with CreateLayout". With the next message (I arbitrarily picked one, which is coming reliably, didn't even check, which it is (id is 1651078253) I check, if I'm coming from restore and create layout is done and then initiate a call to InitValues(). This seems to work for the moment, but of course seems also like a pretty risky and "racy" approach. The "raciness" could be healed by emitting a CoreMessage in this case and then call InitValues when it is received. I dig this. But the entire approach feels so awkward to me...
I must have missed something really fundamental here. Something crucial to properly handle this situation.
Unfortunately searching the forum and browsing the SDK docs, I was not able to find any hints into the direction of my issue.
So, to wrap it up and try to summarize the question in a nutshell:
What is the correct way to get a call to InitValues() after C4D has started up for a dialog that got docked and folded in the startup layout?
Any pointers would be very welcome!
Thanks for your efforts in advance, I really hope the question is as stupid, as I fell right now.
Cheers,
Andreas
Edit: Forgot to set tags... oh, unfortunately I can't set more than seven tags. I'm testing here on Win10. It is a Python plugin. And I have this issue in all versions of C4D I tested, meaning all from R17 up to S24.