Mouse-Exit Bug

Hi all,

I’ve spotted a mouse-event related bug when using modal windows, where the mouseExit() method isn’t being called on a Component when dismissing a modal window (e.g. PopupMenu).

The code below shows the problem of a Button::Listener::buttonClicked callback being used to trigger a PopupMenu, and whenever that menu window is dismissed by clicking outside of the trigger Button’s bounds (or selecting a menu item) the mouseExit call to the trigger Button is lost. Also, moving the mouse back in to the Button will trigger a second mouseEnter call, still without a mouseExit.

I’m pretty sure this behaviour is a side-effect of the fix discussed in this topic: Missing mouseEnter callback, but I can’t see a way of getting the mouseExit call back to the original Component from where that fix is.

class MainContentComponent   : public Component
                             , private Button::Listener
{
public:
    MainContentComponent()
    {
        addAndMakeVisible (button);
        button.addListener (this);

        setSize (600, 400);
    }

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

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

private:
    void MainContentComponent::buttonClicked (Button* buttonClicked) override
    {
        PopupMenu menu;
        menu.addItem (1, "My Menu Item");

        PopupMenu::Options options;

        int result = menu.showAt (buttonClicked);
        ignoreUnused (result);
    }

    class EnterExitButton : public TextButton
    {
    public:
        EnterExitButton()
        { }

    protected:
        void mouseEnter (const MouseEvent&) override
        {
            DBG ("Entering " + getName());
        }
    
        void mouseExit (const MouseEvent&) override
        {
            DBG ("Exiting " + getName());
        }
    };

    EnterExitButton button;
};

For starters here, you should try not using a modal loop - as I’ve said endlessly on the forums, they’re dangerous, troublesome, and will eventually be deprecated. Try showing your menu asynchronously and this might go away.

The only reason for showing the menu synchronously in that example was so I didn’t have to bother with the callback pointer, but you can also use this call to show the menu asynchronously and it shows exactly the same problem:

menu.showMenuAsync(PopupMenu::Options().withParentComponent(this), nullptr);

Any suggestions for working around this bug? One easy solution would be to call MouseExit on the original component that triggered the PopupMenu in the popup callback, but AFAIK, there’s no way to create a faux MouseEvent to call MouseExit with.

That is exactly what we ended up doing; you can use Desktop::getInstance().getMainMouseSource() to get a MouseInputSource to use to create a fake MouseEvent, and just pass that on to whatever Component was used to trigger the menu.

Cool, thanks for the confirmation that that’s not a crazy workaround.

Has there been any progress on this issue? I see the same behavior reported originally by LukeM1. Whether or not the menu is shown async. It’s easy enough to find a work-around, but still…

1 Like

Same problem here.
Currently using JUCE 6.0.7.