Please add AsyncQuitRetrier class to JUCE


#1

If you Quit while a FileChooser is open it causes a crash. I see that you get around this in ProJucer using an AsyncQuitRetrier class.

struct AsyncQuitRetrier  : private Timer
{
    AsyncQuitRetrier()   { startTimer (500); }

    void timerCallback() override
    {
        stopTimer();
        delete this;

        if (JUCEApplicationBase* app = JUCEApplicationBase::getInstance())
            app->systemRequestedQuit();
    }

    JUCE_DECLARE_NON_COPYABLE (AsyncQuitRetrier)
};

void ProjucerApplication::systemRequestedQuit()
{
    if (server != nullptr)
    {
        sendQuitMessageToIDE (server);
    }
    else if (ModalComponentManager::getInstance()->cancelAllModalComponents())
    {
        new AsyncQuitRetrier();
    }
    else
    {
        if (closeAllMainWindows())
            quit();
    }
}

Perhaps you can add this to the JUCE Demo as well.

Thanks,

Rail


runModalLoop
#2

… or better yet… add the AsyncQuitRetrier class to the JUCE code and in a ProJucer created GUI app in systemRequestedQuit() add the relevant code automatically:

void systemRequestedQuit() override
{
    // This is called when the app is being asked to quit: you can ignore this
    // request and let the app carry on running, or call quit() to allow the app to close.

    if (ModalComponentManager::getInstance()->cancelAllModalComponents())
        new AsyncQuitRetrier();
    else
        quit();
}

Rail


#3

Seems like the perfect place to use the new Timer:: callAfterDelay()

In JUCEApplication:

 #if JUCE_COMPILER_SUPPORTS_LAMBDAS

struct AsyncQuitRetrier
{
    AsyncQuitRetrier()
    {
        Timer::callAfterDelay (500, std::bind (&AsyncQuitRetrier::lambdaTimerCallback, this));
    }
    
    void lambdaTimerCallback()
    {
        if (JUCEApplicationBase* app = JUCEApplicationBase::getInstance())
            app->systemRequestedQuit();
    }
    
    JUCE_DECLARE_NON_COPYABLE (AsyncQuitRetrier)
};

#else

struct AsyncQuitRetrier  : private Timer
{
    AsyncQuitRetrier()   { startTimer (500); }

    void timerCallback() override
    {
        stopTimer();
        delete this;
        
        if (JUCEApplicationBase* app = JUCEApplicationBase::getInstance())
            app->systemRequestedQuit();
    }

    JUCE_DECLARE_NON_COPYABLE (AsyncQuitRetrier)
};

#endif

Rail


#4

TBH with the new Timer::callAfterDelay, there’s not really much point in us adding a class to the library, because it becomes trivial to write:

Timer::callAfterDelay (500, []()
{
    if (auto app = JUCEApplicationBase::getInstance()
        app->systemRequestedQuit(); 
});