I'm struggling to solve the following problem. My window top left corner has negative coordinates when maximized (both x and y are -9), and it's size is actually bigger than the available area. I'm using WinAPI to get some platform specific features like Aero snap, so it becomes complicated to understand why exactly this problem happens. My window has the following styles and attributes set:
setFlags(Qt::Window | Qt::FramelessWindowHint);
SetWindowLongPtr((HWND)winId(), GWL_STYLE, WS_POPUPWINDOW | WS_CAPTION | WS_SIZEBOX | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CLIPCHILDREN);
WS_CAPTION is same as WS_BORDER | WS_DLGFRAME, so if I remove WS_DLGFRAME, maximized size is ok, and I see that the native maximizing animation disappears — but I get the flickering white border when resize because of WS_SIZEBOX (same as WS_THICKFRAME). Without WS_SIZEBOX I loose aero snap.
I thought maybe I can do something with maximixed size in nativeEvent, so I tried the following:
bool FramelessWindow::nativeEvent(const QByteArray& eventType, void* message, qintptr* result)
{
if (auto* msg = static_cast<MSG*>(message); msg->message == WM_NCCALCSIZE)
{
NCCALCSIZE_PARAMS& params = *reinterpret_cast<NCCALCSIZE_PARAMS*>(msg->lParam);
if (params.rgrc[0].top != 0)
{
--params.rgrc[0].top;
}
*result = WVR_REDRAW;
return true; //this removes the native border and title
}
else if (msg->message == WM_GETMINMAXINFO)
{
if (IsMaximized((HWND)winId()))
{
MINMAXINFO* mmi = (MINMAXINFO*)msg->lParam;
auto g = screen()->availableGeometry();
mmi->ptMaxTrackSize.x = g.width() * devicePixelRatio();
mmi->ptMaxTrackSize.y = g.height() * devicePixelRatio();
*result = 0;
return true;
}
}
return QQuickWindow::nativeEvent(eventType, message, result);
}
For some reason, MINMAXINFO overloading does nothing until I set mmi->ptMaxTrackSize.x = g.width() * devicePixelRatio() - 1;. In this case, the size is almost nice, except that there is a 1 px empty gap between the right border of the screen and the window. So there is no way I can obtain the correct size with changing MINMAXINFO, because the real correct size should be actually same as in the above code. The initial ptMaxTrackSize is pretty strange: 3462, 1462 in mmi vs 3440, 1390 in availableGeometry).
I can do something like that, but I'd like to keep QWindow::Maximized state, which is reset when I call setGeometry.
bool FramelessWindow::eventFilter(QObject* watched, QEvent* event)
{
if (event->type() == QEvent::WindowStateChange && QWindow::visibility() == QWindow::Maximized)
{
setGeometry(screen()->availableGeometry()); //the window is no longer maximized
return true;
}
return QQuickWindow::eventFilter(watched, event);
}
Since I'm not able to use QWindow::Maximized in setGeometry approach, this approach equals to implementing my own maximize, normalize and so on, what is undesirable and also won't affect on maximizing with aero.
I also tried to add margins in maximized state, but creating a layout causes ugly flickering when resize, since the instance of my window is created in QML. And I'm unable to use setLayout and try to add margins in C++ code, because my class inherited QQuickWindow.
Am I missing something?
UPD: Now I have found out that this problem is mainly related to WinAPI + framelessness, not to Qt, so not only Qt users have "window extends beyond the screen when maximized". It helps a bit, at least I am now able to test the already existing WinAPI solutions, but the problem is they don't work as expected.
I've tried modifying NCCALCSIZE_PARAMS while processing the WM_NCCALCSIZE message:
Here is what I got in rgrc[0]:
What I've tried according to melak47's code:
void adjustMaximized(HWND hwnd, RECT& rect)
{
auto monitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL);
if (!monitor)
{
return;
}
MONITORINFO monitor_info{};
monitor_info.cbSize = sizeof(monitor_info);
if (!::GetMonitorInfoW(monitor, &monitor_info))
{
return;
}
rect = monitor_info.rcWork;
}
bool FramelessWindow::nativeEvent(const QByteArray& eventType, void* message, qintptr* result)
{
if (auto* msg = static_cast<MSG*>(message); msg->message == WM_NCCALCSIZE)
{
NCCALCSIZE_PARAMS& params = *reinterpret_cast<NCCALCSIZE_PARAMS*>(msg->lParam);
if (params.rgrc[0].top != 0)
{
--params.rgrc[0].top;
}
if (IsMaximized(hwnd_))
{
adjustMaximized(hwnd_, params.rgrc[0]);
}
return true;
}
...
}

