Bug with calling Editor setSize() in VST3

I’ve found that calling setSize() inside of an AudioProcessorEditor with a size that exceeds the screen bounds causes incorrect editor drawing / positioning. I’ve observed this with VST3 in Live - AU works properly.

I’ve got a plugin which the user can continuously resize with a corner resizer. The plugin also has an “expansion” panel for more advanced parameters, which is opened at the bottom of the plugin via a button in the UI.

The issue is - when the VST3 plugin size is close to the screen height and the user opens the expansion panel (making the plugin height greater than the available screen height), the hosting window doesn’t also expand. This results in the editor being “moved up” inside of the window, and appearing incorrectly. This doesn’t happen with AU in Live, as the host window also expands.

Here’s a video of what I’d expect to happen (AU in Live):

Here’s what happens with VST3:

What’s interesting, is if I don’t make the plugin resizable, and just size the plugin close to the screen size, then the issue doesn’t happen in VST3:

I’ve also noticed that something similar happens with VST3 in Cubase - the host window doesn’t resize. It’s less noticeable there, however, because the editor’s position stays the same. It just draws past the bottom of the host window.

Here’s the code for the demo editor used in the above videos, if helpful. Just replace the setResize… stuff in the constructor with setSize() close to the screen bounds to get the behavior in the last video.

class JuceDemoPluginAudioProcessorEditor final : public AudioProcessorEditor
    {
    public:
        JuceDemoPluginAudioProcessorEditor (JuceDemoPluginAudioProcessor& owner)
            : AudioProcessorEditor (owner)
        {
            wrapperLabel.setText(owner.getWrapperTypeDescription(owner.wrapperType), dontSendNotification);
            addAndMakeVisible(wrapperLabel);

            expandButton.setButtonText("Expand");
            expandButton.setClickingTogglesState(true);
            addAndMakeVisible(expandButton);
            expandButton.onClick = [this]
            {
                if (expandButton.getToggleState())
                    setSize(getWidth(), std::min(getHeight() + expandHeight, maxHeight));
                else
                    setSize(getWidth(), getHeight() - expandHeight);
            };

            // set resize limits for this plug-in
            setResizeLimits(minWidth, minHeight, maxWidth, maxHeight);
            setResizable(true, owner.wrapperType != wrapperType_AudioUnitv3);

            // ... it works if you comment out the above two lines and use this instead though!
            // setSize(widthCloseToScreenBounds, heightCloseToScreenBounds);
        }

        ~JuceDemoPluginAudioProcessorEditor() override {}

        //==============================================================================
        void paint (Graphics& g) override
        {
            g.setColour(juce::Colours::darkgrey);
            g.fillAll();

            auto gradBounds {getNonExpandedBounds()};
            g.setGradientFill(juce::ColourGradient::vertical(juce::Colours::darkred, gradBounds.getY(),
                                                             juce::Colours::darkblue, gradBounds.getBottom()));
            g.fillRect(gradBounds);
        }

        void resized() override
        {
            auto bounds {getNonExpandedBounds().reduced(8)};

            constexpr int w = 100;
            constexpr int h = 40;
            wrapperLabel.setBounds(bounds.withWidth(w).withHeight(h));
            expandButton.setBounds(bounds.withSizeKeepingCentre(w, h));
        }

    private:
        juce::Rectangle<int> getNonExpandedBounds()
        {
            auto bounds {getLocalBounds()};

            if (expandButton.getToggleState())
                bounds.removeFromBottom(expandHeight);

            return bounds;
        }

        juce::TextButton expandButton;
        juce::Label wrapperLabel;

        static constexpr int minWidth = 400;
        static constexpr int minHeight = 400;
        static constexpr int maxWidth = 4000;
        static constexpr int maxHeight = 4000;
        static constexpr int expandHeight = 200;
    };

Has anyone else run into this before, and have a solution? Or is this just some limit of VST3? It doesn’t seem like we get called back with the VST3 wrapper’s checkSizeConstraint()function, so the host seemingly accepts the new size, but then doesn’t actually size up it’s hosting window to it.

1 Like

Bump. JUCE team, would it be possible to take a look at this?

1 Like

Yet another bump. I worked around the issue by limiting the maximum size of the plugin window based on the display size, but I’d appreciate any insight.

This is on my backlog. However, I was away for the last couple of weeks so I’ve got quite a lot else to look at, too. I’ll update this thread once we have an update to share.

1 Like

I’ve done some quick debugging in the Live beta 12.3b14.

The call sequence when the plugin initiates a resize is outlined here:

  • The plugin calls resizeView on the host interface to request a new size.
  • If the host can’t honour the new size, then it’s allowed to ignore the request!
  • Otherwise, the host might try some alternative sizes, checking them by calling checkSizeConstraint on the plugin view.
  • Once the host has found a size that both the host and plugin consider suitable, then it can call onSize on the plugin editor to set the new size.

What I’m actually seeing is as follows:

  • We click the “expand” button.
  • The plugin computes a new size (e.g. 700x1570) and passes it to resizeView.
  • Live calls back to checkSizeConstraint() with a smaller rect that would fit on-screen (e.g. 700x1421).
  • The plugin does not modify this rect, and it returns kResultTrue from checkSizeConstraint. This indicates to the host that the plugin is happy with the new viewport size.
  • Live then calls onSize(), but passes the size that the plugin requested, instead of the modified size that it just validated with checkSizeConstraint.

It seems like the problem is that Live shrinks the editor window to fit on-screen, but then sets the plugin view to a different, larger size. As far as I can tell, the VST3 wrapper is doing the right thing, so I think this is a bug in Live. I don’t think there’s a feasible workaround on the plugin side.


Reported to Ableton as L12-BUG-4665

Thanks for taking a look and the detailed explanation! I’d taken a look in the documentation in my local copy of the VST3 SDK, but hadn’t been able to find that diagram - super helpful.

Additionally, thanks for submitting the report to Ableton.

I’ll note that Cubase 14 seems to have a related issue. When clicking “Expand”, the viewport only expands to the maximum height that would fit on screen, and the UI will draw off the bottom of the viewport. Definitely a much less noticeable issue, but still perhaps worth opening a bug report with Steinberg? They don’t appear to call checkSizeConstraint() at all.

Thanks, that’s reported to Steinberg here:

1 Like