diff --git a/crates/gpui3/src/app.rs b/crates/gpui3/src/app.rs index 8fbccaa838..94025ff9a8 100644 --- a/crates/gpui3/src/app.rs +++ b/crates/gpui3/src/app.rs @@ -14,7 +14,7 @@ use crate::{ }; use anyhow::{anyhow, Result}; use collections::{HashMap, VecDeque}; -use futures::Future; +use futures::{channel::oneshot, Future}; use parking_lot::Mutex; use slotmap::SlotMap; use smallvec::SmallVec; @@ -93,9 +93,9 @@ type Handlers = SmallVec<[Arc bool + Send + Sync + 's pub struct AppContext { this: Weak>>, platform: MainThreadOnly, - dispatcher: Arc, text_system: Arc, pending_updates: usize, + pub(crate) dispatcher: Arc, pub(crate) svg_renderer: SvgRenderer, pub(crate) image_cache: ImageCache, pub(crate) text_style_stack: Vec, @@ -185,19 +185,29 @@ impl AppContext { } pub fn run_on_main( - &self, + &mut self, f: impl FnOnce(&mut MainThread) -> R + Send + 'static, ) -> impl Future where R: Send + 'static, { - let this = self.this.upgrade().unwrap(); - run_on_main(self.dispatcher.clone(), move || { - let cx = &mut *this.lock(); - cx.update(|cx| { - f(unsafe { mem::transmute::<&mut AppContext, &mut MainThread>(cx) }) - }) - }) + let (tx, rx) = oneshot::channel(); + if self.dispatcher.is_main_thread() { + let _ = tx.send(f(unsafe { + mem::transmute::<&mut AppContext, &mut MainThread>(self) + })); + } else { + let this = self.this.upgrade().unwrap(); + let _ = run_on_main(self.dispatcher.clone(), move || { + let cx = &mut *this.lock(); + cx.update(|cx| { + let _ = tx.send(f(unsafe { + mem::transmute::<&mut Self, &mut MainThread>(cx) + })); + }) + }); + } + async move { rx.await.unwrap() } } pub fn spawn_on_main( @@ -307,7 +317,7 @@ impl MainThread { pub(crate) fn update_window( &mut self, id: WindowId, - update: impl FnOnce(&mut WindowContext) -> R, + update: impl FnOnce(&mut MainThread) -> R, ) -> Result { self.0.update_window(id, |cx| { update(unsafe { diff --git a/crates/gpui3/src/executor.rs b/crates/gpui3/src/executor.rs index 81df5a3738..6a4f7a13e9 100644 --- a/crates/gpui3/src/executor.rs +++ b/crates/gpui3/src/executor.rs @@ -27,7 +27,15 @@ where F: FnOnce() -> R + Send + 'static, R: Send + 'static, { - spawn_on_main(dispatcher, move || async move { func() }) + let (tx, rx) = oneshot::channel(); + if dispatcher.is_main_thread() { + let _ = tx.send(func()); + } else { + let _ = spawn_on_main(dispatcher, move || async move { + let _ = tx.send(func()); + }); + } + async move { rx.await.unwrap() } } /// Enqueues the given closure to be run on the application's event loop. The diff --git a/crates/gpui3/src/gpui3.rs b/crates/gpui3/src/gpui3.rs index a429541cb8..7c8c7c498c 100644 --- a/crates/gpui3/src/gpui3.rs +++ b/crates/gpui3/src/gpui3.rs @@ -37,6 +37,7 @@ pub use serde_json; pub use smallvec; pub use smol::Timer; use std::{ + mem, ops::{Deref, DerefMut}, sync::Arc, }; @@ -89,6 +90,42 @@ impl DerefMut for MainThread { } } +impl Context for MainThread { + type EntityContext<'a, 'w, T: 'static + Send + Sync> = MainThread>; + type Result = C::Result; + + fn entity( + &mut self, + build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, + ) -> Self::Result> { + self.0.entity(|cx| { + let cx = unsafe { + mem::transmute::< + &mut C::EntityContext<'_, '_, T>, + &mut MainThread>, + >(cx) + }; + build_entity(cx) + }) + } + + fn update_entity( + &mut self, + handle: &Handle, + update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R, + ) -> Self::Result { + self.0.update_entity(handle, |entity, cx| { + let cx = unsafe { + mem::transmute::< + &mut C::EntityContext<'_, '_, T>, + &mut MainThread>, + >(cx) + }; + update(entity, cx) + }) + } +} + pub trait BorrowAppContext { fn app_mut(&mut self) -> &mut AppContext; diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index 2e53016f65..12bc21d9f0 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -7,7 +7,7 @@ use crate::{ WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::Result; -use futures::Future; +use futures::{channel::oneshot, Future}; use smallvec::SmallVec; use std::{any::TypeId, borrow::Cow, marker::PhantomData, mem, sync::Arc}; use util::ResultExt; @@ -112,6 +112,29 @@ impl<'a, 'w> WindowContext<'a, 'w> { self.window.dirty = true; } + fn run_on_main( + &mut self, + f: impl FnOnce(&mut MainThread>) -> R + Send + 'static, + ) -> impl Future + where + R: Send + 'static, + { + let (tx, rx) = oneshot::channel(); + if self.dispatcher.is_main_thread() { + let _ = tx.send(f(unsafe { + mem::transmute::<&mut Self, &mut MainThread>(self) + })); + } else { + let id = self.window.handle.id; + let _ = self.app.run_on_main(move |cx| { + cx.update_window(id, |cx| { + let _ = tx.send(f(cx)); + }) + }); + } + async move { rx.await.unwrap() } + } + pub fn request_layout( &mut self, style: Style, @@ -191,23 +214,6 @@ impl<'a, 'w> WindowContext<'a, 'w> { self.window.current_layer_id.clone() } - pub fn run_on_main( - &self, - f: impl FnOnce(&mut MainThread) -> R + Send + 'static, - ) -> impl Future> - where - R: Send + 'static, - { - let id = self.window.handle.id; - self.app.run_on_main(move |cx| { - cx.update_window(id, |cx| { - f(unsafe { - mem::transmute::<&mut WindowContext, &mut MainThread>(cx) - }) - }) - }) - } - pub fn paint_glyph( &mut self, origin: Point, @@ -389,7 +395,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { pub(crate) fn draw(&mut self) -> Result<()> { let unit_entity = self.unit_entity.clone(); - self.update_entity(&unit_entity, |_, cx| { + self.update_entity(&unit_entity, |view, cx| { let mut root_view = cx.window.root_view.take().unwrap(); let (root_layout_id, mut frame_state) = root_view.layout(&mut (), cx)?; let available_space = cx.window.content_size.map(Into::into); @@ -403,14 +409,14 @@ impl<'a, 'w> WindowContext<'a, 'w> { cx.window.root_view = Some(root_view); let scene = cx.window.scene.take(); - let _ = cx.run_on_main(|cx| { + let _ = cx.run_on_main(view, |_, cx| { cx.window .platform_window .borrow_on_main_thread() .draw(scene); + cx.window.dirty = false; }); - cx.window.dirty = false; Ok(()) }) } @@ -596,6 +602,29 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> { .push_back(Effect::Notify(self.entity_id)); } + pub fn run_on_main( + &mut self, + view: &mut S, + f: impl FnOnce(&mut S, &mut MainThread>) -> R + Send + 'static, + ) -> impl Future + where + R: Send + 'static, + { + let (tx, rx) = oneshot::channel(); + if self.dispatcher.is_main_thread() { + let cx = unsafe { mem::transmute::<&mut Self, &mut MainThread>(self) }; + let _ = tx.send(f(view, cx)); + } else { + let handle = self.handle().upgrade(self).unwrap(); + let _ = self.window_cx.run_on_main(move |cx| { + handle.update(cx, |view, cx| { + let _ = tx.send(f(view, cx)); + }) + }); + } + async move { rx.await.unwrap() } + } + pub(crate) fn erase_state(&mut self, f: impl FnOnce(&mut ViewContext<()>) -> R) -> R { let entity_id = self.unit_entity.id; let mut cx = ViewContext::mutable(