From 7a6c27cf24cc2e155ad17770e93241032c5b9654 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 29 Sep 2023 14:04:58 -0600 Subject: [PATCH] WIP --- crates/gpui3/src/app.rs | 85 +++++++++++++++++++++++++---- crates/gpui3/src/executor.rs | 17 +++++- crates/gpui3/src/gpui3.rs | 20 +------ crates/gpui3/src/window.rs | 9 ++- crates/storybook2/src/storybook2.rs | 7 +++ 5 files changed, 102 insertions(+), 36 deletions(-) diff --git a/crates/gpui3/src/app.rs b/crates/gpui3/src/app.rs index b1d08dcb53..2ac703d8a3 100644 --- a/crates/gpui3/src/app.rs +++ b/crates/gpui3/src/app.rs @@ -8,8 +8,9 @@ pub use model_context::*; use refineable::Refineable; use crate::{ - current_platform, Context, LayoutId, MainThreadOnly, Platform, RootView, TextStyle, - TextStyleRefinement, TextSystem, Window, WindowContext, WindowHandle, WindowId, + current_platform, run_on_main, spawn_on_main, Context, LayoutId, MainThreadOnly, Platform, + PlatformDispatcher, Reference, RootView, TextStyle, TextStyleRefinement, TextSystem, Window, + WindowContext, WindowHandle, WindowId, }; use anyhow::{anyhow, Result}; use collections::{HashMap, VecDeque}; @@ -19,6 +20,7 @@ use slotmap::SlotMap; use smallvec::SmallVec; use std::{ any::{type_name, Any, TypeId}, + ops::{Deref, DerefMut}, sync::{Arc, Weak}, }; use util::ResultExt; @@ -77,6 +79,7 @@ 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) text_style_stack: Vec, @@ -98,19 +101,36 @@ impl AppContext { AsyncContext(self.this.clone()) } + pub fn run_on_main( + &self, + f: impl FnOnce(&mut MainThreadContext) -> 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(); + let platform = cx.platform.borrow_on_main_thread().clone(); + cx.update(|cx| f(&mut MainThreadContext::mutable(cx, platform.as_ref()))) + }) + } + pub fn spawn_on_main( &self, - f: impl FnOnce(&dyn Platform, &mut Self) -> F + Send + 'static, + f: impl FnOnce(&mut MainThreadContext) -> F + Send + 'static, ) -> impl Future where F: Future + 'static, R: Send + 'static, { let this = self.this.upgrade().unwrap(); - self.platform.read(move |platform| { + spawn_on_main(self.dispatcher.clone(), move || { let cx = &mut *this.lock(); - cx.update(|cx| f(platform, cx)) + let platform = cx.platform.borrow_on_main_thread().clone(); + cx.update(|cx| f(&mut MainThreadContext::mutable(cx, platform.as_ref()))) }) + // self.platform.read(move |platform| { } pub fn open_window( @@ -120,13 +140,7 @@ impl AppContext { ) -> impl Future> { let id = self.windows.insert(None); let handle = WindowHandle::new(id); - self.spawn_on_main(move |platform, cx| { - let mut window = Window::new(handle.into(), options, platform, cx); - let root_view = build_root_view(&mut WindowContext::mutable(cx, &mut window)); - window.root_view.replace(root_view.into_any()); - cx.windows.get_mut(id).unwrap().replace(window); - future::ready(handle) - }) + self.spawn_on_main(move |cx| future::ready(cx.open_window(options, build_root_view))) } pub fn text_style(&self) -> TextStyle { @@ -275,6 +289,53 @@ impl Context for AppContext { } } +pub struct MainThreadContext<'a> { + app: Reference<'a, AppContext>, + platform: &'a dyn Platform, +} + +impl<'a> MainThreadContext<'a> { + fn mutable(cx: &'a mut AppContext, platform: &'a dyn Platform) -> Self { + Self { + app: Reference::Mutable(cx), + platform, + } + } + + pub fn activate(&mut self, ignoring_other_apps: bool) { + self.platform.activate(ignoring_other_apps); + } + + pub fn open_window( + &mut self, + options: crate::WindowOptions, + build_root_view: impl FnOnce(&mut WindowContext) -> RootView + Send + 'static, + ) -> WindowHandle { + let id = self.windows.insert(None); + let handle = WindowHandle::new(id); + let cx = &mut *self.app; + let mut window = Window::new(handle.into(), options, self.platform, cx); + let root_view = build_root_view(&mut WindowContext::mutable(cx, &mut window)); + window.root_view.replace(root_view.into_any()); + cx.windows.get_mut(id).unwrap().replace(window); + handle + } +} + +impl<'a> Deref for MainThreadContext<'a> { + type Target = AppContext; + + fn deref(&self) -> &Self::Target { + &*self.app + } +} + +impl<'a> DerefMut for MainThreadContext<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut *self.app + } +} + pub(crate) enum Effect { Notify(EntityId), } diff --git a/crates/gpui3/src/executor.rs b/crates/gpui3/src/executor.rs index b85e5471f2..81df5a3738 100644 --- a/crates/gpui3/src/executor.rs +++ b/crates/gpui3/src/executor.rs @@ -17,8 +17,21 @@ use std::{ time::Duration, }; -/// Enqueues the given closure to be run on the application's event loop. Can be -/// called on any thread. +/// Enqueues the given closure to run on the application's event loop. +/// Returns the result asynchronously. +pub(crate) fn run_on_main( + dispatcher: Arc, + func: F, +) -> impl Future +where + F: FnOnce() -> R + Send + 'static, + R: Send + 'static, +{ + spawn_on_main(dispatcher, move || async move { func() }) +} + +/// Enqueues the given closure to be run on the application's event loop. The +/// closure returns a future which will be run to completion on the main thread. pub(crate) fn spawn_on_main( dispatcher: Arc, func: impl FnOnce() -> F + Send + 'static, diff --git a/crates/gpui3/src/gpui3.rs b/crates/gpui3/src/gpui3.rs index 8c8e64589f..60341b3f2b 100644 --- a/crates/gpui3/src/gpui3.rs +++ b/crates/gpui3/src/gpui3.rs @@ -31,7 +31,6 @@ pub use serde_json; pub use smallvec; pub use smol::Timer; use std::{ - future::Future, ops::{Deref, DerefMut}, sync::Arc, }; @@ -176,27 +175,10 @@ impl MainThreadOnly { Self { dispatcher, value } } - pub(crate) fn borrow_on_main_thread(&self) -> &T { + pub(crate) fn borrow_on_main_thread(&self) -> &Arc { assert!(self.dispatcher.is_main_thread()); &self.value } - - pub(crate) fn read( - &self, - f: impl FnOnce(&T) -> F + Send + 'static, - ) -> impl Future - where - F: Future + 'static, - R: Send + 'static, - { - let this = self.clone(); - crate::spawn_on_main(self.dispatcher.clone(), || async move { - // Required so we move `this` instead of this.value. Only `this` is `Send`. - let this = this; - let result = f(&this.value); - result.await - }) - } } unsafe impl Send for MainThreadOnly {} diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index 37e37716a4..1e773ca4d2 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -92,9 +92,12 @@ impl<'a, 'w> WindowContext<'a, 'w> { cx.window.root_view = Some(root_view); let scene = cx.window.scene.take(); dbg!(&scene); - let _ = cx.window.platform_window.read(|platform_window| { - platform_window.draw(scene); - future::ready(()) + + self.run_on_main(|cx| { + cx.window + .platform_window + .borrow_on_main_thread() + .draw(scene); }); Ok(()) diff --git a/crates/storybook2/src/storybook2.rs b/crates/storybook2/src/storybook2.rs index bc927b78fa..3b70bfd3af 100644 --- a/crates/storybook2/src/storybook2.rs +++ b/crates/storybook2/src/storybook2.rs @@ -1,5 +1,7 @@ #![allow(dead_code, unused_variables)] +use std::future; + use log::LevelFilter; use simplelog::SimpleLogger; @@ -18,6 +20,11 @@ fn main() { gpui3::App::production().run(|cx| { let window = cx.open_window(Default::default(), |cx| workspace(cx)); + + cx.spawn_on_main(move |platform, _| { + platform.activate(true); + future::ready(()) + }); }); }