mirror of
https://github.com/slint-ui/slint.git
synced 2025-12-23 09:19:32 +00:00
spawn_local: initialize the platform if not initialized before the call
Take the opportunity to refactor a bit the way the global platform or context is accessed Fixes: #5871
This commit is contained in:
parent
d978a856fc
commit
43c7f57b0f
17 changed files with 163 additions and 145 deletions
|
|
@ -251,6 +251,93 @@ pub fn run_event_loop_until_quit() -> Result<(), PlatformError> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Spawns a [`Future`](core::future::Future) to execute in the Slint event loop.
|
||||
///
|
||||
/// This function is intended to be invoked only from the main Slint thread that runs the event loop.
|
||||
///
|
||||
/// For spawning a `Send` future from a different thread, this function should be called from a closure
|
||||
/// passed to [`invoke_from_event_loop()`].
|
||||
///
|
||||
/// This function is typically called from a UI callback.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// slint::spawn_local(async move {
|
||||
/// // your async code goes here
|
||||
/// }).unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// # Compatibility with Tokio and other runtimes
|
||||
///
|
||||
/// The runtime used to execute the future on the main thread is platform-dependent,
|
||||
/// for instance, it could be the winit event loop. Therefore, futures that assume a specific runtime
|
||||
/// may not work. This may be an issue if you call `.await` on a future created by another
|
||||
/// runtime, or pass the future directly to `spawn_local`.
|
||||
///
|
||||
/// Futures from the [smol](https://docs.rs/smol/latest/smol/) runtime always hand off their work to
|
||||
/// separate I/O threads that run in parallel to the Slint event loop.
|
||||
///
|
||||
/// The [Tokio](https://docs.rs/tokio/latest/tokio/index.html) runtime is to the following constraints:
|
||||
///
|
||||
/// * Tokio futures require entering the context of a global Tokio runtime.
|
||||
/// * Tokio futures aren't guaranteed to hand off their work to separate threads and may therefore not complete, because
|
||||
/// the Slint runtime can't drive the Tokio runtime.
|
||||
/// * Tokio futures require regular yielding to the Tokio runtime for fairness, a constraint that also can't be met by Slint.
|
||||
/// * Tokio's [current-thread schedule](https://docs.rs/tokio/latest/tokio/runtime/index.html#current-thread-scheduler)
|
||||
/// cannot be used in Slint main thread, because Slint cannot yield to it.
|
||||
///
|
||||
/// To address these constraints, use [async_compat](https://docs.rs/async-compat/latest/async_compat/index.html)'s [Compat::new()](https://docs.rs/async-compat/latest/async_compat/struct.Compat.html#method.new)
|
||||
/// to implicitly allocate a shared, multi-threaded Tokio runtime that will be used for Tokio futures.
|
||||
///
|
||||
/// The following little example demonstrates the use of Tokio's [`TcpStream`](https://docs.rs/tokio/latest/tokio/net/struct.TcpStream.html) to
|
||||
/// read from a network socket. The entire future passed to `spawn_local()` is wrapped in `Compat::new()` to make it run:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// // A dummy TCP server that once reports "Hello World"
|
||||
/// # i_slint_backend_testing::init_integration_test_with_mock_time();
|
||||
/// use std::io::Write;
|
||||
///
|
||||
/// let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
/// let local_addr = listener.local_addr().unwrap();
|
||||
/// let server = std::thread::spawn(move || {
|
||||
/// let mut stream = listener.incoming().next().unwrap().unwrap();
|
||||
/// stream.write("Hello World".as_bytes()).unwrap();
|
||||
/// });
|
||||
///
|
||||
/// let slint_future = async move {
|
||||
/// use tokio::io::AsyncReadExt;
|
||||
/// let mut stream = tokio::net::TcpStream::connect(local_addr).await.unwrap();
|
||||
/// let mut data = Vec::new();
|
||||
/// stream.read_to_end(&mut data).await.unwrap();
|
||||
/// assert_eq!(data, "Hello World".as_bytes());
|
||||
/// slint::quit_event_loop().unwrap();
|
||||
/// };
|
||||
///
|
||||
/// // Wrap the future that includes Tokio futures in async_compat's `Compat` to ensure
|
||||
/// // presence of a Tokio run-time.
|
||||
/// slint::spawn_local(async_compat::Compat::new(slint_future)).unwrap();
|
||||
///
|
||||
/// slint::run_event_loop_until_quit().unwrap();
|
||||
///
|
||||
/// server.join().unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// The use of `#[tokio::main]` is **not recommended**. If it's necessary to use though, wrap the call to enter the Slint
|
||||
/// event loop in a call to [`tokio::task::block_in_place`](https://docs.rs/tokio/latest/tokio/task/fn.block_in_place.html):
|
||||
///
|
||||
/// ```rust, no_run
|
||||
/// // Wrap the call to run_event_loop to ensure presence of a Tokio run-time.
|
||||
/// tokio::task::block_in_place(slint::run_event_loop).unwrap();
|
||||
/// ```
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
pub fn spawn_local<F: core::future::Future + 'static>(
|
||||
fut: F,
|
||||
) -> Result<JoinHandle<F::Output>, EventLoopError> {
|
||||
i_slint_backend_selector::with_global_context(|ctx| ctx.spawn_local(fut))
|
||||
.map_err(|_| EventLoopError::NoEventLoopProvider)?
|
||||
}
|
||||
|
||||
/// Include the code generated with the slint-build crate from the build script. After calling `slint_build::compile`
|
||||
/// in your `build.rs` build script, the use of this macro includes the generated Rust code and makes the exported types
|
||||
/// available for you to instantiate.
|
||||
|
|
|
|||
|
|
@ -41,6 +41,19 @@ mod executor {
|
|||
fn main() {
|
||||
i_slint_backend_testing::init_integration_test_with_mock_time();
|
||||
|
||||
// test_spawn_local_from_thread
|
||||
std::thread::spawn(|| {
|
||||
assert_eq!(
|
||||
slint::spawn_local(async {
|
||||
panic!("the future shouldn't be run since we're in a thread")
|
||||
})
|
||||
.map(drop),
|
||||
Err(slint::EventLoopError::NoEventLoopProvider)
|
||||
);
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
|
||||
slint::invoke_from_event_loop(|| {
|
||||
let handle = slint::spawn_local(async { String::from("Hello") }).unwrap();
|
||||
slint::spawn_local(async move { panic!("Aborted task") }).unwrap().abort();
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ extern crate alloc;
|
|||
use alloc::boxed::Box;
|
||||
use i_slint_core::platform::Platform;
|
||||
use i_slint_core::platform::PlatformError;
|
||||
use i_slint_core::SlintContext;
|
||||
|
||||
#[cfg(all(feature = "i-slint-backend-qt", not(no_qt), not(target_os = "android")))]
|
||||
fn create_qt_backend() -> Result<Box<dyn Platform + 'static>, PlatformError> {
|
||||
|
|
@ -133,8 +134,14 @@ cfg_if::cfg_if! {
|
|||
pub fn with_platform<R>(
|
||||
f: impl FnOnce(&dyn Platform) -> Result<R, PlatformError>,
|
||||
) -> Result<R, PlatformError> {
|
||||
with_global_context(|ctx| f(ctx.platform()))?
|
||||
}
|
||||
|
||||
/// Run the callback with the [`SlintContext`].
|
||||
/// Create the backend if it does not exist yet
|
||||
pub fn with_global_context<R>(f: impl FnOnce(&SlintContext) -> R) -> Result<R, PlatformError> {
|
||||
let mut platform_created = false;
|
||||
let result = i_slint_core::with_platform(
|
||||
let result = i_slint_core::with_global_context(
|
||||
|| {
|
||||
let backend = create_backend();
|
||||
platform_created = backend.is_ok();
|
||||
|
|
|
|||
|
|
@ -664,9 +664,9 @@ impl ElementHandle {
|
|||
|
||||
/// Simulates a double click (or touch tap) on the element at its center point.
|
||||
pub async fn double_click(&self, button: i_slint_core::platform::PointerEventButton) {
|
||||
let Ok(click_interval) = i_slint_core::with_platform(
|
||||
let Ok(click_interval) = i_slint_core::with_global_context(
|
||||
|| Err(i_slint_core::platform::PlatformError::NoPlatform),
|
||||
|platform| Ok(platform.click_interval()),
|
||||
|ctx| ctx.platform().click_interval(),
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -70,16 +70,21 @@ impl TestingClient {
|
|||
|
||||
let this = self.clone();
|
||||
self.message_loop_future.get_or_init(|| {
|
||||
i_slint_core::future::spawn_local({
|
||||
let this = this.clone();
|
||||
async move {
|
||||
message_loop(&this.server_addr, |request| {
|
||||
let this = this.clone();
|
||||
Box::pin(async move { this.handle_request(request).await })
|
||||
})
|
||||
.await;
|
||||
}
|
||||
})
|
||||
i_slint_core::with_global_context(
|
||||
|| panic!("uninitialized platform"),
|
||||
|context| {
|
||||
let this = this.clone();
|
||||
context
|
||||
.spawn_local(async move {
|
||||
message_loop(&this.server_addr, |request| {
|
||||
let this = this.clone();
|
||||
Box::pin(async move { this.handle_request(request).await })
|
||||
})
|
||||
.await;
|
||||
})
|
||||
.unwrap()
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ impl Instant {
|
|||
|
||||
fn duration_since_start() -> core::time::Duration {
|
||||
crate::context::GLOBAL_CONTEXT
|
||||
.with(|p| p.get().map(|p| p.0.platform.duration_since_start()))
|
||||
.with(|p| p.get().map(|p| p.platform().duration_since_start()))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ thread_local! {
|
|||
}
|
||||
|
||||
pub(crate) struct SlintContextInner {
|
||||
pub(crate) platform: Box<dyn Platform>,
|
||||
platform: Box<dyn Platform>,
|
||||
pub(crate) window_count: core::cell::RefCell<isize>,
|
||||
/// This property is read by all translations, and marked dirty when the language change
|
||||
/// so that every translated string gets re-translated
|
||||
|
|
@ -42,6 +42,11 @@ impl SlintContext {
|
|||
}))
|
||||
}
|
||||
|
||||
/// Return a reference to the platform abstraction
|
||||
pub fn platform(&self) -> &dyn Platform {
|
||||
&*self.0.platform
|
||||
}
|
||||
|
||||
/// Return an event proxy
|
||||
// FIXME: Make EvenLoopProxy clonable, and maybe wrap in a struct
|
||||
pub fn event_loop_proxy(&self) -> Option<Box<dyn EventLoopProxy>> {
|
||||
|
|
@ -49,7 +54,7 @@ impl SlintContext {
|
|||
}
|
||||
|
||||
#[cfg(target_has_atomic = "ptr")]
|
||||
/// Context specific version of [`slint::spawn_local`](crate::future::spawn_local)
|
||||
/// Context specific version of `slint::spawn_local`
|
||||
pub fn spawn_local<F: core::future::Future + 'static>(
|
||||
&self,
|
||||
fut: F,
|
||||
|
|
@ -62,18 +67,18 @@ impl SlintContext {
|
|||
}
|
||||
}
|
||||
|
||||
/// Internal function to access the platform abstraction.
|
||||
/// Internal function to access the context.
|
||||
/// The factory function is called if the platform abstraction is not yet
|
||||
/// initialized, and should be given by the platform_selector
|
||||
pub fn with_platform<R>(
|
||||
pub fn with_global_context<R>(
|
||||
factory: impl FnOnce() -> Result<Box<dyn Platform + 'static>, PlatformError>,
|
||||
f: impl FnOnce(&dyn Platform) -> Result<R, PlatformError>,
|
||||
f: impl FnOnce(&SlintContext) -> R,
|
||||
) -> Result<R, PlatformError> {
|
||||
GLOBAL_CONTEXT.with(|p| match p.get() {
|
||||
Some(ctx) => f(&*ctx.0.platform),
|
||||
Some(ctx) => Ok(f(ctx)),
|
||||
None => {
|
||||
crate::platform::set_platform(factory()?).map_err(PlatformError::SetPlatformError)?;
|
||||
f(&*p.get().unwrap().0.platform)
|
||||
Ok(f(p.get().unwrap()))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ impl<T: 'static> Wake for FutureRunner<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The return value of the [`spawn_local()`] function
|
||||
/// The return value of the `spawn_local()` function
|
||||
///
|
||||
/// Can be used to abort the future, or to get the value from a different thread with `.await`
|
||||
///
|
||||
|
|
@ -128,95 +128,7 @@ impl<T> JoinHandle<T> {
|
|||
// Safety: JoinHandle doesn't access the future, only the
|
||||
unsafe impl<T: Send> Send for JoinHandle<T> {}
|
||||
|
||||
/// Spawns a [`Future`] to execute in the Slint event loop.
|
||||
///
|
||||
/// This function is intended to be invoked only from the main Slint thread that runs the event loop.
|
||||
/// The event loop must be initialized prior to calling this function.
|
||||
///
|
||||
/// For spawning a `Send` future from a different thread, this function should be called from a closure
|
||||
/// passed to [`invoke_from_event_loop()`](crate::api::invoke_from_event_loop).
|
||||
///
|
||||
/// This function is typically called from a UI callback.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// slint::spawn_local(async move {
|
||||
/// // your async code goes here
|
||||
/// }).unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// # Compatibility with Tokio and other runtimes
|
||||
///
|
||||
/// The runtime used to execute the future on the main thread is platform-dependent,
|
||||
/// for instance, it could be the winit event loop. Therefore, futures that assume a specific runtime
|
||||
/// may not work. This may be an issue if you call `.await` on a future created by another
|
||||
/// runtime, or pass the future directly to `spawn_local`.
|
||||
///
|
||||
/// Futures from the [smol](https://docs.rs/smol/latest/smol/) runtime always hand off their work to
|
||||
/// separate I/O threads that run in parallel to the Slint event loop.
|
||||
///
|
||||
/// The [Tokio](https://docs.rs/tokio/latest/tokio/index.html) runtime is to the following constraints:
|
||||
///
|
||||
/// * Tokio futures require entering the context of a global Tokio runtime.
|
||||
/// * Tokio futures aren't guaranteed to hand off their work to separate threads and may therefore not complete, because
|
||||
/// the Slint runtime can't drive the Tokio runtime.
|
||||
/// * Tokio futures require regular yielding to the Tokio runtime for fairness, a constraint that also can't be met by Slint.
|
||||
/// * Tokio's [current-thread schedule](https://docs.rs/tokio/latest/tokio/runtime/index.html#current-thread-scheduler)
|
||||
/// cannot be used in Slint main thread, because Slint cannot yield to it.
|
||||
///
|
||||
/// To addresse these constraints, use [async_compat](https://docs.rs/async-compat/latest/async_compat/index.html)'s [Compat::new()](https://docs.rs/async-compat/latest/async_compat/struct.Compat.html#method.new)
|
||||
/// to implicitly allocate a shared, multi-threaded Tokio runtime that will be used for Tokio futures.
|
||||
///
|
||||
/// The following little example demonstrates the use of Tokio's [`TcpStream`](https://docs.rs/tokio/latest/tokio/net/struct.TcpStream.html) to
|
||||
/// read from a network socket. The entire future passed to `spawn_local()` is wrapped in `Compat::new()` to make it run:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// // A dummy TCP server that once reports "Hello World"
|
||||
/// # i_slint_backend_testing::init_integration_test_with_mock_time();
|
||||
/// use std::io::Write;
|
||||
///
|
||||
/// let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
/// let local_addr = listener.local_addr().unwrap();
|
||||
/// let server = std::thread::spawn(move || {
|
||||
/// let mut stream = listener.incoming().next().unwrap().unwrap();
|
||||
/// stream.write("Hello World".as_bytes()).unwrap();
|
||||
/// });
|
||||
///
|
||||
/// let slint_future = async move {
|
||||
/// use tokio::io::AsyncReadExt;
|
||||
/// let mut stream = tokio::net::TcpStream::connect(local_addr).await.unwrap();
|
||||
/// let mut data = Vec::new();
|
||||
/// stream.read_to_end(&mut data).await.unwrap();
|
||||
/// assert_eq!(data, "Hello World".as_bytes());
|
||||
/// slint::quit_event_loop().unwrap();
|
||||
/// };
|
||||
///
|
||||
/// // Wrap the future that includes Tokio futures in async_compat's `Compat` to ensure
|
||||
/// // presence of a Tokio run-time.
|
||||
/// slint::spawn_local(async_compat::Compat::new(slint_future)).unwrap();
|
||||
///
|
||||
/// slint::run_event_loop_until_quit().unwrap();
|
||||
///
|
||||
/// server.join().unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// The use of `#[tokio::main]` is **not recommended**. If it's necessary to use though, wrap the call to enter the Slint
|
||||
/// event loop in a call to [`tokio::task::block_in_place`](https://docs.rs/tokio/latest/tokio/task/fn.block_in_place.html):
|
||||
///
|
||||
/// ```rust, no_run
|
||||
/// // Wrap the call to run_event_loop to ensure presence of a Tokio run-time.
|
||||
/// tokio::task::block_in_place(slint::run_event_loop).unwrap();
|
||||
/// ```
|
||||
pub fn spawn_local<F: Future + 'static>(fut: F) -> Result<JoinHandle<F::Output>, EventLoopError> {
|
||||
// ensure we are in the backend's thread
|
||||
crate::context::GLOBAL_CONTEXT.with(|ctx| {
|
||||
let ctx = ctx.get().ok_or(EventLoopError::NoEventLoopProvider)?;
|
||||
spawn_local_with_ctx(ctx, fut)
|
||||
})
|
||||
}
|
||||
|
||||
/// Implementation for [SlintContext::spawn_locale]
|
||||
/// Implementation for [`SlintContext::spawn_local`]
|
||||
pub(crate) fn spawn_local_with_ctx<F: Future + 'static>(
|
||||
ctx: &SlintContext,
|
||||
fut: F,
|
||||
|
|
@ -232,16 +144,3 @@ pub(crate) fn spawn_local_with_ctx<F: Future + 'static>(
|
|||
arc.wake_by_ref();
|
||||
Ok(JoinHandle(arc))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_spawn_local_from_thread() {
|
||||
std::thread::spawn(|| {
|
||||
assert_eq!(
|
||||
spawn_local(async { panic!("the future shouldn't be run since we're in a thread") })
|
||||
.map(drop),
|
||||
Err(EventLoopError::NoEventLoopProvider)
|
||||
);
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1532,8 +1532,7 @@ impl TextInput {
|
|||
|
||||
WindowInner::from_pub(window_adapter.window())
|
||||
.ctx
|
||||
.0
|
||||
.platform
|
||||
.platform()
|
||||
.set_clipboard_text(&text[anchor..cursor], clipboard);
|
||||
}
|
||||
|
||||
|
|
@ -1548,7 +1547,7 @@ impl TextInput {
|
|||
clipboard: Clipboard,
|
||||
) {
|
||||
if let Some(text) =
|
||||
WindowInner::from_pub(window_adapter.window()).ctx.0.platform.clipboard_text(clipboard)
|
||||
WindowInner::from_pub(window_adapter.window()).ctx.platform().clipboard_text(clipboard)
|
||||
{
|
||||
self.preedit_text.set(Default::default());
|
||||
self.insert(&text, window_adapter, self_rc);
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ pub use graphics::PathData;
|
|||
#[doc(inline)]
|
||||
pub use graphics::BorderRadius;
|
||||
|
||||
pub use context::{with_platform, SlintContext};
|
||||
pub use context::{with_global_context, SlintContext};
|
||||
|
||||
#[cfg(not(slint_int_coord))]
|
||||
pub type Coord = f32;
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ pub fn update_timers_and_animations() {
|
|||
pub fn duration_until_next_timer_update() -> Option<core::time::Duration> {
|
||||
crate::timers::TimerList::next_timeout().map(|timeout| {
|
||||
let duration_since_start = crate::context::GLOBAL_CONTEXT
|
||||
.with(|p| p.get().map(|p| p.0.platform.duration_since_start()))
|
||||
.with(|p| p.get().map(|p| p.platform().duration_since_start()))
|
||||
.unwrap_or_default();
|
||||
core::time::Duration::from_millis(
|
||||
timeout.0.saturating_sub(duration_since_start.as_millis() as u64),
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ pub extern "C" fn send_keyboard_string_sequence(
|
|||
#[doc(hidden)]
|
||||
pub fn debug_log_impl(args: core::fmt::Arguments) {
|
||||
crate::context::GLOBAL_CONTEXT.with(|p| match p.get() {
|
||||
Some(ctx) => ctx.0.platform.debug_log(args),
|
||||
Some(ctx) => ctx.platform().debug_log(args),
|
||||
None => default_debug_log(args),
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -554,7 +554,7 @@ impl WindowInner {
|
|||
crate::animations::update_animations();
|
||||
|
||||
// handle multiple press release
|
||||
event = self.click_state.check_repeat(event, self.ctx.0.platform.click_interval());
|
||||
event = self.click_state.check_repeat(event, self.ctx.platform().click_interval());
|
||||
|
||||
let pressed_event = matches!(event, MouseEvent::Pressed { .. });
|
||||
let released_event = matches!(event, MouseEvent::Released { .. });
|
||||
|
|
@ -625,7 +625,7 @@ impl WindowInner {
|
|||
|
||||
if last_top_item != mouse_input_state.top_item_including_delayed() {
|
||||
self.click_state.reset();
|
||||
self.click_state.check_repeat(event, self.ctx.0.platform.click_interval());
|
||||
self.click_state.check_repeat(event, self.ctx.platform().click_interval());
|
||||
}
|
||||
|
||||
self.mouse_input_state.set(mouse_input_state);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use i_slint_core::window::WindowInner;
|
|||
use i_slint_core::{PathData, SharedVector};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -572,11 +573,8 @@ impl ComponentCompiler {
|
|||
/// was not in place (i.e: load from the file system following the include paths)
|
||||
pub fn set_file_loader(
|
||||
&mut self,
|
||||
file_loader_fallback: impl Fn(
|
||||
&Path,
|
||||
) -> core::pin::Pin<
|
||||
Box<dyn core::future::Future<Output = Option<std::io::Result<String>>>>,
|
||||
> + 'static,
|
||||
file_loader_fallback: impl Fn(&Path) -> core::pin::Pin<Box<dyn Future<Output = Option<std::io::Result<String>>>>>
|
||||
+ 'static,
|
||||
) {
|
||||
self.config.open_import_fallback =
|
||||
Some(Rc::new(move |path| file_loader_fallback(Path::new(path.as_str()))));
|
||||
|
|
@ -737,11 +735,8 @@ impl Compiler {
|
|||
/// was not in place (i.e: load from the file system following the include paths)
|
||||
pub fn set_file_loader(
|
||||
&mut self,
|
||||
file_loader_fallback: impl Fn(
|
||||
&Path,
|
||||
) -> core::pin::Pin<
|
||||
Box<dyn core::future::Future<Output = Option<std::io::Result<String>>>>,
|
||||
> + 'static,
|
||||
file_loader_fallback: impl Fn(&Path) -> core::pin::Pin<Box<dyn Future<Output = Option<std::io::Result<String>>>>>
|
||||
+ 'static,
|
||||
) {
|
||||
self.config.open_import_fallback =
|
||||
Some(Rc::new(move |path| file_loader_fallback(Path::new(path.as_str()))));
|
||||
|
|
@ -1572,6 +1567,14 @@ pub fn run_event_loop() -> Result<(), PlatformError> {
|
|||
i_slint_backend_selector::with_platform(|b| b.run_event_loop())
|
||||
}
|
||||
|
||||
/// Spawns a [`Future`] to execute in the Slint event loop.
|
||||
///
|
||||
/// See the documentation of `slint::spawn_local()` for more info
|
||||
pub fn spawn_local<F: Future + 'static>(fut: F) -> Result<JoinHandle<F::Output>, EventLoopError> {
|
||||
i_slint_backend_selector::with_global_context(|ctx| ctx.spawn_local(fut))
|
||||
.map_err(|_| EventLoopError::NoEventLoopProvider)?
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "internal", target_arch = "wasm32"))]
|
||||
/// Spawn the event loop.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ pub fn run_in_ui_thread<F: Future<Output = ()> + 'static>(
|
|||
}
|
||||
}
|
||||
i_slint_core::api::invoke_from_event_loop(move || {
|
||||
i_slint_core::future::spawn_local(create_future()).unwrap();
|
||||
slint::spawn_local(create_future()).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ fn invoke_from_event_loop_wrapped_in_promise(
|
|||
pub fn run_in_ui_thread<F: Future<Output = ()> + 'static>(
|
||||
create_future: impl Send + FnOnce() -> F + 'static,
|
||||
) -> Result<(), String> {
|
||||
i_slint_core::future::spawn_local(create_future()).map_err(|e| e.to_string())?;
|
||||
slint::spawn_local(create_future()).map_err(|e| e.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@ fn start_fswatch_thread(args: Cli) -> Result<Arc<Mutex<notify::RecommendedWatche
|
|||
let args = args.clone();
|
||||
let w2 = w2.clone();
|
||||
i_slint_core::api::invoke_from_event_loop(move || {
|
||||
i_slint_core::future::spawn_local(reload(args, w2)).unwrap();
|
||||
slint_interpreter::spawn_local(reload(args, w2)).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue