This AutoResizingNSViewComponentWithParent gets created and allocates and sets its own internal view (which you can see in the constructor)
VSTPluginWindow::openPluginWindow is then called, passing in this newlyt created NSView
The plugin takes a reference to that NSView
After 30ms the timer callback happens and the AutoResizingNSViewComponentWithParent looks inside the view it created for any subviews and assigns one of those to the owned view
The originally juce-created NSView is now deleted and the plugin holds a dangling reference to it
The plugin tries to attach a new NSView (like a popup menu) to the dangling NSView
Plugin crashes
Is there a reason for this async reassignment of the child?
And does anyone know if it’s valid for plugins to take a reference to the NSView passed in to the Vst2::effEditOpen call?
Hmm, thinking about this a bit more this is probably so that if the NSView that the plugin creates changes size, the AutoResizingNSViewComponentWithParent can respond to that?
Do we know exactly which plugins require this behaviour?
I’m going to have to raise this again as I’ve got several users complain that Softube plugins are crashing when their UIs are opened on macOS now and I can replicate the problem.
If I comment out that startTimer call in AutoResizingNSViewComponentWithParent, the plugin UIs successfully open. This problem is also evident in pluginval.
I’d like to say all plugin developers would update their plugins and not keep a reference to the passed in NSView but unfortunately I don’t think that’s going to happen and I’ve had several developers already tell me they won’t make that change.
Do we have any examples of plugins that resize a nested view but not the top level NSView?
I did try retaining the created NSView until the destruction of the AutoResizingNSViewComponentWithParent but that results in a blank UI.
I’ve spent ages trying to get both Softube plugins to load and this plugin but to no avail.
I’ve tried forcing resizes all over the place, retaining the original view, passing the actual window to openPluginWindow and even closing and reopening the window to try and pass the child view back in to itself.
Basically I’m at a bit of a dead end. One thing I can say after speaking to some plugin developers is that they definitely don’t expect the pointer passed to Vst2::effEditOpen to be deleted on them.
The only thing I can think of at this time is to start adding exceptions for certain plugin manufacturers to not start the timer.
I’m wrestling with this issue as well, with JUCE 6.0.8.
I’ve put in some nasty hacks to AutoResizingNSViewComponentWithParent for now, but it would be great if this could get resolved once and for all in the framework.
I’m investigating this at the moment. Are you aware of any plugins, other than the following, which misbehave with the current setup in JUCE?
Softube plugins. I’m using Saturation Knob for testing, which crashes when the timer is present.
KORG Gadget series, which display a black screen when the timer is present.
FabFilter Pro-C, which displays at the wrong size when the timer is not present, if created on a retina display.
I have a potential fix which seems to resolve problems with the above plugins. However, it would be good to check with some other problematic plugins (if there are any) before pushing this new approach.
Sure, it’s very much WIP, but something like this seems to work for the three problematic plugins above. I haven’t tested this on iOS yet, so there’s a chance it’ll break things there.
struct AutoResizingNSViewComponentWithParent : public AutoResizingNSViewComponent,
private Timer
{
AutoResizingNSViewComponentWithParent()
: view ([[[JUCE_IOS_MAC_VIEW alloc] init] autorelease])
{
setView (view);
// Some FabFilter plugins may open at the wrong scale, so we'll try giving them
// a nudge once they've had a chance to display.
startTimer (30);
}
~AutoResizingNSViewComponentWithParent() override { stopTimer(); }
void resized() override
{
const auto currentBounds = convertToRectFloat ([view frame]);
const auto requiredBounds = getLocalBounds().toFloat();
if (currentBounds != requiredBounds)
{
const auto convertedBounds = convertToCGRect (requiredBounds);
[view setFrame: convertedBounds];
for (JUCE_IOS_MAC_VIEW* subview in [view subviews])
[subview setFrame: convertedBounds];
}
}
private:
void timerCallback() override
{
stopTimer();
resized();
}
NSView* view = nullptr;
};
After a bit of testing, this still doesn’t seem to resize Pro-C properly. It opens at the right scale, but any additional resizing causes it to break again. I’ll have another go at this tomorrow.
All I did was rework the AutoResizingNSViewComponentWithParent constructor, adding a bool parameter to control whether or not the timer gets started. I only disable the timer for Softube plug-ins, which at least makes them usable on the Mac.
I’ve spent a bit more time looking at this, and unfortunately still haven’t managed to find a solution which works for all the plugins mentioned here. The most problematic plugin is Pro-C - all other plugins I’ve tried seem to work properly when the timer code is removed completely. Pro-C seems to be somewhat broken in every configuration I’ve tried, though. Even on the current develop, the view reverts to the incorrect size if the plugin view is resized at all after the timer has fired (at least on Catalina with a retina display - it’s less broken on Big Sur).
Given that Pro-C is slightly broken with or without the timer, and that removing the timer allows us to avoid breakage in Korg and Softube plugins, my current inclination is to just remove the timer. This should allow Korg and Softube plugins to work, without degrading the experience of using Pro-C.
Do you have any thoughts on this approach? Do you foresee it causing issues on your side?
Yes, it’s not ideal. I was thinking that, in a trade-off between Softube plugins crashing the host, and Pro-C rendering incorrectly, the latter scenario is likely preferable. However, I can see that existing Pro-C users may not feel the same way.
If it’s really only Pro-C that behaves this way, could you add an exception for it? At least it would document the behaviour. That way, if there are any more reports of plugins appearing 1/4 size, they could be added to the exception list?
Not ideal but might save some time.
Is there an Apple AU host example somewhere? Does this behave correctly? If so, what do they do with the parent view?
I have a similar issue when hosting VST3 plugins on OSX. I would like to set the editor of the hosted plugin as a child component of my editor, so embed its editor into my GUI. It works fine in case of most plugins, but in case of Native Instrument plugins a new native window is created when the plugin is loaded. It happens only on OSX and only in case of VST3 format. On Windows it works fine. Has anybody else already run into the same problem?
I use JUCE 6.1.2.
Thank you!