Tendedero 源码剖析(四):零权限调用 WindowServer 私有 API,精准识别全屏 Space
Tendedero 源码剖析四零权限调用 WindowServer 私有 API精准识别全屏 Space【免费下载链接】tendederoScreenshots, hung out to dry. A tiny native macOS app that hangs every screenshot on a line at the top of your screen.项目地址: https://gitcode.com/gh_mirrors/te/tendederoTendedero 是一款 macOS 原生截图管理工具它把每次截图像晾衣服一样挂在屏幕顶部的晾衣绳上鼠标停在菜单栏就会滑下来移开即收起。它能在所有 Space虚拟桌面之间跟随却从不覆盖全屏应用。这期源码剖析聚焦一个精巧的设计如何在不申请任何权限、不使用任何公开 API 的情况下直接调用 WindowServer 的私有函数精准判断当前屏幕是否处于全屏 Space从而决定晾衣绳该出现还是该等待。问题晾衣绳为什么必须避开全屏Tendedero 的核心面板是一块横跨屏幕顶部的透明条带它的窗口行为设置让它能浮现在所有 Space 之上// 每个 Space 都加入但全屏 Space 除外 collectionBehavior [.canJoinAllSpaces, .stationary, .ignoresCycle]完整实现见 Sources/Tendedero/LinePanel.swift。.canJoinAllSpaces是 AppKit 的公开能力但这里有个系统级细节带此标志的窗口在普通 Space 可见在全屏 Space 上则不出现。所以不盖住电影这件事窗口管理器其实已经帮忙做了一半。然而只靠系统行为不够。用户可能先截了图、再点开一部全屏视频——此时晾衣绳被系统藏起来了但截图还在等上线。理想的体验是全屏期间晾衣绳安静等待一旦退出版全屏就立刻露面。要做到这一点应用必须主动知道这块屏幕现在是不是全屏而这正是本期要剖析的能力。零权限调用私有 API两行_silgen_namemacOS 的窗口与 Space 管理由 WindowServer窗口服务进程负责它通过 CoreGraphics 框架暴露了一批以CGSCoreGraphics Services开头的函数。其中两个关键函数没有公开头文件却稳定存在了十多年也是 yabai 等窗口管理器的依赖基础// 窗口服务器知道每个显示器当前显示的是哪类 Space _silgen_name(CGSMainConnectionID) private func CGSMainConnectionID() - Int32 _silgen_name(CGSCopyManagedDisplaySpaces) private func CGSCopyManagedDisplaySpaces(_ connection: Int32) - CFArray代码位置Sources/Tendedero/FullScreen.swift。这里的技巧是 Swift 的_silgen_name属性它让编译器在链接期直接生成一个 C 符号引用绕开 Swift/ObjC 的方法查找机制。链接时从 CoreGraphics 的动态库中解析出该符号运行期像普通函数一样调用。整个过程❌ 不需要辅助功能Accessibility权限❌ 不需要沙盒例外或 entitlements❌ 不需要CGSSpace相关的任何私有头文件签名靠人工声明✅ 只需知道函数名和返回结构两行声明即可源码注释说得很直白These calls are private but stable for a decade, need no permission这些调用是私有的但十多年来稳定不变且无需权限。解读返回值type 为 4 就是全屏 Space拿到两个函数后判断全屏只剩读懂返回值这一步。CGSCopyManagedDisplaySpaces返回一个数组每个元素描述一块显示器的 Space 信息核心字段是字段含义Display Identifier显示器的 UUID 字符串Current Space当前 Space 的字典Current Space.typeSpace 类型全屏 Space 的类型是4主判断逻辑只有几行private static let fullScreenSpaceType 4 let current entry?[Current Space] as? [String: Any] return (current?[type] as? Int) fullScreenSpaceType完整入口是 FullScreen.isActive(on:)整个文件不超过 40 行。多屏兼容两种系统设置的自适应macOS 在显示器具有单独的空间Displays have separate Spaces关闭时返回数组里只有一条记录、覆盖所有屏幕开启时则每块显示器一条。源码对两种情况做了区分if displays.count 1 { entry displays.first // 单条目覆盖所有屏幕 } else { let uuid uuidString(for: screen) entry displays.first { ($0[Display Identifier] as? String) uuid } }多屏分支中把NSScreen转成Display Identifier需要一个小小的桥接uuidString(for:)从deviceDescription取出NSScreenNumber即CGDirectDisplayID用公开的CGDisplayCreateUUIDFromDisplayID换成CFUUID再转成字符串与返回值比对。这样在双屏一屏全屏一屏工作的场景下也能精确判断正在使用的那块屏幕是否全屏。与界面逻辑的协作不是藏而是等识别出全屏后Tendedero 并没有简单地把面板藏死而是在 AppDelegate.refresh() 里把它变成一个门控条件let blocked panel.screen.map(FullScreen.isActive(on:)) ?? LinePanel.screenUnderPointer().map(FullScreen.isActive(on:)) ?? false if wanted !blocked { present() // 有内容要展示且不在全屏 → 出现 } else { dismiss() // 否则收起wanted 保留退全屏后自动回来 }关键在于wanted这个状态位截图挂上时置为true全屏只会让它暂时不呈现而不会清除它。等用户退出全屏Space 切换通知触发重新检查晾衣绳立刻等来了自己的时机。同样的判断也用在热区检测中——指针停在菜单栏准备拉下晾衣绳时会先确认该屏幕不是全屏AppDelegate.swift避免在全屏应用里触发无意义的动画。监听 Space 切换动画结束后的二次采样进出全屏本质上是一次 Space 切换。AppDelegate.swift 订阅了两个系统通知activeSpaceDidChangeNotificationSpace 切换时didActivateApplicationNotification应用激活时每次触发都调用两次refresh()一次立即、一次延迟 0.8 秒。注释解释了原因Entering or leaving full screen switches Space. Check again once the switch animation has settled.进入或退出全屏会切换 Space等切换动画结束后再检查一次。二次采样是个务实的细节macOS 的全屏切换有动画动画进行中的窗口服务器状态可能尚未落定800ms 后的复检保证了状态判断的可靠性。小结这套设计的三个要点要点做法价值零权限_silgen_name直接链接 WindowServer 私有符号无需授权弹窗用户体验零摩擦选稳定的私有 API依赖十年未变的 CGS 函数族与窗口管理器同款的成熟路径风险可控状态机而非开关wantedblocked门控全屏不是隐藏而是等待退出即恢复全文涉及的核心文件全屏检测Sources/Tendedero/FullScreen.swiftREADME 中的角色描述是Knows when to stay hidden——知道何时该保持隐藏面板行为Sources/Tendedero/LinePanel.swift状态编排Sources/Tendedero/AppDelegate.swift工程配置Package.swiftmacOS 14Swift/AppKit/SwiftUI无第三方依赖一个不到 40 行的文件两行私有 API 声明加上一个wanted状态位就构成了晾衣绳在全屏应用前知礼退让、又随时候命的完整体验。对于想在 macOS 上做窗口管理、悬浮面板类工具的同学这份源码展示了调用 WindowServer 私有 API 时最克制的工程姿态用最少的声明换最稳的私有接口再用状态机把系统行为变成产品行为。【免费下载链接】tendederoScreenshots, hung out to dry. A tiny native macOS app that hangs every screenshot on a line at the top of your screen.项目地址: https://gitcode.com/gh_mirrors/te/tendedero创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

