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