Python: Add support for invoke_from_event_loop

Fixes #4203
This commit is contained in:
Simon Hausmann 2024-03-05 16:02:27 +01:00 committed by Simon Hausmann
parent 7ada390251
commit 855cd0df14
3 changed files with 47 additions and 0 deletions

View file

@ -63,6 +63,19 @@ fn set_xdg_app_id(app_id: String) -> Result<(), errors::PyPlatformError> {
slint_interpreter::set_xdg_app_id(app_id).map_err(|e| e.into())
}
#[gen_stub_pyfunction]
#[pyfunction]
fn invoke_from_event_loop(callable: Py<PyAny>) -> Result<(), errors::PyEventLoopError> {
slint_interpreter::invoke_from_event_loop(move || {
Python::attach(|py| {
if let Err(err) = callable.call0(py) {
eprintln!("Error invoking python callable from closure invoked via slint::invoke_from_event_loop: {}", err)
}
})
})
.map_err(|e| e.into())
}
use pyo3::prelude::*;
#[pymodule]
@ -90,6 +103,7 @@ fn slint(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(run_event_loop, m)?)?;
m.add_function(wrap_pyfunction!(quit_event_loop, m)?)?;
m.add_function(wrap_pyfunction!(set_xdg_app_id, m)?)?;
m.add_function(wrap_pyfunction!(invoke_from_event_loop, m)?)?;
Ok(())
}

View file

@ -143,6 +143,7 @@ class Timer:
def restart(self) -> None: ...
def set_xdg_app_id(app_id: str) -> None: ...
def invoke_from_event_loop(callable: typing.Callable[[], None]) -> None: ...
def run_event_loop() -> None: ...
def quit_event_loop() -> None: ...

View file

@ -0,0 +1,32 @@
# Copyright © SixtyFPS GmbH <info@slint.dev>
# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
from slint import slint as native
import threading
from datetime import timedelta
was_here = False
def test_threads() -> None:
global was_here
was_here = False
def invoked_from_event_loop() -> None:
global was_here
was_here = True
native.quit_event_loop()
def quit() -> None:
native.invoke_from_event_loop(invoked_from_event_loop)
thr = threading.Thread(target=quit)
native.Timer.single_shot(timedelta(milliseconds=10), lambda: thr.start())
fallback_timer = native.Timer()
fallback_timer.start(
native.TimerMode.Repeated, timedelta(milliseconds=100), native.quit_event_loop
)
native.run_event_loop()
thr.join()
fallback_timer.stop()
assert was_here