修复 Win32 原生窗口重建后的 frame 位置漂移 - #243
Conversation
改动
说明本 PR 不包含调试日志代码,也不修改示例程序的 pin 逻辑。 该 workaround 是保守触发的:只有在 WinIdChange 后检测到明确符合标题栏高度级别漂移特征的 proposed geometry 时才会修正位置,避免影响正常窗口移动或 resize。 这个修复主要解决 QWK 托管窗口在 native window recreate 后的 frame 漂移问题。对于 pin/topmost 功能,更理想的后续方案是由 QWK 提供 验证
|
|
@wangwenx190 用AI写的一个简短的方案,基本测试通过. |
There was a problem hiding this comment.
Pull request overview
该 PR 针对 QWindowKit 在 Windows 上顶层窗口发生原生 HWND 重建后,Qt 可能在重建窗口的几何换算路径中引入一次“系统标题栏参与的偏移”,从而导致 frame 位置向下漂移的问题,在 Win32 hook 层增加了“重建前稳定 frame rect 缓存 + 重建后漂移识别与纠正”的防护逻辑。
Changes:
- 在 Win32 上新增“重建前 frame rect”缓存,并在
HWND变化后基于该 rect 生成“待纠正目标 rect”。 - 增加漂移识别逻辑:通过
WM_WINDOWPOSCHANGING与异步SetWindowPos两条路径拦截并纠正疑似漂移。 - 在私有上下文结构中新增相关状态字段以跟踪一次重建周期内的纠正流程。
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/core/contexts/win32windowcontext.cpp | 新增漂移判定函数,并在 winIdChanged/WM_WINDOWPOSCHANGING 路径中缓存与纠正 frame 漂移 |
| src/core/contexts/win32windowcontext_p.h | 为一次 native handle 重建周期增加 frame rect 缓存与纠正状态字段 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const auto oldHWnd = reinterpret_cast<HWND>(oldWinId); | ||
| if (!restoringFrameRectAfterWinIdChange && isValidWindow(oldHWnd, false, true) && | ||
| isWindowNoState(oldHWnd)) { | ||
| hasFrameRectBeforeWinIdChange = | ||
| ::GetWindowRect(oldHWnd, &frameRectBeforeWinIdChange) != FALSE; | ||
| } | ||
| removeManagedWindow(oldHWnd); | ||
| } |
|
非常感谢!我暂时也没看出什么问题,先合了。有问题我们后面再修复 |
概要
修复 QWindowKit 托管窗口在 Windows 上发生原生
HWND重建后,窗口 frame 可能向下漂移的问题。当 Qt 重新创建顶层窗口的 native window 时,QWindowKit 的 Win32 hook 需要重新绑定到新的
HWND。在旧HWND失效、新HWND完整接管之间,Qt/Windows 可能先按系统标题栏参与一次 frame/client 坐标换算。随后 Qt 会把这个带系统标题栏偏移的 client geometry 当作新的窗口位置继续应用,导致窗口整体向下偏移约一个标题栏高度。本 PR 在 QWK Win32 层缓存 native window 重建前的稳定 frame rect,并在
WM_WINDOWPOSCHANGING阶段识别和修正这类漂移,避免错误位置真正应用到窗口。问题
一个典型触发路径是示例程序中切换置顶状态: