From e4e9da7673c7d79367bf14df4336de428b99cc51 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 22 Sep 2023 12:44:37 -0600 Subject: [PATCH] Checkpoint Co-Authored-By: Nathan Sobo --- crates/gpui3/src/app.rs | 151 +++++++++---------- crates/gpui3/src/elements/div.rs | 17 +-- crates/gpui3/src/gpui3.rs | 64 +++++++- crates/gpui3/src/platform.rs | 23 ++- crates/gpui3/src/platform/mac/platform.rs | 7 +- crates/gpui3/src/platform/mac/screen.rs | 38 +++-- crates/gpui3/src/platform/mac/window.rs | 119 +++++++-------- crates/gpui3/src/platform/test.rs | 3 +- crates/gpui3/src/text_system/line_wrapper.rs | 2 +- crates/gpui3/src/view.rs | 14 +- crates/gpui3/src/window.rs | 50 +++--- crates/storybook2/src/storybook2.rs | 2 +- 12 files changed, 280 insertions(+), 210 deletions(-) diff --git a/crates/gpui3/src/app.rs b/crates/gpui3/src/app.rs index 5f0b35d281..7702856d6b 100644 --- a/crates/gpui3/src/app.rs +++ b/crates/gpui3/src/app.rs @@ -1,21 +1,19 @@ use crate::{ - current_platform, Context, LayoutId, Platform, Reference, RootView, TextSystem, Window, - WindowContext, WindowHandle, WindowId, + current_platform, Context, LayoutId, MainThreadOnly, Platform, Reference, RootView, TextSystem, + Window, WindowContext, WindowHandle, WindowId, }; use anyhow::{anyhow, Result}; -use parking_lot::RwLock; +use futures::Future; +use parking_lot::Mutex; use slotmap::SlotMap; use std::{ any::Any, marker::PhantomData, - mem, sync::{Arc, Weak}, }; #[derive(Clone)] -pub struct App(Arc>>); - -pub struct MainThread; +pub struct App(Arc>); impl App { pub fn production() -> Self { @@ -28,14 +26,14 @@ impl App { } fn new(platform: Arc) -> Self { + 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_id = entities.insert(Some(Box::new(()) as Box)); Self(Arc::new_cyclic(|this| { - RwLock::new(AppContext { + Mutex::new(AppContext { this: this.clone(), - thread: PhantomData, - platform, + platform: MainThreadOnly::new(platform, dispatcher), text_system, unit_entity_id, entities, @@ -47,83 +45,65 @@ impl App { pub fn run(self, on_finish_launching: F) where - F: 'static + FnOnce(&mut AppContext), + F: 'static + FnOnce(&mut AppContext), { - let platform = self.0.read().platform.clone(); - platform.run(Box::new(move || { - let mut cx = self.0.write(); - let cx: &mut AppContext<()> = &mut cx; - let cx: &mut AppContext = unsafe { mem::transmute(cx) }; + let platform = self.0.lock().platform.clone(); + platform.borrow_on_main_thread().run(Box::new(move || { + let cx = &mut *self.0.lock(); on_finish_launching(cx); })); } } -pub struct AppContext { - this: Weak>, - thread: PhantomData, - platform: Arc, +pub struct AppContext { + this: Weak>, + platform: MainThreadOnly, text_system: Arc, pub(crate) unit_entity_id: EntityId, - pub(crate) entities: SlotMap>>, + pub(crate) entities: SlotMap>>, pub(crate) windows: SlotMap>, // We recycle this memory across layout requests. pub(crate) layout_id_buffer: Vec, } -impl AppContext<()> { - // pub fn run_on_main( - // &self, - // to_call: F, - // ) -> Result> - // where - // F: Fn(&mut AppContext) -> T + Send + Sync, - // { - // todo!(); - - // // let dispatcher = self.platform().dispatcher(); - // // if dispatcher.is_main_thread() { - // // } else { - // // let future = async move { - // // // let cx = unsafe { }; - // // }; - // // let schedule = move |runnable: Runnable| dispatcher.run_on_main_thread(runnable); - // // // let (runnable, task) = async_task::spawn_local(); - // // // runnable.schedule(); - // // } - - // // let (runnable, task) = async_task::spawn_local(future, schedule); - // // runnable.schedule(); - // // task - // } -} - -impl AppContext { +impl AppContext { pub fn text_system(&self) -> &Arc { &self.text_system } - pub fn open_window( + pub fn with_platform( + &mut self, + f: impl FnOnce(&dyn Platform, &mut Self) -> R + Send + 'static, + ) -> impl Future { + let this = self.this.upgrade().unwrap(); + self.platform.read(move |platform| { + let cx = &mut *this.lock(); + f(platform, cx) + }) + } + + pub fn open_window( &mut self, options: crate::WindowOptions, - build_root_view: impl FnOnce(&mut WindowContext) -> RootView, - ) -> WindowHandle { - let id = self.windows.insert(None); - let handle = WindowHandle::new(id); - let platform_window = self.platform.open_window(handle.into(), options); + build_root_view: impl FnOnce(&mut WindowContext) -> RootView + Send + 'static, + ) -> impl Future> { + self.with_platform(move |platform, cx| { + let id = cx.windows.insert(None); + let handle = WindowHandle::new(id); - let mut window = Window::new(id, platform_window); - let root_view = build_root_view(&mut WindowContext::mutable(self, &mut window)); - window.root_view.replace(Box::new(root_view)); + let mut window = Window::new(handle.into(), options, platform); + let root_view = build_root_view(&mut WindowContext::mutable(cx, &mut window)); + window.root_view.replace(Box::new(root_view)); - self.windows.get_mut(id).unwrap().replace(window); - handle + cx.windows.get_mut(id).unwrap().replace(window); + handle + }) } pub(crate) fn update_window( &mut self, window_id: WindowId, - update: impl FnOnce(&mut WindowContext) -> R, + update: impl FnOnce(&mut WindowContext) -> R, ) -> Result { let mut window = self .windows @@ -143,16 +123,10 @@ impl AppContext { } } -impl AppContext { - pub fn platform(&self) -> &dyn Platform { - self.platform.as_ref() - } -} +impl Context for AppContext { + type EntityContext<'a, 'w, T: Send + 'static> = ModelContext<'a, T>; -impl Context for AppContext { - type EntityContext<'a, 'w, T: 'static> = ModelContext<'a, Thread, T>; - - fn entity( + fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, ) -> Handle { @@ -163,7 +137,7 @@ impl Context for AppContext { Handle::new(id) } - fn update_entity( + fn update_entity( &mut self, handle: &Handle, update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R, @@ -183,14 +157,14 @@ impl Context for AppContext { } } -pub struct ModelContext<'a, Thread: 'static, T> { - app: Reference<'a, AppContext>, +pub struct ModelContext<'a, T> { + app: Reference<'a, AppContext>, entity_type: PhantomData, entity_id: EntityId, } -impl<'a, Thread, T: 'static> ModelContext<'a, Thread, T> { - pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self { +impl<'a, T: 'static> ModelContext<'a, T> { + pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self { Self { app: Reference::Mutable(app), entity_type: PhantomData, @@ -198,7 +172,7 @@ impl<'a, Thread, T: 'static> ModelContext<'a, Thread, T> { } } - fn immutable(app: &'a AppContext, entity_id: EntityId) -> Self { + fn immutable(app: &'a AppContext, entity_id: EntityId) -> Self { Self { app: Reference::Immutable(app), entity_type: PhantomData, @@ -224,16 +198,17 @@ impl<'a, Thread, T: 'static> ModelContext<'a, Thread, T> { } } -impl<'a, Thread, T: 'static> Context for ModelContext<'a, Thread, T> { - type EntityContext<'b, 'c, U: 'static> = ModelContext<'b, Thread, U>; - fn entity( +impl<'a, T: 'static> Context for ModelContext<'a, T> { + type EntityContext<'b, 'c, U: Send + 'static> = ModelContext<'b, U>; + + fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U, ) -> Handle { self.app.entity(build_entity) } - fn update_entity( + fn update_entity( &mut self, handle: &Handle, update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R, @@ -249,7 +224,7 @@ pub struct Handle { slotmap::new_key_type! { pub struct EntityId; } -impl Handle { +impl Handle { fn new(id: EntityId) -> Self { Self { id, @@ -279,3 +254,15 @@ impl Clone for Handle { } } } + +#[cfg(test)] +mod tests { + use super::AppContext; + + #[test] + fn test_app_context_send_sync() { + // This will not compile if `AppContext` does not implement `Send` + fn assert_send() {} + assert_send::(); + } +} diff --git a/crates/gpui3/src/elements/div.rs b/crates/gpui3/src/elements/div.rs index 61ca403576..1daef0f7c8 100644 --- a/crates/gpui3/src/elements/div.rs +++ b/crates/gpui3/src/elements/div.rs @@ -2,8 +2,9 @@ use crate::{ AnyElement, Bounds, Element, Layout, LayoutId, Overflow, ParentElement, Pixels, Point, Refineable, RefinementCascade, Result, Style, StyleHelpers, Styled, ViewContext, }; +use parking_lot::Mutex; use smallvec::SmallVec; -use std::{cell::Cell, rc::Rc}; +use std::sync::Arc; use util::ResultExt; pub struct Div { @@ -271,26 +272,22 @@ impl ParentElement for Div { } #[derive(Default, Clone)] -pub struct ScrollState(Rc>>); +pub struct ScrollState(Arc>>); impl ScrollState { pub fn x(&self) -> Pixels { - self.0.get().x + self.0.lock().x } pub fn set_x(&self, value: Pixels) { - let mut current_value = self.0.get(); - current_value.x = value; - self.0.set(current_value); + self.0.lock().x = value; } pub fn y(&self) -> Pixels { - self.0.get().y + self.0.lock().y } pub fn set_y(&self, value: Pixels) { - let mut current_value = self.0.get(); - current_value.y = value; - self.0.set(current_value); + self.0.lock().y = value; } } diff --git a/crates/gpui3/src/gpui3.rs b/crates/gpui3/src/gpui3.rs index 73fbc825ee..c364b68a7b 100644 --- a/crates/gpui3/src/gpui3.rs +++ b/crates/gpui3/src/gpui3.rs @@ -22,6 +22,7 @@ pub use color::*; pub use element::*; pub use elements::*; pub use executor::*; +use futures::channel::oneshot; pub use geometry::*; pub use gpui3_macros::*; pub use platform::*; @@ -31,7 +32,11 @@ pub use serde; pub use serde_json; pub use smallvec; pub use smol::Timer; -use std::ops::{Deref, DerefMut}; +use std::{ + future::Future, + ops::{Deref, DerefMut}, + sync::Arc, +}; pub use style::*; pub use style_helpers::*; pub use styled::*; @@ -43,14 +48,14 @@ pub use view::*; pub use window::*; pub trait Context { - type EntityContext<'a, 'w, T: 'static>; + type EntityContext<'a, 'w, T: Send + 'static>; - fn entity( + fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, ) -> Handle; - fn update_entity( + fn update_entity( &mut self, handle: &Handle, update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R, @@ -110,3 +115,54 @@ impl<'a, T> DerefMut for Reference<'a, T> { } } } + +pub(crate) struct MainThreadOnly { + dispatcher: Arc, + value: Arc, +} + +impl Clone for MainThreadOnly { + fn clone(&self) -> Self { + Self { + dispatcher: self.dispatcher.clone(), + value: self.value.clone(), + } + } +} + +/// Allows a value to be accessed only on the main thread, allowing a non-`Send` type +/// to become `Send`. +impl MainThreadOnly { + pub(crate) fn new(value: Arc, dispatcher: Arc) -> Self { + Self { dispatcher, value } + } + + pub(crate) fn borrow_on_main_thread(&self) -> &T { + assert!(self.dispatcher.is_main_thread()); + &self.value + } + + pub(crate) fn read( + &self, + f: impl FnOnce(&T) -> R + Send + 'static, + ) -> impl Future + where + R: Send + 'static, + { + let (tx, rx) = oneshot::channel(); + if self.dispatcher.is_main_thread() { + let _ = tx.send(f(&self.value)); + } else { + let this = self.clone(); + let _ = 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 _ = tx.send(f(&this.value)); + }); + } + + async move { rx.await.unwrap() } + } +} + +unsafe impl Send for MainThreadOnly {} diff --git a/crates/gpui3/src/platform.rs b/crates/gpui3/src/platform.rs index 95b1d4338f..4974d7e9e9 100644 --- a/crates/gpui3/src/platform.rs +++ b/crates/gpui3/src/platform.rs @@ -15,6 +15,7 @@ use futures::channel::oneshot; use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; use seahash::SeaHasher; use serde::{Deserialize, Serialize}; +use std::ffi::c_void; use std::hash::{Hash, Hasher}; use std::{ any::Any, @@ -40,7 +41,7 @@ pub(crate) fn current_platform() -> Arc { Arc::new(MacPlatform::new()) } -pub trait Platform { +pub trait Platform: 'static { fn dispatcher(&self) -> Arc; fn text_system(&self) -> Arc; @@ -53,7 +54,7 @@ pub trait Platform { fn unhide_other_apps(&self); fn screens(&self) -> Vec>; - fn screen_by_id(&self, id: uuid::Uuid) -> Option>; + fn screen_by_id(&self, id: ScreenId) -> Option>; fn main_window(&self) -> Option; fn open_window( &self, @@ -96,12 +97,23 @@ pub trait Platform { } pub trait PlatformScreen: Debug { + fn id(&self) -> Option; + fn handle(&self) -> PlatformScreenHandle; fn as_any(&self) -> &dyn Any; fn bounds(&self) -> Bounds; fn content_bounds(&self) -> Bounds; - fn display_uuid(&self) -> Option; } +pub struct PlatformScreenHandle(pub *mut c_void); + +impl Debug for PlatformScreenHandle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "PlatformScreenHandle({:p})", self.0) + } +} + +unsafe impl Send for PlatformScreenHandle {} + pub trait PlatformWindow: HasRawWindowHandle + HasRawDisplayHandle { fn bounds(&self) -> WindowBounds; fn content_size(&self) -> Size; @@ -190,6 +202,9 @@ pub trait InputHandler { fn bounds_for_range(&self, range_utf16: Range) -> Option>; } +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct ScreenId(pub(crate) Uuid); + #[derive(Copy, Clone, Debug)] pub enum RasterizationOptions { Alpha, @@ -205,7 +220,7 @@ pub struct WindowOptions { pub show: bool, pub kind: WindowKind, pub is_movable: bool, - pub screen: Option>, + pub screen: Option, } impl Default for WindowOptions { diff --git a/crates/gpui3/src/platform/mac/platform.rs b/crates/gpui3/src/platform/mac/platform.rs index 0c5367eb9f..cde57f8bcf 100644 --- a/crates/gpui3/src/platform/mac/platform.rs +++ b/crates/gpui3/src/platform/mac/platform.rs @@ -2,7 +2,7 @@ use super::BoolExt; use crate::{ AnyWindowHandle, ClipboardItem, CursorStyle, Event, MacDispatcher, MacScreen, MacTextSystem, MacWindow, PathPromptOptions, Platform, PlatformScreen, PlatformTextSystem, PlatformWindow, - Result, SemanticVersion, WindowOptions, + Result, ScreenId, SemanticVersion, WindowOptions, }; use anyhow::anyhow; use block::ConcreteBlock; @@ -462,7 +462,7 @@ impl Platform for MacPlatform { .collect() } - fn screen_by_id(&self, id: uuid::Uuid) -> Option> { + fn screen_by_id(&self, id: ScreenId) -> Option> { MacScreen::find_by_id(id).map(|screen| Rc::new(screen) as Rc<_>) } @@ -479,8 +479,7 @@ impl Platform for MacPlatform { handle: AnyWindowHandle, options: WindowOptions, ) -> Box { - let dispatcher = self.0.lock().dispatcher.clone(); - Box::new(MacWindow::open(handle, options, dispatcher)) + Box::new(MacWindow::open(handle, options, self)) } fn open_url(&self, url: &str) { diff --git a/crates/gpui3/src/platform/mac/screen.rs b/crates/gpui3/src/platform/mac/screen.rs index 259f4f4a16..6a7b325dee 100644 --- a/crates/gpui3/src/platform/mac/screen.rs +++ b/crates/gpui3/src/platform/mac/screen.rs @@ -1,5 +1,8 @@ use super::ns_string; -use crate::{platform, point, px, size, Bounds, Pixels, PlatformScreen}; +use crate::{ + platform, point, px, size, Bounds, MainThreadOnly, Pixels, PlatformScreen, + PlatformScreenHandle, ScreenId, +}; use cocoa::{ appkit::NSScreen, base::{id, nil}, @@ -10,6 +13,7 @@ use core_foundation::{ uuid::{CFUUIDGetUUIDBytes, CFUUIDRef}, }; use core_graphics::display::CGDirectDisplayID; +use objc::runtime::Object; use std::{any::Any, ffi::c_void}; use uuid::Uuid; @@ -23,10 +27,18 @@ pub struct MacScreen { pub(crate) native_screen: id, } +unsafe impl Send for MacScreen {} + impl MacScreen { + pub(crate) fn from_handle(handle: PlatformScreenHandle) -> Self { + Self { + native_screen: handle.0 as *mut Object, + } + } + /// Get the screen with the given UUID. - pub fn find_by_id(uuid: Uuid) -> Option { - Self::all().find(|screen| platform::MacScreen::display_uuid(screen) == Some(uuid)) + pub fn find_by_id(id: ScreenId) -> Option { + Self::all().find(|screen| screen.id() == Some(id)) } /// Get the primary screen - the one with the menu bar, and whose bottom left @@ -82,14 +94,8 @@ impl MacScreen { } impl PlatformScreen for MacScreen { - fn as_any(&self) -> &dyn Any { - self - } - - fn display_uuid(&self) -> Option { + fn id(&self) -> Option { unsafe { - // Screen ids are not stable. Further, the default device id is also unstable across restarts. - // CGDisplayCreateUUIDFromDisplayID is stable but not exposed in the bindings we use. // This approach is similar to that which winit takes // https://github.com/rust-windowing/winit/blob/402cbd55f932e95dbfb4e8b5e8551c49e56ff9ac/src/platform_impl/macos/monitor.rs#L99 let device_description = self.native_screen.deviceDescription(); @@ -114,7 +120,7 @@ impl PlatformScreen for MacScreen { } let bytes = CFUUIDGetUUIDBytes(cfuuid); - Some(Uuid::from_bytes([ + Some(ScreenId(Uuid::from_bytes([ bytes.byte0, bytes.byte1, bytes.byte2, @@ -131,10 +137,18 @@ impl PlatformScreen for MacScreen { bytes.byte13, bytes.byte14, bytes.byte15, - ])) + ]))) } } + fn handle(&self) -> PlatformScreenHandle { + PlatformScreenHandle(self.native_screen as *mut c_void) + } + + fn as_any(&self) -> &dyn Any { + self + } + fn bounds(&self) -> Bounds { unsafe { Self::screen_bounds_from_native(self.native_screen.frame()) } } diff --git a/crates/gpui3/src/platform/mac/window.rs b/crates/gpui3/src/platform/mac/window.rs index 23a4e8fc6b..d5ef95c76c 100644 --- a/crates/gpui3/src/platform/mac/window.rs +++ b/crates/gpui3/src/platform/mac/window.rs @@ -1,8 +1,8 @@ use crate::{ point, px, size, AnyWindowHandle, Bounds, Event, InputHandler, KeyDownEvent, Keystroke, - MacDispatcher, MacScreen, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, - MouseMovedEvent, MouseUpEvent, NSRectExt, Pixels, PlatformDispatcher, PlatformScreen, - PlatformWindow, Point, Size, Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions, + MacScreen, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent, + MouseUpEvent, NSRectExt, Pixels, Platform, PlatformDispatcher, PlatformScreen, PlatformWindow, + Point, Size, Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions, WindowPromptLevel, }; use block::ConcreteBlock; @@ -38,8 +38,8 @@ use std::{ ops::Range, os::raw::c_char, ptr, - rc::{Rc, Weak}, - sync::Arc, + rc::Rc, + sync::{Arc, Weak}, time::Duration, }; @@ -417,11 +417,7 @@ unsafe impl Send for WindowState {} pub struct MacWindow(Arc>); impl MacWindow { - pub fn open( - handle: AnyWindowHandle, - options: WindowOptions, - dispatcher: Arc, - ) -> Self { + pub fn open(handle: AnyWindowHandle, options: WindowOptions, platform: &dyn Platform) -> Self { unsafe { let pool = NSAutoreleasePool::new(nil); @@ -454,9 +450,7 @@ impl MacWindow { NO, options .screen - .and_then(|screen| { - Some(screen.as_any().downcast_ref::()?.native_screen) - }) + .map(|screen| MacScreen::from_handle(screen).native_screen) .unwrap_or(nil), ); assert!(!native_window.is_null()); @@ -487,7 +481,7 @@ impl MacWindow { let window = Self(Arc::new(Mutex::new(WindowState { handle, - dispatcher, + dispatcher: platform.dispatcher(), native_window, kind: options.kind, event_callback: None, @@ -610,7 +604,7 @@ impl MacWindow { let app = NSApplication::sharedApplication(nil); let main_window: id = msg_send![app, mainWindow]; if msg_send![main_window, isKindOfClass: WINDOW_CLASS] { - let handle = get_window_state(&*main_window).borrow().handle; + let handle = get_window_state(&*main_window).lock().handle; Some(handle) } else { None @@ -892,7 +886,7 @@ impl PlatformWindow for MacWindow { let is_panel: BOOL = msg_send![top_most_window, isKindOfClass: PANEL_CLASS]; let is_window: BOOL = msg_send![top_most_window, isKindOfClass: WINDOW_CLASS]; if is_panel == YES || is_window == YES { - let topmost_window = get_window_state(&*top_most_window).borrow().handle; + let topmost_window = get_window_state(&*top_most_window).lock().handle; topmost_window == self_handle } else { // Someone else's window is on top @@ -909,9 +903,9 @@ fn get_scale_factor(native_window: id) -> f32 { } } -unsafe fn get_window_state(object: &Object) -> Rc> { +unsafe fn get_window_state(object: &Object) -> Arc> { let raw: *mut c_void = *object.get_ivar(WINDOW_STATE_IVAR); - let rc1 = Rc::from_raw(raw as *mut RefCell); + let rc1 = Arc::from_raw(raw as *mut Mutex); let rc2 = rc1.clone(); mem::forget(rc1); rc2 @@ -950,7 +944,7 @@ 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().borrow_mut(); + let mut window_state_borrow = window_state.as_ref().lock(); let window_height = window_state_borrow.content_size().height; let event = unsafe { Event::from_native(native_event, Some(window_height)) }; @@ -990,7 +984,7 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: } let mut handled = false; - let mut window_state_borrow = window_state.borrow_mut(); + 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 is_held = event.is_held; @@ -1056,7 +1050,7 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: } } - window_state.borrow_mut().event_callback = Some(callback); + window_state.lock().event_callback = Some(callback); } } else { handled = true; @@ -1070,8 +1064,8 @@ 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 = Rc::downgrade(&window_state); - let mut window_state_borrow = window_state.as_ref().borrow_mut(); + 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 window_height = window_state_borrow.content_size().height; @@ -1172,7 +1166,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { if let Some(event) = synthesized_second_event { callback(event); } - window_state.borrow_mut().event_callback = Some(callback); + window_state.lock().event_callback = Some(callback); } } } @@ -1181,7 +1175,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().borrow_mut(); + let mut window_state_borrow = window_state.as_ref().lock(); let keystroke = Keystroke { modifiers: Default::default(), @@ -1196,13 +1190,13 @@ extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) { if let Some(mut callback) = window_state_borrow.event_callback.take() { drop(window_state_borrow); callback(event); - window_state.borrow_mut().event_callback = Some(callback); + window_state.lock().event_callback = Some(callback); } } extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) { let window_state = unsafe { get_window_state(this) }; - window_state.as_ref().borrow().move_traffic_light(); + window_state.as_ref().lock().move_traffic_light(); } extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) { @@ -1215,27 +1209,27 @@ 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().borrow_mut(); + 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); callback(is_fullscreen); - window_state.borrow_mut().fullscreen_callback = Some(callback); + window_state.lock().fullscreen_callback = Some(callback); } } 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().borrow_mut(); + 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); callback(); - window_state.borrow_mut().moved_callback = Some(callback); + window_state.lock().moved_callback = Some(callback); } } 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.borrow(); + let window_state_borrow = window_state.lock(); let is_active = unsafe { window_state_borrow.native_window.isKeyWindow() == YES }; // When opening a pop-up while the application isn't active, Cocoa sends a spurious @@ -1259,22 +1253,22 @@ extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) let dispatcher = window_state_borrow.dispatcher.clone(); drop(window_state_borrow); let _ = crate::spawn_on_main_local(dispatcher, async move { - let mut window_state_borrow = window_state.as_ref().borrow_mut(); + 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); callback(is_active); - window_state.borrow_mut().activate_callback = Some(callback); + window_state.lock().activate_callback = Some(callback); }; }); } 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().borrow_mut(); + 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 should_close = callback(); - window_state.borrow_mut().should_close_callback = Some(callback); + window_state.lock().should_close_callback = Some(callback); should_close as BOOL } else { YES @@ -1287,8 +1281,7 @@ extern "C" fn close_window(this: &Object, _: Sel) { let window_state = get_window_state(this); window_state .as_ref() - .try_borrow_mut() - .ok() + .try_lock() .and_then(|mut window_state| window_state.close_callback.take()) }; @@ -1302,13 +1295,13 @@ extern "C" fn close_window(this: &Object, _: Sel) { // extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id { // let window_state = unsafe { get_window_state(this) }; -// let window_state = window_state.as_ref().borrow(); +// let window_state = window_state.as_ref().lock(); // window_state.renderer.layer().as_ptr() as 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().borrow_mut(); + let mut window_state_borrow = window_state.as_ref().lock(); // unsafe { // let scale_factor = window_state_borrow.scale_factor() as f64; @@ -1331,13 +1324,13 @@ extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel) { if let Some(mut callback) = window_state_borrow.resize_callback.take() { drop(window_state_borrow); callback(); - window_state.as_ref().borrow_mut().resize_callback = Some(callback); + 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().borrow(); + let window_state_borrow = window_state.as_ref().lock(); if window_state_borrow.content_size() == size.into() { return; @@ -1361,18 +1354,18 @@ extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) { // } drop(window_state_borrow); - let mut window_state_borrow = window_state.borrow_mut(); + let mut window_state_borrow = window_state.lock(); if let Some(mut callback) = window_state_borrow.resize_callback.take() { drop(window_state_borrow); callback(); - window_state.borrow_mut().resize_callback = Some(callback); + window_state.lock().resize_callback = Some(callback); }; } extern "C" fn display_layer(_this: &Object, _: Sel, _: id) { // unsafe { // let window_state = get_window_state(this); - // let mut window_state = window_state.as_ref().borrow_mut(); + // let mut window_state = window_state.as_ref().lock(); // if let Some(scene) = window_state.scene_to_render.take() { // window_state.renderer.render(&scene); // }; @@ -1408,7 +1401,7 @@ extern "C" fn first_rect_for_character_range( _: id, ) -> NSRect { let frame = unsafe { - let window = get_window_state(this).borrow().native_window; + let window = get_window_state(this).lock().native_window; NSView::frame(window) }; with_input_handler(this, |input_handler| { @@ -1432,7 +1425,7 @@ 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.borrow_mut(); + let mut window_state_borrow = window_state.lock(); let pending_key_down = window_state_borrow.pending_key_down.take(); drop(window_state_borrow); @@ -1448,8 +1441,8 @@ extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NS .unwrap(); let replacement_range = replacement_range.to_range(); - window_state.borrow_mut().ime_text = Some(text.to_string()); - window_state.borrow_mut().ime_state = ImeState::Acted; + window_state.lock().ime_text = Some(text.to_string()); + window_state.lock().ime_state = ImeState::Acted; let is_composing = with_input_handler(this, |input_handler| input_handler.marked_text_range()) @@ -1466,7 +1459,7 @@ extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NS replacement_range, text: text.to_string(), }); - window_state.borrow_mut().pending_key_down = Some(pending_key_down); + window_state.lock().pending_key_down = Some(pending_key_down); } } } @@ -1480,7 +1473,7 @@ extern "C" fn set_marked_text( ) { unsafe { let window_state = get_window_state(this); - window_state.borrow_mut().pending_key_down.take(); + window_state.lock().pending_key_down.take(); let is_attributed_string: BOOL = msg_send![text, isKindOfClass: [class!(NSAttributedString)]]; @@ -1495,8 +1488,8 @@ extern "C" fn set_marked_text( .to_str() .unwrap(); - window_state.borrow_mut().ime_state = ImeState::Acted; - window_state.borrow_mut().ime_text = Some(text.to_string()); + window_state.lock().ime_state = ImeState::Acted; + window_state.lock().ime_text = Some(text.to_string()); with_input_handler(this, |input_handler| { input_handler.replace_and_mark_text_in_range(replacement_range, text, selected_range); @@ -1507,7 +1500,7 @@ extern "C" fn set_marked_text( extern "C" fn unmark_text(this: &Object, _: Sel) { unsafe { let state = get_window_state(this); - let mut borrow = state.borrow_mut(); + let mut borrow = state.lock(); borrow.ime_state = ImeState::Acted; borrow.ime_text.take(); } @@ -1541,7 +1534,7 @@ extern "C" fn attributed_substring_for_proposed_range( extern "C" fn do_command_by_selector(this: &Object, _: Sel, _: Sel) { unsafe { let state = get_window_state(this); - let mut borrow = state.borrow_mut(); + let mut borrow = state.lock(); borrow.ime_state = ImeState::Continue; borrow.ime_text.take(); } @@ -1550,11 +1543,11 @@ 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().borrow_mut(); + let mut state_borrow = state.as_ref().lock(); if let Some(mut callback) = state_borrow.appearance_changed_callback.take() { drop(state_borrow); callback(); - state.borrow_mut().appearance_changed_callback = Some(callback); + state.lock().appearance_changed_callback = Some(callback); } } } @@ -1562,7 +1555,7 @@ 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().borrow(); + let state_borrow = state.as_ref().lock(); return if state_borrow.kind == WindowKind::PopUp { YES } else { @@ -1572,19 +1565,19 @@ extern "C" fn accepts_first_mouse(this: &Object, _: Sel, _: id) -> BOOL { } async fn synthetic_drag( - window_state: Weak>, + window_state: Weak>, drag_id: usize, event: MouseMovedEvent, ) { loop { Timer::after(Duration::from_millis(16)).await; if let Some(window_state) = window_state.upgrade() { - let mut window_state_borrow = window_state.borrow_mut(); + 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); callback(Event::MouseMoved(event.clone())); - window_state.borrow_mut().event_callback = Some(callback); + window_state.lock().event_callback = Some(callback); } } else { break; @@ -1598,11 +1591,11 @@ where F: FnOnce(&mut dyn InputHandler) -> R, { let window_state = unsafe { get_window_state(window) }; - let mut window_state_borrow = window_state.as_ref().borrow_mut(); + 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 result = f(input_handler.as_mut()); - window_state.borrow_mut().input_handler = Some(input_handler); + window_state.lock().input_handler = Some(input_handler); Some(result) } else { None diff --git a/crates/gpui3/src/platform/test.rs b/crates/gpui3/src/platform/test.rs index 4463d27b65..8c418eb9c1 100644 --- a/crates/gpui3/src/platform/test.rs +++ b/crates/gpui3/src/platform/test.rs @@ -1,4 +1,5 @@ use super::Platform; +use crate::ScreenId; pub struct TestPlatform; @@ -49,7 +50,7 @@ impl Platform for TestPlatform { todo!() } - fn screen_by_id(&self, _id: uuid::Uuid) -> Option> { + fn screen_by_id(&self, _id: ScreenId) -> Option> { todo!() } diff --git a/crates/gpui3/src/text_system/line_wrapper.rs b/crates/gpui3/src/text_system/line_wrapper.rs index d976aba466..4cca331da7 100644 --- a/crates/gpui3/src/text_system/line_wrapper.rs +++ b/crates/gpui3/src/text_system/line_wrapper.rs @@ -215,7 +215,7 @@ impl Boundary { #[cfg(test)] mod tests { use super::*; - use crate::{App, AppContext, FontWeight}; + use crate::{App, FontWeight}; #[test] fn test_wrap_line() { diff --git a/crates/gpui3/src/view.rs b/crates/gpui3/src/view.rs index 887963742e..af92760ac4 100644 --- a/crates/gpui3/src/view.rs +++ b/crates/gpui3/src/view.rs @@ -2,11 +2,11 @@ use crate::{ AnyElement, Element, Handle, IntoAnyElement, Layout, LayoutId, Result, ViewContext, WindowContext, }; -use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc}; +use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc, sync::Arc}; pub struct View { state: Handle, - render: Rc) -> AnyElement>, + render: Arc) -> AnyElement + Send + Sync + 'static>, parent_state_type: PhantomData

