Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

My window geometry fails without explicable reasons when trying to change the size after a DPI scaling



  • I'm creating a frameless application, which should allow the user to resize it. As Qt doesn't provide any simple and native solution to turn that possible, I implemented this behavior in the following manner:

    1. configured my qml ApplicationWindow with the following flags:
    ApplicationWindow
    {
        id: awMainForm
        objectName: "awMainForm"
        width: 602
        height: 728
        minimumWidth: 602
        minimumHeight: 600
        flags: Qt.Window | Qt.FramelessWindowHint
        ....
    
    1. In my c++ code, I overridden the Qt window message loop in the following manner:
        // get previous Windows procedure, and set newly allocated Windows procedure
        m_fPrevWndProc = (WNDPROC)::SetWindowLongPtrW((HWND)pWindow->winId(), GWLP_WNDPROC, (LONG_PTR)WndProc);
    
    1. In the window message loop, I listen the WM_NCHITTEST message, to detect when the mouse is above the border of the form, and to trigger the matching resize action on my form
    LRESULT CALLBACK WQTFramelessForm::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        // dispatch message
        switch (msg)
        {
            case WM_NCHITTEST:
            {
                RECT winRect;
                ::GetWindowRect(hWnd, &winRect);
    
                const long x            = GET_X_LPARAM(lParam);
                const long y            = GET_Y_LPARAM(lParam);
                const bool resizeWidth  = m_pWindow->minimumWidth()  != m_pWindow->maximumWidth();
                const bool resizeHeight = m_pWindow->minimumHeight() != m_pWindow->maximumHeight();
    
                LRESULT result = 0;
    
                if (resizeWidth)
                    // left or right border
                    if (x >= winRect.left && x < winRect.left + m_BorderWidth)
                        result = HTLEFT;
                    else
                    if (x < winRect.right && x >= winRect.right - m_BorderWidth)
                        result = HTRIGHT;
    
                if (resizeHeight)
                    // top or bottom border
                    if (y >= winRect.top && y < winRect.top + m_BorderWidth)
                        result = HTTOP;
                    else
                    if (y < winRect.bottom && y >= winRect.bottom - m_BorderWidth)
                        result = HTBOTTOM;
    
                if (resizeWidth && resizeHeight)
                    // top left, top right, bottom left or bottom right corner
                    if (x >= winRect.left && x < winRect.left + m_BorderWidth &&
                            y >= winRect.top && y < winRect.top + m_BorderWidth)
                        result = HTTOPLEFT;
                    else
                    if (x < winRect.right && x >= winRect.right - m_BorderWidth &&
                            y >= winRect.top && y < winRect.top + m_BorderWidth)
                        result = HTTOPRIGHT;
                    else
                    if (x >= winRect.left && x < winRect.left + m_BorderWidth &&
                            y < winRect.bottom && y >= winRect.bottom - m_BorderWidth)
                        result = HTBOTTOMLEFT;
                    else
                    if (x < winRect.right && x >= winRect.right - m_BorderWidth &&
                            y < winRect.bottom && y >= winRect.bottom - m_BorderWidth)
                        result = HTBOTTOMRIGHT;
    
                if (!result)
                {
                    if (m_fPrevWndProc)
                        return m_fPrevWndProc(hWnd, msg, wParam, lParam);
    
                    return HTCLIENT;
                }
    
                return result;
            }
    
            default:
                break;
        }
    
        if (m_fPrevWndProc)
            return m_fPrevWndProc(hWnd, msg, wParam, lParam);
    
        return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    

    This is not perfect (e.g the Windows aero functionalities aren't working and there are several missing stuff like the shadow surrounding the window), but it works pretty well for my needs.

    Except for one thing.

    Indeed my application should support the per monitor DPI functionalities. To test that, I configured my first monitor to 96 dpi, and the second to 150 dpi. My app opens on the 96 dpi monitor, but when I try to move it on the 150 dpi monitor, I get the following warning:
    [QT][20:46:42 + 00:00:17.663] QWindowsWindow::setGeometry: Unable to set geometry 1204x1456+3346+438 (frame: 1204x1456+3346+438) on WQTMainForm_QMLTYPE_105/"awMainForm" on "\\.\DISPLAY1". Resulting geometry: 1806x2184+3346+438 (frame: 1806x2184+3346+438) margins: 0, 0, 0, 0 minimum size: 602x600 MINMAXINFO maxSize=0,0 maxpos=0,0 mintrack=1204,1200 maxtrack=0,0) - qwindowswindow.cpp:1891, void __cdecl QWindowsWindow::setGeometry(const class QRect &)

    However my window appears on my 150dpi monitor but is too height and exceeds the screen. When I try to resize it by clicking the left and top edge, the app disappear completely from my monitor and I get the following warning:
    [QT][20:51:19 + 00:04:54.975] QSGThreadedRenderLoop: expose event received for window WQTMainForm_QMLTYPE_105(0x1cb897899c0 active exposed, visibility=QWindow::Windowed, flags=QFlags<Qt::WindowType>(Window|FramelessWindowHint), title=CopyTrans Filey, name=awMainForm, geometry=1952,589 903x550) with invalid geometry: QRect(1952,589 903x550) on QScreen(0x1cb86646f60, name=\\.\DISPLAY1) - scenegraph\qsgthreadedrenderloop.cpp:1308, void __cdecl QSGThreadedRenderLoop::handleExposure(class QQuickWindow *)

    For me these messages are completely obscure and I cannot figure out what is happening here. Why my app disappears? What should I do to resolve that? As far as I know the error seems to happen because my app exceeds the screen, but how a dpi scaled app may NEVER exceed the screen? Is Qt unable to support correctly a so basic issue?

    I would be grateful if someone could point me what is the issue I'm facing, and what I can do to resolve it.


Log in to reply