Detailed changes
@@ -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<dyn Fn(&mut AppContext) -> bool + Send + Sync + 's
pub struct AppContext {
this: Weak<Mutex<MainThread<AppContext>>>,
platform: MainThreadOnly<dyn Platform>,
- dispatcher: Arc<dyn PlatformDispatcher>,
text_system: Arc<TextSystem>,
pending_updates: usize,
+ pub(crate) dispatcher: Arc<dyn PlatformDispatcher>,
pub(crate) svg_renderer: SvgRenderer,
pub(crate) image_cache: ImageCache,
pub(crate) text_style_stack: Vec<TextStyleRefinement>,
@@ -185,19 +185,29 @@ impl AppContext {
}
pub fn run_on_main<R>(
- &self,
+ &mut self,
f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
) -> impl Future<Output = R>
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<AppContext>>(cx) })
- })
- })
+ let (tx, rx) = oneshot::channel();
+ if self.dispatcher.is_main_thread() {
+ let _ = tx.send(f(unsafe {
+ mem::transmute::<&mut AppContext, &mut MainThread<AppContext>>(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<Self>>(cx)
+ }));
+ })
+ });
+ }
+ async move { rx.await.unwrap() }
}
pub fn spawn_on_main<F, R>(
@@ -307,7 +317,7 @@ impl MainThread<AppContext> {
pub(crate) fn update_window<R>(
&mut self,
id: WindowId,
- update: impl FnOnce(&mut WindowContext) -> R,
+ update: impl FnOnce(&mut MainThread<WindowContext>) -> R,
) -> Result<R> {
self.0.update_window(id, |cx| {
update(unsafe {
@@ -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
@@ -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<T> DerefMut for MainThread<T> {
}
}
+impl<C: Context> Context for MainThread<C> {
+ type EntityContext<'a, 'w, T: 'static + Send + Sync> = MainThread<C::EntityContext<'a, 'w, T>>;
+ type Result<T> = C::Result<T>;
+
+ fn entity<T: Send + Sync + 'static>(
+ &mut self,
+ build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
+ ) -> Self::Result<Handle<T>> {
+ self.0.entity(|cx| {
+ let cx = unsafe {
+ mem::transmute::<
+ &mut C::EntityContext<'_, '_, T>,
+ &mut MainThread<C::EntityContext<'_, '_, T>>,
+ >(cx)
+ };
+ build_entity(cx)
+ })
+ }
+
+ fn update_entity<T: Send + Sync + 'static, R>(
+ &mut self,
+ handle: &Handle<T>,
+ update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
+ ) -> Self::Result<R> {
+ self.0.update_entity(handle, |entity, cx| {
+ let cx = unsafe {
+ mem::transmute::<
+ &mut C::EntityContext<'_, '_, T>,
+ &mut MainThread<C::EntityContext<'_, '_, T>>,
+ >(cx)
+ };
+ update(entity, cx)
+ })
+ }
+}
+
pub trait BorrowAppContext {
fn app_mut(&mut self) -> &mut AppContext;
@@ -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<R>(
+ &mut self,
+ f: impl FnOnce(&mut MainThread<WindowContext<'_, '_>>) -> R + Send + 'static,
+ ) -> impl Future<Output = R>
+ 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>>(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<R>(
- &self,
- f: impl FnOnce(&mut MainThread<WindowContext>) -> R + Send + 'static,
- ) -> impl Future<Output = Result<R>>
- 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<WindowContext>>(cx)
- })
- })
- })
- }
-
pub fn paint_glyph(
&mut self,
origin: Point<Pixels>,
@@ -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<R>(
+ &mut self,
+ view: &mut S,
+ f: impl FnOnce(&mut S, &mut MainThread<ViewContext<'_, '_, S>>) -> R + Send + 'static,
+ ) -> impl Future<Output = R>
+ 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>>(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<R>(&mut self, f: impl FnOnce(&mut ViewContext<()>) -> R) -> R {
let entity_id = self.unit_entity.id;
let mut cx = ViewContext::mutable(