OpenDisplay AppPresentation状态机:菜单栏模式与窗口模式的设计取舍
OpenDisplay AppPresentation状态机菜单栏模式与窗口模式的设计取舍【免费下载链接】opendisplayFree, open-source Sidecar/Duet alternative — use your iPhone, iPad or Mac as a true second monitor for your primary Mac over USB or WiFi. Low latency H.264, Retina HiDPI, touch input.项目地址: https://gitcode.com/GitHub_Trending/op/opendisplayOpenDisplay 是一个免费的开源第二屏虚拟显示器工具可以把 iPhone、iPad 或备用 Mac 变成主 Mac 的真实扩展显示器。本文深入解析它的 Mac 端核心设计——AppPresentation状态机一个枚举、三种出现方式菜单栏、Dock 窗口、纯后台以及背后关于激活策略、单一事实来源和运行时热切换的完整取舍。为什么第二屏工具需要三种出现方式OpenDisplay 的 Mac 端程序长期运行在后台它创建虚拟显示器、用 VideoToolbox 硬件编码 H.264再通过 USB 或 WiFi 把画面流式推送到设备。对这类跑起来就不用管的工具用户的使用习惯差异很大有人希望它像剪贴板工具一样只占菜单栏一小格不打扰 Dock有人习惯正常窗口应用想从 Dock 点图标打开控制面板也有人要完全隐形流媒体继续跑但屏幕上什么都不留。OpenDisplay 的解法很巧妙不打包三个 App而是一个 bundle 在运行时切换外观走的是 Raycast / Hammerspoon 风格的后台代理background agent路线。这个决策的入口就是下面这个状态机。AppPresentation 状态机三个状态一个单一事实来源状态机的全部定义在 OpenSidecarMacApp.swift 中短到一眼能看完enum AppPresentation: String, CaseIterable { case menuBar, dock, background }三个状态各有中文名与用途状态界面上显示激活策略典型场景menuBar菜单栏菜单栏图标 下拉面板.accessory无 Dock 图标日常默认最省资源dock窗口独立控制面板窗口.regular有 Dock 图标偏好传统 App 体验background纯后台无任何界面.accessory挂机投屏、专用投屏机状态机的心脏是控制器里的一个带副作用的发布属性 SenderControllerPublished var presentation AppPresentation( rawValue: UserDefaults.standard.string(forKey: presentation) ?? ) ?? .menuBar { didSet { UserDefaults.standard.set(presentation.rawValue, forKey: presentation) NSApp.setActivationPolicy(presentation .dock ? .regular : .accessory) // Never strand the user without UI if presentation ! .menuBar { MainWindow.show() } } }这段代码是全文最值得初学者借鉴的设计它把三件事收敛在一处持久化选择写入UserDefaults下次启动自动恢复系统行为切换通过NSApp.setActivationPolicy决定 Dock 图标显隐——只有dock状态用.regular其余都是.accessory兜底规则离开菜单栏模式时立即弹出控制窗口永远不让用户找不到界面。这就是状态机里最重要的一个不变量UI 入口和状态永远同步切换是热切换不需要重启 App。菜单栏模式MenuBarExtra 的只读插入绑定菜单栏模式是默认值它的实现有一个反直觉的细节。整个 App 只有一个 SwiftUI Scene MenuBarExtraMenuBarExtra(isInserted: Binding( get: { controller.presentation .menuBar }, set: { _ in } // 故意不处理写入 )) { ... }注意set是空实现——菜单栏图标的插入与否完全由状态机推导而非用户动作。图标本身还会随投屏状态变化运行时是实心图标rectangle.on.rectangle.fill空闲时是空心扫一眼菜单栏就知道第二屏有没有在工作。面板内容用的是.window风格而非原生菜单因为控制面板里有表单、按钮等富交互。代码里还记录了一个真实的坑MenuBarExtra窗口对分组表单的自动测量不可靠在高分屏上会裁剪所以面板显式固定为 440×540 并内部滚动面板尺寸说明。窗口模式与纯后台模式给不想被图标打扰的人Dock 窗口模式的承载者是 MainWindow——一个脱离 SwiftUI Scene、直接用 AppKit 构建的NSWindow内容用NSHostingView包同一个ContentView。这是一个 bundle 两种皮肤的关键菜单栏面板和 Dock 窗口共享同一份控制器、同一个 Sparkle 更新器实例只是挂在不同的宿主上。纯后台模式则把 UI 完全关掉但流媒体管线照跑。为了让它不至于变成打不开的死胡同App 重开了 applicationShouldHandleReopenBackground/Dock 模式下再次打开 AppSpotlight、Finder、Dock 点击都会带出控制窗口——Hammerspoon 风格。界面里也配了诚实的提示文字选择Background only后会说明无菜单栏和 Dock 图标但投屏继续运行再次打开 OpenDisplay 即可显示此窗口 界面文案。设置入口本身则是一个极简的PickerShow app in…三个选项直接遍历AppPresentation.allCases呈现方式选择器。设计取舍总结为什么是一个 bundle而不是两个 App把这套状态机摊开看每个选择背后都是一次明确的取舍单一 bundle 运行时切换vs 双 App 分发只有一份代码、一个更新器、一份UserDefaults不存在菜单栏版和窗口版版本不一致的漂移问题代价是启动时要先读状态再决定激活策略 启动时决策。状态驱动 UIvs 用户驱动 UI菜单栏图标的显隐是状态的派生结果切换发生在didSet里同步完成用户永远看不到图标没了但窗口也没了的中间态。.accessory兜底两种无 Dock 模式共用.accessory策略保证菜单栏模式和纯后台模式的系统占用完全一致区别只是面板插没插。这套菜单栏 ↔ 窗口 ↔ 纯后台的三态设计是第二屏工具类 App 很值得参考的通用方案后台代理的本质是长期驻留而驻留型应用的 UI 形态必须服从用户的工作流而不是反过来。OpenDisplay 用一个 11 行的枚举 一个带didSet的属性就实现了完整、可持久化、可热切换的呈现状态机。相关模块与源码位置状态机与 App 入口Mac/OpenSidecarMacApp.swift投屏管线虚拟显示器 编码器 传输Mac/MacSender.swift、Mac/VirtualDisplay.swift接收端备用 Mac 作为显示器MacReceiver/MacReceiver.swift、MacReceiver/ReceiverPanel.swift通信协议说明PROTOCOL.md功能历史v0.3.0 引入菜单栏 App 与呈现模式CHANGELOG.md【免费下载链接】opendisplayFree, open-source Sidecar/Duet alternative — use your iPhone, iPad or Mac as a true second monitor for your primary Mac over USB or WiFi. Low latency H.264, Retina HiDPI, touch input.项目地址: https://gitcode.com/GitHub_Trending/op/opendisplay创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

