pytauri_core/ext_mod_impl/lib/
app.rs1use pyo3::prelude::*;
2use pyo3_utils::{
3 py_wrapper::{PyWrapper, PyWrapperT2},
4 ungil::UnsafeUngilExt,
5};
6
7use crate::{
8 ext_mod::{
9 debug_assert_app_handle_py_is_rs, AppHandle, PyAppHandleExt as _, RunEvent, TauriAppHandle,
10 },
11 tauri_runtime::Runtime,
12 utils::PyResultExt as _,
13};
14
15pub(crate) type TauriApp = tauri::App<Runtime>;
16
17#[pyclass(frozen, unsendable)]
18#[non_exhaustive]
19pub struct App(pub PyWrapper<PyWrapperT2<TauriApp>>);
20
21impl App {
22 #[cfg(feature = "__private")]
23 pub fn try_build(py: Python<'_>, app: TauriApp) -> PyResult<Self> {
24 app.get_or_init_py_app_handle(py)?;
26 Ok(Self(PyWrapper::new2(app)))
27 }
28
29 fn py_cb_to_rs_cb(
30 callback: PyObject,
31 app_handle: Py<AppHandle>,
32 ) -> impl FnMut(&TauriAppHandle, tauri::RunEvent) {
33 move |_app_handle, run_event| {
34 let py_app_handle: &Py<AppHandle> = &app_handle;
35 debug_assert_app_handle_py_is_rs(&app_handle, _app_handle);
36
37 Python::with_gil(|py| {
38 let py_run_event: RunEvent = RunEvent::from_tauri(py, run_event)
39 .expect("Failed to convert rust `RunEvent` to pyobject");
41
42 let callback = callback.bind(py);
43 let result = callback.call1((py_app_handle, py_run_event));
44 result.unwrap_unraisable_py_result(py, Some(callback), || {
48 "Python exception occurred in `App` run callback"
49 });
50 })
51 }
52 }
53
54 fn noop_callback(_: &TauriAppHandle, _: tauri::RunEvent) {}
55}
56
57#[pymethods]
58impl App {
59 #[pyo3(signature = (callback = None, /))]
60 fn run(&self, py: Python<'_>, callback: Option<PyObject>) -> PyResult<()> {
61 let app = self.0.try_take_inner()??;
62 let py_app_handle = app.py_app_handle().clone_ref(py);
63 unsafe {
64 py.allow_threads_unsend(app, move |app| {
66 match callback {
67 Some(callback) => app.run(Self::py_cb_to_rs_cb(callback, py_app_handle)),
68 None => app.run(Self::noop_callback),
69 }
70 Ok(())
71 })
72 }
73 }
74
75 #[pyo3(signature = (callback = None, /))]
76 fn run_return(&self, py: Python<'_>, callback: Option<PyObject>) -> PyResult<i32> {
77 let app = self.0.try_take_inner()??;
78 let py_app_handle = app.py_app_handle().clone_ref(py);
79 unsafe {
80 py.allow_threads_unsend(app, move |app| {
82 let exit_code = match callback {
83 Some(callback) => app.run_return(Self::py_cb_to_rs_cb(callback, py_app_handle)),
84 None => app.run_return(Self::noop_callback),
85 };
86 Ok(exit_code)
87 })
88 }
89 }
90
91 #[expect(deprecated)]
92 #[pyo3(signature = (callback = None, /))]
93 fn run_iteration(&self, py: Python<'_>, callback: Option<PyObject>) -> PyResult<()> {
94 let app = self.0.try_lock_inner_mut()??;
95 let py_app_handle = app.py_app_handle().clone_ref(py);
96 unsafe {
97 py.allow_threads_unsend(app, |mut app| {
99 match callback {
100 Some(callback) => {
101 app.run_iteration(Self::py_cb_to_rs_cb(callback, py_app_handle))
102 }
103 None => app.run_iteration(Self::noop_callback),
104 }
105 Ok(())
106 })
107 }
108 }
109
110 fn cleanup_before_exit(&self, py: Python<'_>) -> PyResult<()> {
111 unsafe {
113 py.allow_threads_unsend(self, |slf| {
114 let app = slf.0.try_lock_inner_ref()??;
115 app.cleanup_before_exit();
116 Ok(())
117 })
118 }
119 }
120
121 fn handle(&self, py: Python<'_>) -> PyResult<Py<AppHandle>> {
122 let app = self.0.try_lock_inner_ref()??;
123 let app_handle = app.py_app_handle().clone_ref(py);
125 Ok(app_handle)
126 }
127}