Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: MacOS addToDesktop w/ nativeWindowToAttachTo handles mouseMove incorrectly #1442

Closed
1 task done
emezeske opened this issue Oct 10, 2024 · 4 comments
Closed
1 task done

Comments

@emezeske
Copy link

Detailed steps on how to reproduce the bug

This sample code reproduces the problem. On MacOS, create a button as a child NSView of the current component's window, make sure it's visible etc, and then mouse over it. What you'll see is that it may temporarily flash to the highlighted isOver state, it will immediately revert to not being highlighted, as if the mouse exited it (even though it didn't).

 juce::TextButton button{"Mouse over me"};

 button.setOpaque(true);
 button.setVisible(true);
 button.addToDesktop(0, getWindowHandle());
 button.toFront(false);
 button.setBounds(100, 100, 50, 50);

I have debugged this fairly extensively, and I can explain the problem, and I have a possible solution but it needs to be vetted by someone who understands this stuff more than I do.

The problem is in:

lib/JUCE/modules/juce_gui_basics/native/juce_NSViewComponentPeer_mac.mm

What's happening is that both the parent and the child NSView that JUCE creates have NSTrackingAreas installed. These areas are firing mouse events for both the parent and child windows when the mouse is over the child window (despite the NSTrackingInVisibleRect option being set -- it does not prevent this).

Now for methods like redirectMouseEnter() and redirectMouseExit(), this is handled properly by checking that the NSEvent's tracking area is actually the one installed for the current component's NSView.

But for the redirectMouseMove() method, that's not possible as [ev trackingArea] is not defined for this type of event. So what happens is the isWindowAtPoint() method returns true for both the parent and child windows, and they BOTH call sendMouseEvent(), leading to the current component changing repeatedly as the mouse moves. When the current component changes, JUCE calls mouseExit() for the previous component. It so happens that redirectMouseMove() is called in the order of child, then parent, so the button gets exited over and over as JUCE sees the mouseMove in the parent.

My proposed solution is to check if the top-level view at the mouse coordinates is, in fact, the view associated with the NSViewComponentPeer object on which redirectMouseMove() is called. So instead of:

        if (isWindowAtPoint ([ev window], screenPos)) {
            sendMouseEvent (ev);
        } else
            // moved into another window which overlaps this one, so trigger an exit
            handleMouseEvent (...)

It would be:

        if (isWindowAtPoint ([ev window], screenPos)) {
            if ([[[ev window] contentView] hitTest: windowPos] == view) {
              sendMouseEvent (ev);
            }
        } else
            // moved into another window which overlaps this one, so trigger an exit
            handleMouseEvent (...)

This solution does indeed fix things for my test case. But perhaps it causes issues I'm not aware of, or is not general enough, I'm not sure (which is why I didn't submit a pull request).

What is the expected behaviour?

Mousing over the TextButton in the example above should cause it to be highlighted in the isOver state until the mouse is moved out of the bounds of the button.

Operating systems

macOS

What versions of the operating systems?

Sonoma

Architectures

ARM, 64-bit

Stacktrace

No response

Plug-in formats (if applicable)

No response

Plug-in host applications (DAWs) (if applicable)

No response

Testing on the develop branch

The bug is present on the develop branch

Code of Conduct

  • I agree to follow the Code of Conduct
@emezeske
Copy link
Author

Actually it seems so far like my proposed fix works. I can't find anything that it breaks, although it's possible that I'm not being creative enough... ? I'm going to submit a pull request.

#1443

@emezeske
Copy link
Author

Created a forum post because contributing.md told me to do so:

https://forum.juce.com/t/bug-macos-addtodesktop-w-nativewindowtoattachto-handles-mousemove-incorrectly/63879

@reuk
Copy link
Member

reuk commented Nov 4, 2024

Thanks for your patience. We've now added a fix for this issue on the develop branch.

The fix we merged is fairly similar to the one you suggested, but we call the NSViewComponentPeer::contains function rather than calling hitTest directly:

b108fe2

This also unearthed an issue where the argument to hitTest inside NSViewComponentPeer::contains was not correctly using the superview's coordinate space. That issue is addressed here:

fcf62ab

@reuk reuk closed this as completed Nov 4, 2024
@emezeske
Copy link
Author

emezeske commented Nov 4, 2024

Thanks, I can confirm that the fixes work for my use case!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants