@@ -26,27 +26,46 @@ static QHash<QQmlEngine*, EngineGeneration*> g_generations; // NOLINT
2626
2727EngineGeneration::EngineGeneration (QmlScanner scanner)
2828 : scanner(std::move(scanner))
29- , interceptNetFactory(this ->scanner.qmldirIntercepts) {
30- g_generations.insert (&this ->engine , this );
29+ , interceptNetFactory(this ->scanner.qmldirIntercepts)
30+ , engine(new QQmlEngine()) {
31+ g_generations.insert (this ->engine , this );
3132
32- this ->engine . addUrlInterceptor (&this ->urlInterceptor );
33- this ->engine . setNetworkAccessManagerFactory (&this ->interceptNetFactory );
34- this ->engine . setIncubationController (&this ->delayedIncubationController );
33+ this ->engine -> addUrlInterceptor (&this ->urlInterceptor );
34+ this ->engine -> setNetworkAccessManagerFactory (&this ->interceptNetFactory );
35+ this ->engine -> setIncubationController (&this ->delayedIncubationController );
3536
36- this ->engine . addImageProvider (" icon" , new IconImageProvider ());
37+ this ->engine -> addImageProvider (" icon" , new IconImageProvider ());
3738
3839 QuickshellPlugin::runConstructGeneration (*this );
3940}
4041
4142EngineGeneration::~EngineGeneration () {
42- g_generations.remove (& this ->engine );
43- if ( this ->root != nullptr ) this -> root -> deleteLater () ;
43+ g_generations.remove (this ->engine );
44+ delete this ->engine ;
4445}
4546
4647void EngineGeneration::destroy () {
47- if (this ->root != nullptr ) {
48+ // Multiple generations can detect a reload at the same time.
49+ delete this ->watcher ;
50+ this ->watcher = nullptr ;
51+
52+ // Yes all of this is actually necessary.
53+ if (this ->engine != nullptr && this ->root != nullptr ) {
4854 QObject::connect (this ->root , &QObject::destroyed, this , [this ]() {
49- delete this ;
55+ // The timer seems to fix *one* of the possible qml item destructor crashes.
56+ QTimer::singleShot (0 , [this ]() {
57+ // Garbage is not collected during engine destruction.
58+ this ->engine ->collectGarbage ();
59+
60+ QObject::connect (this ->engine , &QObject::destroyed, this , [this ]() { delete this ; });
61+
62+ // Even after all of that there's still multiple failing assertions and segfaults.
63+ // Pray you don't hit one.
64+ // Note: it appeats *some* of the crashes are related to values owned by the generation.
65+ // Test by commenting the connect() above.
66+ this ->engine ->deleteLater ();
67+ this ->engine = nullptr ;
68+ });
5069 });
5170
5271 this ->root ->deleteLater ();
@@ -63,23 +82,26 @@ void EngineGeneration::onReload(EngineGeneration* old) {
6382 }
6483
6584 auto * app = QCoreApplication::instance ();
66- QObject::connect (& this ->engine , &QQmlEngine::quit, app, &QCoreApplication::quit);
67- QObject::connect (& this ->engine , &QQmlEngine::exit, app, &QCoreApplication::exit);
85+ QObject::connect (this ->engine , &QQmlEngine::quit, app, &QCoreApplication::quit);
86+ QObject::connect (this ->engine , &QQmlEngine::exit, app, &QCoreApplication::exit);
6887
6988 this ->root ->reload (old == nullptr ? nullptr : old->root );
7089 this ->singletonRegistry .onReload (old == nullptr ? nullptr : &old->singletonRegistry );
7190 this ->reloadComplete = true ;
7291 emit this ->reloadFinished ();
7392
7493 if (old != nullptr ) {
75- old->destroy ();
7694 QObject::connect (old, &QObject::destroyed, this , [this ]() { this ->postReload (); });
95+ old->destroy ();
7796 } else {
7897 this ->postReload ();
7998 }
8099}
81100
82101void EngineGeneration::postReload () {
102+ // This can be called on a generation during its destruction.
103+ if (this ->engine == nullptr || this ->root == nullptr ) return ;
104+
83105 QuickshellPlugin::runOnReload ();
84106 PostReloadHook::postReloadTree (this ->root );
85107 this ->singletonRegistry .onPostReload ();
@@ -132,7 +154,10 @@ void EngineGeneration::registerIncubationController(QQmlIncubationController* co
132154
133155 qCDebug (logIncubator) << " Registered incubation controller" << controller;
134156
135- if (this ->engine .incubationController () == &this ->delayedIncubationController ) {
157+ // This function can run during destruction.
158+ if (this ->engine == nullptr ) return ;
159+
160+ if (this ->engine ->incubationController () == &this ->delayedIncubationController ) {
136161 this ->assignIncubationController ();
137162 }
138163}
@@ -156,7 +181,10 @@ void EngineGeneration::deregisterIncubationController(QQmlIncubationController*
156181 qCDebug (logIncubator) << " Deregistered incubation controller" << controller;
157182 }
158183
159- if (this ->engine .incubationController () == controller) {
184+ // This function can run during destruction.
185+ if (this ->engine == nullptr ) return ;
186+
187+ if (this ->engine ->incubationController () == controller) {
160188 qCDebug (logIncubator
161189 ) << " Destroyed incubation controller was currently active, reassigning from pool" ;
162190 this ->assignIncubationController ();
@@ -183,7 +211,10 @@ void EngineGeneration::incubationControllerDestroyed() {
183211 qCDebug (logIncubator) << " Destroyed incubation controller" << controller << " deregistered" ;
184212 }
185213
186- if (this ->engine .incubationController () == controller) {
214+ // This function can run during destruction.
215+ if (this ->engine == nullptr ) return ;
216+
217+ if (this ->engine ->incubationController () == controller) {
187218 qCDebug (logIncubator
188219 ) << " Destroyed incubation controller was currently active, reassigning from pool" ;
189220 this ->assignIncubationController ();
@@ -198,7 +229,7 @@ void EngineGeneration::assignIncubationController() {
198229 qCDebug (logIncubator) << " Assigning incubation controller to engine:" << controller
199230 << " fallback:" << (controller == &this ->delayedIncubationController );
200231
201- this ->engine . setIncubationController (controller);
232+ this ->engine -> setIncubationController (controller);
202233}
203234
204235EngineGeneration* EngineGeneration::findObjectGeneration (QObject* object) {
0 commit comments