// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 use crate::api::PlatformError; use crate::platform::{EventLoopProxy, Platform}; #[cfg(all(not(feature = "std"), feature = "unsafe-single-threaded"))] use crate::thread_local; use crate::Property; #[cfg(not(feature = "std"))] use alloc::boxed::Box; use alloc::rc::Rc; thread_local! { pub(crate) static GLOBAL_CONTEXT : once_cell::unsync::OnceCell = const { once_cell::unsync::OnceCell::new() } } pub(crate) struct SlintContextInner { platform: Box, pub(crate) window_count: core::cell::RefCell, /// This property is read by all translations, and marked dirty when the language change /// so that every translated string gets re-translated pub(crate) translations_dirty: core::pin::Pin>>, pub(crate) window_shown_hook: core::cell::RefCell)>>>, } /// This context is meant to hold the state and the backend. /// Currently it is not possible to have several platform at the same time in one process, but in the future it might be. /// See issue #4294 #[derive(Clone)] pub struct SlintContext(pub(crate) Rc); impl SlintContext { /// Create a new context with a given platform pub fn new(platform: Box) -> Self { Self(Rc::new(SlintContextInner { platform, window_count: 0.into(), translations_dirty: Box::pin(Property::new_named((), "SlintContext::translations")), window_shown_hook: Default::default(), })) } /// 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> { self.0.platform.new_event_loop_proxy() } #[cfg(target_has_atomic = "ptr")] /// Context specific version of `slint::spawn_local` pub fn spawn_local( &self, fut: F, ) -> Result, crate::api::EventLoopError> { crate::future::spawn_local_with_ctx(self, fut) } pub fn run_event_loop(&self) -> Result<(), PlatformError> { self.0.platform.run_event_loop() } } /// 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_global_context( factory: impl FnOnce() -> Result, PlatformError>, f: impl FnOnce(&SlintContext) -> R, ) -> Result { GLOBAL_CONTEXT.with(|p| match p.get() { Some(ctx) => Ok(f(ctx)), None => { crate::platform::set_platform(factory()?).map_err(PlatformError::SetPlatformError)?; Ok(f(p.get().unwrap())) } }) } /// Internal function to set a hook that's invoked whenever a slint::Window is shown. This /// is used by the system testing module. Returns a previously set hook, if any. pub fn set_window_shown_hook( hook: Option)>>, ) -> Result)>>, PlatformError> { GLOBAL_CONTEXT.with(|p| match p.get() { Some(ctx) => Ok(ctx.0.window_shown_hook.replace(hook)), None => Err(PlatformError::NoPlatform), }) }