From 463f9a297fd48ff1118ad71539b31f635a214d5a Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Tue, 12 Mar 2024 14:55:51 -0700 Subject: [PATCH] root: recreate the qml engine on reload instead of clearing it This causes singletons to be recreated instead of kept alive. --- CMakeLists.txt | 31 ++++---- src/core/main.cpp | 1 - src/core/qmlglobal.cpp | 101 +++++++++++++++----------- src/core/qmlglobal.hpp | 22 ++++-- src/core/rootwrapper.cpp | 19 +++-- src/core/rootwrapper.hpp | 2 +- src/main.cpp | 4 +- src/wayland/session_lock.cpp | 3 +- src/wayland/wlr_layershell/window.hpp | 4 +- 9 files changed, 109 insertions(+), 78 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c6fff4af..86b9fd38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,21 +70,26 @@ file(GENERATE CONTENT "" ) -add_library(qt-pch ${CMAKE_CURRENT_BINARY_DIR}/pchstub.cpp) -target_link_libraries(qt-pch PRIVATE ${QT_DEPS}) -target_precompile_headers(qt-pch PUBLIC - - - - - - - -) +# pch breaks clang-tidy..... somehow +if (NOT NO_PCH) + add_library(qt-pch ${CMAKE_CURRENT_BINARY_DIR}/pchstub.cpp) + target_link_libraries(qt-pch PRIVATE ${QT_DEPS}) + target_precompile_headers(qt-pch PUBLIC + + + + + + + + ) +endif() function (qs_pch target) - target_precompile_headers(${target} REUSE_FROM qt-pch) - target_link_libraries(${target} PRIVATE ${QT_DEPS}) # required for gcc to accept the pch on plugin targets + if (NOT NO_PCH) + target_precompile_headers(${target} REUSE_FROM qt-pch) + target_link_libraries(${target} PRIVATE ${QT_DEPS}) # required for gcc to accept the pch on plugin targets + endif() endfunction() add_subdirectory(src) diff --git a/src/core/main.cpp b/src/core/main.cpp index 04761f45..198011b1 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -1,5 +1,4 @@ #include "main.hpp" - #include #include diff --git a/src/core/qmlglobal.cpp b/src/core/qmlglobal.cpp index 0242d0e3..b6d50fa1 100644 --- a/src/core/qmlglobal.cpp +++ b/src/core/qmlglobal.cpp @@ -57,38 +57,81 @@ void QuickshellSettings::setWatchFiles(bool watchFiles) { emit this->watchFilesChanged(); } -QuickshellGlobal::QuickshellGlobal(QObject* parent): QObject(parent) { - // clang-format off - QObject::connect(QuickshellSettings::instance(), &QuickshellSettings::workingDirectoryChanged, this, &QuickshellGlobal::workingDirectoryChanged); - QObject::connect(QuickshellSettings::instance(), &QuickshellSettings::watchFilesChanged, this, &QuickshellGlobal::watchFilesChanged); - QObject::connect(QuickshellSettings::instance(), &QuickshellSettings::lastWindowClosed, this, &QuickshellGlobal::lastWindowClosed); - // clang-format on - +QuickshellTracked::QuickshellTracked() { auto* app = QCoreApplication::instance(); auto* guiApp = qobject_cast(app); if (guiApp != nullptr) { // clang-format off - QObject::connect(guiApp, &QGuiApplication::primaryScreenChanged, this, &QuickshellGlobal::updateScreens); - QObject::connect(guiApp, &QGuiApplication::screenAdded, this, &QuickshellGlobal::updateScreens); - QObject::connect(guiApp, &QGuiApplication::screenRemoved, this, &QuickshellGlobal::updateScreens); + QObject::connect(guiApp, &QGuiApplication::primaryScreenChanged, this, &QuickshellTracked::updateScreens); + QObject::connect(guiApp, &QGuiApplication::screenAdded, this, &QuickshellTracked::updateScreens); + QObject::connect(guiApp, &QGuiApplication::screenRemoved, this, &QuickshellTracked::updateScreens); // clang-format on this->updateScreens(); } } +QuickshellTracked* QuickshellTracked::instance() { + static QuickshellTracked* instance = nullptr; // NOLINT + if (instance == nullptr) { + QJSEngine::setObjectOwnership(instance, QJSEngine::CppOwnership); + instance = new QuickshellTracked(); + } + return instance; +} + +void QuickshellTracked::updateScreens() { + auto screens = QGuiApplication::screens(); + auto newScreens = QList(); + + for (auto* newScreen: screens) { + for (auto i = 0; i < this->screens.length(); i++) { + auto* oldScreen = this->screens[i]; + if (newScreen == oldScreen->screen) { + newScreens.push_back(oldScreen); + this->screens.remove(i); + goto next; + } + } + + { + auto* si = new QuickshellScreenInfo(this, newScreen); + QQmlEngine::setObjectOwnership(si, QQmlEngine::CppOwnership); + newScreens.push_back(si); + } + next:; + } + + for (auto* oldScreen: this->screens) { + oldScreen->deleteLater(); + } + + this->screens = newScreens; + emit this->screensChanged(); +} + +QuickshellGlobal::QuickshellGlobal(QObject* parent): QObject(parent) { + // clang-format off + QObject::connect(QuickshellSettings::instance(), &QuickshellSettings::workingDirectoryChanged, this, &QuickshellGlobal::workingDirectoryChanged); + QObject::connect(QuickshellSettings::instance(), &QuickshellSettings::watchFilesChanged, this, &QuickshellGlobal::watchFilesChanged); + QObject::connect(QuickshellSettings::instance(), &QuickshellSettings::lastWindowClosed, this, &QuickshellGlobal::lastWindowClosed); + + QObject::connect(QuickshellTracked::instance(), &QuickshellTracked::screensChanged, this, &QuickshellGlobal::screensChanged); + // clang-format on +} + qint32 QuickshellGlobal::processId() const { // NOLINT return getpid(); } -qsizetype QuickshellGlobal::screensCount(QQmlListProperty* prop) { - return static_cast(prop->object)->mScreens.size(); // NOLINT +qsizetype QuickshellGlobal::screensCount(QQmlListProperty* /*unused*/) { + return QuickshellTracked::instance()->screens.size(); } QuickshellScreenInfo* -QuickshellGlobal::screenAt(QQmlListProperty* prop, qsizetype i) { - return static_cast(prop->object)->mScreens.at(i); // NOLINT +QuickshellGlobal::screenAt(QQmlListProperty* /*unused*/, qsizetype i) { + return QuickshellTracked::instance()->screens.at(i); } QQmlListProperty QuickshellGlobal::screens() { @@ -128,36 +171,6 @@ void QuickshellGlobal::setWatchFiles(bool watchFiles) { // NOLINT QuickshellSettings::instance()->setWatchFiles(watchFiles); } -void QuickshellGlobal::updateScreens() { - auto screens = QGuiApplication::screens(); - auto newScreens = QList(); - - for (auto* newScreen: screens) { - for (auto i = 0; i < this->mScreens.length(); i++) { - auto* oldScreen = this->mScreens[i]; - if (newScreen == oldScreen->screen) { - newScreens.push_back(oldScreen); - this->mScreens.remove(i); - goto next; - } - } - - { - auto* si = new QuickshellScreenInfo(this, newScreen); - QQmlEngine::setObjectOwnership(si, QQmlEngine::CppOwnership); - newScreens.push_back(si); - } - next:; - } - - for (auto* oldScreen: this->mScreens) { - oldScreen->deleteLater(); - } - - this->mScreens = newScreens; - emit this->screensChanged(); -} - QVariant QuickshellGlobal::env(const QString& variable) { // NOLINT auto vstr = variable.toStdString(); if (!qEnvironmentVariableIsSet(vstr.data())) return QVariant::fromValue(nullptr); diff --git a/src/core/qmlglobal.hpp b/src/core/qmlglobal.hpp index 204ff032..df852a18 100644 --- a/src/core/qmlglobal.hpp +++ b/src/core/qmlglobal.hpp @@ -53,6 +53,23 @@ private: bool mWatchFiles = true; }; +class QuickshellTracked: public QObject { + Q_OBJECT; + +public: + QuickshellTracked(); + + QVector screens; + + static QuickshellTracked* instance(); + +private slots: + void updateScreens(); + +signals: + void screensChanged(); +}; + class QuickshellGlobal: public QObject { Q_OBJECT; // clang-format off @@ -124,12 +141,7 @@ signals: void workingDirectoryChanged(); void watchFilesChanged(); -public slots: - void updateScreens(); - private: static qsizetype screensCount(QQmlListProperty* prop); static QuickshellScreenInfo* screenAt(QQmlListProperty* prop, qsizetype i); - - QVector mScreens; }; diff --git a/src/core/rootwrapper.cpp b/src/core/rootwrapper.cpp index 16941f5a..68c11de9 100644 --- a/src/core/rootwrapper.cpp +++ b/src/core/rootwrapper.cpp @@ -21,12 +21,7 @@ RootWrapper::RootWrapper(QString rootPath) : QObject(nullptr) , rootPath(std::move(rootPath)) - , engine(this) , originalWorkingDirectory(QDir::current().absolutePath()) { - auto* app = QCoreApplication::instance(); - QObject::connect(&this->engine, &QQmlEngine::quit, app, &QCoreApplication::quit); - QObject::connect(&this->engine, &QQmlEngine::exit, app, &QCoreApplication::exit); - // clang-format off QObject::connect(QuickshellSettings::instance(), &QuickshellSettings::watchFilesChanged, this, &RootWrapper::onWatchFilesChanged); // clang-format on @@ -45,16 +40,22 @@ RootWrapper::~RootWrapper() { } void RootWrapper::reloadGraph(bool hard) { + auto* oldEngine = this->engine; + this->engine = new QQmlEngine(this); + + auto* app = QCoreApplication::instance(); + QObject::connect(this->engine, &QQmlEngine::quit, app, &QCoreApplication::quit); + QObject::connect(this->engine, &QQmlEngine::exit, app, &QCoreApplication::exit); + if (this->root != nullptr) { QuickshellSettings::reset(); - this->engine.clearComponentCache(); } QDir::setCurrent(this->originalWorkingDirectory); - auto component = QQmlComponent(&this->engine, QUrl::fromLocalFile(this->rootPath)); + auto component = QQmlComponent(this->engine, QUrl::fromLocalFile(this->rootPath)); - auto* obj = component.beginCreate(this->engine.rootContext()); + auto* obj = component.beginCreate(this->engine->rootContext()); if (obj == nullptr) { qWarning() << component.errorString().toStdString().c_str(); @@ -90,6 +91,8 @@ void RootWrapper::reloadGraph(bool hard) { QuickshellPlugin::runOnReload(); } + delete oldEngine; + this->onWatchFilesChanged(); } diff --git a/src/core/rootwrapper.hpp b/src/core/rootwrapper.hpp index 6174c7b1..43d3bbb7 100644 --- a/src/core/rootwrapper.hpp +++ b/src/core/rootwrapper.hpp @@ -25,7 +25,7 @@ private slots: private: QString rootPath; - QQmlEngine engine; + QQmlEngine* engine = nullptr; ShellRoot* root = nullptr; FiletreeWatcher* configWatcher = nullptr; QString originalWorkingDirectory; diff --git a/src/main.cpp b/src/main.cpp index 0ce548e7..935853ac 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,3 @@ #include "core/main.hpp" -int main(int argc, char** argv) { - return qs_main(argc, argv); -} +int main(int argc, char** argv) { return qs_main(argc, argv); } diff --git a/src/wayland/session_lock.cpp b/src/wayland/session_lock.cpp index 405763ed..73967c9c 100644 --- a/src/wayland/session_lock.cpp +++ b/src/wayland/session_lock.cpp @@ -78,7 +78,8 @@ void WlSessionLock::updateSurfaces(WlSessionLock* old) { auto* instance = qobject_cast(instanceObj); if (instance == nullptr) { - qWarning() << "WlSessionLock.surface does not create a WlSessionLockSurface. Aborting lock."; + qWarning( + ) << "WlSessionLock.surface does not create a WlSessionLockSurface. Aborting lock."; if (instanceObj != nullptr) instanceObj->deleteLater(); this->unlock(); return; diff --git a/src/wayland/wlr_layershell/window.hpp b/src/wayland/wlr_layershell/window.hpp index 022098a8..163f3aa7 100644 --- a/src/wayland/wlr_layershell/window.hpp +++ b/src/wayland/wlr_layershell/window.hpp @@ -26,7 +26,7 @@ enum Enum { }; Q_ENUM_NS(Enum); -} // namespace Layer +} // namespace WlrLayer ///! WlrLayershell keyboard focus mode namespace WlrKeyboardFocus { // NOLINT @@ -47,7 +47,7 @@ enum Enum { }; Q_ENUM_NS(Enum); -} // namespace KeyboardFocus +} // namespace WlrKeyboardFocus class QSWaylandLayerSurface;