Fix maximize resize guard and add records
This commit is contained in:
+40
-6
@@ -661,7 +661,6 @@ int Window::runEventLoop()
|
||||
if (GetCursorPos(&pt))
|
||||
{
|
||||
ScreenToClient(this->hWnd, &pt);
|
||||
ExMessage mm;
|
||||
// 只分发给 window 层控件(因为 dialog 已经关闭或即将关闭)
|
||||
managedDispatchActive = true;
|
||||
dispatchSyntheticMouseMoveToControls((short)pt.x, (short)pt.y);
|
||||
@@ -692,17 +691,52 @@ int Window::runEventLoop()
|
||||
int actualWidth = clientRect.right - clientRect.left;
|
||||
int actualHeight = clientRect.bottom - clientRect.top;
|
||||
|
||||
const int virtualScreenWidth = (std::max)(1, GetSystemMetrics(SM_CXVIRTUALSCREEN));
|
||||
const int virtualScreenHeight = (std::max)(1, GetSystemMetrics(SM_CYVIRTUALSCREEN));
|
||||
const int maxReasonableWidth = (std::max)(10000, virtualScreenWidth * 2);
|
||||
const int maxReasonableHeight = (std::max)(10000, virtualScreenHeight * 2);
|
||||
|
||||
// 仅拦截“明显非法”的客户区尺寸,不再按“变化跨度”误杀正常最大化。
|
||||
if (actualWidth <= 0 || actualHeight <= 0
|
||||
|| actualWidth > maxReasonableWidth || actualHeight > maxReasonableHeight)
|
||||
{
|
||||
SX_LOGD("Resize")
|
||||
<< SX_T("尺寸调整被非法尺寸保护跳过:old=(", "Resize settle skipped by invalid-size guard: old=(")
|
||||
<< width << "x" << height
|
||||
<< SX_T(") pending=(", ") pending=(")
|
||||
<< pendingW << "x" << pendingH
|
||||
<< SX_T(") actual=(", ") actual=(")
|
||||
<< actualWidth << "x" << actualHeight
|
||||
<< SX_T(") virtual=(", ") virtual=(")
|
||||
<< virtualScreenWidth << "x" << virtualScreenHeight
|
||||
<< SX_T(") maxAllowed=(", ") maxAllowed=(")
|
||||
<< maxReasonableWidth << "x" << maxReasonableHeight
|
||||
<< SX_T(")", ")");
|
||||
needResizeDirty = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
const int finalW = (std::max)(minClientW, actualWidth);
|
||||
const int finalH = (std::max)(minClientH, actualHeight);
|
||||
|
||||
// 变化过大/异常场景保护
|
||||
if (finalW != width || finalH != height)
|
||||
{
|
||||
if (abs(finalW - width) > 1000 || abs(finalH - height) > 1000)
|
||||
const int diffW = abs(finalW - width);
|
||||
const int diffH = abs(finalH - height);
|
||||
if (diffW > 1000 || diffH > 1000)
|
||||
{
|
||||
// 认为是异常帧,跳过本次(不改变任何状态)
|
||||
needResizeDirty = false;
|
||||
continue;
|
||||
SX_LOGD("Resize")
|
||||
<< SX_T("检测到大跨度尺寸调整,继续执行收口:old=(", "Large-span resize detected; continue settle: old=(")
|
||||
<< width << "x" << height
|
||||
<< SX_T(") new=(", ") new=(")
|
||||
<< finalW << "x" << finalH
|
||||
<< SX_T(") diff=(", ") diff=(")
|
||||
<< diffW << "x" << diffH
|
||||
<< SX_T(") actual=(", ") actual=(")
|
||||
<< actualWidth << "x" << actualHeight
|
||||
<< SX_T(") virtual=(", ") virtual=(")
|
||||
<< virtualScreenWidth << "x" << virtualScreenHeight
|
||||
<< SX_T(")", ")");
|
||||
}
|
||||
|
||||
// 再次冻结窗口更新,保证批量绘制的原子性
|
||||
|
||||
@@ -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`
|
||||
- 落地状态:
|
||||
- 当前工作区已完成,待提交
|
||||
Reference in New Issue
Block a user