On juce 6.1.6, we have noticed a crash when using AlertWindow
with JUCE_MODAL_LOOPS_PERMITTED
inside a PopupMenu
.
The following PIP can be used to reproduce: Simply build and run and click on the button, then the menus.
/*******************************************************************************
The block below describes the properties of this PIP. A PIP is a short snippet
of code that can be read by the Projucer and used to generate a JUCE project.
BEGIN_JUCE_PIP_METADATA
name: PopupMenuCrash
dependencies: juce_core, juce_data_structures, juce_events, juce_graphics, juce_gui_basics
exporters: XCODE_MAC
defines: JUCE_MODAL_LOOPS_PERMITTED=1
type: Component
mainClass: MyComponent
END_JUCE_PIP_METADATA
*******************************************************************************/
#pragma once
#include <memory>
//==============================================================================
class MenuCallback : public juce::PopupMenu::CustomCallback
{
public:
MenuCallback() = default;
bool menuItemTriggered() override
{
std::unique_ptr<AlertWindow> alert { std::make_unique<AlertWindow>("Alert", "This will crash on the second or third try", MessageBoxIconType::WarningIcon, nullptr) };
alert->addButton("Crash", 0);
alert->runModalLoop();
return false;
}
};
class MyComponent : public juce::Component
{
public:
//==============================================================================
MyComponent()
{
button = std::make_unique<TextButton>("Crash");
button->onClick = [this](){crash();};
addAndMakeVisible(button.get());
setSize (600, 400);
}
~MyComponent() override
{
}
//==============================================================================
void paint (juce::Graphics& g) override
{
// (Our component is opaque, so we must completely fill the background with a solid colour)
g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));
g.setFont (juce::Font (16.0f));
g.setColour (juce::Colours::white);
g.drawText ("Hello World!", getLocalBounds(), juce::Justification::centred, true);
}
void crash()
{
PopupMenu submenu;
PopupMenu::Item item;
item.text = "Crash";
item.itemID = 1;
item.customCallback = new MenuCallback();
submenu.addItem(item);
juce::Rectangle<int> pos(button->getBounds());
PopupMenu menu;
menu.addSubMenu("Crash >", submenu);
menu.showMenuAsync(PopupMenu::Options().withTargetComponent(this).withTargetScreenArea(localAreaToGlobal(pos)).withMinimumWidth(100));
}
void resized() override
{
button->setBounds(getLocalBounds().withSizeKeepingCentre(100, 25));
// This is called when the MyComponent is resized.
// If you add any child components, this is where you should
// update their positions.
}
private:
//==============================================================================
// Your private member variables go here...
std::unique_ptr<TextButton> button;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MyComponent)
};