From 8d3ef93885dd6df704c2e2bf1c279ad254de7ff1 Mon Sep 17 00:00:00 2001 From: Yuhang Zhao Date: Sat, 5 Aug 2023 13:46:23 +0800 Subject: [PATCH] win: fix theme not updating --- .../Core/private/framelessmanager_p.h | 5 ++ src/core/framelesshelper_win.cpp | 31 +++++++-- src/core/framelessmanager.cpp | 44 +++++++++---- src/core/utils_win.cpp | 64 ++++++++++++++++++- 4 files changed, 126 insertions(+), 18 deletions(-) diff --git a/include/FramelessHelper/Core/private/framelessmanager_p.h b/include/FramelessHelper/Core/private/framelessmanager_p.h index 436cfd53..ae06a526 100644 --- a/include/FramelessHelper/Core/private/framelessmanager_p.h +++ b/include/FramelessHelper/Core/private/framelessmanager_p.h @@ -25,6 +25,7 @@ #pragma once #include +#include #include FRAMELESSHELPER_BEGIN_NAMESPACE @@ -66,6 +67,8 @@ class FRAMELESSHELPER_CORE_API FramelessManagerPrivate : public QObject private: void initialize(); + void doNotifySystemThemeHasChangedOrNot(); + void doNotifyWallpaperHasChangedOrNot(); private: FramelessManager *q_ptr = nullptr; @@ -77,6 +80,8 @@ class FRAMELESSHELPER_CORE_API FramelessManagerPrivate : public QObject #endif QString m_wallpaper = {}; Global::WallpaperAspectStyle m_wallpaperAspectStyle = Global::WallpaperAspectStyle::Fill; + QTimer m_themeTimer{}; + QTimer m_wallpaperTimer{}; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/src/core/framelesshelper_win.cpp b/src/core/framelesshelper_win.cpp index 1a326a5f..ff3bb530 100644 --- a/src/core/framelesshelper_win.cpp +++ b/src/core/framelesshelper_win.cpp @@ -106,9 +106,21 @@ struct FramelessWin32HelperInternal Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData) +[[nodiscard]] extern bool operator==(const POINT &lhs, const POINT &rhs) noexcept; +[[nodiscard]] extern bool operator!=(const POINT &lhs, const POINT &rhs) noexcept; + +[[nodiscard]] extern bool operator==(const SIZE &lhs, const SIZE &rhs) noexcept; +[[nodiscard]] extern bool operator!=(const SIZE &lhs, const SIZE &rhs) noexcept; + [[nodiscard]] extern bool operator==(const RECT &lhs, const RECT &rhs) noexcept; [[nodiscard]] extern bool operator!=(const RECT &lhs, const RECT &rhs) noexcept; +[[nodiscard]] extern QPoint point2qpoint(const POINT &point); +[[nodiscard]] extern POINT qpoint2point(const QPoint &point); + +[[nodiscard]] extern QSize size2qsize(const SIZE &size); +[[nodiscard]] extern SIZE qsize2size(const QSize &size); + [[nodiscard]] extern QRect rect2qrect(const RECT &rect); [[nodiscard]] extern RECT qrect2rect(const QRect &qrect); @@ -388,6 +400,11 @@ Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData) return false; } const auto parentWindowHandle = reinterpret_cast(parentWindowId); + POINT parentWindowOriginPoint = { 0, 0 }; + if (ClientToScreen(parentWindowHandle, &parentWindowOriginPoint) == FALSE) { + WARNING << Utils::getSystemErrorMessage(kClientToScreen); + return false; + } RECT parentWindowClientRect = {}; if (GetClientRect(parentWindowHandle, &parentWindowClientRect) == FALSE) { WARNING << Utils::getSystemErrorMessage(kGetClientRect); @@ -395,13 +412,19 @@ Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData) } const int titleBarHeight = Utils::getTitleBarHeight(parentWindowId, true); const auto fallbackTitleBarWindowHandle = reinterpret_cast(fallbackTitleBarWindowId); + POINT fallbackTitleBarOriginPoint = { 0, 0 }; + if (ClientToScreen(fallbackTitleBarWindowHandle, &fallbackTitleBarOriginPoint) == FALSE) { + WARNING << Utils::getSystemErrorMessage(kClientToScreen); + return false; + } RECT fallbackTitleBarClientRect = {}; if (GetClientRect(fallbackTitleBarWindowHandle, &fallbackTitleBarClientRect) == FALSE) { WARNING << Utils::getSystemErrorMessage(kGetClientRect); return false; } - if ((RECT_WIDTH(fallbackTitleBarClientRect) == RECT_WIDTH(parentWindowClientRect)) - && (RECT_HEIGHT(fallbackTitleBarClientRect) == RECT_HEIGHT(parentWindowClientRect))) { + const SIZE currentSize = { RECT_WIDTH(fallbackTitleBarClientRect), RECT_HEIGHT(fallbackTitleBarClientRect) }; + const SIZE expectedSize = { RECT_WIDTH(parentWindowClientRect), LONG(titleBarHeight) }; + if ((fallbackTitleBarOriginPoint == parentWindowOriginPoint) && (currentSize == expectedSize)) { return true; } const UINT flags = (SWP_NOACTIVATE | (hide ? SWP_HIDEWINDOW : SWP_SHOWWINDOW)); @@ -415,7 +438,7 @@ Q_GLOBAL_STATIC(FramelessWin32HelperInternal, g_framelessWin32HelperData) // it finally works. Since our current solution works well, I have no interest in digging // into all the magic behind it. if (SetWindowPos(fallbackTitleBarWindowHandle, HWND_TOP, 0, 0, - RECT_WIDTH(parentWindowClientRect), titleBarHeight, flags) == FALSE) { + int(expectedSize.cx), int(expectedSize.cy), flags) == FALSE) { WARNING << Utils::getSystemErrorMessage(kSetWindowPos); return false; } @@ -1350,11 +1373,9 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me // Sometimes the FramelessManager instance may be destroyed already. if (FramelessManager * const manager = FramelessManager::instance()) { if (FramelessManagerPrivate * const managerPriv = FramelessManagerPrivate::get(manager)) { -#if (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) if (systemThemeChanged) { managerPriv->notifySystemThemeHasChangedOrNot(); } -#endif // (QT_VERSION < QT_VERSION_CHECK(6, 5, 0)) if (wallpaperChanged) { managerPriv->notifyWallpaperHasChangedOrNot(); } diff --git a/src/core/framelessmanager.cpp b/src/core/framelessmanager.cpp index 39bc0034..31cb927b 100644 --- a/src/core/framelessmanager.cpp +++ b/src/core/framelessmanager.cpp @@ -60,13 +60,12 @@ FRAMELESSHELPER_BEGIN_NAMESPACE using namespace Global; -struct FramelessManagerData -{ - QList windowIds = {}; -}; +using FramelessManagerData = QList; Q_GLOBAL_STATIC(FramelessManagerData, g_framelessManagerData) +static constexpr const int kEventDelayInterval = 1000; + #ifndef FRAMELESSHELPER_CORE_NO_BUNDLE_RESOURCE [[nodiscard]] static inline QString iconFontFamilyName() { @@ -184,10 +183,10 @@ void FramelessManagerPrivate::addWindow(FramelessParamsConst params) return; } const WId windowId = params->getWindowId(); - if (g_framelessManagerData()->windowIds.contains(windowId)) { + if (g_framelessManagerData()->contains(windowId)) { return; } - g_framelessManagerData()->windowIds.append(windowId); + g_framelessManagerData()->append(windowId); static const bool pureQt = usePureQtImplementation(); if (pureQt) { FramelessHelperQt::addWindow(params); @@ -207,10 +206,10 @@ void FramelessManagerPrivate::removeWindow(const WId windowId) if (!windowId) { return; } - if (!g_framelessManagerData()->windowIds.contains(windowId)) { + if (!g_framelessManagerData()->contains(windowId)) { return; } - g_framelessManagerData()->windowIds.removeAll(windowId); + g_framelessManagerData()->removeAll(windowId); static const bool pureQt = usePureQtImplementation(); if (pureQt) { FramelessHelperQt::removeWindow(windowId); @@ -225,6 +224,16 @@ void FramelessManagerPrivate::removeWindow(const WId windowId) } void FramelessManagerPrivate::notifySystemThemeHasChangedOrNot() +{ + m_themeTimer.start(); +} + +void FramelessManagerPrivate::notifyWallpaperHasChangedOrNot() +{ + m_wallpaperTimer.start(); +} + +void FramelessManagerPrivate::doNotifySystemThemeHasChangedOrNot() { const SystemTheme currentSystemTheme = (Utils::shouldAppsUseDarkMode() ? SystemTheme::Dark : SystemTheme::Light); const QColor currentAccentColor = Utils::getAccentColor(); @@ -259,7 +268,7 @@ void FramelessManagerPrivate::notifySystemThemeHasChangedOrNot() } } -void FramelessManagerPrivate::notifyWallpaperHasChangedOrNot() +void FramelessManagerPrivate::doNotifyWallpaperHasChangedOrNot() { const QString currentWallpaper = Utils::getWallpaperFilePath(); const WallpaperAspectStyle currentWallpaperAspectStyle = Utils::getWallpaperAspectStyle(); @@ -314,6 +323,16 @@ bool FramelessManagerPrivate::isThemeOverrided() const void FramelessManagerPrivate::initialize() { + m_themeTimer.setInterval(kEventDelayInterval); + m_themeTimer.callOnTimeout(this, [this](){ + m_themeTimer.stop(); + doNotifySystemThemeHasChangedOrNot(); + }); + m_wallpaperTimer.setInterval(kEventDelayInterval); + m_wallpaperTimer.callOnTimeout(this, [this](){ + m_wallpaperTimer.stop(); + doNotifyWallpaperHasChangedOrNot(); + }); m_systemTheme = (Utils::shouldAppsUseDarkMode() ? SystemTheme::Dark : SystemTheme::Light); m_accentColor = Utils::getAccentColor(); #ifdef Q_OS_WINDOWS @@ -329,7 +348,10 @@ void FramelessManagerPrivate::initialize() << ", wallpaper: " << m_wallpaper << ", aspect style: " << m_wallpaperAspectStyle << '.'; -#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) + // We are doing some tricks in our Windows message handling code, so + // we don't use Qt's theme notifier on Windows. But for other platforms + // we want to use as many Qt functionalities as possible. +#if ((QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) && !defined(Q_OS_WINDOWS)) QStyleHints * const styleHints = QGuiApplication::styleHints(); Q_ASSERT(styleHints); if (styleHints) { @@ -338,7 +360,7 @@ void FramelessManagerPrivate::initialize() notifySystemThemeHasChangedOrNot(); }); } -#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) +#endif // ((QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) && !defined(Q_OS_WINDOWS)) static bool flagSet = false; if (!flagSet) { flagSet = true; diff --git a/src/core/utils_win.cpp b/src/core/utils_win.cpp index b3770614..b3e519ae 100644 --- a/src/core/utils_win.cpp +++ b/src/core/utils_win.cpp @@ -199,6 +199,46 @@ struct Win32UtilsInternal Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData) +[[nodiscard]] bool operator==(const POINT &lhs, const POINT &rhs) noexcept +{ + return ((lhs.x == rhs.x) && (lhs.y == rhs.y)); +} + +[[nodiscard]] bool operator!=(const POINT &lhs, const POINT &rhs) noexcept +{ + return !operator==(lhs, rhs); +} + +[[nodiscard]] bool operator==(const SIZE &lhs, const SIZE &rhs) noexcept +{ + return ((lhs.cx == rhs.cx) && (lhs.cy == rhs.cy)); +} + +[[nodiscard]] bool operator!=(const SIZE &lhs, const SIZE &rhs) noexcept +{ + return !operator==(lhs, rhs); +} + +[[nodiscard]] bool operator>(const SIZE &lhs, const SIZE &rhs) noexcept +{ + return ((lhs.cx * lhs.cy) > (rhs.cx * rhs.cy)); +} + +[[nodiscard]] bool operator>=(const SIZE &lhs, const SIZE &rhs) noexcept +{ + return (operator>(lhs, rhs) || operator==(lhs, rhs)); +} + +[[nodiscard]] bool operator<(const SIZE &lhs, const SIZE &rhs) noexcept +{ + return (operator!=(lhs, rhs) && !operator>(lhs, rhs)); +} + +[[nodiscard]] bool operator<=(const SIZE &lhs, const SIZE &rhs) noexcept +{ + return (operator<(lhs, rhs) || operator==(lhs, rhs)); +} + [[nodiscard]] bool operator==(const RECT &lhs, const RECT &rhs) noexcept { return ((lhs.left == rhs.left) && (lhs.top == rhs.top) @@ -210,14 +250,34 @@ Q_GLOBAL_STATIC(Win32UtilsInternal, g_win32UtilsData) return !operator==(lhs, rhs); } +[[nodiscard]] QPoint point2qpoint(const POINT &point) +{ + return QPoint{ int(point.x), int(point.y) }; +} + +[[nodiscard]] POINT qpoint2point(const QPoint &point) +{ + return POINT{ LONG(point.x()), LONG(point.y()) }; +} + +[[nodiscard]] QSize size2qsize(const SIZE &size) +{ + return QSize{ int(size.cx), int(size.cy) }; +} + +[[nodiscard]] SIZE qsize2size(const QSize &size) +{ + return SIZE{ LONG(size.width()), LONG(size.height()) }; +} + [[nodiscard]] QRect rect2qrect(const RECT &rect) { - return QRect{QPoint{rect.left, rect.top}, QSize{RECT_WIDTH(rect), RECT_HEIGHT(rect)}}; + return QRect{ QPoint{ int(rect.left), int(rect.top) }, QSize{ int(RECT_WIDTH(rect)), int(RECT_HEIGHT(rect)) } }; } [[nodiscard]] RECT qrect2rect(const QRect &qrect) { - return {qrect.left(), qrect.top(), qrect.right(), qrect.bottom()}; + return RECT{ LONG(qrect.left()), LONG(qrect.top()), LONG(qrect.right()), LONG(qrect.bottom()) }; } [[nodiscard]] QString hwnd2str(const WId windowId)