feat(app-iced): M116 窗口外框圆角策略(跟随系统/直角)+ DWM 读写的受控对照实验
用户问「为什么窗口没有圆角」。核实:组件层圆角齐,但窗口外框**零处理**——代码里没有任何
Dwm* / SetWindowRgn。本 mission 先做实测,再按平台分开落策略。
判据(纯函数、可真值表):
- `platform::plan_corner(策略 × 系统版本 × 渲染档)` → `source=dwm|square` + `excluded_reason`。
Win11 / Server 2025(build ≥ 22000)→ DWM;Win10 及更早 → 直角(不做 SetWindowRgn 毛边默认);
探测不到版本(macOS / X11 / Wayland)→ 直角 + `unknown-os`(「不承诺」而不是「做不到」)。
CPU 档在 Win11 上照样用 DWM(D36 限制的是我们自己的合成技巧,不是系统合成器)。
落点:`platform/win32/transparency.rs` 仍是全仓唯一 unsafe 文件,新增 DWM 的 FFI 与安全包装;
`alpha.rs` / `dwm.rs` / `probe.rs` 三个新子模块零 unsafe、零 extern(沿 exstyle.rs 的既有形状)。
实测(本机 Server 2025 build 26100、RDP 会话断开、同进程三窗口对照):
- `DwmSetWindowAttribute(DWMWA_WINDOW_CORNER_PREFERENCE)` 在 WS_OVERLAPPEDWINDOW / WS_POPUP /
WS_POPUP|WS_EX_LAYERED(α=0.8) 上**全部成功** ⇒ 无边框与整窗 α 不会让属性设不上;
- `DwmGetWindowAttribute` 同一属性三种样式**全部 E_INVALIDARG** ⇒ 本机不支持回读,与样式无关;
- `DWMWA_EXTENDED_FRAME_BOUNDS − GetWindowRect`:有边框 = +0,−7,popup = +0,+0
⇒ DWM 只给有边框窗口加不可见调整带,我们的窗口没有可画的圆角区域(结构性解释)。
- 像素(角上透明/方块)**未验**:RDP 断连导致 CopyFromScreen / gdigrab 全废。
同时修掉一个自己踩到的判据错误:`i32::unsigned_abs()` 不能用来打印 HRESULT
(E_INVALIDARG 0x80070057 会被印成 0x7FF8FFA9)。现在 HRESULT 用 `hr as u32` + 严重性位,
GetLastError 的 DWORD 语义保持 `unsigned_abs` 并写死注释(两者不同源,别统一)。
配置:新键 `appearance.window_corner ∈ {system, square}`(出厂 system),schema 1.5.0 只推 minor、
不写迁移:老文件缺键 = 取默认 = 跟随系统;旧版本读新文件时未知键被登记并原样写回(`RenderMode::Full`),
只在显式 `store.set` 该键时才 `UnknownKey`。
设置 UI:外观组只留两档(跟随系统 / 直角)+ 一句按平台说清的说明,文案走 i18n 中英。
日志:`[corner] <ctx> corner=policy=… source=… os=… excluded_reason=… radius=system pref=… readback=… frame=… layered=…`
(形状由 `corner::format_line` 的格式化单测钉住,用探针窗口真实读数构造)。
证据:DevDocs/artifacts/m116/{README.md,probe-table.md}
This commit is contained in:
1 parent
aace0c5836
commit
88dbf6d955
29 files changed
+2047
-259
No files matched your search
@@ -52,9 +52,16 @@ pub const JDK_VENDORS: &[&str] = &["temurin", "oracle", "microsoft", "zulu"];
|
||||
/// `1.4.0` 登记 P4 的外观下层三键(`appearance.window_opacity` / `titlebar_mode` /
|
||||
/// `palette_source`,M91 · D36/D37/D38):仍然只推 minor、不加迁移步骤——三者的出厂值
|
||||
/// (不透明 / auto / 内置色卡)正是「老文件没有这些键」时的等价物。
|
||||
/// `1.5.0` 登记 M116 的窗口圆角策略(`appearance.window_corner`,出厂 `system`):
|
||||
/// 同一套纯增量语义——老文件缺该键 ⇒ 读默认 `system` ⇒ 跟随系统,与写进文件后行为一致。
|
||||
/// **向前兼容(旧版本读新文件)**:本仓的 [`super::catalog`] 是白名单校验,
|
||||
/// 但读路径 (`SettingDocument::load`) 只**登记**陌生键、不报错也不删除(`RenderMode::Full`
|
||||
/// 会把它们原样写回),所以旧版本打开新文件不会崩,只是看不到「直角」这一档;
|
||||
/// 只有**显式 `store.set("appearance.window_corner", …)`** 在旧版本上才会
|
||||
/// 返回 `SettingError::UnknownKey`(新版本自己不会这么调)。
|
||||
#[must_use]
|
||||
pub fn launcher_version() -> SchemaVersion {
|
||||
SchemaVersion::new(1, 4, 0)
|
||||
SchemaVersion::new(1, 5, 0)
|
||||
}
|
||||
|
||||
/// `config/launcher.json` 的 schema。
|
||||
@@ -336,6 +343,16 @@ pub fn launcher_schema() -> SettingSchema {
|
||||
AiPolicy::audited(),
|
||||
"配色来源档(D38 三级):background-image(背景图取色)/ wallpaper(桌面壁纸取色)/ preset(内置色卡,默认)",
|
||||
))
|
||||
// M116:窗口外框圆角策略。只有两档(system / square)——系统不暴露圆角半径,
|
||||
// 「固定 8/12/16」只能是自绘圆角,而自绘圆角在无边框 + 整窗 α 上要裁内容层,
|
||||
// 会连标题栏三键与缩放热区一起裁掉(用户定案 2026-11-03)。
|
||||
.with(SettingSpec::enumeration(
|
||||
"appearance.window_corner",
|
||||
"system",
|
||||
super::appearance::WINDOW_CORNERS,
|
||||
AiPolicy::audited(),
|
||||
"窗口圆角:system(跟随系统:Win11/Server 2025 走 DWM,Win10 保持直角)/ square(总是直角),默认 system",
|
||||
))
|
||||
// 已废弃:D17 定案 appearance.theme_mode 为准(旧值读兼容映射,写永远走新键)。
|
||||
.with(
|
||||
SettingSpec::new(
|
||||
|
||||
Reference in new issue
Block a user