Lots of spurious mouseMove triggered by loading SVGs

It sounds strange, but it happens because:

Loading SVGs causes every elementary “part” of the resulting image to be represented by a Drawable.

Drawables are Components, and setVisible() is called on every one of them according to its desired visibility in the final image.

Every setVisible() call invokes sendFakeMouseMove(). I presume this is to trigger proper mouseEnter/Exit events for Components that appear/disappear right beneath the mouse cursor.

The problem is, that such fake mouse moves are triggered unconditionally, regardless of whether the Component even has a chance of being the one on the screen under the mouse.

checking

if (isOnDesktop() 
    || (parentComponent != nullptr && parentComponent->isShowing()))

before

sendFakeMouseMove()

would get rid of all the spurious calls while still retaining the meaningful ones.

2 Likes

Interesting find!
Could that speed up loading SVGs?

That might cause some issues when using addAndMakeVisible() as that calls setVisible() before adding the child, so the (parentComponent != nullptr && parentComponent->isShowing()) check would always be false. A better solution might be to not send the mouse move if the component passes through all mouse events (as Drawable does). We’ve added this to develop:

Thanks for the fast response, good idea about moving the check inside sendFakeMouseMove() so that spurious mouseMoves can also be prevented when that’s called from other places.

Unfortunately, while your implementation works for the case of SVGs, I’ve realized it wouldn’t work for other cases, for example Components that blink (e.g. the TextEditor caret or an indicator of MIDI activity).

To deal with those, what do you think about implementing my original check && watch if the mouse is within the component screen bounds?
After all, if the mouse is not within bounds, there’s no chance it could trigger mouse events related to the component (dis)appearance.

To solve the addAndMakeVisible() issue, another such sendFakeMouseMove() could be added to addChildComponent(), the same way there’s already one in removeChildComponent() and reorderChildInternal()
(or perhaps, all those three could be replaced with a single invocation in internalChildrenChanged())

It will if they are calling setInterceptsMouseClicks (false, false), as the CaretComponent does.

I’m not sure about adding those other checks as this feels like quite a fragile area that may have knock-on effects in other places. We’d need to do a lot more testing to be sure it won’t break anything else.

I get your point and feel your pain about that.

Unfortunately, it’s easy to forget to setInterceptsMouseClicks (false, false) diligently. More often than not, Components are left with their default (true) and only set to not intercept when that turns out to be the solution to a problem.

And once a whole UI is laid out that way, debugging mouse events suddenly becomes a nightmare because streams of fake mouse events come from all over the place (not to think about how many times the mouseListeners are being called unnecessarly). And a tedious phase of “hunt the fake mouse source” starts before the actual debugging can take place.

Can you think about a good way to enforce the good practice of setting to non-intercepting those components that don’t care about the mouse?
Or some clever jassert that triggers when “too many” mouse moves happen while the mouse hasn’t actually moved? Too many fake mouse moves → a source is probably emitting them at a steady pace while it shouldn’t

Perhaps there are a few more places in JUCE where we could be setting those flags - if you have run into any classes where you think we should be doing this then please let us know and we can add them if required. However I don’t think it’s something we’d want to enforce on users by checking the number of mouse moves as there could be edge cases where this is required and, again, it seems like quite a fragile bit of code.

Ah no I’ve been misunderstood about that: I didn’t mean JUCE should enforce that, I was just wondering if anything of that sort came to your mind, some JUCE-inspired trick, that I could put in my company projects to catch components that don’t do anything with mouse events and could therefore be set to non-intercepting (preventing them from sending those unnecessary fake moves).

No I don’t think there’s any particular trick to it other than being conscious of which components should and should not receive mouse events when constructing your UIs.

1 Like