4
votes

I have a custom borderless NSWindow in the shape of a circle. To do this I use a custom NSView that draws a filled circle.

Mouse clicks on a transparent pixel inside the window's content rect go straight through the window to whatever application happens to be behind it. Clicks inside the filled circle are intercepted by my application. So far so good.

The problem is that with the following line the above behavior changes and all clicks inside the windows's content rect are intercepted, transparent pixel or not:

[circleView setWantsLayer:YES];

Is there a way to have clicks on transparent pixels of CALayer instances go through the window/view/layer to the application behind it?

It's essentially the exact same problem as described below (only that the solution doesn't work in all cases, because it doesn't support animations):

http://www.cocoabuilder.com/archive/cocoa/235281-clicking-through-nsview-with-calayers.html

3
Is circleView the window's content view or is it a subview of the content view?Joshua Nozzi

3 Answers

0
votes

I'm not entirely sure whether this works on layer backed views, but a possible solution is to override - (NSView *)hitTest:(NSPoint)aPoint on your circle view subclass and check whether aPoint lies inside the path of the circle. If it's outside the circle, returning nil from that method should cause the click to be passed through.

0
votes

A CAShapeLayer with CGPath will works, or you can create a CAShapeLayer as a mask to the content layer.

0
votes

When you created a CALayer inside a NSView you can ask the Views backing layer for its farthest descendant of the receiver in its layer hierarchy. CALayers in QuartzCore have also a hitTest: method.

Once you catch a layer for this point you could ask for a given name property of your CALayer or CALayer Subclass in case you have several CALayers and need to know which of them exactly was hit.
CALayers do not have a .tag property.

-(NSView *)hitTest:(NSPoint)p {
    __kindof CALayer *catched = [self.layer hitTest:point];
    NSString *className = NSStringFromClass([catched class]);
    NSLog(@"x%0.1f y%0.1f class:%@ name:%@", p.x, p.y, className, catched.name);
    return [super hitTest:p];
}

beware: the result may be null if there is no layer found.