reload: encapsulate each engine generation more

This commit is contained in:
outfoxxed 2024-03-13 22:53:05 -07:00
parent 211f454de9
commit 1687ff3614
Signed by: outfoxxed
GPG Key ID: 4C88A185FB89301E
7 changed files with 125 additions and 79 deletions

View File

@ -17,6 +17,7 @@ qt_add_library(quickshell-core STATIC
panelinterface.cpp panelinterface.cpp
popupwindow.cpp popupwindow.cpp
singleton.cpp singleton.cpp
generation.cpp
) )
set_source_files_properties(main.cpp PROPERTIES COMPILE_DEFINITIONS GIT_REVISION="${GIT_REVISION}") set_source_files_properties(main.cpp PROPERTIES COMPILE_DEFINITIONS GIT_REVISION="${GIT_REVISION}")

53
src/core/generation.cpp Normal file
View File

@ -0,0 +1,53 @@
#include "generation.hpp"
#include <qcontainerfwd.h>
#include <qcoreapplication.h>
#include <qhash.h>
#include <qobject.h>
#include <qqmlcontext.h>
#include <qqmlengine.h>
#include <qtimer.h>
#include "plugin.hpp"
#include "reload.hpp"
static QHash<QQmlEngine*, EngineGeneration*> 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;
}

23
src/core/generation.hpp Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include <qobject.h>
#include <qtclasshelpermacros.h>
#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;
};

View File

@ -2,21 +2,17 @@
#include <cstdlib> #include <cstdlib>
#include <utility> #include <utility>
#include <qcoreapplication.h>
#include <qdir.h> #include <qdir.h>
#include <qfileinfo.h> #include <qfileinfo.h>
#include <qlogging.h> #include <qlogging.h>
#include <qobject.h> #include <qobject.h>
#include <qqmlcomponent.h> #include <qqmlcomponent.h>
#include <qqmlengine.h> #include <qqmlengine.h>
#include <qtimer.h>
#include <qurl.h> #include <qurl.h>
#include "plugin.hpp" #include "generation.hpp"
#include "qmlglobal.hpp" #include "qmlglobal.hpp"
#include "reload.hpp"
#include "shell.hpp" #include "shell.hpp"
#include "singleton.hpp"
#include "watcher.hpp" #include "watcher.hpp"
RootWrapper::RootWrapper(QString rootPath) RootWrapper::RootWrapper(QString rootPath)
@ -29,7 +25,7 @@ RootWrapper::RootWrapper(QString rootPath)
this->reloadGraph(true); this->reloadGraph(true);
if (this->root == nullptr) { if (this->generation == nullptr) {
qCritical() << "could not create scene graph, exiting"; qCritical() << "could not create scene graph, exiting";
exit(-1); // NOLINT exit(-1); // NOLINT
} }
@ -37,31 +33,32 @@ RootWrapper::RootWrapper(QString rootPath)
RootWrapper::~RootWrapper() { RootWrapper::~RootWrapper() {
// event loop may no longer be running so deleteLater is not an option // 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) { void RootWrapper::reloadGraph(bool hard) {
auto* oldEngine = this->engine; auto* generation = new EngineGeneration();
this->engine = new QQmlEngine(this);
auto* app = QCoreApplication::instance(); // todo: move into EngineGeneration
QObject::connect(this->engine, &QQmlEngine::quit, app, &QCoreApplication::quit); if (this->generation != nullptr) {
QObject::connect(this->engine, &QQmlEngine::exit, app, &QCoreApplication::exit);
if (this->root != nullptr) {
QuickshellSettings::reset(); QuickshellSettings::reset();
SingletonRegistry::instance()->flip();
} }
QDir::setCurrent(this->originalWorkingDirectory); 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) { if (obj == nullptr) {
qWarning() << component.errorString().toStdString().c_str(); qWarning() << component.errorString().toStdString().c_str();
qWarning() << "failed to create root component"; qWarning() << "failed to create root component";
delete generation;
return; return;
} }
@ -69,31 +66,19 @@ void RootWrapper::reloadGraph(bool hard) {
if (newRoot == nullptr) { if (newRoot == nullptr) {
qWarning() << "root component was not a Quickshell.ShellRoot"; qWarning() << "root component was not a Quickshell.ShellRoot";
delete obj; delete obj;
delete generation;
return; return;
} }
generation->root = newRoot;
component.completeCreate(); component.completeCreate();
auto* oldRoot = this->root; generation->onReload(hard ? nullptr : this->generation);
this->root = newRoot; if (hard) delete this->generation;
this->generation = generation;
this->root->onReload(hard ? nullptr : oldRoot); qInfo() << "Configuration Loaded";
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;
this->onWatchFilesChanged(); this->onWatchFilesChanged();
} }

View File

@ -6,7 +6,7 @@
#include <qtmetamacros.h> #include <qtmetamacros.h>
#include <qurl.h> #include <qurl.h>
#include "shell.hpp" #include "generation.hpp"
#include "watcher.hpp" #include "watcher.hpp"
class RootWrapper: public QObject { class RootWrapper: public QObject {
@ -25,8 +25,7 @@ private slots:
private: private:
QString rootPath; QString rootPath;
QQmlEngine* engine = nullptr; EngineGeneration* generation = nullptr;
ShellRoot* root = nullptr;
FiletreeWatcher* configWatcher = nullptr; FiletreeWatcher* configWatcher = nullptr;
QString originalWorkingDirectory; QString originalWorkingDirectory;
}; };

View File

@ -7,58 +7,48 @@
#include <qqmlengine.h> #include <qqmlengine.h>
#include <qurl.h> #include <qurl.h>
#include "generation.hpp"
#include "reload.hpp" #include "reload.hpp"
void Singleton::componentComplete() { void Singleton::componentComplete() {
auto* context = QQmlEngine::contextForObject(this); auto* context = QQmlEngine::contextForObject(this);
if (context == nullptr) { 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; return;
} }
auto url = context->baseUrl(); auto url = context->baseUrl();
if (this->parent() != nullptr || context->contextObject() != this) { 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; << "which is not the root component of its file" << url;
return; 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(); this->ReloadPropagator::componentComplete();
} }
SingletonRegistry::~SingletonRegistry() { void SingletonRegistry::registerSingleton(const QUrl& url, Singleton* singleton) {
delete this->previousRegistry; if (this->registry.contains(url)) {
delete this->currentRegistry; qWarning() << "Tried to register singleton twice for the same file" << url;
} return;
void SingletonRegistry::install(const QUrl& url, Singleton* singleton) {
QObject* old = nullptr;
if (this->previousRegistry != nullptr) {
old = this->previousRegistry->value(url);
} }
if (this->currentRegistry == nullptr) { this->registry.insert(url, singleton);
this->currentRegistry = new QMap<QUrl, QObject*>(); }
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;
} }

View File

@ -21,15 +21,10 @@ public:
class SingletonRegistry { class SingletonRegistry {
public: public:
SingletonRegistry() = default; SingletonRegistry() = default;
~SingletonRegistry();
Q_DISABLE_COPY_MOVE(SingletonRegistry);
void install(const QUrl& url, Singleton* singleton); void registerSingleton(const QUrl& url, Singleton* singleton);
void flip(); void onReload(SingletonRegistry* old);
static SingletonRegistry* instance();
private: private:
QMap<QUrl, QObject*>* previousRegistry = nullptr; QMap<QUrl, Singleton*> registry;
QMap<QUrl, QObject*>* currentRegistry = nullptr;
}; };