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}