macOS“Big Sur”检测深色菜单栏/系统托盘

tre*_*esf 11 c++ java objective-c statusbar

从 macOS(10.16“Beta”/11.0)“Big Sur”开始,菜单栏和系统托盘不再支持桌面暗模式首选项,因此很难为此桌面正确设置系统托盘图标的主题。

以前,使用 shell 命令default read,可以检测到暗模式:

defaults read -g AppleInterfaceStyle
# "Dark"
Run Code Online (Sandbox Code Playgroud)

这对于检测 Window 主题仍然很有效,但它不适用于菜单栏和系统托盘主题。

由于这个区域似乎是由壁纸亮度/白度/亮度驱动的,我们如何检测暗系统托盘?

n

如何在(例如)Objective-C/C++ 中检测到这一点?欢迎任何解决方案,因为大多数解决方案都可以进行调整。

问题也发布到 Apple 开发者论坛:https : //developer.apple.com/forums/thread/652540

Qt5.6 有一个称为setIsMask(...)允许操作系统自动处理的功能。这实际上是一个别名NSImage::setTemplate:Yes

更多关于 macOS“黑暗模式”的参考:

采用OpenJDK上游错误报告:

关键词:NSStatusBar,Menu Bar Extras

Yuj*_*uji 9

我有同样的问题,但我想我找到了解决方案。正如Big Sur 的 AppKit 发行说明中所写的(请参阅 的条目NSStatusItem),您可以只观察NSStatusItem'sbuttoneffectiveAppearance。如果名称effectiveAppearance包含dark,则它是暗模式。否则就是光模式。

我创建的示例代码显示lightdark作为 的文本标签NSStatusItem可在此 GitHub 存储库中找到,特别是AppDelegate.m。(我很抱歉因为使用 Objective-C 而成为近乎灭绝的恐龙。)您可以通过在 Catalina 或 Big Sur 上运行,从系统偏好设置更改暗/亮设置或桌面图片的颜色来测试它。

编辑:事实证明,Big Sur 有时 effectiveAppearance从亮变为亮或从暗变为暗(从某种意义上说,虽然外观实际上并未改变,但调用了 KVO。)因此,建议检查effectiveApparance前后的值更改以确认实际更改的值。

  • 恐龙很酷,Objective-C 也很酷。 (2认同)

ine*_*tus 1

我刚刚提交了 TSI,得到了答复:

\n
\n

但我不会直接在 NSStatusItem\xe2\x80\x99s 按钮之上添加 NSView。文档提到使用按钮属性来自定义状态项的外观和行为,但它应该在按钮本身的范围内工作,也就是说,它具有各种属性,例如图像和文本及其位置。几年前,\nNSStatusItem 允许自定义视图,但后来被弃用,\n为了支持基于按钮的 UI,\n因此允许其绘图\n行为轻松适应菜单栏\xe2\x80\x99 外观的变化。

\n
\n

不幸的是,无法以编程方式获取此信息。\n但是,获取信息对于我的三个应用程序非常重要,因此我开始探索。

\n

对于我个人来说,获取此信息不会触发任何安全提示非常重要。

\n

我想出了以下想法:

\n
    \n
  • 创建并隐藏NSStatusItem
  • \n
  • 设置模板化NSImage
  • \n
  • 将 的内容渲染CALayerNSImage
  • \n
\n

您可以使用此代码来获取颜色信息(注意:它NSStatusItem永远不可见,并且不会导致现有项目移动或类似的情况)。请随意调整格式和类别:

\n

我创建了一个MenuBar具有公共属性的类:

\n
public class MenuBar {\n    private static var statusItem: NSStatusItem?\n\n    public static var theme: MenuBarTheme {\n        if self.statusItem == nil {\n            self.statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)\n            self.statusItem?.button?.image = NSImage(systemSymbolName: "circle.fill", accessibilityDescription: nil)\n            self.statusItem?.isVisible = false\n        }\n        \n        if let color = self.getPixelColor() {\n            return color.redComponent < 0.20 && color.blueComponent < 0.20 && color.greenComponent < 0.20 ? .light : .dark\n        }\n        else\n        {\n            return NSApplication.isDarkMode ? .dark : .light\n        }\n    }\n\n    public static var tintColor: NSColor {\n        return self.theme == .light ? NSColor.black : NSColor.white\n  }\n    \n  // MARK: - Helper\n  fileprivate static func getPixelColor() -> NSColor?\n  {\n     if let image = self.statusItem?.button?.layer?.getBitmapImage() {\n        let imageRep = NSBitmapImageRep(data: image.tiffRepresentation!)\n            \n         if let color = imageRep?.colorAt(x: Int(image.size.width / 2.0), y: Int(image.size.height / 2.0)) {\n            return color\n         }\n     }\n        \n     return nil\n  }\n}\n\npublic enum MenuBarTheme : String\n{\n    case light = "light"\n    case dark = "dark"\n}\n\npublic extension NSApplication\n{\n    class var isDarkMode: Bool\n    {\n        return NSApplication.shared.appearance?.description.lowercased().contains("dark") ?? false\n    }\n}\n\npublic extension CALayer\n{\n    func getBitmapImage() -> NSImage\n    {\n        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)\n\n        let ctx = NSGraphicsContext(bitmapImageRep: btmpImgRep!)\n        let cgContext = ctx!.cgContext\n        \n        self.render(in: cgContext)\n        \n        let cgImage = cgContext.makeImage()\n\n        return NSImage(cgImage: cgImage!, size: CGSize(width: self.frame.width, height: self.frame.height))\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n