From 9a5ad44aa9d7fb36f2603dbc1a198f20fdd30584 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Wed, 31 Jan 2024 17:43:18 -0800 Subject: [PATCH] feat: add hard reload signal and wrap root object --- CMakeLists.txt | 1 + src/cpp/main.cpp | 21 ++++---------- src/cpp/rootwrapper.cpp | 64 +++++++++++++++++++++++++++++++++++++++++ src/cpp/rootwrapper.hpp | 28 ++++++++++++++++++ src/cpp/shell.cpp | 19 ++++++++---- src/cpp/shell.hpp | 5 +++- 6 files changed, 116 insertions(+), 22 deletions(-) create mode 100644 src/cpp/rootwrapper.cpp create mode 100644 src/cpp/rootwrapper.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 760a618..d3f8207 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ qt_add_executable(qtshell src/cpp/main.cpp src/cpp/shell.cpp src/cpp/variants.cpp + src/cpp/rootwrapper.cpp ) qt_add_qml_module(qtshell URI QtShell) diff --git a/src/cpp/main.cpp b/src/cpp/main.cpp index 03418ca..73aa555 100644 --- a/src/cpp/main.cpp +++ b/src/cpp/main.cpp @@ -5,10 +5,11 @@ #include #include #include -#include +#include #include #include +#include "rootwrapper.hpp" #include "shell.hpp" int main(int argc, char** argv) { @@ -43,21 +44,11 @@ int main(int argc, char** argv) { CONFIG_PATH = configPath; 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(); - engine.load(configPath); - - if (engine.rootObjects().isEmpty()) { - qCritical() << "failed to load config file"; - return -1; - } - - auto* shellobj = qobject_cast(engine.rootObjects().first()); - - if (shellobj == nullptr) { - qCritical() << "root item was not a QtShell"; - return -1; - } + auto root = RootWrapper(configPath); return QGuiApplication::exec(); } diff --git a/src/cpp/rootwrapper.cpp b/src/cpp/rootwrapper.cpp new file mode 100644 index 0000000..3902ce0 --- /dev/null +++ b/src/cpp/rootwrapper.cpp @@ -0,0 +1,64 @@ +#include "rootwrapper.hpp" +#include +#include + +#include +#include +#include +#include +#include + +#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(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(); } diff --git a/src/cpp/rootwrapper.hpp b/src/cpp/rootwrapper.hpp new file mode 100644 index 0000000..4efdadf --- /dev/null +++ b/src/cpp/rootwrapper.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include +#include +#include + +#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; +}; diff --git a/src/cpp/shell.cpp b/src/cpp/shell.cpp index e8e71e5..120f3a5 100644 --- a/src/cpp/shell.cpp +++ b/src/cpp/shell.cpp @@ -11,18 +11,25 @@ #include #include +#include "rootwrapper.hpp" + QString CONFIG_PATH; // NOLINT -QtShell::QtShell(): QObject(nullptr), path(CONFIG_PATH), dir(QFileInfo(this->path).dir()) { - CONFIG_PATH = ""; -} +QtShell::QtShell(): QObject(nullptr), path(CONFIG_PATH), dir(QFileInfo(this->path).dir()) {} -void QtShell::componentComplete() { - if (this->path.isEmpty()) { - qWarning() << "Multiple QtShell objects were created. You should not do this."; +void QtShell::reload() { + auto* rootobj = QQmlEngine::contextForObject(this)->engine()->parent(); + auto* root = qobject_cast(rootobj); + + if (root == nullptr) { + qWarning() << "cannot find RootWrapper for reload, ignoring request"; return; } + root->reloadGraph(); +} + +void QtShell::componentComplete() { for (auto* component: this->mComponents) { component->prepare(this->dir); } diff --git a/src/cpp/shell.hpp b/src/cpp/shell.hpp index 5b01748..205ab9f 100644 --- a/src/cpp/shell.hpp +++ b/src/cpp/shell.hpp @@ -23,11 +23,14 @@ class QtShell: public QObject, public QQmlParserStatus { public: explicit QtShell(); - void classBegin() override {}; + void classBegin() override {} void componentComplete() override; QQmlListProperty components(); +public slots: + void reload(); + private: static void appendComponent(QQmlListProperty* list, ShellComponent* component);