docs: explain Tessera modules and execution flows in Chinese

This commit is contained in:
2026-11-11 23:36:03 +08:00
parent 4c3fc8b5dd
commit 1fedd21d3c
77 changed files with 1418 additions and 0 deletions
+34
View File
@@ -1,3 +1,7 @@
//! winit 原生应用生命周期和窗口事件入口。这里创建窗口、发布逻辑视口、转发输入,并把不可变文档画到原生表面。
//! 窗口线程不执行 Endor 业务回调;共享状态通过锁读取,实际 VM 更新由 runtime worker 串行完成。
//! 侧栏、页面与开发工具有各自命中区域。拖动捕获必须保留最初的视口目标,不能随指针经过其他组件而跳转。
//!
use std::{
num::NonZeroU32,
sync::{Arc, RwLock},
@@ -24,6 +28,7 @@ use crate::{
};
#[derive(Clone, Debug)]
/// worker 到原生事件循环的通知,携带更新/错误/退出状态而不是可执行 VM 引用。
pub enum AppEvent {
RuntimeFailed { message: String },
DocumentUpdated,
@@ -31,6 +36,7 @@ pub enum AppEvent {
ConsoleFailed { message: String, source: String },
}
/// 一个原生窗口的宿主状态;主窗口还协调子窗口资源,共用同一运行时与输入通道。
pub struct TesseraApp {
resource: u64,
control: crate::api::RuntimeControl,
@@ -63,6 +69,7 @@ pub struct TesseraApp {
}
impl TesseraApp {
/// 构造本类型并初始化其状态;资源建立和默认字段以函数体为准。
pub fn new(
namespace: Arc<RwLock<NamespaceState>>,
activity: Activity,
@@ -79,6 +86,7 @@ impl TesseraApp {
))
}
/// 建立窗口宿主状态并复用权威输入客户端,避免子窗口使用滞后的独立事件队列。
fn with_event_client(
namespace: Arc<RwLock<NamespaceState>>,
activity: Activity,
@@ -118,6 +126,7 @@ impl TesseraApp {
}
}
/// 将已发布窗口文档与原生资源对齐;session 更换时丢弃旧域的子窗口。
fn reconcile_windows(&mut self, event_loop: &ActiveEventLoop) {
if self.resource != crate::window::MAIN_WINDOW {
return;
@@ -183,6 +192,7 @@ impl TesseraApp {
}
}
/// 只应用当前运行时身份的窗口命令;执行前从共享队列取走,避免重复执行。
fn apply_window_commands(&mut self) {
let Ok(mut namespace) = self.namespace.write() else {
return;
@@ -236,6 +246,7 @@ impl TesseraApp {
self.publish_viewport();
}
/// 将真实原生窗口尺寸换算成扣除侧栏的逻辑页面尺寸,并发布给 worker。
fn publish_viewport(&self) {
let Some(window) = &self.window else {
return;
@@ -280,12 +291,14 @@ impl TesseraApp {
}
}
/// 仅请求原生事件循环安排重绘,不在调用处立即递归绘制。
fn request_redraw(&self) {
if let Some(window) = &self.window {
window.request_redraw();
}
}
/// 通过托管开发工具入口打开指定工具页面,保留对应窗口上下文。
fn open_developer_tool(&mut self, name: &str) {
let input = self.namespace.read().ok().map(|namespace| {
let frame = &namespace.document.frame;
@@ -313,6 +326,7 @@ impl TesseraApp {
self.request_redraw();
}
/// 接收完整文档更新,协调子窗口和原生命令,再更新输入焦点并请求重绘。
fn document_updated(&mut self, event_loop: &ActiveEventLoop) {
self.reconcile_windows(event_loop);
self.apply_window_commands();
@@ -343,6 +357,7 @@ impl TesseraApp {
self.request_redraw();
}
/// 先处理宿主管理输入、选择与快捷键,再按焦点决定是否交给页面。
fn handle_keyboard(&mut self, event: &winit::event::KeyEvent) {
let command = self.modifiers.super_key() || self.modifiers.control_key();
if command
@@ -486,6 +501,7 @@ impl TesseraApp {
self.request_redraw();
}
/// 判断指针是否被侧栏或管理面板覆盖,阻止一次点击同时落入页面。
fn guest_covered(&self, point: Point) -> bool {
if self.sidebar.covers(point) {
return true;
@@ -501,6 +517,7 @@ impl TesseraApp {
.contains(point)
}
/// 排除宿主管理区域后,把原生指针转换到页面使用的坐标系。
fn guest_point(&self) -> Option<Point> {
if self.guest_covered(self.pointer) {
return None;
@@ -518,6 +535,7 @@ impl TesseraApp {
Some(current.document.frame.surface.to_world(point))
}
/// 从页面坐标与当前帧命中结果构造带版本的点击输入。
fn guest_hit(&self) -> Option<crate::events::Input> {
let point = self.guest_point()?;
let current = self.namespace.read().ok()?;
@@ -540,6 +558,7 @@ impl TesseraApp {
})
}
/// 将标签快捷键转换为当前窗口/帧中的明确页面动作。
fn send_tab_shortcut(&mut self, close: bool) -> bool {
let input = self.namespace.read().ok().and_then(|namespace| {
let frame = &namespace.document.frame;
@@ -577,6 +596,7 @@ impl TesseraApp {
}
}
/// 处理侧栏展开、工具入口和页面管理,尺寸变化还需重新发布可用视口。
fn sidebar_action(&mut self, action: crate::sidebar::Action) {
use crate::sidebar::Action;
match action {
@@ -619,6 +639,7 @@ impl TesseraApp {
self.request_redraw();
}
/// 在手势开始时捕获具体相机视口 ID,后续拖动保持同一目标。
fn begin_pan(&mut self) -> bool {
self.pan_viewport = None;
let Some(point) = self.guest_point() else {
@@ -632,6 +653,7 @@ impl TesseraApp {
self.pan_viewport.is_some() || frame.surface.mode != crate::page::Mode::Window
}
/// 把窗口位移/缩放转换为捕获视口的纯数据相机事件,处理侧栏和页面视角的尺度差异。
fn page_view(&mut self, kind: &str, delta: [f32; 2]) {
if !self.panning && self.guest_covered(self.pointer) {
return;
@@ -724,6 +746,7 @@ impl TesseraApp {
}
}
/// 把已经构造的页面输入交给有界客户端,保持 GUI 线程不直接调用 VM。
fn send_guest(&mut self, event: crate::events::Input) {
if !self.event_client.send(event) {
self.developer_tools.input_error = "Native event queue is unavailable or full".into();
@@ -731,6 +754,7 @@ impl TesseraApp {
}
}
/// 把页面拥有焦点时的键盘动作转换为托管事件,保留按下/释放配对。
fn handle_guest_key(&mut self, event: &winit::event::KeyEvent) -> bool {
let Key::Named(key) = &event.logical_key else {
return false;
@@ -800,6 +824,7 @@ impl TesseraApp {
false
}
/// 按平台窗口属性创建原生窗口、软件表面和输入法支持,再公布实际逻辑视口。
fn create_native(&mut self, event_loop: &ActiveEventLoop) -> anyhow::Result<()> {
if self.window.is_some() {
return Ok(());
@@ -847,6 +872,7 @@ impl TesseraApp {
Ok(())
}
/// 停止新的交互并请求运行时清理;原生事件循环等待完成通知后退出。
fn request_exit(&mut self) {
if self.exit_requested {
return;
@@ -863,6 +889,7 @@ impl TesseraApp {
}
}
/// 把原生应用记录的最终错误反馈给 main 的退出结果。
pub fn exit_result(&self) -> anyhow::Result<()> {
if let Some(error) = &self.native_error {
anyhow::bail!("{error}");
@@ -870,6 +897,7 @@ impl TesseraApp {
Ok(())
}
/// 包装一次实际绘制,统一记录故障并避免对同一错误反复发送通知。
fn redraw(&mut self) {
#[cfg(target_os = "macos")]
if let Some(window) = self.window.as_ref() {
@@ -891,6 +919,7 @@ impl TesseraApp {
}
}
/// 读取完整发布文档,生成整窗显示列表,写入原生像素表面并呈现;错误交由外层记录。
fn try_redraw(&mut self) -> anyhow::Result<()> {
let guest_cursor = self.guest_hit().is_some()
|| self
@@ -956,6 +985,7 @@ impl TesseraApp {
}
impl ApplicationHandler<AppEvent> for TesseraApp {
/// 处理 OS 直接结束事件循环的收尾,尝试在明确时限内等待运行时清理。
fn exiting(&mut self, _: &ActiveEventLoop) {
// OS termination can bypass CloseRequested. The loop is already ending;
// use a bounded fallback rather than silently dropping every callback.
@@ -973,8 +1003,10 @@ impl ApplicationHandler<AppEvent> for TesseraApp {
}
}
/// 当前不在进入等待前轮询工作;文档通知和原生事件负责唤醒循环,避免空闲忙转。
fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {}
/// 应用获得原生活跃上下文时建立窗口,并仅在需要时请求初始页面。
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
if self.resource == crate::window::MAIN_WINDOW
&& !self.startup_page_requested
@@ -998,6 +1030,7 @@ impl ApplicationHandler<AppEvent> for TesseraApp {
}
}
/// 处理 worker 发回的文档更新、故障和退出完成通知,不在 GUI 线程执行源回调。
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: AppEvent) {
if self.control.is_exiting() && !matches!(&event, AppEvent::ShutdownComplete { .. }) {
return;
@@ -1029,6 +1062,7 @@ impl ApplicationHandler<AppEvent> for TesseraApp {
}
}
/// 处理原生尺寸、输入、焦点和关闭事件;先判断宿主控件,再转发页面事件。
fn window_event(
&mut self,
_event_loop: &ActiveEventLoop,