CGContext Syntactic Sugar

Tired of typing CGContextBlah(context, ...)? There’s an extension for that: context.blah(...)

//  CGContextABCD(context!, ...) becomes context?.ABCD(...)
import Cocoa
extension CGContext {
    func saveGState() { CGContextSaveGState(self) }
    func restoreGState() { CGContextRestoreGState(self) }
    func scaleCTM( sx: CGFloat, sy: CGFloat) { CGContextScaleCTM(self, sx, sy) }
    func translateCTM( tx: CGFloat, ty: CGFloat) { CGContextTranslateCTM(self, tx, ty) }
    func rotateCTM( angle: CGFloat) { CGContextRotateCTM(self, angle) }

Get CGContextExt.swift.

Text Aliasing in Custom Drawn OSX Status Bar Items

Its fairly straightforward for an OSX app to add a status bar item:

// -1: variable length
var statusBarItem = NSStatusBar.systemStatusBar().statusItemWithLength(-1)

As of OSX 10.10, most drawing modes have been “softly” deprecated, including custom views. To quote the docs:

Custom views should not be set on a status item. The button property with a template image will allow proper styling of the status item in various states and contexts and should be used instead.

This isn’t a major issue for static status items which can set text via the button’s title or an image via the button’s image. Non-static status items will likely miss the ability to set custom views.

One workaround is to install a drawing handler for button’s image. The handler will be called within the appropriate drawing context. Note that this method is preferable over creating a “rendered” NSImage (lockFocus & draw) since lockFocus() will ignore text antialiasing.

let image = NSImage(size: mySize, flipped: false, drawingHandler: drawImage)
image.cacheMode = .Never //don't cache, always draw
statusItem.button.image = image

func drawImage(rect: NSRect) -> Bool {
  var context = NSGraphicsContext.currentContext()?.CGContext



Beginning with Yosemite, status items are required to deal with dark modes. If we supply a template image, Yosemite will automatically handle the display mode (a template image comprises only clear or greyscale pixels).

let image = NSImage(size: mySize, flipped: false, drawingHandler: drawImage)

However, text aliasing isn’t optimal when template mode is turned on. Turns out that for best performance, text anti-aliasing uses a dash of color pixels which isn’t possible in pure-greyscale template mode. Note the differences in the images below:




In dark mode:





The solution? Don’t set template mode and handle display mode changes appropriately.

Update May 04

The app which prompted this study is now live on the app store.