Skip to content

Commit 6eb68d2

Browse files
committed
core/reloader: fix late creation of Reloadable types
1 parent 6181234 commit 6eb68d2

File tree

13 files changed

+87
-48
lines changed

13 files changed

+87
-48
lines changed

src/core/floatingwindow.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ void FloatingWindowInterface::onReload(QObject* oldInstance) {
4343
QQmlEngine::setContextForObject(this->window, QQmlEngine::contextForObject(this));
4444

4545
auto* old = qobject_cast<FloatingWindowInterface*>(oldInstance);
46-
this->window->onReload(old != nullptr ? old->window : nullptr);
46+
this->window->reload(old != nullptr ? old->window : nullptr);
4747
}
4848

4949
QQmlListProperty<QObject> FloatingWindowInterface::data() { return this->window->data(); }

src/core/generation.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <qqmlengine.h>
1414
#include <qqmlincubator.h>
1515
#include <qtimer.h>
16+
#include <qtmetamacros.h>
1617

1718
#include "iconimageprovider.hpp"
1819
#include "incubator.hpp"
@@ -54,8 +55,10 @@ void EngineGeneration::onReload(EngineGeneration* old) {
5455
QObject::connect(&this->engine, &QQmlEngine::quit, app, &QCoreApplication::quit);
5556
QObject::connect(&this->engine, &QQmlEngine::exit, app, &QCoreApplication::exit);
5657

57-
this->root->onReload(old == nullptr ? nullptr : old->root);
58+
this->root->reload(old == nullptr ? nullptr : old->root);
5859
this->singletonRegistry.onReload(old == nullptr ? nullptr : &old->singletonRegistry);
60+
this->reloadComplete = true;
61+
emit this->reloadFinished();
5962

6063
if (old != nullptr) {
6164
QTimer::singleShot(0, [this, old]() {

src/core/generation.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ class EngineGeneration: public QObject {
4141
SingletonRegistry singletonRegistry;
4242
QFileSystemWatcher* watcher = nullptr;
4343
DelayedQmlIncubationController delayedIncubationController;
44+
bool reloadComplete = false;
4445

4546
signals:
4647
void filesChanged();
48+
void reloadFinished();
4749

4850
private slots:
4951
void incubationControllerDestroyed();

src/core/lazyloader.cpp

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@ void LazyLoader::onReload(QObject* oldInstance) {
2323

2424
if (this->mItem != nullptr) {
2525
if (auto* reloadable = qobject_cast<Reloadable*>(this->mItem)) {
26-
reloadable->onReload(old == nullptr ? nullptr : old->mItem);
26+
reloadable->reload(old == nullptr ? nullptr : old->mItem);
2727
} else {
2828
Reloadable::reloadRecursive(this->mItem, old);
2929
}
3030
}
31-
32-
this->postReload = true;
3331
}
3432

3533
QObject* LazyLoader::item() {
@@ -48,14 +46,6 @@ void LazyLoader::setItem(QObject* item) {
4846

4947
if (item != nullptr) {
5048
item->setParent(this);
51-
52-
if (this->postReload) {
53-
if (auto* reloadable = qobject_cast<Reloadable*>(this->mItem)) {
54-
reloadable->onReload(nullptr);
55-
} else {
56-
Reloadable::reloadRecursive(this->mItem, nullptr);
57-
}
58-
}
5949
}
6050

6151
this->targetActive = this->isActive();
@@ -160,7 +150,7 @@ void LazyLoader::setSource(QString source) {
160150
}
161151

162152
void LazyLoader::incubateIfReady(bool overrideReloadCheck) {
163-
if (!(this->postReload || overrideReloadCheck) || !(this->targetLoading || this->targetActive)
153+
if (!(this->reloadComplete || overrideReloadCheck) || !(this->targetLoading || this->targetActive)
164154
|| this->mComponent == nullptr || this->incubator != nullptr)
165155
{
166156
return;

src/core/lazyloader.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,6 @@ private slots:
152152
void incubateIfReady(bool overrideReloadCheck = false);
153153
void waitForObjectCreation();
154154

155-
bool postReload = false;
156155
bool targetLoading = false;
157156
bool targetActive = false;
158157
QObject* mItem = nullptr;

src/core/main.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#include <qguiapplication.h>
1111
#include <qhash.h>
1212
#include <qlogging.h>
13-
#include <qobject.h>
1413
#include <qquickwindow.h>
1514
#include <qstandardpaths.h>
1615
#include <qstring.h>

src/core/reload.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,43 @@
44
#include <qobject.h>
55
#include <qqmllist.h>
66

7+
#include "generation.hpp"
8+
9+
void Reloadable::componentComplete() {
10+
this->engineGeneration = EngineGeneration::findObjectGeneration(this);
11+
12+
if (this->engineGeneration != nullptr) {
13+
// When called this way there is no chance a reload will have old data,
14+
// but this will at least help prevent weird behaviors due to never getting a reload.
15+
if (this->engineGeneration->reloadComplete) this->reload();
16+
else {
17+
QObject::connect(
18+
this->engineGeneration,
19+
&EngineGeneration::reloadFinished,
20+
this,
21+
&Reloadable::onReloadFinished
22+
);
23+
}
24+
}
25+
}
26+
27+
void Reloadable::reload(QObject* oldInstance) {
28+
if (this->reloadComplete) return;
29+
this->onReload(oldInstance);
30+
this->reloadComplete = true;
31+
32+
if (this->engineGeneration != nullptr) {
33+
QObject::disconnect(
34+
this->engineGeneration,
35+
&EngineGeneration::reloadFinished,
36+
this,
37+
&Reloadable::onReloadFinished
38+
);
39+
}
40+
}
41+
42+
void Reloadable::onReloadFinished() { this->reload(nullptr); }
43+
744
void ReloadPropagator::onReload(QObject* oldInstance) {
845
auto* old = qobject_cast<ReloadPropagator*>(oldInstance);
946

@@ -13,7 +50,7 @@ void ReloadPropagator::onReload(QObject* oldInstance) {
1350
auto* oldChild = old == nullptr || old->mChildren.length() <= i
1451
? nullptr
1552
: qobject_cast<Reloadable*>(old->mChildren.at(i));
16-
newChild->onReload(oldChild);
53+
newChild->reload(oldChild);
1754
} else {
1855
Reloadable::reloadRecursive(newChild, oldInstance);
1956
}

src/core/reload.hpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <qqmlparserstatus.h>
88
#include <qtmetamacros.h>
99

10+
class EngineGeneration;
11+
1012
///! The base class of all types that can be reloaded.
1113
/// Reloadables will attempt to take specific state from previous config revisions if possible.
1214
/// Some examples are [ProxyWindowBase] and [PersistentProperties]
@@ -56,21 +58,28 @@ class Reloadable
5658
public:
5759
explicit Reloadable(QObject* parent = nullptr): QObject(parent) {}
5860

59-
// Called unconditionally in the reload phase, with nullptr if no source could be determined.
60-
// If non null the old instance may or may not be of the same type, and should be checked
61-
// by `onReload`.
62-
virtual void onReload(QObject* oldInstance) = 0;
61+
void reload(QObject* oldInstance = nullptr);
6362

64-
// TODO: onReload runs after initialization for reloadable objects created late
65-
void classBegin() override {}
66-
void componentComplete() override {}
63+
void classBegin() override {};
64+
void componentComplete() override;
6765

6866
// Reload objects in the parent->child graph recursively.
6967
static void reloadRecursive(QObject* newObj, QObject* oldRoot);
7068
// Same as above but does not reload the passed object, only its children.
7169
static void reloadChildrenRecursive(QObject* newRoot, QObject* oldRoot);
7270

7371
QString mReloadableId;
72+
bool reloadComplete = false;
73+
EngineGeneration* engineGeneration = nullptr;
74+
75+
private slots:
76+
void onReloadFinished();
77+
78+
protected:
79+
// Called unconditionally in the reload phase, with nullptr if no source could be determined.
80+
// If non null the old instance may or may not be of the same type, and should be checked
81+
// by `onReload`.
82+
virtual void onReload(QObject* oldInstance) = 0;
7483

7584
private:
7685
static QObject* getChildByReloadId(QObject* parent, const QString& reloadId);

src/core/singleton.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ void SingletonRegistry::registerSingleton(const QUrl& url, Singleton* singleton)
4848

4949
void SingletonRegistry::onReload(SingletonRegistry* old) {
5050
for (auto [url, singleton]: this->registry.asKeyValueRange()) {
51-
singleton->onReload(old == nullptr ? nullptr : old->registry.value(url));
51+
singleton->reload(old == nullptr ? nullptr : old->registry.value(url));
5252
}
5353
}
5454

src/core/test/popupwindow.cpp

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ void TestPopupWindow::initiallyVisible() { // NOLINT
1616
popup.setParentWindow(&parent);
1717
popup.setVisible(true);
1818

19-
parent.onReload(nullptr);
20-
popup.onReload(nullptr);
19+
parent.reload();
20+
popup.reload();
2121

2222
QVERIFY(popup.isVisible());
2323
QVERIFY(popup.backingWindow()->isVisible());
@@ -36,8 +36,8 @@ void TestPopupWindow::reloadReparent() { // NOLINT
3636
popup.setParentWindow(&parent);
3737
popup.setVisible(true);
3838

39-
parent.onReload(nullptr);
40-
popup.onReload(nullptr);
39+
parent.reload();
40+
popup.reload();
4141

4242
// second generation
4343
auto newParent = ProxyWindowBase();
@@ -51,8 +51,8 @@ void TestPopupWindow::reloadReparent() { // NOLINT
5151

5252
auto spy = QSignalSpy(oldWindow, &QWindow::visibleChanged);
5353

54-
newParent.onReload(&parent);
55-
newPopup.onReload(&popup);
54+
newParent.reload(&parent);
55+
newPopup.reload(&popup);
5656

5757
QVERIFY(newPopup.isVisible());
5858
QVERIFY(newPopup.backingWindow()->isVisible());
@@ -69,15 +69,15 @@ void TestPopupWindow::reloadUnparent() { // NOLINT
6969
popup.setParentWindow(&parent);
7070
popup.setVisible(true);
7171

72-
parent.onReload(nullptr);
73-
popup.onReload(nullptr);
72+
parent.reload();
73+
popup.reload();
7474

7575
// second generation
7676
auto newPopup = ProxyPopupWindow();
7777

7878
// parent not set
7979
newPopup.setVisible(true);
80-
newPopup.onReload(&popup);
80+
newPopup.reload(&popup);
8181

8282
QVERIFY(!newPopup.isVisible());
8383
QVERIFY(!newPopup.backingWindow()->isVisible());
@@ -88,7 +88,7 @@ void TestPopupWindow::invisibleWithoutParent() { // NOLINT
8888
auto popup = ProxyPopupWindow();
8989

9090
popup.setVisible(true);
91-
popup.onReload(nullptr);
91+
popup.reload();
9292

9393
QVERIFY(!popup.isVisible());
9494
}
@@ -102,8 +102,8 @@ void TestPopupWindow::moveWithParent() { // NOLINT
102102
popup.setRelativeY(10);
103103
popup.setVisible(true);
104104

105-
parent.onReload(nullptr);
106-
popup.onReload(nullptr);
105+
parent.reload();
106+
popup.reload();
107107

108108
QCOMPARE(popup.x(), parent.x() + 10);
109109
QCOMPARE(popup.y(), parent.y() + 10);
@@ -121,8 +121,8 @@ void TestPopupWindow::attachParentLate() { // NOLINT
121121

122122
popup.setVisible(true);
123123

124-
parent.onReload(nullptr);
125-
popup.onReload(nullptr);
124+
parent.reload();
125+
popup.reload();
126126

127127
QVERIFY(!popup.isVisible());
128128

@@ -139,14 +139,14 @@ void TestPopupWindow::reparentLate() { // NOLINT
139139
popup.setParentWindow(&parent);
140140
popup.setVisible(true);
141141

142-
parent.onReload(nullptr);
143-
popup.onReload(nullptr);
142+
parent.reload();
143+
popup.reload();
144144

145145
QCOMPARE(popup.x(), parent.x());
146146
QCOMPARE(popup.y(), parent.y());
147147

148148
auto parent2 = ProxyWindowBase();
149-
parent2.onReload(nullptr);
149+
parent2.reload();
150150

151151
parent2.backingWindow()->setX(10);
152152
parent2.backingWindow()->setY(10);
@@ -166,8 +166,8 @@ void TestPopupWindow::xMigrationFix() { // NOLINT
166166
popup.setParentWindow(&parent);
167167
popup.setVisible(true);
168168

169-
parent.onReload(nullptr);
170-
popup.onReload(nullptr);
169+
parent.reload();
170+
popup.reload();
171171

172172
QCOMPARE(popup.x(), parent.x());
173173

0 commit comments

Comments
 (0)