feat: add hard reload signal and wrap root object

This commit is contained in:
outfoxxed 2024-01-31 17:43:18 -08:00
parent d14258df8e
commit 9a5ad44aa9
Signed by untrusted user: outfoxxed
GPG key ID: 4C88A185FB89301E
6 changed files with 116 additions and 22 deletions

View file

@ -26,6 +26,7 @@ qt_add_executable(qtshell
src/cpp/main.cpp src/cpp/main.cpp
src/cpp/shell.cpp src/cpp/shell.cpp
src/cpp/variants.cpp src/cpp/variants.cpp
src/cpp/rootwrapper.cpp
) )
qt_add_qml_module(qtshell URI QtShell) qt_add_qml_module(qtshell URI QtShell)

View file

@ -5,10 +5,11 @@
#include <qguiapplication.h> #include <qguiapplication.h>
#include <qlogging.h> #include <qlogging.h>
#include <qobject.h> #include <qobject.h>
#include <qqmlapplicationengine.h> #include <qquickwindow.h>
#include <qstandardpaths.h> #include <qstandardpaths.h>
#include <qstring.h> #include <qstring.h>
#include "rootwrapper.hpp"
#include "shell.hpp" #include "shell.hpp"
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -43,21 +44,11 @@ int main(int argc, char** argv) {
CONFIG_PATH = configPath; CONFIG_PATH = configPath;
LayerShellQt::Shell::useLayerShell(); LayerShellQt::Shell::useLayerShell();
// Base window transparency appears to be additive.
// Use a fully transparent window with a colored rect.
QQuickWindow::setDefaultAlphaBuffer(true);
auto engine = QQmlApplicationEngine(); auto root = RootWrapper(configPath);
engine.load(configPath);
if (engine.rootObjects().isEmpty()) {
qCritical() << "failed to load config file";
return -1;
}
auto* shellobj = qobject_cast<QtShell*>(engine.rootObjects().first());
if (shellobj == nullptr) {
qCritical() << "root item was not a QtShell";
return -1;
}
return QGuiApplication::exec(); return QGuiApplication::exec();
} }

64
src/cpp/rootwrapper.cpp Normal file
View file

@ -0,0 +1,64 @@
#include "rootwrapper.hpp"
#include <cstdlib>
#include <utility>
#include <qlogging.h>
#include <qobject.h>
#include <qqmlcomponent.h>
#include <qqmlengine.h>
#include <qurl.h>
#include "shell.hpp"
RootWrapper::RootWrapper(QUrl rootUrl):
QObject(nullptr), rootUrl(std::move(rootUrl)), engine(this) {
this->reloadGraph();
if (this->activeRoot == nullptr) {
qCritical() << "could not create scene graph, exiting";
exit(-1); // NOLINT
}
}
void RootWrapper::reloadGraph() {
if (this->activeRoot != nullptr) {
this->engine.clearComponentCache();
}
auto component = QQmlComponent(&this->engine, this->rootUrl);
auto* obj = component.beginCreate(this->engine.rootContext());
if (obj == nullptr) {
qWarning() << "failed to create root component";
return;
}
auto* qtsobj = qobject_cast<QtShell*>(obj);
if (qtsobj == nullptr) {
qWarning() << "root component was not a QtShell";
delete obj;
return;
}
component.completeCreate();
if (this->activeRoot != nullptr) {
this->activeRoot->deleteLater();
this->activeRoot = nullptr;
}
this->activeRoot = qtsobj;
}
void RootWrapper::changeRoot(QtShell* newRoot) {
if (this->activeRoot != nullptr) {
QObject::disconnect(this->destroyConnection);
this->activeRoot->deleteLater();
}
if (newRoot != nullptr) {
this->activeRoot = newRoot;
QObject::connect(this->activeRoot, &QtShell::destroyed, this, &RootWrapper::destroy);
}
}
void RootWrapper::destroy() { this->deleteLater(); }

28
src/cpp/rootwrapper.hpp Normal file
View file

@ -0,0 +1,28 @@
#pragma once
#include <qobject.h>
#include <qobjectdefs.h>
#include <qqmlengine.h>
#include <qtmetamacros.h>
#include <qurl.h>
#include "shell.hpp"
class RootWrapper: public QObject {
Q_OBJECT;
public:
explicit RootWrapper(QUrl rootUrl);
void reloadGraph();
void changeRoot(QtShell* newRoot);
private slots:
void destroy();
private:
QUrl rootUrl;
QQmlEngine engine;
QtShell* activeRoot = nullptr;
QMetaObject::Connection destroyConnection;
};

View file

@ -11,18 +11,25 @@
#include <qqmllist.h> #include <qqmllist.h>
#include <qtmetamacros.h> #include <qtmetamacros.h>
#include "rootwrapper.hpp"
QString CONFIG_PATH; // NOLINT QString CONFIG_PATH; // NOLINT
QtShell::QtShell(): QObject(nullptr), path(CONFIG_PATH), dir(QFileInfo(this->path).dir()) { QtShell::QtShell(): QObject(nullptr), path(CONFIG_PATH), dir(QFileInfo(this->path).dir()) {}
CONFIG_PATH = "";
}
void QtShell::componentComplete() { void QtShell::reload() {
if (this->path.isEmpty()) { auto* rootobj = QQmlEngine::contextForObject(this)->engine()->parent();
qWarning() << "Multiple QtShell objects were created. You should not do this."; auto* root = qobject_cast<RootWrapper*>(rootobj);
if (root == nullptr) {
qWarning() << "cannot find RootWrapper for reload, ignoring request";
return; return;
} }
root->reloadGraph();
}
void QtShell::componentComplete() {
for (auto* component: this->mComponents) { for (auto* component: this->mComponents) {
component->prepare(this->dir); component->prepare(this->dir);
} }

View file

@ -23,11 +23,14 @@ class QtShell: public QObject, public QQmlParserStatus {
public: public:
explicit QtShell(); explicit QtShell();
void classBegin() override {}; void classBegin() override {}
void componentComplete() override; void componentComplete() override;
QQmlListProperty<ShellComponent> components(); QQmlListProperty<ShellComponent> components();
public slots:
void reload();
private: private:
static void appendComponent(QQmlListProperty<ShellComponent>* list, ShellComponent* component); static void appendComponent(QQmlListProperty<ShellComponent>* list, ShellComponent* component);