Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-124250

Dragging Window handling with Win32 custom NonClient frame squishes contents

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P2: Important
    • None
    • 6.5, 6.6, 6.7
    • QPA: Windows
    • None
    • Windows 10, Windows 11
      Qt6.5, Qt6.6, Qt6.7
    • Windows

    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();
      }

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            owolff Oliver Wolff
            besd Dmitry Beskorovainov
            Votes:
            3 Vote for this issue
            Watchers:
            6 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes