# AtomUI.Native 架构 ## 定位 `AtomUI.Native` 是 AtomUI 的内部底层 OS 能力封装层。它按“是否属于操作系统、窗口系统或原生运行时 调用”划定边界,而不是按 `Window`、`Dialog`、主题、控件等上层概念划定边界。只要实现需要直接接触 P/Invoke、原生 handle、原生结构体、平台协议对象、native hook 或平台错误码,就应优先收敛到 `AtomUI.Native`。 窗口相关能力可以进入 `AtomUI.Native`。Win32、DWM、Objective-C runtime、Xlib/XCB、Wayland protocol 等窗口系统原生调用,本质上是底层 OS/backend 能力,不应因为服务于 Window/Dialog 就回到控件层。 `AtomUI.Native` 不决定控件策略、主题策略或用户可观察行为。上层库负责选择何时启用某个原生能力, 并承担 Avalonia 控件生命周期、事件订阅、属性同步和模板状态。Native 层提供能力,不拥有业务状态。 Avalonia drawn decorations、`TopLevelHost`、resize grip layer 等 Desktop 控件私有结构发现通常保留在 `AtomUI.Desktop.Controls`。只有当实现必须解析原生协议对象、调用原生 API,或把 P/Invoke/协议细节 压回 Native 边界时,才应进入 `AtomUI.Native`。 ```text AtomUI.Desktop.Controls - 选择 Window chrome manager - 管理 Window 事件、属性和模板生命周期 - 决定何时启用某个原生能力 | v AtomUI.Native - 校验原生 handle / 参数 - 调用 Win32、Objective-C、Xlib/XCB 或 NWayland - 封装原生结构体、常量、消息和协议对象 - 管理原生资源、hook 和错误边界 ``` 所有成员目前都是 `internal`,通过 `InternalsVisibleTo` 向 `AtomUI.Desktop.Controls` 和目标程序集名称 `AtomUI.Mobile.Controls` 开放。当前仓库没有 Mobile 实现消费者;这项预留只定义未来可见性边界,不是 Mobile 源码、 平台验证或发布证据。它是实现包,不是公共 Native SDK。 ### 能力与策略分界 | 层级 | 可以做 | 不应该做 | |---|---|---| | `AtomUI.Native` | 封装 OS/backend 原生调用、窗口系统底层能力、消息结构体、hook/façade、句柄校验、原生资源释放 | 决定窗口主题、Dialog 行为、控件状态机、Token、默认平台策略 | | `AtomUI.Core` | AtomUI 基础设施、主题/Token/语言、资源、动画、应用启动默认选项;必要时调用 `AtomUI.Native` 获取底层 OS 能力 | 直接散落 P/Invoke、原生结构体、平台协议细节,或依赖具体控件生命周期 | | `AtomUI.Desktop.Controls` | Window/Dialog/Popup 等桌面控件语义、生命周期、何时调用 Native 能力 | 直接维护 P/Invoke、原生结构体或重复实现 OS 协议 | | `AtomUI.Mobile.Controls`(目标) | Viewport、Gesture、Overlay、Theme、owner 生命周期、平台默认策略,以及何时调用 Native 能力 | 直接维护 P/Invoke、原生 handle/结构体、不可释放 hook,或把 OS 类型暴露到 Public Control API | `AtomUI.Core` 可以依赖 `AtomUI.Native`。`Core` 是 AtomUI 的基础设施层,不等于必须排除所有 Window 或 OS 概念;判断标准是能力本身是否属于底层 OS/native 操作。例如安全打开文件、解析真实路径、读取系统 窗口 metric、封装窗口系统原生调用,都可以由 `Core` 通过 `AtomUI.Native` 使用。相反,Dialog 的默认尺寸、 最大/最小尺寸策略、控件状态同步和模板生命周期仍属于上层控件库。 ## 当前依赖 | 依赖 | 用途 | 影响 | |---|---|---| | `Avalonia` | `Window`、`WindowBase`、geometry 和 platform handle | AtomUI 基础依赖 | | `NWayland` | `WlSurface`、`WlCompositor`、`WlRegion` | 会进入所有引用 Native 的依赖图 | `AtomUI.Native` 当前与 `Avalonia.Wayland` 共享 NWayland 类型。具体版本以集中包管理和最终 restore 依赖图为准;升级任一依赖时必须同步核对类型版本和跨包 ABI,不能把当前偶然一致视为兼容保证。 上层项目是否引用 `AtomUI.Native` 取决于是否存在真实底层 OS/native 调用点。不能为了让 `Core` 看起来 “纯净”而把 P/Invoke、native struct 或平台错误处理留在 `Core`;也不能因为某个 native 能力最终服务于 Window/Dialog,就把底层 OS 细节放回 `AtomUI.Desktop.Controls`。 未来 Mobile adapter 同样遵循这条边界:优先使用 Avalonia 公共 API;只有 Safe Area、system bar、input pane、返回手势、 haptic 或生命周期能力确实需要原生调用时才进入 Native。Native 负责底层资源和确定释放,Mobile Runtime 负责 `TopLevel` owner、订阅、snapshot 合并、取消和产品行为。 ## 目录和职责 ```text src/AtomUI.Native/ ├── AtomUI.Native.csproj ├── NativeWindowSizing.cs ├── WindowExtensions.cs ├── FileSystem/ │ └── NativeFileSystem.cs ├── Windows/ │ ├── WindowsCsdSizingHook.cs │ ├── WindowUtils.Interop.cs │ └── WindowUtils.Windows.cs ├── MacOS/ │ ├── WindowUtils.Interop.cs │ └── WindowUtils.MacOS.cs └── Linux/ ├── WindowUtils.Interop.cs ├── WindowUtils.Linux.cs ├── XcbConnectionHolder.cs ├── WaylandWindowReflectionExtensions.cs └── WaylandWindowUtils.cs ``` ### Windows - `SetWindowIgnoreMouseEventsWindows()` 修改 `WS_EX_TRANSPARENT/WS_EX_LAYERED`。 - `WindowsCsdSizingHook` 封装 opt-in 的 `WM_GETMINMAXINFO` track size 修正和 `WM_ENTERSIZEMOVE/WM_EXITSIZEMOVE` live resize 信号。 - Windows 目录可以封装 DWM 属性、系统 metric、Win32 消息结构体和受限的可释放 hook。 - Windows 目录不决定 live resize 策略、合成后端策略、CSD/SSD 策略或控件行为。 - 窗口装饰与 resize hit-test 由 Avalonia CSD 管理;AtomUI 不处理 `WM_NCCALCSIZE` 或 `WM_NCHITTEST`,不返回 resize hit-test。 - 标题栏按钮通过 Avalonia 公共 `WindowDecorationProperties.ElementRole` 接入原生行为, 不需要 AtomUI 自定义 caption WndProc hook。 - 允许 Native 层提供窄范围、显式 opt-in、可释放的 sizing/message helper,例如只处理 `WM_GETMINMAXINFO` 或 live resize 生命周期信号;这类 helper 不能实现第二套 window chrome。 ### macOS - Objective-C runtime 调用 `NSWindow.ignoresMouseEvents`。 - 查询和重排 standard window buttons。 - x64 的 32-byte `NSRect` 返回走 `objc_msgSend_stret`,其他架构走 `objc_msgSend`。 ### Linux/X11 - Xlib 设置 map 前初始 geometry 和 `WM_NORMAL_HINTS`。 - `_GTK_FRAME_EXTENTS` 告知 Mutter/KWin CSD 阴影范围。 - 进程级独立 XCB 连接复用 SHAPE input-region 请求。 X11 能力必须以 `IPlatformHandle.HandleDescriptor == "XID"` 为前置条件,不能只判断 Linux OS。 ### Linux/Wayland `WaylandWindowUtils` 只接受已经解析出的 NWayland `WlSurface/WlCompositor`,创建 region 并调用 `SetInputRegion()`。Avalonia 私有字段解析集中在 `WaylandWindowReflectionExtensions`,不能扩散到 `WaylandWindowUtils` 或上层业务控件。 但 Avalonia Wayland 后端的真实 surface 属于专用 worker。当前调用方从 UI 线程越过 `WXdgTopLevelProxy` 直接调用真实 `WlSurface`,不符合上游线程和重连契约。`DynamicDependency` 只保证 reflection metadata 不被裁剪,不能解决该问题。正确边界应由 Avalonia persistent surface/proxy 提供 input-region 方法,并通过 `WaylandWorkerClient.PostWithCommit` 下发。 ### FileSystem - `NativeFileSystem` 封装跨平台文件系统原生调用,例如 no-follow 打开文件和解析目录 canonical path。 - 文件系统能力可以被 `AtomUI.Core` 使用;判断标准是是否需要 P/Invoke、平台错误码、native handle 或 OS-specific flag,而不是调用方是否位于 Core。 - Native 层只负责底层安全打开、路径解析和错误转换,不决定 ThemeDefinition 的加载策略、搜索路径或 用户目录信任模型。 ## 设计约束 1. 平台判断和后端判断是两层条件。Linux 不等于 X11,非 X11 也不等于 Wayland。 2. 只有 Avalonia 公共 API 无法表达、且涉及原生调用或原生协议细节的能力才进入 Native。 3. Window 相关 native 能力可以进入 Native;限制点是不能在 Native 层拥有 Window/Dialog 控件策略。 4. Native 层可以持有原生资源或可释放 hook,但 owner 必须清晰,上层必须有明确释放点。 5. Native 层不修改 Avalonia control properties,不决定 resize band、主题 token 或 Dialog/Window 行为。 6. Native 层不订阅控件业务事件;需要事件驱动时,上层负责订阅 Avalonia 事件并调用 Native 能力。 7. 原生调用失败不能让 Window manager 的更新队列永久卡死;异步/延迟状态更新需要 `try/finally` 恢复标志。 8. AOT 要同时满足 metadata 保留和真实 publish;`DynamicDependency`、普通 build、源码字符串测试分别只能 覆盖一部分风险。 ## 已知结构问题 ### 平台依赖扩散 `AtomUI.Native` 当前只面向桌面控件等需要原生能力的上层库开放。`AtomUI.Desktop.Controls` 直接引用 `Avalonia.Desktop` 和 `Avalonia.Wayland`,Browser 当前通过 WASM 内部 item 过滤部分 desktop assembly, 这只是构建补偿,不是清晰的依赖边界。 长期建议把 desktop bootstrap 与具体后端拆成可选 assembly,例如 X11、Wayland、Win32、macOS backend 包;Browser 只引用平台无关 controls,不应先引入桌面包再从 bundle 中删除 assembly。 ### API 命名和校验 `WindowExtensions` 只承担内部跨平台路由,具体实现保留在 `Windows`、`MacOS` 和 `Linux` 目录。 只有 Avalonia 公共 API 无法表达的能力才进入 Native;平台实现应统一校验 handle descriptor、零句柄、 尺寸范围和平台。是否继续拆分文件取决于资源所有权和生命周期复杂度,不为了形式上的分层搬移代码。 ### 测试层级 当前 Native 相关测试主要读取源码并断言字符串。这能防止某些旧代码回归,但不能验证 ABI、线程、资源释放、 协议顺序或真实 NativeAOT。至少需要: - 纯计算和参数校验单元测试。 - 可替换 native façade 的调用顺序/错误路径测试。 - X11/Wayland 集成测试或最小 smoke app。 - Linux/Windows/macOS 的 NativeAOT publish matrix。 ## 依赖升级检查 Native 架构结论以 AtomUI 的平台边界、公开契约和验证矩阵为准。升级 Avalonia 或原生协议依赖时,至少重新验证: - Wayland proxy、worker 和 persistent surface 的线程所有权与 commit 顺序。 - CSD/SSD 协商、shadow extents 和 window geometry 的状态传播。 - X11 handle descriptor、drawn decorations gating 和 input-region 行为。 - Win32/macOS 平台能力仍由公开 API 或隔离的 Native 边界承担。 外部框架的类型名可以作为调查入口,但文件路径、源码行号和某次源码快照都不是 AtomUI 的架构契约。