西门子S7-1200 PLC六层电梯控制程序开发实战:从IO规划到调试

西门子S7-1200 PLC六层电梯控制程序开发实战:从IO规划到调试

一台六层电梯,听起来不算复杂,但真正从零开始写PLC程序的时候,才能体会到什么叫“麻雀虽小,五脏俱全”。楼层呼叫的逻辑、平层停车的精度、开关门的时序、安全回路的冗余——每一个环节都直接关系到设备能不能稳定运行、乘客敢不敢…

2026/10/10 8:40:12 阅读更多 →
Unison 中 `dependents` 与 `delete.term` 的联动使用:fix4898 回归测试解读

Unison 中 `dependents` 与 `delete.term` 的联动使用:fix4898 回归测试解读

编程语言编译器语言运行时开发工具 【免费下载链接】unison A friendly programming language from the future 项目地址: https://gitcode.com/gh_mirrors/un/unison 点击查看 免费下载 本篇文章以仓库中的回归测试 transcript(fix4898.md)…

2026/10/10 8:40:12 阅读更多 →
AI+前端入门:零基础用Trae、Live Server和F12调试HTML

AI+前端入门:零基础用Trae、Live Server和F12调试HTML

开篇先把我自己的结论放在这里:如果今天你让我给一个零基础想走前端路线的人列第一周学习计划,HTML绝对排在第一位,配套工具则是Trae、浏览器F12和Live Server这三件套。这正好也是这套“AI前端教程”第01讲要解决的内容——写最基础的HTML页…