3步刷入Armbian到TX3 Mini:S905W电视盒子变Linux服务器的完整避坑实录

3步刷入Armbian到TX3 Mini:S905W电视盒子变Linux服务器的完整避坑实录

3步刷入Armbian到TX3 Mini:S905W电视盒子变Linux服务器的完整避坑实录 【免费下载链接】amlogic-s9xxx-armbian Supports running Armbian on Amlogic, Allwinner, and Rockchip devices. Support a311d, s922x, s905x3, s905x2, s912, s905d, s905x, s905w, s905, …

2026/9/18 19:57:05 阅读更多 →
first-contributions 开源协作入门:使用 git revert 安全撤销已推送的提交

first-contributions 开源协作入门:使用 git revert 安全撤销已推送的提交

first-contributions 开源协作入门:使用 git revert 安全撤销已推送的提交 【免费下载链接】first-contributions 🚀✨ Help beginners to contribute to open source projects 项目地址: https://gitcode.com/gh_mirrors/fi/first-contributions …

2026/9/18 19:57:05 阅读更多 →
Node.js v23.10.0(Current)版本解析:--experimental-config-file 实验性配置文件、TLS/V8 新 API 与发布说明的构成

Node.js v23.10.0(Current)版本解析:--experimental-config-file 实验性配置文件、TLS/V8 新 API 与发布说明的构成

Node.js v23.10.0(Current)版本解析:--experimental-config-file 实验性配置文件、TLS/V8 新 API 与发布说明的构成 【免费下载链接】nodejs.org The Node.js Website 项目地址: https://gitcode.com/GitHub_Trending/no/nodejs.org N…

2026/9/18 19:57:05 阅读更多 →

最新新闻

InfiniBand物理规范1.5版深度解析:HDR链路设计与合规验证

InfiniBand物理规范1.5版深度解析:HDR链路设计与合规验证

