forked from github_mirror/framelesshelper
Compare commits
7 Commits
d2d2c7b75d
...
10580baf54
Author | SHA1 | Date |
---|---|---|
|
10580baf54 | |
|
e72257bb34 | |
|
43f632f261 | |
|
9dce992112 | |
|
d1b4aadb76 | |
|
6b09aa9e91 | |
|
617a015b97 |
|
@ -1,3 +1,3 @@
|
|||
[submodule "cmake"]
|
||||
path = cmake
|
||||
url = https://github.com/wangwenx190/cmake-utils.git
|
||||
url = https://git.ourdocs.cn/github_mirror/cmake-utils.git
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(FramelessHelper
|
||||
VERSION "2.3.7"
|
||||
VERSION "2.4.0"
|
||||
DESCRIPTION "Cross-platform window customization framework for Qt Widgets and Qt Quick."
|
||||
HOMEPAGE_URL "https://github.com/wangwenx190/framelesshelper/"
|
||||
)
|
||||
|
@ -38,14 +38,14 @@ option(FRAMELESSHELPER_BUILD_WIDGETS "Build FramelessHelper's Widgets module." O
|
|||
option(FRAMELESSHELPER_BUILD_QUICK "Build FramelessHelper's Quick module." ON)
|
||||
option(FRAMELESSHELPER_BUILD_EXAMPLES "Build FramelessHelper demo applications." OFF)
|
||||
option(FRAMELESSHELPER_EXAMPLES_DEPLOYQT "Deploy the Qt framework after building the demo projects." OFF)
|
||||
option(FRAMELESSHELPER_NO_DEBUG_OUTPUT "Suppress the debug messages from FramelessHelper." ON)
|
||||
option(FRAMELESSHELPER_NO_DEBUG_OUTPUT "Suppress the debug messages from FramelessHelper." OFF)
|
||||
option(FRAMELESSHELPER_NO_BUNDLE_RESOURCE "Do not bundle any resources within FramelessHelper." OFF)
|
||||
option(FRAMELESSHELPER_NO_PRIVATE "Do not use any private functionalities from Qt." OFF)
|
||||
option(FRAMELESSHELPER_ENABLE_VCLTL "MSVC only: link to the system MSVCRT/UCRT and get rid of API sets." OFF)
|
||||
option(FRAMELESSHELPER_ENABLE_YYTHUNKS "MSVC only: dynamic load most Win32 APIs to give better compatibility for old Windows versions." OFF)
|
||||
option(FRAMELESSHELPER_NO_PERMISSIVE_CHECKS "MSVC only: disable the additional permissive checks." OFF)
|
||||
option(FRAMELESSHELPER_NO_INSTALL "Don't install any files." OFF)
|
||||
option(FRAMELESSHELPER_NO_SUMMARY "Don't show CMake configure summary." ON)
|
||||
option(FRAMELESSHELPER_NO_SUMMARY "Don't show CMake configure summary." OFF)
|
||||
option(FRAMELESSHELPER_ENABLE_SPECTRE "Mitigate Spectre security vulnerabilities." OFF)
|
||||
option(FRAMELESSHELPER_ENABLE_EHCONTGUARD "MSVC only: Enable EH Continuation (EHCONT) Metadata." OFF)
|
||||
option(FRAMELESSHELPER_ENABLE_INTELCET "Enable Intel CET." OFF)
|
||||
|
|
|
@ -28,6 +28,11 @@ You can join our [Discord channel](https://discord.gg/grrM4Tmesy) to communicate
|
|||
- Widgets: Nested frameless windows are supported now!
|
||||
- Linux: There have been many improvements to the Linux/X11 implementation! Most of them won't be directly visible to the user, but the code quality has been greatly improved.
|
||||
- macOS: The frameless windows will now use native window frame and buttons, only the title bar itself is hidden, which also means the window will have round corners as all other native windows on macOS.
|
||||
- Mica Material: It is now possible to load wallpaper images with very large file size or resolution, for example, 4K pictures. However, if the images have larger resolution than 1920x1080, they will be shrinked to reduce memory usage, and this process will also lower the image quality and break the aspect ratio of them.
|
||||
- Mica Material: FramelessHelper will now use a seperate thread to load and apply special effects to the wallpaper image, to speed up application startup performance and avoid such process block the main thread.
|
||||
- Window management: It is now possible to close the window (the dtor is executed) and show it again without breaking the frameless functionalities.
|
||||
- Theme: It is now possible to force a desired theme instead of always respecting the system theme.
|
||||
- Build system: The [**Ninja Multi-Config**](https://cmake.org/cmake/help/latest/generator/Ninja%20Multi-Config.html) generator is fully supported now, finally!
|
||||
- Routine bug fixes and internal refactorings.
|
||||
|
||||
## Highlights v2.3
|
||||
|
|
2
cmake
2
cmake
|
@ -1 +1 @@
|
|||
Subproject commit c1e8081d4de985e5c7edbe2d5209860cb1ceb62f
|
||||
Subproject commit 4b4b901807771eda16fb07f36a5cb40505f64087
|
|
@ -39,16 +39,23 @@ Dialog::~Dialog() = default;
|
|||
void Dialog::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
if (!parent()) {
|
||||
Settings::set({}, kGeometry, geometry());
|
||||
Settings::set({}, kDevicePixelRatio, devicePixelRatioF());
|
||||
const QString id = objectName();
|
||||
Settings::set(id, kGeometry, geometry());
|
||||
Settings::set(id, kDevicePixelRatio, devicePixelRatioF());
|
||||
}
|
||||
FramelessDialog::closeEvent(event);
|
||||
}
|
||||
|
||||
void Dialog::setupUi()
|
||||
{
|
||||
setWindowTitle(tr("Qt Dialog demo"));
|
||||
setWindowTitle(tr("FramelessHelper demo application - QDialog"));
|
||||
setWindowIcon(QFileIconProvider().icon(QFileIconProvider::Computer));
|
||||
connect(this, &Dialog::objectNameChanged, this, [this](const QString &name){
|
||||
if (name.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
setWindowTitle(windowTitle() + FRAMELESSHELPER_STRING_LITERAL(" [%1]").arg(name));
|
||||
});
|
||||
|
||||
titleBar = new StandardTitleBar(this);
|
||||
titleBar->setWindowIconVisible(true);
|
||||
|
@ -142,9 +149,10 @@ void Dialog::waitReady()
|
|||
{
|
||||
FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this);
|
||||
helper->waitForReady();
|
||||
const auto savedGeometry = Settings::get<QRect>({}, kGeometry);
|
||||
const QString id = objectName();
|
||||
const auto savedGeometry = Settings::get<QRect>(id, kGeometry);
|
||||
if (savedGeometry.isValid() && !parent()) {
|
||||
const auto savedDpr = Settings::get<qreal>({}, kDevicePixelRatio);
|
||||
const auto savedDpr = Settings::get<qreal>(id, kDevicePixelRatio);
|
||||
// Qt doesn't support dpr < 1.
|
||||
const qreal oldDpr = std::max(savedDpr, qreal(1));
|
||||
const qreal scale = (devicePixelRatioF() / oldDpr);
|
||||
|
|
|
@ -29,6 +29,12 @@
|
|||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
#define CREATE_WINDOW(Name) \
|
||||
const auto Name = std::make_unique<Dialog>(); \
|
||||
Name->setObjectName(FRAMELESSHELPER_STRING_LITERAL(#Name)); \
|
||||
Name->waitReady(); \
|
||||
Name->show();
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Log::setup(FRAMELESSHELPER_STRING_LITERAL("dialog"));
|
||||
|
@ -51,11 +57,11 @@ int main(int argc, char *argv[])
|
|||
FramelessHelper::Core::setApplicationOSThemeAware();
|
||||
|
||||
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
|
||||
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
|
||||
//FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
|
||||
|
||||
const auto dialog = std::make_unique<Dialog>();
|
||||
dialog->waitReady();
|
||||
dialog->show();
|
||||
CREATE_WINDOW(dialog1)
|
||||
CREATE_WINDOW(dialog2)
|
||||
CREATE_WINDOW(dialog3)
|
||||
|
||||
return QCoreApplication::exec();
|
||||
}
|
||||
|
|
|
@ -29,6 +29,12 @@
|
|||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
#define CREATE_WINDOW(Name) \
|
||||
const auto Name = std::make_unique<MainWindow>(); \
|
||||
Name->setObjectName(FRAMELESSHELPER_STRING_LITERAL(#Name)); \
|
||||
Name->waitReady(); \
|
||||
Name->show();
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Log::setup(FRAMELESSHELPER_STRING_LITERAL("mainwindow"));
|
||||
|
@ -51,11 +57,11 @@ int main(int argc, char *argv[])
|
|||
FramelessHelper::Core::setApplicationOSThemeAware();
|
||||
|
||||
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
|
||||
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
|
||||
//FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
|
||||
|
||||
const auto mainWindow = std::make_unique<MainWindow>();
|
||||
mainWindow->waitReady();
|
||||
mainWindow->show();
|
||||
CREATE_WINDOW(mainWindow1)
|
||||
CREATE_WINDOW(mainWindow2)
|
||||
CREATE_WINDOW(mainWindow3)
|
||||
|
||||
return QCoreApplication::exec();
|
||||
}
|
||||
|
|
|
@ -60,9 +60,10 @@ MainWindow::~MainWindow() = default;
|
|||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
if (!parent()) {
|
||||
Settings::set({}, kGeometry, geometry());
|
||||
Settings::set({}, kState, saveState());
|
||||
Settings::set({}, kDevicePixelRatio, devicePixelRatioF());
|
||||
const QString id = objectName();
|
||||
Settings::set(id, kGeometry, geometry());
|
||||
Settings::set(id, kState, saveState());
|
||||
Settings::set(id, kDevicePixelRatio, devicePixelRatioF());
|
||||
}
|
||||
FramelessMainWindow::closeEvent(event);
|
||||
}
|
||||
|
@ -108,8 +109,14 @@ QMenuBar::item:pressed {
|
|||
#endif // Q_OS_MACOS
|
||||
helper->setHitTestVisible(mb); // IMPORTANT!
|
||||
|
||||
setWindowTitle(tr("FramelessHelper demo application - Qt MainWindow"));
|
||||
setWindowTitle(tr("FramelessHelper demo application - QMainWindow"));
|
||||
setWindowIcon(QFileIconProvider().icon(QFileIconProvider::Computer));
|
||||
connect(this, &MainWindow::objectNameChanged, this, [this](const QString &name){
|
||||
if (name.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
setWindowTitle(windowTitle() + FRAMELESSHELPER_STRING_LITERAL(" [%1]").arg(name));
|
||||
});
|
||||
connect(m_mainWindow->pushButton, &QPushButton::clicked, this, [this]{
|
||||
const auto dialog = new Dialog(this);
|
||||
dialog->waitReady();
|
||||
|
@ -128,9 +135,10 @@ void MainWindow::waitReady()
|
|||
{
|
||||
FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this);
|
||||
helper->waitForReady();
|
||||
const auto savedGeometry = Settings::get<QRect>({}, kGeometry);
|
||||
const QString id = objectName();
|
||||
const auto savedGeometry = Settings::get<QRect>(id, kGeometry);
|
||||
if (savedGeometry.isValid() && !parent()) {
|
||||
const auto savedDpr = Settings::get<qreal>({}, kDevicePixelRatio);
|
||||
const auto savedDpr = Settings::get<qreal>(id, kDevicePixelRatio);
|
||||
// Qt doesn't support dpr < 1.
|
||||
const qreal oldDpr = std::max(savedDpr, qreal(1));
|
||||
const qreal scale = (devicePixelRatioF() / oldDpr);
|
||||
|
@ -138,7 +146,7 @@ void MainWindow::waitReady()
|
|||
} else {
|
||||
helper->moveWindowToDesktopCenter();
|
||||
}
|
||||
const QByteArray savedState = Settings::get<QByteArray>({}, kState);
|
||||
const QByteArray savedState = Settings::get<QByteArray>(id, kState);
|
||||
if (!savedState.isEmpty() && !parent()) {
|
||||
restoreState(savedState);
|
||||
}
|
||||
|
|
|
@ -59,10 +59,9 @@ int main(int argc, char *argv[])
|
|||
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
|
||||
//FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
|
||||
|
||||
CREATE_WINDOW(window1)
|
||||
CREATE_WINDOW(window2)
|
||||
CREATE_WINDOW(window3)
|
||||
CREATE_WINDOW(window4)
|
||||
CREATE_WINDOW(widget1)
|
||||
CREATE_WINDOW(widget2)
|
||||
CREATE_WINDOW(widget3)
|
||||
|
||||
return QCoreApplication::exec();
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ void Widget::closeEvent(QCloseEvent *event)
|
|||
|
||||
void Widget::initialize()
|
||||
{
|
||||
setWindowTitle(tr("FramelessHelper demo application - Qt Widgets"));
|
||||
setWindowTitle(tr("FramelessHelper demo application - QWidget"));
|
||||
setWindowIcon(QFileIconProvider().icon(QFileIconProvider::Computer));
|
||||
resize(800, 600);
|
||||
m_titleBar = new StandardTitleBar(this);
|
||||
|
|
|
@ -31,6 +31,12 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
|
||||
class MicaMaterial;
|
||||
|
||||
using Transform = struct Transform
|
||||
{
|
||||
qreal Horizontal = 0;
|
||||
qreal Vertical = 0;
|
||||
};
|
||||
|
||||
class FRAMELESSHELPER_CORE_API MicaMaterialPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -64,10 +70,7 @@ private:
|
|||
bool fallbackEnabled = true;
|
||||
QBrush micaBrush = {};
|
||||
bool initialized = false;
|
||||
struct {
|
||||
qreal x = 0;
|
||||
qreal y = 0;
|
||||
} transform = {};
|
||||
Transform transform = {};
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -34,10 +34,10 @@
|
|||
#define _FRAMELESSHELPER_VERSION_DEFINED_
|
||||
|
||||
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_MAJOR = 2;
|
||||
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_MINOR = 3;
|
||||
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_PATCH = 7;
|
||||
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_MINOR = 4;
|
||||
[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_PATCH = 0;
|
||||
//[[maybe_unused]] inline constexpr const int FRAMELESSHELPER_VERSION_TWEAK = 0;
|
||||
[[maybe_unused]] inline constexpr const char FRAMELESSHELPER_VERSION_STR[] = "2.3.7";
|
||||
[[maybe_unused]] inline constexpr const char FRAMELESSHELPER_VERSION_STR[] = "2.4.0";
|
||||
[[maybe_unused]] inline constexpr const char FRAMELESSHELPER_COMMIT_STR[] = "UNKNOWN";
|
||||
[[maybe_unused]] inline constexpr const char FRAMELESSHELPER_COMPILE_DATETIME_STR[] = "UNKNOWN";
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include "framelessconfig_p.h"
|
||||
#include <QtCore/qsysinfo.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qthread.h>
|
||||
#include <QtGui/qpixmap.h>
|
||||
#include <QtGui/qimage.h>
|
||||
#include <QtGui/qimagereader.h>
|
||||
|
@ -77,6 +79,7 @@ struct MicaMaterialData
|
|||
{
|
||||
QPixmap blurredWallpaper = {};
|
||||
bool graphicsResourcesReady = false;
|
||||
QMutex mutex{};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(MicaMaterialData, g_micaMaterialData)
|
||||
|
@ -497,6 +500,130 @@ static inline void expblur(QImage &img, qreal radius, const bool improvedQuality
|
|||
return {x, y, w, h};
|
||||
}
|
||||
|
||||
class WallpaperThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(WallpaperThread)
|
||||
|
||||
public:
|
||||
explicit WallpaperThread(QObject *parent = nullptr) : QThread(parent) {}
|
||||
~WallpaperThread() override = default;
|
||||
|
||||
Q_SIGNALS:
|
||||
void imageUpdated(const Transform &);
|
||||
|
||||
protected:
|
||||
void run() override
|
||||
{
|
||||
Transform transform = {};
|
||||
// ### FIXME: Ideally, we should not use virtual desktop size here.
|
||||
QSize monitorSize = QGuiApplication::primaryScreen()->virtualSize();
|
||||
if (monitorSize.isEmpty()) {
|
||||
WARNING << "Failed to retrieve the monitor size. Using default size (1920x1080) instead ...";
|
||||
monitorSize = kMaximumPictureSize;
|
||||
}
|
||||
const QSize imageSize = (monitorSize > kMaximumPictureSize ? kMaximumPictureSize : monitorSize);
|
||||
if (imageSize != monitorSize) {
|
||||
transform.Horizontal = (qreal(imageSize.width()) / qreal(monitorSize.width()));
|
||||
transform.Vertical = (qreal(imageSize.height()) / qreal(monitorSize.height()));
|
||||
}
|
||||
const QString wallpaperFilePath = Utils::getWallpaperFilePath();
|
||||
if (wallpaperFilePath.isEmpty()) {
|
||||
WARNING << "Failed to retrieve the wallpaper file path.";
|
||||
return;
|
||||
}
|
||||
QImageReader reader(wallpaperFilePath);
|
||||
if (!reader.canRead()) {
|
||||
WARNING << "Qt can't read the wallpaper file:" << reader.errorString();
|
||||
return;
|
||||
}
|
||||
const QSize actualSize = reader.size();
|
||||
if (actualSize.isEmpty()) {
|
||||
WARNING << "The wallpaper picture size is invalid.";
|
||||
return;
|
||||
}
|
||||
const QSize correctedSize = (actualSize > kMaximumPictureSize ? kMaximumPictureSize : actualSize);
|
||||
if (correctedSize != actualSize) {
|
||||
DEBUG << "The wallpaper picture size is greater than 1920x1080, it will be shrinked to reduce memory consumption.";
|
||||
reader.setScaledSize(correctedSize);
|
||||
}
|
||||
QImage image(correctedSize, kDefaultImageFormat);
|
||||
if (!reader.read(&image)) {
|
||||
WARNING << "Failed to read the wallpaper image:" << reader.errorString();
|
||||
return;
|
||||
}
|
||||
if (image.isNull()) {
|
||||
WARNING << "The obtained image data is null.";
|
||||
return;
|
||||
}
|
||||
WallpaperAspectStyle aspectStyle = Utils::getWallpaperAspectStyle();
|
||||
QImage buffer(imageSize, kDefaultImageFormat);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (aspectStyle == WallpaperAspectStyle::Center) {
|
||||
buffer.fill(kDefaultBlackColor);
|
||||
}
|
||||
#endif
|
||||
if ((aspectStyle == WallpaperAspectStyle::Stretch)
|
||||
|| (aspectStyle == WallpaperAspectStyle::Fit)
|
||||
|| (aspectStyle == WallpaperAspectStyle::Fill)) {
|
||||
Qt::AspectRatioMode mode = Qt::KeepAspectRatioByExpanding;
|
||||
if (aspectStyle == WallpaperAspectStyle::Stretch) {
|
||||
mode = Qt::IgnoreAspectRatio;
|
||||
} else if (aspectStyle == WallpaperAspectStyle::Fit) {
|
||||
mode = Qt::KeepAspectRatio;
|
||||
}
|
||||
QSize newSize = image.size();
|
||||
newSize.scale(imageSize, mode);
|
||||
image = image.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
static constexpr const QPoint desktopOriginPoint = {0, 0};
|
||||
const QRect desktopRect = {desktopOriginPoint, imageSize};
|
||||
if (aspectStyle == WallpaperAspectStyle::Tile) {
|
||||
QPainter bufferPainter(&buffer);
|
||||
bufferPainter.setRenderHints(QPainter::Antialiasing |
|
||||
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
bufferPainter.fillRect(desktopRect, QBrush(image));
|
||||
} else {
|
||||
QPainter bufferPainter(&buffer);
|
||||
bufferPainter.setRenderHints(QPainter::Antialiasing |
|
||||
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
const QRect rect = alignedRect(Qt::LeftToRight, Qt::AlignCenter, image.size(), desktopRect);
|
||||
bufferPainter.drawImage(rect.topLeft(), image);
|
||||
}
|
||||
g_micaMaterialData()->mutex.lock();
|
||||
g_micaMaterialData()->blurredWallpaper = QPixmap(imageSize);
|
||||
g_micaMaterialData()->blurredWallpaper.fill(kDefaultTransparentColor);
|
||||
QPainter painter(&g_micaMaterialData()->blurredWallpaper);
|
||||
painter.setRenderHints(QPainter::Antialiasing |
|
||||
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
painter.drawImage(desktopOriginPoint, buffer);
|
||||
#else // !FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
qt_blurImage(&painter, buffer, kDefaultBlurRadius, true, false);
|
||||
#endif // FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
g_micaMaterialData()->mutex.unlock();
|
||||
Q_EMIT imageUpdated(transform);
|
||||
}
|
||||
};
|
||||
|
||||
struct ThreadData
|
||||
{
|
||||
std::unique_ptr<WallpaperThread> thread = nullptr;
|
||||
QMutex mutex{};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(ThreadData, g_threadData)
|
||||
|
||||
static inline void threadCleaner()
|
||||
{
|
||||
const QMutexLocker locker(&g_threadData()->mutex);
|
||||
if (g_threadData()->thread && g_threadData()->thread->isRunning()) {
|
||||
g_threadData()->thread->requestInterruption();
|
||||
g_threadData()->thread->quit();
|
||||
g_threadData()->thread->wait();
|
||||
}
|
||||
}
|
||||
|
||||
MicaMaterialPrivate::MicaMaterialPrivate(MicaMaterial *q) : QObject(q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
|
@ -529,98 +656,19 @@ const MicaMaterialPrivate *MicaMaterialPrivate::get(const MicaMaterial *q)
|
|||
|
||||
void MicaMaterialPrivate::maybeGenerateBlurredWallpaper(const bool force)
|
||||
{
|
||||
g_micaMaterialData()->mutex.lock();
|
||||
if (!g_micaMaterialData()->blurredWallpaper.isNull() && !force) {
|
||||
g_micaMaterialData()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
QSize monitorSize = QGuiApplication::primaryScreen()->virtualSize();
|
||||
if (monitorSize.isEmpty()) {
|
||||
WARNING << "Failed to retrieve the monitor size. Using default size (1920x1080) instead ...";
|
||||
monitorSize = kMaximumPictureSize;
|
||||
}
|
||||
const QSize imageSize = (monitorSize > kMaximumPictureSize ? kMaximumPictureSize : monitorSize);
|
||||
const QString wallpaperFilePath = Utils::getWallpaperFilePath();
|
||||
if (wallpaperFilePath.isEmpty()) {
|
||||
WARNING << "Failed to retrieve the wallpaper file path.";
|
||||
return;
|
||||
}
|
||||
QImageReader reader(wallpaperFilePath);
|
||||
if (!reader.canRead()) {
|
||||
WARNING << "Qt can't read the wallpaper file:" << reader.errorString();
|
||||
return;
|
||||
}
|
||||
const QSize actualSize = reader.size();
|
||||
if (actualSize.isEmpty()) {
|
||||
WARNING << "The wallpaper picture size is invalid.";
|
||||
return;
|
||||
}
|
||||
const QSize correctedSize = (actualSize > kMaximumPictureSize ? kMaximumPictureSize : actualSize);
|
||||
if (actualSize == correctedSize) {
|
||||
transform = {};
|
||||
} else {
|
||||
DEBUG << "The wallpaper picture size is greater than 1920x1080, it will be shrinked to reduce memory consumption.";
|
||||
reader.setScaledSize(correctedSize);
|
||||
transform.x = qreal(correctedSize.width()) / qreal(actualSize.width());
|
||||
transform.y = qreal(correctedSize.height()) / qreal(actualSize.height());
|
||||
}
|
||||
QImage image(correctedSize, kDefaultImageFormat);
|
||||
if (!reader.read(&image)) {
|
||||
WARNING << "Failed to read the wallpaper image:" << reader.errorString();
|
||||
transform = {};
|
||||
return;
|
||||
}
|
||||
if (image.isNull()) {
|
||||
WARNING << "The obtained image data is null.";
|
||||
transform = {};
|
||||
return;
|
||||
}
|
||||
WallpaperAspectStyle aspectStyle = Utils::getWallpaperAspectStyle();
|
||||
QImage buffer(imageSize, kDefaultImageFormat);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (aspectStyle == WallpaperAspectStyle::Center) {
|
||||
buffer.fill(kDefaultBlackColor);
|
||||
}
|
||||
#endif
|
||||
if ((aspectStyle == WallpaperAspectStyle::Stretch)
|
||||
|| (aspectStyle == WallpaperAspectStyle::Fit)
|
||||
|| (aspectStyle == WallpaperAspectStyle::Fill)) {
|
||||
Qt::AspectRatioMode mode = Qt::KeepAspectRatioByExpanding;
|
||||
if (aspectStyle == WallpaperAspectStyle::Stretch) {
|
||||
mode = Qt::IgnoreAspectRatio;
|
||||
} else if (aspectStyle == WallpaperAspectStyle::Fit) {
|
||||
mode = Qt::KeepAspectRatio;
|
||||
}
|
||||
QSize newSize = image.size();
|
||||
newSize.scale(imageSize, mode);
|
||||
image = image.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
static constexpr const QPoint desktopOriginPoint = {0, 0};
|
||||
const QRect desktopRect = {desktopOriginPoint, imageSize};
|
||||
if (aspectStyle == WallpaperAspectStyle::Tile) {
|
||||
QPainter bufferPainter(&buffer);
|
||||
bufferPainter.setRenderHints(QPainter::Antialiasing |
|
||||
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
bufferPainter.fillRect(desktopRect, QBrush(image));
|
||||
} else {
|
||||
QPainter bufferPainter(&buffer);
|
||||
bufferPainter.setRenderHints(QPainter::Antialiasing |
|
||||
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
const QRect rect = alignedRect(Qt::LeftToRight, Qt::AlignCenter, image.size(), desktopRect);
|
||||
bufferPainter.drawImage(rect.topLeft(), image);
|
||||
}
|
||||
g_micaMaterialData()->blurredWallpaper = QPixmap(imageSize);
|
||||
g_micaMaterialData()->blurredWallpaper.fill(kDefaultTransparentColor);
|
||||
QPainter painter(&g_micaMaterialData()->blurredWallpaper);
|
||||
painter.setRenderHints(QPainter::Antialiasing |
|
||||
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
painter.drawImage(desktopOriginPoint, buffer);
|
||||
#else // !FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
qt_blurImage(&painter, buffer, kDefaultBlurRadius, true, false);
|
||||
#endif // FRAMELESSHELPER_CORE_NO_PRIVATE
|
||||
if (initialized) {
|
||||
Q_Q(MicaMaterial);
|
||||
Q_EMIT q->shouldRedraw();
|
||||
g_micaMaterialData()->mutex.unlock();
|
||||
const QMutexLocker locker(&g_threadData()->mutex);
|
||||
if (g_threadData()->thread->isRunning()) {
|
||||
g_threadData()->thread->requestInterruption();
|
||||
g_threadData()->thread->quit();
|
||||
g_threadData()->thread->wait();
|
||||
}
|
||||
g_threadData()->thread->start(QThread::LowPriority);
|
||||
}
|
||||
|
||||
void MicaMaterialPrivate::updateMaterialBrush()
|
||||
|
@ -661,18 +709,21 @@ void MicaMaterialPrivate::paint(QPainter *painter, const QSize &size, const QPoi
|
|||
static constexpr const QPointF originPoint = {0, 0};
|
||||
QPointF correctedPos = pos;
|
||||
QSizeF correctedSize = size;
|
||||
if (!qFuzzyIsNull(transform.x) && (transform.x > qreal(0)) && !qFuzzyCompare(transform.x, qreal(1))) {
|
||||
correctedPos.setX(correctedPos.x() * transform.x);
|
||||
correctedSize.setWidth(correctedSize.width() * transform.x);
|
||||
if (!qFuzzyIsNull(transform.Horizontal) && (transform.Horizontal > qreal(0))
|
||||
&& !qFuzzyCompare(transform.Horizontal, qreal(1))) {
|
||||
correctedPos.setX(correctedPos.x() * transform.Horizontal);
|
||||
correctedSize.setWidth(correctedSize.width() * transform.Horizontal);
|
||||
}
|
||||
if (!qFuzzyIsNull(transform.y) && (transform.y > qreal(0)) && !qFuzzyCompare(transform.y, qreal(1))) {
|
||||
correctedPos.setY(correctedPos.y() * transform.y);
|
||||
correctedSize.setHeight(correctedSize.height() * transform.y);
|
||||
if (!qFuzzyIsNull(transform.Vertical) && (transform.Vertical > qreal(0))
|
||||
&& !qFuzzyCompare(transform.Vertical, qreal(1))) {
|
||||
correctedPos.setY(correctedPos.y() * transform.Vertical);
|
||||
correctedSize.setHeight(correctedSize.height() * transform.Vertical);
|
||||
}
|
||||
painter->save();
|
||||
painter->setRenderHints(QPainter::Antialiasing |
|
||||
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
if (active) {
|
||||
const QMutexLocker locker(&g_micaMaterialData()->mutex);
|
||||
painter->drawPixmap(originPoint, g_micaMaterialData()->blurredWallpaper, QRectF{correctedPos, correctedSize});
|
||||
}
|
||||
painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
|
@ -691,6 +742,20 @@ void MicaMaterialPrivate::paint(QPainter *painter, const QSize &size, const QPoi
|
|||
|
||||
void MicaMaterialPrivate::initialize()
|
||||
{
|
||||
g_threadData()->mutex.lock();
|
||||
if (!g_threadData()->thread) {
|
||||
g_threadData()->thread = std::make_unique<WallpaperThread>();
|
||||
qAddPostRoutine(threadCleaner);
|
||||
}
|
||||
connect(g_threadData()->thread.get(), &WallpaperThread::imageUpdated, this, [this](const Transform &t){
|
||||
transform = t;
|
||||
if (initialized) {
|
||||
Q_Q(MicaMaterial);
|
||||
Q_EMIT q->shouldRedraw();
|
||||
}
|
||||
});
|
||||
g_threadData()->mutex.unlock();
|
||||
|
||||
tintColor = kDefaultTransparentColor;
|
||||
tintOpacity = kDefaultTintOpacity;
|
||||
// Leave fallbackColor invalid, we need to use this state to judge
|
||||
|
@ -715,10 +780,13 @@ void MicaMaterialPrivate::initialize()
|
|||
|
||||
void MicaMaterialPrivate::prepareGraphicsResources()
|
||||
{
|
||||
g_micaMaterialData()->mutex.lock();
|
||||
if (g_micaMaterialData()->graphicsResourcesReady) {
|
||||
g_micaMaterialData()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
g_micaMaterialData()->graphicsResourcesReady = true;
|
||||
g_micaMaterialData()->mutex.unlock();
|
||||
maybeGenerateBlurredWallpaper();
|
||||
}
|
||||
|
||||
|
@ -839,3 +907,5 @@ void MicaMaterial::paint(QPainter *painter, const QSize &size, const QPoint &pos
|
|||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
||||
#include "micamaterial.moc"
|
||||
|
|
|
@ -91,7 +91,13 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
|
|||
return new FramelessQuickUtils;
|
||||
});
|
||||
qmlRegisterAnonymousType<QuickChromePalette>(QUICK_URI_SHORT);
|
||||
|
||||
#if (QT_VERSION <= QT_VERSION_CHECK(5, 16, 0))
|
||||
qRegisterMetaType<QuickGlobal::SystemTheme>("QuickGlobal::SystemTheme");
|
||||
qRegisterMetaType<QuickGlobal::SystemButtonType>("QuickGlobal::SystemButtonType");
|
||||
qRegisterMetaType<QuickGlobal::ButtonState>("QuickGlobal::ButtonState");
|
||||
qRegisterMetaType<QuickGlobal::BlurMode>("QuickGlobal::BlurMode");
|
||||
qRegisterMetaType<QuickGlobal::WindowEdge>("QuickGlobal::WindowEdge");
|
||||
#endif
|
||||
qmlRegisterType<FramelessQuickHelper>(QUICK_URI_EXPAND("FramelessHelper"));
|
||||
qmlRegisterType<QuickMicaMaterial>(QUICK_URI_EXPAND("MicaMaterial"));
|
||||
qmlRegisterType<QuickImageItem>(QUICK_URI_EXPAND("ImageItem"));
|
||||
|
|
|
@ -90,7 +90,16 @@ WallpaperImageNode::WallpaperImageNode(QuickMicaMaterial *item)
|
|||
initialize();
|
||||
}
|
||||
|
||||
WallpaperImageNode::~WallpaperImageNode() = default;
|
||||
WallpaperImageNode::~WallpaperImageNode(){
|
||||
if (m_texture) {
|
||||
delete m_texture;
|
||||
m_texture = nullptr;
|
||||
}
|
||||
if (m_node) {
|
||||
delete m_node;
|
||||
m_node = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
void WallpaperImageNode::initialize()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue