From 343c426307e4e3a0018906632f748dd4135af9eb Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 22 Sep 2023 10:02:11 -0600 Subject: [PATCH] Checkpoint --- crates/gpui3/src/app.rs | 105 +++++---- crates/gpui3/src/element.rs | 1 - crates/gpui3/src/executor.rs | 49 +++- crates/gpui3/src/platform.rs | 8 +- crates/gpui3/src/platform/mac/platform.rs | 160 ++++++------- crates/gpui3/src/platform/mac/window.rs | 193 ++++++++------- crates/gpui3/src/platform/test.rs | 2 +- crates/gpui3/src/text_system/line_wrapper.rs | 233 ++++++++++--------- crates/gpui3/src/window.rs | 16 +- crates/storybook2/src/storybook2.rs | 2 +- 10 files changed, 401 insertions(+), 368 deletions(-) diff --git a/crates/gpui3/src/app.rs b/crates/gpui3/src/app.rs index ce6d7d88dc..5f0b35d281 100644 --- a/crates/gpui3/src/app.rs +++ b/crates/gpui3/src/app.rs @@ -3,13 +3,12 @@ use crate::{ WindowContext, WindowHandle, WindowId, }; use anyhow::{anyhow, Result}; -use async_task::Runnable; -use futures::Future; use parking_lot::RwLock; use slotmap::SlotMap; use std::{ any::Any, marker::PhantomData, + mem, sync::{Arc, Weak}, }; @@ -19,17 +18,43 @@ pub struct App(Arc>>); pub struct MainThread; impl App { - pub fn new() -> Self { - Self(Arc::new(RwLock::new(AppContext::new(current_platform())))) + pub fn production() -> Self { + Self::new(current_platform()) + } + + #[cfg(any(test, feature = "test"))] + pub fn test() -> Self { + Self::new(Arc::new(super::TestPlatform::new())) + } + + fn new(platform: Arc) -> Self { + 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)); + Self(Arc::new_cyclic(|this| { + RwLock::new(AppContext { + this: this.clone(), + thread: PhantomData, + platform, + text_system, + unit_entity_id, + entities, + windows: SlotMap::with_key(), + layout_id_buffer: Default::default(), + }) + })) } pub fn run(self, on_finish_launching: F) where F: 'static + FnOnce(&mut AppContext), { + let platform = self.0.read().platform.clone(); platform.run(Box::new(move || { let mut cx = self.0.write(); - on_finish_launching(&mut *cx); + let cx: &mut AppContext<()> = &mut cx; + let cx: &mut AppContext = unsafe { mem::transmute(cx) }; + on_finish_launching(cx); })); } } @@ -37,7 +62,7 @@ impl App { pub struct AppContext { this: Weak>, thread: PhantomData, - platform: Box, + platform: Arc, text_system: Arc, pub(crate) unit_entity_id: EntityId, pub(crate) entities: SlotMap>>, @@ -47,53 +72,33 @@ pub struct AppContext { } impl AppContext<()> { - pub fn run_on_main( - &self, - to_call: F, - ) -> Result> - where - F: Fn(&mut AppContext) -> T + Send + Sync, - { - 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); + // pub fn run_on_main( + // &self, + // to_call: F, + // ) -> Result> + // where + // F: Fn(&mut AppContext) -> T + Send + Sync, + // { + // todo!(); - let (runnable, task) = async_task::spawn_local(); - runnable.schedule(); - } + // // 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 - } + // // let (runnable, task) = async_task::spawn_local(future, schedule); + // // runnable.schedule(); + // // task + // } } impl AppContext { - pub fn new(platform: Arc) -> Self { - 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)); - - AppContext { - thread: PhantomData, - platform, - text_system, - unit_entity_id, - entities, - windows: SlotMap::with_key(), - layout_id_buffer: Default::default(), - } - } - - #[cfg(any(test, feature = "test"))] - pub fn test() -> Self { - Self::new(Arc::new(super::TestPlatform::new())) - } - pub fn text_system(&self) -> &Arc { &self.text_system } @@ -101,7 +106,7 @@ impl AppContext { pub fn open_window( &mut self, options: crate::WindowOptions, - build_root_view: impl FnOnce(&mut WindowContext) -> RootView, + build_root_view: impl FnOnce(&mut WindowContext) -> RootView, ) -> WindowHandle { let id = self.windows.insert(None); let handle = WindowHandle::new(id); @@ -118,7 +123,7 @@ impl AppContext { 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 diff --git a/crates/gpui3/src/element.rs b/crates/gpui3/src/element.rs index 2ba202f7a9..c145a9725b 100644 --- a/crates/gpui3/src/element.rs +++ b/crates/gpui3/src/element.rs @@ -1,6 +1,5 @@ use super::{Layout, LayoutId, Pixels, Point, Result, ViewContext}; pub(crate) use smallvec::SmallVec; -use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc}; pub trait Element: 'static { type State; diff --git a/crates/gpui3/src/executor.rs b/crates/gpui3/src/executor.rs index 253ddf5e36..c30a159274 100644 --- a/crates/gpui3/src/executor.rs +++ b/crates/gpui3/src/executor.rs @@ -1,7 +1,8 @@ use crate::util; +use crate::PlatformDispatcher; use anyhow::{anyhow, Result}; use async_task::Runnable; -use futures::channel::mpsc; +use futures::channel::{mpsc, oneshot}; use smol::{channel, prelude::*, Executor}; use std::{ any::Any, @@ -16,7 +17,51 @@ use std::{ time::Duration, }; -use crate::PlatformDispatcher; +/// Enqueues the given closure to be run on the application's event loop. Can be +/// called on any thread. +pub(crate) fn spawn_on_main( + dispatcher: Arc, + future: impl Future + Send + 'static, +) -> impl Future +where + R: Send + 'static, +{ + let (tx, rx) = oneshot::channel(); + let (runnable, task) = async_task::spawn( + async move { + let result = future.await; + let _ = tx.send(result); + }, + move |runnable| dispatcher.run_on_main_thread(runnable), + ); + runnable.schedule(); + task.detach(); + async move { rx.await.unwrap() } +} + +/// Enqueues the given closure to be run on the application's event loop. Must +/// be called on the main thread. +pub(crate) fn spawn_on_main_local( + dispatcher: Arc, + future: impl Future + 'static, +) -> impl Future +where + R: 'static, +{ + assert!(dispatcher.is_main_thread(), "must be called on main thread"); + + let (tx, rx) = oneshot::channel(); + let (runnable, task) = async_task::spawn_local( + async move { + let result = future.await; + let _ = tx.send(result); + }, + move |runnable| dispatcher.run_on_main_thread(runnable), + ); + runnable.schedule(); + task.detach(); + async move { rx.await.unwrap() } +} pub enum ForegroundExecutor { Platform { diff --git a/crates/gpui3/src/platform.rs b/crates/gpui3/src/platform.rs index 587e755697..95b1d4338f 100644 --- a/crates/gpui3/src/platform.rs +++ b/crates/gpui3/src/platform.rs @@ -6,8 +6,8 @@ mod mac; mod test; use crate::{ - AnyWindowHandle, Bounds, FontFeatures, FontId, FontMetrics, FontStyle, FontWeight, - ForegroundExecutor, GlyphId, LineLayout, Pixels, Point, Result, RunStyle, SharedString, Size, + AnyWindowHandle, Bounds, FontFeatures, FontId, FontMetrics, FontStyle, FontWeight, GlyphId, + LineLayout, Pixels, Point, Result, RunStyle, SharedString, Size, }; use anyhow::anyhow; use async_task::Runnable; @@ -37,14 +37,14 @@ pub use test::*; #[cfg(target_os = "macos")] pub(crate) fn current_platform() -> Arc { - Rc::new(MacPlatform::new()) + Arc::new(MacPlatform::new()) } pub trait Platform { fn dispatcher(&self) -> Arc; fn text_system(&self) -> Arc; - fn run(&self, on_finish_launching: Box); + fn run(&self, on_finish_launching: Box); fn quit(&self); fn restart(&self); fn activate(&self, ignoring_other_apps: bool); diff --git a/crates/gpui3/src/platform/mac/platform.rs b/crates/gpui3/src/platform/mac/platform.rs index c6c0e533f7..0c5367eb9f 100644 --- a/crates/gpui3/src/platform/mac/platform.rs +++ b/crates/gpui3/src/platform/mac/platform.rs @@ -1,8 +1,8 @@ use super::BoolExt; use crate::{ - AnyWindowHandle, ClipboardItem, CursorStyle, Event, ForegroundExecutor, MacDispatcher, - MacScreen, MacTextSystem, MacWindow, PathPromptOptions, Platform, PlatformScreen, - PlatformTextSystem, PlatformWindow, Result, SemanticVersion, WindowOptions, + AnyWindowHandle, ClipboardItem, CursorStyle, Event, MacDispatcher, MacScreen, MacTextSystem, + MacWindow, PathPromptOptions, Platform, PlatformScreen, PlatformTextSystem, PlatformWindow, + Result, SemanticVersion, WindowOptions, }; use anyhow::anyhow; use block::ConcreteBlock; @@ -33,9 +33,10 @@ use objc::{ runtime::{Class, Object, Sel}, sel, sel_impl, }; +use parking_lot::Mutex; use ptr::null_mut; use std::{ - cell::{Cell, RefCell}, + cell::Cell, convert::TryInto, ffi::{c_void, CStr, OsStr}, os::{raw::c_char, unix::ffi::OsStrExt}, @@ -138,10 +139,10 @@ unsafe fn build_classes() { } } -pub struct MacPlatform(RefCell); +pub struct MacPlatform(Mutex); pub struct MacPlatformState { - executor: Rc, + dispatcher: Arc, text_system: Arc, pasteboard: id, text_hash_pasteboard_type: id, @@ -161,8 +162,8 @@ pub struct MacPlatformState { impl MacPlatform { pub fn new() -> Self { - Self(RefCell::new(MacPlatformState { - executor: Rc::new(ForegroundExecutor::new(Arc::new(MacDispatcher)).unwrap()), + Self(Mutex::new(MacPlatformState { + dispatcher: Arc::new(MacDispatcher), text_system: Arc::new(MacTextSystem::new()), pasteboard: unsafe { NSPasteboard::generalPasteboard(nil) }, text_hash_pasteboard_type: unsafe { ns_string("zed-text-hash") }, @@ -182,7 +183,7 @@ impl MacPlatform { } unsafe fn read_from_pasteboard(&self, kind: id) -> Option<&[u8]> { - let pasteboard = self.0.borrow().pasteboard; + let pasteboard = self.0.lock().pasteboard; let data = pasteboard.dataForType(kind); if data == nil { None @@ -342,16 +343,16 @@ impl MacPlatform { } impl Platform for MacPlatform { - fn executor(&self) -> Rc { - self.0.borrow().executor.clone() + fn dispatcher(&self) -> Arc { + Arc::new(MacDispatcher) } fn text_system(&self) -> Arc { - self.0.borrow().text_system.clone() + self.0.lock().text_system.clone() } fn run(&self, on_finish_launching: Box) { - self.0.borrow_mut().finish_launching = Some(on_finish_launching); + self.0.lock().finish_launching = Some(on_finish_launching); unsafe { let app: id = msg_send![APP_CLASS, sharedApplication]; @@ -465,25 +466,21 @@ impl Platform for MacPlatform { MacScreen::find_by_id(id).map(|screen| Rc::new(screen) as Rc<_>) } - fn main_window(&self) -> Option { - MacWindow::main_window() - } - // fn add_status_item(&self, _handle: AnyWindowHandle) -> Box { // Box::new(StatusItem::add(self.fonts())) // } + fn main_window(&self) -> Option { + MacWindow::main_window() + } + fn open_window( &self, handle: AnyWindowHandle, options: WindowOptions, ) -> Box { - Box::new(MacWindow::open( - handle, - options, - self.executor(), - self.text_system(), - )) + let dispatcher = self.0.lock().dispatcher.clone(); + Box::new(MacWindow::open(handle, options, dispatcher)) } fn open_url(&self, url: &str) { @@ -497,7 +494,7 @@ impl Platform for MacPlatform { } fn on_open_urls(&self, callback: Box)>) { - self.0.borrow_mut().open_urls = Some(callback); + self.0.lock().open_urls = Some(callback); } fn prompt_for_paths( @@ -570,41 +567,38 @@ impl Platform for MacPlatform { fn reveal_path(&self, path: &Path) { unsafe { let path = path.to_path_buf(); - self.0 - .borrow() - .executor - .spawn(async move { - let full_path = ns_string(path.to_str().unwrap_or("")); - let root_full_path = ns_string(""); - let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace]; - let _: BOOL = msg_send![ - workspace, - selectFile: full_path - inFileViewerRootedAtPath: root_full_path - ]; - }) - .detach(); + let dispatcher = self.0.lock().dispatcher.clone(); + let _ = crate::spawn_on_main_local(dispatcher, async move { + let full_path = ns_string(path.to_str().unwrap_or("")); + let root_full_path = ns_string(""); + let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace]; + let _: BOOL = msg_send![ + workspace, + selectFile: full_path + inFileViewerRootedAtPath: root_full_path + ]; + }); } } fn on_become_active(&self, callback: Box) { - self.0.borrow_mut().become_active = Some(callback); + self.0.lock().become_active = Some(callback); } fn on_resign_active(&self, callback: Box) { - self.0.borrow_mut().resign_active = Some(callback); + self.0.lock().resign_active = Some(callback); } fn on_quit(&self, callback: Box) { - self.0.borrow_mut().quit = Some(callback); + self.0.lock().quit = Some(callback); } fn on_reopen(&self, callback: Box) { - self.0.borrow_mut().reopen = Some(callback); + self.0.lock().reopen = Some(callback); } fn on_event(&self, callback: Box bool>) { - self.0.borrow_mut().event = Some(callback); + self.0.lock().event = Some(callback); } fn os_name(&self) -> &'static str { @@ -704,7 +698,7 @@ impl Platform for MacPlatform { } fn write_to_clipboard(&self, item: ClipboardItem) { - let state = self.0.borrow(); + let state = self.0.lock(); unsafe { state.pasteboard.clearContents(); @@ -741,7 +735,7 @@ impl Platform for MacPlatform { } fn read_from_clipboard(&self) -> Option { - let state = self.0.borrow(); + let state = self.0.lock(); unsafe { if let Some(text_bytes) = self.read_from_pasteboard(NSPasteboardTypeString) { let text = String::from_utf8_lossy(text_bytes).to_string(); @@ -777,6 +771,32 @@ impl Platform for MacPlatform { } } + // fn on_menu_command(&self, callback: Box) { + // self.0.lock().menu_command = Some(callback); + // } + + // fn on_will_open_menu(&self, callback: Box) { + // self.0.lock().will_open_menu = Some(callback); + // } + + // fn on_validate_menu_command(&self, callback: Box bool>) { + // self.0.lock().validate_menu_command = Some(callback); + // } + + // fn set_menus(&self, menus: Vec, keystroke_matcher: &KeymapMatcher) { + // unsafe { + // let app: id = msg_send![APP_CLASS, sharedApplication]; + // let mut state = self.0.lock(); + // let actions = &mut state.menu_actions; + // app.setMainMenu_(self.create_menu_bar( + // menus, + // app.delegate(), + // actions, + // keystroke_matcher, + // )); + // } + // } + fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Result<()> { let url = CFString::from(url); let username = CFString::from(username); @@ -816,32 +836,6 @@ impl Platform for MacPlatform { Ok(()) } - // fn on_menu_command(&self, callback: Box) { - // self.0.borrow_mut().menu_command = Some(callback); - // } - - // fn on_will_open_menu(&self, callback: Box) { - // self.0.borrow_mut().will_open_menu = Some(callback); - // } - - // fn on_validate_menu_command(&self, callback: Box bool>) { - // self.0.borrow_mut().validate_menu_command = Some(callback); - // } - - // fn set_menus(&self, menus: Vec, keystroke_matcher: &KeymapMatcher) { - // unsafe { - // let app: id = msg_send![APP_CLASS, sharedApplication]; - // let mut state = self.0.borrow_mut(); - // let actions = &mut state.menu_actions; - // app.setMainMenu_(self.create_menu_bar( - // menus, - // app.delegate(), - // actions, - // keystroke_matcher, - // )); - // } - // } - fn read_credentials(&self, url: &str) -> Result)>> { let url = CFString::from(url); let cf_true = CFBoolean::true_value().as_CFTypeRef(); @@ -921,7 +915,7 @@ extern "C" fn send_event(this: &mut Object, _sel: Sel, native_event: id) { unsafe { if let Some(event) = Event::from_native(native_event, None) { let platform = get_foreground_platform(this); - if let Some(callback) = platform.0.borrow_mut().event.as_mut() { + if let Some(callback) = platform.0.lock().event.as_mut() { if callback(event) { return; } @@ -937,7 +931,7 @@ extern "C" fn did_finish_launching(this: &mut Object, _: Sel, _: id) { app.setActivationPolicy_(NSApplicationActivationPolicyRegular); let platform = get_foreground_platform(this); - let callback = platform.0.borrow_mut().finish_launching.take(); + let callback = platform.0.lock().finish_launching.take(); if let Some(callback) = callback { callback(); } @@ -947,7 +941,7 @@ extern "C" fn did_finish_launching(this: &mut Object, _: Sel, _: id) { extern "C" fn should_handle_reopen(this: &mut Object, _: Sel, _: id, has_open_windows: bool) { if !has_open_windows { let platform = unsafe { get_foreground_platform(this) }; - if let Some(callback) = platform.0.borrow_mut().reopen.as_mut() { + if let Some(callback) = platform.0.lock().reopen.as_mut() { callback(); } } @@ -955,21 +949,21 @@ extern "C" fn should_handle_reopen(this: &mut Object, _: Sel, _: id, has_open_wi extern "C" fn did_become_active(this: &mut Object, _: Sel, _: id) { let platform = unsafe { get_foreground_platform(this) }; - if let Some(callback) = platform.0.borrow_mut().become_active.as_mut() { + if let Some(callback) = platform.0.lock().become_active.as_mut() { callback(); } } extern "C" fn did_resign_active(this: &mut Object, _: Sel, _: id) { let platform = unsafe { get_foreground_platform(this) }; - if let Some(callback) = platform.0.borrow_mut().resign_active.as_mut() { + if let Some(callback) = platform.0.lock().resign_active.as_mut() { callback(); } } extern "C" fn will_terminate(this: &mut Object, _: Sel, _: id) { let platform = unsafe { get_foreground_platform(this) }; - if let Some(callback) = platform.0.borrow_mut().quit.as_mut() { + if let Some(callback) = platform.0.lock().quit.as_mut() { callback(); } } @@ -991,7 +985,7 @@ extern "C" fn open_urls(this: &mut Object, _: Sel, _: id, urls: id) { .collect::>() }; let platform = unsafe { get_foreground_platform(this) }; - if let Some(callback) = platform.0.borrow_mut().open_urls.as_mut() { + if let Some(callback) = platform.0.lock().open_urls.as_mut() { callback(urls); } } @@ -1000,7 +994,7 @@ extern "C" fn handle_menu_item(__this: &mut Object, _: Sel, __item: id) { todo!() // unsafe { // let platform = get_foreground_platform(this); - // let mut platform = platform.0.borrow_mut(); + // let mut platform = platform.0.lock(); // if let Some(mut callback) = platform.menu_command.take() { // let tag: NSInteger = msg_send![item, tag]; // let index = tag as usize; @@ -1017,7 +1011,7 @@ extern "C" fn validate_menu_item(__this: &mut Object, _: Sel, __item: id) -> boo // unsafe { // let mut result = false; // let platform = get_foreground_platform(this); - // let mut platform = platform.0.borrow_mut(); + // let mut platform = platform.0.lock(); // if let Some(mut callback) = platform.validate_menu_command.take() { // let tag: NSInteger = msg_send![item, tag]; // let index = tag as usize; @@ -1033,7 +1027,7 @@ extern "C" fn validate_menu_item(__this: &mut Object, _: Sel, __item: id) -> boo extern "C" fn menu_will_open(this: &mut Object, _: Sel, _: id) { unsafe { let platform = get_foreground_platform(this); - let mut platform = platform.0.borrow_mut(); + let mut platform = platform.0.lock(); if let Some(mut callback) = platform.will_open_menu.take() { callback(); platform.will_open_menu = Some(callback); @@ -1112,7 +1106,7 @@ mod tests { ); platform .0 - .borrow_mut() + .lock() .pasteboard .setData_forType(bytes, NSPasteboardTypeString); } @@ -1124,7 +1118,7 @@ mod tests { fn build_platform() -> MacPlatform { let platform = MacPlatform::new(); - platform.0.borrow_mut().pasteboard = unsafe { NSPasteboard::pasteboardWithUniqueName(nil) }; + platform.0.lock().pasteboard = unsafe { NSPasteboard::pasteboardWithUniqueName(nil) }; platform } } diff --git a/crates/gpui3/src/platform/mac/window.rs b/crates/gpui3/src/platform/mac/window.rs index 377f06cb0b..23a4e8fc6b 100644 --- a/crates/gpui3/src/platform/mac/window.rs +++ b/crates/gpui3/src/platform/mac/window.rs @@ -1,9 +1,9 @@ use crate::{ - point, px, size, AnyWindowHandle, Bounds, Event, ForegroundExecutor, InputHandler, - KeyDownEvent, Keystroke, MacScreen, Modifiers, ModifiersChangedEvent, MouseButton, - MouseDownEvent, MouseMovedEvent, MouseUpEvent, NSRectExt, Pixels, PlatformScreen, - PlatformTextSystem, PlatformWindow, Point, Size, Timer, WindowAppearance, WindowBounds, - WindowKind, WindowOptions, WindowPromptLevel, + 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, + WindowPromptLevel, }; use block::ConcreteBlock; use cocoa::{ @@ -25,6 +25,7 @@ use objc::{ runtime::{Class, Object, Protocol, Sel, BOOL, NO, YES}, sel, sel_impl, }; +use parking_lot::Mutex; use raw_window_handle::{ AppKitDisplayHandle, AppKitWindowHandle, HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle, @@ -282,6 +283,7 @@ struct InsertText { struct WindowState { handle: AnyWindowHandle, + dispatcher: Arc, native_window: id, kind: WindowKind, event_callback: Option bool>>, @@ -296,7 +298,6 @@ struct WindowState { pending_key_down: Option<(KeyDownEvent, Option)>, last_key_equivalent: Option, synthetic_drag_counter: usize, - executor: Rc, last_fresh_keydown: Option, traffic_light_position: Option>, previous_modifiers_changed_event: Option, @@ -411,14 +412,15 @@ impl WindowState { } } -pub struct MacWindow(Rc>); +unsafe impl Send for WindowState {} + +pub struct MacWindow(Arc>); impl MacWindow { pub fn open( handle: AnyWindowHandle, options: WindowOptions, - executor: Rc, - text_system: Arc, + dispatcher: Arc, ) -> Self { unsafe { let pool = NSAutoreleasePool::new(nil); @@ -483,8 +485,9 @@ impl MacWindow { assert!(!native_view.is_null()); - let window = Self(Rc::new(RefCell::new(WindowState { + let window = Self(Arc::new(Mutex::new(WindowState { handle, + dispatcher, native_window, kind: options.kind, event_callback: None, @@ -499,7 +502,6 @@ impl MacWindow { pending_key_down: None, last_key_equivalent: None, synthetic_drag_counter: 0, - executor, last_fresh_keydown: None, traffic_light_position: options .titlebar @@ -512,12 +514,12 @@ impl MacWindow { (*native_window).set_ivar( WINDOW_STATE_IVAR, - Rc::into_raw(window.0.clone()) as *const c_void, + Arc::into_raw(window.0.clone()) as *const c_void, ); native_window.setDelegate_(native_window); (*native_view).set_ivar( WINDOW_STATE_IVAR, - Rc::into_raw(window.0.clone()) as *const c_void, + Arc::into_raw(window.0.clone()) as *const c_void, ); if let Some(title) = options @@ -596,7 +598,7 @@ impl MacWindow { native_window.orderFront_(nil); } - window.0.borrow().move_traffic_light(); + window.0.lock().move_traffic_light(); pool.drain(); window @@ -619,21 +621,19 @@ impl MacWindow { impl Drop for MacWindow { fn drop(&mut self) { - let this = self.0.borrow(); - let window = this.native_window; - this.executor - .spawn(async move { - unsafe { - window.close(); - } - }) - .detach(); + let this = self.0.clone(); + let dispatcher = self.0.lock().dispatcher.clone(); + let _ = crate::spawn_on_main(dispatcher, async move { + unsafe { + this.lock().native_window.close(); + } + }); } } unsafe impl HasRawWindowHandle for MacWindow { fn raw_window_handle(&self) -> RawWindowHandle { - let ns_window = self.0.borrow().native_window; + let ns_window = self.0.lock().native_window; let ns_view = unsafe { ns_window.contentView() }; let mut handle = AppKitWindowHandle::empty(); handle.ns_window = ns_window as *mut c_void; @@ -650,24 +650,24 @@ unsafe impl HasRawDisplayHandle for MacWindow { impl PlatformWindow for MacWindow { fn bounds(&self) -> WindowBounds { - self.0.as_ref().borrow().bounds() + self.0.as_ref().lock().bounds() } fn content_size(&self) -> Size { - self.0.as_ref().borrow().content_size().into() + self.0.as_ref().lock().content_size().into() } fn scale_factor(&self) -> f32 { - self.0.as_ref().borrow().scale_factor() + self.0.as_ref().lock().scale_factor() } fn titlebar_height(&self) -> Pixels { - self.0.as_ref().borrow().titlebar_height() + self.0.as_ref().lock().titlebar_height() } fn appearance(&self) -> WindowAppearance { unsafe { - let appearance: id = msg_send![self.0.borrow().native_window, effectiveAppearance]; + let appearance: id = msg_send![self.0.lock().native_window, effectiveAppearance]; WindowAppearance::from_native(appearance) } } @@ -675,7 +675,7 @@ impl PlatformWindow for MacWindow { fn screen(&self) -> Rc { unsafe { Rc::new(MacScreen { - native_screen: self.0.as_ref().borrow().native_window.screen(), + native_screen: self.0.as_ref().lock().native_window.screen(), }) } } @@ -683,7 +683,7 @@ impl PlatformWindow for MacWindow { fn mouse_position(&self) -> Point { let position = unsafe { self.0 - .borrow() + .lock() .native_window .mouseLocationOutsideOfEventStream() }; @@ -695,7 +695,7 @@ impl PlatformWindow for MacWindow { } fn set_input_handler(&mut self, input_handler: Box) { - self.0.as_ref().borrow_mut().input_handler = Some(input_handler); + self.0.as_ref().lock().input_handler = Some(input_handler); } fn prompt( @@ -761,131 +761,123 @@ impl PlatformWindow for MacWindow { } }); let block = block.copy(); - let native_window = self.0.borrow().native_window; - self.0 - .borrow() - .executor - .spawn(async move { - let _: () = msg_send![ - alert, - beginSheetModalForWindow: native_window - completionHandler: block - ]; - }) - .detach(); + let native_window = self.0.lock().native_window; + let dispatcher = self.0.lock().dispatcher.clone(); + let _ = crate::spawn_on_main_local(dispatcher, async move { + let _: () = msg_send![ + alert, + beginSheetModalForWindow: native_window + completionHandler: block + ]; + }); done_rx } } fn activate(&self) { - let window = self.0.borrow().native_window; - self.0 - .borrow() - .executor - .spawn(async move { - unsafe { - let _: () = msg_send![window, makeKeyAndOrderFront: nil]; - } - }) - .detach(); + let window = self.0.lock().native_window; + let dispatcher = self.0.lock().dispatcher.clone(); + let _ = crate::spawn_on_main_local(dispatcher.clone(), async move { + unsafe { + let _: () = msg_send![window, makeKeyAndOrderFront: nil]; + } + }); } fn set_title(&mut self, title: &str) { unsafe { let app = NSApplication::sharedApplication(nil); - let window = self.0.borrow().native_window; + let window = self.0.lock().native_window; let title = ns_string(title); let _: () = msg_send![app, changeWindowsItem:window title:title filename:false]; let _: () = msg_send![window, setTitle: title]; - self.0.borrow().move_traffic_light(); + self.0.lock().move_traffic_light(); } } fn set_edited(&mut self, edited: bool) { unsafe { - let window = self.0.borrow().native_window; + let window = self.0.lock().native_window; msg_send![window, setDocumentEdited: edited as BOOL] } // Changing the document edited state resets the traffic light position, // so we have to move it again. - self.0.borrow().move_traffic_light(); + self.0.lock().move_traffic_light(); } fn show_character_palette(&self) { unsafe { let app = NSApplication::sharedApplication(nil); - let window = self.0.borrow().native_window; + let window = self.0.lock().native_window; let _: () = msg_send![app, orderFrontCharacterPalette: window]; } } fn minimize(&self) { - let window = self.0.borrow().native_window; + let window = self.0.lock().native_window; unsafe { window.miniaturize_(nil); } } fn zoom(&self) { - let this = self.0.borrow(); + let this = self.0.lock(); let window = this.native_window; - this.executor - .spawn(async move { - unsafe { - window.zoom_(nil); - } - }) - .detach(); + let dispatcher = this.dispatcher.clone(); + let _ = crate::spawn_on_main_local(dispatcher, async move { + unsafe { + window.zoom_(nil); + } + }); } fn toggle_full_screen(&self) { - let this = self.0.borrow(); + let this = self.0.lock(); let window = this.native_window; - this.executor - .spawn(async move { - unsafe { - window.toggleFullScreen_(nil); - } - }) - .detach(); + let dispatcher = this.dispatcher.clone(); + let _ = crate::spawn_on_main_local(dispatcher, async move { + unsafe { + window.toggleFullScreen_(nil); + } + }); } fn on_event(&mut self, callback: Box bool>) { - self.0.as_ref().borrow_mut().event_callback = Some(callback); + self.0.as_ref().lock().event_callback = Some(callback); } fn on_active_status_change(&mut self, callback: Box) { - self.0.as_ref().borrow_mut().activate_callback = Some(callback); + self.0.as_ref().lock().activate_callback = Some(callback); } fn on_resize(&mut self, callback: Box) { - self.0.as_ref().borrow_mut().resize_callback = Some(callback); + self.0.as_ref().lock().resize_callback = Some(callback); } fn on_fullscreen(&mut self, callback: Box) { - self.0.as_ref().borrow_mut().fullscreen_callback = Some(callback); + self.0.as_ref().lock().fullscreen_callback = Some(callback); } fn on_moved(&mut self, callback: Box) { - self.0.as_ref().borrow_mut().moved_callback = Some(callback); + self.0.as_ref().lock().moved_callback = Some(callback); } fn on_should_close(&mut self, callback: Box bool>) { - self.0.as_ref().borrow_mut().should_close_callback = Some(callback); + self.0.as_ref().lock().should_close_callback = Some(callback); } fn on_close(&mut self, callback: Box) { - self.0.as_ref().borrow_mut().close_callback = Some(callback); + self.0.as_ref().lock().close_callback = Some(callback); } fn on_appearance_changed(&mut self, callback: Box) { - self.0.borrow_mut().appearance_changed_callback = Some(callback); + self.0.lock().appearance_changed_callback = Some(callback); } fn is_topmost_for_position(&self, position: Point) -> bool { - let self_borrow = self.0.borrow(); + let self_borrow = self.0.lock(); let self_handle = self_borrow.handle; unsafe { @@ -1133,14 +1125,15 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) { }, ) => { window_state_borrow.synthetic_drag_counter += 1; - window_state_borrow - .executor - .spawn(synthetic_drag( + let dispatcher = window_state_borrow.dispatcher.clone(); + let _ = crate::spawn_on_main_local( + dispatcher, + synthetic_drag( weak_window_state, window_state_borrow.synthetic_drag_counter, event.clone(), - )) - .detach(); + ), + ); } Event::MouseMoved(_) @@ -1263,18 +1256,16 @@ extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id) } } - let executor = window_state_borrow.executor.clone(); + let dispatcher = window_state_borrow.dispatcher.clone(); drop(window_state_borrow); - executor - .spawn(async move { - let mut window_state_borrow = window_state.as_ref().borrow_mut(); - 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); - }; - }) - .detach(); + let _ = crate::spawn_on_main_local(dispatcher, async move { + let mut window_state_borrow = window_state.as_ref().borrow_mut(); + 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); + }; + }); } extern "C" fn window_should_close(this: &Object, _: Sel, _: id) -> BOOL { diff --git a/crates/gpui3/src/platform/test.rs b/crates/gpui3/src/platform/test.rs index aec0ef6146..4463d27b65 100644 --- a/crates/gpui3/src/platform/test.rs +++ b/crates/gpui3/src/platform/test.rs @@ -9,7 +9,7 @@ impl TestPlatform { } impl Platform for TestPlatform { - fn executor(&self) -> std::rc::Rc { + fn dispatcher(&self) -> std::sync::Arc { todo!() } diff --git a/crates/gpui3/src/text_system/line_wrapper.rs b/crates/gpui3/src/text_system/line_wrapper.rs index 5ade6aeda0..d976aba466 100644 --- a/crates/gpui3/src/text_system/line_wrapper.rs +++ b/crates/gpui3/src/text_system/line_wrapper.rs @@ -215,133 +215,134 @@ impl Boundary { #[cfg(test)] mod tests { use super::*; - use crate::{AppContext, FontWeight}; + use crate::{App, AppContext, FontWeight}; #[test] fn test_wrap_line() { - let cx = AppContext::test(); + App::test().run(|cx| { + let text_system = cx.text_system().clone(); + let family = text_system + .load_font_family(&["Courier"], &Default::default()) + .unwrap(); + let font_id = text_system + .select_font(family, Default::default(), Default::default()) + .unwrap(); - let text_system = cx.text_system().clone(); - let family = text_system - .load_font_family(&["Courier"], &Default::default()) - .unwrap(); - let font_id = text_system - .select_font(family, Default::default(), Default::default()) - .unwrap(); - - let mut wrapper = - LineWrapper::new(font_id, px(16.), text_system.platform_text_system.clone()); - assert_eq!( - wrapper - .wrap_line("aa bbb cccc ddddd eeee", px(72.)) - .collect::>(), - &[ - Boundary::new(7, 0), - Boundary::new(12, 0), - Boundary::new(18, 0) - ], - ); - assert_eq!( - wrapper - .wrap_line("aaa aaaaaaaaaaaaaaaaaa", px(72.0)) - .collect::>(), - &[ - Boundary::new(4, 0), - Boundary::new(11, 0), - Boundary::new(18, 0) - ], - ); - assert_eq!( - wrapper - .wrap_line(" aaaaaaa", px(72.)) - .collect::>(), - &[ - Boundary::new(7, 5), - Boundary::new(9, 5), - Boundary::new(11, 5), - ] - ); - assert_eq!( - wrapper - .wrap_line(" ", px(72.)) - .collect::>(), - &[ - Boundary::new(7, 0), - Boundary::new(14, 0), - Boundary::new(21, 0) - ] - ); - assert_eq!( - wrapper - .wrap_line(" aaaaaaaaaaaaaa", px(72.)) - .collect::>(), - &[ - Boundary::new(7, 0), - Boundary::new(14, 3), - Boundary::new(18, 3), - Boundary::new(22, 3), - ] - ); + let mut wrapper = + LineWrapper::new(font_id, px(16.), text_system.platform_text_system.clone()); + assert_eq!( + wrapper + .wrap_line("aa bbb cccc ddddd eeee", px(72.)) + .collect::>(), + &[ + Boundary::new(7, 0), + Boundary::new(12, 0), + Boundary::new(18, 0) + ], + ); + assert_eq!( + wrapper + .wrap_line("aaa aaaaaaaaaaaaaaaaaa", px(72.0)) + .collect::>(), + &[ + Boundary::new(4, 0), + Boundary::new(11, 0), + Boundary::new(18, 0) + ], + ); + assert_eq!( + wrapper + .wrap_line(" aaaaaaa", px(72.)) + .collect::>(), + &[ + Boundary::new(7, 5), + Boundary::new(9, 5), + Boundary::new(11, 5), + ] + ); + assert_eq!( + wrapper + .wrap_line(" ", px(72.)) + .collect::>(), + &[ + Boundary::new(7, 0), + Boundary::new(14, 0), + Boundary::new(21, 0) + ] + ); + assert_eq!( + wrapper + .wrap_line(" aaaaaaaaaaaaaa", px(72.)) + .collect::>(), + &[ + Boundary::new(7, 0), + Boundary::new(14, 3), + Boundary::new(18, 3), + Boundary::new(22, 3), + ] + ); + }); } // todo! repeat this test #[test] fn test_wrap_shaped_line() { - let cx = AppContext::test(); - let text_system = cx.text_system().clone(); + App::test().run(|cx| { + let text_system = cx.text_system().clone(); - let family = text_system - .load_font_family(&["Helvetica"], &Default::default()) - .unwrap(); - let font_id = text_system - .select_font(family, Default::default(), Default::default()) - .unwrap(); - let normal = RunStyle { - font_id, - color: Default::default(), - underline: Default::default(), - }; - let bold = RunStyle { - font_id: text_system - .select_font(family, FontWeight::BOLD, Default::default()) - .unwrap(), - color: Default::default(), - underline: Default::default(), - }; + let family = text_system + .load_font_family(&["Helvetica"], &Default::default()) + .unwrap(); + let font_id = text_system + .select_font(family, Default::default(), Default::default()) + .unwrap(); + let normal = RunStyle { + font_id, + color: Default::default(), + underline: Default::default(), + }; + let bold = RunStyle { + font_id: text_system + .select_font(family, FontWeight::BOLD, Default::default()) + .unwrap(), + color: Default::default(), + underline: Default::default(), + }; - let text = "aa bbb cccc ddddd eeee"; - let line = text_system.layout_str( - text, - px(16.), - &[ - (4, normal.clone()), - (5, bold.clone()), - (6, normal.clone()), - (1, bold), - (7, normal), - ], - ); + let text = "aa bbb cccc ddddd eeee"; + let line = text_system.layout_str( + text, + px(16.), + &[ + (4, normal.clone()), + (5, bold.clone()), + (6, normal.clone()), + (1, bold), + (7, normal), + ], + ); - let mut wrapper = - LineWrapper::new(font_id, px(16.), text_system.platform_text_system.clone()); - assert_eq!( - wrapper - .wrap_shaped_line(text, &line, px(72.)) - .collect::>(), - &[ - ShapedBoundary { - run_ix: 1, - glyph_ix: 3 - }, - ShapedBoundary { - run_ix: 2, - glyph_ix: 3 - }, - ShapedBoundary { - run_ix: 4, - glyph_ix: 2 - } - ], - ); + let mut wrapper = + LineWrapper::new(font_id, px(16.), text_system.platform_text_system.clone()); + assert_eq!( + wrapper + .wrap_shaped_line(text, &line, px(72.)) + .collect::>(), + &[ + ShapedBoundary { + run_ix: 1, + glyph_ix: 3 + }, + ShapedBoundary { + run_ix: 2, + glyph_ix: 3 + }, + ShapedBoundary { + run_ix: 4, + glyph_ix: 2 + } + ], + ); + }); } } diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index ec804159e2..5f6d6ea751 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -1,6 +1,4 @@ -use crate::{ - AvailableSpace, Bg, PlatformWindow, Point, Size, Style, TextStyle, TextStyleRefinement, -}; +use crate::{AvailableSpace, PlatformWindow, Point, Size, Style, TextStyle, TextStyleRefinement}; use super::{ px, taffy::LayoutId, AppContext, Bounds, Context, EntityId, Handle, Pixels, Reference, @@ -39,22 +37,22 @@ impl Window { } #[derive(Deref, DerefMut)] -pub struct WindowContext<'a, 'b> { +pub struct WindowContext<'a, 'b, Thread = ()> { #[deref] #[deref_mut] - app: Reference<'a, AppContext>, + app: Reference<'a, AppContext>, window: Reference<'b, Window>, } -impl<'a, 'w> WindowContext<'a, 'w> { - pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window) -> Self { +impl<'a, 'w, Thread> WindowContext<'a, 'w, Thread> { + 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), @@ -123,7 +121,7 @@ impl<'a, 'w> WindowContext<'a, 'w> { 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 { Ok(update(self)) diff --git a/crates/storybook2/src/storybook2.rs b/crates/storybook2/src/storybook2.rs index 83357905c6..042c98362c 100644 --- a/crates/storybook2/src/storybook2.rs +++ b/crates/storybook2/src/storybook2.rs @@ -21,7 +21,7 @@ mod workspace; fn main() { SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger"); - gpui3::App::new().run(|cx| { + gpui3::App::production().run(|cx| { let window: gpui3::WindowHandle<()> = cx.open_window(Default::default(), |cx| todo!()); });