qtbridge_runtime/
qapp.rs

1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
3
4use cxx::UniquePtr;
5use qtbridge_type_lib::{QGuiApplication, QQmlApplicationEngine, QString, QVariant, QVariantMap};
6use crate::qml_register::QmlRegister;
7/// Runs a minimal application from an embedded QML file.
8///
9/// This macro is a convenience helper for small applications and examples.
10/// It embeds the given QML file at compile time using [`include_bytes!`],
11/// creates a [`QApp`] instance, loads the QML source, and starts the Qt
12/// event loop.
13///
14/// The macro is intended to be used directly in `main` and requires no
15/// additional setup beyond a valid QML file.
16///
17/// # Parameters
18///
19/// * `$path` – Path to a QML file, relative to the source file.
20///
21/// # Example
22///
23/// ```
24///# use qtbridge_runtime::run_simple_app;
25/// fn main() {
26///     run_simple_app!("qml/main.qml");
27/// }
28/// ```
29///
30/// # Notes
31///
32/// * The QML file is embedded into the binary at compile time.
33/// * This macro does not provide access to the [`QApp`] instance and is
34///   therefore best suited for simple applications.
35/// * For more advanced use cases, create and configure a [`QApp`] manually.
36#[macro_export]
37macro_rules! run_simple_app {
38    ($path:expr) => {{
39        let main_qml_bytes = include_bytes!($path);
40        $crate::QApp::new()
41            .load_qml(main_qml_bytes)
42            .run();
43    }};
44}
45
46/// This struct represents a Qt QML application and acts as the entry point for all applications.
47///
48/// QApp allows running QML code and injecting Rust objects into its context. Aside from the
49/// initialization of the backend logic this should be the only code in your main function.
50///
51/// # Example
52///
53/// A minimal “Hello World” application without a Rust backend:
54///
55/// ```rust
56///# use qtbridge_runtime::QApp;
57/// let prop = 42;
58///
59/// QApp::new()
60///     .load_qml(br#"
61///         import QtQuick
62///         import QtQuick.Controls
63///         Text {
64///             text: "Hello Rust!"
65///#            Component.onCompleted: closeTimer.start()
66///#            Timer {
67///#                id: closeTimer
68///#                interval: 1
69///#                onTriggered: Qt.quit()
70///#            }
71///         }"#)
72///     .run();
73/// ```
74pub struct QApp {
75    engine: UniquePtr<QQmlApplicationEngine>, // engine must be first field so its dropped before app
76    #[allow(dead_code)]
77    app: UniquePtr<QGuiApplication>,
78    initial_properties: QVariantMap,
79}
80
81impl QApp {
82    /// Creates a new application instance.
83    ///
84    /// The application object must be created before any QML or GUI-related
85    /// functionality is used.
86    pub fn new() -> Self {
87        let app = QGuiApplication::new();
88        let engine = QQmlApplicationEngine::new();
89        Self {
90            engine: engine,
91            app: app,
92            initial_properties: QVariantMap::default(),
93        }
94    }
95
96    /// Enters the Qt main event loop.
97    ///
98    /// This function blocks until the application exits and returns
99    /// the exit code provided by Qt. This function does not return a reference to
100    /// self and is usually the last call in a `main` function.
101    ///
102    /// # Returns
103    ///
104    /// The application exit code.
105    pub fn run(&mut self) -> i32 {
106        QGuiApplication::exec()
107    }
108
109    /// Add an initial property to the root object of the QML application.
110    ///
111    /// This method takes a string slice for the property name and a reference to a [`QVariant`]
112    /// as the property value. The property is stored internally and applied when [`QApp::load_qml`]
113    /// is called.
114    ///
115    /// ### Arguments
116    ///
117    /// * `id` - The name of the property to add to the root QML object.
118    /// * `value` - The value of the property.
119    ///
120    /// ### Example
121    ///
122    /// ```rust
123    ///# use qtbridge_runtime::QApp;
124    /// let prop = 42;
125    ///
126    /// QApp::new()
127    /// .add_initial_property("answer", &prop.into())
128    /// .load_qml(br#"
129    ///     import QtQuick
130    ///     import QtQuick.Controls
131    ///     ApplicationWindow {
132    ///         required property var answer
133    ///#        Component.onCompleted: closeTimer.start()
134    ///#        Timer {
135    ///#            id: closeTimer
136    ///#            interval: 1
137    ///#            onTriggered: Qt.quit()
138    ///#        }
139    ///     }"#)
140    /// .run();
141    /// ```
142    pub fn add_initial_property(&mut self, id: &str, value: &QVariant) -> &mut Self {
143        self.initial_properties.insert(&QString::from(id), value);
144        self
145    }
146
147    /// Sets the initial properties of the root object in the QML application.
148    ///
149    /// This method passes a list of [`str`]-[`QVariant`] pairs to the engine
150    /// and you can read and write the value in your QML code.
151    ///
152    /// # Returns
153    ///
154    /// A mutable reference to `self`, allowing method chaining.
155    ///
156    /// # Example
157    ///
158    /// ```rust
159    ///# use qtbridge_runtime::QApp;
160    /// let prop = 42;
161    ///
162    /// QApp::new()
163    ///     .with_initial_properties(&[
164    ///         ("answer", prop.into()),
165    ///     ])
166    ///     .load_qml(br#"
167    ///         import QtQuick
168    ///         import QtQuick.Controls
169    ///         ApplicationWindow {
170    ///             required property var answer
171    ///#            Component.onCompleted: closeTimer.start()
172    ///#            Timer {
173    ///#                id: closeTimer
174    ///#                interval: 1
175    ///#                onTriggered: Qt.quit()
176    ///#            }
177    ///         }"#)
178    ///     .run();
179    /// ```
180    /// # Returns
181    ///
182    /// A mutable reference to `self`, allowing method chaining.
183    pub fn with_initial_properties(&mut self, properties: &[(&str, QVariant)]) -> &mut Self {
184        self.engine.pin_mut().set_initial_properties(&properties.into());
185        self
186    }
187
188    /// Loads the main QML source code from an in-memory byte slice.
189    ///
190    /// This method loads the given QML source into the application's
191    /// QML engine. It is typically used to initialize the UI before
192    /// entering the Qt event loop.
193    ///
194    /// # Parameters
195    ///
196    /// * `code` – A byte slice containing the QML source.
197    ///
198    /// # Returns
199    ///
200    /// A mutable reference to `self`, allowing method chaining.
201    pub fn load_qml(&mut self, code: &[u8]) -> &mut Self {
202        if !self.initial_properties.is_empty() {
203            self.engine.pin_mut().set_initial_properties(&self.initial_properties);
204        }
205        self.engine.pin_mut().load_data(code);
206        self
207    }
208
209    /// Registers a QML type, making it instantiable from QML.
210    ///
211    /// This is a convenience wrapper that calls [`QmlRegister::register`]
212    /// for the given type `T`.
213    ///
214    /// ```rust
215    ///# use qtbridge::{QApp, qobject_impl};
216    /// #[derive(Default)]
217    /// pub struct Backend {
218    /// }
219    /// #[qobject_impl]
220    /// impl Backend {
221    /// }
222    ///
223    /// QApp::new()
224    ///     .register::<Backend>()
225    ///     .load_qml(br#"
226    ///         import QtQuick
227    ///         import QtQuick.Controls
228    ///#        import qtbridge_runtime
229    ///         ApplicationWindow {
230    ///             Backend {}
231    ///#            Component.onCompleted: closeTimer.start()
232    ///#            Timer {
233    ///#                id: closeTimer
234    ///#                interval: 1
235    ///#                onTriggered: Qt.quit()
236    ///#            }
237    ///      }"#)
238    ///     .run();
239    /// ```
240    pub fn register<T: QmlRegister>(&mut self) -> &mut Self {
241        T::register();
242        self
243    }
244
245    /// Sets the application name.
246    ///
247    /// # Parameters
248    ///
249    /// * `name` – The application name.
250    ///
251    /// # Returns
252    ///
253    /// A mutable reference to `self`, allowing method chaining.
254    pub fn application_name(&mut self, name: &str) -> &mut Self {
255        QGuiApplication::set_application_name(name);
256        self
257    }
258}