popupMenu and setDefaultLookAndFeel crash

Is it wrong to setDefaultLookAndFeel with a SharedResourcePointer<LookAndFeel> ?


It seems to lead to some crash under certain circumstances.
Here is how to reproduce with a basic plugin :


- create a brand new plugin with the introjucer
- add 2 private members :

    SharedResourcePointer<LookAndFeel_V3> lookAndFeel_V3;
    ComboBox comboBox;

and then :


TestPlugAudioProcessorEditor::TestPlugAudioProcessorEditor (TestPlugAudioProcessor& p)
    : AudioProcessorEditor (&p), processor (p)
{
    LookAndFeel::setDefaultLookAndFeel (lookAndFeel_V3);
    addAndMakeVisible (comboBox);
    
    setSize (400, 300);
}

void TestPlugAudioProcessorEditor::resized()
{
    comboBox.setBounds (30, 30, 200, 40);
}


- create a new reaper project
- create a new track
- insert the plugin
- click on the comboBox to open its menu
- open the track FX window by clicking on the green "FX" button
- double click on the plugin name that is on the right of that window (see attached pic)
-> crash

 

 

Well, hard to tell exactly what you're doing, but it's probably unsafe because the SharedResourcePointer will delete its object when all the SharedResourcePointers go out of scope, and this would leave the dangling pointer selected as the global L+F..

So what is the recommanded way to deal with defaultLookAndFeel and plugins?

Something like that ?

class MyLookAndFeel : public LookAndFeel_V3, public DeletedAtShutdown
{
public:
    MyLookAndFeel() {}

    ~MyLookAndFeel()
    {
        clearSingletonInstance();
    }

    juce_DeclareSingleton (MyLookAndFeel, false)
};

 

juce_ImplementSingleton (MyLookAndFeel)

TestPlugAudioProcessorEditor::TestPlugAudioProcessorEditor (TestPlugAudioProcessor& p)
    : AudioProcessorEditor (&p), processor (p)
{
    LookAndFeel::setDefaultLookAndFeel (myLookAndFeel.getInstance());
    addAndMakeVisible (comboBox);

    setSize (400, 300);
}

A SharedResourcePointer is OK as long as you make sure that when it is deleted, you stop it being the look+feel.

This is C++ so you should use RAII to do this cleanly, e.g.

struct MyLookAndFeel
{
    MyLookAndFeel()  { LookAndFeel::setDefaultLookAndFeel (&lf); }
    ~MyLookAndFeel() { LookAndFeel::setDefaultLookAndFeel (nullptr); }

    LookAndFeel_V3 lf;
};

then use SharedResourcePointer<MyLookAndFeel>

 

of course! :) thanks Jules!