BR: Drop shadow crash when creating dialog box

I see there was a fix a while ago to fix a potential crash in DropShadower

I wasn’t seeing a crash before, but now I am every time. When my AboutBox gets created and added to the desktop, the TopLevelModalDismissBroadcaster immediately deletes my AboutBox, it gets deleted while in the componentVisibilityChanged and it all blows up.

>	Waveform 11 (64-bit).exe!juce::DropShadower::~DropShadower() Line 95	C++
 	Waveform 11 (64-bit).exe!juce::DropShadower::`scalar deleting destructor'(unsigned int)	C++
 	Waveform 11 (64-bit).exe!std::default_delete<juce::DropShadower>::operator()(juce::DropShadower * _Ptr) Line 2084	C++
 	Waveform 11 (64-bit).exe!std::unique_ptr<juce::DropShadower,std::default_delete<juce::DropShadower> >::reset(juce::DropShadower * _Ptr) Line 2335	C++
 	Waveform 11 (64-bit).exe!std::unique_ptr<juce::DropShadower,std::default_delete<juce::DropShadower> >::operator=(void * __formal) Line 2205	C++
 	Waveform 11 (64-bit).exe!juce::HWNDComponentPeer::~HWNDComponentPeer() Line 1400	C++
 	Waveform 11 (64-bit).exe!juce::HWNDComponentPeer::`scalar deleting destructor'(unsigned int)	C++
 	Waveform 11 (64-bit).exe!juce::Component::removeFromDesktop() Line 725	C++
 	Waveform 11 (64-bit).exe!juce::Component::~Component() Line 496	C++
 	Waveform 11 (64-bit).exe!AboutBox::~AboutBox()	C++
 	Waveform 11 (64-bit).exe!AboutBox::`scalar deleting destructor'(unsigned int)	C++
 	Waveform 11 (64-bit).exe!AboutBox::inputAttemptWhenModal() Line 160	C++
 	Waveform 11 (64-bit).exe!juce::HWNDComponentPeer::sendInputAttemptWhenModalMessage() Line 3925	C++
 	Waveform 11 (64-bit).exe!juce::HWNDComponentPeer::windowShouldDismissModals(HWND__ * originator) Line 4165	C++
 	Waveform 11 (64-bit).exe!juce::HWNDComponentPeer::TopLevelModalDismissBroadcaster::processMessage(int nCode, const tagCWPSTRUCT * info) Line 4218	C++
 	Waveform 11 (64-bit).exe!juce::HWNDComponentPeer::TopLevelModalDismissBroadcaster::callWndProc(int nCode, unsigned __int64 wParam, __int64 lParam) Line 4223	C++
 	user32.dll!00007ffec372e022()	Unknown
 	user32.dll!00007ffec3733d62()	Unknown
 	ntdll.dll!00007ffec53f0b54()	Unknown
 	win32u.dll!00007ffec2c114c4()	Unknown
 	Waveform 11 (64-bit).exe!juce::setWindowPos(HWND__ * hwnd, juce::Rectangle<int> bounds, unsigned int flags, bool adjustTopLeft) Line 692	C++
 	Waveform 11 (64-bit).exe!juce::HWNDComponentPeer::setBounds(const juce::Rectangle<int> & bounds, bool isNowFullScreen) Line 1495	C++
 	Waveform 11 (64-bit).exe!juce::ComponentPeer::updateBounds() Line 75	C++
 	Waveform 11 (64-bit).exe!juce::Component::addToDesktop(int styleWanted, void * nativeWindowToAttachTo) Line 679	C++
 	Waveform 11 (64-bit).exe!juce::DropShadower::ShadowWindow::ShadowWindow(juce::Component * comp, const juce::DropShadow & ds) Line 41	C++
 	Waveform 11 (64-bit).exe!juce::DropShadower::updateShadows() Line 192	C++
 	Waveform 11 (64-bit).exe!juce::DropShadower::componentVisibilityChanged(juce::Component & c) Line 171	C++
 	Waveform 11 (64-bit).exe!juce::Component::sendVisibilityChangeMessage::__l4::<lambda>(juce::ComponentListener & l) Line 583	C++
 	Waveform 11 (64-bit).exe!juce::ListenerList<juce::ComponentListener,juce::Array<juce::ComponentListener *,juce::DummyCriticalSection,0> >::callChecked<void <lambda>(juce::ComponentListener &),juce::Component::BailOutChecker>(const juce::Component::BailOutChecker & bailOutChecker, juce::Component::sendVisibilityChangeMessage::__l4::void <lambda>(juce::ComponentListener &) && callback) Line 153	C++
 	Waveform 11 (64-bit).exe!juce::Component::sendVisibilityChangeMessage() Line 583	C++
 	Waveform 11 (64-bit).exe!juce::Component::setVisible(bool shouldBeVisible) Line 563	C++
 	Waveform 11 (64-bit).exe!juce::Component::enterModalState(bool shouldTakeKeyboardFocus, juce::ModalComponentManager::Callback * callback, bool deleteWhenDismissed) Line 1696	C++
 	Waveform 11 (64-bit).exe!juce::Component::runModalLoop() Line 1675	C++

I think the issue is this commit:

It’s creating a lot of issues other than what it’s supposed to do. It’s causing my PopupWindows to disappear when menus open.

Thanks for reporting the issue. Based on the stack trace you provided, I can reproduce the issue shown in the stack trace and have a potential solution.

Do any of the examples in the DemoRunner exhibit the incorrect behaviour? The scenario isn’t particularly clear to me. If menus are opening, presumably some user interaction is causing the menus to open, and it is reasonable to call inputAttemptWhenModal on any modal components as a result of this interaction. Am I missing some subtlety?

Here is what the main menu looks like in Waveform: Screen Recording 2021 05 14 at 8 36 09 AM - YouTube

I have a CallOutBox with a bunch of buttons in it. When you mouse over the buttons, the appropriate menu is shown. After your change, when the menu opens, it closes the CallOutBox. I think it’s incorrect to call inputAttemptWhenModal because there haven’t been any mouse clicks made.

I see, thanks. I’ll try to construct a similar test-case.

I’ve written this test program, which hopefully is similar enough to your program that it’ll find the same sort of bugs:

struct HoverMenu : public juce::Component,
                   private juce::Timer
{
    HoverMenu()
    {
        startTimerHz (30);
    }

    void paint (juce::Graphics& g) override
    {
        g.setColour (juce::Colours::cyan);
        g.drawRect (getLocalBounds(), 2);
    }

    void timerCallback() override
    {
        const auto wasMouseOver = std::exchange (isMouseOver, isMouseOverOrDragging (true));

        if (! wasMouseOver && isMouseOver)
        {
            juce::PopupMenu::dismissAllActiveMenus();
            juce::PopupMenu menu;
            menu.addItem ("hello", nullptr);
            menu.addItem ("world", nullptr);
            menu.showMenuAsync (juce::PopupMenu::Options{}.withTargetComponent (this));
        }
    }

    bool isMouseOver = false;
};

struct MenuHolder : public juce::Component
{
    MenuHolder()
    {
        for (auto& menu : menus)
            addAndMakeVisible (menu);

        setSize (200, 200);
    }

    void resized() override
    {
        juce::FlexBox fb;
        fb.flexDirection = juce::FlexBox::Direction::column;

        for (auto& menu : menus)
            fb.items.add (juce::FlexItem { menu }.withFlex (1.0f).withMargin ({ 5.0f }));

        fb.performLayout (getLocalBounds());
    }

    std::array<HoverMenu, 5> menus;
};

struct AboutWindow : public juce::Component
{
    AboutWindow()
    {
        setSize (300, 300);
        setOpaque (true);
        addAndMakeVisible (box);
        box.addItemList ({ "hello", "world" }, 1);
    }

    void paint (juce::Graphics& g) override { g.fillAll (juce::Colours::cyan); }
    void inputAttemptWhenModal() override { delete this; }
    void resized() override { box.setBounds (getLocalBounds().withSizeKeepingCentre (80, 30)); }

    juce::ComboBox box;
};

class MainComponent   : public juce::Component,
                        private juce::Timer
{
public:
    MainComponent()
    {
        setSize (600, 400);
        addAndMakeVisible (button);
        button.onClick = [this]
        {
            juce::CallOutBox::launchAsynchronously (std::make_unique<MenuHolder>(),
                                                    button.getScreenBounds(),
                                                    nullptr);
        };

        startTimer (1000);
    }

    void paint (juce::Graphics& g) override
    {
        g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));
    }

    void timerCallback() override
    {
        stopTimer();

        auto* window = new AboutWindow();
        window->addToDesktop (juce::ComponentPeer::windowHasDropShadow);
        window->runModalLoop();
    }

    void resized() override
    {
        button.setBounds (getLocalBounds().withSizeKeepingCentre (80, 25));
    }

    juce::TextButton button { "open", "open" };
};

With my bug fixes applied, this program behaves as expected, so I’ll go ahead and push those changes. If the fix doesn’t work for your use-case, I’d appreciate if you could modify the snippet above to demonstrate the problem.

This patch should resolve the issue:

1 Like

Ok, seems to be working now. Another issue this caused was menus closed themselves when they scrolled. So if you had a menu too big for the screen, when you moused down to try scroll all the items into view, the menu disappeared. Also seems to be fixed now.