Big Sur: Detect Dark Tray/Menubar

Hi, since macOS dark mode was originally offered, I've been using the following technique to detect the Dark/Light Desktop theme:

Code Block
defaults read -g AppleInterfaceStyle


Recently with the upgrade to Big Sur, the menu bar and system tray area goes light/dark based on the wallpaper, NOT based on the Desktop preference.

How do I detect this so that I can change my app's System Tray icon to match the os behavior?

Accepted Reply

I began writing a crude luminosity test based on the top-left pixel of the screen. Here's a the test, written in Java:

Code Block java
public static boolean isDarkTaskbar() {
try {
Rectangle rectangle = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
Rectangle topCorner = new Rectangle(rectangle.x, rectangle.y, 1, 1);
BufferedImage pixel = new Robot().createScreenCapture(topCorner);
Color color = new Color(pixel.getRGB(0, 0));
return (color.getRed() * 0.299) + (color.getGreen() * 0.587) + (color.getBlue() * 0.114) <= 174;
} catch(AWTException e) {
log.warn("Unable to detect dark taskbar: {}", e.getMessage());
}
return false;
}


This has some unfortunate side effects:
  1. It triggers the "Screen recording" security prompt, something I'd rather not do.

  2. It doesn't work 100% of the time. Some wallpapers such as "Catalina Silhouette" switch the taskbar to "Light Mode" for seemingly no good reason. Preview: i.imgur.com/eiWa864.png


I assume Apple offers an API, it's just not well known yet. Where would I be able to find API information about this feature?

Replies

I began writing a crude luminosity test based on the top-left pixel of the screen. Here's a the test, written in Java:

Code Block java
public static boolean isDarkTaskbar() {
try {
Rectangle rectangle = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
Rectangle topCorner = new Rectangle(rectangle.x, rectangle.y, 1, 1);
BufferedImage pixel = new Robot().createScreenCapture(topCorner);
Color color = new Color(pixel.getRGB(0, 0));
return (color.getRed() * 0.299) + (color.getGreen() * 0.587) + (color.getBlue() * 0.114) <= 174;
} catch(AWTException e) {
log.warn("Unable to detect dark taskbar: {}", e.getMessage());
}
return false;
}


This has some unfortunate side effects:
  1. It triggers the "Screen recording" security prompt, something I'd rather not do.

  2. It doesn't work 100% of the time. Some wallpapers such as "Catalina Silhouette" switch the taskbar to "Light Mode" for seemingly no good reason. Preview: i.imgur.com/eiWa864.png


I assume Apple offers an API, it's just not well known yet. Where would I be able to find API information about this feature?

I still haven't found an API to query this, so I'm proposing a patch to OpenJDK to fix it -- at least for Java, see JDK-8252015
how do u start the bigger detect bar

what app did u use to code this up
where do u type the codes
Since Apple is unable to provide a technique to detect this, we've begun the process to update the JDK to internally (properly) use the NSImage:isTemplate flag.

More details about this available here: https://github.com/AdoptOpenJDK/openjdk-support/issues/146#issuecomment-697723671

I'm marking this as the accepted answer. The patch will not be available in the JDK for some time yet as it takes a while to get the code approved through the proper channels.
Any updates on this?
If there is color in the status bar button image using a template image is not feasible since template images can only contain black color.
Hello, I made some improvements on @tresf code, it now uses screenDevice based on mouse position and always work, no matter what wallpaper is in use.

The trick was compare the top pixel with a pixel inside de apple icon.

Code Block java
public static boolean isDarkTaskbar() {
try {
BufferedImage pixel = new Robot(MouseInfo.getPointerInfo().getDevice()).createScreenCapture(new Rectangle(30, 0, 1, 10));
return getLuminosity(new Color(pixel.getRGB(0, 0))) < getLuminosity(new Color(pixel.getRGB(0, 9)));
} catch (AWTException e) {
log.warn("Unable to detect dark taskbar: {}", e.getMessage());
}
return false;
}
private static float getLuminosity(Color color) {
return (color.getRed() * 0.299f) + (color.getGreen() * 0.587f) + (color.getBlue() * 0.114f);
}


But macOs allow users to have diff wallpapers in each screen, so it will blink a lot on this cenario if you change it at runtime many times.

this doesn't use anything related to code at all, but i found a way to solve the problem that doesn't involve any code and has no side effects. open the image you want to use in preview, and add a narrow bar to the top. make the fill the color you want the menu bar to be. it doesn't have to cover the whole space that the menu bar will take up. i've tried a few different sizes and it seems like as long as it's about a centimeter with a large image the covers the whole preview window. so you can even make your menu bar lime green or dark purple if you wanted to.
I've found a project which uses JNA to accomplish this in Java: https://github.com/dyorgio/macos-tray-icon-fixer. Note, future Java versions will have a new property. More about that here: JDK-8252015