mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 14:21:16 +00:00
Start the LSP thread when the gui thread is ready
This way we can serve preview requests immediately. This basically makes post_event safe to call before the event loop is entered. The events will be queued up and sent when the event loop is created and we have access to the proxy, which will take over the queue.
This commit is contained in:
parent
d9db07db2a
commit
b81803774b
4 changed files with 65 additions and 26 deletions
|
@ -75,8 +75,45 @@ thread_local! {
|
||||||
scoped_tls_hkt::scoped_thread_local!(static CURRENT_WINDOW_TARGET : for<'a> &'a RunningEventLoop<'a>);
|
scoped_tls_hkt::scoped_thread_local!(static CURRENT_WINDOW_TARGET : for<'a> &'a RunningEventLoop<'a>);
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub static GLOBAL_PROXY: once_cell::sync::OnceCell<
|
pub(crate) enum GlobalEventLoopProxyOrEventQueue {
|
||||||
std::sync::Mutex<Option<winit::event_loop::EventLoopProxy<CustomEvent>>>,
|
Proxy(winit::event_loop::EventLoopProxy<CustomEvent>),
|
||||||
|
Queue(Vec<CustomEvent>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
impl GlobalEventLoopProxyOrEventQueue {
|
||||||
|
pub(crate) fn send_event(&mut self, event: CustomEvent) {
|
||||||
|
match self {
|
||||||
|
GlobalEventLoopProxyOrEventQueue::Proxy(proxy) => proxy.send_event(event).ok().unwrap(),
|
||||||
|
GlobalEventLoopProxyOrEventQueue::Queue(queue) => {
|
||||||
|
queue.push(event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_proxy(&mut self, proxy: winit::event_loop::EventLoopProxy<CustomEvent>) {
|
||||||
|
match self {
|
||||||
|
GlobalEventLoopProxyOrEventQueue::Proxy(_) => {}
|
||||||
|
GlobalEventLoopProxyOrEventQueue::Queue(queue) => {
|
||||||
|
std::mem::take(queue)
|
||||||
|
.into_iter()
|
||||||
|
.for_each(|event| proxy.send_event(event).ok().unwrap());
|
||||||
|
*self = GlobalEventLoopProxyOrEventQueue::Proxy(proxy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
impl Default for GlobalEventLoopProxyOrEventQueue {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Queue(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub(crate) static GLOBAL_PROXY: once_cell::sync::OnceCell<
|
||||||
|
std::sync::Mutex<GlobalEventLoopProxyOrEventQueue>,
|
||||||
> = once_cell::sync::OnceCell::new();
|
> = once_cell::sync::OnceCell::new();
|
||||||
|
|
||||||
pub(crate) fn with_window_target<T>(callback: impl FnOnce(&dyn EventLoopInterface) -> T) -> T {
|
pub(crate) fn with_window_target<T>(callback: impl FnOnce(&dyn EventLoopInterface) -> T) -> T {
|
||||||
|
@ -133,8 +170,11 @@ pub fn run() {
|
||||||
let event_loop_proxy = not_running_loop_instance.event_loop_proxy;
|
let event_loop_proxy = not_running_loop_instance.event_loop_proxy;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
*GLOBAL_PROXY.get_or_init(Default::default).lock().unwrap() =
|
GLOBAL_PROXY
|
||||||
Some(event_loop_proxy.clone());
|
.get_or_init(Default::default)
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.set_proxy(event_loop_proxy.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut winit_loop = not_running_loop_instance.instance;
|
let mut winit_loop = not_running_loop_instance.instance;
|
||||||
|
|
|
@ -1520,12 +1520,7 @@ impl sixtyfps_corelib::backend::Backend for Backend {
|
||||||
fn post_event(&'static self, event: Box<dyn FnOnce() + Send>) {
|
fn post_event(&'static self, event: Box<dyn FnOnce() + Send>) {
|
||||||
let e = crate::eventloop::CustomEvent::UserEvent(event);
|
let e = crate::eventloop::CustomEvent::UserEvent(event);
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
crate::eventloop::GLOBAL_PROXY
|
crate::eventloop::GLOBAL_PROXY.get_or_init(Default::default).lock().unwrap().send_event(e);
|
||||||
.get_or_init(Default::default)
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.as_ref()
|
|
||||||
.map(|proxy| proxy.send_event(e));
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
crate::eventloop::with_window_target(|event_loop| {
|
crate::eventloop::with_window_target(|event_loop| {
|
||||||
event_loop.event_loop_proxy().send_event(e).ok();
|
event_loop.event_loop_proxy().send_event(e).ok();
|
||||||
|
|
|
@ -45,20 +45,20 @@ impl<'a> DocumentCache<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
std::thread::spawn(|| {
|
// Start the LSP thread with a delay when the gui event loop is up and running, to be able
|
||||||
match run_lsp_server() {
|
// to be immediately ready to serve preview requests.
|
||||||
Ok(_) => {}
|
preview::run_in_ui_thread(Box::new(|| {
|
||||||
Err(error) => {
|
std::thread::spawn(|| {
|
||||||
eprintln!("Error running LSP server: {}", error);
|
match run_lsp_server() {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(error) => {
|
||||||
|
eprintln!("Error running LSP server: {}", error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
preview::quit_ui_event_loop();
|
||||||
preview::quit_ui_event_loop();
|
});
|
||||||
});
|
}));
|
||||||
// TODO: Don't terminate the event loop when the window is closed with Qt
|
// TODO: Don't terminate the event loop when the window is closed
|
||||||
// TODO: There's a race condition where theoretically the LSP could receive a preview
|
|
||||||
// request before the gui event loop has started, which would cause post_event to panic.
|
|
||||||
// Instead we should start the lsp thread when the gui thread is *ready*, for example through
|
|
||||||
// a single-shot timer.
|
|
||||||
preview::start_ui_event_loop();
|
preview::start_ui_event_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ unsafe impl Sync for FutureRunner {}
|
||||||
|
|
||||||
impl Wake for FutureRunner {
|
impl Wake for FutureRunner {
|
||||||
fn wake(self: Arc<Self>) {
|
fn wake(self: Arc<Self>) {
|
||||||
sixtyfps_rendering_backend_default::backend().post_event(Box::new(move || {
|
run_in_ui_thread(Box::new(move || {
|
||||||
let waker = self.clone().into();
|
let waker = self.clone().into();
|
||||||
let mut cx = std::task::Context::from_waker(&waker);
|
let mut cx = std::task::Context::from_waker(&waker);
|
||||||
let mut fut_opt = self.fut.lock().unwrap();
|
let mut fut_opt = self.fut.lock().unwrap();
|
||||||
|
@ -41,10 +41,14 @@ impl Wake for FutureRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_in_ui_thread(mut fut: Pin<Box<dyn Future<Output = ()>>>) {
|
fn run_future_in_ui_thread(mut fut: Pin<Box<dyn Future<Output = ()>>>) {
|
||||||
Arc::new(FutureRunner { fut: Mutex::new(Some(fut)) }).wake()
|
Arc::new(FutureRunner { fut: Mutex::new(Some(fut)) }).wake()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run_in_ui_thread(f: Box<dyn FnOnce() + Send>) {
|
||||||
|
sixtyfps_rendering_backend_default::backend().post_event(f);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn start_ui_event_loop() {
|
pub fn start_ui_event_loop() {
|
||||||
sixtyfps_interpreter::run_event_loop();
|
sixtyfps_interpreter::run_event_loop();
|
||||||
}
|
}
|
||||||
|
@ -56,7 +60,7 @@ pub fn quit_ui_event_loop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_preview(path: std::path::PathBuf) {
|
pub fn load_preview(path: std::path::PathBuf) {
|
||||||
run_in_ui_thread(Box::pin(async move { reload_preview(&path).await }));
|
run_future_in_ui_thread(Box::pin(async move { reload_preview(&path).await }));
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn reload_preview(path: &std::path::Path) {
|
async fn reload_preview(path: &std::path::Path) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue