From 09d2a6b68132314df3555e87f97971a5ddce9088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Sat, 10 Oct 2026 23:40:55 -0400 Subject: [PATCH] Windows: no console, app icons, Calc tiles paint, theme switch no edit Release apps use the GUI subsystem; workers, Git and cmd start with CREATE_NO_WINDOW. Each exe embeds its icon as resource 1, which gpui also loads for the window. Patch 0044: Win32 devices take no client buffer, so tiles and slide layers paint at full size, then copy. ely.xcd gives both schemes one notes colour: Calc rewrote the comment style on each switch and left an undo step. lo-patches.sh keeps LF. Co-Authored-By: Claude Opus 5.5 (1M context) --- Cargo.lock | 9 +++ Cargo.toml | 1 + agents.md | 1 + apps/ely-agent/Cargo.toml | 4 ++ apps/ely-agent/src/main.rs | 3 + apps/ely-doc/Cargo.toml | 4 ++ apps/ely-doc/src/main.rs | 3 + apps/ely-mail/Cargo.toml | 4 ++ apps/ely-mail/src/main.rs | 3 + apps/ely-mark/Cargo.toml | 4 ++ apps/ely-mark/src/main.rs | 3 + apps/ely-pdf/Cargo.toml | 4 ++ apps/ely-pdf/src/main.rs | 3 + apps/ely-show/Cargo.toml | 4 ++ apps/ely-show/src/main.rs | 3 + apps/ely-table/Cargo.toml | 4 ++ apps/ely-table/src/main.rs | 3 + apps/ely-tree/Cargo.toml | 4 ++ apps/ely-tree/src/main.rs | 3 + crates/ely-ipc/src/lib.rs | 12 ++++ crates/ely-lok/src/client.rs | 2 +- crates/ely-lok/src/client/tests/sheet.rs | 15 +++++ crates/ely-pdf-engine/src/client.rs | 2 +- crates/ely-platform/Cargo.toml | 1 + crates/ely-platform/src/apps.rs | 2 +- crates/ely-platform/src/git.rs | 4 +- packaging/libreoffice/ely.xcd | 2 +- packaging/windows/icon.rs | 21 ++++++ .../0044-lok-win32-paints-then-copies.patch | 65 +++++++++++++++++++ tests/scripts/lo-patches.sh | 2 + 30 files changed, 189 insertions(+), 6 deletions(-) create mode 100644 packaging/windows/icon.rs create mode 100644 patches/libreoffice/0044-lok-win32-paints-then-copies.patch diff --git a/Cargo.lock b/Cargo.lock index e29711b..7a8b0ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1923,6 +1923,7 @@ version = "0.1.3" dependencies = [ "ely-platform", "ely-ui", + "embed-resource", ] [[package]] @@ -1938,6 +1939,7 @@ dependencies = [ "ely-office", "ely-platform", "ely-ui", + "embed-resource", "env_logger", "gpui-pre", "image", @@ -2032,6 +2034,7 @@ version = "0.1.3" dependencies = [ "ely-platform", "ely-ui", + "embed-resource", ] [[package]] @@ -2046,6 +2049,7 @@ dependencies = [ "ely-platform", "ely-ui", "ely-web-content", + "embed-resource", "futures", "gpui-pre", "jiff", @@ -2086,6 +2090,7 @@ dependencies = [ "ely-pdf-engine", "ely-platform", "ely-ui", + "embed-resource", "gpui-pre", "image", "log", @@ -2117,6 +2122,7 @@ dependencies = [ "core-foundation 0.10.0", "core-video", "directories", + "ely-ipc", "env_logger", "image", "libc", @@ -2151,6 +2157,7 @@ dependencies = [ "ely-office", "ely-platform", "ely-ui", + "embed-resource", "gpui-pre", "gpui-pre-platform", "image", @@ -2169,6 +2176,7 @@ dependencies = [ "ely-office", "ely-platform", "ely-ui", + "embed-resource", "encoding_rs", "gpui-pre", "log", @@ -2184,6 +2192,7 @@ dependencies = [ "ely-gpui-component", "ely-platform", "ely-ui", + "embed-resource", "futures", "gpui-pre", "jiff", diff --git a/Cargo.toml b/Cargo.toml index 05e676d..2580850 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ license = "AGPL-3.0-or-later" publish = false [workspace.dependencies] +embed-resource = "=3.0.11" csv = "1" encoding_rs = "0.8" jiff = "0.2" diff --git a/agents.md b/agents.md index c90a85f..959708f 100644 --- a/agents.md +++ b/agents.md @@ -285,4 +285,5 @@ cargo run -p ely-doc 启动一个应用(ElyDoc 先 cargo build -p ely - 2026-10-10:Windows 与 Linux 的构建环境(E-01)。Windows:MSVC(VS 2022,v143);MuPDF 由 `build-mupdf.sh` 以 MSBuild 编上游 `platform/win32` 的 `libmupdf`(静态运行库 /MT,同 Rust 的 `crt-static`;`HAVE_LIBCRYPTO`,`libmupdf.lib` 内含第三方、Tesseract 与 PKCS#7);静态 OpenSSL 取自钉在 2026.07.29 的 vcpkg(`engines/vcpkg`,`openssl:x64-windows-static`);Git 为 Git for Windows 的 MinGit 2.56.0(钉散列,`engines/git/cmd/git.exe`,LFS 在 `ucrt64/libexec/git-core`);CEF 照 cef-dll-sys 放在可执行文件旁(Windows、Linux 都是),不另载入;`%TEMP%` 下的程序被系统的应用控制拦下,构建与探针都不放那里;cmake 与 ninja 须在 PATH;LibreOffice 的 configure 只认 VS 自带的 CMake(组件 `VC.CMake.Project`)。仓库与 `reference/` 一律 LF(`core.autocrlf false`、`core.eol lf`;`fetch-references.sh` 对每个上游照设)。Linux:WSL 的 Ubuntu 26.04;静态 libcrypto 另需其 pkg-config 列出的库(jitterentropy、zstd、z)。LibreOffice 在 Linux 照 Collabora 的 LOKit 配置构建(无图形后端、cairo RGBA、自带各库)。 - 2026-10-10:Windows 与 Linux 的内核与 worker(W-01、K-01,用户定:0.1.3 先三端发布)。内核只认合并库(`ffi::KERNEL`:`libmergedlo.dylib`、`libmergedlo.so`、`mergedlo.dll`;`sofficeapp` 在合并构建里是文本占位);Windows 载入时一并搜索该 DLL 所在的 `program/`。查找次序照旧,Windows 与 Linux 的包内位置是应用旁的 `libreoffice/program`,开发构建为 `engines/lo-src/instdir/program`。worker 的主循环:macOS 照旧以 GCD;Linux 以 unipoll,`runLoop` 的轮询回调里每次答一个请求,内核的唤醒回调往同一队列放信号(`worker/unipoll.rs`;回调的数据指针须非空,VCL 见空即不调用);Windows 也以 unipoll:LOK 不另起主线程,worker 的主线程跑 `runLoop`(Windows 的消息循环),请求经只收消息的窗口投到这条线程上执行(`worker/messages.rs`),同 macOS 的 GCD;原先 LOK 自起主线程、worker 在另一线程作答,载入表格即死锁。Windows 的循环不调轮询回调,但须传非空的回调,`isUnipoll` 只看它。补丁 `0043-lok-callbacks-flush-inline-everywhere.patch`:回调队列在各平台都即时冲出(原只 macOS),否则请求里等的命令结果与状态要等下一轮主循环才到。`0042-svx-boost-json-needs-no-library.patch`:svxcore 与 sd 定义 `BOOST_ALL_NO_LIB`,MSVC 不再按 Boost 的自动链接索要 `libboost_json`、`libboost_container`。Linux 的内核以 cairo 画图块(worker 设 `SAL_DISABLESKIA`;构建去掉 `--enable-cairo-rgba`,自带的 cairo 要清掉重建),字节为 BGRA,同 macOS 与 Windows;`getTileMode` 只看 cairo 开关,不可信。worker 启动核对在三端都画一段红字,按 BGRA 找不到红色即拒绝。`scripts/apply-lo-patches.sh` 的临时库设 `core.autocrlf false`(Windows 默认转换使任何前缀都对不上)。Windows 的 LibreOffice 在 Cygwin 下构建(`build-libreoffice.sh` 的 CYGWIN 分支:去掉 Unix 专用开关,加 VS 2022,用 `/opt/lo/bin` 的 make,清掉 Git Bash 带进来的 `MSYSTEM`);构建目录与 Cygwin 排除在 Defender 扫描之外(否则并行 configure 删不掉 `conftest.dir`)。英文词典扩展里的 Lightproof(Python 写的语法检查)在构建后删去:macOS 与 Linux 的内核不带 Python,它本不生效;Windows 必带内置 Python(Cygwin 下 configure 不许去掉),第二次用同一配置启动时初始化它,worker 挂起。worker 以 `SAL_NOLOCK_PROFILE` 运行,`ely.xcd` 关掉 LibreOffice 的文档锁(`Common/Misc/UseLocking`):被强杀的 worker 留下的锁会让下次启动或载入弹出交互而挂起;每个应用只有一个 worker 用自己的配置,冲突由 Ely 自己核对。三端发布(CI-01):`.gitea/workflows/release.yml` 在打标签时于三台运行器上执行 `scripts/ci.sh`:macOS 在 Mac mini 的常驻克隆里按需从零构建引擎,Windows 在本机运行器上把 `engines` 与 `reference` 接到开发克隆,Linux 由同一台 Windows 运行器经 WSL 构建(服务器上的 Linux 运行器是一次性容器,建不了内核);各自打包后上传到该标签的发布。Windows 为 NSIS 安装程序,Linux 为 AppImage,都由 `packaging/stage.sh` 分装引擎;更新清单只含 macOS(Windows 与 Linux 的自动安装未做)。 - 2026-10-11:gpui 的 Windows 窗口关闭(W-03 冒烟查出)。`gpui-pre-windows` 0.3.8 在窗口关闭时报三条错:系统已销毁窗口(ElyTree 的关窗交给系统)后 Drop 仍对旧句柄 `RevokeDragDrop` 与 `DestroyWindow`(拖放处理器因此不释放,连带窗口状态);销毁时的失活回报排在异步任务里,执行时窗口已移除(“window not found”);退出后后台任务向已销毁的平台窗口投递(`Invalid window handle`)。修复在 `vendor/gpui-pre-windows`:`WM_DESTROY` 时记下已销毁、在句柄仍有效时撤销拖放、去掉失活回调,Drop 见已销毁即不再动句柄;平台窗口已不在时投递失败只记 debug(应用已退出),其余投递失败照报。三个应用关窗与退出的日志无错。 +- 2026-10-11(用户报:Windows 启动带黑色命令行窗口、“打开方式”里无图标、点 X 不退出、表格全黑无网格线):四处根因。命令行窗口:应用是控制台子系统;发行构建改为 `windows_subsystem = "windows"`(开发构建照旧有控制台看日志),子进程(两个 worker、Git、`cmd start`)一律经 `ely_ipc::windowless` 以 `CREATE_NO_WINDOW` 启动。图标:exe 里只有 gpui 的清单资源;各应用共用构建脚本 `packaging/windows/icon.rs`,把 `assets/icons/<应用>.ico` 编成资源 1(gpui 的窗口图标也取资源 1)。点 X 不退出:窗口其实弹了“保存更改”询问。`ely.xcd` 深色方案的 `CalcNotesBackground` 与浅色不同,Calc 在配色变化时改写批注样式并记一步撤销(`ScDetectiveFunc::UpdateAllComments`),未动的表格切到深色即算已修改;两套方案的批注底色改为同一值(LibreOffice 默认的浅黄),切换主题不再改文档,三端同此(`sheet.rs` 的 `a_theme_switch_is_no_edit`)。全黑:Win32 的虚拟设备没有 `SetSizeUsingBuffer`(基类默认返回假,断言在发行构建里不在),给客户缓冲区的设备停在 1×1 像素,Calc 图块只画了一个像素,放映图层同空;补丁 `0044-lok-win32-paints-then-copies.patch` 让 Windows 走 macOS 的路:按全尺寸画进设备,再拷进客户缓冲区(`doc_paintTile` 与 `SlideshowLayerRenderer`)。Writer 自设设备尺寸,原本不受影响。`tests/scripts/lo-patches.sh` 的临时库也设 `core.autocrlf false`(原先在 Windows 上恒失败)。 - 2026-10-09(用户定):代码与发布从 GitHub 搬到自建的 Gitea(git.zacharyzhang.com;GitHub 账号被封,推送与发布都被拒)。公开仓库 `ZacharyZhang-NY/ElyOffice`(原样推上 main、缺陷清单分支与 v0.1.0、v0.1.1 标签),组件库为同站的 `ZacharyZhang-NY/Ely-GPUI-Components`(Cargo 的 git 依赖与 `fetch-references.sh` 随之改址,钉的提交不变)。v0.1.1 的六个 dmg 与两个源码包重新发在 Gitea 的 v0.1.1 发布里。官网的下载与源码链接指向 Gitea(`releases/latest` 会跳到最新发布页)。`.github/workflows` 删去(它们靠 GitHub 的 macOS 机器与 `gh`,发布改在本机以 `packaging/macos/release.sh` 构建、经 Gitea API 上传)。发布视频里写的地址已在源文件改为 Gitea,已发布的成片仍是旧地址,重渲染后才更新。上游项目(LibreOffice、MuPDF、git-lfs、tessdata 等)照旧从它们自己的 GitHub 地址取。 diff --git a/apps/ely-agent/Cargo.toml b/apps/ely-agent/Cargo.toml index d857749..42bd4a2 100644 --- a/apps/ely-agent/Cargo.toml +++ b/apps/ely-agent/Cargo.toml @@ -5,6 +5,10 @@ edition.workspace = true rust-version.workspace = true license.workspace = true publish.workspace = true +build = "../../packaging/windows/icon.rs" + +[build-dependencies] +embed-resource.workspace = true [dependencies] ely-platform.workspace = true diff --git a/apps/ely-agent/src/main.rs b/apps/ely-agent/src/main.rs index b94546d..92a8eb9 100644 --- a/apps/ely-agent/src/main.rs +++ b/apps/ely-agent/src/main.rs @@ -1,3 +1,6 @@ +// Release builds open no console on Windows. +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + use ely_platform::AppId; fn main() { diff --git a/apps/ely-doc/Cargo.toml b/apps/ely-doc/Cargo.toml index 0c6ae3e..119035b 100644 --- a/apps/ely-doc/Cargo.toml +++ b/apps/ely-doc/Cargo.toml @@ -5,6 +5,10 @@ edition.workspace = true rust-version.workspace = true license.workspace = true publish.workspace = true +build = "../../packaging/windows/icon.rs" + +[build-dependencies] +embed-resource.workspace = true [dependencies] csv.workspace = true diff --git a/apps/ely-doc/src/main.rs b/apps/ely-doc/src/main.rs index 87d5b6c..36121b3 100644 --- a/apps/ely-doc/src/main.rs +++ b/apps/ely-doc/src/main.rs @@ -1,3 +1,6 @@ +// Release builds open no console on Windows. +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + mod actions; mod chrome; mod compare; diff --git a/apps/ely-mail/Cargo.toml b/apps/ely-mail/Cargo.toml index c10d28f..45e1505 100644 --- a/apps/ely-mail/Cargo.toml +++ b/apps/ely-mail/Cargo.toml @@ -5,6 +5,10 @@ edition.workspace = true rust-version.workspace = true license.workspace = true publish.workspace = true +build = "../../packaging/windows/icon.rs" + +[build-dependencies] +embed-resource.workspace = true [dependencies] ely-platform.workspace = true diff --git a/apps/ely-mail/src/main.rs b/apps/ely-mail/src/main.rs index 7510bff..b78bc99 100644 --- a/apps/ely-mail/src/main.rs +++ b/apps/ely-mail/src/main.rs @@ -1,3 +1,6 @@ +// Release builds open no console on Windows. +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + use ely_platform::AppId; fn main() { diff --git a/apps/ely-mark/Cargo.toml b/apps/ely-mark/Cargo.toml index 91bbd9c..d8e2c37 100644 --- a/apps/ely-mark/Cargo.toml +++ b/apps/ely-mark/Cargo.toml @@ -5,6 +5,10 @@ edition.workspace = true rust-version.workspace = true license.workspace = true publish.workspace = true +build = "../../packaging/windows/icon.rs" + +[build-dependencies] +embed-resource.workspace = true [dependencies] anyhow.workspace = true diff --git a/apps/ely-mark/src/main.rs b/apps/ely-mark/src/main.rs index 61505e0..a09c136 100644 --- a/apps/ely-mark/src/main.rs +++ b/apps/ely-mark/src/main.rs @@ -1,3 +1,6 @@ +// Release builds open no console on Windows. +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + mod attach; mod autosave; mod compare; diff --git a/apps/ely-pdf/Cargo.toml b/apps/ely-pdf/Cargo.toml index b729c56..88e9557 100644 --- a/apps/ely-pdf/Cargo.toml +++ b/apps/ely-pdf/Cargo.toml @@ -5,6 +5,10 @@ edition.workspace = true rust-version.workspace = true license.workspace = true publish.workspace = true +build = "../../packaging/windows/icon.rs" + +[build-dependencies] +embed-resource.workspace = true [dependencies] ely-files.workspace = true diff --git a/apps/ely-pdf/src/main.rs b/apps/ely-pdf/src/main.rs index 55c30d9..ce38099 100644 --- a/apps/ely-pdf/src/main.rs +++ b/apps/ely-pdf/src/main.rs @@ -1,3 +1,6 @@ +// Release builds open no console on Windows. +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + mod annotate; mod ask; mod attach; diff --git a/apps/ely-show/Cargo.toml b/apps/ely-show/Cargo.toml index 87f9f11..0fd7fcc 100644 --- a/apps/ely-show/Cargo.toml +++ b/apps/ely-show/Cargo.toml @@ -5,6 +5,10 @@ edition.workspace = true rust-version.workspace = true license.workspace = true publish.workspace = true +build = "../../packaging/windows/icon.rs" + +[build-dependencies] +embed-resource.workspace = true [dependencies] ely-files.workspace = true diff --git a/apps/ely-show/src/main.rs b/apps/ely-show/src/main.rs index 072595b..93c373d 100644 --- a/apps/ely-show/src/main.rs +++ b/apps/ely-show/src/main.rs @@ -1,3 +1,6 @@ +// Release builds open no console on Windows. +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + mod chart; mod check; mod deck; diff --git a/apps/ely-table/Cargo.toml b/apps/ely-table/Cargo.toml index 26b5cb9..994e001 100644 --- a/apps/ely-table/Cargo.toml +++ b/apps/ely-table/Cargo.toml @@ -5,6 +5,10 @@ edition.workspace = true rust-version.workspace = true license.workspace = true publish.workspace = true +build = "../../packaging/windows/icon.rs" + +[build-dependencies] +embed-resource.workspace = true [dependencies] encoding_rs.workspace = true diff --git a/apps/ely-table/src/main.rs b/apps/ely-table/src/main.rs index 22a5094..ff28c7a 100644 --- a/apps/ely-table/src/main.rs +++ b/apps/ely-table/src/main.rs @@ -1,3 +1,6 @@ +// Release builds open no console on Windows. +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + mod analysis; mod bars; mod book; diff --git a/apps/ely-tree/Cargo.toml b/apps/ely-tree/Cargo.toml index f0ede71..103d362 100644 --- a/apps/ely-tree/Cargo.toml +++ b/apps/ely-tree/Cargo.toml @@ -5,6 +5,10 @@ edition.workspace = true rust-version.workspace = true license.workspace = true publish.workspace = true +build = "../../packaging/windows/icon.rs" + +[build-dependencies] +embed-resource.workspace = true [dependencies] ely-files.workspace = true diff --git a/apps/ely-tree/src/main.rs b/apps/ely-tree/src/main.rs index 1332d32..77addc9 100644 --- a/apps/ely-tree/src/main.rs +++ b/apps/ely-tree/src/main.rs @@ -1,3 +1,6 @@ +// Release builds open no console on Windows. +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + mod asks; mod asks_places; mod blame; diff --git a/crates/ely-ipc/src/lib.rs b/crates/ely-ipc/src/lib.rs index 9bf1039..e4e1be5 100644 --- a/crates/ely-ipc/src/lib.rs +++ b/crates/ely-ipc/src/lib.rs @@ -4,6 +4,18 @@ mod relay; pub use relay::{Relay, relay}; use std::io::{self, Read, Write}; +use std::process::Command; + +/// A child that opens no console window on Windows. +pub fn windowless(command: &mut Command) -> &mut Command { + #[cfg(windows)] + { + use std::os::windows::process::CommandExt as _; + // CREATE_NO_WINDOW + command.creation_flags(0x0800_0000); + } + command +} /// A frame: u32 length, u8 tag, u64 request id, payload. pub const MAX_FRAME: usize = 64 * 1024 * 1024; diff --git a/crates/ely-lok/src/client.rs b/crates/ely-lok/src/client.rs index 1a8b29f..133bbec 100644 --- a/crates/ely-lok/src/client.rs +++ b/crates/ely-lok/src/client.rs @@ -147,7 +147,7 @@ impl Worker { let worker_bin = worker_bin()?; log::info!("lok: worker from {}", worker_bin.display()); let mut command = Command::new(worker_bin); - command + ely_ipc::windowless(&mut command) .arg(install) .arg(profile_dir) .env("SAL_FORCE_HIDPI_SCALING", "1") diff --git a/crates/ely-lok/src/client/tests/sheet.rs b/crates/ely-lok/src/client/tests/sheet.rs index 32d6f4c..f11ee13 100644 --- a/crates/ely-lok/src/client/tests/sheet.rs +++ b/crates/ely-lok/src/client/tests/sheet.rs @@ -180,3 +180,18 @@ pub(super) fn open_book(text: &str) -> (tempfile::TempDir, Worker, Doc) { .expect("the area"); (dir, worker, doc) } + +#[test] +fn a_theme_switch_is_no_edit() { + if install().is_none() { + eprintln!("SKIP: no pinned LOK build"); + return; + } + let (_dir, mut worker, doc) = open_book(FODS); + for scheme in ["COLOR_SCHEME_ELY_DARK", "COLOR_SCHEME_ELY_LIGHT"] { + worker.run(&doc, "view.theme", &[scheme]).expect("the theme runs"); + let undo = worker.values(&doc, ".uno:Undo").expect("the undo stack"); + let undo: serde_json::Value = serde_json::from_str(&undo).expect("undo JSON"); + assert_eq!(undo["actions"], "", "{scheme} left undo steps"); + } +} diff --git a/crates/ely-pdf-engine/src/client.rs b/crates/ely-pdf-engine/src/client.rs index 499e52c..9e5b2ac 100644 --- a/crates/ely-pdf-engine/src/client.rs +++ b/crates/ely-pdf-engine/src/client.rs @@ -103,7 +103,7 @@ impl Worker { /// Spawns `bin`; one from other sources is refused. pub fn spawn_from(bin: &Path) -> io::Result { - let mut child = Command::new(bin) + let mut child = ely_ipc::windowless(&mut Command::new(bin)) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) diff --git a/crates/ely-platform/Cargo.toml b/crates/ely-platform/Cargo.toml index d5d040a..9fc3856 100644 --- a/crates/ely-platform/Cargo.toml +++ b/crates/ely-platform/Cargo.toml @@ -10,6 +10,7 @@ publish.workspace = true anyhow.workspace = true arboard.workspace = true directories.workspace = true +ely-ipc.workspace = true env_logger.workspace = true image.workspace = true log.workspace = true diff --git a/crates/ely-platform/src/apps.rs b/crates/ely-platform/src/apps.rs index 2dbb45e..2b57e00 100644 --- a/crates/ely-platform/src/apps.rs +++ b/crates/ely-platform/src/apps.rs @@ -118,7 +118,7 @@ pub fn open_default(path: &Path) -> io::Result<()> { } else { Command::new("xdg-open") }; - let out = command.arg(path).output()?; + let out = ely_ipc::windowless(&mut command).arg(path).output()?; if !out.status.success() { let said = String::from_utf8_lossy(&out.stderr).trim().to_owned(); return Err(io::Error::other(said)); diff --git a/crates/ely-platform/src/git.rs b/crates/ely-platform/src/git.rs index 8503eff..8178730 100644 --- a/crates/ely-platform/src/git.rs +++ b/crates/ely-platform/src/git.rs @@ -45,7 +45,7 @@ pub fn parse_version(text: &str) -> Option<(u32, u32)> { /// What `git --version` says, once it succeeds. pub fn version_of(path: &Path) -> io::Result<(String, (u32, u32))> { - let output = Command::new(path).arg("--version").output()?; + let output = ely_ipc::windowless(&mut Command::new(path)).arg("--version").output()?; if !output.status.success() { let said = String::from_utf8_lossy(&output.stderr).trim().to_string(); return Err(io::Error::other(format!("{} --version failed ({}): {said}", path.display(), output.status))); @@ -83,7 +83,7 @@ fn own(dir: &Path) -> PathBuf { /// Git at `git` in `dir`, as Ely runs it. pub fn command(git: &Path, dir: &Path, args: &[&str]) -> Command { let mut command = Command::new(git); - command + ely_ipc::windowless(&mut command) .args(args) .current_dir(dir) // Reads never take the index lock from an outside Git. diff --git a/packaging/libreoffice/ely.xcd b/packaging/libreoffice/ely.xcd index c3d8f3e..6c65b2e 100644 --- a/packaging/libreoffice/ely.xcd +++ b/packaging/libreoffice/ely.xcd @@ -48,7 +48,7 @@ 0 4144959 4144959 - 3417617 + 16777152 6052440 6052440 6922728 diff --git a/packaging/windows/icon.rs b/packaging/windows/icon.rs new file mode 100644 index 0000000..a558d0d --- /dev/null +++ b/packaging/windows/icon.rs @@ -0,0 +1,21 @@ +//! Each app's build script: its icon as resource 1 on Windows. + +use std::{env, fs, path::PathBuf}; + +fn main() { + if env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("windows") { + return; + } + let app = env::var("CARGO_PKG_NAME").expect("cargo names the package"); + let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("cargo names the folder")); + let icon = root.join("../../assets/icons").join(format!("{app}.ico")); + let icon = fs::canonicalize(&icon).unwrap_or_else(|error| panic!("{}: {error}", icon.display())); + println!("cargo:rerun-if-changed={}", icon.display()); + // gpui's window icon is resource 1. + let rc = PathBuf::from(env::var("OUT_DIR").expect("cargo gives OUT_DIR")).join("icon.rc"); + let path = icon.to_str().expect("a UTF-8 path").trim_start_matches(r"\\?\").replace('\\', "/"); + fs::write(&rc, format!("1 ICON \"{path}\"\n")).expect("the resource script is written"); + embed_resource::compile(&rc, embed_resource::NONE) + .manifest_optional() + .expect("the icon resource compiles"); +} diff --git a/patches/libreoffice/0044-lok-win32-paints-then-copies.patch b/patches/libreoffice/0044-lok-win32-paints-then-copies.patch new file mode 100644 index 0000000..eab97e7 --- /dev/null +++ b/patches/libreoffice/0044-lok-win32-paints-then-copies.patch @@ -0,0 +1,65 @@ +LOK: Windows paints tiles and slide layers, then copies + +Win32 virtual devices have no SetSizeUsingBuffer: the base default +returns false, so the device for a client buffer stayed 1x1 pixel. +Calc tiles came back black with one painted pixel, and slide layers +were empty. Take the macOS path there: paint into the device at full +size, then copy the pixels into the client buffer. + +diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx +index 39b72fb..253fbc0 100644 +--- a/desktop/source/lib/init.cxx ++++ b/desktop/source/lib/init.cxx +@@ -4325,8 +4325,8 @@ static void doc_paintTile(LibreOfficeKitDocument* pThis, + // Set background to transparent by default. + pDevice->SetBackground(Wallpaper(COL_TRANSPARENT)); + +-#if defined(MACOSX) +- // Aqua devices cannot paint client buffers: paint, then copy. ++#if defined(MACOSX) || defined(_WIN32) ++ // No client buffers here: paint, then copy. + pDevice->SetOutputSizePixel(Size(nCanvasWidth, nCanvasHeight)); + #else + pDevice->SetOutputSizePixelScaleOffsetAndLOKBuffer( +diff --git a/sd/source/ui/tools/SlideshowLayerRenderer.cxx b/sd/source/ui/tools/SlideshowLayerRenderer.cxx +index 7ecd4ad..3f3a478 100644 +--- a/sd/source/ui/tools/SlideshowLayerRenderer.cxx ++++ b/sd/source/ui/tools/SlideshowLayerRenderer.cxx +@@ -88,7 +88,7 @@ private: + + EEControlBits mnSavedControlBits; + Color maSavedBackgroundColor; +-#if defined(MACOSX) ++#if defined(MACOSX) || defined(_WIN32) + unsigned char* mpBuffer; + Size maBufferSize; + #endif +@@ -103,7 +103,7 @@ public: + , maVirtualDevice( + CoreGraphics::getiOSGraphicsData(pBuffer, rSlideSize.Width(), rSlideSize.Height()), + Size(1, 1), DeviceFormat::WITHOUT_ALPHA) +-#elif defined(MACOSX) ++#elif defined(MACOSX) || defined(_WIN32) + , mpBuffer(pBuffer) + , maBufferSize(rSlideSize) + , maVirtualDevice(DeviceFormat::WITH_ALPHA) +@@ -123,8 +123,8 @@ public: + + maVirtualDevice->SetBackground(Wallpaper(COL_TRANSPARENT)); + +-#if defined(MACOSX) +- // Aqua devices cannot paint client buffers: paint, then copy. ++#if defined(MACOSX) || defined(_WIN32) ++ // No client buffers here: paint, then copy. + (void)rScale; + maVirtualDevice->SetOutputSizePixel(rSlideSize); + #else +@@ -155,7 +155,7 @@ public: + #ifdef IOS + CoreGraphics::CGContextRelease(maVirtualDevice->GetSystemGfxData().rCGContext); + #endif +-#if defined(MACOSX) ++#if defined(MACOSX) || defined(_WIN32) + maVirtualDevice->EnableMapMode(false); + vcl::bitmap::fillWithData(mpBuffer, + maVirtualDevice->GetBitmap(Point(), maBufferSize)); diff --git a/tests/scripts/lo-patches.sh b/tests/scripts/lo-patches.sh index 813ceca..d0ec9b1 100755 --- a/tests/scripts/lo-patches.sh +++ b/tests/scripts/lo-patches.sh @@ -14,6 +14,8 @@ trap 'rm -rf "$work"' EXIT tree=$work/tree mkdir -p "$tree" git -C "$tree" init -q +# LF, as every tree here; Windows defaults convert. +git -C "$tree" config core.autocrlf false for f in $files; do if git -C "$src" cat-file -e "HEAD:$f" 2>/dev/null; then mkdir -p "$tree/$(dirname "$f")"