I made a custom NSControl to use it as a button with a custom layer.
When an instance of MyButton receives mouseDown and mouseUp , it changes its backgroundLayer backgroundColor and its textLayer foregroundColor .
It uses layers, so changes are implicitly animated.
But in mouseUp , if the mouse is inside the frame of the MyButton instance, I MyButton associated action using the sendAction(_:to:) method.
I associated the action with a method that closes the current window and opens another, but sometimes the application pauses after the second window appears.
I tried several things, and it seems that this is due to the animation of the layers, it is possible to do something before closing the window, which I do not know about.
UPDATE: This is Tweetbot! If Tweetbot launches this, freeze the app! As soon as I leave, the application will become responsive again.
Here you can find an example project: https://dl.dropboxusercontent.com/u/378166/CALayerFreeze.zip
(note that sometimes you will have to try several times before an error occurs)
Here is the code for MyButton .
class MyButton: NSControl { let title = "Click me!" // Init required init?(coder: NSCoder) { super.init(coder: coder) setup() } deinit { trackingAreas.forEach { self.removeTrackingArea($0) } } // Layer + Tracking Area configuration var backgroundLayer = CALayer() var textLayer = CATextLayer() func setup() { wantsLayer = true backgroundLayer.frame = NSRect(origin: .zero, size: frame.size) backgroundLayer.backgroundColor = NSColor.whiteColor().CGColor layer?.addSublayer(backgroundLayer) textLayer.frame = NSRect(origin: .zero, size: frame.size) textLayer.string = title textLayer.foregroundColor = NSColor.blackColor().colorWithAlphaComponent(0.64).CGColor layer?.addSublayer(textLayer) addTrackingArea( NSTrackingArea( rect: bounds, options: [.MouseEnteredAndExited, .EnabledDuringMouseDrag, .ActiveInKeyWindow], owner: self, userInfo: nil ) ) } // States private func normal() { // ——— COMMENTING THIS MAKES THE BEACHBALL GO AWAY backgroundLayer.backgroundColor = NSColor.whiteColor().CGColor textLayer.foregroundColor = NSColor.blackColor().colorWithAlphaComponent(0.64).CGColor } private func highlight() { // ——— COMMENTING THIS MAKES THE BEACHBALL GO AWAY backgroundLayer.backgroundColor = NSColor.grayColor().CGColor textLayer.foregroundColor = NSColor.whiteColor().colorWithAlphaComponent(0.64).CGColor } // Tracking events var isMouseDown = false override func mouseDown(theEvent: NSEvent) { super.mouseDown(theEvent) isMouseDown = true highlight() } override func mouseUp(theEvent: NSEvent) { super.mouseUp(theEvent) isMouseDown = false normal() if frame.contains(convertPoint(theEvent.locationInWindow, toView: self)) { sendAction(action, to: target) } } }