, } @@ -24,16 +24,16 @@ pub type RootView = View; pub fn view>( state: Handle, - render: impl 'static + Fn(&mut S, &mut ViewContext) -> E, + render: impl Fn(&mut S, &mut ViewContext) -> E + Send + Sync + 'static, ) -> View { View { state, - render: Rc::new(move |state, cx| render(state, cx).into_any()), + render: Arc::new(move |state, cx| render(state, cx).into_any()), parent_state_type: PhantomData, } } -impl View { +impl View { pub fn into_any(self) -> AnyView { AnyView { view: Rc::new(RefCell::new(self)), @@ -42,7 +42,7 @@ impl View { } } -impl Element for View { +impl Element for View { type State = P; type FrameState = AnyElement; @@ -80,7 +80,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); diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index 5f6d6ea751..bce9412e21 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -1,4 +1,7 @@ -use crate::{AvailableSpace, PlatformWindow, Point, Size, Style, TextStyle, TextStyleRefinement}; +use crate::{ + AvailableSpace, MainThreadOnly, Platform, PlatformWindow, Point, Size, Style, TextStyle, + TextStyleRefinement, WindowOptions, +}; use super::{ px, taffy::LayoutId, AppContext, Bounds, Context, EntityId, Handle, Pixels, Reference, @@ -10,49 +13,54 @@ use refineable::Refineable; use std::{ any::{Any, TypeId}, marker::PhantomData, + sync::Arc, }; pub struct AnyWindow {} pub struct Window { - id: WindowId, - platform_window: Box, + handle: AnyWindowHandle, + platform_window: MainThreadOnly>, rem_size: Pixels, layout_engine: TaffyLayoutEngine, text_style_stack: Vec, - pub(crate) root_view: Option>, + pub(crate) root_view: Option>, + mouse_position: Point, } impl Window { - pub fn new(id: WindowId, platform_window: Box) -> Window { + pub fn new(handle: AnyWindowHandle, options: WindowOptions, platform: &dyn Platform) -> Window { + let platform_window = Arc::new(platform.open_window(handle, options)); + let mouse_position = platform_window.mouse_position(); Window { - id, - platform_window, + handle, + platform_window: MainThreadOnly::new(platform_window, platform.dispatcher()), rem_size: px(16.), layout_engine: TaffyLayoutEngine::new(), text_style_stack: Vec::new(), root_view: None, + mouse_position, } } } #[derive(Deref, DerefMut)] -pub struct WindowContext<'a, 'b, Thread = ()> { +pub struct WindowContext<'a, 'b> { #[deref] #[deref_mut] - app: Reference<'a, AppContext>, + app: Reference<'a, AppContext>, window: Reference<'b, Window>, } -impl<'a, 'w, Thread> WindowContext<'a, 'w, Thread> { - pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window) -> Self { +impl<'a, 'w> WindowContext<'a, 'w> { + pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window) -> Self { Self { app: Reference::Mutable(app), window: Reference::Mutable(window), } } - pub(crate) fn immutable(app: &'a AppContext, window: &'w Window) -> Self { + pub(crate) fn immutable(app: &'a AppContext, window: &'w Window) -> Self { Self { app: Reference::Immutable(app), window: Reference::Immutable(window), @@ -115,15 +123,15 @@ impl<'a, 'w, Thread> WindowContext<'a, 'w, Thread> { } pub fn mouse_position(&self) -> Point { - self.window.platform_window.mouse_position() + self.window.mouse_position } fn update_window( &mut self, window_id: WindowId, - update: impl FnOnce(&mut WindowContext) -> R, + update: impl FnOnce(&mut WindowContext) -> R, ) -> Result { - if window_id == self.window.id { + if window_id == self.window.handle.id { Ok(update(self)) } else { self.app.update_window(window_id, update) @@ -132,9 +140,9 @@ impl<'a, 'w, Thread> WindowContext<'a, 'w, Thread> { } impl Context for WindowContext<'_, '_> { - type EntityContext<'a, 'w, T: 'static> = ViewContext<'a, 'w, T>; + type EntityContext<'a, 'w, T: Send + 'static> = ViewContext<'a, 'w, T>; - fn entity( + fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T, ) -> Handle { @@ -152,7 +160,7 @@ impl Context for WindowContext<'_, '_> { } } - fn update_entity( + fn update_entity( &mut self, handle: &Handle, update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R, @@ -233,16 +241,16 @@ impl<'a, 'w, T: 'static> ViewContext<'a, 'w, T> { } impl<'a, 'w, T: 'static> Context for ViewContext<'a, 'w, T> { - type EntityContext<'b, 'c, U: 'static> = ViewContext<'b, 'c, U>; + type EntityContext<'b, 'c, U: Send + 'static> = ViewContext<'b, 'c, U>; - fn entity( + fn entity( &mut self, build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T2>) -> T2, ) -> Handle { self.window_cx.entity(build_entity) } - fn update_entity( + fn update_entity( &mut self, handle: &Handle, update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R, diff --git a/crates/storybook2/src/storybook2.rs b/crates/storybook2/src/storybook2.rs index 042c98362c..637b8aadf9 100644 --- a/crates/storybook2/src/storybook2.rs +++ b/crates/storybook2/src/storybook2.rs @@ -22,7 +22,7 @@ fn main() { SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger"); gpui3::App::production().run(|cx| { - let window: gpui3::WindowHandle<()> = cx.open_window(Default::default(), |cx| todo!()); + let window = cx.open_window(Default::default(), |cx| workspace(cx)); }); // gpui3::App::new(Assets).unwrap().run(|cx| {