mica material: don't assume thread is always available

This commit is contained in:
Yuhang Zhao 2023-10-07 17:58:57 +08:00
parent 7a84744dc3
commit ad595c59e4
1 changed files with 58 additions and 5 deletions

View File

@ -27,6 +27,13 @@
#if FRAMELESSHELPER_CONFIG(mica_material) #if FRAMELESSHELPER_CONFIG(mica_material)
#if QT_CONFIG(thread)
# define FRAMELESSHELPER_HAS_THREAD
using FramelessHelperThreadClass = QThread;
#else
using FramelessHelperThreadClass = QObject;
#endif
#include "framelessmanager.h" #include "framelessmanager.h"
#include "utils.h" #include "utils.h"
#include "framelessconfig_p.h" #include "framelessconfig_p.h"
@ -35,8 +42,10 @@
#include <memory> #include <memory>
#include <QtCore/qsysinfo.h> #include <QtCore/qsysinfo.h>
#include <QtCore/qloggingcategory.h> #include <QtCore/qloggingcategory.h>
#include <QtCore/qmutex.h> #ifdef FRAMELESSHELPER_HAS_THREAD
#include <QtCore/qthread.h> # include <QtCore/qmutex.h>
# include <QtCore/qthread.h>
#endif
#include <QtGui/qpixmap.h> #include <QtGui/qpixmap.h>
#include <QtGui/qimage.h> #include <QtGui/qimage.h>
#include <QtGui/qimagereader.h> #include <QtGui/qimagereader.h>
@ -80,7 +89,9 @@ struct ImageData
{ {
QPixmap blurredWallpaper = {}; QPixmap blurredWallpaper = {};
bool graphicsResourcesReady = false; bool graphicsResourcesReady = false;
#ifdef FRAMELESSHELPER_HAS_THREAD
QMutex mutex{}; QMutex mutex{};
#endif
}; };
Q_GLOBAL_STATIC(ImageData, g_imageData) Q_GLOBAL_STATIC(ImageData, g_imageData)
@ -479,20 +490,25 @@ static inline void expblur(QImage &img, qreal radius, const bool improvedQuality
return {x, y, w, h}; return {x, y, w, h};
} }
class WallpaperThread : public QThread class WallpaperThread : public FramelessHelperThreadClass
{ {
Q_OBJECT Q_OBJECT
FRAMELESSHELPER_QT_CLASS(WallpaperThread) FRAMELESSHELPER_QT_CLASS(WallpaperThread)
public: public:
explicit WallpaperThread(QObject *parent = nullptr) : QThread(parent) {} explicit WallpaperThread(QObject *parent = nullptr) : FramelessHelperThreadClass(parent) {}
~WallpaperThread() override = default; ~WallpaperThread() override = default;
Q_SIGNALS: Q_SIGNALS:
void imageUpdated(); void imageUpdated();
#ifdef FRAMELESSHELPER_HAS_THREAD
protected: protected:
void run() override void run() override
#else
public:
void start()
#endif
{ {
const QString wallpaperFilePath = Utils::getWallpaperFilePath(); const QString wallpaperFilePath = Utils::getWallpaperFilePath();
if (wallpaperFilePath.isEmpty()) { if (wallpaperFilePath.isEmpty()) {
@ -565,7 +581,9 @@ protected:
bufferPainter.drawImage(rect.topLeft(), image); bufferPainter.drawImage(rect.topLeft(), image);
} }
{ {
#ifdef FRAMELESSHELPER_HAS_THREAD
const QMutexLocker locker(&g_imageData()->mutex); const QMutexLocker locker(&g_imageData()->mutex);
#endif
g_imageData()->blurredWallpaper = QPixmap(wallpaperSize); g_imageData()->blurredWallpaper = QPixmap(wallpaperSize);
g_imageData()->blurredWallpaper.fill(kDefaultTransparentColor); g_imageData()->blurredWallpaper.fill(kDefaultTransparentColor);
QPainter painter(&g_imageData()->blurredWallpaper); QPainter painter(&g_imageData()->blurredWallpaper);
@ -586,11 +604,13 @@ protected:
struct ThreadData struct ThreadData
{ {
std::unique_ptr<WallpaperThread> thread = nullptr; std::unique_ptr<WallpaperThread> thread = nullptr;
#ifdef FRAMELESSHELPER_HAS_THREAD
QMutex mutex{}; QMutex mutex{};
#endif
}; };
Q_GLOBAL_STATIC(ThreadData, g_threadData) Q_GLOBAL_STATIC(ThreadData, g_threadData)
#ifdef FRAMELESSHELPER_HAS_THREAD
static inline void threadCleaner() static inline void threadCleaner()
{ {
const QMutexLocker locker(&g_threadData()->mutex); const QMutexLocker locker(&g_threadData()->mutex);
@ -600,6 +620,7 @@ static inline void threadCleaner()
g_threadData()->thread->wait(); g_threadData()->thread->wait();
} }
} }
#endif
MicaMaterialPrivate::MicaMaterialPrivate(MicaMaterial *q) : QObject(q) MicaMaterialPrivate::MicaMaterialPrivate(MicaMaterial *q) : QObject(q)
{ {
@ -633,11 +654,16 @@ const MicaMaterialPrivate *MicaMaterialPrivate::get(const MicaMaterial *q)
void MicaMaterialPrivate::maybeGenerateBlurredWallpaper(const bool force) void MicaMaterialPrivate::maybeGenerateBlurredWallpaper(const bool force)
{ {
#ifdef FRAMELESSHELPER_HAS_THREAD
g_imageData()->mutex.lock(); g_imageData()->mutex.lock();
#endif
if (!g_imageData()->blurredWallpaper.isNull() && !force) { if (!g_imageData()->blurredWallpaper.isNull() && !force) {
#ifdef FRAMELESSHELPER_HAS_THREAD
g_imageData()->mutex.unlock(); g_imageData()->mutex.unlock();
#endif
return; return;
} }
#ifdef FRAMELESSHELPER_HAS_THREAD
g_imageData()->mutex.unlock(); g_imageData()->mutex.unlock();
const QMutexLocker locker(&g_threadData()->mutex); const QMutexLocker locker(&g_threadData()->mutex);
if (g_threadData()->thread->isRunning()) { if (g_threadData()->thread->isRunning()) {
@ -646,6 +672,9 @@ void MicaMaterialPrivate::maybeGenerateBlurredWallpaper(const bool force)
g_threadData()->thread->wait(); g_threadData()->thread->wait();
} }
g_threadData()->thread->start(QThread::LowPriority); g_threadData()->thread->start(QThread::LowPriority);
#else
g_threadData()->thread->start();
#endif
} }
void MicaMaterialPrivate::updateMaterialBrush() void MicaMaterialPrivate::updateMaterialBrush()
@ -685,10 +714,14 @@ void MicaMaterialPrivate::forceRebuildWallpaper()
void MicaMaterialPrivate::initialize() void MicaMaterialPrivate::initialize()
{ {
#ifdef FRAMELESSHELPER_HAS_THREAD
g_threadData()->mutex.lock(); g_threadData()->mutex.lock();
#endif
if (!g_threadData()->thread) { if (!g_threadData()->thread) {
g_threadData()->thread = std::make_unique<WallpaperThread>(); g_threadData()->thread = std::make_unique<WallpaperThread>();
#ifdef FRAMELESSHELPER_HAS_THREAD
qAddPostRoutine(threadCleaner); qAddPostRoutine(threadCleaner);
#endif
} }
connect(g_threadData()->thread.get(), &WallpaperThread::imageUpdated, this, [this](){ connect(g_threadData()->thread.get(), &WallpaperThread::imageUpdated, this, [this](){
if (initialized) { if (initialized) {
@ -696,7 +729,9 @@ void MicaMaterialPrivate::initialize()
Q_EMIT q->shouldRedraw(); Q_EMIT q->shouldRedraw();
} }
}); });
#ifdef FRAMELESSHELPER_HAS_THREAD
g_threadData()->mutex.unlock(); g_threadData()->mutex.unlock();
#endif
wallpaperSize = QGuiApplication::primaryScreen()->size(); wallpaperSize = QGuiApplication::primaryScreen()->size();
@ -724,13 +759,19 @@ void MicaMaterialPrivate::initialize()
void MicaMaterialPrivate::prepareGraphicsResources() void MicaMaterialPrivate::prepareGraphicsResources()
{ {
#ifdef FRAMELESSHELPER_HAS_THREAD
g_imageData()->mutex.lock(); g_imageData()->mutex.lock();
#endif
if (g_imageData()->graphicsResourcesReady) { if (g_imageData()->graphicsResourcesReady) {
#ifdef FRAMELESSHELPER_HAS_THREAD
g_imageData()->mutex.unlock(); g_imageData()->mutex.unlock();
#endif
return; return;
} }
g_imageData()->graphicsResourcesReady = true; g_imageData()->graphicsResourcesReady = true;
#ifdef FRAMELESSHELPER_HAS_THREAD
g_imageData()->mutex.unlock(); g_imageData()->mutex.unlock();
#endif
maybeGenerateBlurredWallpaper(); maybeGenerateBlurredWallpaper();
} }
@ -911,25 +952,35 @@ void MicaMaterial::paint(QPainter *painter, const QRect &rect, const bool active
painter->setRenderHint(QPainter::SmoothPixmapTransform, false); painter->setRenderHint(QPainter::SmoothPixmapTransform, false);
if (active) { if (active) {
const QRect intersectedRect = wallpaperRect.intersected(mappedRect); const QRect intersectedRect = wallpaperRect.intersected(mappedRect);
#ifdef FRAMELESSHELPER_HAS_THREAD
g_imageData()->mutex.lock(); g_imageData()->mutex.lock();
#endif
painter->drawPixmap(originPoint, g_imageData()->blurredWallpaper, intersectedRect); painter->drawPixmap(originPoint, g_imageData()->blurredWallpaper, intersectedRect);
#ifdef FRAMELESSHELPER_HAS_THREAD
g_imageData()->mutex.unlock(); g_imageData()->mutex.unlock();
#endif
if (intersectedRect != mappedRect) { if (intersectedRect != mappedRect) {
static constexpr const auto xOffset = QPoint{ 1, 0 }; static constexpr const auto xOffset = QPoint{ 1, 0 };
if (mappedRect.y() + mappedRect.height() <= wallpaperRect.height()) { if (mappedRect.y() + mappedRect.height() <= wallpaperRect.height()) {
const QRect outerRect = { intersectedRect.topRight() + xOffset, QSize{ mappedRect.width() - intersectedRect.width(), intersectedRect.height() } }; const QRect outerRect = { intersectedRect.topRight() + xOffset, QSize{ mappedRect.width() - intersectedRect.width(), intersectedRect.height() } };
const QPoint outerRectOriginPoint = originPoint + QPoint{ intersectedRect.width(), 0 } + xOffset; const QPoint outerRectOriginPoint = originPoint + QPoint{ intersectedRect.width(), 0 } + xOffset;
const QRect mappedOuterRect = d->mapToWallpaper(outerRect); const QRect mappedOuterRect = d->mapToWallpaper(outerRect);
#ifdef FRAMELESSHELPER_HAS_THREAD
const QMutexLocker locker(&g_imageData()->mutex); const QMutexLocker locker(&g_imageData()->mutex);
#endif
painter->drawPixmap(outerRectOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRect); painter->drawPixmap(outerRectOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRect);
} else { } else {
static constexpr const auto yOffset = QPoint{ 0, 1 }; static constexpr const auto yOffset = QPoint{ 0, 1 };
const QRect outerRectBottom = { intersectedRect.bottomLeft() + yOffset, QSize{ intersectedRect.width(), mappedRect.height() - intersectedRect.height() } }; const QRect outerRectBottom = { intersectedRect.bottomLeft() + yOffset, QSize{ intersectedRect.width(), mappedRect.height() - intersectedRect.height() } };
const QPoint outerRectBottomOriginPoint = originPoint + QPoint{ 0, intersectedRect.height() } + yOffset; const QPoint outerRectBottomOriginPoint = originPoint + QPoint{ 0, intersectedRect.height() } + yOffset;
const QRect mappedOuterRectBottom = d->mapToWallpaper(outerRectBottom); const QRect mappedOuterRectBottom = d->mapToWallpaper(outerRectBottom);
#ifdef FRAMELESSHELPER_HAS_THREAD
g_imageData()->mutex.lock(); g_imageData()->mutex.lock();
#endif
painter->drawPixmap(outerRectBottomOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRectBottom); painter->drawPixmap(outerRectBottomOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRectBottom);
#ifdef FRAMELESSHELPER_HAS_THREAD
g_imageData()->mutex.unlock(); g_imageData()->mutex.unlock();
#endif
if (mappedRect.x() + mappedRect.width() > wallpaperRect.width()) { if (mappedRect.x() + mappedRect.width() > wallpaperRect.width()) {
const QRect outerRectRight = { intersectedRect.topRight() + xOffset, QSize{ mappedRect.width() - intersectedRect.width(), intersectedRect.height() } }; const QRect outerRectRight = { intersectedRect.topRight() + xOffset, QSize{ mappedRect.width() - intersectedRect.width(), intersectedRect.height() } };
const QPoint outerRectRightOriginPoint = originPoint + QPoint{ intersectedRect.width(), 0 } + xOffset; const QPoint outerRectRightOriginPoint = originPoint + QPoint{ intersectedRect.width(), 0 } + xOffset;
@ -937,7 +988,9 @@ void MicaMaterial::paint(QPainter *painter, const QRect &rect, const bool active
const QRect outerRectCorner = { intersectedRect.bottomRight() + xOffset + yOffset, QSize{ outerRectRight.width(), outerRectBottom.height() } }; const QRect outerRectCorner = { intersectedRect.bottomRight() + xOffset + yOffset, QSize{ outerRectRight.width(), outerRectBottom.height() } };
const QPoint outerRectCornerOriginPoint = originPoint + QPoint{ intersectedRect.width(), intersectedRect.height() } + xOffset + yOffset; const QPoint outerRectCornerOriginPoint = originPoint + QPoint{ intersectedRect.width(), intersectedRect.height() } + xOffset + yOffset;
const QRect mappedOuterRectCorner = d->mapToWallpaper(outerRectCorner); const QRect mappedOuterRectCorner = d->mapToWallpaper(outerRectCorner);
#ifdef FRAMELESSHELPER_HAS_THREAD
const QMutexLocker locker(&g_imageData()->mutex); const QMutexLocker locker(&g_imageData()->mutex);
#endif
painter->drawPixmap(outerRectRightOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRectRight); painter->drawPixmap(outerRectRightOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRectRight);
painter->drawPixmap(outerRectCornerOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRectCorner); painter->drawPixmap(outerRectCornerOriginPoint, g_imageData()->blurredWallpaper, mappedOuterRectCorner);
} }