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

Dragging Window handling WM_NCCALCSIZE across screens grows its size

    XMLWordPrintable

Details

    • Bug
    • Resolution: Fixed
    • P2: Important
    • None
    • 6.6.2
    • QPA: Windows
    • None
    • Windows

    Description

      I'm implementing a custom window on Windows with a custom title bar. To do this, I'm handling WM_NCCALCSIZE, which removes the window frame (see example below).

      When dragging this window across screens with different DPI (multiple times back and forth), the size of the window slowly grows. This doesn't happen if NCCALCSIZE isn't handled.

      From debugging, I found that AdjustWindowRectExForDpi, which is called in QWindowsGeometryHint::frame, returns the "bad" margins for the window.

      Adding the check for manually overridden margins from QTBUG-117704 in QWindowsGeometryHint::frame yields the correct result:

      QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd, DWORD style, DWORD exStyle)
      {
          if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
              return {};
          RECT windowRect{};
          RECT clientRect{};
          GetWindowRect(hwnd, &windowRect);
          GetClientRect(hwnd, &clientRect);
          if (qrectFromRECT(windowRect).size() == qrectFromRECT(clientRect).size())
              return {};
          // ...
      

      I'm not sure if that's a correct fix though.

      Debug Logs (without the patch):

      qt.qpa.window: >QWindowsGeometryHint::applyToMinMaxInfo< min=0,0 max=16777215,16777215 margins=QMargins(0, 0, 0, 0) in MINMAXINFO(maxSize=POINT(x=1936, y=1096), maxpos=POINT(x=-8, y=-8), maxtrack=POINT(x=3220, y=1108), mintrack=POINT(x=136, y=39))
      qt.qpa.window: <QWindowsGeometryHint::applyToMinMaxInfo out MINMAXINFO(maxSize=POINT(x=1936, y=1096), maxpos=POINT(x=-8, y=-8), maxtrack=POINT(x=3220, y=1108), mintrack=POINT(x=136, y=39))
      qt.qpa.window: QWindowsWindow::getSizeHints QWidgetWindow(0x1e624f97c40, name="QWidgetClassWindow") MINMAXINFO(maxSize=POINT(x=1936, y=1096), maxpos=POINT(x=-8, y=-8), maxtrack=POINT(x=3220, y=1108), mintrack=POINT(x=136, y=39))
      qt.qpa.window: QWindowsGeometryHint::frame style=0x96cf0000 exStyle=0x100 dpi=120 RECT(left=-9, top=-38, right=9, bottom=9 (18x47)) QMargins(9, 38, 9, 9)
      qt.qpa.window: QWindowsWindow::checkForScreenChanged QWidgetWindow(0x1e624f97c40, name=QWidgetClassWindow) "ASUS VX278"->"SyncMaster"
      qt.qpa.window: QWindowsGeometryHint::frame style=0x96cf0000 exStyle=0x100 dpi=120 RECT(left=-9, top=-38, right=9, bottom=9 (18x47)) QMargins(9, 38, 9, 9)
      qt.qpa.window: QWindowsWindow::setFullFrameMargins QWidgetWindow(0x1e624f97c40, name="QWidgetClassWindow") QMargins(0, 0, 0, 0) -> QMargins(9, 38, 9, 9)
      qt.qpa.window: QWindowsGeometryHint::frame style=0x96cf0000 exStyle=0x100 dpi=120 RECT(left=-9, top=-38, right=9, bottom=9 (18x47)) QMargins(9, 38, 9, 9)
      qt.qpa.window: >QWindowsGeometryHint::applyToMinMaxInfo< min=0,0 max=16777215,16777215 margins=QMargins(9, 38, 9, 9) in MINMAXINFO(maxSize=POINT(x=1938, y=1098), maxpos=POINT(x=-9, y=-9), maxtrack=POINT(x=3220, y=1108), mintrack=POINT(x=166, y=47))
      qt.qpa.window: <QWindowsGeometryHint::applyToMinMaxInfo out MINMAXINFO(maxSize=POINT(x=1938, y=1098), maxpos=POINT(x=-9, y=-9), maxtrack=POINT(x=3220, y=1108), mintrack=POINT(x=166, y=47))
      qt.qpa.window: QWindowsWindow::getSizeHints QWidgetWindow(0x1e624f97c40, name="QWidgetClassWindow") MINMAXINFO(maxSize=POINT(x=1938, y=1098), maxpos=POINT(x=-9, y=-9), maxtrack=POINT(x=3220, y=1108), mintrack=POINT(x=166, y=47))
      qt.qpa.window: qWindowsWndProc WM_NCCALCSIZE for 0x3e0998 QMargins(0, 0, 0, 0)
      qt.qpa.window: QWindowsWindow::setFullFrameMargins QWidgetWindow(0x1e624f97c40, name="QWidgetClassWindow") QMargins(9, 38, 9, 9) -> QMargins(0, 0, 0, 0)
      RESIZED 268 x 172
      qt.qpa.window: qWindowsWndProc WM_NCCALCSIZE for 0x3e0998 QMargins(0, 0, 0, 0)
      qt.qpa.window: >QWindowsGeometryHint::applyToMinMaxInfo< min=0,0 max=16777215,16777215 margins=QMargins(0, 0, 0, 0) in MINMAXINFO(maxSize=POINT(x=1938, y=1098), maxpos=POINT(x=-9, y=-9), maxtrack=POINT(x=3220, y=1108), mintrack=POINT(x=166, y=47))
      qt.qpa.window: <QWindowsGeometryHint::applyToMinMaxInfo out MINMAXINFO(maxSize=POINT(x=1938, y=1098), maxpos=POINT(x=-9, y=-9), maxtrack=POINT(x=3220, y=1108), mintrack=POINT(x=166, y=47))
      qt.qpa.window: QWindowsWindow::getSizeHints QWidgetWindow(0x1e624f97c40, name="QWidgetClassWindow") MINMAXINFO(maxSize=POINT(x=1938, y=1098), maxpos=POINT(x=-9, y=-9), maxtrack=POINT(x=3220, y=1108), mintrack=POINT(x=166, y=47))
      

      Code:

      #define WIN32_LEAN_AND_MEAN
      #include <QApplication>
      #include <QLabel>
      #include <QWidget>
      #include <Windows.h>
      
      class RootWidget : public QWidget {
      protected:
          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;
      
              case WM_NCHITTEST: // just to be able to move it around
                  *result = HTCAPTION;
                  return true;
      
              case WM_SIZE: {
                  UINT width = LOWORD(msg->lParam);
                  UINT height = HIWORD(msg->lParam);
                  qDebug() << "RESIZED" << width << "x" << height;
              } break;
              }
      
              QWidget::nativeEvent(eventType, message, result);
              return false;
          }
      };
      
      int main(int argc, char *argv[]) {
          QApplication a(argc, argv);
          RootWidget root;
          QLabel lbl("Hello world!", &root);
          lbl.resize(200, 100);
      
          root.show();
          return QApplication::exec();
      }
      

      Attachments

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

        Activity

          People

            owolff Oliver Wolff
            nerixyz Tom Fors
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes