跳至内容
架构

架构

Flutter 在 Denial 中不是客户端窗口或覆盖层。引擎通过原生 Embedder API 嵌入, AOT 编译的 Dart 桌面外壳运行在 deniald 内。Rust 与 Flutter 共同构成一个逻辑 桌面场景,同时原生资源仍由 Rust 管理。

运行时边界

Rust、Smithay 与仓库内的 Volition 显示组件负责:

  • Wayland 显示、协议状态、Xwayland 与客户端缓冲区;
  • 输入设备、焦点、抓取、原生快捷键、文本输入与绘图板事件;
  • 显示验证、DRM 设备、GBM/EGL 资源、原子 KMS 显示与翻页;
  • 持久设置、显示/会话权限、原生音频与亮度控制以及原生资源生命周期。

嵌入式 Dart 桌面外壳负责:

  • 窗口布局与可见桌面策略;
  • 启动器、仪表板、概览、系统栏、通知面板、通知与锁屏;
  • 动画、手势行为和桌面外壳交互区域;
  • 网络、蓝牙、媒体、电池与电源模式的桌面服务客户端;
  • 把应用纹理和桌面外壳界面合成为桌面场景。

denial-settings 是独立的 Flutter Wayland 应用,通过带版本的控制套接字与 deniald 通信,因此它的渲染负载与嵌入式桌面外壳隔离,验证和持久化仍由合成器负责。 denial-portal 通过标准桌面 Settings Portal 公布已提交的配色与强调色。

帧路径

Wayland 客户端缓冲区保持为原生资源,并作为 Flutter 外部纹理导入。Dart 构建一个跨越 全部输出的逻辑场景。Denial 的 Flutter 分支会把该保留场景中的对应部分投影到各物理 输出自己的合成器帧缓冲池:

Wayland 客户端 ──> Rust / Smithay ──> 外部纹理 ──> 逻辑 Flutter 场景
        输入  <──── 原生路由  <──── 桌面外壳命中区域 <──────────┘
显示器 A <── Volition / 原子 KMS <── 原生栅栏 <── 输出 A 缓冲池
显示器 B <── Volition / 原子 KMS <── 原生栅栏 <── 输出 B 缓冲池

正常 Flutter 路径不再使用共享扫描图集。每个输出都在该连接器的物理模式尺寸下拥有轮换的 三缓冲池。Embedder 的 FlutterCompositor backing-store 回调把已授权的帧缓冲借给 Flutter,并把完成的缓冲区、损伤区域和原生 GPU 栅栏交回 Rust。KMS 仍占有的缓冲区不会 被再次渲染。

当截图或整个桌面的 screencopy 需要统一图像时,Denial 会临时把当前输出缓冲区组装为 桌面图集。该捕获表示不会用于正常扫描显示。

独立输出时钟

KMS 翻页就是帧时钟。每个输出可按自己的刷新时间线请求和显示后继帧;缓慢或耗尽的 缓冲池只会向该输出施加背压,而不会产生全局光栅锁。外部纹理更改按输出归属跟踪, Flutter 只渲染当前事务已授权的输出。

热插拔不会决定 Wayland 会话的生命周期。即使全部输出都断开,客户端与合成器状态仍会 保持活动;重新连接输出后,Denial 会重建显示路径并让会话重新可见。

每个轮换缓冲区分别保留部分损伤。Wayland 帧回调与显示反馈跟随实际显示表面的输出。 屏幕捕获也由所选输出的真实帧周期推进,而不是让事件循环空转。

逻辑坐标与缩放

桌面、输出、窗口、输入与结构化光标坐标保持为逻辑坐标。Flutter 以最大活动输出缩放 接收一个逻辑桌面;每个输出投影再把自身逻辑矩形映射到连接器的原生像素尺寸与变换。 较低缩放输出会被采样到自己的物理目标,Denial 不会放大已经完成的整桌面扫描图像。

原生 Wayland 表面会收到当前所属输出的精确首选分数缩放。Xwayland 则按最大活动输出 使用一个会话级缩放,因为单个 X 服务器无法让每台显示器独立缩放窗口。默认使用精确 分数缩放;对于兼容性模式下表现更好的应用,可设置 DENIAL_XWAYLAND_SCALE_MODE=integer,把会话缩放向上取整。

光标尺寸以物理像素定义。客户端提供的 Wayland 与 X11 光标表面、输出变换、分数缩放 及光标帧回调都会先在原生边界转换,再由 Flutter 绘制软件光标。

合成器边界上的 Impeller

Impeller GLES 是 Denial 默认的 Flutter 渲染器。固定版本的 Flutter 与 Skia 分支将 Impeller 接入合成器拥有的输出 backing store,而不是另一个桌面提供的窗口。该集成 处理精确 FBO 选择、无可用目标的帧、已有缓冲区损伤、外部纹理生命周期、原生栅栏、 打包深度/模板存储及桌面背景效果。

Skia/Ganesh 仍编译在同一个固定引擎世代中作为兼容后备。可通过打包会话覆盖 DENIAL_FLUTTER_RENDERER=skia 选择它,无需另一个引擎软件包。

输入与表面归属

物理事件通过 Smithay 的 libinput 后端进入。Rust 先解析原生快捷键、指针约束、焦点、 移动/调整大小抓取及 Wayland 表面树。Dart 发布有界的桌面外壳命中区域和窗口内容矩形, 使原生路由无需转移原生句柄即可判断事件属于桌面外壳还是应用。

协议覆盖相对与绝对指针输入、触摸、键盘与文本输入状态、内置键盘与外部输入法路径、 客户端光标表面、输出归属、表面变换、alpha modifier 与 tablet-v2 数据。直接触摸 窗口手势在原生表面边界识别,因此即使应用不理解 Denial 桌面外壳手势,也能继续工作。

协议与信任

合成器和嵌入式桌面外壳通过有界、带版本的 FlatBuffers 协议通信。Dart 只接收不可变 元数据与数字资源标识,不拥有文件描述符、Wayland 对象、EGL 图像或 KMS 缓冲区; 嵌入式 Dart 也不会启动辅助进程。Flutter 把经过验证的操作和交互几何信息发回 Rust。

外部客户端使用另一个带版本的 Unix 控制套接字。合成器验证请求,通过文档修订号避免 设置更新丢失,并把已接受工作排入事件循环。实时显示更改是原生事务:在十秒确认回滚 期间,上一个 DRM 与 Flutter 状态会保持可用。

Bundle 兼容性与自定义桌面外壳

deniald、Flutter 引擎与编译后的桌面外壳构成一个经过测试的世代。替代 bundle 必须 匹配原生协议与引擎 ABI。自定义桌面外壳应导入受支持的 package:denial_dart_shell/denial.dart 边界并以 runDenialShell 启动;软件包外部 代码不应导入 lib/src

替代桌面外壳提供移动端和桌面端功能场景,而 Denial 保留生命周期、主题、本地化、 安全锁屏、输入发布、光标、软键盘、截图选择及覆盖层顺序。它仍是受信任的会话代码, 可访问官方桌面外壳公开的全部原生能力。开发时请随时准备好 denialctl ui restore

每个物理扫描目标的任一轴上限为 16,384 像素,全部活动输出缓冲池的总分配量上限为 1 GiB。不受支持的模式会明确失败,而不是被静默裁剪。