Best way to pop down modal dialogs during quit?

This should be easy, I must be overcomplexifying it, I searched the forums (fora), a hint will do.

If I press command-Q when a modal dialog is up, my application starts to quit but then fails because the modal dialog is still up. I’ve tried things like calling window->exitModalState(0) for any window that’s up in my JUCEApplication::shutdown, but no luck, and I’ve tried various other tricks.

I’d be very happy just popping that dialog down or almost as happy if cmd-q were disabled when a modal dialog was up!

Hmm…does the Juce demo quit while command-Q is pressed while a modal is up?

Unfortunately, the Juce demo (always my go-to example) doesn’t seem to have any modal dialogs…

Sure it does, there’s the one that pops the system dialog to perform a file open…its in the synth / sampler section I think?

Ah okay I found it, there is a modal dialog in the Code Editor “…” to select the file.

With modal juce dialogs, it should be pretty straightforward to find and dismiss them using ModalComponentManager, and then re-trigger the quit message with JUCEApplication::quit(). But if you’re showing a native file chooser, I’m not sure how you’d get rid of it…

Good catch! I’d even looked at that page…

Unfortunately, I seem to get the same results from the demo that I do from my code - which I have clarified a little.

  1. If a system dialog is up, and I quit, then in debug mode I have multiple asserts go off, because I’m clearly leaking memory - but then the program exits fine.
  2. If it’s another dialog, specifically the Keyboard Command Mapping dialog, then I get an actual crash. I don’t know if this is true for non-open-file dialogs in the Demo, because there aren’t any.

Unfortunately, there isn’t a great example of bringing up a modal, non-system dialog in the Demo or the other Juce examples…

Try adding a line that puts up a simple OK button juce::AlertWindow

With modal juce dialogs, it should be pretty straightforward to find and dismiss them using ModalComponentManager, and then re-trigger the quit message with JUCEApplication::quit().

Oh, I didn’t know about ModalComponentManager, I sort of rolled my own, but “dismissing” the modal dialog (that is, with Component::exitModalState(0) ?) doesn’t seem to bypass the issue, and I believe i know why (see below).

I’m going to redo this with ModalComponentManager - I love deleting my own code :smiley: but I imagine the results will be quite the same - I’ll still end up in my quit phase with the pointer to a component I know to be modal but be unable to delete it.

Now, the stack is very interesting, and I’m attaching two of them to this post. What it shows is that the call to quit is being done from inside Component::runModalLoop - so no wonder the window isn’t popped down or deleted yet, I’m still in the modal loop that’s reading the buttons!

If you try the same thing with the JUCE demo and a system dialog, you get the same result I do with system dialogs - here we’re hitting a jassert, which will not fire in a release build, but we’re still getting an incorrect result - memory leak checking should be the very last thing to go off, quit should always go off from the top level and all dialogs should be unwound before it happepns.

The Demo doesn’t actually pop up a non-modal dialog but I’d bet 3:2 that it would have the same problem I do if it did.

I think you’re hinting at this, Jules, but clearly there’s some way to suspend the quit process and return control to the modal dialog loop and then have that propagate the quit process back to the top? That’s basically the only solution to this issue.

The logical solution to this whole issue would be to have the Demo put up, say, a juce::KeyMappingEditorComponent in a dialog. This would show off Juce’s marvy KeyMappingEditorComponent and also demonstrate how to correctly create - and destroy during shutdown :slight_smile: - a non-system-dialog modal component.

I’m going to be updating to the tip anyway today so will probably see how quickly I can just toss that somewhere into the Demo and put up a patch to see what would happen - and then if I’m doing something wrong, we can correct it and put the right result into the Demo.

Tracebacks here.

I did in fact add the KeyCommandMapEditor to the Juce Demo, and you can see the git diff here.

Key code is here:[code]ApplicationCommandManager* commandManager = &(mainWindow->commandManager);
KeyMappingEditorComponent comp(*commandManager->getKeyMappings(), true);
comp.setBounds(0, 0, 500, 1000);

juce::DialogWindow::showModalDialog(“Select keyboard mappings”,
&comp, this, Colours::white,
true, true, true);

This exhibits the same behaviour as my application - if you bring this up and then call quit while it’s up, you get a series of jasserts in the debugger.

Actually, I’m believing that my app wouldn’t even actually crash, just jassert, but I still don’t like to be able to jassert (as I like to give out debug releases at times…)

@TomSwirly did you ever solve this?
I’m in the same situation with an AlertWindow in runModalLoop() which causes memory leaks if the user quits.

I’ve tried using ModalComponentManager to kill off the modal windows but it doesn’t make any difference.

Sorry for resurrecting an old thread but this one is on top of search results for the issue.

I resolved the issue with the following code, in my JUCEApplication subclass:

    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.
        auto mgr = ModalComponentManager::getInstance();
        if( mgr->cancelAllModalComponents() )
            Timer::callAfterDelay(100, [this] { quit(); });

The issue is that even if you dismiss the modal window programmatically, the program will still be stuck inside runModalLoop() while all the leaks etc are checked, so calling quit() directly after dismissing doesn’t help. The Timer resolves the issue. The delay of 100 ms is arbitrary. Any number is probably fine.

1 Like