24

The status bar app icon has to be changed when dark mode is enabled in Yosemite. How to detect if dark mode has been enabled ? Is there any notification for the same ?

Is it better to display another image or change the alpha value of existing Image ? Need inputs on which is the better way to go ??

sac
  • 840
  • 5
  • 18

3 Answers3

53

You should make use of template images wherever possible because they allow your UI to automatically adapt to changes made by the system (at least when there's not a bug in the system... http://indiestack.com/2014/10/yosemites-dark-mode/). But in the case where you might use a custom view in the status bar and cannot take advantage of a template image, you can manually check for dark mode and adapt your UI accordingly.

You can check whether or not dark mode is enabled by retrieving a key from the user's global preferences, like this:

NSDictionary *dict = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain];
id style = [dict objectForKey:@"AppleInterfaceStyle"];
BOOL darkModeOn = ( style && [style isKindOfClass:[NSString class]] && NSOrderedSame == [style caseInsensitiveCompare:@"dark"] );

At least for the first release of Yosemite, the key is not present when dark mode is disabled, but the key is present and returns the string value @"Dark" when dark mode is enabled. I added the case insensitive compare because I have seen preference keys change their case between system releases, and this adds a little insurance against that.

To monitor the current state of the setting, you register as an observer of a distributed notification (within an appropriate method), like this:

[[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(darkModeChanged:) name:@"AppleInterfaceThemeChangedNotification" object:nil];

And you create a method to act as the message selector for the notification, like this:

-(void)darkModeChanged:(NSNotification *)notif
{
    NSLog(@"Dark mode changed");
}
Charlie
  • 7,227
  • 48
  • 51
bergdesign
  • 806
  • 1
  • 7
  • 6
  • This is great. I use it to toggle the appearance of my app's windows between `NSAppearanceNameVibrantDark` (dark mode) and `NSAppearanceNameAqua` (normal mode). – Nicolas Miari Feb 19 '16 at 08:22
  • I think you can simplfy your code by changing `style && [style isKindOfClass:[NSString class]]` into just `[style isKindOfClass:[NSString class]]`. If `syle` is `nil`, any message sent to it (inluding `-isKindOfClass:`) will return `nil` (which evalueates to `NO`). – Nicolas Miari Mar 16 '16 at 04:13
  • Although this solution is great for detecting dark mode on 10.15 and lower, Big Sur (10.16/11.0) seems to no longer honor this for system tray icons without a `NSImage` with `setTemplate:Yes`, and instead seem to use the wallpaper luminosity instead. https://stackoverflow.com/q/62685948/3196753 – tresf Jul 18 '20 at 07:07
16

The Status bar icon needs to be a template image. Just set the setTemplate:Yes to NSImage. And when switched to dark mode , the vibrancy should apply.

sac
  • 840
  • 5
  • 18
3

As noted by bergdesign, you need to observe the system wide notification and read the persistent global domain.

We made a class to simplify handling changes to the Dark Mode settings: https://github.com/weAreYeah/WAYTheDarkSide

It becomes as easy as...

[WAYTheDarkSide welcomeApplicationWithBlock:^{
    // Enabling Dark Mode
    [someWindow setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]];
    [someVisualEffectView setMaterial:NSVisualEffectMaterialDark];

} immediately:YES];

and

[WAYTheDarkSide outcastApplicationWithBlock:^{
    // Disabling Dark Mode
    [someWindow setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]];
    [someVisualEffectView setMaterial:NSVisualEffectMaterialLight];

} immediately:YES];

Hope this helps :)

Raffael
  • 1,043
  • 9
  • 19