|
|
|
@ -1025,6 +1025,21 @@ static QSize toNativeSizeConstrained(QSize dip, const QScreen *s)
|
|
|
|
|
return dip;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Helper for checking if frame adjustment needs to be skipped
|
|
|
|
|
// NOTE: Unmaximized frameless windows will skip margins calculation
|
|
|
|
|
static bool shouldOmitFrameAdjustment(const Qt::WindowFlags flags, DWORD style)
|
|
|
|
|
{
|
|
|
|
|
return flags.testFlag(Qt::FramelessWindowHint) && !(style & WS_MAXIMIZE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Helper for checking if frame adjustment needs to be skipped
|
|
|
|
|
// NOTE: Unmaximized frameless windows will skip margins calculation
|
|
|
|
|
static bool shouldOmitFrameAdjustment(const Qt::WindowFlags flags, HWND hwnd)
|
|
|
|
|
{
|
|
|
|
|
DWORD style = hwnd != nullptr ? DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)) : 0;
|
|
|
|
|
return flags.testFlag(Qt::FramelessWindowHint) && !(style & WS_MAXIMIZE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\class QWindowsGeometryHint
|
|
|
|
|
\brief Stores geometry constraints and provides utility functions.
|
|
|
|
@ -1037,7 +1052,7 @@ static QSize toNativeSizeConstrained(QSize dip, const QScreen *s)
|
|
|
|
|
|
|
|
|
|
QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, DWORD style, DWORD exStyle)
|
|
|
|
|
{
|
|
|
|
|
if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
|
|
|
|
|
if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
|
|
|
|
|
return {};
|
|
|
|
|
RECT rect = {0,0,0,0};
|
|
|
|
|
style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs.
|
|
|
|
@ -1053,15 +1068,13 @@ QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, DWORD styl
|
|
|
|
|
|
|
|
|
|
QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, HWND hwnd)
|
|
|
|
|
{
|
|
|
|
|
if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
|
|
|
|
|
return {};
|
|
|
|
|
return frameOnPrimaryScreen(w, DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)),
|
|
|
|
|
DWORD(GetWindowLongPtr(hwnd, GWL_EXSTYLE)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QMargins QWindowsGeometryHint::frame(const QWindow *w, DWORD style, DWORD exStyle, qreal dpi)
|
|
|
|
|
{
|
|
|
|
|
if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
|
|
|
|
|
if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
|
|
|
|
|
return {};
|
|
|
|
|
RECT rect = {0,0,0,0};
|
|
|
|
|
style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs.
|
|
|
|
@ -1080,7 +1093,7 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, DWORD style, DWORD exStyl
|
|
|
|
|
|
|
|
|
|
QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd, DWORD style, DWORD exStyle)
|
|
|
|
|
{
|
|
|
|
|
if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
|
|
|
|
|
if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
|
|
|
|
|
return {};
|
|
|
|
|
if (QWindowsScreenManager::isSingleScreen())
|
|
|
|
|
return frameOnPrimaryScreen(w, style, exStyle);
|
|
|
|
@ -1094,8 +1107,6 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd, DWORD style, D
|
|
|
|
|
|
|
|
|
|
QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd)
|
|
|
|
|
{
|
|
|
|
|
if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
|
|
|
|
|
return {};
|
|
|
|
|
return frame(w, hwnd, DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)),
|
|
|
|
|
DWORD(GetWindowLongPtr(hwnd, GWL_EXSTYLE)));
|
|
|
|
|
}
|
|
|
|
@ -1104,7 +1115,7 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd)
|
|
|
|
|
QMargins QWindowsGeometryHint::frame(const QWindow *w, const QRect &geometry,
|
|
|
|
|
DWORD style, DWORD exStyle)
|
|
|
|
|
{
|
|
|
|
|
if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
|
|
|
|
|
if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
|
|
|
|
|
return {};
|
|
|
|
|
if (QWindowsScreenManager::isSingleScreen()
|
|
|
|
|
|| !QWindowsContext::shouldHaveNonClientDpiScaling(w)) {
|
|
|
|
@ -2042,7 +2053,7 @@ void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam)
|
|
|
|
|
// If the window does not have a frame, WM_MOVE and WM_SIZE won't be
|
|
|
|
|
// called which prevents the content from being scaled appropriately
|
|
|
|
|
// after a DPI change.
|
|
|
|
|
if (m_data.flags & Qt::FramelessWindowHint)
|
|
|
|
|
if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
|
|
|
|
|
handleGeometryChange();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2575,26 +2586,26 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowStates newState)
|
|
|
|
|
if (testFlag(HasBorderInFullScreen))
|
|
|
|
|
newStyle |= WS_BORDER;
|
|
|
|
|
setStyle(newStyle);
|
|
|
|
|
// Use geometry of QWindow::screen() within creation or the virtual screen the
|
|
|
|
|
// window is in (QTBUG-31166, QTBUG-30724).
|
|
|
|
|
const QScreen *screen = window()->screen();
|
|
|
|
|
if (!screen)
|
|
|
|
|
screen = QGuiApplication::primaryScreen();
|
|
|
|
|
const QRect r = screen ? QHighDpi::toNativePixels(screen->geometry(), window()) : m_savedFrameGeometry;
|
|
|
|
|
|
|
|
|
|
const HMONITOR monitor = MonitorFromWindow(m_data.hwnd, MONITOR_DEFAULTTONEAREST);
|
|
|
|
|
MONITORINFO monitorInfo = {};
|
|
|
|
|
monitorInfo.cbSize = sizeof(MONITORINFO);
|
|
|
|
|
GetMonitorInfoW(monitor, &monitorInfo);
|
|
|
|
|
const QRect screenGeometry(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top,
|
|
|
|
|
monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left,
|
|
|
|
|
monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top);
|
|
|
|
|
if (newState & Qt::WindowMinimized) {
|
|
|
|
|
setMinimizedGeometry(m_data.hwnd, r);
|
|
|
|
|
setMinimizedGeometry(m_data.hwnd, screenGeometry);
|
|
|
|
|
if (stateChange & Qt::WindowMaximized)
|
|
|
|
|
setRestoreMaximizedFlag(m_data.hwnd, newState & Qt::WindowMaximized);
|
|
|
|
|
} else {
|
|
|
|
|
const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE;
|
|
|
|
|
const bool wasSync = testFlag(SynchronousGeometryChangeEvent);
|
|
|
|
|
setFlag(SynchronousGeometryChangeEvent);
|
|
|
|
|
SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf);
|
|
|
|
|
SetWindowPos(m_data.hwnd, HWND_TOP, screenGeometry.left(), screenGeometry.top(), screenGeometry.width(), screenGeometry.height(), swpf);
|
|
|
|
|
if (!wasSync)
|
|
|
|
|
clearFlag(SynchronousGeometryChangeEvent);
|
|
|
|
|
clearFlag(MaximizeToFullScreen);
|
|
|
|
|
QWindowSystemInterface::handleGeometryChange(window(), r);
|
|
|
|
|
QWindowSystemInterface::handleGeometryChange(window(), screenGeometry);
|
|
|
|
|
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
@ -2761,7 +2772,7 @@ bool QWindowsWindow::handleGeometryChanging(MSG *message) const
|
|
|
|
|
|
|
|
|
|
void QWindowsWindow::setFullFrameMargins(const QMargins &newMargins)
|
|
|
|
|
{
|
|
|
|
|
if (m_data.flags & Qt::FramelessWindowHint)
|
|
|
|
|
if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
|
|
|
|
|
return;
|
|
|
|
|
if (m_data.fullFrameMargins != newMargins) {
|
|
|
|
|
qCDebug(lcQpaWindow) << __FUNCTION__ << window() << m_data.fullFrameMargins << "->" << newMargins;
|
|
|
|
@ -2780,13 +2791,8 @@ void QWindowsWindow::updateFullFrameMargins()
|
|
|
|
|
|
|
|
|
|
void QWindowsWindow::calculateFullFrameMargins()
|
|
|
|
|
{
|
|
|
|
|
if (m_data.flags & Qt::FramelessWindowHint)
|
|
|
|
|
if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
|
|
|
|
|
return;
|
|
|
|
|
// Normally obtained from WM_NCCALCSIZE. This calculation only works
|
|
|
|
|
// when no native menu is present.
|
|
|
|
|
const auto systemMargins = testFlag(DisableNonClientScaling)
|
|
|
|
|
? QWindowsGeometryHint::frameOnPrimaryScreen(window(), m_data.hwnd)
|
|
|
|
|
: frameMargins_sys();
|
|
|
|
|
|
|
|
|
|
// QTBUG-113736: systemMargins depends on AdjustWindowRectExForDpi. This doesn't take into
|
|
|
|
|
// account possible external modifications to the titlebar, as with ExtendsContentIntoTitleBar()
|
|
|
|
@ -2800,6 +2806,20 @@ void QWindowsWindow::calculateFullFrameMargins()
|
|
|
|
|
RECT clientRect{};
|
|
|
|
|
GetWindowRect(handle(), &windowRect);
|
|
|
|
|
GetClientRect(handle(), &clientRect);
|
|
|
|
|
|
|
|
|
|
// QTBUG-117704 It is also possible that the user has manually removed the frame (for example
|
|
|
|
|
// by handling WM_NCCALCSIZE). If that is the case, i.e., the client area and the window area
|
|
|
|
|
// have identical sizes, we don't want to override the user-defined margins.
|
|
|
|
|
|
|
|
|
|
if (qrectFromRECT(windowRect).size() == qrectFromRECT(clientRect).size())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Normally obtained from WM_NCCALCSIZE. This calculation only works
|
|
|
|
|
// when no native menu is present.
|
|
|
|
|
const auto systemMargins = testFlag(DisableNonClientScaling)
|
|
|
|
|
? QWindowsGeometryHint::frameOnPrimaryScreen(window(), m_data.hwnd)
|
|
|
|
|
: frameMargins_sys();
|
|
|
|
|
|
|
|
|
|
const int yDiff = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top);
|
|
|
|
|
const bool typicalFrame = (systemMargins.left() == systemMargins.right())
|
|
|
|
|
&& (systemMargins.right() == systemMargins.bottom());
|
|
|
|
@ -2822,7 +2842,7 @@ QMargins QWindowsWindow::frameMargins() const
|
|
|
|
|
|
|
|
|
|
QMargins QWindowsWindow::fullFrameMargins() const
|
|
|
|
|
{
|
|
|
|
|
if (m_data.flags & Qt::FramelessWindowHint)
|
|
|
|
|
if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
|
|
|
|
|
return {};
|
|
|
|
|
return m_data.fullFrameMargins;
|
|
|
|
|
}
|
|
|
|
|