简介:本资源是InfiniBand架构1.5版本第二卷《物理规范》官方标准文档,面向从事高速互连硬件设计、模块开发与系统集成的工程师及研究人员,解决物理层兼容性设计、高速信令实现、电源管理优化及多代接口(如OSFP、QSFP28、CXP&#…

2026/9/18 21:43:14 阅读更多 →
盒图(N-S图)完全指南:从流程图失控到结构化详细设计

盒图(N-S图)完全指南:从流程图失控到结构化详细设计

刚接手课程设计那阵子,我用流程图画模块逻辑画得一头乱麻。有一次小组评审,老师指着我图里两条交叉的箭头问“如果这里出现异常,控制流到底走哪条”,我盯着屏幕愣是答不上来。也就是从那天起,我开始认真用盒图&#xf…

2026/9/18 21:43:14 阅读更多 →
走 TaoToken,GLM-5.3-Flash 跑 Blender/CAD 这类 Agent 行不行?

走 TaoToken,GLM-5.3-Flash 跑 Blender/CAD 这类 Agent 行不行?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/18 21:43:14 阅读更多 →
Layout布局实战:Flex、Grid与跨端约束式布局

Layout布局实战:Flex、Grid与跨端约束式布局

做页面设计这行,最容易被低估、又最容易翻车的一环,就是 Layout 布局。很多人以为布局无非是把几个块摆到该在的位置上,可真到了需求评审之后、产品经理说“这里再窄一点、那个卡片要能自动换行、手机端也要好看”的时候,才发现当…

2026/9/18 21:43:14 阅读更多 →
eslint-plugin-unicorn 规则详解:no-console-spaces 如何消除 console 输出中的冗余空格

eslint-plugin-unicorn 规则详解:no-console-spaces 如何消除 console 输出中的冗余空格

eslint-plugin-unicorn 规则详解:no-console-spaces 如何消除 console 输出中的冗余空格 【免费下载链接】eslint-plugin-unicorn More than 300 powerful ESLint rules 项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn 导读 本文…

2026/9/18 21:43:14 阅读更多 →
jQuery hide()与show()方法深度解析与应用实践

jQuery hide()与show()方法深度解析与应用实践

1. jQuery 隐藏/显示功能解析作为一名前端开发老兵,我处理过无数DOM元素显隐控制的场景。jQuery的hide()和show()方法看似简单,但其中蕴含着不少值得深挖的技巧。今天我们就来彻底剖析这两个基础但强大的方法。在早期的Web开发中,要实现元素的…

2026/9/18 21:42:07 阅读更多 →

日新闻

Matlab手写逻辑回归:从数学原理到多变量概率预测模型实现

Matlab手写逻辑回归:从数学原理到多变量概率预测模型实现

很多朋友第一次看到"逻辑回归"这四个字,第一反应就是——这玩意儿是个回归模型吧?我当年也是在Matlab里跑完一段代码,看着输出的0.73、0.86这种概率值,才回过神来:这家伙其实是披着回归外衣的分类神器&#…

2026/9/18 0:00:28 阅读更多 →
高值医用耗材研报PDF:用Python完成字段抽取、清洗与趋势预测

高值医用耗材研报PDF:用Python完成字段抽取、清洗与趋势预测

简介:这份报告是2023-2028年高值医用耗材行业调研及发展前景趋势预测报告,面向医疗器械企业管理者、投资机构、行业研究人员及关注政策变化的从业者,用于把握行业监管动向、市场格局与未来趋势。报告以PDF格式呈现,共1个文件、整体…

2026/9/18 0:00:28 阅读更多 →
三维高斯场赋能世界模型:几何语义蒸馏与机器人决策实战

三维高斯场赋能世界模型:几何语义蒸馏与机器人决策实战

先把我自己的背景交代一下:我之前在搞具身智能和机器人导航相关的项目,很长一段时间里都被“环境表示”这件事卡着。传统做法是用点云或者网格做几何建模,语义信息另外再跑分割模型,两套东西各管各的,时间一长就会发现…

2026/9/18 0:00:28 阅读更多 →

周新闻

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验 【免费下载链接】ai The AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and ag…

2026/9/16 19:03:19 阅读更多 →
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化

Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化 【免费下载链接】refine A React Framework for building internal tools, admin panels, dashboards & B2B apps with unmatched flexibility. 项目地址: https://gitcode.com/GitH…

2026/9/17 7:57:36 阅读更多 →
Flutter应用改名全指南:从Android到iOS的配置与工具实践

Flutter应用改名全指南:从Android到iOS的配置与工具实践

刚接一个外包项目时,甲方要求把工程里临时用的应用名改成正式产品名。我本来觉得“改名”这种小事,打开配置文件改一行不就完了?结果真动手才发现,Flutter项目里“应用名称”根本不是一处配置,而是一整套散落在 Androi…

2026/9/17 10:19:14 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/16 22:31:27 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/15 21:39:18 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/16 22:32:59 阅读更多 →