fix various issues

1. Fix mica material doesn't work normally when used on multiple windows.
2. Fix build on Qt5.

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-10-12 14:08:26 +08:00
parent 994b02ad6c
commit f15ca8daf0
19 changed files with 206 additions and 75 deletions

View File

@ -37,7 +37,7 @@ int main(int argc, char *argv[])
// of any Q(Core|Gui)Application instances.
FramelessHelper::Widgets::initialize();
QApplication application(argc, argv);
const QScopedPointer<QApplication> application(new QApplication(argc, argv));
// Must be called after QGuiApplication has been constructed, we are using
// some private functions from QPA which won't be available until there's
@ -48,8 +48,8 @@ int main(int argc, char *argv[])
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
Dialog dialog;
dialog.show();
const QScopedPointer<Dialog> dialog(new Dialog);
dialog->show();
const int exec = QCoreApplication::exec();

View File

@ -37,7 +37,7 @@ int main(int argc, char *argv[])
// of any Q(Core|Gui)Application instances.
FramelessHelper::Widgets::initialize();
QApplication application(argc, argv);
const QScopedPointer<QApplication> application(new QApplication(argc, argv));
// Must be called after QGuiApplication has been constructed, we are using
// some private functions from QPA which won't be available until there's
@ -48,8 +48,8 @@ int main(int argc, char *argv[])
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
MainWindow mainWindow;
mainWindow.show();
const QScopedPointer<MainWindow> mainWindow(new MainWindow);
mainWindow->show();
const int exec = QCoreApplication::exec();

View File

@ -74,7 +74,7 @@ int main(int argc, char *argv[])
// of any Q(Core|Gui)Application instances.
FramelessHelper::Widgets::initialize();
QApplication application(argc, argv);
const QScopedPointer<QApplication> application(new QApplication(argc, argv));
// Must be called after QGuiApplication has been constructed, we are using
// some private functions from QPA which won't be available until there's
@ -100,8 +100,8 @@ int main(int argc, char *argv[])
QSurfaceFormat::setDefaultFormat(fmt);
MainWindow mainWindow;
mainWindow.show();
const QScopedPointer<MainWindow> mainWindow(new MainWindow);
mainWindow->show();
const int exec = QCoreApplication::exec();

View File

