5.9 KiB
AtomUI.Native 架构
定位
AtomUI.Native 是 AtomUI 的内部原生调用层。它只负责在上层已经确定平台和窗口后端后执行原生操作,
不负责窗口主题、CSD/SSD 策略、Avalonia 私有对象发现或控件生命周期。
AtomUI.Desktop.Controls
- 选择 Window chrome manager
- 管理 Window 事件、属性和模板生命周期
- 维护 Avalonia private API reflection boundary
|
v
AtomUI.Native
- 校验原生 handle / 参数
- 调用 Win32、Objective-C、Xlib/XCB 或 NWayland
- 管理原生资源和错误边界
所有成员目前都是 internal,通过 InternalsVisibleTo 向 AtomUI.Core、
AtomUI.Desktop.Controls 和预留的 AtomUI.Mobile.Controls 开放。它是实现包,不是公共 Native SDK。
当前依赖
| 依赖 | 用途 | 影响 |
|---|---|---|
Avalonia |
Window、WindowBase、geometry 和 platform handle |
AtomUI 基础依赖 |
NWayland 0.11.0 |
WlSurface、WlCompositor、WlRegion |
会进入所有引用 Native 的依赖图 |
Avalonia.Wayland 12.1.0 同样依赖 NWayland 0.11.0。类型版本当前一致,但这不是稳定的跨包 ABI
保证;升级 Avalonia.Wayland 时必须同步核对 NWayland 版本。
目录和职责
src/AtomUI.Native/
├── AtomUI.Native.csproj
├── WindowExtensions.cs
├── Windows/
│ ├── WindowUtils.Interop.cs
│ └── WindowUtils.Windows.cs
├── MacOS/
│ ├── WindowUtils.Interop.cs
│ └── WindowUtils.MacOS.cs
└── Linux/
├── WindowUtils.Interop.cs
├── WindowUtils.Linux.cs
├── XcbConnectionHolder.cs
├── ClickThroughShadowExtensions.cs
└── WaylandWindowUtils.cs
Windows
SetWindowIgnoreMouseEventsWindows()修改WS_EX_TRANSPARENT/WS_EX_LAYERED。- 该目录不承担 live resize、合成后端、CSD 或 non-client frame 策略。
- 窗口装饰与 resize hit-test 由 Avalonia CSD 管理;AtomUI 不处理
WM_NCCALCSIZE。 - 标题栏按钮通过 Avalonia 公共
WindowDecorationProperties.ElementRole接入原生行为, 不需要 AtomUI WndProc hook。
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 私有字段或查找 WindowImpl。
但 Avalonia 12.1 的真实 surface 属于专用 Wayland worker。当前调用方从 UI 线程越过
WXdgTopLevelProxy 直接调用真实 WlSurface,不符合上游线程和重连契约。DynamicDependency 只保证
reflection metadata 不被裁剪,不能解决该问题。正确边界应由 Avalonia persistent surface/proxy 提供
input-region 方法,并通过 WaylandWorkerClient.PostWithCommit 下发。
设计约束
- 平台判断和后端判断是两层条件。Linux 不等于 X11,非 X11 也不等于 Wayland。
- Avalonia private reflection 留在
AtomUI.Desktop.Controls/Reflection或对应 Window 适配边界, Native 只接收已经确定的原生对象。 - 原生资源必须有明确 owner 和释放点。临时 region 在请求入队后销毁;长期连接要记录进程生命周期策略。
- 原生调用失败不能让 Window manager 的更新队列永久卡死;异步/延迟状态更新需要
try/finally恢复标志。 - AOT 要同时满足 metadata 保留和真实 publish;
DynamicDependency、普通 build、源码字符串测试分别只能 覆盖一部分风险。 - Native 层不修改 Avalonia control properties,不订阅 Window 事件,不决定 resize band 或主题 token。
已知结构问题
平台依赖扩散
AtomUI.Native 被 AtomUI.Core 引用,因此 NWayland 会出现在 Browser 共享依赖闭包;
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。
事实源
Avalonia 行为以仓库同级 ../ReferenceProjects/Avalonia 的 12.1.0 tag
(commit a21b9f573172f705a944dcc8aad7f036b9986f39)为准,重点文件:
src/Avalonia.Wayland/WindowImpl.cssrc/Avalonia.Wayland/WindowImplBase.cssrc/Avalonia.Wayland/Server/WaylandWorkerClient.cssrc/Avalonia.Wayland/Server/Persistent/WSurface.cssrc/Avalonia.Controls/TopLevelHost.Decorations.cssrc/Avalonia.X11/X11Window.cs