diff --git a/crates/gpui3/src/app.rs b/crates/gpui3/src/app.rs index 5752d91261..9e55a716dd 100644 --- a/crates/gpui3/src/app.rs +++ b/crates/gpui3/src/app.rs @@ -31,13 +31,13 @@ impl App { let dispatcher = platform.dispatcher(); let text_system = Arc::new(TextSystem::new(platform.text_system())); let mut entities = SlotMap::with_key(); - let unit_entity_id = entities.insert(Some(Box::new(()) as Box)); + let unit_entity = Handle::new(entities.insert(Some(Box::new(()) as Box))); Self(Arc::new_cyclic(|this| { Mutex::new(AppContext { this: this.clone(), platform: MainThreadOnly::new(platform, dispatcher), text_system, - unit_entity_id, + unit_entity, entities, windows: SlotMap::with_key(), pending_updates: 0, @@ -67,7 +67,7 @@ pub struct AppContext { this: Weak>, platform: MainThreadOnly, text_system: Arc, - pub(crate) unit_entity_id: EntityId, + pub(crate) unit_entity: Handle<()>, pub(crate) entities: SlotMap>>, pub(crate) windows: SlotMap>, pending_updates: usize, @@ -82,8 +82,12 @@ impl AppContext { &self.text_system } + pub fn to_async(&self) -> AsyncContext { + AsyncContext(self.this.clone()) + } + pub fn spawn_on_main( - &mut self, + &self, f: impl FnOnce(&dyn Platform, &mut Self) -> F + Send + 'static, ) -> impl Future where @@ -97,7 +101,7 @@ impl AppContext { }) } - pub fn open_window( + pub fn open_window( &mut self, options: crate::WindowOptions, build_root_view: impl FnOnce(&mut WindowContext) -> RootView + Send + 'static, @@ -105,9 +109,9 @@ impl AppContext { 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); + 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(Box::new(root_view)); + window.root_view.replace(root_view.into_any()); cx.windows.get_mut(id).unwrap().replace(window); future::ready(handle) }) @@ -184,6 +188,7 @@ impl AppContext { impl Context for AppContext { type EntityContext<'a, 'w, T: Send + Sync + 'static> = ModelContext<'a, T>; + type Result = T; fn entity( &mut self, @@ -216,6 +221,54 @@ impl Context for AppContext { } } +#[derive(Clone)] +pub struct AsyncContext(Weak>); + +impl Context for AsyncContext { + type EntityContext<'a, 'b, T: Send + Sync + 'static> = ModelContext<'a, T>; + type Result = Result; + + fn entity( + &mut self, + build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, + ) -> Result> { + let app = self + .0 + .upgrade() + .ok_or_else(|| anyhow!("app was released"))?; + let mut lock = app.lock(); + Ok(lock.entity(build_entity)) + } + + fn update_entity( + &mut self, + handle: &Handle, + update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R, + ) -> Result { + let app = self + .0 + .upgrade() + .ok_or_else(|| anyhow!("app was released"))?; + let mut lock = app.lock(); + Ok(lock.update_entity(handle, update)) + } +} + +impl AsyncContext { + pub fn update_window( + &self, + handle: AnyWindowHandle, + update: impl FnOnce(&mut WindowContext) -> T + Send + Sync, + ) -> Result { + let app = self + .0 + .upgrade() + .ok_or_else(|| anyhow!("app was released"))?; + let mut app_context = app.lock(); + app_context.update_window(handle.id, update) + } +} + pub struct ModelContext<'a, T> { app: Reference<'a, AppContext>, entity_type: PhantomData, @@ -293,6 +346,7 @@ impl<'a, T: Send + Sync + 'static> ModelContext<'a, T> { impl<'a, T: 'static> Context for ModelContext<'a, T> { type EntityContext<'b, 'c, U: Send + Sync + 'static> = ModelContext<'b, U>; + type Result = U; fn entity( &mut self, @@ -341,7 +395,7 @@ impl Handle { &self, cx: &mut C, update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R, - ) -> R { + ) -> C::Result { cx.update_entity(self, update) } } @@ -380,12 +434,15 @@ impl WeakHandle { &self, cx: &mut C, update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R, - ) -> Result { - if let Some(this) = self.upgrade(cx) { - Ok(cx.update_entity(&this, update)) - } else { - Err(anyhow!("entity released")) - } + ) -> Result + where + Result>: crate::Flatten, + { + crate::Flatten::flatten( + self.upgrade(cx) + .ok_or_else(|| anyhow!("entity release")) + .map(|this| cx.update_entity(&this, update)), + ) } } diff --git a/crates/gpui3/src/elements/stateless.rs b/crates/gpui3/src/elements/stateless.rs index c4850d28cd..9726685365 100644 --- a/crates/gpui3/src/elements/stateless.rs +++ b/crates/gpui3/src/elements/stateless.rs @@ -1,6 +1,5 @@ -use std::marker::PhantomData; - use crate::Element; +use std::marker::PhantomData; pub struct Stateless, S> { element: E, diff --git a/crates/gpui3/src/gpui3.rs b/crates/gpui3/src/gpui3.rs index 537c5490a5..562c7fcbfe 100644 --- a/crates/gpui3/src/gpui3.rs +++ b/crates/gpui3/src/gpui3.rs @@ -47,17 +47,34 @@ pub use window::*; pub trait Context { type EntityContext<'a, 'w, T: Send + Sync + 'static>; + type Result; fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, - ) -> Handle; + ) -> Self::Result>; fn update_entity( &mut self, handle: &Handle, update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R, - ) -> R; + ) -> Self::Result; +} + +pub trait Flatten { + fn flatten(self) -> Result; +} + +impl Flatten for Result> { + fn flatten(self) -> Result { + self? + } +} + +impl Flatten for Result { + fn flatten(self) -> Result { + self + } } #[derive(Clone, Eq, PartialEq)] diff --git a/crates/gpui3/src/platform.rs b/crates/gpui3/src/platform.rs index 37ce045816..acbd8f99a7 100644 --- a/crates/gpui3/src/platform.rs +++ b/crates/gpui3/src/platform.rs @@ -136,14 +136,14 @@ pub trait PlatformWindow { fn minimize(&self); fn zoom(&self); fn toggle_full_screen(&self); - fn on_event(&mut self, callback: Box bool>); - fn on_active_status_change(&mut self, callback: Box); - fn on_resize(&mut self, callback: Box); - fn on_fullscreen(&mut self, callback: Box); - fn on_moved(&mut self, callback: Box); - fn on_should_close(&mut self, callback: Box bool>); - fn on_close(&mut self, callback: Box); - fn on_appearance_changed(&mut self, callback: Box); + fn on_event(&self, callback: Box bool>); + fn on_active_status_change(&self, callback: Box); + fn on_resize(&self, callback: Box, f32)>); + fn on_fullscreen(&self, callback: Box); + fn on_moved(&self, callback: Box); + fn on_should_close(&self, callback: Box bool>); + fn on_close(&self, callback: Box); + fn on_appearance_changed(&self, callback: Box); fn is_topmost_for_position(&self, position: Point) -> bool; fn draw(&self, scene: Scene); } diff --git a/crates/gpui3/src/platform/mac/window.rs b/crates/gpui3/src/platform/mac/window.rs index 6542fb5080..6e5dc8bed2 100644 --- a/crates/gpui3/src/platform/mac/window.rs +++ b/crates/gpui3/src/platform/mac/window.rs @@ -286,7 +286,7 @@ struct MacWindowState { kind: WindowKind, event_callback: Option bool>>, activate_callback: Option>, - resize_callback: Option>, + resize_callback: Option, f32)>>, fullscreen_callback: Option>, moved_callback: Option>, should_close_callback: Option bool>>, @@ -821,35 +821,35 @@ impl PlatformWindow for MacWindow { }); } - fn on_event(&mut self, callback: Box bool>) { + fn on_event(&self, callback: Box bool>) { self.0.as_ref().lock().event_callback = Some(callback); } - fn on_active_status_change(&mut self, callback: Box) { + fn on_active_status_change(&self, callback: Box) { self.0.as_ref().lock().activate_callback = Some(callback); } - fn on_resize(&mut self, callback: Box) { + fn on_resize(&self, callback: Box, f32)>) { self.0.as_ref().lock().resize_callback = Some(callback); } - fn on_fullscreen(&mut self, callback: Box) { + fn on_fullscreen(&self, callback: Box) { self.0.as_ref().lock().fullscreen_callback = Some(callback); } - fn on_moved(&mut self, callback: Box) { + fn on_moved(&self, callback: Box) { self.0.as_ref().lock().moved_callback = Some(callback); } - fn on_should_close(&mut self, callback: Box bool>) { + fn on_should_close(&self, callback: Box bool>) { self.0.as_ref().lock().should_close_callback = Some(callback); } - fn on_close(&mut self, callback: Box) { + fn on_close(&self, callback: Box) { self.0.as_ref().lock().close_callback = Some(callback); } - fn on_appearance_changed(&mut self, callback: Box) { + fn on_appearance_changed(&self, callback: Box) { self.0.lock().appearance_changed_callback = Some(callback); } @@ -935,9 +935,9 @@ extern "C" fn handle_key_down(this: &Object, _: Sel, native_event: id) { extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: bool) -> BOOL { let window_state = unsafe { get_window_state(this) }; - let mut window_state_borrow = window_state.as_ref().lock(); + let mut lock = window_state.as_ref().lock(); - let window_height = window_state_borrow.content_size().height; + let window_height = lock.content_size().height; let event = unsafe { Event::from_native(native_event, Some(window_height)) }; if let Some(Event::KeyDown(event)) = event { @@ -946,8 +946,8 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: // makes no distinction between these two types of events, so we need to ignore // the "key down" event if we've already just processed its "key equivalent" version. if key_equivalent { - window_state_borrow.last_key_equivalent = Some(event.clone()); - } else if window_state_borrow.last_key_equivalent.take().as_ref() == Some(&event) { + lock.last_key_equivalent = Some(event.clone()); + } else if lock.last_key_equivalent.take().as_ref() == Some(&event) { return NO; } @@ -956,14 +956,14 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: // Ignore events from held-down keys after some of the initially-pressed keys // were released. if event.is_held { - if window_state_borrow.last_fresh_keydown.as_ref() != Some(&keydown) { + if lock.last_fresh_keydown.as_ref() != Some(&keydown) { return YES; } } else { - window_state_borrow.last_fresh_keydown = Some(keydown); + lock.last_fresh_keydown = Some(keydown); } - window_state_borrow.pending_key_down = Some((event, None)); - drop(window_state_borrow); + lock.pending_key_down = Some((event, None)); + drop(lock); // Send the event to the input context for IME handling, unless the `fn` modifier is // being pressed. @@ -975,12 +975,12 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: } let mut handled = false; - let mut window_state_borrow = window_state.lock(); - let ime_text = window_state_borrow.ime_text.clone(); - if let Some((event, insert_text)) = window_state_borrow.pending_key_down.take() { + let mut lock = window_state.lock(); + let ime_text = lock.ime_text.clone(); + if let Some((event, insert_text)) = lock.pending_key_down.take() { let is_held = event.is_held; - if let Some(mut callback) = window_state_borrow.event_callback.take() { - drop(window_state_borrow); + if let Some(mut callback) = lock.event_callback.take() { + drop(lock); let is_composing = with_input_handler(this, |input_handler| input_handler.marked_text_range()) @@ -1056,10 +1056,10 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { let window_state = unsafe { get_window_state(this) }; let weak_window_state = Arc::downgrade(&window_state); - let mut window_state_borrow = window_state.as_ref().lock(); - let is_active = unsafe { window_state_borrow.native_window.isKeyWindow() == YES }; + let mut lock = window_state.as_ref().lock(); + let is_active = unsafe { lock.native_window.isKeyWindow() == YES }; - let window_height = window_state_borrow.content_size().height; + let window_height = lock.content_size().height; let event = unsafe { Event::from_native(native_event, Some(window_height)) }; if let Some(mut event) = event { @@ -1095,7 +1095,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { modifiers: Modifiers { control: true, .. }, .. }) => { - window_state_borrow.synthetic_drag_counter += 1; + lock.synthetic_drag_counter += 1; return; } @@ -1109,50 +1109,46 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { .. }, ) => { - window_state_borrow.synthetic_drag_counter += 1; - let dispatcher = window_state_borrow.dispatcher.clone(); + lock.synthetic_drag_counter += 1; + let dispatcher = lock.dispatcher.clone(); let _ = crate::spawn_on_main_local( dispatcher, synthetic_drag( weak_window_state, - window_state_borrow.synthetic_drag_counter, + lock.synthetic_drag_counter, event.clone(), ), ); } - Event::MouseMoved(_) - if !(is_active || window_state_borrow.kind == WindowKind::PopUp) => - { - return - } + Event::MouseMoved(_) if !(is_active || lock.kind == WindowKind::PopUp) => return, Event::MouseUp(MouseUpEvent { button: MouseButton::Left, .. }) => { - window_state_borrow.synthetic_drag_counter += 1; + lock.synthetic_drag_counter += 1; } Event::ModifiersChanged(ModifiersChangedEvent { modifiers }) => { // Only raise modifiers changed event when they have actually changed if let Some(Event::ModifiersChanged(ModifiersChangedEvent { modifiers: prev_modifiers, - })) = &window_state_borrow.previous_modifiers_changed_event + })) = &lock.previous_modifiers_changed_event { if prev_modifiers == modifiers { return; } } - window_state_borrow.previous_modifiers_changed_event = Some(event.clone()); + lock.previous_modifiers_changed_event = Some(event.clone()); } _ => {} } - if let Some(mut callback) = window_state_borrow.event_callback.take() { - drop(window_state_borrow); + if let Some(mut callback) = lock.event_callback.take() { + drop(lock); callback(event); if let Some(event) = synthesized_second_event { callback(event); @@ -1166,7 +1162,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=300620#c6 extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) { let window_state = unsafe { get_window_state(this) }; - let mut window_state_borrow = window_state.as_ref().lock(); + let mut lock = window_state.as_ref().lock(); let keystroke = Keystroke { modifiers: Default::default(), @@ -1177,9 +1173,9 @@ extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) { is_held: false, }); - window_state_borrow.last_fresh_keydown = Some(keystroke); - if let Some(mut callback) = window_state_borrow.event_callback.take() { - drop(window_state_borrow); + lock.last_fresh_keydown = Some(keystroke); + if let Some(mut callback) = lock.event_callback.take() { + drop(lock); callback(event); window_state.lock().event_callback = Some(callback); } @@ -1200,9 +1196,9 @@ extern "C" fn window_will_exit_fullscreen(this: &Object, _: Sel, _: id) { fn window_fullscreen_changed(this: &Object, is_fullscreen: bool) { let window_state = unsafe { get_window_state(this) }; - let mut window_state_borrow = window_state.as_ref().lock(); - if let Some(mut callback) = window_state_borrow.fullscreen_callback.take() { - drop(window_state_borrow); + let mut lock = window_state.as_ref().lock(); + if let Some(mut callback) = lock.fullscreen_callback.take() { + drop(lock); callback(is_fullscreen); window_state.lock().fullscreen_callback = Some(callback); } @@ -1210,9 +1206,9 @@ fn window_fullscreen_changed(this: &Object, is_fullscreen: bool) { extern "C" fn window_did_move(this: &Object, _: Sel, _: id) { let window_state = unsafe { get_window_state(this) }; - let mut window_state_borrow = window_state.as_ref().lock(); - if let Some(mut callback) = window_state_borrow.moved_callback.take() { - drop(window_state_borrow); + let mut lock = window_state.as_ref().lock(); + if let Some(mut callback) = lock.moved_callback.take() { + drop(lock); callback(); window_state.lock().moved_callback = Some(callback); } @@ -1220,8 +1216,8 @@ extern "C" fn window_did_move(this: &Object, _: Sel, _: id) { extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) { let window_state = unsafe { get_window_state(this) }; - let window_state_borrow = window_state.lock(); - let is_active = unsafe { window_state_borrow.native_window.isKeyWindow() == YES }; + let lock = window_state.lock(); + let is_active = unsafe { lock.native_window.isKeyWindow() == YES }; // When opening a pop-up while the application isn't active, Cocoa sends a spurious // `windowDidBecomeKey` message to the previous key window even though that window @@ -1235,18 +1231,18 @@ extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) if selector == sel!(windowDidBecomeKey:) { if !is_active { unsafe { - let _: () = msg_send![window_state_borrow.native_window, resignKeyWindow]; + let _: () = msg_send![lock.native_window, resignKeyWindow]; return; } } } - let dispatcher = window_state_borrow.dispatcher.clone(); - drop(window_state_borrow); + let dispatcher = lock.dispatcher.clone(); + drop(lock); let _ = crate::spawn_on_main_local(dispatcher, async move { - let mut window_state_borrow = window_state.as_ref().lock(); - if let Some(mut callback) = window_state_borrow.activate_callback.take() { - drop(window_state_borrow); + let mut lock = window_state.as_ref().lock(); + if let Some(mut callback) = lock.activate_callback.take() { + drop(lock); callback(is_active); window_state.lock().activate_callback = Some(callback); }; @@ -1255,9 +1251,9 @@ extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) extern "C" fn window_should_close(this: &Object, _: Sel, _: id) -> BOOL { let window_state = unsafe { get_window_state(this) }; - let mut window_state_borrow = window_state.as_ref().lock(); - if let Some(mut callback) = window_state_borrow.should_close_callback.take() { - drop(window_state_borrow); + let mut lock = window_state.as_ref().lock(); + if let Some(mut callback) = lock.should_close_callback.take() { + drop(lock); let should_close = callback(); window_state.lock().should_close_callback = Some(callback); should_close as BOOL @@ -1292,38 +1288,40 @@ extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id { extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel) { let window_state = unsafe { get_window_state(this) }; - let mut window_state_borrow = window_state.as_ref().lock(); + let mut lock = window_state.as_ref().lock(); unsafe { - let scale_factor = window_state_borrow.scale_factor() as f64; - let size = window_state_borrow.content_size(); + let scale_factor = lock.scale_factor() as f64; + let size = lock.content_size(); let drawable_size: NSSize = NSSize { width: f64::from(size.width) * scale_factor, height: f64::from(size.height) * scale_factor, }; let _: () = msg_send![ - window_state_borrow.renderer.layer(), + lock.renderer.layer(), setContentsScale: scale_factor ]; let _: () = msg_send![ - window_state_borrow.renderer.layer(), + lock.renderer.layer(), setDrawableSize: drawable_size ]; } - if let Some(mut callback) = window_state_borrow.resize_callback.take() { - drop(window_state_borrow); - callback(); + if let Some(mut callback) = lock.resize_callback.take() { + let content_size = lock.content_size(); + let scale_factor = lock.scale_factor(); + drop(lock); + callback(content_size, scale_factor); window_state.as_ref().lock().resize_callback = Some(callback); }; } extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { let window_state = unsafe { get_window_state(this) }; - let window_state_borrow = window_state.as_ref().lock(); + let lock = window_state.as_ref().lock(); - if window_state_borrow.content_size() == size.into() { + if lock.content_size() == size.into() { return; } @@ -1331,7 +1329,7 @@ extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { let _: () = msg_send![super(this, class!(NSView)), setFrameSize: size]; } - let scale_factor = window_state_borrow.scale_factor() as f64; + let scale_factor = lock.scale_factor() as f64; let drawable_size: NSSize = NSSize { width: size.width * scale_factor, height: size.height * scale_factor, @@ -1339,16 +1337,18 @@ extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { unsafe { let _: () = msg_send![ - window_state_borrow.renderer.layer(), + lock.renderer.layer(), setDrawableSize: drawable_size ]; } - drop(window_state_borrow); - let mut window_state_borrow = window_state.lock(); - if let Some(mut callback) = window_state_borrow.resize_callback.take() { - drop(window_state_borrow); - callback(); + drop(lock); + let mut lock = window_state.lock(); + if let Some(mut callback) = lock.resize_callback.take() { + let content_size = lock.content_size(); + let scale_factor = lock.scale_factor(); + drop(lock); + callback(content_size, scale_factor); window_state.lock().resize_callback = Some(callback); }; } @@ -1416,9 +1416,9 @@ extern "C" fn first_rect_for_character_range( extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NSRange) { unsafe { let window_state = get_window_state(this); - let mut window_state_borrow = window_state.lock(); - let pending_key_down = window_state_borrow.pending_key_down.take(); - drop(window_state_borrow); + let mut lock = window_state.lock(); + let pending_key_down = lock.pending_key_down.take(); + drop(lock); let is_attributed_string: BOOL = msg_send![text, isKindOfClass: [class!(NSAttributedString)]]; @@ -1534,9 +1534,9 @@ extern "C" fn do_command_by_selector(this: &Object, _: Sel, _: Sel) { extern "C" fn view_did_change_effective_appearance(this: &Object, _: Sel) { unsafe { let state = get_window_state(this); - let mut state_borrow = state.as_ref().lock(); - if let Some(mut callback) = state_borrow.appearance_changed_callback.take() { - drop(state_borrow); + let mut lock = state.as_ref().lock(); + if let Some(mut callback) = lock.appearance_changed_callback.take() { + drop(lock); callback(); state.lock().appearance_changed_callback = Some(callback); } @@ -1546,8 +1546,8 @@ extern "C" fn view_did_change_effective_appearance(this: &Object, _: Sel) { extern "C" fn accepts_first_mouse(this: &Object, _: Sel, _: id) -> BOOL { unsafe { let state = get_window_state(this); - let state_borrow = state.as_ref().lock(); - return if state_borrow.kind == WindowKind::PopUp { + let lock = state.as_ref().lock(); + return if lock.kind == WindowKind::PopUp { YES } else { NO @@ -1563,10 +1563,10 @@ async fn synthetic_drag( loop { Timer::after(Duration::from_millis(16)).await; if let Some(window_state) = window_state.upgrade() { - let mut window_state_borrow = window_state.lock(); - if window_state_borrow.synthetic_drag_counter == drag_id { - if let Some(mut callback) = window_state_borrow.event_callback.take() { - drop(window_state_borrow); + let mut lock = window_state.lock(); + if lock.synthetic_drag_counter == drag_id { + if let Some(mut callback) = lock.event_callback.take() { + drop(lock); callback(Event::MouseMoved(event.clone())); window_state.lock().event_callback = Some(callback); } @@ -1582,9 +1582,9 @@ where F: FnOnce(&mut dyn InputHandler) -> R, { let window_state = unsafe { get_window_state(window) }; - let mut window_state_borrow = window_state.as_ref().lock(); - if let Some(mut input_handler) = window_state_borrow.input_handler.take() { - drop(window_state_borrow); + let mut lock = window_state.as_ref().lock(); + if let Some(mut input_handler) = lock.input_handler.take() { + drop(lock); let result = f(input_handler.as_mut()); window_state.lock().input_handler = Some(input_handler); Some(result) diff --git a/crates/gpui3/src/scene.rs b/crates/gpui3/src/scene.rs index ad02d50e53..3aeafd0eae 100644 --- a/crates/gpui3/src/scene.rs +++ b/crates/gpui3/src/scene.rs @@ -1,3 +1,5 @@ +use std::mem; + use super::{Bounds, Hsla, Pixels, Point}; use crate::{Corners, Edges}; use bytemuck::{Pod, Zeroable}; @@ -8,7 +10,7 @@ pub type PointF = Point; pub struct Scene { layers: BTreeMap, - scale_factor: f32, + pub(crate) scale_factor: f32, } #[derive(Default)] @@ -24,6 +26,13 @@ impl Scene { } } + pub fn take(&mut self) -> Scene { + Scene { + layers: mem::take(&mut self.layers), + scale_factor: self.scale_factor, + } + } + pub fn insert(&mut self, primitive: impl Into) { let mut primitive = primitive.into(); primitive.scale(self.scale_factor); diff --git a/crates/gpui3/src/taffy.rs b/crates/gpui3/src/taffy.rs index 95236a07ec..3aa53a11cd 100644 --- a/crates/gpui3/src/taffy.rs +++ b/crates/gpui3/src/taffy.rs @@ -66,6 +66,16 @@ impl TaffyLayoutEngine { .into()) } + pub fn compute_layout( + &mut self, + id: LayoutId, + available_space: Size, + ) -> Result<()> { + self.taffy + .compute_layout(id.into(), available_space.into())?; + Ok(()) + } + pub fn layout(&mut self, id: LayoutId) -> Result { if let Some(layout) = self.absolute_layouts.get(&id).cloned() { return Ok(layout); @@ -104,16 +114,6 @@ impl From for NodeId { } } -#[derive(Copy, Clone, Debug)] -pub enum AvailableSpace { - /// The amount of space available is the specified number of pixels - Definite(Pixels), - /// The amount of space available is indefinite and the node should be laid out under a min-content constraint - MinContent, - /// The amount of space available is indefinite and the node should be laid out under a max-content constraint - MaxContent, -} - struct Measureable(F); impl taffy::tree::Measurable for Measureable @@ -334,17 +334,28 @@ impl + Clone + Debug, U> From> for taffy::geometry::Size { // } // } -// impl From> for Size { -// fn from(taffy_size: TaffySize) -> Self { -// Size { -// width: From::from(taffy_size.width), -// height: From::from(taffy_size.height), -// } -// } -// } +#[derive(Copy, Clone, Debug)] +pub enum AvailableSpace { + /// The amount of space available is the specified number of pixels + Definite(Pixels), + /// The amount of space available is indefinite and the node should be laid out under a min-content constraint + MinContent, + /// The amount of space available is indefinite and the node should be laid out under a max-content constraint + MaxContent, +} + +impl From for TaffyAvailableSpace { + fn from(space: AvailableSpace) -> TaffyAvailableSpace { + match space { + AvailableSpace::Definite(Pixels(value)) => TaffyAvailableSpace::Definite(value), + AvailableSpace::MinContent => TaffyAvailableSpace::MinContent, + AvailableSpace::MaxContent => TaffyAvailableSpace::MaxContent, + } + } +} impl From for AvailableSpace { - fn from(space: TaffyAvailableSpace) -> Self { + fn from(space: TaffyAvailableSpace) -> AvailableSpace { match space { TaffyAvailableSpace::Definite(value) => AvailableSpace::Definite(Pixels(value)), TaffyAvailableSpace::MinContent => AvailableSpace::MinContent, @@ -353,6 +364,12 @@ impl From for AvailableSpace { } } +impl From for AvailableSpace { + fn from(pixels: Pixels) -> Self { + AvailableSpace::Definite(pixels) + } +} + impl From<&taffy::tree::Layout> for Layout { fn from(layout: &taffy::tree::Layout) -> Self { Layout { diff --git a/crates/gpui3/src/view.rs b/crates/gpui3/src/view.rs index be38dcb4e5..e8aaf2357a 100644 --- a/crates/gpui3/src/view.rs +++ b/crates/gpui3/src/view.rs @@ -1,8 +1,10 @@ +use parking_lot::Mutex; + use crate::{ AnyElement, Element, Handle, IntoAnyElement, Layout, LayoutId, Result, ViewContext, WindowContext, }; -use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc, sync::Arc}; +use std::{any::Any, marker::PhantomData, sync::Arc}; pub struct View { state: Handle, @@ -10,6 +12,15 @@ pub struct View { parent_state_type: PhantomData

, } +impl View { + pub fn into_any(self) -> AnyView

{ + AnyView { + view: Arc::new(Mutex::new(self)), + parent_state_type: PhantomData, + } + } +} + impl Clone for View { fn clone(&self) -> Self { Self { @@ -33,15 +44,6 @@ pub fn view>( } } -impl View { - pub fn into_any(self) -> AnyView { - AnyView { - view: Rc::new(RefCell::new(self)), - parent_state_type: PhantomData, - } - } -} - impl Element for View { type State = P; type FrameState = AnyElement; @@ -70,7 +72,7 @@ impl Element for View { } } -trait ViewObject { +trait ViewObject: Send + 'static { fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box)>; fn paint( &mut self, @@ -80,7 +82,7 @@ trait ViewObject { ) -> Result<()>; } -impl ViewObject for View { +impl ViewObject for View { fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box)> { self.state.update(cx, |state, cx| { let mut element = (self.render)(state, cx); @@ -106,12 +108,12 @@ impl ViewObject for View { } pub struct AnyView { - view: Rc>, + view: Arc>, parent_state_type: PhantomData, } impl Element for AnyView { - type State = S; + type State = (); type FrameState = Box; fn layout( @@ -119,7 +121,7 @@ impl Element for AnyView { _: &mut Self::State, cx: &mut ViewContext, ) -> Result<(LayoutId, Self::FrameState)> { - self.view.borrow_mut().layout(cx) + self.view.lock().layout(cx) } fn paint( @@ -129,7 +131,7 @@ impl Element for AnyView { element: &mut Self::FrameState, cx: &mut ViewContext, ) -> Result<()> { - self.view.borrow_mut().paint(layout, element, cx) + self.view.lock().paint(layout, element, cx) } } diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index ca28928739..1e12ad67b3 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -1,16 +1,13 @@ use crate::{ - px, AppContext, AvailableSpace, Bounds, Context, Effect, EntityId, Handle, LayoutId, - MainThreadOnly, Pixels, Platform, PlatformWindow, Point, Reference, Size, Style, - TaffyLayoutEngine, TextStyle, TextStyleRefinement, WeakHandle, WindowOptions, + px, AnyView, AppContext, AvailableSpace, Bounds, Context, Effect, Element, EntityId, Handle, + LayoutId, MainThreadOnly, Pixels, Platform, PlatformWindow, Point, Reference, Scene, Size, + Style, TaffyLayoutEngine, TextStyle, TextStyleRefinement, WeakHandle, WindowOptions, }; use anyhow::Result; use derive_more::{Deref, DerefMut}; use refineable::Refineable; -use std::{ - any::{Any, TypeId}, - marker::PhantomData, - sync::Arc, -}; +use std::{any::TypeId, future, marker::PhantomData, sync::Arc}; +use util::ResultExt; pub struct AnyWindow {} @@ -18,26 +15,51 @@ pub struct Window { handle: AnyWindowHandle, platform_window: MainThreadOnly>, rem_size: Pixels, + content_size: Size, layout_engine: TaffyLayoutEngine, text_style_stack: Vec, - pub(crate) root_view: Option>, + pub(crate) root_view: Option>, mouse_position: Point, + pub(crate) scene: Scene, pub(crate) dirty: bool, } impl Window { - pub fn new(handle: AnyWindowHandle, options: WindowOptions, platform: &dyn Platform) -> Self { + pub fn new( + handle: AnyWindowHandle, + options: WindowOptions, + platform: &dyn Platform, + cx: &mut AppContext, + ) -> Self { let platform_window = platform.open_window(handle, options); let mouse_position = platform_window.mouse_position(); + let content_size = platform_window.content_size(); + let scale_factor = platform_window.scale_factor(); + platform_window.on_resize(Box::new({ + let handle = handle; + let cx = cx.to_async(); + move |content_size, scale_factor| { + cx.update_window(handle, |cx| { + cx.window.scene = Scene::new(scale_factor); + cx.window.content_size = content_size; + cx.window.dirty = true; + }) + .log_err(); + } + })); + let platform_window = MainThreadOnly::new(Arc::new(platform_window), platform.dispatcher()); + Window { handle, platform_window, rem_size: px(16.), + content_size, layout_engine: TaffyLayoutEngine::new(), text_style_stack: Vec::new(), root_view: None, mouse_position, + scene: Scene::new(scale_factor), dirty: true, } } @@ -66,6 +88,28 @@ 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| { + 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); + cx.window + .layout_engine + .compute_layout(root_layout_id, available_space)?; + let layout = cx.window.layout_engine.layout(root_layout_id)?; + root_view.paint(layout, &mut (), &mut frame_state, cx)?; + cx.window.root_view = Some(root_view); + let scene = cx.window.scene.take(); + let _ = cx.window.platform_window.read(|platform_window| { + platform_window.draw(scene); + future::ready(()) + }); + + Ok(()) + }) + } + pub fn request_layout( &mut self, style: Style, @@ -140,6 +184,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { impl Context for WindowContext<'_, '_> { type EntityContext<'a, 'w, T: Send + Sync + 'static> = ViewContext<'a, 'w, T>; + type Result = T; fn entity( &mut self, @@ -229,11 +274,11 @@ impl<'a, 'w, T: Send + Sync + 'static> ViewContext<'a, 'w, T> { } pub fn erase_state(&mut self, f: impl FnOnce(&mut ViewContext<()>) -> R) -> R { - let unit_entity_id = self.unit_entity_id; + let entity_id = self.unit_entity.id; let mut cx = ViewContext::mutable( &mut *self.window_cx.app, &mut *self.window_cx.window, - unit_entity_id, + entity_id, ); f(&mut cx) } @@ -281,6 +326,7 @@ impl<'a, 'w, T: Send + Sync + 'static> ViewContext<'a, 'w, T> { impl<'a, 'w, T: 'static> Context for ViewContext<'a, 'w, T> { type EntityContext<'b, 'c, U: Send + Sync + 'static> = ViewContext<'b, 'c, U>; + type Result = U; fn entity( &mut self,