- 桌面应用
【免费下载链接】Lunar
Intelligent adaptive brightness for your external monitors
Lunar 5.6.0 是该版本周期中一次以"稳定性与体验打磨"为主线的发布:它重写了负责内置屏熄屏(BlackOut)的核心子系统,增强了 XDR(HDR)亮度下的对比度与切换流畅度,并为 QuickActions 菜单栏引入了 App Info 区块、Advanced Settings 标签页和 Menu Density(菜单密度)三项 UI 能力;同时,官方取消了"购买后仅享 1 年更新"的限制,将 Lunar 5 的授权模型切换为"按大版本计费"。本文以 ReleaseNotes/5.6.0.md 为核心骨架,结合仓库源码逐项还原每个功能点在实现层面的真实逻辑,帮助读者理解这些改动背后的工程原理。
一、授权模式变更:取消 1 年更新限制,转向大版本授权
发布说明在开头单独用一节(Licensing model)阐述了商业化模型的调整,这是 5.6.0 中唯一非技术性的重大变更:
- 取消 1 年更新限制:所有用户将享受Lunar 5 大版本范围内的无限量免费更新(unlimited free updates);
- 按大版本计费:只有当发布新的大版本(例如 Lunar 6)时才需要购买新授权;
- 老授权可作抵扣券:如果未来真的发布 Lunar 6,旧版购买者可以将之前的授权作为优惠券(coupon)获得可观折扣。
对开发者和用户而言,这意味着 Lunar 5 生命周期内的所有迭代(5.6.x、5.7、5.8、5.9 直至 5.x 结尾)都不再额外收费。在仓库中,授权与版本相关的 UI 入口被集中放置,例如 Lunar/SwiftUIViews/QuickActionsMenuView.swift 中的appInfo视图同时挂载了LicenseView、VersionView(updater:)与MenuDensityView,与下文第五节的 App Info 区块直接对应。
二、XDR 亮度增强:对比度、无闪烁切换与待机保持
5.6.0 对 XDR 的支持做了五项具体增强,发布说明原文如下:
- 增强对比度(Enhance contrast):让"深色背景 + 亮色文字"的场景在阳光直射下更可用;
- 更无缝的 XDR 切换:仅用键盘把亮度调到超过 100%就应该平滑地进入 XDR,且不再有大量闪烁;
- 屏幕从待机恢复后保持 XDR 开启状态;
- 修复 HDR 内容过曝:只要不启用 Gamma 就生效。发布说明明确指出这仍然是macOS 的系统级 bug,Apple 尚未修复,Lunar 只是做了绕过(work around);
- 在非 Apple 显示器上暂时禁用 XDR:等待"强制单色(forced-monochrome)"相关 bug 被修复后再启用。
从源码结构看,这些行为落在 Apple 私有控制通道 Lunar/Control/AppleNativeControl.swift 与调度层 Lunar/Utils/DisplayController.swift 中。以updateNits()为例,当显示器处于 XDR 增强态(display.enhanced)且存在xdrBrightness时,软件亮度值(0~1)会被线性映射到硬件的 nits 区间:
if display.enhanced, let maxHardwareNits = display.maxHardwareNits, display.xdrBrightness > 0 { nits = display.xdrBrightness.d.map(from: (0, 1), to: (maxNits, maxHardwareNits)) }紧接着,只要系统支持 XDR 对比度(DC.supportsXDRContrast)且距离上次重置超过 3 秒,就会按当前 nits(钳制在 600~1600 之间)计算并写入对比度,xdrContrastFactor来自用户可调的缓存默认值:
if DC.supportsXDRContrast, timeSince(lastXDRContrastResetTime) > 3, display.softwareBrightness >= 1 { let xdrContrast = display.computeXDRContrast( xdrBrightness: nits.f.capped(between: 600, and: 1600), xdrContrastFactor: CachedDefaults[.xdrContrastFactor] + 0.3, minBrightness: 600, maxBrightness: 1600, gamma: 2.2) if xdrContrast != DC.xdrContrast { DC.setXDRContrast(xdrContrast) } }这里的 600 nits 下限、1600 nits 上限与 gamma 2.2 参数,正是发布说明中"增强对比度使深色背景场景在阳光可用"这一条在实现上的落点:进入 XDR 亮度区间后,Lunar 并非只抬亮暗部,而是同步调整对比度曲线。相关的用户侧提示视图可参见 Lunar/Views/XDRTipView.swift 与 Lunar/SwiftUIViews/HDRSettingsView.swift。
需要强调的是发布说明中的事实边界:HDR 过曝问题被明确归因为 macOS bug,Lunar 的"修复"是绕过而非根治;"非 Apple 显示器禁用 XDR"也是临时策略,以"forced-monochrome bugs 被修复"为前提,因此这一行为可能随后续版本变化。
三、BlackOut 子系统重写:对齐系统设置所用的私有框架
5.6.0 对 BlackOut(内置屏熄屏,用于把 MacBook 当作外接显示底座)子系统做了一次重写,发布说明列出三点:
- 改为使用
System Preferences(系统设置)同款私有框架来操作面板背光; - 镜像(mirroring)行为更稳定;
- 与 BetterDummy 的最新版本(v1.1.10-beta)做了紧密集成——BetterDummy 是配合虚拟显示使用,使内置屏熄屏后系统不降级分辨率的第三方驱动。
在实现层,BlackOut 的状态机位于 Lunar/Utils/DisplayController.swift,每个显示器持有blackOutEnabled/blackOutEnabledWithoutMirroring两个状态标志,显示插拔与镜像变化时通过blackOut(display:state:mirroringAllowed:)统一调度。例如内置屏被镜像时主动关闭熄屏、显示列表变化时校验状态一致性:
log.debug("\(d): blackOutEnabled=\(d.blackOutEnabled) blackOutEnabledWithoutMirroring=\(d.blackOutEnabledWithoutMirroring)") guard d.blackOutEnabled, !d.blackOutEnabledWithoutMirroring, let panel = Self.panel(with: d.id), !panel.isMirrored else { ... }镜像场景下熄屏会被暂时关闭并保留自适应模式,解除镜像时再按blackOutEnabledWithoutMirroring决定是否恢复:
let preservedAdaptiveMode = d.blackOutEnabledWithoutMirroring && CachedDefaults[.overrideAdaptiveMode] ? adaptiveModeKey : nil blackOut(display: d.id, state: .off, mirroringAllowed: !d.blackOutEnabledWithoutMirroring)这一分支逻辑正是发布说明"More stable mirroring(更稳定的镜像)"的源码印证:重写后的子系统把"镜像中是否允许熄屏"显式建模,而不是让镜像副作用直接污染熄屏状态。对外控制入口分布在 Lunar/AppDelegate.swift(blackOutPowerOff菜单动作)、Lunar/Data/Hotkeys.swift(BlackOut 系列全局快捷键,含blackOutNoMirroringHotkeyHandler、blackOutOthersHotkeyHandler)以及 SwiftUI 侧的 Lunar/SwiftUIViews/BlackoutPopoverView.swift。
四、Auto BlackOut OSD:等待系统稳定 + Esc 取消
Auto BlackOut 是连接非内置外接显示器时自动熄屏内置屏的能力。5.6.0 为它新增了 OSD(屏幕叠加)提示,并引入两个行为改进:
- 允许系统先完成屏幕配置稳定(settle),再执行熄屏,避免在显示器协商过程中误触发;
- 用户可按
esc键取消Auto BlackOut。
取消路径在 Lunar/AppDelegate.swift 的按键处理中可以直接看到:
case kVK_Escape where DC.autoBlackoutPending: DC.cancelAutoBlackout()autoBlackoutPending是一个带日志的原子状态位,而"等待系统稳定后重试"由 Lunar/Utils/DisplayController.swift 中的retryAutoBlackoutLater()实现——它同时校验四个前提:熄屏尚未生效、该显示器未被判定为可能已断开、当前不在校准流程中:
func retryAutoBlackoutLater() { if autoBlackoutPending, let d = builtinDisplay, !d.blackOutEnabled, DisplayController.possiblyDisconnectedDisplays[d.id] == nil, !calibrating { log.info("Retrying Auto Black Out later") d.showAutoBlackOutOSD() autoBlackoutPublisher.send(true) } }OSD 窗口的窗口控制器按显示器的autoBlackoutOsd类型缓存,见 Lunar/Data/Display.swift:
get { Self.getWindowController(id, type: "autoBlackoutOsd") }AppDelegate在多个系统事件回调中(如显示配置变化)调用retryAutoBlackoutLater(),这正对应发布说明中"Allow the system to settle screen configuration"的语义:不是立刻熄屏,而是监听稳定信号后再经 Publisher 驱动执行。
五、App Info 区块与 Advanced Settings 标签页
发布说明中的 App Info section 一节列出四项内容:License status(授权状态)、版本号与 Check for updates 按钮、Auto update 设置、Menu density 选择器;Advanced settings tab 一节则展示了 QuickActions 弹出面板新增的设置标签页。
App Info 区块的完整实现位于 Lunar/SwiftUIViews/QuickActionsMenuView.swift 的appInfo计算属性中,结构与发布说明逐条对应:
var appInfo: some View { VStack(alignment: .leading, spacing: 6) { HStack { Toggle("Launch at login", isOn: $startAtLogin) ... } LicenseView() // License status VersionView(updater: appDelegate!.updater) // 版本号 + Check for updates MenuDensityView() // Menu density selector } ... }其中"Check for updates"最终调用 Sparkle 系更新器:菜单栏路径走 Lunar/AppDelegate.swift 的checkForUpdates(_:)→updater.checkForUpdates(),而 QuickActions 脚部在检测到新版本时直接以版本号按钮触发同一方法。Auto update 开关则绑定@Default(.checkForUpdate)并同样驱动updater.checkForUpdates(),实现见 Lunar/Views/ProViews.swift。
Advanced Settings 标签页的容器视图是 Lunar/SwiftUIViews/AdvancedSettingsView.swift,它挂在 QuickActions 的选项菜单中;标签枚举OptionsTab(layout / advanced / hdr)定义在 Lunar/Controllers/QuickActionsViewController.swift:
enum OptionsTab: String, Defaults.Serializable { case layout case advanced case hdr }六、Menu Density:clean / comfortable / dense 三档菜单密度
Menu Density 允许用户调整 QuickActions 菜单栏的行距密度,三档取值定义在 Lunar/Controllers/QuickActionsViewController.swift:
enum MenuDensity: String, Codable, Defaults.Serializable { case clean case comfortable case dense }其默认值在 Lunar/Data/DataStore.swift 中声明为.comfortable,并被纳入跨进程缓存与 Shortcut 扩展同步的键集合:
static let menuDensity = Key<MenuDensity>("menuDensity", default: .comfortable)用户侧交互由 Lunar/Views/ProViews.swift 中的MenuDensityView提供,三个按钮分别写入.clean/.comfortable/.dense,并通过onChange触发菜单重排。菜单宽度常量(如MENU_WIDTH = 320、MENU_CLEAN_WIDTH = 300、MENU_HORIZONTAL_PADDING = 24)同样集中定义在 QuickActionsViewController.swift 中,密度档位影响的就是这些行距与内边距的组合。
七、Improvements:镜像分辨率保持、CPU 占用与 DDC 端口分配
发布说明的 Improvements 小节包含四条,逐条对应如下:
- 镜像前保存上一次的分辨率,并在镜像结束后重新应用。发布说明注明这是在规避一个系统 bug:关闭镜像时系统会应用非原生分辨率。
- 进一步降低 CPU 占用:在菜单不可见时减少 UI 结构更新——对应 QuickActions 菜单大量使用
DispatchWorkItem延迟任务(如windowShowTask、headerShowHideTask、footerShowHideTask)做按需刷新与取消的架构。 - QuickActions 菜单触底时可滚动:菜单最大高度由
EnvState.menuMaxHeight(屏幕可见高度减 50pt)约束,超出部分滚动显示。 - 对无法通过 EDID 匹配的显示器,按顺序(sequentially)分配剩余的 DDC 端口。
第 4 条的匹配基础在 Lunar/DDC/DDC.swift:DDC 子系统维护一张displayUUIDByEDID映射(EDID 原始 256 字节数据 → 显示器 UUID),并通过getEdid(displayID:)、extractName(from:)、extractSerialNumber(from:)等函数解析 EDID 块;当多个显示器因 EDID 重复或无法读取而无法唯一匹配时,5.6.0 引入了顺序分配剩余端口的回退策略,保证每个可寻址显示器都能获得一个确定的 DDC 端口,而不是随机命中他人端口。
八、Fixes:递归调用与内存/线程优化
Fixes 小节两条都指向资源占用:
- 降低 CPU 占用:修复分辨率下拉框(resolutions dropdown)上的一个递归调用——该下拉框用于切换显示器分辨率,递归调用会在每次枚举时重复触发自身;
- 降低内存占用与创建的线程数量。
这两项属于纯性能修复,发布说明未提供额外细节;从仓库结构看,分辨率与显示配置相关逻辑集中在 Lunar/Data/Display.swift 与 Lunar/Utils/DisplayController.swift,修复的具体调用点未在公开源码中单独标记,此处不做进一步推测。
九、适用前提与边界说明
- 本文所述行为以当前仓库快照为准,对应发布说明 ReleaseNotes/5.6.0.md;仓库已演进到后续版本(6.x 系列,见 CHANGELOG.md 与 ReleaseNotes/ 目录),部分 5.6.0 时期的实现细节(如 Auto XDR 相关状态机)已在此后继续重构;
- XDR 相关增强仅适用于支持 XDR 的内置显示器(如带 XDR 屏的 MacBook Pro),发布说明明确非 Apple 显示器在 forced-monochrome bug 修复前 XDR 被禁用;
- HDR 过曝问题的根治依赖 Apple 修复 macOS 系统 bug,Lunar 侧仅做绕过;
- BlackOut 与虚拟显示驱动的紧密集成以 BetterDummy v1.1.10-beta 为版本基线,更换虚拟显示驱动方案时行为可能不同;
- 授权模式变更(大版本计费、旧授权可作折扣券)属于产品策略,本文仅转录发布说明原文,不构成承诺条款的引用。
- 桌面应用
【免费下载链接】Lunar
Intelligent adaptive brightness for your external monitors
相关推荐
Lunar 5.5.1 版本技术解读:XDR Brightness、Sub-zero Dimming 与 BlackOut 机制实现
Lunar 5.5.1 版本技术解读:XDR Brightness、Sub zero Dimming 与 BlackOut 机制实现 本文以 Lunar 5.5
桌面应用Lunar 4.9.6 版本深度解析:菜单栏信息增强、单屏 BlackOut 与线程安全缓存修复
Lunar 4.9.6 版本深度解析:菜单栏信息增强、单屏 BlackOut 与线程安全缓存修复 Lunar 4.9.6 是这款「外接显示器智能亮度调节」mac
桌面应用pandas 0.10.0 版本深度解析:CSV 解析引擎重写、resample 语义变更与 HDFStore 全面增强
pandas 0.10.0 版本深度解析:CSV 解析引擎重写、resample 语义变更与 HDFStore 全面增强 导读 :本文以官方发布说明 doc/s
数据分析数据科学数据处理
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考