diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4ce42b92..4eab3fad 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -17,6 +17,7 @@ qt_add_library(quickshell-core STATIC panelinterface.cpp popupwindow.cpp singleton.cpp + generation.cpp ) set_source_files_properties(main.cpp PROPERTIES COMPILE_DEFINITIONS GIT_REVISION="${GIT_REVISION}") diff --git a/src/core/generation.cpp b/src/core/generation.cpp new file mode 100644 index 00000000..6454a002 --- /dev/null +++ b/src/core/generation.cpp @@ -0,0 +1,53 @@ +#include "generation.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include "plugin.hpp" +#include "reload.hpp" + +static QHash g_generations; // NOLINT + +EngineGeneration::EngineGeneration() { g_generations.insert(&this->engine, this); } + +EngineGeneration::~EngineGeneration() { + g_generations.remove(&this->engine); + if (this->root != nullptr) this->root->deleteLater(); +} + +void EngineGeneration::onReload(EngineGeneration* old) { + auto* app = QCoreApplication::instance(); + QObject::connect(&this->engine, &QQmlEngine::quit, app, &QCoreApplication::quit); + QObject::connect(&this->engine, &QQmlEngine::exit, app, &QCoreApplication::exit); + + this->root->onReload(old == nullptr ? nullptr : old->root); + this->singletonRegistry.onReload(old == nullptr ? nullptr : &old->singletonRegistry); + + delete old; + + if (old != nullptr) { + QTimer::singleShot(0, [this]() { + QuickshellPlugin::runOnReload(); + PostReloadHook::postReloadTree(this->root); + }); + } else { + QuickshellPlugin::runOnReload(); + PostReloadHook::postReloadTree(this->root); + } +} + +EngineGeneration* EngineGeneration::findObjectGeneration(QObject* object) { + while (object != nullptr) { + auto* context = QQmlEngine::contextForObject(object); + if (auto* generation = g_generations.value(context->engine())) { + return generation; + } + } + + return nullptr; +} diff --git a/src/core/generation.hpp b/src/core/generation.hpp new file mode 100644 index 00000000..f62149f1 --- /dev/null +++ b/src/core/generation.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include "shell.hpp" +#include "singleton.hpp" + +class EngineGeneration { +public: + explicit EngineGeneration(); + ~EngineGeneration(); + Q_DISABLE_COPY_MOVE(EngineGeneration); + + // assumes root has been initialized, consumes old generation + void onReload(EngineGeneration* old); + + static EngineGeneration* findObjectGeneration(QObject* object); + + QQmlEngine engine; + ShellRoot* root = nullptr; + SingletonRegistry singletonRegistry; +}; diff --git a/src/core/rootwrapper.cpp b/src/core/rootwrapper.cpp index 382bf73a..bcbc56be 100644 --- a/src/core/rootwrapper.cpp +++ b/src/core/rootwrapper.cpp @@ -2,21 +2,17 @@ #include #include -#include #include #include #include #include #include #include -#include #include -#include "plugin.hpp" +#include "generation.hpp" #include "qmlglobal.hpp" -#include "reload.hpp" #include "shell.hpp" -#include "singleton.hpp" #include "watcher.hpp" RootWrapper::RootWrapper(QString rootPath) @@ -29,7 +25,7 @@ RootWrapper::RootWrapper(QString rootPath) this->reloadGraph(true); - if (this->root == nullptr) { + if (this->generation == nullptr) { qCritical() << "could not create scene graph, exiting"; exit(-1); // NOLINT } @@ -37,31 +33,32 @@ RootWrapper::RootWrapper(QString rootPath) RootWrapper::~RootWrapper() { // event loop may no longer be running so deleteLater is not an option - delete this->root; + if (this->generation != nullptr) { + delete this->generation->root; + this->generation->root = nullptr; + } + + delete this->generation; } void RootWrapper::reloadGraph(bool hard) { - auto* oldEngine = this->engine; - this->engine = new QQmlEngine(this); + auto* generation = new EngineGeneration(); - 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) { + // todo: move into EngineGeneration + if (this->generation != nullptr) { QuickshellSettings::reset(); - SingletonRegistry::instance()->flip(); } QDir::setCurrent(this->originalWorkingDirectory); - auto component = QQmlComponent(this->engine, QUrl::fromLocalFile(this->rootPath)); + auto component = QQmlComponent(&generation->engine, QUrl::fromLocalFile(this->rootPath)); - auto* obj = component.beginCreate(this->engine->rootContext()); + auto* obj = component.beginCreate(generation->engine.rootContext()); if (obj == nullptr) { qWarning() << component.errorString().toStdString().c_str(); qWarning() << "failed to create root component"; + delete generation; return; } @@ -69,31 +66,19 @@ void RootWrapper::reloadGraph(bool hard) { if (newRoot == nullptr) { qWarning() << "root component was not a Quickshell.ShellRoot"; delete obj; + delete generation; return; } + generation->root = newRoot; + component.completeCreate(); - auto* oldRoot = this->root; - this->root = newRoot; + generation->onReload(hard ? nullptr : this->generation); + if (hard) delete this->generation; + this->generation = generation; - this->root->onReload(hard ? nullptr : oldRoot); - - if (oldRoot != nullptr) { - oldRoot->deleteLater(); - - QTimer::singleShot(0, [this, newRoot]() { - if (this->root == newRoot) { - QuickshellPlugin::runOnReload(); - PostReloadHook::postReloadTree(this->root); - } - }); - } else { - PostReloadHook::postReloadTree(newRoot); - QuickshellPlugin::runOnReload(); - } - - delete oldEngine; + qInfo() << "Configuration Loaded"; this->onWatchFilesChanged(); } diff --git a/src/core/rootwrapper.hpp b/src/core/rootwrapper.hpp index 43d3bbb7..7b39d4af 100644 --- a/src/core/rootwrapper.hpp +++ b/src/core/rootwrapper.hpp @@ -6,7 +6,7 @@ #include #include -#include "shell.hpp" +#include "generation.hpp" #include "watcher.hpp" class RootWrapper: public QObject { @@ -25,8 +25,7 @@ private slots: private: QString rootPath; - QQmlEngine* engine = nullptr; - ShellRoot* root = nullptr; + EngineGeneration* generation = nullptr; FiletreeWatcher* configWatcher = nullptr; QString originalWorkingDirectory; }; diff --git a/src/core/singleton.cpp b/src/core/singleton.cpp index 61d2e068..ef03a741 100644 --- a/src/core/singleton.cpp +++ b/src/core/singleton.cpp @@ -7,58 +7,48 @@ #include #include +#include "generation.hpp" #include "reload.hpp" void Singleton::componentComplete() { auto* context = QQmlEngine::contextForObject(this); if (context == nullptr) { - qWarning() << "not registering singleton not created in the qml context:" << this; + qWarning() << "Not registering singleton not created in the qml context:" << this; return; } auto url = context->baseUrl(); if (this->parent() != nullptr || context->contextObject() != this) { - qWarning() << "tried to register singleton" << this + qWarning() << "Tried to register singleton" << this << "which is not the root component of its file" << url; return; } - SingletonRegistry::instance()->install(url, this); + auto* generation = EngineGeneration::findObjectGeneration(this); + + if (generation == nullptr) { + qWarning() << "Tried to register singleton" << this + << "which has no associated engine generation" << url; + return; + } + + generation->singletonRegistry.registerSingleton(url, this); this->ReloadPropagator::componentComplete(); } -SingletonRegistry::~SingletonRegistry() { - delete this->previousRegistry; - delete this->currentRegistry; -} - -void SingletonRegistry::install(const QUrl& url, Singleton* singleton) { - QObject* old = nullptr; - - if (this->previousRegistry != nullptr) { - old = this->previousRegistry->value(url); +void SingletonRegistry::registerSingleton(const QUrl& url, Singleton* singleton) { + if (this->registry.contains(url)) { + qWarning() << "Tried to register singleton twice for the same file" << url; + return; } - if (this->currentRegistry == nullptr) { - this->currentRegistry = new QMap(); + this->registry.insert(url, singleton); +} + +void SingletonRegistry::onReload(SingletonRegistry* old) { + for (auto [url, singleton]: this->registry.asKeyValueRange()) { + singleton->onReload(old == nullptr ? nullptr : old->registry.value(url)); } - - this->currentRegistry->insert(url, singleton); - singleton->onReload(old); -} - -void SingletonRegistry::flip() { - delete this->previousRegistry; - this->previousRegistry = this->currentRegistry; - this->currentRegistry = nullptr; -} - -SingletonRegistry* SingletonRegistry::instance() { - static SingletonRegistry* instance = nullptr; // NOLINT - if (instance == nullptr) { - instance = new SingletonRegistry(); - } - return instance; } diff --git a/src/core/singleton.hpp b/src/core/singleton.hpp index 2b9e8e75..cbbce41a 100644 --- a/src/core/singleton.hpp +++ b/src/core/singleton.hpp @@ -21,15 +21,10 @@ public: class SingletonRegistry { public: SingletonRegistry() = default; - ~SingletonRegistry(); - Q_DISABLE_COPY_MOVE(SingletonRegistry); - void install(const QUrl& url, Singleton* singleton); - void flip(); - - static SingletonRegistry* instance(); + void registerSingleton(const QUrl& url, Singleton* singleton); + void onReload(SingletonRegistry* old); private: - QMap* previousRegistry = nullptr; - QMap* currentRegistry = nullptr; + QMap registry; };