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 _, TauriError},
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 fn run_on_main_thread(&self, py: Python<'_>, handler: PyObject) -> PyResult<()> {
60 unsafe {
61 py.allow_threads_unsend(self, |slf| {
66 let app = slf.0.try_lock_inner_ref()??;
67 app.run_on_main_thread(move || {
68 Python::with_gil(|py| {
69 let handler = handler.bind(py);
70 let result = handler.call0();
71 result.unwrap_unraisable_py_result(py, Some(handler), || {
72 "Python exception occurred in `App::run_on_main_thread`"
73 });
74 })
75 })
76 .map_err(TauriError::from)
77 .map_err(PyErr::from)
78 })
79 }
80 }
81
82 fn handle(&self, py: Python<'_>) -> PyResult<Py<AppHandle>> {
83 let app = self.0.try_lock_inner_ref()??;
84 let app_handle = app.py_app_handle().clone_ref(py);
86 Ok(app_handle)
87 }
88
89 #[pyo3(signature = (callback = None, /))]
90 fn run(&self, py: Python<'_>, callback: Option<PyObject>) -> PyResult<()> {
91 let app = self.0.try_take_inner()??;
92 let py_app_handle = app.py_app_handle().clone_ref(py);
93 unsafe {
94 py.allow_threads_unsend(app, move |app| {
96 match callback {
97 Some(callback) => app.run(Self::py_cb_to_rs_cb(callback, py_app_handle)),
98 None => app.run(Self::noop_callback),
99 }
100 Ok(())
101 })
102 }
103 }
104
105 #[pyo3(signature = (callback = None, /))]
106 fn run_return(&self, py: Python<'_>, callback: Option<PyObject>) -> PyResult<i32> {
107 let app = self.0.try_take_inner()??;
108 let py_app_handle = app.py_app_handle().clone_ref(py);
109 unsafe {
110 py.allow_threads_unsend(app, move |app| {
112 let exit_code = match callback {
113 Some(callback) => app.run_return(Self::py_cb_to_rs_cb(callback, py_app_handle)),
114 None => app.run_return(Self::noop_callback),
115 };
116 Ok(exit_code)
117 })
118 }
119 }
120
121 #[expect(deprecated)]
122 #[pyo3(signature = (callback = None, /))]
123 fn run_iteration(&self, py: Python<'_>, callback: Option<PyObject>) -> PyResult<()> {
124 let app = self.0.try_lock_inner_mut()??;
125 let py_app_handle = app.py_app_handle().clone_ref(py);
126 unsafe {
127 py.allow_threads_unsend(app, |mut app| {
129 match callback {
130 Some(callback) => {
131 app.run_iteration(Self::py_cb_to_rs_cb(callback, py_app_handle))
132 }
133 None => app.run_iteration(Self::noop_callback),
134 }
135 Ok(())
136 })
137 }
138 }
139
140 fn cleanup_before_exit(&self, py: Python<'_>) -> PyResult<()> {
141 unsafe {
142 py.allow_threads_unsend(self, |slf| {
144 let app = slf.0.try_lock_inner_ref()??;
145 app.cleanup_before_exit();
146 Ok(())
147 })
148 }
149 }
150}