[Bug] Minimize to dock on MacOS causes modal component to lose modality

If you create and install a child component over your mainComponent, and set it to be modal (so as to simulate a modal dialog for example), if you then minimize that state to the dock and restore it, the modal component is no longer modal.

Test Project:

ModalComponent.zip (11.4 KB)

Steps to reproduce:

  1. In the MainWindow, click the “Modal Component” button. This installs the child component and calls enterModalState(). The modal component comes up resembling a dialog. Test modality by trying to activate any buttons in the background mainComponent. Cannot do so - it is modal.

  2. Click on the minimize button in the title bar to minimize it to the dock.

  3. Restore it from the dock. Test modality - it is now gone and you can freely click buttons in the background mainComponent.

What happens is:
When the MainWindow is minimized, in ModalComponentManager::ModalItem, the ComponentMovementWatcher that is attached to each modal component receives a componentVisibilityChanged:

    void componentVisibilityChanged() override
    {
        if (! component->isShowing())
            cancel();
    }

This then causes the active flag for that component to be set to false, and an asyncUpdate is triggered:

    void cancel()
    {
        if (isActive)
        {
            isActive = false;

            if (auto* mcm = ModalComponentManager::getInstanceWithoutCreating())
                mcm->triggerAsyncUpdate();
        }
    }

handleAsyncUpdate then removes the component from the stack of modal components. Then when you unminimize, the component is no longer modal:

void ModalComponentManager::handleAsyncUpdate()
{
    for (int i = stack.size(); --i >= 0;)
    {
        auto* item = stack.getUnchecked (i);

        if (! item->isActive)
        {
            std::unique_ptr<ModalItem> deleter (stack.removeAndReturn (i));
            Component::SafePointer<Component> compToDelete (item->autoDelete ? item->component : nullptr);

            for (int j = item->callbacks.size(); --j >= 0;)
                item->callbacks.getUnchecked (j)->modalStateFinished (item->returnValue);

            compToDelete.deleteAndZero();
        }
    }
}

Tested with JUCE 7.0.5 and Mojave. I did not test on Windows but from the code, I expect similar behavior.

(Bump)

This seems to be an issue ONLY on MacOS, and only for a GUI app. I have now tested this project on Windows, and also as a Mac and Windows VST3 plugin.

On Windows (GUI App) - when the component is modal, you cannot click on the minimize or close buttons in the titlebar. They are disabled.

But on MacOS, you can click the minimize and close buttons, with a modal component. Why is this?

There’s no good way to control the disabled state of the minimize button on the Mac with a native titlebar, either. So you can’t prevent it from being used.

In the AudioPluginHost, in both Mac and Windows, clicking the minimize button on the PluginEditor with the modal component up is allowed, but results in no visibility change coming to the modal component, so the problem does not exist. When you unminimize, the component is still modal.

It appears the Mac version needs to be smarter about whether the top desktop window is being minimized or not, and provide some sort of exception for this. Something like this, which works, but I’m not sure how robust it would be…

struct ModalComponentManager::ModalItem  : public ComponentMovementWatcher
{
    [snip...]

    void componentVisibilityChanged() override
    {
        if (! component->isShowing())
        {
            #if JUCE_MAC
            if (component->getTopLevelComponent()->isOnDesktop())
            {
                if (component->getPeer()->isMinimised())
                {
                    DBG("**    ModalItem::componentVisibilityChanged: " + component->getName() + " - SKIP Deletion");
                    return;
                }
            }
            #endif //JUCE_MAC

            cancel();
        }
    }

I also just tested with 7.0.7 develop latest, and on a newer MacOS (Big Sur at least), and the issue is still there.

@reuk - this is precisely what I am doing - using a component overlay on my MainEditor, along with EnterModalState(). While this is working fine, and minimizing the window causes no issues in a plugin on either Windows or Mac, the same is not true for my GUI App version of the same thing. On MacOS, minimizing the window causes a loss of modality as explained above.