ToggleButton not always trigger

JUCE 8.0.10 with Linux Ubuntu 20.0.4, happens with Reaper and Bitwig. I was able to reproduce it with the VST2 version of our plugin in Reaper. No problem on all other OS’s.

A user reported that the ToggleButtons do not trigger when the mouse is not moving. He needs the mouse a bit afterward to make the buttons trigger.
I was able to reproduce it with the touchpad in a Linux VM. It didn’t happen every time with the touchpad. Probably every 10-20th time.

It only happened with the VST2 plugin and our CLAP. It also looks our other plugins don’t have this issue, even though they use the same button and the same JUCE. I think this is timing related.
The buttons are assigned to their parameter with an attachment and they also do onStateChanged() to set flags. We don’t do any special things here.

Any anyone noticed similar problems on Linux? Any Ideas what the problem could be?

The following video illustrates the problem. The first click in the video does not trigger the button. Moving the mouse afterward triggers the button. The other clicks worked. The problem happens randomly.

Nothing special in the code. Here the construction:

    _eqBypassButton = std::make_unique<TalTextButton>("BYP");
    _eqBypassButton->onClick =  [this]
    {
        _graphicEq->setAlpha(_eqBypassButton->getToggleState() ? 0.5f : 1.0f);
    };
    _eqBypassButtonAt = std::make_unique<AudioProcessorValueTreeState::ButtonAttachment>(*p._params->treeState, p._params->paramBypass, *_eqBypassButton);
    addAndMakeVisible(_eqBypassButton.get());
    // set bounds in the resize method

The ToggleButton class only overwrites the paint method and forwards the mouseUp and mouseDown button events to the base class (kickButton is not enabled here):

class TalTextButton : public juce::ToggleButton
{
    juce::String _text;
    bool _isKickButton;

protected:
    const bool _abButton;

public:
    TalTextButton (juce::String text, bool isKickButton = false, bool abButton = false)
            : ToggleButton(text), _isKickButton(isKickButton), _abButton(abButton)
    {
        _text = text;
        setWantsKeyboardFocus (false);
        _isKickButton = isKickButton;
    }

    ~TalTextButton() override = default;

    void mouseUp (const juce::MouseEvent& event) override
    {
        if (_isKickButton)
        {
            this->setToggleState(false, juce::sendNotification);
        }
        else
        {
            ToggleButton::mouseUp(event);
        }

        repaint();
    }

    void mouseDown (const juce::MouseEvent& event) override
    {
        if (_isKickButton)
        {
            setToggleState(true, juce::sendNotification);
        }
        else
        {
            ToggleButton::mouseDown(event);
        }

        repaint();
    }

    void paintButton (juce::Graphics& g, bool, bool) override
    {
        // ...
    }
};

Perhaps you can attach the to debuger to see whether & when the plugin actually receives the mouse down? To me the button does not receive the first mouse down at all. But it does not explain why it only happens on VST2.

    void mouseDown (const juce::MouseEvent& event) override
    {
        std::cout << "mouse down" << std::endl;
        ...
    }

Thanks for the idea. Did some tests with the log.

What happens when the click fails:

  • Most of the time mouseUp and mouseDown are not triggered when click. In rarer cases, it also happens that only mouseUp is not triggered.
  • They trigger afterwards when the mouse moves. No mouse event gets lost.

To exclude different things I tried the following, but the problem persists:

  • Without ButtonAttachment
  • Without onClick action
  • Without timerCallback actions on the main component

I can also reproduce it with other plugins with JUCE 8.0.10. But not with all. I wasn’t able to reproduce this on simpler plugins with only a few knobs and buttons.

I wonder how mouse events can get stuck in this way. Any ideas?

Edit:
The problem can’t be in the ToggleButton itself. It has to be in the JUCE code that calls the Component mouse down / up functions. It looks like it stops processing the mouse event queue too early in some cases and does not process all events.

I found following comment in juce_XWindowSystem_linux.cpp. Only VST2 and CLAP (via JUCE Wrapper) are affected. So I think something probably goes wrong there:

For plugins, the host (generally) provides some kind of run loop mechanism instead.
- In VST2 plugins, the host should call effEditIdle at regular intervals, and plugins can
  dispatch all pending events inside this callback. The host doesn't know about any of the
  plugin's FDs, so it's possible there will be a bit of latency between an FD becoming ready,
  and its associated callback being called.

Maybe some unlucky timing between the host and the plug-in. This also explains the sometimes sluggish UI behaviour with the JUCE VST2 on Linux.