From 598de50290203058eb6051e1e8e1c8dc99582cf9 Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <2546789017@qq.com> Date: Fri, 24 Feb 2023 13:13:01 +0800 Subject: [PATCH] add synchronize api to wait for the ready signal Signed-off-by: Yuhang Zhao <2546789017@qq.com> --- examples/dialog/dialog.cpp | 28 ++++++++------ examples/dialog/dialog.h | 2 + examples/dialog/main.cpp | 1 + examples/mainwindow/main.cpp | 1 + examples/mainwindow/mainwindow.cpp | 38 +++++++++++-------- examples/mainwindow/mainwindow.h | 2 + examples/openglwidget/main.cpp | 1 + examples/openglwidget/mainwindow.cpp | 28 ++++++++------ examples/openglwidget/mainwindow.h | 2 + examples/quick/qml/ApplicationWindow.qml | 2 +- examples/quick/qml/Window.qml | 2 +- examples/widget/main.cpp | 2 + examples/widget/widget.cpp | 37 +++++++++++------- examples/widget/widget.h | 2 + .../Quick/framelessquickhelper.h | 3 ++ .../Quick/private/framelessquickhelper_p.h | 4 ++ .../Widgets/framelesswidgetshelper.h | 3 ++ .../private/framelesswidgetshelper_p.h | 4 ++ src/quick/framelessquickhelper.cpp | 38 +++++++++++++++++++ src/widgets/framelesswidgetshelper.cpp | 38 +++++++++++++++++++ 20 files changed, 183 insertions(+), 55 deletions(-) diff --git a/examples/dialog/dialog.cpp b/examples/dialog/dialog.cpp index c006882..6c600ca 100644 --- a/examples/dialog/dialog.cpp +++ b/examples/dialog/dialog.cpp @@ -136,16 +136,20 @@ void Dialog::setupUi() // programatically, but we also want the user not able to resize the window manually. // So apparently we can't use QWidget::setFixedWidth/Height/Size() here. FramelessWidgetsHelperPrivate::get(helper)->setProperty(kDontOverrideCursorVar, true); - connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper](){ - const auto savedGeometry = Settings::get({}, kGeometry); - if (savedGeometry.isValid() && !parent()) { - const auto savedDpr = Settings::get({}, kDevicePixelRatio); - // Qt doesn't support dpr < 1. - const qreal oldDpr = std::max(savedDpr, qreal(1)); - const qreal scale = (devicePixelRatioF() / oldDpr); - setGeometry({savedGeometry.topLeft() * scale, savedGeometry.size() * scale}); - } else { - helper->moveWindowToDesktopCenter(); - } - }); +} + +void Dialog::waitReady() +{ + FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this); + helper->waitForReady(); + const auto savedGeometry = Settings::get({}, kGeometry); + if (savedGeometry.isValid() && !parent()) { + const auto savedDpr = Settings::get({}, kDevicePixelRatio); + // Qt doesn't support dpr < 1. + const qreal oldDpr = std::max(savedDpr, qreal(1)); + const qreal scale = (devicePixelRatioF() / oldDpr); + setGeometry({savedGeometry.topLeft() * scale, savedGeometry.size() * scale}); + } else { + helper->moveWindowToDesktopCenter(); + } } diff --git a/examples/dialog/dialog.h b/examples/dialog/dialog.h index 651d2e9..7b28cda 100644 --- a/examples/dialog/dialog.h +++ b/examples/dialog/dialog.h @@ -27,6 +27,8 @@ public: explicit Dialog(QWidget *parent = nullptr); ~Dialog() override; + void waitReady(); + protected: void closeEvent(QCloseEvent *event) override; diff --git a/examples/dialog/main.cpp b/examples/dialog/main.cpp index 033dfe4..df2c996 100644 --- a/examples/dialog/main.cpp +++ b/examples/dialog/main.cpp @@ -54,6 +54,7 @@ int main(int argc, char *argv[]) FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial); const auto dialog = std::make_unique(); + dialog->waitReady(); dialog->show(); return QCoreApplication::exec(); diff --git a/examples/mainwindow/main.cpp b/examples/mainwindow/main.cpp index 0da082b..a427d1f 100644 --- a/examples/mainwindow/main.cpp +++ b/examples/mainwindow/main.cpp @@ -54,6 +54,7 @@ int main(int argc, char *argv[]) FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial); const auto mainWindow = std::make_unique(); + mainWindow->waitReady(); mainWindow->show(); return QCoreApplication::exec(); diff --git a/examples/mainwindow/mainwindow.cpp b/examples/mainwindow/mainwindow.cpp index 537f0f5..5a5e490 100644 --- a/examples/mainwindow/mainwindow.cpp +++ b/examples/mainwindow/mainwindow.cpp @@ -107,33 +107,39 @@ QMenuBar::item:pressed { helper->setSystemButton(m_titleBar->closeButton(), SystemButtonType::Close); #endif // Q_OS_MACOS helper->setHitTestVisible(mb); // IMPORTANT! - connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper](){ - const auto savedGeometry = Settings::get({}, kGeometry); - if (savedGeometry.isValid() && !parent()) { - const auto savedDpr = Settings::get({}, kDevicePixelRatio); - // Qt doesn't support dpr < 1. - const qreal oldDpr = std::max(savedDpr, qreal(1)); - const qreal scale = (devicePixelRatioF() / oldDpr); - setGeometry({savedGeometry.topLeft() * scale, savedGeometry.size() * scale}); - } else { - helper->moveWindowToDesktopCenter(); - } - const QByteArray savedState = Settings::get({}, kState); - if (!savedState.isEmpty() && !parent()) { - restoreState(savedState); - } - }); setWindowTitle(tr("FramelessHelper demo application - Qt MainWindow")); setWindowIcon(QFileIconProvider().icon(QFileIconProvider::Computer)); connect(m_mainWindow->pushButton, &QPushButton::clicked, this, [this]{ const auto dialog = new Dialog(this); + dialog->waitReady(); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->exec(); }); connect(m_mainWindow->pushButton_2, &QPushButton::clicked, this, [this]{ const auto widget = new Widget(this); + widget->waitReady(); widget->setAttribute(Qt::WA_DeleteOnClose); widget->show(); }); } + +void MainWindow::waitReady() +{ + FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this); + helper->waitForReady(); + const auto savedGeometry = Settings::get({}, kGeometry); + if (savedGeometry.isValid() && !parent()) { + const auto savedDpr = Settings::get({}, kDevicePixelRatio); + // Qt doesn't support dpr < 1. + const qreal oldDpr = std::max(savedDpr, qreal(1)); + const qreal scale = (devicePixelRatioF() / oldDpr); + setGeometry({savedGeometry.topLeft() * scale, savedGeometry.size() * scale}); + } else { + helper->moveWindowToDesktopCenter(); + } + const QByteArray savedState = Settings::get({}, kState); + if (!savedState.isEmpty() && !parent()) { + restoreState(savedState); + } +} diff --git a/examples/mainwindow/mainwindow.h b/examples/mainwindow/mainwindow.h index 10e99c5..56c8590 100644 --- a/examples/mainwindow/mainwindow.h +++ b/examples/mainwindow/mainwindow.h @@ -44,6 +44,8 @@ public: explicit MainWindow(QWidget *parent = nullptr, const Qt::WindowFlags flags = {}); ~MainWindow() override; + void waitReady(); + protected: void closeEvent(QCloseEvent *event) override; diff --git a/examples/openglwidget/main.cpp b/examples/openglwidget/main.cpp index d7a97f2..8f6bef6 100644 --- a/examples/openglwidget/main.cpp +++ b/examples/openglwidget/main.cpp @@ -103,6 +103,7 @@ int main(int argc, char *argv[]) QSurfaceFormat::setDefaultFormat(fmt); const auto mainWindow = std::make_unique(); + mainWindow->waitReady(); mainWindow->show(); return QCoreApplication::exec(); diff --git a/examples/openglwidget/mainwindow.cpp b/examples/openglwidget/mainwindow.cpp index dd274f4..87a1365 100644 --- a/examples/openglwidget/mainwindow.cpp +++ b/examples/openglwidget/mainwindow.cpp @@ -82,16 +82,20 @@ void MainWindow::initialize() helper->setSystemButton(m_titleBar->maximizeButton(), SystemButtonType::Maximize); helper->setSystemButton(m_titleBar->closeButton(), SystemButtonType::Close); #endif // Q_OS_MACOS - connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper](){ - const auto savedGeometry = Settings::get({}, kGeometry); - if (savedGeometry.isValid() && !parent()) { - const auto savedDpr = Settings::get({}, kDevicePixelRatio); - // Qt doesn't support dpr < 1. - const qreal oldDpr = std::max(savedDpr, qreal(1)); - const qreal scale = (devicePixelRatioF() / oldDpr); - setGeometry({savedGeometry.topLeft() * scale, savedGeometry.size() * scale}); - } else { - helper->moveWindowToDesktopCenter(); - } - }); +} + +void MainWindow::waitReady() +{ + FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this); + helper->waitForReady(); + const auto savedGeometry = Settings::get({}, kGeometry); + if (savedGeometry.isValid() && !parent()) { + const auto savedDpr = Settings::get({}, kDevicePixelRatio); + // Qt doesn't support dpr < 1. + const qreal oldDpr = std::max(savedDpr, qreal(1)); + const qreal scale = (devicePixelRatioF() / oldDpr); + setGeometry({savedGeometry.topLeft() * scale, savedGeometry.size() * scale}); + } else { + helper->moveWindowToDesktopCenter(); + } } diff --git a/examples/openglwidget/mainwindow.h b/examples/openglwidget/mainwindow.h index 6a0d2ee..b52c4e4 100644 --- a/examples/openglwidget/mainwindow.h +++ b/examples/openglwidget/mainwindow.h @@ -41,6 +41,8 @@ public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow() override; + void waitReady(); + protected: void closeEvent(QCloseEvent *event) override; diff --git a/examples/quick/qml/ApplicationWindow.qml b/examples/quick/qml/ApplicationWindow.qml index 4eed4cd..e60c0d1 100644 --- a/examples/quick/qml/ApplicationWindow.qml +++ b/examples/quick/qml/ApplicationWindow.qml @@ -33,7 +33,7 @@ FramelessApplicationWindow { 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") + title: qsTr("FramelessHelper demo application - Qt Quick [") + objectName + ']' color: { if (FramelessHelper.blurBehindWindowEnabled) { return "transparent"; diff --git a/examples/quick/qml/Window.qml b/examples/quick/qml/Window.qml index 1bf98b3..2de8087 100644 --- a/examples/quick/qml/Window.qml +++ b/examples/quick/qml/Window.qml @@ -33,7 +33,7 @@ FramelessWindow { 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") + title: qsTr("FramelessHelper demo application - Qt Quick [") + objectName +']' color: { if (FramelessHelper.blurBehindWindowEnabled) { return "transparent"; diff --git a/examples/widget/main.cpp b/examples/widget/main.cpp index 3d8c199..bf0f070 100644 --- a/examples/widget/main.cpp +++ b/examples/widget/main.cpp @@ -55,10 +55,12 @@ int main(int argc, char *argv[]) const auto window1 = std::make_unique(); window1->setObjectName(FRAMELESSHELPER_STRING_LITERAL("window1")); + window1->waitReady(); window1->show(); const auto window2 = std::make_unique(); window2->setObjectName(FRAMELESSHELPER_STRING_LITERAL("window2")); + window2->waitReady(); window2->show(); return QCoreApplication::exec(); diff --git a/examples/widget/widget.cpp b/examples/widget/widget.cpp index fdf374a..a6d80d8 100644 --- a/examples/widget/widget.cpp +++ b/examples/widget/widget.cpp @@ -126,6 +126,13 @@ void Widget::initialize() } }); + connect(this, &Widget::objectNameChanged, this, [this](const QString &name){ + if (name.isEmpty()) { + return; + } + setWindowTitle(windowTitle() + FRAMELESSHELPER_STRING_LITERAL(" [%1]").arg(name)); + }); + FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this); helper->setTitleBarWidget(m_titleBar); #ifndef Q_OS_MACOS @@ -133,19 +140,6 @@ void Widget::initialize() helper->setSystemButton(m_titleBar->maximizeButton(), SystemButtonType::Maximize); helper->setSystemButton(m_titleBar->closeButton(), SystemButtonType::Close); #endif // Q_OS_MACOS - connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper](){ - const QString objName = objectName(); - const auto savedGeometry = Settings::get(objName, kGeometry); - if (savedGeometry.isValid() && !parent()) { - const auto savedDpr = Settings::get(objName, kDevicePixelRatio); - // Qt doesn't support dpr < 1. - const qreal oldDpr = std::max(savedDpr, qreal(1)); - const qreal scale = (devicePixelRatioF() / oldDpr); - setGeometry({savedGeometry.topLeft() * scale, savedGeometry.size() * scale}); - } else { - helper->moveWindowToDesktopCenter(); - } - }); } void Widget::updateStyleSheet() @@ -162,3 +156,20 @@ void Widget::updateStyleSheet() } update(); } + +void Widget::waitReady() +{ + FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this); + helper->waitForReady(); + const QString objName = objectName(); + const auto savedGeometry = Settings::get(objName, kGeometry); + if (savedGeometry.isValid() && !parent()) { + const auto savedDpr = Settings::get(objName, kDevicePixelRatio); + // Qt doesn't support dpr < 1. + const qreal oldDpr = std::max(savedDpr, qreal(1)); + const qreal scale = (devicePixelRatioF() / oldDpr); + setGeometry({savedGeometry.topLeft() * scale, savedGeometry.size() * scale}); + } else { + helper->moveWindowToDesktopCenter(); + } +} diff --git a/examples/widget/widget.h b/examples/widget/widget.h index 1c984e0..4acd171 100644 --- a/examples/widget/widget.h +++ b/examples/widget/widget.h @@ -44,6 +44,8 @@ public: explicit Widget(QWidget *parent = nullptr); ~Widget() override; + void waitReady(); + protected: void timerEvent(QTimerEvent *event) override; void closeEvent(QCloseEvent *event) override; diff --git a/include/FramelessHelper/Quick/framelessquickhelper.h b/include/FramelessHelper/Quick/framelessquickhelper.h index f1fca8f..8ee1b48 100644 --- a/include/FramelessHelper/Quick/framelessquickhelper.h +++ b/include/FramelessHelper/Quick/framelessquickhelper.h @@ -66,6 +66,9 @@ public: Q_NODISCARD QuickMicaMaterial *micaMaterial() const; Q_NODISCARD QuickWindowBorder *windowBorder() const; + Q_NODISCARD bool isReady() const; + void waitForReady(); + public Q_SLOTS: void extendsContentIntoTitleBar(const bool value = true); diff --git a/include/FramelessHelper/Quick/private/framelessquickhelper_p.h b/include/FramelessHelper/Quick/private/framelessquickhelper_p.h index 039acb9..c60b39a 100644 --- a/include/FramelessHelper/Quick/private/framelessquickhelper_p.h +++ b/include/FramelessHelper/Quick/private/framelessquickhelper_p.h @@ -85,6 +85,9 @@ public: Q_NODISCARD static FramelessQuickHelper *findOrCreateFramelessHelper(QObject *object); + Q_NODISCARD bool isReady() const; + void waitForReady(); + private: Q_NODISCARD QRect mapItemGeometryToScene(const QQuickItem * const item) const; Q_NODISCARD bool isInSystemButtons(const QPoint &pos, QuickGlobal::SystemButtonType *button) const; @@ -101,6 +104,7 @@ private: bool m_blurBehindWindowEnabled = false; std::optional m_extendIntoTitleBar = std::nullopt; bool m_destroying = false; + bool m_qpaReady = false; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/include/FramelessHelper/Widgets/framelesswidgetshelper.h b/include/FramelessHelper/Widgets/framelesswidgetshelper.h index 48d23dd..aaa9bd8 100644 --- a/include/FramelessHelper/Widgets/framelesswidgetshelper.h +++ b/include/FramelessHelper/Widgets/framelesswidgetshelper.h @@ -59,6 +59,9 @@ public: Q_NODISCARD MicaMaterial *micaMaterial() const; Q_NODISCARD WindowBorderPainter *windowBorder() const; + Q_NODISCARD bool isReady() const; + void waitForReady(); + public Q_SLOTS: void extendsContentIntoTitleBar(const bool value = true); diff --git a/include/FramelessHelper/Widgets/private/framelesswidgetshelper_p.h b/include/FramelessHelper/Widgets/private/framelesswidgetshelper_p.h index 4421561..511fca8 100644 --- a/include/FramelessHelper/Widgets/private/framelesswidgetshelper_p.h +++ b/include/FramelessHelper/Widgets/private/framelesswidgetshelper_p.h @@ -86,6 +86,9 @@ public: Q_NODISCARD static WidgetsSharedHelper *findOrCreateSharedHelper(QWidget *window); Q_NODISCARD static FramelessWidgetsHelper *findOrCreateFramelessHelper(QObject *object); + Q_NODISCARD bool isReady() const; + void waitForReady(); + private: Q_NODISCARD QRect mapWidgetGeometryToScene(const QWidget * const widget) const; Q_NODISCARD bool isInSystemButtons(const QPoint &pos, Global::SystemButtonType *button) const; @@ -102,6 +105,7 @@ private: bool m_blurBehindWindowEnabled = false; QPointer m_window = nullptr; bool m_destroying = false; + bool m_qpaReady = false; }; FRAMELESSHELPER_END_NAMESPACE diff --git a/src/quick/framelessquickhelper.cpp b/src/quick/framelessquickhelper.cpp index 27057d9..d0b25f6 100644 --- a/src/quick/framelessquickhelper.cpp +++ b/src/quick/framelessquickhelper.cpp @@ -35,6 +35,7 @@ #endif // Q_OS_WINDOWS #include #include +#include #include #ifndef FRAMELESSHELPER_QUICK_NO_PRIVATE # if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) @@ -237,6 +238,7 @@ void FramelessQuickHelperPrivate::attach() // due to QPA will reset the position and size of the window during it's // initialization process. QTimer::singleShot(0, this, [this](){ + m_qpaReady = true; if (FramelessConfig::instance()->isSet(Option::CenterWindowBeforeShow)) { moveWindowToDesktopCenter(); } @@ -660,6 +662,30 @@ FramelessQuickHelper *FramelessQuickHelperPrivate::findOrCreateFramelessHelper(Q return instance; } +bool FramelessQuickHelperPrivate::isReady() const +{ + return m_qpaReady; +} + +void FramelessQuickHelperPrivate::waitForReady() +{ + if (m_qpaReady) { + return; + } +#if 1 + QEventLoop loop; + Q_Q(FramelessQuickHelper); + const QMetaObject::Connection connection = connect( + q, &FramelessQuickHelper::ready, &loop, &QEventLoop::quit); + loop.exec(); + disconnect(connection); +#else + while (!m_qpaReady) { + QCoreApplication::processEvents(); + } +#endif +} + QRect FramelessQuickHelperPrivate::mapItemGeometryToScene(const QQuickItem * const item) const { Q_ASSERT(item); @@ -993,6 +1019,18 @@ QuickWindowBorder *FramelessQuickHelper::windowBorder() const return d->findOrCreateWindowBorder(); } +bool FramelessQuickHelper::isReady() const +{ + Q_D(const FramelessQuickHelper); + return d->isReady(); +} + +void FramelessQuickHelper::waitForReady() +{ + Q_D(FramelessQuickHelper); + d->waitForReady(); +} + void FramelessQuickHelper::extendsContentIntoTitleBar(const bool value) { Q_D(FramelessQuickHelper); diff --git a/src/widgets/framelesswidgetshelper.cpp b/src/widgets/framelesswidgetshelper.cpp index 547aa67..540b192 100644 --- a/src/widgets/framelesswidgetshelper.cpp +++ b/src/widgets/framelesswidgetshelper.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -320,6 +321,30 @@ FramelessWidgetsHelper *FramelessWidgetsHelperPrivate::findOrCreateFramelessHelp return instance; } +bool FramelessWidgetsHelperPrivate::isReady() const +{ + return m_qpaReady; +} + +void FramelessWidgetsHelperPrivate::waitForReady() +{ + if (m_qpaReady) { + return; + } +#if 1 + QEventLoop loop; + Q_Q(FramelessWidgetsHelper); + const QMetaObject::Connection connection = connect( + q, &FramelessWidgetsHelper::ready, &loop, &QEventLoop::quit); + loop.exec(); + disconnect(connection); +#else + while (!m_qpaReady) { + QCoreApplication::processEvents(); + } +#endif +} + bool FramelessWidgetsHelperPrivate::isContentExtendedIntoTitleBar() const { return getWindowData().ready; @@ -476,6 +501,7 @@ void FramelessWidgetsHelperPrivate::attach() // due to QPA will reset the position and size of the window during it's // initialization process. QTimer::singleShot(0, this, [this](){ + m_qpaReady = true; if (FramelessConfig::instance()->isSet(Option::CenterWindowBeforeShow)) { moveWindowToDesktopCenter(); } @@ -916,6 +942,18 @@ WindowBorderPainter *FramelessWidgetsHelper::windowBorder() const return d->getWindowBorderIfAny(); } +bool FramelessWidgetsHelper::isReady() const +{ + Q_D(const FramelessWidgetsHelper); + return d->isReady(); +} + +void FramelessWidgetsHelper::waitForReady() +{ + Q_D(FramelessWidgetsHelper); + d->waitForReady(); +} + void FramelessWidgetsHelper::extendsContentIntoTitleBar(const bool value) { Q_D(FramelessWidgetsHelper);