[OSX] Resizing issue with addToDesktop() and attachToNativeWindow

#1

Hi,

on OSX we encounter a strange resizing issue with a component attached to a native window. We use this method to host a plugin UI in another surrounding JUCE plugin UI. There is a AudioProcessorEditor component and a child component is attached to the top-level component using addToDesktop(0, getTopLevelComponent()->getWindowHandle()). Full code can be seen below.

When the top-level component is resized (using the +/- buttons), the attached component should follow but the attached component’s y-position is incorrect afterwards. This is due to the fact that JUCE internally needs to invert the coordinate system at juce_mac_NSViewComponentPeer.mm, NSViewComponentPeer::setBounds(), l.285. The transform relies on the dimensions of the superview but this has not yet been set at this point. Hence, the resulting coordinates refer to the old parent window size.

I tried to find a fix like inverting the order of resize callbacks that are triggered in JUCE but did not succeed. My second try was to manually force a complete resize of the window hierachy with the Resize button as a workaround. But the resizes bail out as the sizes in JUCE are the same.

So my question would be if you see a potential easy fix in JUCE or if there is a good workaround to make this work in my code? Or maybe I am wrong with my understanding how this should work?

Thanks,
Sebastian

Example Code

class NativeComponent : public Component
{
public:
    
    void paint (Graphics& g)
    {
        g.fillAll (Colours::yellow);
        
        g.setColour (Colours::black);
        g.setFont (15.0f);
        g.drawFittedText ("Native window!", getLocalBounds(), Justification::centred, 1);
    }
    
};


class CompPeerTestAudioProcessorEditor  : public AudioProcessorEditor, public Button::Listener
{
public:
    CompPeerTestAudioProcessorEditor (CompPeerTestAudioProcessor& p) : AudioProcessorEditor (&p), processor (p)
    {
        setSize (400, 300);
        
        addAndMakeVisible(btnPlus);
        addAndMakeVisible(btnMinus);
        addAndMakeVisible(btnResize);
        
        btnPlus.setButtonText("+");
        btnMinus.setButtonText("-");
        btnResize.setButtonText("Trigger Resize");
        
        btnPlus.addListener(this);
        btnMinus.addListener(this);
        btnResize.addListener(this);
        
        addAndMakeVisible(natcomp);
    }

    ~CompPeerTestAudioProcessorEditor() {}

    //==============================================================================
    void paint (Graphics& g) override
    {
        g.fillAll (Colours::green);
        
        g.setColour (Colours::white);
        g.setFont (15.0f);
        g.drawFittedText ("Hello World!", getLocalBounds(), Justification::centred, 1);
        g.drawLine(0, 100, getWidth(), 100);
        g.drawLine(0, getHeight() - 100, getWidth(), getHeight() - 100);
    }
    
    void resized() override
    {
        btnPlus.setBounds(0, 0, 20, 20);
        btnMinus.setBounds(25, 0, 20, 20);
        btnResize.setBounds(50, 0, 200, 20);
        
        natcomp.setBounds(50, 100, getWidth() - 100, getHeight() - 200);
    }

    void parentHierarchyChanged() override
    {
        natcomp.removeFromDesktop();
        natcomp.addToDesktop(0, getTopLevelComponent()->getWindowHandle());
    }

private:
    
    void buttonClicked(Button* button) override
    {
        if (button == &btnPlus)
        {
            setSize(getWidth(), getHeight() + 200);
        }
        else if (button == &btnMinus)
        {
            setSize(getWidth(), getHeight() - 200);
        }
        else if (button == &btnResize)
        {
            // Force complete resize event chain by changing the size
            setSize(getWidth(), getHeight() - 1);
            setSize(getWidth(), getHeight() + 1);
        }
    }
    
    CompPeerTestAudioProcessor& processor;

    TextButton btnPlus, btnMinus, btnResize;
    NativeComponent natcomp;
    
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CompPeerTestAudioProcessorEditor)
};