R6.12 round 2 fix: unbundled workers ask for accessory

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-10-15 19:56:48 -04:00
1 parent 1317c4ad39
commit f72528c474
4 files changed
+30 -8

No files matched your search

+2 -2
View File
@@ -170,7 +170,7 @@ tests/scripts/pdf-recovery.sh 真窗口 ElyPDF:加锁文件的封存恢复点
tests/scripts/autosave.sh 真窗口 ElyDoc:自动保存开关、停手即写、外部改动不覆盖(需辅助功能权限)
tests/scripts/print.sh 真窗口 ElyDoc:打印用文档自己的纸张,取消不动文档(需辅助功能权限)
tests/scripts/show-fullscreen.sh 真窗口 ElyShow:F5 放映的窗口盖住整块屏幕(菜单栏与程序坞之上,需辅助功能权限)
tests/scripts/dock-macos.sh dist 里 ElyDoc、ElyTable、ElyShow 各启动数次:LOK worker 从未登记为程序坞应用,图块照出
tests/scripts/dock-macos.sh dist 里 ElyDoc、ElyTable、ElyShow 与包外的 target/debug/ely-doc 各启动数次:LOK worker 从未登记为程序坞应用,图块照出
tests/scripts/windows-installer.sh 假应用的安装程序:所选目录原有的文件经两次安装与卸载都在,旧版按注册表清理,文件被占用或程序在运行时什么也不改,写不进时放回旧版(缺 makensis 时 SKIP)
tests/scripts/types.sh packaging/types.tsv 的文件类型在 Linux 桌面项、Windows 安装程序与 macOS 文档类型里一致,从不设为默认
tests/scripts/layout.sh 真窗口:六个应用在 640、800、1100 宽下无元素越出窗口左右,留截图(需辅助功能与屏幕录制权限)
@@ -304,5 +304,5 @@ cargo run -p ely-doc 启动一个应用(ElyDoc 先 cargo build -p ely
- 2026-10-15(用户报:ElyMark 代码块后的“你好↵测试”离开输入框后成了“你好 测试”):单个换行照 Typora 的默认(编辑时保留,导出与打印不保留):组件库 93efa7f 起 `MarkdownReader::new`(屏上:可视、预览、右键与命令的读法)把软换行读作换行,`MarkdownReader::joined`(输出)照 GFM 读作空格;标题的大纲与目录文字照旧一行。ElyMark 的 HTML、PDF、富文本复制与纯文本导出用 `joined`(R6.7)。组件库 c31d092 与 26af4be:画出成一个换行的 CRLF 对回其起点(原先按在 CRLF 行末键入落在 CR 与 LF 之间),行内代码照留两字则逐字对回。
- 2026-10-15(用户报:ElyMark 源码模式“测”后的插入点画在“测”的中间):组件库 `CodeEditor` 原按“列 × m 的宽”放插入点、选区、按下处与输入法框,中日韩字与表情约宽两格。组件库 9fb607b 起按 gpui 排好的这一行定位(`editor::measure`,含着色带来的字重),块状与下划线插入点取所在字的宽;标尺与缩进参考线仍按列(R6.8)。上下移动仍按字数记目标列。cd61653:按下处取最近的字首或行末(gpui 的 `closest_index_for_x` 越过末字字首即给行末);上次绘制得出的括号与配对位置只属当时的文字(`Buffer` 每次改动换一个戳),输入法改字后、下次绘制前的测量不用它们(原先把新字切进不同字体段,DirectWrite 崩溃)。
- 2026-10-15(用户报:ElyMark 三、四级标题不显眼):组件库 5954132 起标题字号随正文按 Typora 的倍数(一至六级 2.25、1.75、1.5、1.25、1、1),一律加粗,六级为次要色,行高为字号的 1.3 倍(原为固定的 24、20、16、14 像素,正文 13,三、四级只是中等字重)(R6.9)。90bd37b:粗体与标题同一字重(原粗体为半粗,标题里的粗体反而更细,正文粗体随之由半粗改为粗,同 Typora);标题行高按自身字号取 1.3 倍。Windows 真窗口核对(`.work/r69`):可视模式各级标题分明、“你好↵测试”两行,源码模式“测”后的插入点落在两字之间。
- 2026-10-15(用户报:macOS 打开一个文档,程序坞里有两个同样的图标):LOK worker 在应用包的 `Contents/MacOS` 里启动 AppKit,系统按包的 Info.plist 把它也登记为常规应用(`lsappinfo` 里应用与 worker 都是 Foreground),程序坞多一个图标;内核自己从不设激活策略。worker 在内核启动 AppKit 之前(`Lok::hook` 打开内核之后、调钩子之前)把本进程主包信息里的 `LSUIElement` 设为真,AppKit 登记时即为辅助应用(无程序坞图标、无菜单栏,仍可建屏外窗口);钩子之后核对激活策略是辅助,不是即报错、不启动(`ffi/accessory.rs`)。原先在登记之后才改策略,审查实测 15 次启动有 11 次先登记为 Foreground 约 30 毫秒(R6.12 第 1 轮)。`tests/scripts/dock-macos.sh` 连续启动三个应用,从 worker 启动起采样其类型到首块图块,见 Foreground 即失败(R6.12)。
- 2026-10-15(用户报:macOS 打开一个文档,程序坞里有两个同样的图标):LOK worker 在应用包的 `Contents/MacOS` 里启动 AppKit,系统按包的 Info.plist 把它也登记为常规应用(`lsappinfo` 里应用与 worker 都是 Foreground),程序坞多一个图标;内核自己从不设激活策略。worker 在内核启动 AppKit 之前(`Lok::hook` 打开内核之后、调钩子之前)把本进程主包信息里的 `LSUIElement` 设为真,AppKit 登记时即为辅助应用(无程序坞图标、无菜单栏,仍可建屏外窗口);钩子之后核对激活策略是辅助,不是即报错、不启动(`ffi/accessory.rs`);包外的 worker(`cargo run`、单测)无包可登记,策略为禁止,此时改设辅助(R6.12 第 2 轮)。原先在登记之后才改策略,审查实测 15 次启动有 11 次先登记为 Foreground 约 30 毫秒(R6.12 第 1 轮)。`tests/scripts/dock-macos.sh` 连续启动三个应用与包外的开发构建,从 worker 启动起采样其类型到首块图块,见 Foreground 即失败(R6.12)。
- 2026-10-15(用户报:ElyShow 编辑区滚轮与上下键不换页,三端):内核在未选中对象时把上下键当作滚动窗口(`fupoor.cxx`),Ely 的画布整页适合、无处可滚,滚轮同样。`LokView::turn_parts`(ElyShow 首次适合时调用)之后:整页可见时滚轮换页(`view/turn.rs`:每格一页;触控板一次手势只换一页,惯性不算,静止 250 毫秒或新手势再计),未选中对象、未编辑文字时上下键换页;视图发 `Turn`,ElyShow 从视图所示的页起算(连续换页累加),经缩略图条同一路径 `show_part`,到首末页即停;后台读回的当前页只在视图已无待落地输入时采用,排队的换页不被先前的读取拉回(R6.13)。
+13 -2
View File
@@ -13,6 +13,8 @@ unsafe extern "C" {
/// NSApplicationActivationPolicyAccessory: no Dock icon, no menu bar.
const ACCESSORY: isize = 1;
/// NSApplicationActivationPolicyProhibited: an unbundled worker starts so.
const PROHIBITED: isize = 2;
type Id = *mut c_void;
@@ -38,7 +40,7 @@ fn get(object: Id, selector: &std::ffi::CStr) -> io::Result<Id> {
Ok(result)
}
/// Marks this process a UI element before the kit registers it.
/// Marks the process a UI element before registration.
pub fn hide() -> io::Result<()> {
// The kit reads the bundle's LSUIElement when it registers.
let info = get(get(class(c"NSBundle")?, c"mainBundle")?, c"infoDictionary")?;
@@ -59,9 +61,18 @@ pub fn hide() -> io::Result<()> {
/// Fails unless the kernel's application came up an accessory.
pub fn check() -> io::Result<()> {
type Policy = unsafe extern "C" fn(Id, Id) -> isize;
type SetPolicy = unsafe extern "C" fn(Id, Id, isize) -> i8;
let policy: Policy = unsafe { std::mem::transmute(send()) };
let set: SetPolicy = unsafe { std::mem::transmute(send()) };
let app = get(class(c"NSApplication")?, c"sharedApplication")?;
let found = unsafe { policy(app, sel_registerName(c"activationPolicy".as_ptr())) };
let read = || unsafe { policy(app, sel_registerName(c"activationPolicy".as_ptr())) };
let mut found = read();
if found == PROHIBITED {
// Outside a bundle nothing registers; accessory lets it draw.
let done = unsafe { set(app, sel_registerName(c"setActivationPolicy:".as_ptr()), ACCESSORY) };
found = read();
log::info!("lok: the unbundled worker asked for accessory ({done})");
}
if found != ACCESSORY {
return Err(io::Error::other(format!("the worker's activation policy is {found}, not accessory")));
}
+5
View File
@@ -0,0 +1,5 @@
FAIL
- crates/ely-lok/src/ffi/accessory.rs:65 — Unbundled macOS workers now fail during startup. Setting the main bundle dictionary's `LSUIElement` leaves their activation policy at 2, which this check rejects. On macOS 27.0.1 arm64, the independently built round 2 worker exited 1 before answering its first IPC request with `the worker's activation policy is 2, not accessory`; the independently built round 1 worker, using the same engine and fresh profiles, loaded and rendered Writer, Calc and Impress documents and shut down successfully (`.work/R6.12-r2/unbundled-r2-worker.log`, `unbundled-r1.log`). This breaks the standalone worker layout used by `cargo run` and the macOS worker tests. Establish an appropriate policy for unbundled workers while retaining the pre-registration bundle fix, and cover both launch layouts in the regression test.
- crates/ely-lok/src/ffi/accessory.rs:41 — The new documentation comment contains eleven words, exceeding the explicit ten-word limit. Running `python tests/scripts/comments.py` exits 1 and identifies this line (`.work/R6.12-r2/comments.log`). Shorten it to ten words or fewer, or remove it.
+10 -4
View File
@@ -4,7 +4,8 @@ set -euo pipefail
[ "$(uname)" = Darwin ] || { echo "SKIP: macOS only"; exit 0; }
runs=${ELY_DOCK_RUNS:-5}
apps=("$@")
[ ${#apps[@]} -gt 0 ] || apps=(dist/ElyDoc.app dist/ElyTable.app dist/ElyShow.app)
# Bundled apps from dist and one unbundled dev build.
[ ${#apps[@]} -gt 0 ] || apps=(dist/ElyDoc.app dist/ElyTable.app dist/ElyShow.app target/debug/ely-doc)
# One launch: samples the worker's type until a tile shows.
launch() {
@@ -35,9 +36,14 @@ launch() {
}
for app in "${apps[@]}"; do
[ -d "$app" ] || { echo "FAIL: $app is missing"; exit 1; }
bin=$(find "$app/Contents/MacOS" -maxdepth 1 -type f -name 'ely-*' ! -name 'ely-lok-worker' | head -1)
[ -n "$bin" ] || { echo "FAIL: $app has no app binary"; exit 1; }
if [ -f "$app" ]; then
bin=$app
[ -x "$(dirname "$app")/ely-lok-worker" ] || { echo "FAIL: no worker beside $app (cargo build -p ely-lok --bins)"; exit 1; }
else
[ -d "$app" ] || { echo "FAIL: $app is missing"; exit 1; }
bin=$(find "$app/Contents/MacOS" -maxdepth 1 -type f -name 'ely-*' ! -name 'ely-lok-worker' | head -1)
[ -n "$bin" ] || { echo "FAIL: $app has no app binary"; exit 1; }
fi
log="$HOME/Library/Application Support/ElyOffice/$(basename "$bin")/ely.log"
for _ in $(seq 1 "$runs"); do launch "$bin" "$log"; done
done