2026/10/10 8:40:12 阅读更多 →

最新新闻

识别虚假技术资源:Bishop深度学习2024真伪验证指南

识别虚假技术资源:Bishop深度学习2024真伪验证指南

简介:这是一本由机器学习权威Christopher M. Bishop与Hugh Bishop合著的深度学习前沿教材,面向高校研究生、AI研究人员及具备数学与编程基础的进阶学习者,系统构建从神经网络基础到Transformer、图神经网络等现代架构的理论框架。资源为单文件…

2026/10/11 10:57:28 阅读更多 →
如何将impeccable拆解为可执行的质量标准与检查清单

如何将impeccable拆解为可执行的质量标准与检查清单

1. 一个词撬动的思维革命:为什么"impeccable"值得深挖第一次看到"impeccable"这个词被单独拎出来当作项目标题,我的直觉是:这要么是个文字游戏,要么背后藏着某种极致追求。后来跟几个做产品和设计的朋友聊了一…

2026/10/11 10:57:28 阅读更多 →
CAPL脚本入门:掌握on start、on message与output三大核心函数

CAPL脚本入门:掌握on start、on message与output三大核心函数

1. 为什么第一个CAPL脚本值得认真对待很多人第一次接触CAPL,心态都是“先跑起来再说”。这个思路没错,但问题在于,如果第一个脚本只是照抄示例、点下编译、看到没有报错就结束,那基本等于没入门。后面一旦遇到真实项目里的报文周期…

2026/10/11 10:57:28 阅读更多 →
操作系统实验报告写作指南:进程调度、内存管理与并发同步实战

操作系统实验报告写作指南:进程调度、内存管理与并发同步实战

简介:这份资源是西安电子科技大学操作系统课程的上机实验报告,面向正在学习操作系统、需要完成进程与线程相关实验的高校学生及自学者。报告围绕Linux环境下C语言编程展开,完整覆盖进程建立、线程共享进程数据、信号通信、匿名管道与命名管道…

2026/10/11 10:57:28 阅读更多 →
无DOM测试与happy-dom:bloub如何验证导出缺陷的测试体系

无DOM测试与happy-dom:bloub如何验证导出缺陷的测试体系

前端图形学 【免费下载链接】bloub SVG recreation of the x.ai bot avatar. One shape morphing through 14 states, measured off the reference video frame by frame. 项目地址: https://gitcode.com/gh_mirrors/bl/bloub 点击查看 免费下载 bloub 是一个用 SV…

2026/10/11 10:57:28 阅读更多 →
小学组C++算法赛初赛备考指南:从真题拆解到避坑技巧

小学组C++算法赛初赛备考指南:从真题拆解到避坑技巧

简介:这份资源是2024年信息素养大赛C算法创意实践挑战赛小学组初赛的真题解析文档,面向小学阶段对编程有兴趣、已具备一定C基础的学习者,也适合指导教师作为教学参考。内容覆盖单选题与判断题两种题型,涉及变量定义、运算符、布尔…

2026/10/11 10:56:27 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/10 10:38:42 阅读更多 →