Search code examples
c++qtaeroborderlessaero-snap

Borderless window with Aero Snap too large in maximized state


I am trying to make a borderless window in Qt5.6.0, with aero-snap functionality. Everything works, except when I maximize the window : it is too big.

My screen resolution is 2560x1440, so the window should be sized 2560x1400 (40 Pixels for the Taskbar), but in the WM_SIZE message, the new size is 2576x1416. So the window is exactly 8 pixels too big in every direction. This also means that the window is not aligned in the top-left corner, it is exactly 8 pixels off-screen in both directions.

I can't find a solution for this problem, everything I have tried doesn't work and causes bugs.

The only thing that fixes this is to remove the WS_CAPTION and WS_THICKFRAME styles, but then I lose the areo snap functionality.

I somehow have to tell Qt or DWM to make the window 16 pixels smaller and move it 8 pixels right, and bottom. Does anybody have an idea on how to do that?


Solution

  • My first try, was setting the window geometry to the available geometry:

    QRect rect = QApplication::desktop()->availableGeometry();
    setGeometry(rect.left() , rect.top(), rect.right(), rect.bottom());
    

    The only Problem is that the window is a pixel too small on the right and bottom side and

    setGeometry(rect.left() , rect.top(), rect.right() + 1, rect.bottom() + 1);
    

    gives me an error:

    QWindowsWindow::setGeometry: Unable to set geometry 2560x1400+0+0 on QWidgetWindow/'MainWindowWindow'. Resulting geometry:  2576x1416+-8+-8 (frame: 0, 0, 0, 0, custom margin: 0, 0, 0, 0, minimum size: 45x13, maximum size: 16777215x16777215)
    

    Then I looked at the rectangle coordinates of Visual Studio 2015 and they are the same size as my implementation of a borderless window, 8 pixels larger in every direction.

    I can give the contents of my window a margin of 8 so it doesn't clip out of the screen if the window is maximized and set the window region:

    setContentsMargins({ 8, 8, 8, 8 });
    
    HRGN WinRgn;
    RECT winrect;
    GetClientRect(hwnd, &winrect);
    WinRgn = CreateRectRgn(8, 8, winrect.right - 8, winrect.bottom - 8);
    SetWindowRgn(hwnd, WinRgn, true);
    

    When the window gets restored, we need to reset the previous changes. The result is:

    case WM_SIZE:
        WINDOWPLACEMENT wp;
        wp.length = sizeof(WINDOWPLACEMENT);
        GetWindowPlacement(hwnd, &wp);
        if (wp.showCmd == SW_MAXIMIZE) {
            setContentsMargins({ 8, 8, 8, 8 });
    
            HRGN WinRgn;
            RECT winrect;
            GetClientRect(hwnd, &winrect);
            WinRgn = CreateRectRgn(8, 8, winrect.right - 8, winrect.bottom - 8);
            SetWindowRgn(hwnd, WinRgn, true);
            UpdateWindow(hwnd);
    
            is_fullscreen = true;
    
        } else {
            if (is_fullscreen) {
                setContentsMargins({ 0, 0, 0, 0 });
                SetWindowRgn(hwnd, NULL, true);
    
                is_fullscreen = false;
            }
        }
        break;