I wanted to be able to detect when Dark mode was turned on or off in my Go program so I can swap icons in my tray app, but the Apple-blessed methods all use Swift and ObjectiveC. To work around this I figured out the following:
- When dark mode is set, a property called "AppleInterfaceStyle" is set to "Dark" for the user.
- When dark mode is disabled, that property is removed.
- You can see this by running "defaults read -g AppleInterfaceStyle"
// Dark Mode On defaults read -g AppleInterfaceStyle Dark echo $? // <- check error code 0 // Dark Mode Off defaults read -g AppleInterfaceStyle 2019-12-08 00:50:27.106 defaults[37703:790070] The domain/default pair of (kCFPreferencesAnyApplication, AppleInterfaceStyle) does not exist echo $? // <- check error code 1
Global properties for the user are stored in ~/Library/Preferences/.GlobalPreferences.plist.
When the property is set, the file is truncated and rewritten by the OS, which results in a REMOVE and CREATE filesystem event. Since I didn't want to just poll the setting every few seconds since that seemed wasteful, I wanted to use a filesystem event watcher like what is provided with the Go package fsnotify.
I used this package to monitor the plist file for CREATE events and then when they occurred I called the defaults command shown above and checked the error code to determine whether or not dark mode was enabled.
When the dark mode state changed, the OS writes the change to the file and the file system watcher detects that and calls a separate function to react to the change.
Because it's a global property store, it's likely that it will be updated for more than just changes to dark mode, so it's important to track the previous state and only react when the state has actually changed.