Big Sur: Detect when menu bar is light/dark

I am currently developing a menu bar application that shows a PNG symbol in the menubar. In Catalina, the PNG was always visible due to the menu bar being more opaque. However, in Big Sur, when a light wallpaper is used, the PNG symbol is not legible. This is because of the menu bar adapting to the wallpaper instead of the Aqua theme.

I have found a way of applying a shadow on the button so that the symbol is legible even with light a wallpaper. In order to apply this shadow only when the legibility is low (i.e. light wallpaper and menu bar) I need to know when the menu bar is light/dark. Is there an API I can use to determine when the menu bar is light and dark so I can apply the shadow only when needed?

I am using the image property of NSStatusBarButton (inherited from NSButton) to place the image in the menu bar.

Replies

I have the same question. As stated here (https://stackoverflow.com/questions/62685948/macos-big-sur-detect-dark-menu-bar-system-tray) you can use NSStatusBarButton.isTemplate property to let the OS render the button correct.
However, I want to include color in my button and the documentation of "isTemplate" states that there can only be black color in a template image.

So how can I detect whether the menu bar is currently in dark or light mode to decide whether the outline of my status bar button has to be drawn white/black?
Hi guys, for good statusbar support on catalina/bigsur you need to use a black image and isTemplate like @D0miH said.

Using colored icon is not a good thing in macOs, only if it is dynamic, like change during program execution...

The real problem when you try to "detect if menu bar is light or dark" occours in multiple displays. Each display can have a different theme, so you cannot just detect it in one and create a new version, because both displays will render the same version.
Recently I also encountered this problem, my solution is as follows, work for me
Code Block swift
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
guard let button = statusItem.button else {
      return
}
button.image = NSImage(named: "console")
button.image?.isTemplate = true

The previous solution, but there are still problems in Big Sur:
Code Block swift
var isDarkMode:Bool {UserDefaults.standard.string(forKey: "AppleInterfaceStyle") == "Dark"}
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
func listenToInterfaceChangesNotification() {
    DispatchQueue.main.async { [self] in
      DistributedNotificationCenter.default.addObserver(
        self,
        selector: #selector(interfaceModeChanged(sender:)),
        name: .AppleInterfaceThemeChangedNotification,
        object: nil
      )
    }
  }
@objc func interfaceModeChanged(sender: NSNotification) {
guard let button = statusItem.button else {
return
}
     
if(isDarkMode) {
button.image = NSImage(named: "console_light")
} else {
button.image = NSImage(named: "console")
}
}


isTemplate | Apple Developer Documentation
https://developer.apple.com/documentation/appkit/nsimage/1520017-istemplate