Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make NSPopover properly follow the mouse pointer and ignore mouse events?

I would like to display an informational NSPopover that tracks the user's mouse cursor.

For this, I am using an NSTrackingArea to update the popover's positioningRect whenever the mouseMoved event fires.

However, this has two drawbacks:

  1. The popover follows the mouse with a slight delay. How can I reduce this delay to make the popover appear more "glued" to the mouse pointer?
  2. When I move the mouse pointer in the direction of the popover, the tracking area's mouseExited method gets called, which causes the popover to "absorb" the mouse movement events, so that the tracking area's mouseMoved event no longer fires. How can I avoid the popover absorbing the mouse events, or at least keep forwarding these events?

This question is very similar to Any way around this NSTrackingArea quirk?, with the distinction that I am using NSPopover, so I have nothing to set ignoresMouseEvents on.

like image 439
MrMage Avatar asked Oct 30 '22 17:10

MrMage


1 Answers

I took a look at your problem. I was not able to eliminate the lag, but it might reduce if you set popover.animates to false.

Wrong approach:

I was able to solve the mouseExited over popover issue by adding a new border (and shadowless) window on top of the other one. The trackingArea is added to the transparent window, the popover to the original one. Depending on the transparent windows level, it is above the popover and therefore they can't interfere with each other. In the gif below you can see the results of my tests:

example gif

Here is some of my code:

The mouse tracking:

override func mouseMoved(with event: NSEvent) {
    let location = self.view.convert(event.locationInWindow, from: nil)
    popover.positioningRect.origin.x = location.x
    popover.positioningRect.origin.y = location.y
}

The custom window:

transparentWindow.backgroundColor = NSColor.clear
transparentWindow.isOpaque = false
transparentWindow.styleMask = .borderless
transparentWindow.makeKeyAndOrderFront(nil)

Update 11/11/2016:

I just read the question in the link you provided. There is a window to set ignoresMouseEvents on. Even though NSPopover inherits from NSObject, you have a contentViewController, which holds an view object, which holds the popovers window. (as explained here)

So simply set

popover.contentViewController?.view.window?.ignoresMouseEvents = true

after the popover is shown.

like image 107
mangerlahn Avatar answered Nov 15 '22 05:11

mangerlahn