Details
-
Bug
-
Resolution: Fixed
-
P2: Important
-
6.5.3, 6.6.1
-
None
-
Windows 10 22H2
-
-
03a416420 (dev), d2881ae09 (6.7), 0056998ba (6.6), 0eb11bcee (tqtc/lts-6.5)
Description
I'm implementing a custom window on Windows with a custom title bar. To do this, I'm handling WM_NCCALCSIZE to disable the title bar and WM_NCHITTEST to handle resizing/moving.
After updating from Qt 6.5.0 to Qt 6.5.3, I noticed that when dragging, the window gets squished to the left when moving, but when resizing, the effect vanishes.
This seems to be caused by https://codereview.qt-project.org/c/qt/qtbase/+/492695, specifically the added call to calculateFullFrameMargins() in QWindowsWindow::handleGeometryChange (removing that call seems to fix this bug). This will be called when the window is moved and will eventually set different margins than the ones set in qWindowsWndProc when handling WM_NCCALCSIZE (or the default margins I suppose).
I made an example app:
Before dragging:
After dragging:
As explained before, resizing the window fixes the bug.
In the debug logs, you can see them fighting over the correct margins:
qt.qpa.window: qWindowsWndProc WM_NCCALCSIZE for 0x1e70696 QMargins(0, 0, 0, 0) qt.qpa.window: QWindowsWindow::setFullFrameMargins QWidgetWindow(0x22092a2bf40, name="QWidgetClassWindow") QMargins(8, -8, 8, 8) -> QMargins(0, 0, 0, 0) qt.qpa.window: QWindowsWindow::setFullFrameMargins QWidgetWindow(0x22092a2bf40, name="QWidgetClassWindow") QMargins(0, 0, 0, 0) -> QMargins(8, -8, 8, 8) qt.qpa.window: qWindowsWndProc WM_NCCALCSIZE for 0x1e70696 QMargins(0, 0, 0, 0) qt.qpa.window: QWindowsWindow::setFullFrameMargins QWidgetWindow(0x22092a2bf40, name="QWidgetClassWindow") QMargins(8, -8, 8, 8) -> QMargins(0, 0, 0, 0) qt.qpa.window: QWindowsWindow::setFullFrameMargins QWidgetWindow(0x22092a2bf40, name="QWidgetClassWindow") QMargins(0, 0, 0, 0) -> QMargins(8, -8, 8, 8) qt.qpa.window: qWindowsWndProc WM_NCCALCSIZE for 0x1e70696 QMargins(0, 0, 0, 0) qt.qpa.window: QWindowsWindow::setFullFrameMargins QWidgetWindow(0x22092a2bf40, name="QWidgetClassWindow") QMargins(8, -8, 8, 8) -> QMargins(0, 0, 0, 0) qt.qpa.window: QWindowsWindow::setFullFrameMargins QWidgetWindow(0x22092a2bf40, name="QWidgetClassWindow") QMargins(0, 0, 0, 0) -> QMargins(8, -8, 8, 8)
#include <QApplication> #include <QHBoxLayout> #include <QLabel> #include <QPainter> #include <QWidget> #include <Windows.h> #include <windowsx.h> class Draggy : public QWidget { bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result) override { MSG *msg = reinterpret_cast<MSG *>(message); switch (msg->message) { case WM_NCCALCSIZE: { *result = 0; return true; } break; case WM_NCHITTEST: { const LONG borderWidth = 8; RECT winrect; GetWindowRect(HWND(winId()), &winrect); long x = GET_X_LPARAM(msg->lParam); long y = GET_Y_LPARAM(msg->lParam); QPoint point(x - winrect.left, y - winrect.top); *result = 0; bool resizeWidth = minimumWidth() != maximumWidth(); bool resizeHeight = minimumHeight() != maximumHeight(); if (resizeWidth) { // left border if (x < winrect.left + borderWidth) { *result = HTLEFT; } // right border else if (x >= winrect.right - borderWidth) { *result = HTRIGHT; } } if (resizeHeight) { // bottom border if (y >= winrect.bottom - borderWidth) { *result = HTBOTTOM; } // top border else if (y < winrect.top + borderWidth) { *result = HTTOP; } } if (resizeWidth && resizeHeight) { // bottom left corner if (x >= winrect.left && x < winrect.left + borderWidth && y < winrect.bottom && y >= winrect.bottom - borderWidth) { *result = HTBOTTOMLEFT; } // bottom right corner else if (x < winrect.right && x >= winrect.right - borderWidth && y < winrect.bottom && y >= winrect.bottom - borderWidth) { *result = HTBOTTOMRIGHT; } // top left corner else if (x >= winrect.left && x < winrect.left + borderWidth && y >= winrect.top && y < winrect.top + borderWidth) { *result = HTTOPLEFT; } // top right corner else if (x < winrect.right && x >= winrect.right - borderWidth && y >= winrect.top && y < winrect.top + borderWidth) { *result = HTTOPRIGHT; } } if (*result == 0) { *result = HTCAPTION; } return true; } break; default: return false; } } void paintEvent(QPaintEvent *event) override { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setBrush(Qt::black); auto rect = this->rect(); painter.drawLine(rect.bottomLeft(), rect.topRight()); painter.drawLine(rect.topLeft(), rect.bottomRight()); } }; int main(int argc, char **argv) { QApplication app(argc, argv); Draggy wrap; QHBoxLayout layout(&wrap); QLabel foo("Foo"); layout.addWidget(&foo, 0, Qt::AlignCenter); wrap.show(); return app.exec(); }
Attachments
For Gerrit Dashboard: QTBUG-117704 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
509236,5 | Windows QPA: don't override user-removed margins | dev | qt/qtbase | Status: MERGED | +2 | 0 |
526118,2 | Windows QPA: don't override user-removed margins | 6.7 | qt/qtbase | Status: MERGED | +2 | 0 |
526306,2 | Windows QPA: don't override user-removed margins | 6.6 | qt/qtbase | Status: MERGED | +2 | 0 |
526413,2 | Windows QPA: don't override user-removed margins | tqtc/lts-6.5 | qt/tqtc-qtbase | Status: MERGED | +2 | 0 |