Details
-
Bug
-
Resolution: Unresolved
-
P2: Important
-
None
-
6.5, 6.6, 6.7
-
None
-
Windows 10, Windows 11
Qt6.5, Qt6.6, Qt6.7
Description
Aditional cases for QTBUG-117704 Dragging Window handling WM_NCCALCSIZE and WM_NCHITTEST squishes contents - Qt Bug Tracker
Test 1 WM_NCCALCSIZE
#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 : { NCCALCSIZE_PARAMS* sizeParams = reinterpret_cast<NCCALCSIZE_PARAMS*>(msg->lParam); QMargins customMargins = { 1, 70, 1, 1 } ; sizeParams->rgrc[0].left += customMargins.left(); sizeParams->rgrc[0].top += customMargins.top(); sizeParams->rgrc[0].right -= customMargins.right(); sizeParams->rgrc[0].bottom -= customMargins.bottom(); 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); app.setApplicationName("Foo"); Draggy wrap; QHBoxLayout layout(&wrap); QLabel foo("Foo"); layout.addWidget(&foo, 0, Qt::AlignCenter); wrap.show(); return app.exec(); }
Test 2, QPlatformWindow::setCustomMargins(...)
*.pro
QT += gui-private
#include <QApplication> #include <QHBoxLayout> #include <QLabel> #include <QPainter> #include <QWidget> #include <Windows.h> #include <windowsx.h> #include <QWindow> #define QTN_QT6 1 #include <qpa/qplatformwindow.h> #include <qpa/qplatformnativeinterface.h> #include <qpa/qwindowsysteminterface.h> #ifdef QTN_QT6 #include <qpa/qplatformwindow_p.h> using namespace QNativeInterface::Private; #endif class Draggy : public QWidget { protected: bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result) override { MSG* msg = reinterpret_cast<MSG*>(message); switch (msg->message) { 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 showEvent(QShowEvent* event) override { QMargins customMargins = { 1, 70, 1, 1 }; RECT rect = { 0,0,0,0 }; DWORD style = WS_CAPTION | WS_POPUP | WS_VISIBLE | WS_SYSMENU | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX; AdjustWindowRect(&rect, style, FALSE); customMargins -= QMargins(qAbs(rect.left), qAbs(rect.top), qAbs(rect.right), qAbs(rect.bottom)); QWindow* windowHandle = window() != Q_NULLPTR ? window()->windowHandle() : Q_NULLPTR; if (windowHandle == Q_NULLPTR) return; windowHandle->setProperty("_q_windowsCustomMargins", QVariant::fromValue(customMargins)); #ifdef QTN_QT6 QPlatformWindow* pw = windowHandle->handle(); if (QWindowsWindow* platformWindow = dynamic_cast<QWindowsWindow*>(pw)) { if (platformWindow->customMargins() == customMargins) return; platformWindow->setCustomMargins(customMargins); } #else QPlatformWindow* platformWindow = windowHandle->handle(); Q_ASSERT(platformWindow != Q_NULL); if (platformWindow == Q_NULL || QGuiApplication::platformNativeInterface()->windowProperty(platformWindow, QStringLiteral("WindowsCustomMargins")) == QVariant::fromValue(customMargins)) return; QGuiApplication::platformNativeInterface()->setWindowProperty(platformWindow, QStringLiteral("WindowsCustomMargins"), QVariant::fromValue(customMargins)); #endif QWidget::showEvent(event); } 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); app.setApplicationName("Foo"); Draggy wrap; QHBoxLayout layout(&wrap); QLabel foo("Foo"); layout.addWidget(&foo, 0, Qt::AlignCenter); wrap.show(); return app.exec(); }