@ -0,0 +1,108 @@
/*
* MIT License
*
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import QtQuick
import QtQuick.Controls.Basic
import org.wangwenx190.FramelessHelper
import Demo
FramelessApplicationWindow {
id: window
objectName: "applicationWindow"
visible: false // Hide the window before we sets up it's correct size and position.
width: 800
height: 600
title: qsTr("FramelessHelper demo application - Qt Quick")
color: {
if (FramelessHelper.blurBehindWindowEnabled) {
return "transparent";
}
if (FramelessUtils.systemTheme === FramelessHelperConstants.Dark) {
return FramelessUtils.defaultSystemDarkColor;
}
return FramelessUtils.defaultSystemLightColor;
}
onClosing: Settings.saveGeometry(window)
FramelessHelper.onReady: {
// Let FramelessHelper know what's our homemade title bar, otherwise
// our window won't be draggable.
FramelessHelper.titleBarItem = titleBar;
// Make our own items visible to the hit test and on Windows, enable
// the snap layout feature (available since Windows 11).
FramelessHelper.setSystemButton(titleBar.minimizeButton, FramelessHelperConstants.Minimize);
FramelessHelper.setSystemButton(titleBar.maximizeButton, FramelessHelperConstants.Maximize);
FramelessHelper.setSystemButton(titleBar.closeButton, FramelessHelperConstants.Close);
if (!Settings.restoreGeometry(window)) {
FramelessHelper.moveWindowToDesktopCenter();
}
// Finally, show the window after everything is setted.
window.visible = true;
}
Shortcut {
sequences: [ StandardKey.Cancel, StandardKey.Close, StandardKey.Quit ]
onActivated: {
if (window.visibility === Window.FullScreen) {
window.toggleFullScreen();
} else {
window.close();
}
}
}
Shortcut {
sequences: [ StandardKey.FullScreen, "ALT+RETURN" ]
onActivated: window.toggleFullScreen()
}
Timer {
interval: 500
running: true
repeat: true
onTriggered: timeLabel.text = Qt.formatTime(new Date(), "hh:mm:ss")
}
Label {
id: timeLabel
anchors.centerIn: parent
font {
pointSize: 70
bold: true
}
color: (FramelessUtils.systemTheme === FramelessHelperConstants.Dark) ? Qt.color("white") : Qt.color("black")
}
StandardTitleBar {
id: titleBar
anchors {
top: parent.top
topMargin: window.visibility === Window.Windowed ? 1 : 0
left: parent.left
right: parent.right
}
windowIcon: "qrc:///Demo/images/microsoft.svg"
windowIconVisible: true
}
}

View File

@ -53,7 +53,9 @@ if(${QT_VERSION} VERSION_GREATER_EQUAL 6.2)
QtQuick.Controls.Basic/auto
org.wangwenx190.FramelessHelper/auto
QML_FILES
MainWindow.qml
Window.qml
ApplicationWindow.qml
HomePage.qml
#ENABLE_TYPE_COMPILER # We can't use it for now due to it still can't compile singletons.
# There's some hope to get it supported in Qt 6.5.
)

View File

@ -0,0 +1,35 @@
/*
* MIT License
*
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import QtQml
QtObject {
property Window window: Window{}
property ApplicationWindow applicationWindow: ApplicationWindow{}
Component.onCompleted: {
window.show();
applicationWindow.show();
}
}

View File

@ -28,18 +28,8 @@ import org.wangwenx190.FramelessHelper
import Demo
FramelessWindow {
property int __savedWindowState: Window.Windowed
function toggleFullScreen() {
if (window.visibility === Window.FullScreen) {
window.visibility = window.__savedWindowState;
} else {
window.__savedWindowState = window.visibility;
window.showFullScreen();
}
}
id: window
objectName: "window"
visible: false // Hide the window before we sets up it's correct size and position.
width: 800
height: 600

View File

@ -36,7 +36,7 @@
#include <clocale>
#include "settings.h"
#if QMLTC_ENABLED
# include <mainwindow.h>
# include <homepage.h>
#endif
FRAMELESSHELPER_USE_NAMESPACE
@ -49,7 +49,7 @@ int main(int argc, char *argv[])
// of any Q(Core|Gui)Application instances.
FramelessHelper::Quick::initialize();
QGuiApplication application(argc, argv);
const QScopedPointer<QGuiApplication> application(new QGuiApplication(argc, argv));
// Must be called after QGuiApplication has been constructed, we are using
// some private functions from QPA which won't be available until there's
@ -80,14 +80,14 @@ int main(int argc, char *argv[])
#endif
}
QQmlApplicationEngine engine;
const QScopedPointer<QQmlApplicationEngine> engine(new QQmlApplicationEngine);
#if (!QMLTC_ENABLED && !defined(QUICK_USE_QMAKE))
engine.addImportPath(FRAMELESSHELPER_STRING_LITERAL("../imports"));
engine->addImportPath(FRAMELESSHELPER_STRING_LITERAL("../imports"));
#endif
#if (((QT_VERSION < QT_VERSION_CHECK(6, 2, 0)) || defined(QUICK_USE_QMAKE)) && !QMLTC_ENABLED)
// Don't forget to register our own custom QML types!
FramelessHelper::Quick::registerTypes(&engine);
FramelessHelper::Quick::registerTypes(engine.data());
qmlRegisterSingletonType<Settings>("Demo", 1, 0, "Settings",
[](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
@ -110,18 +110,18 @@ int main(int argc, char *argv[])
#endif
#if !QMLTC_ENABLED
const QUrl mainUrl(FRAMELESSHELPER_STRING_LITERAL("qrc:///Demo/MainWindow.qml"));
const QUrl mainUrl(FRAMELESSHELPER_STRING_LITERAL("qrc:///Demo/HomePage.qml"));
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0))
QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, &application,
QObject::connect(engine.data(), &QQmlApplicationEngine::objectCreationFailed, qApp,
[](const QUrl &url){
qCritical() << "The QML engine failed to create component:" << url;
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
#elif !QMLTC_ENABLED
const QMetaObject::Connection connection = QObject::connect(
&engine, &QQmlApplicationEngine::objectCreated, &application,
engine.data(), &QQmlApplicationEngine::objectCreated, &application,
[&mainUrl, &connection](QObject *object, const QUrl &url) {
if (url != mainUrl) {
return;
@ -135,12 +135,12 @@ int main(int argc, char *argv[])
#endif
#if !QMLTC_ENABLED
engine.load(mainUrl);
engine->load(mainUrl);
#endif
#if QMLTC_ENABLED
QScopedPointer<MainWindow> mainWindow(new MainWindow(&engine));
mainWindow->show();
QScopedPointer<HomePage> homePage(new HomePage(engine.data()));
homePage->show();
#endif
const int exec = QCoreApplication::exec();

View File

@ -1,6 +1,8 @@
<RCC>
<qresource prefix="/Demo">
<file>images/microsoft.svg</file>
<file>MainWindow.qml</file>
<file>Window.qml</file>
<file>ApplicationWindow.qml</file>
<file>HomePage.qml</file>
</qresource>
</RCC>

View File

@ -29,7 +29,7 @@
#include <QtCore/qdir.h>
#include <QtCore/qdatastream.h>
FRAMELESSHELPER_STRING_CONSTANT2(IniKeyPath, "Window/Geometry")
FRAMELESSHELPER_STRING_CONSTANT2(IniKeyPathTemplate, "%1/Geometry")
Settings::Settings(QObject *parent) : QObject(parent)
{
@ -51,7 +51,7 @@ void Settings::saveGeometry(QWindow *window)
QDataStream stream(&data, QDataStream::WriteOnly);
stream.setVersion(QDataStream::Qt_5_6);
stream << window->geometry();
m_settings->setValue(kIniKeyPath, data);
m_settings->setValue(kIniKeyPathTemplate.arg(window->objectName()), data);
}
bool Settings::restoreGeometry(QWindow *window)
@ -60,7 +60,7 @@ bool Settings::restoreGeometry(QWindow *window)
if (!window) {
return false;
}
const QByteArray data = m_settings->value(kIniKeyPath).toByteArray();
const QByteArray data = m_settings->value(kIniKeyPathTemplate.arg(window->objectName())).toByteArray();
if (data.isEmpty()) {
return false;
}

View File

@ -37,7 +37,7 @@ int main(int argc, char *argv[])
// of any Q(Core|Gui)Application instances.
FramelessHelper::Widgets::initialize();
QApplication application(argc, argv);
const QScopedPointer<QApplication> application(new QApplication(argc, argv));
// Must be called after QGuiApplication has been constructed, we are using
// some private functions from QPA which won't be available until there's
@ -48,8 +48,13 @@ int main(int argc, char *argv[])
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
Widget widget;
widget.show();
const QScopedPointer<Widget> window1(new Widget);
window1->setObjectName(FRAMELESSHELPER_STRING_LITERAL("window1"));
window1->show();
const QScopedPointer<Widget> window2(new Widget);
window2->setObjectName(FRAMELESSHELPER_STRING_LITERAL("window2"));
window2->show();
const int exec = QCoreApplication::exec();

View File

@ -46,7 +46,7 @@ FRAMELESSHELPER_USE_NAMESPACE
using namespace Global;
FRAMELESSHELPER_STRING_CONSTANT2(IniKeyPath, "Window/Geometry")
FRAMELESSHELPER_STRING_CONSTANT2(IniKeyPathTemplate, "%1/Geometry")
[[nodiscard]] static inline QSettings *appConfigFile()
{
@ -77,7 +77,7 @@ void Widget::timerEvent(QTimerEvent *event)
void Widget::closeEvent(QCloseEvent *event)
{
const QScopedPointer<QSettings> settings(appConfigFile());
settings->setValue(kIniKeyPath, saveGeometry());
settings->setValue(kIniKeyPathTemplate.arg(objectName()), saveGeometry());
FramelessWidget::closeEvent(event);
}
@ -135,7 +135,7 @@ void Widget::initialize()
helper->setSystemButton(m_titleBar->closeButton(), SystemButtonType::Close);
connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper](){
const QScopedPointer<QSettings> settings(appConfigFile());
const QByteArray data = settings->value(kIniKeyPath).toByteArray();
const QByteArray data = settings->value(kIniKeyPathTemplate.arg(objectName())).toByteArray();
if (data.isEmpty()) {
helper->moveWindowToDesktopCenter();
} else {

View File

@ -57,7 +57,6 @@ public:
public Q_SLOTS:
void paint(QPainter *painter, const QSize &size, const QPoint &pos);
Q_NODISCARD static MicaMaterial *findOrCreateMicaMaterial(QObject *target);
Q_SIGNALS:
void tintColorChanged();

View File

@ -47,7 +47,6 @@ public Q_SLOTS:
void maybeGenerateBlurredWallpaper(const bool force = false);
void updateMaterialBrush();
void paint(QPainter *painter, const QSize &size, const QPoint &pos);
Q_NODISCARD static MicaMaterial *findOrCreateMicaMaterial(QObject *target);
private:
void initialize();
@ -59,6 +58,7 @@ private:
qreal tintOpacity = 0.0;
qreal noiseOpacity = 0.0;
QBrush micaBrush = {};
bool initialized = false;
};
FRAMELESSHELPER_END_NAMESPACE

View File

@ -79,7 +79,7 @@ private:
QPointer<QScreen> m_screen = nullptr;
#endif
bool m_micaEnabled = false;
QPointer<MicaMaterial> m_micaMaterial;
QScopedPointer<MicaMaterial> m_micaMaterial;
QMetaObject::Connection m_micaRedrawConnection = {};
qreal m_screenDpr = 0.0;
QMetaObject::Connection m_screenDpiChangeConnection = {};

View File

@ -569,8 +569,10 @@ void MicaMaterialPrivate::updateMaterialBrush()
painter.setOpacity(noiseOpacity);
painter.fillRect(rect, QBrush(noiseTexture));
micaBrush = QBrush(micaTexture);
Q_Q(MicaMaterial);
Q_EMIT q->shouldRedraw();
if (initialized) {
Q_Q(MicaMaterial);
Q_EMIT q->shouldRedraw();
}
}
void MicaMaterialPrivate::paint(QPainter *painter, const QSize &size, const QPoint &pos)
@ -593,24 +595,14 @@ void MicaMaterialPrivate::paint(QPainter *painter, const QSize &size, const QPoi
painter->restore();
}
MicaMaterial *MicaMaterialPrivate::findOrCreateMicaMaterial(QObject *target)
{
Q_ASSERT(target);
if (!target) {
return nullptr;
}
if (const auto instance = target->findChild<MicaMaterial *>()) {
return instance;
}
return new MicaMaterial(target);
}
void MicaMaterialPrivate::initialize()
{
tintColor = kDefaultTransparentColor;
tintOpacity = kDefaultTintOpacity;
noiseOpacity = kDefaultNoiseOpacity;
updateMaterialBrush();
connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged,
this, &MicaMaterialPrivate::updateMaterialBrush);
connect(FramelessManager::instance(), &FramelessManager::wallpaperChanged,
@ -621,6 +613,8 @@ void MicaMaterialPrivate::initialize()
if (FramelessConfig::instance()->isSet(Option::DisableLazyInitializationForMicaMaterial)) {
prepareGraphicsResources();
}
initialized = true;
}
void MicaMaterialPrivate::prepareGraphicsResources()
@ -633,7 +627,6 @@ void MicaMaterialPrivate::prepareGraphicsResources()
g_micaMaterialData()->graphicsResourcesReady = true;
g_micaMaterialData()->mutex.unlock();
maybeGenerateBlurredWallpaper();
updateMaterialBrush();
}
MicaMaterial::MicaMaterial(QObject *parent)
@ -707,9 +700,4 @@ void MicaMaterial::paint(QPainter *painter, const QSize &size, const QPoint &pos
d->paint(painter, size, pos);
}
MicaMaterial *MicaMaterial::findOrCreateMicaMaterial(QObject *target)
{
return MicaMaterialPrivate::findOrCreateMicaMaterial(target);
}
FRAMELESSHELPER_END_NAMESPACE

View File

@ -30,8 +30,8 @@
#include "quickimageitem.h"
#include "quickwindowborder.h"
#include "framelessquickwindow_p.h"
#include "framelessquickapplicationwindow_p.h"
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
# include "framelessquickapplicationwindow_p.h"
# include "quickstandardsystembutton_p.h"
# include "quickstandardtitlebar_p.h"
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
@ -87,15 +87,17 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
qmlRegisterType<FramelessQuickHelper>(QUICK_URI_EXPAND("FramelessHelper"));
qmlRegisterType<FramelessQuickWindow>(QUICK_URI_EXPAND("FramelessWindow"));
qmlRegisterType<FramelessQuickApplicationWindow>(QUICK_URI_EXPAND("FramelessApplicationWindow"));
qmlRegisterType<QuickMicaMaterial>(QUICK_URI_EXPAND("MicaMaterial"));
qmlRegisterType<QuickImageItem>(QUICK_URI_EXPAND("ImageItem"));
qmlRegisterType<QuickWindowBorder>(QUICK_URI_EXPAND("WindowBorder"));
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
qmlRegisterType<FramelessQuickApplicationWindow>(QUICK_URI_EXPAND("FramelessApplicationWindow"));
qmlRegisterType<QuickStandardSystemButton>(QUICK_URI_EXPAND("StandardSystemButton"));
qmlRegisterType<QuickStandardTitleBar>(QUICK_URI_EXPAND("StandardTitleBar"));
#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
#else // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
qmlRegisterTypeNotAvailable(QUICK_URI_EXPAND("FramelessApplicationWindow"),
FRAMELESSHELPER_STRING_LITERAL("FramelessApplicationWindow is not available until Qt6."));
qmlRegisterTypeNotAvailable(QUICK_URI_EXPAND("StandardSystemButton"),
FRAMELESSHELPER_STRING_LITERAL("StandardSystemButton is not available until Qt6."));
qmlRegisterTypeNotAvailable(QUICK_URI_EXPAND("StandardTitleBar"),

View File

@ -71,7 +71,7 @@ private:
QPointer<QuickMicaMaterial> m_item = nullptr;
QSGSimpleTextureNode *m_node = nullptr;
QPixmap m_pixmapCache = {};
QPointer<MicaMaterial> m_micaMaterial = nullptr;
QScopedPointer<MicaMaterial> m_micaMaterial;
};
WallpaperImageNode::WallpaperImageNode(QuickMicaMaterial *item)
@ -91,7 +91,7 @@ void WallpaperImageNode::initialize()
g_data()->mutex.lock();
QQuickWindow * const window = m_item->window();
m_micaMaterial = MicaMaterial::findOrCreateMicaMaterial(window);
m_micaMaterial.reset(new MicaMaterial);
m_node = new QSGSimpleTextureNode;
m_node->setFiltering(QSGTexture::Linear);
@ -103,7 +103,7 @@ void WallpaperImageNode::initialize()
appendChildNode(m_node);
connect(m_micaMaterial, &MicaMaterial::shouldRedraw, this, [this](){
connect(m_micaMaterial.data(), &MicaMaterial::shouldRedraw, this, [this](){
maybeGenerateWallpaperImageCache(true);
});
connect(window, &QQuickWindow::beforeRendering, this,

View File

@ -74,12 +74,12 @@ void WidgetsSharedHelper::setup(QWidget *widget)
m_targetWidget->update();
}
});
m_micaMaterial = MicaMaterial::findOrCreateMicaMaterial(m_targetWidget);
m_micaMaterial.reset(new MicaMaterial);
if (m_micaRedrawConnection) {
disconnect(m_micaRedrawConnection);
m_micaRedrawConnection = {};
}
m_micaRedrawConnection = connect(m_micaMaterial, &MicaMaterial::shouldRedraw,
m_micaRedrawConnection = connect(m_micaMaterial.data(), &MicaMaterial::shouldRedraw,
this, [this](){
if (m_targetWidget) {
m_targetWidget->update();
@ -253,8 +253,8 @@ void WidgetsSharedHelper::handleScreenChanged(QScreen *screen)
return;
}
m_screenDpr = currentDpr;
if (m_micaEnabled && m_micaMaterial) {
MicaMaterialPrivate::get(m_micaMaterial)->maybeGenerateBlurredWallpaper(true);
if (m_micaEnabled && !m_micaMaterial.isNull()) {
MicaMaterialPrivate::get(m_micaMaterial.data())->maybeGenerateBlurredWallpaper(true);
}
});
}