Fix:pinning-induced window position drift on Windows - #241
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the Widgets MainWindow example’s “Pin” (stay-on-top) behavior on Windows to avoid repeated top-level flag changes that can recreate the native window handle and cause gradual frame position drift.
Changes:
- On Windows, implement pin/unpin by changing native z-order via
SetWindowPos(HWND_TOPMOST/HWND_NOTOPMOST)instead of togglingQt::WindowStaysOnTopHint+show(). - Cache the requested stay-on-top state and reapply it on
QEvent::WinIdChangeto survive native handle recreation. - Keep a geometry-preserving Qt-based fallback for non-Windows platforms and improve UI synchronization when pin requests can’t be applied.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| examples/mainwindow/mainwindow.h | Adds helper API + state flags to track and reapply stay-on-top behavior. |
| examples/mainwindow/mainwindow.cpp | Implements Windows z-order pinning, WinIdChange reapply, and updated pin button handling. |
Comments suppressed due to low confidence (2)
examples/mainwindow/mainwindow.cpp:141
- This Windows-only event handling is guarded by
Q_OS_WINDOWS, but other Windows-specific blocks in this file useQ_OS_WIN. Using a single Windows macro consistently within the file avoids platform-guard mismatches.
#ifdef Q_OS_WINDOWS
case QEvent::WinIdChange:
if (!applyingStayOnTop) {
setStayOnTop(stayOnTop);
}
break;
#endif
examples/mainwindow/mainwindow.cpp:476
setStayOnTop()is currently compiled underQ_OS_WINDOWSwhile other Windows-specific logic in this file is underQ_OS_WIN. Consider using the same macro consistently to prevent any platform-guard mismatches.
bool MainWindow::setStayOnTop(bool enabled) {
#ifdef Q_OS_WINDOWS
if (applyingStayOnTop) {
return false;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
看起来有道理,但我觉得应该是Qt内部有bug,你这样实际上只是从表层进行workaround吧? |
|
@wangwenx190 是的,这个改动属于 example 层的 workaround。问题发生在一个已经显示的顶层 QWidget 上调用 setWindowFlag(Qt::WindowStaysOnTopHint, ...) 并重新 show() 时;该过程可能重建 HWND。在 QWindowKit 自定义 non-client frame 的场景下,重建前后的 frame/client 坐标换算会导致窗口位置发生偏移,这部分可能是 Qt Windows platform plugin 的问题 |
|
你这个PR其实改了不少地方,我有点不确定为了workaround示例程序的问题,引入这种改动是否有必要 |
Fix pinning-induced window position drift on Windows
Summary
Fix the Widgets MainWindow example moving downward when the Pin button is toggled repeatedly on Windows.
The Pin action now changes only the native window z-order instead of changing
Qt::WindowStaysOnTopHintand showing the window again. The selected Pin state is cached and restored if Qt recreates the native window handle.Problem
The previous Pin callback used:
Changing a top-level window flag can recreate its native
HWND. For a frameless window with custom non-client handling, recreating and showing the window can alter the conversion between client and frame coordinates. Repeated Pin/Unpin operations therefore caused the window to drift downward by approximately one title-bar height per toggle.Changes
SetWindowPos()withHWND_TOPMOSTorHWND_NOTOPMOSTon Windows.SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDERso the operation changes only z-order.internalWinId()to avoid creating a native handle as a side effect.QEvent::WinIdChangeso pinning survives unrelated native handle recreation.This change is limited to the Widgets example and does not modify QWindowKit's public API.
Verification
QWKExample_MainWindowin Release mode with Qt 6.8.3 and MSVC.Scope
No core WindowAgent behavior or public API is changed. The fix only replaces the example application's Pin policy implementation.