forked from quickshell/quickshell
reload: encapsulate each engine generation more
This commit is contained in:
parent
211f454de9
commit
1687ff3614
|
@ -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
53
src/core/generation.cpp
Normal 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
23
src/core/generation.hpp
Normal 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;
|
||||||
|
};
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue