[OSX] Resizing issue with addToDesktop() and attachToNativeWindow

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)
};

Sorry for bumping this issue up a bit.

Could someone from the JUCE team at least recommend a way to force a setBounds() on all components? Or any way to fire the event chain such that all component sizes are recalculated?

That would already be suffcient for my use case. My main problem is that setBounds() does not have any effect because the component size is unchanged although the NSView did not yet pick up the correct size. So calling setBounds() again would already solve the problem.

1 Like