diff --git a/include/FramelessHelper/Core/private/chromepalette_p.h b/include/FramelessHelper/Core/private/chromepalette_p.h index 2db51887..0f6ff624 100644 --- a/include/FramelessHelper/Core/private/chromepalette_p.h +++ b/include/FramelessHelper/Core/private/chromepalette_p.h @@ -44,10 +44,8 @@ class FRAMELESSHELPER_CORE_API ChromePalettePrivate : public QObject Q_NODISCARD static ChromePalettePrivate *get(ChromePalette *q); Q_NODISCARD static const ChromePalettePrivate *get(const ChromePalette *q); -public Q_SLOTS: - void refresh(); + Q_SLOT void refresh(); -private: ChromePalette *q_ptr = nullptr; // System-defined ones: QColor titleBarActiveBackgroundColor_sys = {}; diff --git a/include/FramelessHelper/Core/private/framelessmanager_p.h b/include/FramelessHelper/Core/private/framelessmanager_p.h index ae06a526..73009542 100644 --- a/include/FramelessHelper/Core/private/framelessmanager_p.h +++ b/include/FramelessHelper/Core/private/framelessmanager_p.h @@ -49,39 +49,27 @@ class FRAMELESSHELPER_CORE_API FramelessManagerPrivate : public QObject static void initializeIconFont(); Q_NODISCARD static QFont getIconFont(); - Q_NODISCARD Global::SystemTheme systemTheme() const; - Q_NODISCARD QColor systemAccentColor() const; - Q_NODISCARD QString wallpaper() const; - Q_NODISCARD Global::WallpaperAspectStyle wallpaperAspectStyle() const; + Q_SLOT void notifySystemThemeHasChangedOrNot(); + Q_SLOT void notifyWallpaperHasChangedOrNot(); - static void addWindow(const SystemParameters *params); - static void removeWindow(const WId windowId); - - Q_INVOKABLE void notifySystemThemeHasChangedOrNot(); - Q_INVOKABLE void notifyWallpaperHasChangedOrNot(); - - Q_NODISCARD static bool usePureQtImplementation(); - - void setOverrideTheme(const Global::SystemTheme theme); Q_NODISCARD bool isThemeOverrided() const; -private: void initialize(); + void doNotifySystemThemeHasChangedOrNot(); void doNotifyWallpaperHasChangedOrNot(); -private: FramelessManager *q_ptr = nullptr; - Global::SystemTheme m_systemTheme = Global::SystemTheme::Unknown; - std::optional m_overrideTheme = std::nullopt; - QColor m_accentColor = {}; + Global::SystemTheme systemTheme = Global::SystemTheme::Unknown; + std::optional overrideTheme = std::nullopt; + QColor accentColor = {}; #ifdef Q_OS_WINDOWS - Global::DwmColorizationArea m_colorizationArea = Global::DwmColorizationArea::None; + Global::DwmColorizationArea colorizationArea = Global::DwmColorizationArea::None; #endif - QString m_wallpaper = {}; - Global::WallpaperAspectStyle m_wallpaperAspectStyle = Global::WallpaperAspectStyle::Fill; - QTimer m_themeTimer{}; - QTimer m_wallpaperTimer{}; + QString wallpaper = {}; + Global::WallpaperAspectStyle wallpaperAspectStyle = Global::WallpaperAspectStyle::Fill; + QTimer themeTimer{}; + QTimer wallpaperTimer{}; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Core/private/micamaterial_p.h b/include/FramelessHelper/Core/private/micamaterial_p.h index 117ac7cf..6014d2a8 100644 --- a/include/FramelessHelper/Core/private/micamaterial_p.h +++ b/include/FramelessHelper/Core/private/micamaterial_p.h @@ -50,22 +50,18 @@ class FRAMELESSHELPER_CORE_API MicaMaterialPrivate : public QObject Q_NODISCARD QSize mapToWallpaper(const QSize &size) const; Q_NODISCARD QRect mapToWallpaper(const QRect &rect) const; -public Q_SLOTS: - void maybeGenerateBlurredWallpaper(const bool force = false); - void updateMaterialBrush(); - void paint(QPainter *painter, const QRect &rect, const bool active = true); - void forceRebuildWallpaper(); + Q_SLOT void maybeGenerateBlurredWallpaper(const bool force = false); + Q_SLOT void updateMaterialBrush(); + Q_SLOT void forceRebuildWallpaper(); -private: void initialize(); void prepareGraphicsResources(); -private: MicaMaterial *q_ptr = nullptr; QColor tintColor = {}; - qreal tintOpacity = 0.0; + qreal tintOpacity = qreal(0); QColor fallbackColor = {}; - qreal noiseOpacity = 0.0; + qreal noiseOpacity = qreal(0); bool fallbackEnabled = true; QBrush micaBrush = {}; bool initialized = false; diff --git a/include/FramelessHelper/Core/private/registrykey_p.h b/include/FramelessHelper/Core/private/registrykey_p.h index 5adea9e7..32c22d07 100644 --- a/include/FramelessHelper/Core/private/registrykey_p.h +++ b/include/FramelessHelper/Core/private/registrykey_p.h @@ -74,7 +74,7 @@ class FRAMELESSHELPER_CORE_API RegistryKey : public QObject Q_NODISCARD std::optional value(const QString &name) const { const QVariant var = value(name); - if (var.isValid()) { + if (var.isValid() && !var.isNull()) { return qvariant_cast(var); } return std::nullopt; diff --git a/include/FramelessHelper/Core/private/windowborderpainter_p.h b/include/FramelessHelper/Core/private/windowborderpainter_p.h index f5f0a4f5..dfe63cad 100644 --- a/include/FramelessHelper/Core/private/windowborderpainter_p.h +++ b/include/FramelessHelper/Core/private/windowborderpainter_p.h @@ -44,22 +44,11 @@ class FRAMELESSHELPER_CORE_API WindowBorderPainterPrivate : public QObject Q_NODISCARD static WindowBorderPainterPrivate *get(WindowBorderPainter *q); Q_NODISCARD static const WindowBorderPainterPrivate *get(const WindowBorderPainter *q); - Q_NODISCARD static int getNativeBorderThickness(); - Q_NODISCARD static QColor getNativeBorderColor(const bool active); - Q_NODISCARD static Global::WindowEdges getNativeBorderEdges(); - -public Q_SLOTS: - void paint(QPainter *painter, const QSize &size, const bool active) const; - -private: - void initialize(); - -private: WindowBorderPainter *q_ptr = nullptr; - std::optional m_thickness = std::nullopt; - std::optional m_edges = std::nullopt; - std::optional m_activeColor = std::nullopt; - std::optional m_inactiveColor = std::nullopt; + std::optional thickness = std::nullopt; + std::optional edges = std::nullopt; + std::optional activeColor = std::nullopt; + std::optional inactiveColor = std::nullopt; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Core/windowborderpainter.h b/include/FramelessHelper/Core/windowborderpainter.h index 063d955b..648e62dc 100644 --- a/include/FramelessHelper/Core/windowborderpainter.h +++ b/include/FramelessHelper/Core/windowborderpainter.h @@ -61,7 +61,7 @@ class FRAMELESSHELPER_CORE_API WindowBorderPainter : public QObject Q_NODISCARD QColor nativeInactiveColor() const; public Q_SLOTS: - void paint(QPainter *painter, const QSize &size, const bool active) const; + void paint(QPainter *painter, const QSize &size, const bool active); void setThickness(const int value); void setEdges(const Global::WindowEdges value); void setActiveColor(const QColor &value); diff --git a/src/core/framelessmanager.cpp b/src/core/framelessmanager.cpp index bfefb7c4..d2fbcd58 100644 --- a/src/core/framelessmanager.cpp +++ b/src/core/framelessmanager.cpp @@ -84,6 +84,18 @@ static constexpr const int kEventDelayInterval = 1000; } #endif // FRAMELESSHELPER_CORE_NO_BUNDLE_RESOURCE +[[nodiscard]] static inline bool usePureQtImplementation() +{ + static const auto result = []() -> bool { +#ifdef Q_OS_WINDOWS + return FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation); +#else + return true; +#endif + }(); + return result; +} + FramelessManagerPrivate::FramelessManagerPrivate(FramelessManager *q) : QObject(q) { Q_ASSERT(q); @@ -152,85 +164,14 @@ QFont FramelessManagerPrivate::getIconFont() #endif // FRAMELESSHELPER_CORE_NO_BUNDLE_RESOURCE } -SystemTheme FramelessManagerPrivate::systemTheme() const -{ - // The user's choice has top priority. - if (isThemeOverrided()) { - return m_overrideTheme.value(); - } - return m_systemTheme; -} - -QColor FramelessManagerPrivate::systemAccentColor() const -{ - return m_accentColor; -} - -QString FramelessManagerPrivate::wallpaper() const -{ - return m_wallpaper; -} - -WallpaperAspectStyle FramelessManagerPrivate::wallpaperAspectStyle() const -{ - return m_wallpaperAspectStyle; -} - -void FramelessManagerPrivate::addWindow(FramelessParamsConst params) -{ - Q_ASSERT(params); - if (!params) { - return; - } - const WId windowId = params->getWindowId(); - if (g_framelessManagerData()->contains(windowId)) { - return; - } - g_framelessManagerData()->append(windowId); - static const bool pureQt = usePureQtImplementation(); - if (pureQt) { - FramelessHelperQt::addWindow(params); - } -#ifdef Q_OS_WINDOWS - if (!pureQt) { - FramelessHelperWin::addWindow(params); - } - std::ignore = Utils::installWindowProcHook(windowId, params); -#endif - connect(params->getWindowHandle(), &QWindow::destroyed, FramelessManager::instance(), [windowId](){ removeWindow(windowId); }); -} - -void FramelessManagerPrivate::removeWindow(const WId windowId) -{ - Q_ASSERT(windowId); - if (!windowId) { - return; - } - if (!g_framelessManagerData()->contains(windowId)) { - return; - } - g_framelessManagerData()->removeAll(windowId); - static const bool pureQt = usePureQtImplementation(); - if (pureQt) { - FramelessHelperQt::removeWindow(windowId); - } -#ifdef Q_OS_WINDOWS - if (!pureQt) { - FramelessHelperWin::removeWindow(windowId); - } - std::ignore = Utils::uninstallWindowProcHook(windowId); - std::ignore = Utils::removeMicaWindow(windowId); -#endif -} - void FramelessManagerPrivate::notifySystemThemeHasChangedOrNot() { - m_themeTimer.start(); + themeTimer.start(); } void FramelessManagerPrivate::notifyWallpaperHasChangedOrNot() { - m_wallpaperTimer.start(); + wallpaperTimer.start(); } void FramelessManagerPrivate::doNotifySystemThemeHasChangedOrNot() @@ -241,17 +182,17 @@ void FramelessManagerPrivate::doNotifySystemThemeHasChangedOrNot() const DwmColorizationArea currentColorizationArea = Utils::getDwmColorizationArea(); #endif bool notify = false; - if (m_systemTheme != currentSystemTheme) { - m_systemTheme = currentSystemTheme; + if (systemTheme != currentSystemTheme) { + systemTheme = currentSystemTheme; notify = true; } - if (m_accentColor != currentAccentColor) { - m_accentColor = currentAccentColor; + if (accentColor != currentAccentColor) { + accentColor = currentAccentColor; notify = true; } #ifdef Q_OS_WINDOWS - if (m_colorizationArea != currentColorizationArea) { - m_colorizationArea = currentColorizationArea; + if (colorizationArea != currentColorizationArea) { + colorizationArea = currentColorizationArea; notify = true; } #endif @@ -259,10 +200,10 @@ void FramelessManagerPrivate::doNotifySystemThemeHasChangedOrNot() if (notify && !isThemeOverrided()) { Q_Q(FramelessManager); Q_EMIT q->systemThemeChanged(); - DEBUG.nospace() << "System theme changed. Current theme: " << m_systemTheme - << ", accent color: " << m_accentColor.name(QColor::HexArgb).toUpper() + DEBUG.nospace() << "System theme changed. Current theme: " << systemTheme + << ", accent color: " << accentColor.name(QColor::HexArgb).toUpper() #ifdef Q_OS_WINDOWS - << ", colorization area: " << m_colorizationArea + << ", colorization area: " << colorizationArea #endif << '.'; } @@ -273,80 +214,53 @@ void FramelessManagerPrivate::doNotifyWallpaperHasChangedOrNot() const QString currentWallpaper = Utils::getWallpaperFilePath(); const WallpaperAspectStyle currentWallpaperAspectStyle = Utils::getWallpaperAspectStyle(); bool notify = false; - if (m_wallpaper != currentWallpaper) { - m_wallpaper = currentWallpaper; + if (wallpaper != currentWallpaper) { + wallpaper = currentWallpaper; notify = true; } - if (m_wallpaperAspectStyle != currentWallpaperAspectStyle) { - m_wallpaperAspectStyle = currentWallpaperAspectStyle; + if (wallpaperAspectStyle != currentWallpaperAspectStyle) { + wallpaperAspectStyle = currentWallpaperAspectStyle; notify = true; } if (notify) { Q_Q(FramelessManager); Q_EMIT q->wallpaperChanged(); - DEBUG.nospace() << "Wallpaper changed. Current wallpaper: " << m_wallpaper - << ", aspect style: " << m_wallpaperAspectStyle << '.'; + DEBUG.nospace() << "Wallpaper changed. Current wallpaper: " << wallpaper + << ", aspect style: " << wallpaperAspectStyle << '.'; } } -bool FramelessManagerPrivate::usePureQtImplementation() -{ - static const auto result = []() -> bool { -#ifdef Q_OS_WINDOWS - return FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation); -#else - return true; -#endif - }(); - return result; -} - -void FramelessManagerPrivate::setOverrideTheme(const SystemTheme theme) -{ - if ((!m_overrideTheme.has_value() && (theme == SystemTheme::Unknown)) - || (m_overrideTheme.has_value() && (m_overrideTheme.value() == theme))) { - return; - } - if (theme == SystemTheme::Unknown) { - m_overrideTheme = std::nullopt; - } else { - m_overrideTheme = theme; - } - Q_Q(FramelessManager); - Q_EMIT q->systemThemeChanged(); -} - bool FramelessManagerPrivate::isThemeOverrided() const { - return (m_overrideTheme.value_or(SystemTheme::Unknown) != SystemTheme::Unknown); + return (overrideTheme.value_or(SystemTheme::Unknown) != SystemTheme::Unknown); } void FramelessManagerPrivate::initialize() { - m_themeTimer.setInterval(kEventDelayInterval); - m_themeTimer.callOnTimeout(this, [this](){ - m_themeTimer.stop(); + themeTimer.setInterval(kEventDelayInterval); + themeTimer.callOnTimeout(this, [this](){ + themeTimer.stop(); doNotifySystemThemeHasChangedOrNot(); }); - m_wallpaperTimer.setInterval(kEventDelayInterval); - m_wallpaperTimer.callOnTimeout(this, [this](){ - m_wallpaperTimer.stop(); + wallpaperTimer.setInterval(kEventDelayInterval); + wallpaperTimer.callOnTimeout(this, [this](){ + wallpaperTimer.stop(); doNotifyWallpaperHasChangedOrNot(); }); - m_systemTheme = (Utils::shouldAppsUseDarkMode() ? SystemTheme::Dark : SystemTheme::Light); - m_accentColor = Utils::getAccentColor(); + systemTheme = (Utils::shouldAppsUseDarkMode() ? SystemTheme::Dark : SystemTheme::Light); + accentColor = Utils::getAccentColor(); #ifdef Q_OS_WINDOWS - m_colorizationArea = Utils::getDwmColorizationArea(); + colorizationArea = Utils::getDwmColorizationArea(); #endif - m_wallpaper = Utils::getWallpaperFilePath(); - m_wallpaperAspectStyle = Utils::getWallpaperAspectStyle(); - DEBUG.nospace() << "Current system theme: " << m_systemTheme - << ", accent color: " << m_accentColor.name(QColor::HexArgb).toUpper() + wallpaper = Utils::getWallpaperFilePath(); + wallpaperAspectStyle = Utils::getWallpaperAspectStyle(); + DEBUG.nospace() << "Current system theme: " << systemTheme + << ", accent color: " << accentColor.name(QColor::HexArgb).toUpper() #ifdef Q_OS_WINDOWS - << ", colorization area: " << m_colorizationArea + << ", colorization area: " << colorizationArea #endif - << ", wallpaper: " << m_wallpaper - << ", aspect style: " << m_wallpaperAspectStyle + << ", wallpaper: " << wallpaper + << ", aspect style: " << wallpaperAspectStyle << '.'; // 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 @@ -389,43 +303,91 @@ FramelessManager *FramelessManager::instance() SystemTheme FramelessManager::systemTheme() const { Q_D(const FramelessManager); - return d->systemTheme(); + // The user's choice has top priority. + if (d->isThemeOverrided()) { + return d->overrideTheme.value(); + } + return d->systemTheme; } QColor FramelessManager::systemAccentColor() const { Q_D(const FramelessManager); - return d->systemAccentColor(); + return d->accentColor; } QString FramelessManager::wallpaper() const { Q_D(const FramelessManager); - return d->wallpaper(); + return d->wallpaper; } WallpaperAspectStyle FramelessManager::wallpaperAspectStyle() const { Q_D(const FramelessManager); - return d->wallpaperAspectStyle(); + return d->wallpaperAspectStyle; } -void FramelessManager::addWindow(FramelessParamsConst params) +void FramelessManager::setOverrideTheme(const SystemTheme theme) { Q_D(FramelessManager); - d->addWindow(params); + if ((!d->overrideTheme.has_value() && (theme == SystemTheme::Unknown)) + || (d->overrideTheme.has_value() && (d->overrideTheme.value() == theme))) { + return; + } + if (theme == SystemTheme::Unknown) { + d->overrideTheme = std::nullopt; + } else { + d->overrideTheme = theme; + } + Q_EMIT systemThemeChanged(); } -void FramelessManager::removeWindow(const WId windowId) +void FramelessManager::addWindow(FramelessParamsConst params) { - Q_D(FramelessManager); - d->removeWindow(windowId); + Q_ASSERT(params); + if (!params) { + return; + } + const WId windowId = params->getWindowId(); + if (g_framelessManagerData()->contains(windowId)) { + return; + } + g_framelessManagerData()->append(windowId); + static const bool pureQt = usePureQtImplementation(); + if (pureQt) { + FramelessHelperQt::addWindow(params); + } +#ifdef Q_OS_WINDOWS + if (!pureQt) { + FramelessHelperWin::addWindow(params); + } + std::ignore = Utils::installWindowProcHook(windowId, params); +#endif + connect(params->getWindowHandle(), &QWindow::destroyed, FramelessManager::instance(), [this, windowId](){ removeWindow(windowId); }); } -void FramelessManager::setOverrideTheme(const SystemTheme theme) +void FramelessManager::removeWindow(const WId windowId) { - Q_D(FramelessManager); - d->setOverrideTheme(theme); + Q_ASSERT(windowId); + if (!windowId) { + return; + } + if (!g_framelessManagerData()->contains(windowId)) { + return; + } + g_framelessManagerData()->removeAll(windowId); + static const bool pureQt = usePureQtImplementation(); + if (pureQt) { + FramelessHelperQt::removeWindow(windowId); + } +#ifdef Q_OS_WINDOWS + if (!pureQt) { + FramelessHelperWin::removeWindow(windowId); + } + std::ignore = Utils::uninstallWindowProcHook(windowId); + std::ignore = Utils::removeMicaWindow(windowId); +#endif } FRAMELESSHELPER_END_NAMESPACE diff --git a/src/core/micamaterial.cpp b/src/core/micamaterial.cpp index a5fc8290..56e40e23 100644 --- a/src/core/micamaterial.cpp +++ b/src/core/micamaterial.cpp @@ -680,70 +680,6 @@ void MicaMaterialPrivate::updateMaterialBrush() } } -void MicaMaterialPrivate::paint(QPainter *painter, const QRect &rect, const bool active) -{ - Q_ASSERT(painter); - if (!painter) { - return; - } - prepareGraphicsResources(); - static constexpr const QPoint originPoint = {0, 0}; - const QRect wallpaperRect = { originPoint, wallpaperSize }; - const QRect mappedRect = mapToWallpaper(rect); - painter->save(); - // Same as above. Speed is more important here. - painter->setRenderHint(QPainter::Antialiasing, false); - painter->setRenderHint(QPainter::TextAntialiasing, false); - painter->setRenderHint(QPainter::SmoothPixmapTransform, false); - if (active) { - const QRect intersectedRect = wallpaperRect.intersected(mappedRect); - g_imageData()->mutex.lock(); - painter->drawPixmap(originPoint, g_imageData()->blurredWallpaper, intersectedRect); - g_imageData()->mutex.unlock(); - if (intersectedRect != mappedRect) { - static constexpr const auto xOffset = QPoint{ 1, 0 }; - if (mappedRect.y() + mappedRect.height() <= wallpaperRect.height()) { - const QRect outerRect = { intersectedRect.topRight() + xOffset, QSize{ mappedRect.width() - intersectedRect.width(), intersectedRect.height() } }; - const QPoint outerRectOriginPoint = originPoint + QPoint{ intersectedRect.width(), 0 } + xOffset; - const QRect mappedOuterRect = mapToWallpaper(outerRect); - const QMutexLocker locker(&g_imageData()->mutex); - painter->drawPixmap(outerRectOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRect); - } else { - static constexpr const auto yOffset = QPoint{ 0, 1 }; - const QRect outerRectBottom = { intersectedRect.bottomLeft() + yOffset, QSize{ intersectedRect.width(), mappedRect.height() - intersectedRect.height() } }; - const QPoint outerRectBottomOriginPoint = originPoint + QPoint{ 0, intersectedRect.height() } + yOffset; - const QRect mappedOuterRectBottom = mapToWallpaper(outerRectBottom); - g_imageData()->mutex.lock(); - painter->drawPixmap(outerRectBottomOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRectBottom); - g_imageData()->mutex.unlock(); - if (mappedRect.x() + mappedRect.width() > wallpaperRect.width()) { - const QRect outerRectRight = { intersectedRect.topRight() + xOffset, QSize{ mappedRect.width() - intersectedRect.width(), intersectedRect.height() } }; - const QPoint outerRectRightOriginPoint = originPoint + QPoint{ intersectedRect.width(), 0 } + xOffset; - const QRect mappedOuterRectRight = mapToWallpaper(outerRectRight); - const QRect outerRectCorner = { intersectedRect.bottomRight() + xOffset + yOffset, QSize{ outerRectRight.width(), outerRectBottom.height() } }; - const QPoint outerRectCornerOriginPoint = originPoint + QPoint{ intersectedRect.width(), intersectedRect.height() } + xOffset + yOffset; - const QRect mappedOuterRectCorner = mapToWallpaper(outerRectCorner); - const QMutexLocker locker(&g_imageData()->mutex); - painter->drawPixmap(outerRectRightOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRectRight); - painter->drawPixmap(outerRectCornerOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRectCorner); - } - } - } - } - painter->setCompositionMode(QPainter::CompositionMode_SourceOver); - painter->setOpacity(qreal(1)); - painter->fillRect(QRect{originPoint, mappedRect.size()}, [this, active]() -> QBrush { - if (!fallbackEnabled || active) { - return micaBrush; - } - if (fallbackColor.isValid()) { - return fallbackColor; - } - return systemFallbackColor(); - }()); - painter->restore(); -} - void MicaMaterialPrivate::forceRebuildWallpaper() { wallpaperSize = QGuiApplication::primaryScreen()->size(); @@ -962,8 +898,67 @@ void MicaMaterial::setFallbackEnabled(const bool value) void MicaMaterial::paint(QPainter *painter, const QRect &rect, const bool active) { + Q_ASSERT(painter); + if (!painter) { + return; + } Q_D(MicaMaterial); - d->paint(painter, rect, active); + d->prepareGraphicsResources(); + static constexpr const auto originPoint = QPoint{ 0, 0 }; + const QRect wallpaperRect = { originPoint, d->wallpaperSize }; + const QRect mappedRect = d->mapToWallpaper(rect); + painter->save(); + // Same as above. Speed is more important here. + painter->setRenderHint(QPainter::Antialiasing, false); + painter->setRenderHint(QPainter::TextAntialiasing, false); + painter->setRenderHint(QPainter::SmoothPixmapTransform, false); + if (active) { + const QRect intersectedRect = wallpaperRect.intersected(mappedRect); + g_imageData()->mutex.lock(); + painter->drawPixmap(originPoint, g_imageData()->blurredWallpaper, intersectedRect); + g_imageData()->mutex.unlock(); + if (intersectedRect != mappedRect) { + static constexpr const auto xOffset = QPoint{ 1, 0 }; + if (mappedRect.y() + mappedRect.height() <= wallpaperRect.height()) { + const QRect outerRect = { intersectedRect.topRight() + xOffset, QSize{ mappedRect.width() - intersectedRect.width(), intersectedRect.height() } }; + const QPoint outerRectOriginPoint = originPoint + QPoint{ intersectedRect.width(), 0 } + xOffset; + const QRect mappedOuterRect = d->mapToWallpaper(outerRect); + const QMutexLocker locker(&g_imageData()->mutex); + painter->drawPixmap(outerRectOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRect); + } else { + static constexpr const auto yOffset = QPoint{ 0, 1 }; + const QRect outerRectBottom = { intersectedRect.bottomLeft() + yOffset, QSize{ intersectedRect.width(), mappedRect.height() - intersectedRect.height() } }; + const QPoint outerRectBottomOriginPoint = originPoint + QPoint{ 0, intersectedRect.height() } + yOffset; + const QRect mappedOuterRectBottom = d->mapToWallpaper(outerRectBottom); + g_imageData()->mutex.lock(); + painter->drawPixmap(outerRectBottomOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRectBottom); + g_imageData()->mutex.unlock(); + if (mappedRect.x() + mappedRect.width() > wallpaperRect.width()) { + const QRect outerRectRight = { intersectedRect.topRight() + xOffset, QSize{ mappedRect.width() - intersectedRect.width(), intersectedRect.height() } }; + const QPoint outerRectRightOriginPoint = originPoint + QPoint{ intersectedRect.width(), 0 } + xOffset; + const QRect mappedOuterRectRight = d->mapToWallpaper(outerRectRight); + const QRect outerRectCorner = { intersectedRect.bottomRight() + xOffset + yOffset, QSize{ outerRectRight.width(), outerRectBottom.height() } }; + const QPoint outerRectCornerOriginPoint = originPoint + QPoint{ intersectedRect.width(), intersectedRect.height() } + xOffset + yOffset; + const QRect mappedOuterRectCorner = d->mapToWallpaper(outerRectCorner); + const QMutexLocker locker(&g_imageData()->mutex); + painter->drawPixmap(outerRectRightOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRectRight); + painter->drawPixmap(outerRectCornerOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRectCorner); + } + } + } + } + painter->setCompositionMode(QPainter::CompositionMode_SourceOver); + painter->setOpacity(qreal(1)); + painter->fillRect(QRect{originPoint, mappedRect.size()}, [d, active]() -> QBrush { + if (!d->fallbackEnabled || active) { + return d->micaBrush; + } + if (d->fallbackColor.isValid()) { + return d->fallbackColor; + } + return d->systemFallbackColor(); + }()); + painter->restore(); } FRAMELESSHELPER_END_NAMESPACE diff --git a/src/core/windowborderpainter.cpp b/src/core/windowborderpainter.cpp index 70e626a0..f8e8208a 100644 --- a/src/core/windowborderpainter.cpp +++ b/src/core/windowborderpainter.cpp @@ -59,7 +59,6 @@ WindowBorderPainterPrivate::WindowBorderPainterPrivate(WindowBorderPainter *q) : return; } q_ptr = q; - initialize(); } WindowBorderPainterPrivate::~WindowBorderPainterPrivate() = default; @@ -82,46 +81,85 @@ const WindowBorderPainterPrivate *WindowBorderPainterPrivate::get(const WindowBo return q->d_func(); } -int WindowBorderPainterPrivate::getNativeBorderThickness() +WindowBorderPainter::WindowBorderPainter(QObject *parent) + : QObject(parent), d_ptr(new WindowBorderPainterPrivate(this)) { - // Qt will scale it to the appropriate value for us automatically, - // based on the current system DPI and scale factor rounding policy. - return kDefaultWindowFrameBorderThickness; + connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged, this, &WindowBorderPainter::nativeBorderChanged); + connect(this, &WindowBorderPainter::nativeBorderChanged, this, &WindowBorderPainter::shouldRepaint); +} + +WindowBorderPainter::~WindowBorderPainter() = default; + +int WindowBorderPainter::thickness() const +{ + Q_D(const WindowBorderPainter); + return d->thickness.value_or(nativeThickness()); +} + +WindowEdges WindowBorderPainter::edges() const +{ + Q_D(const WindowBorderPainter); + return d->edges.value_or(nativeEdges()); +} + +QColor WindowBorderPainter::activeColor() const +{ + Q_D(const WindowBorderPainter); + return d->activeColor.value_or(nativeActiveColor()); +} + +QColor WindowBorderPainter::inactiveColor() const +{ + Q_D(const WindowBorderPainter); + return d->inactiveColor.value_or(nativeInactiveColor()); } -QColor WindowBorderPainterPrivate::getNativeBorderColor(const bool active) +int WindowBorderPainter::nativeThickness() const { - return Utils::getFrameBorderColor(active); + // Qt will scale it to the appropriate value for us automatically, + // based on the current system DPI and scale factor rounding policy. + return kDefaultWindowFrameBorderThickness; } -WindowEdges WindowBorderPainterPrivate::getNativeBorderEdges() +WindowEdges WindowBorderPainter::nativeEdges() const { #ifdef Q_OS_WINDOWS if (Utils::isWindowFrameBorderVisible() && !WindowsVersionHelper::isWin11OrGreater()) { - return {WindowEdge::Top}; + return { WindowEdge::Top }; } #endif return {}; } -void WindowBorderPainterPrivate::paint(QPainter *painter, const QSize &size, const bool active) const +QColor WindowBorderPainter::nativeActiveColor() const +{ + return Utils::getFrameBorderColor(true); +} + +QColor WindowBorderPainter::nativeInactiveColor() const +{ + return Utils::getFrameBorderColor(false); +} + +void WindowBorderPainter::paint(QPainter *painter, const QSize &size, const bool active) { Q_ASSERT(painter); Q_ASSERT(!size.isEmpty()); if (!painter || size.isEmpty()) { return; } + Q_D(WindowBorderPainter); #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QList lines = {}; #else QVector lines = {}; #endif static constexpr const auto gap = qreal(0.5); - const QPointF leftTop = {gap, gap}; - const QPointF rightTop = {qreal(size.width()) - gap, gap}; - const QPointF rightBottom = {qreal(size.width()) - gap, qreal(size.height()) - gap}; - const QPointF leftBottom = {gap, qreal(size.height()) - gap}; - const WindowEdges edges = m_edges.value_or(getNativeBorderEdges()); + const auto leftTop = QPointF{ gap, gap }; + const auto rightTop = QPointF{ qreal(size.width()) - gap, leftTop.y() }; + const auto rightBottom = QPointF{ rightTop.x(), qreal(size.height()) - gap }; + const auto leftBottom = QPointF{ leftTop.x(), rightBottom.y() }; + const WindowEdges edges = d->edges.value_or(nativeEdges()); if (edges & WindowEdge::Left) { lines.append({leftBottom, leftTop}); } @@ -140,93 +178,24 @@ void WindowBorderPainterPrivate::paint(QPainter *painter, const QSize &size, con painter->save(); painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform); QPen pen = {}; - pen.setColor([active, this]() -> QColor { + pen.setColor([this, d, active]() -> QColor { QColor color = {}; if (active) { - color = m_activeColor.value_or(getNativeBorderColor(true)); + color = d->activeColor.value_or(nativeActiveColor()); } else { - color = m_inactiveColor.value_or(getNativeBorderColor(false)); + color = d->inactiveColor.value_or(nativeInactiveColor()); } if (color.isValid()) { return color; } return (active ? kDefaultBlackColor : kDefaultDarkGrayColor); }()); - pen.setWidth(m_thickness.value_or(getNativeBorderThickness())); + pen.setWidth(d->thickness.value_or(nativeThickness())); painter->setPen(pen); painter->drawLines(lines); painter->restore(); } -void WindowBorderPainterPrivate::initialize() -{ - Q_Q(WindowBorderPainter); - connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged, - q, &WindowBorderPainter::nativeBorderChanged); - connect(q, &WindowBorderPainter::nativeBorderChanged, q, &WindowBorderPainter::shouldRepaint); -} - -WindowBorderPainter::WindowBorderPainter(QObject *parent) - : QObject(parent), d_ptr(new WindowBorderPainterPrivate(this)) -{ -} - -WindowBorderPainter::~WindowBorderPainter() = default; - -int WindowBorderPainter::thickness() const -{ - Q_D(const WindowBorderPainter); - return d->m_thickness.value_or(d->getNativeBorderThickness()); -} - -WindowEdges WindowBorderPainter::edges() const -{ - Q_D(const WindowBorderPainter); - return d->m_edges.value_or(d->getNativeBorderEdges()); -} - -QColor WindowBorderPainter::activeColor() const -{ - Q_D(const WindowBorderPainter); - return d->m_activeColor.value_or(d->getNativeBorderColor(true)); -} - -QColor WindowBorderPainter::inactiveColor() const -{ - Q_D(const WindowBorderPainter); - return d->m_inactiveColor.value_or(d->getNativeBorderColor(false)); -} - -int WindowBorderPainter::nativeThickness() const -{ - Q_D(const WindowBorderPainter); - return d->getNativeBorderThickness(); -} - -WindowEdges WindowBorderPainter::nativeEdges() const -{ - Q_D(const WindowBorderPainter); - return d->getNativeBorderEdges(); -} - -QColor WindowBorderPainter::nativeActiveColor() const -{ - Q_D(const WindowBorderPainter); - return d->getNativeBorderColor(true); -} - -QColor WindowBorderPainter::nativeInactiveColor() const -{ - Q_D(const WindowBorderPainter); - return d->getNativeBorderColor(false); -} - -void WindowBorderPainter::paint(QPainter *painter, const QSize &size, const bool active) const -{ - Q_D(const WindowBorderPainter); - d->paint(painter, size, active); -} - void WindowBorderPainter::setThickness(const int value) { Q_ASSERT(value >= 0); @@ -238,7 +207,7 @@ void WindowBorderPainter::setThickness(const int value) return; } Q_D(WindowBorderPainter); - d->m_thickness = value; + d->thickness = value; Q_EMIT thicknessChanged(); Q_EMIT shouldRepaint(); } @@ -249,7 +218,7 @@ void WindowBorderPainter::setEdges(const Global::WindowEdges value) return; } Q_D(WindowBorderPainter); - d->m_edges = value; + d->edges = value; Q_EMIT edgesChanged(); Q_EMIT shouldRepaint(); } @@ -264,7 +233,7 @@ void WindowBorderPainter::setActiveColor(const QColor &value) return; } Q_D(WindowBorderPainter); - d->m_activeColor = value; + d->activeColor = value; Q_EMIT activeColorChanged(); Q_EMIT shouldRepaint(); } @@ -279,7 +248,7 @@ void WindowBorderPainter::setInactiveColor(const QColor &value) return; } Q_D(WindowBorderPainter); - d->m_inactiveColor = value; + d->inactiveColor = value; Q_EMIT inactiveColorChanged(); Q_EMIT shouldRepaint(); }