forked from quickshell/quickshell
core/reloader: fix late creation of Reloadable types
This commit is contained in:
parent
61812343f5
commit
6eb68d2cd7
|
@ -43,7 +43,7 @@ void FloatingWindowInterface::onReload(QObject* oldInstance) {
|
||||||
QQmlEngine::setContextForObject(this->window, QQmlEngine::contextForObject(this));
|
QQmlEngine::setContextForObject(this->window, QQmlEngine::contextForObject(this));
|
||||||
|
|
||||||
auto* old = qobject_cast<FloatingWindowInterface*>(oldInstance);
|
auto* old = qobject_cast<FloatingWindowInterface*>(oldInstance);
|
||||||
this->window->onReload(old != nullptr ? old->window : nullptr);
|
this->window->reload(old != nullptr ? old->window : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
QQmlListProperty<QObject> FloatingWindowInterface::data() { return this->window->data(); }
|
QQmlListProperty<QObject> FloatingWindowInterface::data() { return this->window->data(); }
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <qqmlengine.h>
|
#include <qqmlengine.h>
|
||||||
#include <qqmlincubator.h>
|
#include <qqmlincubator.h>
|
||||||
#include <qtimer.h>
|
#include <qtimer.h>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
#include "iconimageprovider.hpp"
|
#include "iconimageprovider.hpp"
|
||||||
#include "incubator.hpp"
|
#include "incubator.hpp"
|
||||||
|
@ -54,8 +55,10 @@ void EngineGeneration::onReload(EngineGeneration* old) {
|
||||||
QObject::connect(&this->engine, &QQmlEngine::quit, app, &QCoreApplication::quit);
|
QObject::connect(&this->engine, &QQmlEngine::quit, app, &QCoreApplication::quit);
|
||||||
QObject::connect(&this->engine, &QQmlEngine::exit, app, &QCoreApplication::exit);
|
QObject::connect(&this->engine, &QQmlEngine::exit, app, &QCoreApplication::exit);
|
||||||
|
|
||||||
this->root->onReload(old == nullptr ? nullptr : old->root);
|
this->root->reload(old == nullptr ? nullptr : old->root);
|
||||||
this->singletonRegistry.onReload(old == nullptr ? nullptr : &old->singletonRegistry);
|
this->singletonRegistry.onReload(old == nullptr ? nullptr : &old->singletonRegistry);
|
||||||
|
this->reloadComplete = true;
|
||||||
|
emit this->reloadFinished();
|
||||||
|
|
||||||
if (old != nullptr) {
|
if (old != nullptr) {
|
||||||
QTimer::singleShot(0, [this, old]() {
|
QTimer::singleShot(0, [this, old]() {
|
||||||
|
|
|
@ -41,9 +41,11 @@ public:
|
||||||
SingletonRegistry singletonRegistry;
|
SingletonRegistry singletonRegistry;
|
||||||
QFileSystemWatcher* watcher = nullptr;
|
QFileSystemWatcher* watcher = nullptr;
|
||||||
DelayedQmlIncubationController delayedIncubationController;
|
DelayedQmlIncubationController delayedIncubationController;
|
||||||
|
bool reloadComplete = false;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void filesChanged();
|
void filesChanged();
|
||||||
|
void reloadFinished();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void incubationControllerDestroyed();
|
void incubationControllerDestroyed();
|
||||||
|
|
|
@ -23,13 +23,11 @@ void LazyLoader::onReload(QObject* oldInstance) {
|
||||||
|
|
||||||
if (this->mItem != nullptr) {
|
if (this->mItem != nullptr) {
|
||||||
if (auto* reloadable = qobject_cast<Reloadable*>(this->mItem)) {
|
if (auto* reloadable = qobject_cast<Reloadable*>(this->mItem)) {
|
||||||
reloadable->onReload(old == nullptr ? nullptr : old->mItem);
|
reloadable->reload(old == nullptr ? nullptr : old->mItem);
|
||||||
} else {
|
} else {
|
||||||
Reloadable::reloadRecursive(this->mItem, old);
|
Reloadable::reloadRecursive(this->mItem, old);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->postReload = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject* LazyLoader::item() {
|
QObject* LazyLoader::item() {
|
||||||
|
@ -48,14 +46,6 @@ void LazyLoader::setItem(QObject* item) {
|
||||||
|
|
||||||
if (item != nullptr) {
|
if (item != nullptr) {
|
||||||
item->setParent(this);
|
item->setParent(this);
|
||||||
|
|
||||||
if (this->postReload) {
|
|
||||||
if (auto* reloadable = qobject_cast<Reloadable*>(this->mItem)) {
|
|
||||||
reloadable->onReload(nullptr);
|
|
||||||
} else {
|
|
||||||
Reloadable::reloadRecursive(this->mItem, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->targetActive = this->isActive();
|
this->targetActive = this->isActive();
|
||||||
|
@ -160,7 +150,7 @@ void LazyLoader::setSource(QString source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LazyLoader::incubateIfReady(bool overrideReloadCheck) {
|
void LazyLoader::incubateIfReady(bool overrideReloadCheck) {
|
||||||
if (!(this->postReload || overrideReloadCheck) || !(this->targetLoading || this->targetActive)
|
if (!(this->reloadComplete || overrideReloadCheck) || !(this->targetLoading || this->targetActive)
|
||||||
|| this->mComponent == nullptr || this->incubator != nullptr)
|
|| this->mComponent == nullptr || this->incubator != nullptr)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -152,7 +152,6 @@ private:
|
||||||
void incubateIfReady(bool overrideReloadCheck = false);
|
void incubateIfReady(bool overrideReloadCheck = false);
|
||||||
void waitForObjectCreation();
|
void waitForObjectCreation();
|
||||||
|
|
||||||
bool postReload = false;
|
|
||||||
bool targetLoading = false;
|
bool targetLoading = false;
|
||||||
bool targetActive = false;
|
bool targetActive = false;
|
||||||
QObject* mItem = nullptr;
|
QObject* mItem = nullptr;
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <qguiapplication.h>
|
#include <qguiapplication.h>
|
||||||
#include <qhash.h>
|
#include <qhash.h>
|
||||||
#include <qlogging.h>
|
#include <qlogging.h>
|
||||||
#include <qobject.h>
|
|
||||||
#include <qquickwindow.h>
|
#include <qquickwindow.h>
|
||||||
#include <qstandardpaths.h>
|
#include <qstandardpaths.h>
|
||||||
#include <qstring.h>
|
#include <qstring.h>
|
||||||
|
|
|
@ -4,6 +4,43 @@
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qqmllist.h>
|
#include <qqmllist.h>
|
||||||
|
|
||||||
|
#include "generation.hpp"
|
||||||
|
|
||||||
|
void Reloadable::componentComplete() {
|
||||||
|
this->engineGeneration = EngineGeneration::findObjectGeneration(this);
|
||||||
|
|
||||||
|
if (this->engineGeneration != nullptr) {
|
||||||
|
// When called this way there is no chance a reload will have old data,
|
||||||
|
// but this will at least help prevent weird behaviors due to never getting a reload.
|
||||||
|
if (this->engineGeneration->reloadComplete) this->reload();
|
||||||
|
else {
|
||||||
|
QObject::connect(
|
||||||
|
this->engineGeneration,
|
||||||
|
&EngineGeneration::reloadFinished,
|
||||||
|
this,
|
||||||
|
&Reloadable::onReloadFinished
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reloadable::reload(QObject* oldInstance) {
|
||||||
|
if (this->reloadComplete) return;
|
||||||
|
this->onReload(oldInstance);
|
||||||
|
this->reloadComplete = true;
|
||||||
|
|
||||||
|
if (this->engineGeneration != nullptr) {
|
||||||
|
QObject::disconnect(
|
||||||
|
this->engineGeneration,
|
||||||
|
&EngineGeneration::reloadFinished,
|
||||||
|
this,
|
||||||
|
&Reloadable::onReloadFinished
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reloadable::onReloadFinished() { this->reload(nullptr); }
|
||||||
|
|
||||||
void ReloadPropagator::onReload(QObject* oldInstance) {
|
void ReloadPropagator::onReload(QObject* oldInstance) {
|
||||||
auto* old = qobject_cast<ReloadPropagator*>(oldInstance);
|
auto* old = qobject_cast<ReloadPropagator*>(oldInstance);
|
||||||
|
|
||||||
|
@ -13,7 +50,7 @@ void ReloadPropagator::onReload(QObject* oldInstance) {
|
||||||
auto* oldChild = old == nullptr || old->mChildren.length() <= i
|
auto* oldChild = old == nullptr || old->mChildren.length() <= i
|
||||||
? nullptr
|
? nullptr
|
||||||
: qobject_cast<Reloadable*>(old->mChildren.at(i));
|
: qobject_cast<Reloadable*>(old->mChildren.at(i));
|
||||||
newChild->onReload(oldChild);
|
newChild->reload(oldChild);
|
||||||
} else {
|
} else {
|
||||||
Reloadable::reloadRecursive(newChild, oldInstance);
|
Reloadable::reloadRecursive(newChild, oldInstance);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include <qqmlparserstatus.h>
|
#include <qqmlparserstatus.h>
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
|
class EngineGeneration;
|
||||||
|
|
||||||
///! The base class of all types that can be reloaded.
|
///! The base class of all types that can be reloaded.
|
||||||
/// Reloadables will attempt to take specific state from previous config revisions if possible.
|
/// Reloadables will attempt to take specific state from previous config revisions if possible.
|
||||||
/// Some examples are [ProxyWindowBase] and [PersistentProperties]
|
/// Some examples are [ProxyWindowBase] and [PersistentProperties]
|
||||||
|
@ -56,14 +58,10 @@ class Reloadable
|
||||||
public:
|
public:
|
||||||
explicit Reloadable(QObject* parent = nullptr): QObject(parent) {}
|
explicit Reloadable(QObject* parent = nullptr): QObject(parent) {}
|
||||||
|
|
||||||
// Called unconditionally in the reload phase, with nullptr if no source could be determined.
|
void reload(QObject* oldInstance = nullptr);
|
||||||
// If non null the old instance may or may not be of the same type, and should be checked
|
|
||||||
// by `onReload`.
|
|
||||||
virtual void onReload(QObject* oldInstance) = 0;
|
|
||||||
|
|
||||||
// TODO: onReload runs after initialization for reloadable objects created late
|
void classBegin() override {};
|
||||||
void classBegin() override {}
|
void componentComplete() override;
|
||||||
void componentComplete() override {}
|
|
||||||
|
|
||||||
// Reload objects in the parent->child graph recursively.
|
// Reload objects in the parent->child graph recursively.
|
||||||
static void reloadRecursive(QObject* newObj, QObject* oldRoot);
|
static void reloadRecursive(QObject* newObj, QObject* oldRoot);
|
||||||
|
@ -71,6 +69,17 @@ public:
|
||||||
static void reloadChildrenRecursive(QObject* newRoot, QObject* oldRoot);
|
static void reloadChildrenRecursive(QObject* newRoot, QObject* oldRoot);
|
||||||
|
|
||||||
QString mReloadableId;
|
QString mReloadableId;
|
||||||
|
bool reloadComplete = false;
|
||||||
|
EngineGeneration* engineGeneration = nullptr;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onReloadFinished();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Called unconditionally in the reload phase, with nullptr if no source could be determined.
|
||||||
|
// If non null the old instance may or may not be of the same type, and should be checked
|
||||||
|
// by `onReload`.
|
||||||
|
virtual void onReload(QObject* oldInstance) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static QObject* getChildByReloadId(QObject* parent, const QString& reloadId);
|
static QObject* getChildByReloadId(QObject* parent, const QString& reloadId);
|
||||||
|
|
|
@ -48,7 +48,7 @@ void SingletonRegistry::registerSingleton(const QUrl& url, Singleton* singleton)
|
||||||
|
|
||||||
void SingletonRegistry::onReload(SingletonRegistry* old) {
|
void SingletonRegistry::onReload(SingletonRegistry* old) {
|
||||||
for (auto [url, singleton]: this->registry.asKeyValueRange()) {
|
for (auto [url, singleton]: this->registry.asKeyValueRange()) {
|
||||||
singleton->onReload(old == nullptr ? nullptr : old->registry.value(url));
|
singleton->reload(old == nullptr ? nullptr : old->registry.value(url));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@ void TestPopupWindow::initiallyVisible() { // NOLINT
|
||||||
popup.setParentWindow(&parent);
|
popup.setParentWindow(&parent);
|
||||||
popup.setVisible(true);
|
popup.setVisible(true);
|
||||||
|
|
||||||
parent.onReload(nullptr);
|
parent.reload();
|
||||||
popup.onReload(nullptr);
|
popup.reload();
|
||||||
|
|
||||||
QVERIFY(popup.isVisible());
|
QVERIFY(popup.isVisible());
|
||||||
QVERIFY(popup.backingWindow()->isVisible());
|
QVERIFY(popup.backingWindow()->isVisible());
|
||||||
|
@ -36,8 +36,8 @@ void TestPopupWindow::reloadReparent() { // NOLINT
|
||||||
popup.setParentWindow(&parent);
|
popup.setParentWindow(&parent);
|
||||||
popup.setVisible(true);
|
popup.setVisible(true);
|
||||||
|
|
||||||
parent.onReload(nullptr);
|
parent.reload();
|
||||||
popup.onReload(nullptr);
|
popup.reload();
|
||||||
|
|
||||||
// second generation
|
// second generation
|
||||||
auto newParent = ProxyWindowBase();
|
auto newParent = ProxyWindowBase();
|
||||||
|
@ -51,8 +51,8 @@ void TestPopupWindow::reloadReparent() { // NOLINT
|
||||||
|
|
||||||
auto spy = QSignalSpy(oldWindow, &QWindow::visibleChanged);
|
auto spy = QSignalSpy(oldWindow, &QWindow::visibleChanged);
|
||||||
|
|
||||||
newParent.onReload(&parent);
|
newParent.reload(&parent);
|
||||||
newPopup.onReload(&popup);
|
newPopup.reload(&popup);
|
||||||
|
|
||||||
QVERIFY(newPopup.isVisible());
|
QVERIFY(newPopup.isVisible());
|
||||||
QVERIFY(newPopup.backingWindow()->isVisible());
|
QVERIFY(newPopup.backingWindow()->isVisible());
|
||||||
|
@ -69,15 +69,15 @@ void TestPopupWindow::reloadUnparent() { // NOLINT
|
||||||
popup.setParentWindow(&parent);
|
popup.setParentWindow(&parent);
|
||||||
popup.setVisible(true);
|
popup.setVisible(true);
|
||||||
|
|
||||||
parent.onReload(nullptr);
|
parent.reload();
|
||||||
popup.onReload(nullptr);
|
popup.reload();
|
||||||
|
|
||||||
// second generation
|
// second generation
|
||||||
auto newPopup = ProxyPopupWindow();
|
auto newPopup = ProxyPopupWindow();
|
||||||
|
|
||||||
// parent not set
|
// parent not set
|
||||||
newPopup.setVisible(true);
|
newPopup.setVisible(true);
|
||||||
newPopup.onReload(&popup);
|
newPopup.reload(&popup);
|
||||||
|
|
||||||
QVERIFY(!newPopup.isVisible());
|
QVERIFY(!newPopup.isVisible());
|
||||||
QVERIFY(!newPopup.backingWindow()->isVisible());
|
QVERIFY(!newPopup.backingWindow()->isVisible());
|
||||||
|
@ -88,7 +88,7 @@ void TestPopupWindow::invisibleWithoutParent() { // NOLINT
|
||||||
auto popup = ProxyPopupWindow();
|
auto popup = ProxyPopupWindow();
|
||||||
|
|
||||||
popup.setVisible(true);
|
popup.setVisible(true);
|
||||||
popup.onReload(nullptr);
|
popup.reload();
|
||||||
|
|
||||||
QVERIFY(!popup.isVisible());
|
QVERIFY(!popup.isVisible());
|
||||||
}
|
}
|
||||||
|
@ -102,8 +102,8 @@ void TestPopupWindow::moveWithParent() { // NOLINT
|
||||||
popup.setRelativeY(10);
|
popup.setRelativeY(10);
|
||||||
popup.setVisible(true);
|
popup.setVisible(true);
|
||||||
|
|
||||||
parent.onReload(nullptr);
|
parent.reload();
|
||||||
popup.onReload(nullptr);
|
popup.reload();
|
||||||
|
|
||||||
QCOMPARE(popup.x(), parent.x() + 10);
|
QCOMPARE(popup.x(), parent.x() + 10);
|
||||||
QCOMPARE(popup.y(), parent.y() + 10);
|
QCOMPARE(popup.y(), parent.y() + 10);
|
||||||
|
@ -121,8 +121,8 @@ void TestPopupWindow::attachParentLate() { // NOLINT
|
||||||
|
|
||||||
popup.setVisible(true);
|
popup.setVisible(true);
|
||||||
|
|
||||||
parent.onReload(nullptr);
|
parent.reload();
|
||||||
popup.onReload(nullptr);
|
popup.reload();
|
||||||
|
|
||||||
QVERIFY(!popup.isVisible());
|
QVERIFY(!popup.isVisible());
|
||||||
|
|
||||||
|
@ -139,14 +139,14 @@ void TestPopupWindow::reparentLate() { // NOLINT
|
||||||
popup.setParentWindow(&parent);
|
popup.setParentWindow(&parent);
|
||||||
popup.setVisible(true);
|
popup.setVisible(true);
|
||||||
|
|
||||||
parent.onReload(nullptr);
|
parent.reload();
|
||||||
popup.onReload(nullptr);
|
popup.reload();
|
||||||
|
|
||||||
QCOMPARE(popup.x(), parent.x());
|
QCOMPARE(popup.x(), parent.x());
|
||||||
QCOMPARE(popup.y(), parent.y());
|
QCOMPARE(popup.y(), parent.y());
|
||||||
|
|
||||||
auto parent2 = ProxyWindowBase();
|
auto parent2 = ProxyWindowBase();
|
||||||
parent2.onReload(nullptr);
|
parent2.reload();
|
||||||
|
|
||||||
parent2.backingWindow()->setX(10);
|
parent2.backingWindow()->setX(10);
|
||||||
parent2.backingWindow()->setY(10);
|
parent2.backingWindow()->setY(10);
|
||||||
|
@ -166,8 +166,8 @@ void TestPopupWindow::xMigrationFix() { // NOLINT
|
||||||
popup.setParentWindow(&parent);
|
popup.setParentWindow(&parent);
|
||||||
popup.setVisible(true);
|
popup.setVisible(true);
|
||||||
|
|
||||||
parent.onReload(nullptr);
|
parent.reload();
|
||||||
popup.onReload(nullptr);
|
popup.reload();
|
||||||
|
|
||||||
QCOMPARE(popup.x(), parent.x());
|
QCOMPARE(popup.x(), parent.x());
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ void Variants::onReload(QObject* oldInstance) {
|
||||||
|
|
||||||
auto* instance = qobject_cast<Reloadable*>(instanceObj);
|
auto* instance = qobject_cast<Reloadable*>(instanceObj);
|
||||||
|
|
||||||
if (instance != nullptr) instance->onReload(oldInstance);
|
if (instance != nullptr) instance->reload(oldInstance);
|
||||||
else Reloadable::reloadChildrenRecursive(instanceObj, oldInstance);
|
else Reloadable::reloadChildrenRecursive(instanceObj, oldInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ void Variants::updateVariants() {
|
||||||
this->mInstances.insert(variant, instance);
|
this->mInstances.insert(variant, instance);
|
||||||
|
|
||||||
if (this->loaded) {
|
if (this->loaded) {
|
||||||
if (auto* reloadable = qobject_cast<Reloadable*>(instance)) reloadable->onReload(nullptr);
|
if (auto* reloadable = qobject_cast<Reloadable*>(instance)) reloadable->reload(nullptr);
|
||||||
else Reloadable::reloadChildrenRecursive(instance, nullptr);
|
else Reloadable::reloadChildrenRecursive(instance, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ void WlSessionLock::updateSurfaces(WlSessionLock* old) {
|
||||||
instance->setScreen(screen);
|
instance->setScreen(screen);
|
||||||
|
|
||||||
auto* oldInstance = old == nullptr ? nullptr : old->surfaces.value(screen, nullptr);
|
auto* oldInstance = old == nullptr ? nullptr : old->surfaces.value(screen, nullptr);
|
||||||
instance->onReload(oldInstance);
|
instance->reload(oldInstance);
|
||||||
|
|
||||||
this->surfaces[screen] = instance;
|
this->surfaces[screen] = instance;
|
||||||
}
|
}
|
||||||
|
|
|
@ -197,7 +197,7 @@ void WaylandPanelInterface::onReload(QObject* oldInstance) {
|
||||||
QQmlEngine::setContextForObject(this->layer, QQmlEngine::contextForObject(this));
|
QQmlEngine::setContextForObject(this->layer, QQmlEngine::contextForObject(this));
|
||||||
|
|
||||||
auto* old = qobject_cast<WaylandPanelInterface*>(oldInstance);
|
auto* old = qobject_cast<WaylandPanelInterface*>(oldInstance);
|
||||||
this->layer->onReload(old != nullptr ? old->layer : nullptr);
|
this->layer->reload(old != nullptr ? old->layer : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
QQmlListProperty<QObject> WaylandPanelInterface::data() { return this->layer->data(); }
|
QQmlListProperty<QObject> WaylandPanelInterface::data() { return this->layer->data(); }
|
||||||
|
|
Loading…
Reference in a new issue