mouseExit callback not always triggered?

An issue that has been haunting us for a while is that when you move the mouse fast over a component, sometimes the mouseExit callback is not triggered. We’re using the callback to change the state of the component, so the missing mouseExit leaves the component in an unintended state. Its also intermittent and seems to happen more often when we’re painting relatively heavy unrelated other components on a timer.

I’ve noticed this on OS X here and there if you really move the cursor really quickly over a component. It’s like the OS is figuring out the cursor velocity and skipping the mouse event calls until the velocity drops past a certain point. But who knows… I’m curious what the solution ends up being or if this is just a flaw of every OS out there that makes use of a mouse cursor.

I thought Jules had said previously that you are guaranteed a mouseExit for every mouseEnter…

1 Like

Yes, the MouseInputSource class will enforce the fact that a mouse can’t enter a new component until the last one got a mouseExit. Maybe what’s happening here is that the mouse enters some other window so quickly that the OS never sends a move or exit event, so the MouseInputSource is left thinking that the mouse was still inside the last one. I think that once it re-enters somewhere else, the old one would finally get its exit callback.

What happens is that you always get a mouse enter, regardless of cursor speed, but sometimes not the corresponding mouse exit. A hack that would work is to trigger a clean up of the child component that is missing its mouseExit when the mouse moves into its parent component and and parent receives the dependable mouseEnter.

I am very weary with that whole complex, when considering, that there might be not only one MouseInputSource.
Just consider trackpad+mouse or multi-touch displays…
No idea, what would be a clean solution…

I don’t think it’s OS dependent, because we can observe the same behavior with Windows 10 here. We implemented a listener for a ListBox, that highlights the currently hovered line. If you move the mouse fast enough to an adjacent ListBox, the currently highlighted line stays in it’s hovered state until I move the mouse back.

It would be really weird if both OSes suffered from the exact same bug. It’s a JUCE thing. Looking at the relevant code, it shouldn’t happen, but it does.

Like I said in my earlier reply, that’s exactly how it already works!

All events go through a MouseInputSource, and it would only fail to clean up the state of a previously “mouse-overed” component if that old component had been deleted or hidden (or its mouselistener was removed).

Everything has to go through this function:

I don’t think we’d be able to help with this unless you can share some code that reproduces it. And are you sure you’re not deleting or hiding one of the components that’s involved?

I’ll see if can create a tiny repro project in the next few days. We don’t do any hiding or removing of any components while observing said behavior.

1 Like