win: fix wrong restore geometry when after DPI changes

This commit is contained in:
Yuhang Zhao 2023-04-25 15:19:31 +08:00
parent 30d2261baf
commit 41e91bb39a
5 changed files with 74 additions and 12 deletions

View File

@ -442,6 +442,16 @@ struct Dpi
{
quint32 x = 0;
quint32 y = 0;
[[nodiscard]] friend constexpr bool operator==(const Dpi &lhs, const Dpi &rhs) noexcept
{
return ((lhs.x == rhs.x) && (lhs.y == rhs.y));
}
[[nodiscard]] friend constexpr bool operator!=(const Dpi &lhs, const Dpi &rhs) noexcept
{
return !operator==(lhs, rhs);
}
};
} // namespace Global

View File

@ -81,6 +81,8 @@ FRAMELESSHELPER_CORE_API void registerThemeChangeNotification();
[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint fromNativeLocalPosition(const QWindow *window, const QPoint &point);
[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint fromNativeGlobalPosition(const QWindow *window, const QPoint &point);
[[nodiscard]] FRAMELESSHELPER_CORE_API int horizontalAdvance(const QFontMetrics &fm, const QString &str);
[[nodiscard]] FRAMELESSHELPER_CORE_API qreal getRelativeScaleFactor(const quint32 oldDpi, const quint32 newDpi);
[[nodiscard]] FRAMELESSHELPER_CORE_API QSize rescaleSize(const QSize &oldSize, const quint32 oldDpi, const quint32 newDpi);
#ifdef Q_OS_WINDOWS
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowsVersionOrGreater(const Global::WindowsVersion version);

View File

@ -1144,16 +1144,12 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
*result = FALSE; // Use the default linear DPI scaling provided by Windows.
return true; // Jump over Qt's wrong handling logic.
}
const QSizeF oldSize = {qreal(RECT_WIDTH(clientRect)), qreal(RECT_HEIGHT(clientRect))};
static constexpr const auto defaultDpi = qreal(USER_DEFAULT_SCREEN_DPI);
// We need to round the scale factor according to Qt's rounding policy.
const qreal oldDpr = Utils::roundScaleFactor(qreal(data.dpi.x) / defaultDpi);
const auto newDpi = UINT(wParam);
const qreal newDpr = Utils::roundScaleFactor(qreal(newDpi) / defaultDpi);
const QSizeF newSize = (oldSize / oldDpr * newDpr);
const QSize oldSize = {RECT_WIDTH(clientRect), RECT_HEIGHT(clientRect)};
const QSize newSize = Utils::rescaleSize(oldSize, data.dpi.x, newDpi);
const auto suggestedSize = reinterpret_cast<LPSIZE>(lParam);
suggestedSize->cx = std::round(newSize.width());
suggestedSize->cy = std::round(newSize.height());
suggestedSize->cx = newSize.width();
suggestedSize->cy = newSize.height();
// If the window frame is visible, we need to expand the suggested size, currently
// it's pure client size, we need to add the frame size to it. Windows expects a
// full window size, including the window frame.
@ -1171,10 +1167,21 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
}
#endif // (QT_VERSION <= QT_VERSION_CHECK(6, 4, 2))
case WM_DPICHANGED: {
const Dpi dpi = {UINT(LOWORD(wParam)), UINT(HIWORD(wParam))};
DEBUG.noquote() << "New DPI for window" << hwnd2str(hWnd) << "is" << dpi;
const Dpi oldDpi = data.dpi;
const Dpi newDpi = {UINT(LOWORD(wParam)), UINT(HIWORD(wParam))};
if (Q_UNLIKELY(newDpi == oldDpi)) {
WARNING << "Wrong WM_DPICHANGED received: same DPI.";
break;
}
DEBUG.noquote() << "New DPI for window" << hwnd2str(hWnd)
<< "is" << newDpi << "(was" << oldDpi << ").";
g_win32Helper()->mutex.lock();
g_win32Helper()->data[windowId].dpi = dpi;
g_win32Helper()->data[windowId].dpi = newDpi;
if (data.restoreGeometry.isValid() && !data.restoreGeometry.isNull()) {
// Update the window size only. The position should not be changed.
g_win32Helper()->data[windowId].restoreGeometry.setSize(
Utils::rescaleSize(data.restoreGeometry.size(), oldDpi.x, newDpi.x));
}
g_win32Helper()->mutex.unlock();
#if (QT_VERSION <= QT_VERSION_CHECK(6, 4, 2))
// We need to wait until Qt has handled this message, otherwise everything

View File

@ -87,7 +87,12 @@ QDebug operator<<(QDebug d, const FRAMELESSHELPER_PREPEND_NAMESPACE(Global)::Ver
QDebug operator<<(QDebug d, const FRAMELESSHELPER_PREPEND_NAMESPACE(Global)::Dpi &dpi)
{
const QDebugStateSaver saver(d);
const qreal scaleFactor = (qreal(dpi.x) / qreal(96));
#ifdef Q_OS_MACOS
static constexpr const auto defaultDpi = quint32(72);
#else // !Q_OS_MACOS
static constexpr const auto defaultDpi = quint32(96);
#endif // Q_OS_MACOS
const qreal scaleFactor = (qreal(dpi.x) / qreal(defaultDpi));
d.nospace().noquote() << "Dpi("
<< "x: " << dpi.x << ", "
<< "y: " << dpi.y << ", "

View File

@ -522,4 +522,42 @@ int Utils::horizontalAdvance(const QFontMetrics &fm, const QString &str)
#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
}
qreal Utils::getRelativeScaleFactor(const quint32 oldDpi, const quint32 newDpi)
{
if (newDpi == oldDpi) {
return qreal(1);
}
#ifdef Q_OS_MACOS
static constexpr const auto defaultDpi = quint32(72);
#else // !Q_OS_MACOS
static constexpr const auto defaultDpi = quint32(96);
#endif // Q_OS_MACOS
if ((oldDpi < defaultDpi) || (newDpi < defaultDpi)) {
return qreal(1);
}
// We need to round the scale factor according to Qt's rounding policy.
const qreal oldDpr = roundScaleFactor(qreal(oldDpi) / qreal(defaultDpi));
const qreal newDpr = roundScaleFactor(qreal(newDpi) / qreal(defaultDpi));
return qreal(newDpr / oldDpr);
}
QSize Utils::rescaleSize(const QSize &oldSize, const quint32 oldDpi, const quint32 newDpi)
{
if (oldSize.isEmpty()) {
return {};
}
if (newDpi == oldDpi) {
return oldSize;
}
const qreal scaleFactor = getRelativeScaleFactor(oldDpi, newDpi);
if (qFuzzyIsNull(scaleFactor)) {
return {};
}
if (qFuzzyCompare(scaleFactor, qreal(1))) {
return oldSize;
}
const QSizeF newSize = QSizeF(oldSize) * scaleFactor;
return newSize.toSize(); // The numbers will be rounded to the nearest integer.
}
FRAMELESSHELPER_END_NAMESPACE