Java macOS“;“大苏尔”;检测黑暗菜单栏/系统托盘
从macOS(10.16“Beta”/11.0)“Big Sur”开始,菜单栏和系统托盘不再支持桌面暗模式首选项,因此很难为该桌面正确设置系统托盘图标的主题 以前,使用shell命令Java macOS“;“大苏尔”;检测黑暗菜单栏/系统托盘,java,c++,objective-c,statusbar,Java,C++,Objective C,Statusbar,从macOS(10.16“Beta”/11.0)“Big Sur”开始,菜单栏和系统托盘不再支持桌面暗模式首选项,因此很难为该桌面正确设置系统托盘图标的主题 以前,使用shell命令默认读取,可以检测到暗模式: defaults read -g AppleInterfaceStyle # "Dark" 这对于检测窗口主题仍然很有效,但对于菜单栏和系统托盘主题不起作用 由于该区域似乎受壁纸亮度/白度/亮度的影响,我们如何检测黑暗的系统托盘 如何在(例如)Objective-
默认读取
,可以检测到暗模式:
defaults read -g AppleInterfaceStyle
# "Dark"
这对于检测窗口主题仍然很有效,但对于菜单栏和系统托盘主题不起作用
由于该区域似乎受壁纸亮度/白度/亮度的影响,我们如何检测黑暗的系统托盘
如何在(例如)Objective-C/C++中检测此问题?任何解决方案都是受欢迎的,因为大多数方案都可以调整
问题也发布到苹果开发者论坛:
Qt5.6有一个名为的功能,允许操作系统自动处理此问题。这实际上是的别名
更多关于macOS“暗模式”的参考:
关键词:
NSStatusBar
,菜单栏附加功能
我刚刚提交了一份TSI,我得到了一个答案:
但我不会在NSStatusItem按钮的顶部添加NSView
直接的。文档提到使用按钮属性进行自定义
状态项的外观和行为,但它应该工作
在按钮本身的范围内,也就是说,它是多种多样的
属性,如图像和文本及其位置。几年前,,
NSStatusItem允许自定义视图,但后来在中被弃用
以支持基于按钮的UI,因此允许其绘制
行为,以便轻松适应菜单栏外观的更改
不幸的是,没有办法通过编程获得这些信息。
然而,获取信息对于我的三个应用程序来说非常重要,所以我开始探索
对我个人来说,获取这些信息不会触发任何安全提示是非常重要的
我想到了以下想法:
- 创建并隐藏
NSStatusItem
- 设置模板化的
NSImage
- 将
的内容呈现为CALayer
NSImage
NSStatusItem
永远不可见,不会导致现有项目移动或类似情况)。请随意调整格式和类:
我使用公共属性创建了一个名为MenuBar
的类:
public class MenuBar {
private static var statusItem: NSStatusItem?
public static var theme: MenuBarTheme {
if self.statusItem == nil {
self.statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
self.statusItem?.button?.image = NSImage(systemSymbolName: "circle.fill", accessibilityDescription: nil)
self.statusItem?.isVisible = false
}
if let color = self.getPixelColor() {
return color.redComponent < 0.20 && color.blueComponent < 0.20 && color.greenComponent < 0.20 ? .light : .dark
}
else
{
return NSApplication.isDarkMode ? .dark : .light
}
}
public static var tintColor: NSColor {
return self.theme == .light ? NSColor.black : NSColor.white
}
// MARK: - Helper
fileprivate static func getPixelColor() -> NSColor?
{
if let image = self.statusItem?.button?.layer?.getBitmapImage() {
let imageRep = NSBitmapImageRep(data: image.tiffRepresentation!)
if let color = imageRep?.colorAt(x: Int(image.size.width / 2.0), y: Int(image.size.height / 2.0)) {
return color
}
}
return nil
}
}
public enum MenuBarTheme : String
{
case light = "light"
case dark = "dark"
}
public extension NSApplication
{
class var isDarkMode: Bool
{
return NSApplication.shared.appearance?.description.lowercased().contains("dark") ?? false
}
}
public extension CALayer
{
func getBitmapImage() -> NSImage
{
let btmpImgRep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(self.frame.width), pixelsHigh: Int(self.frame.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: .deviceRGB, bytesPerRow: 0, bitsPerPixel: 32)
let ctx = NSGraphicsContext(bitmapImageRep: btmpImgRep!)
let cgContext = ctx!.cgContext
self.render(in: cgContext)
let cgImage = cgContext.makeImage()
return NSImage(cgImage: cgImage!, size: CGSize(width: self.frame.width, height: self.frame.height))
}
}
公共类菜单栏{
私有静态变量statusItem:NSStatusItem?
公共静态变量主题:菜单基础{
如果self.statusItem==nil{
self.statusItem=NSStatusBar.system.statusItem(带长度:NSStatusItem.variableLength)
self.statusItem?.button?.image=NSImage(系统符号名称:“circle.fill”,可访问性说明:nil)
self.statusItem?.isVisible=false
}
如果let color=self.getPixelColor(){
返回color.redComponent<0.20&&color.blueComponent<0.20&&color.greenComponent<0.20?。亮:。暗
}
其他的
{
返回NSApplication.isDarkMode?.dark:.亮
}
}
公共静态颜色:NSColor{
return self.theme==.light?NSColor.black:NSColor.white
}
//马克:-助手
fileprivate静态函数getPixelColor()->NSColor?
{
如果让image=self.statusItem?.button?.layer?.getBitmapImage(){
让imageRep=NSBitmapImageRep(数据:image.tiffRepresentation!)
如果let color=imageRep?.colorAt(x:Int(image.size.width/2.0),y:Int(image.size.height/2.0)){
返回颜色
}
}
归零
}
}
公共枚举菜单项:字符串
{
case light=“light”
case dark=“dark”
}
公共扩展非应用程序
{
类别var isDarkMode:布尔
{
返回NSApplication.shared.appearance?.description.lowercased().contains(“深色”)?false
}
}
公共分机
{
func getBitmapImage()->NSImage
{
设btmpImgRep=NSBitmapImageRep(bitmapDataPlanes:nil,pixelsWide:Int(self.frame.width),pixelsHigh:Int(self.frame.height),bitsPerSample:8,samplesPerPixel:4,hasAlpha:true,isPlanar:false,colorSpaceName:.deviceRGB,bytesPerRow:0,bitsPerPixel:32)
设ctx=NSGraphicsContext(bitmapImageRep:BTMPIMIGREP!)
让cgContext=ctx!.cgContext
self.render(在:cgContext中)
让cgImage=cgContext.makeImage()
返回NSImage(cgImage:cgImage!,大小:CGSize(宽度:self.frame.width,高度:self.frame.height))
}
}
我也有同样的问题,但我想我找到了解决办法。如中所述(请参见NSStatusItem
的条目),您只需观察NSStatusItem
的按钮的有效外观即可。如果有效外观
的名称包含暗
,则为暗模式。否则就是灯光模式
我创建的示例代码显示亮
或暗
作为NSStatusItem
的文本标签,可在中找到,请特别参阅。(我很抱歉因为使用Objective-C而成为濒临灭绝的恐龙。)您可以通过在Catalina或Big-Sur上运行,从系统首选项更改暗/光设置或桌面图片的颜色来测试它
编辑:事实证明,Big Sur有时会将有效外观
从亮变亮或从暗变暗(从某种意义上说,尽管外观实际上没有改变,但调用了KVO)因此,建议在更改前后检查有效外观的值,以确认实际更改的值。对于Java 17,已添加此功能。它最终将被后移植到Java11
新物业为:
apple.awt.enableTemplateImages
从
// Verify theme to choose image version
Image iconImage = MacOSTrayIconFixer.getInitialIcon(blackImage, whiteImage);
// Create your TrayIcon using image
TrayIcon icon = new TrayIcon(iconImage, "Test");
// (Optional) add action and menu
icon.addActionListener((e) -> System.out.println("examples.BasicUsage.main():" + SwingUtilities.isEventDispatchThread()));
// Include in SystemTray BEFORE call fixer
SystemTray.getSystemTray().add(icon);
// Fix
MacOSTrayIconFixer.fix(icon, blackImage, whiteImage, false, 0);