Fix maximize resize guard and add records

This commit is contained in:
Codex
2026-04-09 04:19:56 +08:00
parent f567369300
commit 97710db9e3
5 changed files with 297 additions and 6 deletions
@@ -0,0 +1,55 @@
# 补充记录-20260409-窗口最大化收口保护
## 说明
- 本文件用于补充记录 2026-04-09 当天新增的窗口最大化收口问题。
- 对应修改发生在 `f567369` 快照之后,当前仍位于工作区未提交状态。
## 问题概述
- 现象:
- 某些窗口初始尺寸下,直接点击最大化会出现黑背景、控件残影。
- 若先手动拖拽窗口略微放大,再最大化,则问题消失。
- 影响用例:
- `KEY == 1`
- `KEY == 2`
- 不受影响用例:
- `KEY == 3`
- `KEY == 4`
## 根因
- [`Window.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Window.cpp) 的 `runEventLoop()` resize 收口中存在一段历史“跨度保护”。
- 该保护把“宽高变化超过 1000”视为异常帧,直接终止收口:
- 不再执行 `adaptiveLayout`
- 不再执行 `Resize`
- 不再执行 `redrawScene(true, true)`
- 因此新暴露区域不会被完整刷新,最终表现为黑背景与残影。
## 本次新增记录
- BUG
- [`BUG-20260409-0003 直接最大化触发收口保护导致黑背景与残影`](./BUG/BUG-20260409-0003-直接最大化触发收口保护导致黑背景与残影.md)
- Fix
- [`Fix-BUG-20260409-0003 直接最大化触发收口保护导致黑背景与残影`](./Fix/Fix-BUG-20260409-0003-直接最大化触发收口保护导致黑背景与残影.md)
- 功能变更:
- [`Feature-20260409-0006 窗口最大化收口保护调整`](./功能变更/Feature-20260409-0006-窗口最大化收口保护调整.md)
## 修改摘要
- 将“跨度过大即跳过”改为“仅非法尺寸才跳过”。
- 非法尺寸标准:
- `actualWidth <= 0`
- `actualHeight <= 0`
- `actualWidth > max(10000, virtualScreenWidth * 2)`
- `actualHeight > max(10000, virtualScreenHeight * 2)`
- 对“大跨度但合法”的 resize 保留 `DEBUG` 日志,但继续执行完整收口。
- 顺手删除了 `Window.cpp` 中未使用的 `ExMessage mm;` 遗留变量。
## 当前状态
- 代码修改:已完成,待提交
- 文档记录:已补充
- 验证状态:
- 已完成源码级编译验证
- 待用户做 GUI 回归
@@ -0,0 +1,68 @@
# BUG-20260409-0003
> 适用场景:记录问题本身,不展开完整修复方案。修复内容写入对应的 Fix 文档。
## 基本信息
- ID: BUG-20260409-0003
- 标题: 直接最大化触发收口保护,导致黑背景与控件残影
- 状态:已修复 / 待回归验证
- 严重性:S2
- 优先级:P0
- 模块:Window / Resize / Scene Redraw
- 版本 / 分支:`master`
- 环境:Windows 桌面 + EasyX + VS2022
- 发现人:用户反馈
- 关联 Fix ID`Fix-BUG-20260409-0003`
## 问题描述
- 现象:
- 某些用例在窗口初始大小下直接点击最大化后,新暴露出的区域显示为黑色背景。
- 已有控件可能出现残留、残影或旧内容未被覆盖。
- 若先手动拖动边框略微放大,再执行最大化,则问题消失。
- 影响范围:
- 顶层窗口 resize 收口
- 背景完整重绘
- 控件 resize 后的快照/标脏收口
- 期望结果:
- 无论是拖拽 resize 还是直接最大化,只要 `WM_SIZE` 进入收口流程,都应完成一次完整 redraw。
- 实际结果:
- 某些“大跨度但合法”的最大化尺寸变化,会在收口中途被直接跳过,导致背景和控件未完成刷新。
## 复现信息
- 复现条件:
- 初始窗口尺寸与最大化后的客户区尺寸跨度较大。
- 典型用例:
1. `KEY == 1``1200x400 -> 2160x1417`
2. `KEY == 2``700x510 -> 2160x1417`
3. `KEY == 3 / 4`:初始尺寸较大时不复现
- 复现概率:高
- 证据:
- `WM_SIZE:待处理=(2160x1417), isSizing=0`
- `调整窗口尺寸开始:width=... height=...`
- `尺寸调整被跨度保护跳过:old=(...) new=(...) diff=(...)`
- 异常日志中缺失 `尺寸调整已完成`
## 初步分析
- 疑似位置:
- [`Window.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Window.cpp) 的 `runEventLoop()` resize 收口逻辑
- 可疑代码特征:
- 使用 `abs(finalW - width) > 1000 || abs(finalH - height) > 1000` 作为跳过条件
- 命中后直接:
- `needResizeDirty = false`
- `continue`
- 根因判断:
- 该分支把“跨度较大的合法最大化”误判为异常帧
- 导致后续 `Resize / adaptiveLayout / redrawScene / done log` 全部被跳过
## 跟踪信息
- 首次发现时间:2026-04-09
- 最后更新时间:2026-04-09
- 修复版本:当前工作区
- 验证版本:待用户回归
- 备注:
- 当前证据表明问题与 DPI 不是同一级根因,更直接的是跨度阈值误杀。
@@ -0,0 +1,80 @@
# Fix-BUG-20260409-0003
> 适用场景:记录某个 BUG 的修复方案、影响评估、验证结果与落地信息。
## 关联信息
- Fix ID: `Fix-BUG-20260409-0003`
- 关联 BUG ID: `BUG-20260409-0003`
- 修复目标: 取消对合法大跨度最大化的误拦截,仅保留非法尺寸保护
- 状态:已完成 / 待用户回归
- 负责人:Codex 协作修改
- 分支 / 版本:`master`
## 根因分析
- 旧逻辑问题:
- `runEventLoop()` 的 resize 收口中存在“跨度保护”:
- `abs(finalW - width) > 1000 || abs(finalH - height) > 1000`
- 命中后直接跳过整个收口流程。
- 为什么会出问题:
- 该判断关注的是“变化跨度”,而不是“尺寸是否合法”。
- 在大屏、窗口初始尺寸较小、直接最大化等正常场景下,跨度超过 `1000` 很常见。
- 为什么之前未必稳定暴露:
- 当初始尺寸较大时,最大化跨度较小,不会命中阈值。
- 先手动拉大一点后再最大化,也会避开该阈值。
## 修复方案
- 修复思路:
- 删除“跨度过大即跳过”的保护语义。
- 改成“仅非法客户区尺寸才跳过”。
- 保留关键 `DEBUG` 日志,方便追踪极端尺寸帧。
- 关键改动:
- 删除旧的 `>1000` 误拦截分支。
- 引入虚拟桌面尺寸:
- `SM_CXVIRTUALSCREEN`
- `SM_CYVIRTUALSCREEN`
- 仅在以下情况下跳过本次收口:
- `actualWidth <= 0`
- `actualHeight <= 0`
- `actualWidth > max(10000, virtualScreenWidth * 2)`
- `actualHeight > max(10000, virtualScreenHeight * 2)`
- 对“大跨度但合法”的 resize 增加 `DEBUG` 日志,但继续执行收口。
- 涉及文件 / 类 / 函数:
- `Window.cpp`
- `Window::runEventLoop()`
- 输出日志:
- `尺寸调整被非法尺寸保护跳过`
- `检测到大跨度尺寸调整,继续执行收口`
## 影响评估
- 对外行为变化:
- 有。直接最大化不再被 `>1000` 阈值拦截。
- 兼容性影响:
- 正向兼容。正常拖拽 resize、正常最大化都仍然走原有收口流程。
- 风险:
- 如果系统偶发产生一次极端异常客户区尺寸,可能会更多依赖当前“非法尺寸保护”而不是原来的跨度阈值。
- 但相较于误杀合法最大化,这个风险更合理。
## 验证结果
- 验证方式:
1.`>1000` 旧保护分支中先加 `DEBUG` 日志,确认 `KEY == 1 / 2` 命中。
2. 替换为非法尺寸保护后,编译 [`Window.cpp`](D:/programming/imGUI-easyX/imGui-easyX/Window.cpp)。
3.`KEY == 1 ~ 4` 做逻辑推演。
- 理论结果:
- `KEY == 1 / 2`:现在应打印“大跨度但继续执行收口”日志,并继续完成 `尺寸调整已完成`
- `KEY == 3 / 4`:原本正常,行为保持一致。
- 备注:
- 当前这轮无法直接替用户跑 GUI 自动化,只能做逻辑推演和源码级编译验证。
## 落地信息
- Commit
- `f567369`:修改前快照
- 当前工作区:已替换跨度保护,待提交
- 发布版本:待定
- 备注:
- 同轮顺手删除了 `Window.cpp` 中一个未使用的 `ExMessage mm;` 遗留变量。
@@ -0,0 +1,54 @@
# Feature-20260409-0006
> 适用场景:记录小到中等规模的接口、行为、默认值、交互和内部机制变化。
## 基本信息
- ID: `Feature-20260409-0006`
- 标题: 窗口最大化收口保护从跨度阈值改为非法尺寸判断
- 类型:修改
- 级别:L2
- 模块:Window / Resize
- 状态:已完成 / 待用户回归
- 关联:
- `BUG-20260409-0003`
- `Fix-BUG-20260409-0003`
## 背景
- 旧实现把“大跨度尺寸变化”视为异常帧。
- 在初始窗口较小、显示器较大时,正常最大化会被误伤。
## 变更内容
- 删除旧的跨度保护语义:
- 不再以 `abs(finalW - width)``abs(finalH - height)` 决定是否跳过。
- 新增非法尺寸保护语义:
- 仅拦截 `<= 0` 的客户区尺寸
- 仅拦截明显超出虚拟桌面合理范围的客户区尺寸
- 新增两类调试日志:
- 非法尺寸跳过日志
- 大跨度但继续执行日志
## 对外影响
- 直接最大化的行为更稳定。
- 之前会黑背景/残影的场景,现在理论上应恢复为正常收口。
## 兼容性
- 向后兼容。
- 不涉及公开 API 变化。
## 验证方式
- 用户回归 `KEY == 1 ~ 4`
- 日志检查是否继续打印 `尺寸调整已完成`
- 单文件编译验证 `Window.cpp`
## 落地信息
- 涉及文件:
- `Window.cpp`
- 落地状态:
- 当前工作区已完成,待提交