From 38d28085ab9274d132d5ed301ce95551c6ba11de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Morten=20S=C3=B8rvig?= <morten.sorvig@qt.io>
Date: Wed, 20 Mar 2024 13:23:53 +0100
Subject: [PATCH] Add example which demonstrates app cleanup

Don't call exec(), instead allocate objects on the
heap and then delete at quit() time.
---
 examples/application_exit/CMakeLists.txt | 22 +++++++++
 examples/application_exit/Main.qml       | 22 +++++++++
 examples/application_exit/main.cpp       | 57 ++++++++++++++++++++++++
 3 files changed, 101 insertions(+)
 create mode 100644 examples/application_exit/CMakeLists.txt
 create mode 100644 examples/application_exit/Main.qml
 create mode 100644 examples/application_exit/main.cpp

diff --git a/examples/application_exit/CMakeLists.txt b/examples/application_exit/CMakeLists.txt
new file mode 100644
index 0000000..cd7380c
--- /dev/null
+++ b/examples/application_exit/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(application_exit)
+
+find_package(Qt6 REQUIRED COMPONENTS Quick)
+
+qt_standard_project_setup(REQUIRES 6.6)
+
+qt_add_executable(application_exit
+    main.cpp
+)
+
+qt_add_qml_module(application_exit
+    URI applicationexit
+    VERSION 1.0
+    QML_FILES Main.qml
+)
+
+target_link_libraries(application_exit
+    PRIVATE Qt6::Quick
+)
+
diff --git a/examples/application_exit/Main.qml b/examples/application_exit/Main.qml
new file mode 100644
index 0000000..ecc308d
--- /dev/null
+++ b/examples/application_exit/Main.qml
@@ -0,0 +1,22 @@
+import QtQuick
+import QtQuick.Window
+
+Window {
+    width: 640
+    height: 480
+    visible: true
+
+    Text {
+        text: "Click To Quit"
+        anchors.fill: parent
+        horizontalAlignment: Text.AlignHCenter
+        verticalAlignment: Text.AlignVCenter
+    }
+
+    MouseArea {
+        anchors.fill: parent
+        onClicked: {
+            deleter.quit();
+        }
+    }
+}
diff --git a/examples/application_exit/main.cpp b/examples/application_exit/main.cpp
new file mode 100644
index 0000000..15d029a
--- /dev/null
+++ b/examples/application_exit/main.cpp
@@ -0,0 +1,57 @@
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+#include <QQmlContext>
+
+#include <emscripten.h>
+
+class Deleter;
+
+QGuiApplication *g_app = nullptr;
+QQmlApplicationEngine *g_engine = nullptr;
+
+class Deleter : public QObject
+{
+    Q_OBJECT
+public:
+    explicit Deleter(QObject *parent = nullptr)
+        : QObject(parent) {}
+
+    Q_INVOKABLE void quit() {
+        
+        // QCoreApplication does not support deleting itself from inside
+        // an event callback. Make a native zero-timer callback to make sure
+        // we are deleting without Qt on the stack.
+        emscripten_async_call([](void *deleter){
+            
+            // Delete self
+            delete static_cast<Deleter *>(deleter);
+
+            // Delete the QQmlApplicationEngine and QGuiApplication instances.
+            delete g_engine; g_engine = nullptr;
+            delete g_app; g_app = nullptr;
+
+            // Optinally trigger runtime exit as well.
+            emscripten_force_exit(0);
+        }, this, 0);
+    }
+};
+
+int main(int argc, char *argv[])
+{
+    // This example demonstrates how to cleanly exit a Qt application.
+    //
+    // This is done by creating the QML application engine and Qt application
+    // on the heap, and then returning from main() without calling exec().
+    //
+    // Qt for WebAssembly supports omitting the exec() call, since the native 
+    // event loop is already running by the time main() is called. Emscripten
+    // supports returning from main() without exiting the runtime, see the
+    // EXIT_RUNTIME linker option.
+    
+    g_app = new QGuiApplication(argc, argv);
+    g_engine = new QQmlApplicationEngine();
+    g_engine->loadFromModule("applicationexit", "Main");
+    g_engine->rootContext()->setContextProperty("deleter", new Deleter);
+}
+
+#include "main.moc"
-- 
GitLab