用户第三轮 Mac 验收看到四角直角 + `source=square os=unknown`。原来非 Windows 一律 落到 `UnknownOs`,把「Windows 版本读不出来」与「这台根本不是 Windows」糊成同一格。 - `platform/host.rs`:新增 `HostOs`——平台族是一个**值**而不是散落的 `cfg`。 这样三行真值表能在本机(只有 Windows)一次验完,`cfg` 只留在真要 FFI 的地方。 - `plan_corner` 拆成 `plan_corner_for(policy, host, os, backend)` + 保持原签名的薄包装 (`app/update/appearance.rs` 在 scope 外,调用点一字未改)。 - `CornerSource` 加第三档 `Compositor`(跟随合成器,我们既不下发也不自绘); `CornerExclusion` 加 `borderless`(macOS)、`client-side`(Linux)、`unsupported`。 - 日志加 `host=`,非 Windows 的 `os=` 由 `unknown` 改 `n/a`(那栏是 Windows 版本, 在 macOS/Linux 上不是「没读到」而是「跟本机无关」)。 - `platform/macos/mod.rs`:macOS 为什么是直角的**三环证据**(我们的 `decorations: false` → winit `Borderless`(无 `Titled`)→ 窗口服务器只裁 titled 窗;winit macOS 后端 `cornerRadius` 命中 0),以及「迁移原生标题栏」的未实现配方与阻塞点(iced 0.14 未转发 winit 的 `titlebar_buttons_hidden`,缩放键按不掉)。 - `platform/linux/mod.rs`:xdg-shell 无圆角概念、wl_surface 区域只能是矩形、XShape 只能 切硬边 ⇒ CSD 窗没人替我们裁,D46 排除自绘 ⇒ 直角。没把 DWM 判据搬过去(单测钉着 「非 Windows 不许出现 dwm」)。 - `design/shape.rs`:删掉「macOS 走 `layer.cornerRadius`」这句过期描述(D46 不许自绘裁切)。 - `dwm.rs` 的内联测试挪到 `dwm/tests.rs`(原文件 398 行,加第三档映射会顶破 400 行红线)。 验证:cargo fmt --check / clippy -D warnings / `cargo test -p unlucky-app-iced --lib` 684 passed;三次定向变异各自变红(macOS 行改回 Square/UnknownOs → 4 红;非 Windows `os=` 改回 unknown → 1 红;Linux 原因码复制成 borderless → 4 红)。 Windows 侧无语义改动;`cargo test --lib m116 -- --ignored --nocapture` 复跑读回仍是 `pref=2 readback=? read_hr=0x80070057`(写入被接受、回读不可用),**不作为「圆角已生效」的证据**。
94 lines
6.3 KiB
Rust
94 lines
6.3 KiB
Rust
//! macOS 的窗口外框(M182):**本轮不实现**,这里只有结论、证据与后续配方。
|
||
//!
|
||
//! 用户第三轮 Mac 真机验收的现象:四角是直角,日志 `[corner] … source=square os=unknown`。
|
||
//! 「macOS 不支持圆角」是**错的**——macOS 的窗口四角本来就有系统圆角,只是我们交上去的窗口
|
||
//! 不在会被裁的那一类里。三环链条如下,每一环都能在本机复核(读锁文件里的依赖源码即可):
|
||
//!
|
||
//! ## 第 1 环:我们交的是什么窗
|
||
//!
|
||
//! `crates/app-iced/src/app/boot/diagnostics.rs` 的 `window_settings()` 给的是
|
||
//! `decorations: false`(M93 自绘三键)。那是**唯一产地**,`[window]` / `[caps]` 两行
|
||
//! 验收日志也从它取字段。
|
||
//!
|
||
//! ## 第 2 环:winit 把 `decorations: false` 翻成什么
|
||
//!
|
||
//! winit 0.30.13 `src/platform_impl/macos/window_delegate.rs:540-552`:
|
||
//!
|
||
//! ```text
|
||
//! let mut masks = if (!attrs.decorations && screen.is_none()) || titlebar_hidden {
|
||
//! // Resizable without a titlebar or borders
|
||
//! NSWindowStyleMask::Borderless | NSWindowStyleMask::Resizable | NSWindowStyleMask::Miniaturizable
|
||
//! } else {
|
||
//! // default case, resizable window with titlebar and titlebar buttons
|
||
//! NSWindowStyleMask::Closable | Miniaturizable | Resizable | Titled
|
||
//! };
|
||
//! ```
|
||
//!
|
||
//! ⇒ `decorations: false` 拿到的是 **`Borderless`**,**没有 `Titled`**。
|
||
//!
|
||
//! ## 第 3 环:窗口服务器只给 `Titled` 窗做圆角裁剪
|
||
//!
|
||
//! 这是 AppKit 的标准窗口行为(A 级外部事实:标准窗口的圆角由窗口服务器连同阴影一起画,
|
||
//! 无边框窗口不参与)。本仓库**没有**任何一行代码能影响它:winit 的 macOS 后端里
|
||
//! `cornerRadius` / `CornerRadius` 命中数为 **0**(`src/platform_impl/macos/` 内四命中全是
|
||
//! 「屏幕/视图左上角」的注释),也就是说圆角从来没有一行业是我们调的。
|
||
//!
|
||
//! 反向印证:用户第三轮实测(本机窗口就是 borderless)拍到四角直角,与第 3 环一致。
|
||
//!
|
||
//! 判据一侧的落点:`plan_corner_for(MacOs, …)` 现在返回
|
||
//! `source=compositor excluded_reason=borderless`(见 [`crate::platform::win32::corner`]),
|
||
//! 而不是原先含糊的 `source=square os=unknown`。
|
||
//!
|
||
//! ## 为什么**不**用 objc 给 `contentView.layer` 设 `cornerRadius`(M182 任务书原路线,已否)
|
||
//!
|
||
//! 1. **违反 D46 第 4 条**「macOS / X11 / Wayland 按合成器默认、**不主动自绘**」:
|
||
//! 把内容层裁成圆角就是自绘裁切,同一份决策日志里已经否决过这条(还附带
|
||
//! 「会把标题栏三键与边缘缩放热区一起裁掉」的问题)。
|
||
//! 2. **撞 `unsafe` 铁律**:根 `Cargo.toml` 的 `[workspace.lints.rust] unsafe_code = "deny"`,
|
||
//! 且 `guards.yml` 的 `unsafe-scope` 作业要求「带 `allow(unsafe_code)` 的文件集合**恰好等于**
|
||
//! `crates/app-iced/src/platform/win32/transparency.rs`」——新增一个 objc FFI 文件会让该作业
|
||
//! 直接红,而那个工作流不在 M182 的改动范围内。
|
||
//! 3. **拿不到 `NSWindow`**:`app/window_alpha.rs` 的 `probe_hwnd` 在非 Windows 恒返回 `None`,
|
||
//! 于是 `App::apply_window_corner` 走 `NoWindow` 分支——macOS 上那条下发链**从来没被调用过**。
|
||
//! 要接线得改 `app/window_alpha.rs` + `app/update.rs`(M182 范围之外,且 M168/M178 正在改
|
||
//! `app/**`)。
|
||
//! 4. **本机编不了**:macOS 分支要靠 macOS 工具链,Windows 上连类型检查都跑不到。
|
||
//!
|
||
//! ## 后续口径(**未实现**,需另立 mission + Mac 真机第 4 轮验收)
|
||
//!
|
||
//! 目标:把外框交还给窗口服务器当标准窗口,由它按自己的规则圆角(= 用户定的
|
||
//! 「其他系统按照窗口合成器的默认规则来」):
|
||
//!
|
||
//! ```text
|
||
//! decorations: true,
|
||
//! platform_specific: { title_hidden: true, titlebar_transparent: true, fullsize_content_view: true }
|
||
//! ```
|
||
//!
|
||
//! - 三个字段 iced 0.14 已暴露(`iced_core-0.14.0/src/window/settings/macos.rs`),
|
||
//! iced_winit 1:1 转发(`iced_winit-0.14.1/src/conversion.rs:125-137` 的
|
||
//! `#[cfg(target_os = "macos")]` 块);
|
||
//! `FullSizeContentView` 让内容铺满整窗(不留原生标题栏高度),窗口服务器把整窗
|
||
//! ——**连同我们的背景图**——裁成圆角,不会出现「外框圆了、里面还是方块」。
|
||
//! - **必须同时隐藏我们自绘的三键**(`crates/app-iced/src/shell/mod.rs`),否则屏幕上会同时存在
|
||
//! 左上角原生三色灯与右上角自绘三键两套控件——那不是「跟随合成器」,是两套控件打架。
|
||
//! - **已知阻塞点(真做之前必须先解掉)**:winit 有 `with_titlebar_buttons_hidden`
|
||
//! (`src/platform/macos.rs:290`,能一次藏掉全部三色灯),但 **iced 0.14 的
|
||
//! `PlatformSpecific` 没有转发它**;而 `WindowExtMacOS` 也没有运行期隐藏按钮的接口
|
||
//! (只有 `set_has_shadow` / `set_document_edited` 等)。三条出路:① 给 iced 上游提转发
|
||
//! (最干净,但要等版本);② 仅用 `closeable: false, minimizable: false` 藏掉关闭/最小化
|
||
//! 两键——**缩放键藏不掉**,会留一个孤零零的绿灯;③ 拿到 `NSWindow` 后手动 `setHidden:`
|
||
//! (回到 objc + `unsafe`,见上面的第 2、3 条)。
|
||
//! - **验收日志会一起变**:`renderer::acceptance::visual` 从 `decorations` 推
|
||
//! `controls=self-drawn|native`,一旦改成 `true`,那行会写 `controls=native`,而我们当时
|
||
//! 仍在自绘三键(除非同一次改动把三键撤掉)⇒ 那条改动必须**同一个 mission 内**一起做。
|
||
//! - **验证路径**:本机(Windows)拿不到任何 macOS 像素;只能靠
|
||
//! `ci.yml` 的 `runtime-smoke-macos` 作业(dispatch 触发、`continue-on-error`)看**编不编得过**,
|
||
//! 视觉效果必须等**第 4 轮 Mac 真机验收图**或用户手动确认。
|
||
//!
|
||
//! ## 本轮明确未验
|
||
//!
|
||
//! - macOS 圆的半径、平滑度、与系统其它窗口是否一致(无真机);
|
||
//! - 高 DPI(Retina)下系统圆角的视觉半径(由系统决定,我们读不到,也不需要缩放——这一档
|
||
//! 本来就「不归我们管」,见 [`crate::platform::win32::corner`] 的 `radius=system`);
|
||
//! - 原生三色灯的最终观感与「是否保留自绘三键」的产品取舍。
|