mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-04 02:39:28 +00:00
Add support for a simple event loop with proxy to the testing backend
Moved from the spawn_local test, this allows for re-use in the show_strongref integration test.
This commit is contained in:
parent
de58d5e83c
commit
a98e07417e
4 changed files with 64 additions and 64 deletions
|
@ -167,7 +167,6 @@ log = { version = "0.4.17", optional = true }
|
|||
[dev-dependencies]
|
||||
slint-build = { path = "../build" }
|
||||
i-slint-backend-testing = { path = "../../../internal/backends/testing" }
|
||||
i-slint-backend-winit = { path = "../../../internal/backends/winit", features = ["wayland", "x11", "renderer-software"] }
|
||||
serde_json = "1.0.96"
|
||||
serde = { version = "1.0.163", features = ["derive"] }
|
||||
|
||||
|
|
|
@ -3,11 +3,9 @@
|
|||
|
||||
use ::slint::slint;
|
||||
|
||||
// Sorry, can't test with rust test harness and multiple threads.
|
||||
#[cfg(not(any(target_arch = "wasm32", target_os = "macos", target_os = "ios")))]
|
||||
#[test]
|
||||
fn show_maintains_strong_reference() {
|
||||
slint::platform::set_platform(Box::new(i_slint_backend_winit::Backend::new())).unwrap();
|
||||
i_slint_backend_testing::init_with_event_loop();
|
||||
|
||||
slint!(export component TestWindow inherits Window {
|
||||
callback root-clicked();
|
||||
|
@ -21,10 +19,11 @@ fn show_maintains_strong_reference() {
|
|||
let window_weak = window.as_weak();
|
||||
let window_weak_2 = window_weak.clone();
|
||||
|
||||
slint::Timer::single_shot(std::time::Duration::from_millis(20), move || {
|
||||
slint::invoke_from_event_loop(move || {
|
||||
window_weak_2.upgrade().unwrap().hide().unwrap();
|
||||
slint::quit_event_loop().unwrap();
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
window.show().unwrap();
|
||||
drop(window);
|
||||
|
|
|
@ -1,63 +1,6 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
|
||||
|
||||
mod fake_backend {
|
||||
enum Event {
|
||||
Quit,
|
||||
Event(Box<dyn FnOnce() + Send>),
|
||||
}
|
||||
#[derive(Clone)]
|
||||
struct Queue(
|
||||
std::sync::Arc<std::sync::Mutex<std::collections::VecDeque<Event>>>,
|
||||
std::thread::Thread,
|
||||
);
|
||||
pub struct FakeBackend {
|
||||
queue: Queue,
|
||||
}
|
||||
|
||||
impl Default for FakeBackend {
|
||||
fn default() -> Self {
|
||||
Self { queue: Queue(Default::default(), std::thread::current()) }
|
||||
}
|
||||
}
|
||||
impl slint::platform::Platform for FakeBackend {
|
||||
fn create_window_adapter(
|
||||
&self,
|
||||
) -> Result<std::rc::Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn run_event_loop(&self) -> Result<(), slint::PlatformError> {
|
||||
loop {
|
||||
let e = self.queue.0.lock().unwrap().pop_front();
|
||||
match e {
|
||||
Some(Event::Quit) => break Ok(()),
|
||||
Some(Event::Event(e)) => e(),
|
||||
None => std::thread::park(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn new_event_loop_proxy(&self) -> Option<Box<dyn slint::platform::EventLoopProxy>> {
|
||||
Some(Box::new(self.queue.clone()))
|
||||
}
|
||||
}
|
||||
impl slint::platform::EventLoopProxy for Queue {
|
||||
fn quit_event_loop(&self) -> Result<(), slint::EventLoopError> {
|
||||
self.0.lock().unwrap().push_back(Event::Quit);
|
||||
self.1.unpark();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn invoke_from_event_loop(
|
||||
&self,
|
||||
event: Box<dyn FnOnce() + Send>,
|
||||
) -> Result<(), slint::EventLoopError> {
|
||||
self.0.lock().unwrap().push_back(Event::Event(event));
|
||||
self.1.unpark();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Code from https://doc.rust-lang.org/std/task/trait.Wake.html#examples
|
||||
mod executor {
|
||||
use std::future::Future;
|
||||
|
@ -96,7 +39,7 @@ mod executor {
|
|||
|
||||
#[test]
|
||||
fn main() {
|
||||
slint::platform::set_platform(Box::new(fake_backend::FakeBackend::default())).unwrap();
|
||||
i_slint_backend_testing::init_with_event_loop();
|
||||
|
||||
slint::invoke_from_event_loop(|| {
|
||||
let handle = slint::spawn_local(async { String::from("Hello") }).unwrap();
|
||||
|
|
|
@ -19,6 +19,7 @@ use std::sync::Mutex;
|
|||
#[derive(Default)]
|
||||
pub struct TestingBackend {
|
||||
clipboard: Mutex<Option<String>>,
|
||||
queue: Option<Queue>,
|
||||
}
|
||||
|
||||
impl i_slint_core::platform::Platform for TestingBackend {
|
||||
|
@ -51,6 +52,28 @@ impl i_slint_core::platform::Platform for TestingBackend {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn run_event_loop(&self) -> Result<(), PlatformError> {
|
||||
let queue = match self.queue.as_ref() {
|
||||
Some(queue) => queue.clone(),
|
||||
None => return Err(PlatformError::NoEventLoopProvider),
|
||||
};
|
||||
|
||||
loop {
|
||||
let e = queue.0.lock().unwrap().pop_front();
|
||||
match e {
|
||||
Some(Event::Quit) => break Ok(()),
|
||||
Some(Event::Event(e)) => e(),
|
||||
None => std::thread::park(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn new_event_loop_proxy(&self) -> Option<Box<dyn i_slint_core::platform::EventLoopProxy>> {
|
||||
self.queue
|
||||
.as_ref()
|
||||
.map(|q| Box::new(q.clone()) as Box<dyn i_slint_core::platform::EventLoopProxy>)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TestingWindow {
|
||||
|
@ -162,6 +185,33 @@ impl RendererSealed for TestingWindow {
|
|||
}
|
||||
}
|
||||
|
||||
enum Event {
|
||||
Quit,
|
||||
Event(Box<dyn FnOnce() + Send>),
|
||||
}
|
||||
#[derive(Clone)]
|
||||
struct Queue(
|
||||
std::sync::Arc<std::sync::Mutex<std::collections::VecDeque<Event>>>,
|
||||
std::thread::Thread,
|
||||
);
|
||||
|
||||
impl i_slint_core::platform::EventLoopProxy for Queue {
|
||||
fn quit_event_loop(&self) -> Result<(), i_slint_core::api::EventLoopError> {
|
||||
self.0.lock().unwrap().push_back(Event::Quit);
|
||||
self.1.unpark();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn invoke_from_event_loop(
|
||||
&self,
|
||||
event: Box<dyn FnOnce() + Send>,
|
||||
) -> Result<(), i_slint_core::api::EventLoopError> {
|
||||
self.0.lock().unwrap().push_back(Event::Event(event));
|
||||
self.1.unpark();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize the testing backend.
|
||||
/// Must be called before any call that would otherwise initialize the rendering backend.
|
||||
/// Calling it when the rendering backend is already initialized will have no effects
|
||||
|
@ -170,6 +220,15 @@ pub fn init() {
|
|||
.expect("platform already initialized");
|
||||
}
|
||||
|
||||
/// Initialize the testing backend with support for simple event loop.
|
||||
/// This function can only be called once per process, so make sure to use integration
|
||||
/// tests with one `#[test]` function.
|
||||
pub fn init_with_event_loop() {
|
||||
let mut backend = TestingBackend::default();
|
||||
backend.queue = Some(Queue(Default::default(), std::thread::current()));
|
||||
i_slint_core::platform::set_platform(Box::new(backend)).expect("platform already initialized");
|
||||
}
|
||||
|
||||
/// This module contains functions useful for unit tests
|
||||
mod for_unit_test {
|
||||
use i_slint_core::api::ComponentHandle;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue