Hello again!
I am trying to create a plugin system for my recent project. I want the plugins GUI to be displayed inside a Component on the main applications GUI. I wrote two classes to create a tunnel between the main app and the lib, but you can guess that it is not working as I wish, hence my question here.
The problem seems to be a restriction in JUCE code, so I hope someone finds some time to help me out.
I attached an image to explain the idea:
[attachment=0]sketch.gif[/attachment]
The library-gui is coded with JUCE components. These components are attached to a “fake window”: The TunnelPeer - a class inherited from ComponentPeer. This class translates repaint() calls from the GUIs components and passes them on to the main application via the C API.
On the other side, the main application has a TunnelComponent attached to its GUI. This TunnelComponent is “connected” to the TunnelPeer inside the library. It has an image buffer that is painted onto the screen when necessary. Now after the library has called the main application because its GUI needs to be repainted, the main application will eventually do a call to the TunnelPeer to make it repaint the libraries GUI and pass simple Bitmap data back to the main application. This bitmap data is filled inside the TunnelComponents internal buffer and made visible on the screen.
Other GUI related calls (such as Mouse Events) will be treated similar.
This way, I have simple classes on both ends of the tunnel. These behave like normal JUCE classes but are internally connected. So anything drawn on the libraries GUI can be made visible on the main applications GUI through a C interface.
The nice thing is, that any call to “repaint()” from any component inside the libraries GUI will propagate through its parent Components until they reach the TunnelPeer. The TunnelPeer will propagate the message to the main application and from there on upwards until it finally reaches the Window of the main application. So from the library the behavior should actually be the same as if it had its own window.
Now, that does only work partially. The problem is the propagation of this repaint() call from one Component to its parent. Look at this part of the juce::Component implementation[code]void Component::internalRepaintUnchecked (const Rectangle& area, const bool isEntireComponent)
{
if (flags.visibleFlag)
{
if (cachedImage != nullptr)
{
if (isEntireComponent)
cachedImage->invalidateAll();
else
cachedImage->invalidate (area);
}
if (flags.hasHeavyweightPeerFlag)
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED
ComponentPeer* const peer = getPeer();
if (peer != nullptr)
peer->repaint (area);
}
else
{
if (parentComponent != nullptr)
parentComponent->internalRepaint (ComponentHelpers::convertToParentSpace (*this, area));
}
}
}[/code]
When a Component needs to be repainted, it will call its parent Component, if there is one. And if it has “flags.hasHeavyweightPeerFlag” set, it will try to find a ComponentPeer to call “repaint” on. My own TunnelPeer Component is such a HeavyweightPeer but the flag can only be set by calling “Component::addToDesktop(…)”. Which is clearly not, what I’m trying to do. So basically: The repaint() messages from components inside the library propagate all the way up to the most top-level Component that has been attached to my TunnelPeer. But the heavyweight-Flag is not set (and can’t ever be set except from ComponentPeer itself). Thus it will never call the TunnelPeer and thus the message will never reach the main application.
I know that’s a pretty long explanation and I hope it was clear. Please, if anyone has an idea: What can i do to get that propagation right? Everything else seems to be working…
StrangeMan