mirror of
https://github.com/slint-ui/slint.git
synced 2025-11-01 20:31:27 +00:00
Winit: remove maybe_loop_instance thread local
In the future, the plain winit::event_loop::EventLoop won't be usable for window creation anymore. There are two places where we need it: 1. From places where we also have access to the shared backend data. 2. From the top-level create_winit_window() function. The latter we have to eliminate in the future, so might as well do it now and clean up to have one thread local less.
This commit is contained in:
parent
fe56fdd5e4
commit
cd29bdd367
3 changed files with 85 additions and 113 deletions
|
|
@ -18,8 +18,6 @@ use corelib::platform::PlatformError;
|
|||
use corelib::window::*;
|
||||
use i_slint_core as corelib;
|
||||
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
use raw_window_handle::HasDisplayHandle;
|
||||
#[allow(unused_imports)]
|
||||
use std::cell::{RefCell, RefMut};
|
||||
use std::rc::Rc;
|
||||
|
|
@ -28,17 +26,13 @@ use winit::event_loop::ActiveEventLoop;
|
|||
use winit::event_loop::ControlFlow;
|
||||
use winit::window::ResizeDirection;
|
||||
pub(crate) struct NotRunningEventLoop {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(crate) clipboard: Rc<std::cell::RefCell<crate::clipboard::ClipboardPair>>,
|
||||
pub(crate) instance: winit::event_loop::EventLoop<SlintUserEvent>,
|
||||
}
|
||||
|
||||
impl NotRunningEventLoop {
|
||||
pub(crate) fn new(
|
||||
builder: Option<winit::event_loop::EventLoopBuilder<SlintUserEvent>>,
|
||||
mut builder: winit::event_loop::EventLoopBuilder<SlintUserEvent>,
|
||||
) -> Result<Self, PlatformError> {
|
||||
let mut builder = builder.unwrap_or_else(winit::event_loop::EventLoop::with_user_event);
|
||||
|
||||
#[cfg(all(unix, not(target_vendor = "apple")))]
|
||||
{
|
||||
#[cfg(feature = "wayland")]
|
||||
|
|
@ -71,22 +65,11 @@ impl NotRunningEventLoop {
|
|||
let instance =
|
||||
builder.build().map_err(|e| format!("Error initializing winit event loop: {e}"))?;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let clipboard = crate::clipboard::create_clipboard(
|
||||
&instance
|
||||
.display_handle()
|
||||
.map_err(|display_err| PlatformError::OtherError(display_err.into()))?,
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
instance,
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
clipboard: Rc::new(clipboard.into()),
|
||||
})
|
||||
Ok(Self { instance })
|
||||
}
|
||||
}
|
||||
|
||||
struct RunningEventLoop<'a> {
|
||||
pub(crate) struct RunningEventLoop<'a> {
|
||||
active_event_loop: &'a ActiveEventLoop,
|
||||
}
|
||||
|
||||
|
|
@ -131,28 +114,7 @@ impl EventLoopInterface for RunningEventLoop<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
pub(crate) static MAYBE_LOOP_INSTANCE: RefCell<Option<NotRunningEventLoop>> = RefCell::default();
|
||||
}
|
||||
|
||||
scoped_tls_hkt::scoped_thread_local!(static CURRENT_WINDOW_TARGET : for<'a> &'a RunningEventLoop<'a>);
|
||||
|
||||
pub(crate) fn with_event_loop<T>(
|
||||
callback: impl FnOnce(
|
||||
&dyn EventLoopInterface,
|
||||
) -> Result<T, Box<dyn std::error::Error + Send + Sync>>,
|
||||
) -> Result<T, Box<dyn std::error::Error + Send + Sync>> {
|
||||
if CURRENT_WINDOW_TARGET.is_set() {
|
||||
CURRENT_WINDOW_TARGET.with(|current_target| callback(current_target))
|
||||
} else {
|
||||
MAYBE_LOOP_INSTANCE.with(|loop_instance| {
|
||||
if loop_instance.borrow().is_none() {
|
||||
*loop_instance.borrow_mut() = Some(NotRunningEventLoop::new(None)?);
|
||||
}
|
||||
callback(loop_instance.borrow().as_ref().unwrap())
|
||||
})
|
||||
}
|
||||
}
|
||||
scoped_tls_hkt::scoped_thread_local!(pub(crate) static CURRENT_WINDOW_TARGET : for<'a> &'a RunningEventLoop<'a>);
|
||||
|
||||
/// This enum captures run-time specific events that can be dispatched to the event loop in
|
||||
/// addition to the winit events.
|
||||
|
|
@ -644,13 +606,11 @@ impl EventLoopState {
|
|||
#[allow(unused_mut)] // mut need changes for wasm
|
||||
|
||||
pub fn run(mut self) -> Result<Self, corelib::platform::PlatformError> {
|
||||
let not_running_loop_instance = MAYBE_LOOP_INSTANCE
|
||||
.with(|loop_instance| match loop_instance.borrow_mut().take() {
|
||||
Some(instance) => Ok(instance),
|
||||
None => NotRunningEventLoop::new(None),
|
||||
})
|
||||
.map_err(|e| format!("Error initializing winit event loop: {e}"))?;
|
||||
|
||||
let not_running_loop_instance = self
|
||||
.shared_backend_data
|
||||
.not_running_event_loop
|
||||
.take()
|
||||
.ok_or_else(|| PlatformError::from("Nested event loops are not supported"))?;
|
||||
let mut winit_loop = not_running_loop_instance.instance;
|
||||
|
||||
#[cfg(all(not(target_arch = "wasm32"), not(target_os = "ios")))]
|
||||
|
|
@ -662,11 +622,9 @@ impl EventLoopState {
|
|||
|
||||
// Keep the EventLoop instance alive and re-use it in future invocations of run_event_loop().
|
||||
// Winit does not support creating multiple instances of the event loop.
|
||||
let nre = NotRunningEventLoop {
|
||||
instance: winit_loop,
|
||||
clipboard: not_running_loop_instance.clipboard,
|
||||
};
|
||||
MAYBE_LOOP_INSTANCE.with(|loop_instance| *loop_instance.borrow_mut() = Some(nre));
|
||||
self.shared_backend_data
|
||||
.not_running_event_loop
|
||||
.replace(Some(NotRunningEventLoop { instance: winit_loop }));
|
||||
|
||||
if let Some(error) = self.loop_error {
|
||||
return Err(error);
|
||||
|
|
@ -694,13 +652,11 @@ impl EventLoopState {
|
|||
{
|
||||
use winit::platform::pump_events::EventLoopExtPumpEvents;
|
||||
|
||||
let not_running_loop_instance = MAYBE_LOOP_INSTANCE
|
||||
.with(|loop_instance| match loop_instance.borrow_mut().take() {
|
||||
Some(instance) => Ok(instance),
|
||||
None => NotRunningEventLoop::new(None),
|
||||
})
|
||||
.map_err(|e| format!("Error initializing winit event loop: {e}"))?;
|
||||
|
||||
let not_running_loop_instance = self
|
||||
.shared_backend_data
|
||||
.not_running_event_loop
|
||||
.take()
|
||||
.ok_or_else(|| PlatformError::from("Nested event loops are not supported"))?;
|
||||
let mut winit_loop = not_running_loop_instance.instance;
|
||||
|
||||
self.pumping_events_instantly = timeout.is_some_and(|duration| duration.is_zero());
|
||||
|
|
@ -712,11 +668,9 @@ impl EventLoopState {
|
|||
|
||||
// Keep the EventLoop instance alive and re-use it in future invocations of run_event_loop().
|
||||
// Winit does not support creating multiple instances of the event loop.
|
||||
let nre = NotRunningEventLoop {
|
||||
instance: winit_loop,
|
||||
clipboard: not_running_loop_instance.clipboard,
|
||||
};
|
||||
MAYBE_LOOP_INSTANCE.with(|loop_instance| *loop_instance.borrow_mut() = Some(nre));
|
||||
self.shared_backend_data
|
||||
.not_running_event_loop
|
||||
.replace(Some(NotRunningEventLoop { instance: winit_loop }));
|
||||
|
||||
if let Some(error) = self.loop_error {
|
||||
return Err(error);
|
||||
|
|
@ -727,12 +681,11 @@ impl EventLoopState {
|
|||
#[cfg(target_arch = "wasm32")]
|
||||
pub fn spawn(self) -> Result<(), corelib::platform::PlatformError> {
|
||||
use winit::platform::web::EventLoopExtWebSys;
|
||||
let not_running_loop_instance = MAYBE_LOOP_INSTANCE
|
||||
.with(|loop_instance| match loop_instance.borrow_mut().take() {
|
||||
Some(instance) => Ok(instance),
|
||||
None => NotRunningEventLoop::new(None),
|
||||
})
|
||||
.map_err(|e| format!("Error initializing winit event loop: {e}"))?;
|
||||
let not_running_loop_instance = self
|
||||
.shared_backend_data
|
||||
.not_running_event_loop
|
||||
.take()
|
||||
.ok_or_else(|| PlatformError::from("Nested event loops are not supported"))?;
|
||||
|
||||
not_running_loop_instance
|
||||
.instance
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
extern crate alloc;
|
||||
|
||||
use event_loop::{CustomEvent, EventLoopState};
|
||||
use event_loop::{CustomEvent, EventLoopState, NotRunningEventLoop};
|
||||
use i_slint_core::api::EventLoopError;
|
||||
use i_slint_core::graphics::{RequestedGraphicsAPI, RequestedOpenGLVersion};
|
||||
use i_slint_core::platform::{EventLoopProxy, PlatformError};
|
||||
|
|
@ -267,16 +267,7 @@ impl BackendBuilder {
|
|||
|
||||
// Initialize the winit event loop and propagate errors if for example `DISPLAY` or `WAYLAND_DISPLAY` isn't set.
|
||||
|
||||
let nre = crate::event_loop::NotRunningEventLoop::new(Some(event_loop_builder))?;
|
||||
|
||||
let proxy = nre.instance.create_proxy();
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let clipboard = Rc::downgrade(&nre.clipboard);
|
||||
|
||||
crate::event_loop::MAYBE_LOOP_INSTANCE.with(|loop_instance| {
|
||||
*loop_instance.borrow_mut() = Some(nre);
|
||||
});
|
||||
let shared_data = Rc::new(SharedBackendData::new(event_loop_builder)?);
|
||||
|
||||
let renderer_factory_fn = match (
|
||||
self.renderer_name.as_deref(),
|
||||
|
|
@ -341,10 +332,7 @@ impl BackendBuilder {
|
|||
renderer_factory_fn,
|
||||
event_loop_state: Default::default(),
|
||||
window_attributes_hook: self.window_attributes_hook,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
clipboard,
|
||||
proxy,
|
||||
shared_data: Rc::new(SharedBackendData::default()),
|
||||
shared_data,
|
||||
#[cfg(all(muda, target_os = "macos"))]
|
||||
muda_enable_default_menu_bar_bar: self.muda_enable_default_menu_bar_bar,
|
||||
#[cfg(target_family = "wasm")]
|
||||
|
|
@ -353,12 +341,57 @@ impl BackendBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct SharedBackendData {
|
||||
active_windows: RefCell<HashMap<winit::window::WindowId, Weak<WinitWindowAdapter>>>,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
clipboard: std::cell::RefCell<clipboard::ClipboardPair>,
|
||||
not_running_event_loop: RefCell<Option<crate::event_loop::NotRunningEventLoop>>,
|
||||
event_loop_proxy: winit::event_loop::EventLoopProxy<SlintUserEvent>,
|
||||
}
|
||||
|
||||
impl SharedBackendData {
|
||||
fn new(
|
||||
builder: winit::event_loop::EventLoopBuilder<SlintUserEvent>,
|
||||
) -> Result<Self, PlatformError> {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use raw_window_handle::HasDisplayHandle;
|
||||
|
||||
let nre = NotRunningEventLoop::new(builder)?;
|
||||
let event_loop_proxy = nre.instance.create_proxy();
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let clipboard = crate::clipboard::create_clipboard(
|
||||
&nre.instance
|
||||
.display_handle()
|
||||
.map_err(|display_err| PlatformError::OtherError(display_err.into()))?,
|
||||
);
|
||||
Ok(Self {
|
||||
active_windows: Default::default(),
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
clipboard: RefCell::new(clipboard),
|
||||
not_running_event_loop: RefCell::new(Some(nre)),
|
||||
event_loop_proxy,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn with_event_loop<T>(
|
||||
&self,
|
||||
callback: impl FnOnce(
|
||||
&dyn crate::event_loop::EventLoopInterface,
|
||||
) -> Result<T, Box<dyn std::error::Error + Send + Sync>>,
|
||||
) -> Result<T, Box<dyn std::error::Error + Send + Sync>> {
|
||||
if crate::event_loop::CURRENT_WINDOW_TARGET.is_set() {
|
||||
crate::event_loop::CURRENT_WINDOW_TARGET.with(|current_target| callback(current_target))
|
||||
} else {
|
||||
match self.not_running_event_loop.borrow().as_ref() {
|
||||
Some(event_loop) => callback(event_loop),
|
||||
None => {
|
||||
Err(PlatformError::from("Event loop functions called without event loop")
|
||||
.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_window(&self, id: winit::window::WindowId, window: Rc<WinitWindowAdapter>) {
|
||||
self.active_windows.borrow_mut().insert(id, Rc::downgrade(&window));
|
||||
}
|
||||
|
|
@ -385,7 +418,6 @@ pub struct Backend {
|
|||
requested_graphics_api: Option<RequestedGraphicsAPI>,
|
||||
renderer_factory_fn: fn() -> Box<dyn WinitCompatibleRenderer>,
|
||||
event_loop_state: std::cell::RefCell<Option<crate::event_loop::EventLoopState>>,
|
||||
proxy: winit::event_loop::EventLoopProxy<SlintUserEvent>,
|
||||
shared_data: Rc<SharedBackendData>,
|
||||
|
||||
/// This hook is called before a Window is created.
|
||||
|
|
@ -404,9 +436,6 @@ pub struct Backend {
|
|||
pub window_attributes_hook:
|
||||
Option<Box<dyn Fn(winit::window::WindowAttributes) -> winit::window::WindowAttributes>>,
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
clipboard: Weak<std::cell::RefCell<clipboard::ClipboardPair>>,
|
||||
|
||||
#[cfg(all(muda, target_os = "macos"))]
|
||||
muda_enable_default_menu_bar_bar: bool,
|
||||
|
||||
|
|
@ -468,7 +497,7 @@ impl i_slint_core::platform::Platform for Backend {
|
|||
attrs.clone(),
|
||||
self.requested_graphics_api.clone(),
|
||||
#[cfg(any(enable_accesskit, muda))]
|
||||
self.proxy.clone(),
|
||||
self.shared_data.event_loop_proxy.clone(),
|
||||
#[cfg(all(muda, target_os = "macos"))]
|
||||
self.muda_enable_default_menu_bar_bar,
|
||||
)
|
||||
|
|
@ -476,7 +505,7 @@ impl i_slint_core::platform::Platform for Backend {
|
|||
try_create_window_with_fallback_renderer(
|
||||
&self.shared_data,
|
||||
attrs,
|
||||
&self.proxy,
|
||||
&self.shared_data.event_loop_proxy.clone(),
|
||||
#[cfg(all(muda, target_os = "macos"))]
|
||||
self.muda_enable_default_menu_bar_bar,
|
||||
)
|
||||
|
|
@ -561,7 +590,7 @@ impl i_slint_core::platform::Platform for Backend {
|
|||
.map_err(|_| EventLoopError::EventLoopTerminated)
|
||||
}
|
||||
}
|
||||
Some(Box::new(Proxy(self.proxy.clone())))
|
||||
Some(Box::new(Proxy(self.shared_data.event_loop_proxy.clone())))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
|
|
@ -571,8 +600,7 @@ impl i_slint_core::platform::Platform for Backend {
|
|||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn set_clipboard_text(&self, text: &str, clipboard: i_slint_core::platform::Clipboard) {
|
||||
let Some(clipboard_pair) = self.clipboard.upgrade() else { return };
|
||||
let mut pair = clipboard_pair.borrow_mut();
|
||||
let mut pair = self.shared_data.clipboard.borrow_mut();
|
||||
if let Some(clipboard) = clipboard::select_clipboard(&mut pair, clipboard) {
|
||||
clipboard.set_contents(text.into()).ok();
|
||||
}
|
||||
|
|
@ -585,8 +613,7 @@ impl i_slint_core::platform::Platform for Backend {
|
|||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn clipboard_text(&self, clipboard: i_slint_core::platform::Clipboard) -> Option<String> {
|
||||
let clipboard_pair = self.clipboard.upgrade()?;
|
||||
let mut pair = clipboard_pair.borrow_mut();
|
||||
let mut pair = self.shared_data.clipboard.borrow_mut();
|
||||
clipboard::select_clipboard(&mut pair, clipboard).and_then(|c| c.get_contents().ok())
|
||||
}
|
||||
}
|
||||
|
|
@ -659,13 +686,6 @@ impl WinitWindowAccessor for i_slint_core::api::Window {
|
|||
|
||||
impl private::WinitWindowAccessorSealed for i_slint_core::api::Window {}
|
||||
|
||||
/// Creates a non Slint aware window with winit
|
||||
pub fn create_winit_window(
|
||||
window_attributes: winit::window::WindowAttributes,
|
||||
) -> Result<winit::window::Window, winit::error::OsError> {
|
||||
event_loop::with_event_loop(|eli| Ok(eli.create_window(window_attributes))).unwrap()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod testui {
|
||||
slint::slint! {
|
||||
|
|
|
|||
|
|
@ -342,10 +342,9 @@ impl WinitWindowAdapter {
|
|||
muda_enable_default_menu_bar,
|
||||
});
|
||||
|
||||
let winit_window =
|
||||
crate::event_loop::with_event_loop(
|
||||
|event_loop| Ok(self_rc.ensure_window(event_loop)?),
|
||||
)?;
|
||||
let winit_window = self_rc
|
||||
.shared_backend_data
|
||||
.with_event_loop(|event_loop| Ok(self_rc.ensure_window(event_loop)?))?;
|
||||
debug_assert!(!self_rc.renderer.is_suspended());
|
||||
self_rc.size.set(physical_size_to_slint(&winit_window.inner_size()));
|
||||
|
||||
|
|
@ -708,9 +707,9 @@ impl WindowAdapter for WinitWindowAdapter {
|
|||
if visible {
|
||||
let recreating_window = self.winit_window_or_none.borrow().as_window().is_none();
|
||||
|
||||
let winit_window = crate::event_loop::with_event_loop(|event_loop| {
|
||||
Ok(self.ensure_window(event_loop)?)
|
||||
})?;
|
||||
let winit_window = self
|
||||
.shared_backend_data
|
||||
.with_event_loop(|event_loop| Ok(self.ensure_window(event_loop)?))?;
|
||||
|
||||
let runtime_window = WindowInner::from_pub(self.window());
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue