Hi everyone!
I was experiencing an issue in JUCE recently, that was causing many repaint() calls to get discarded on Linux. I’m using JUCE 7.0.5, but I don’t think this is a new issue.
The problem is, if you repaint a large amount of Components on mouseDrag, almost all of those repaint requests get discarded, because it can’t keep up with the rate of MouseEvents. It seems like new repaint() calls are discarded if there is a repaint currently in progress, meaning that if you call repaint() quick enough, it will not repaint anything at all.
Here is a demo of this problem:

And here’s what it looks like after reducing the amount MouseEvents:

This was tested on Fedora/GNOME inside a VM on my Macbook Pro, but I’ve had other Linux users of my app confirm this issue. The same bug does not occur on macOS and Windows.
Not sure here, but there might be some more variables that could influence the rate of MouseEvents, like perhaps the refresh rate of your mouse? That might be something to keep in mind if anyone wants to try to reproduce this.
In case anyone’s wondering, here is the bit of code I’ve used to resolve this.
// Class that blocks events that are too close together, up to a certain rate
// We use this to reduce the rate at which MouseEvents come in, to prevent an overload of repaint() on Linux
struct RateReducer : public Timer
{
RateReducer(int rate) : timerHz(rate) {
}
bool tooFast() {
if(allowEvent) {
allowEvent = false;
startTimerHz(timerHz);
return false;
}
return true;
}
void timerCallback() override {
allowEvent = true;
}
void stop() {
stopTimer();
allowEvent = true;
}
private:
int timerHz;
bool allowEvent = true;
};
// Class that allows reducing mouseDrag rate on any generic JUCE Component
// A bit hacky but it works
template<typename T, int hz = 90>
class MouseRateReducedComponent : public T
{
public:
using T::T;
void mouseDrag(const MouseEvent& e) override
{
if(rateReducer.tooFast()) return;
T::mouseDrag(e);
}
void mouseUp(const MouseEvent& e) override
{
rateReducer.stop();
T::mouseUp(e);
}
private:
RateReducer rateReducer = RateReducer(hz);
};
But I think that this is a bug, and it would be nice to find a real solution.
