Checkpoint

This commit is contained in:
Antonio Scandurra 2023-10-04 19:53:29 +02:00
parent 5aa45607eb
commit dc9a260425
11 changed files with 251 additions and 1194 deletions

View file

@ -19,6 +19,8 @@ fn generate_dispatch_bindings() {
let bindings = bindgen::Builder::default()
.header("src/platform/mac/dispatch.h")
.allowlist_var("_dispatch_main_q")
.allowlist_var("DISPATCH_QUEUE_PRIORITY_DEFAULT")
.allowlist_function("dispatch_get_global_queue")
.allowlist_function("dispatch_async_f")
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.layout_tests(false)

View file

@ -8,9 +8,9 @@ pub use model_context::*;
use refineable::Refineable;
use crate::{
current_platform, image_cache::ImageCache, run_on_main, spawn_on_main, AssetSource, Context,
LayoutId, MainThread, MainThreadOnly, Platform, PlatformDispatcher, RootView, SvgRenderer,
TextStyle, TextStyleRefinement, TextSystem, Window, WindowContext, WindowHandle, WindowId,
current_platform, image_cache::ImageCache, AssetSource, Context, Executor, LayoutId,
MainThread, MainThreadOnly, Platform, RootView, SvgRenderer, Task, TextStyle,
TextStyleRefinement, TextSystem, Window, WindowContext, WindowHandle, WindowId,
};
use anyhow::{anyhow, Result};
use collections::{HashMap, VecDeque};
@ -50,15 +50,15 @@ impl App {
asset_source: Arc<dyn AssetSource>,
http_client: Arc<dyn HttpClient>,
) -> Self {
let dispatcher = platform.dispatcher();
let executor = platform.executor();
let text_system = Arc::new(TextSystem::new(platform.text_system()));
let entities = EntityMap::new();
let unit_entity = entities.redeem(entities.reserve(), ());
Self(Arc::new_cyclic(|this| {
Mutex::new(MainThread::new(AppContext {
this: this.clone(),
platform: MainThreadOnly::new(platform, dispatcher.clone()),
dispatcher,
platform: MainThreadOnly::new(platform, executor.clone()),
executor,
text_system,
svg_renderer: SvgRenderer::new(asset_source),
image_cache: ImageCache::new(http_client),
@ -95,7 +95,7 @@ pub struct AppContext {
platform: MainThreadOnly<dyn Platform>,
text_system: Arc<TextSystem>,
pending_updates: usize,
pub(crate) dispatcher: Arc<dyn PlatformDispatcher>,
pub(crate) executor: Executor,
pub(crate) svg_renderer: SvgRenderer,
pub(crate) image_cache: ImageCache,
pub(crate) text_style_stack: Vec<TextStyleRefinement>,
@ -184,6 +184,10 @@ impl AppContext {
AsyncContext(unsafe { mem::transmute(self.this.clone()) })
}
pub fn executor(&self) -> &Executor {
&self.executor
}
pub fn run_on_main<R>(
&mut self,
f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
@ -192,20 +196,22 @@ impl AppContext {
R: Send + 'static,
{
let (tx, rx) = oneshot::channel();
if self.dispatcher.is_main_thread() {
if self.executor.is_main_thread() {
let _ = tx.send(f(unsafe {
mem::transmute::<&mut AppContext, &mut MainThread<AppContext>>(self)
}));
} else {
let this = self.this.upgrade().unwrap();
let _ = run_on_main(self.dispatcher.clone(), move || {
let cx = &mut *this.lock();
cx.update(|cx| {
let _ = tx.send(f(unsafe {
mem::transmute::<&mut Self, &mut MainThread<Self>>(cx)
}));
self.executor
.run_on_main(move || {
let cx = &mut *this.lock();
cx.update(|cx| {
let _ = tx.send(f(unsafe {
mem::transmute::<&mut Self, &mut MainThread<Self>>(cx)
}));
})
})
});
.detach();
}
async move { rx.await.unwrap() }
}
@ -213,13 +219,13 @@ impl AppContext {
pub fn spawn_on_main<F, R>(
&self,
f: impl FnOnce(&mut MainThread<AppContext>) -> F + Send + 'static,
) -> impl Future<Output = R>
) -> Task<R>
where
F: Future<Output = R> + 'static,
R: Send + 'static,
{
let this = self.this.upgrade().unwrap();
spawn_on_main(self.dispatcher.clone(), move || {
self.executor.spawn_on_main(move || {
let cx = &mut *this.lock();
cx.update(|cx| {
f(unsafe { mem::transmute::<&mut AppContext, &mut MainThread<AppContext>>(cx) })

File diff suppressed because it is too large Load diff

View file

@ -227,14 +227,14 @@ impl<'a, T> DerefMut for Reference<'a, T> {
}
pub(crate) struct MainThreadOnly<T: ?Sized> {
dispatcher: Arc<dyn PlatformDispatcher>,
executor: Executor,
value: Arc<T>,
}
impl<T: ?Sized> Clone for MainThreadOnly<T> {
fn clone(&self) -> Self {
Self {
dispatcher: self.dispatcher.clone(),
executor: self.executor.clone(),
value: self.value.clone(),
}
}
@ -243,12 +243,12 @@ impl<T: ?Sized> Clone for MainThreadOnly<T> {
/// Allows a value to be accessed only on the main thread, allowing a non-`Send` type
/// to become `Send`.
impl<T: 'static + ?Sized> MainThreadOnly<T> {
pub(crate) fn new(value: Arc<T>, dispatcher: Arc<dyn PlatformDispatcher>) -> Self {
Self { dispatcher, value }
pub(crate) fn new(value: Arc<T>, executor: Executor) -> Self {
Self { executor, value }
}
pub(crate) fn borrow_on_main_thread(&self) -> &T {
assert!(self.dispatcher.is_main_thread());
assert!(self.executor.is_main_thread());
&self.value
}
}

View file

@ -7,8 +7,8 @@ mod test;
use crate::image_cache::RenderImageParams;
use crate::{
AnyWindowHandle, Bounds, DevicePixels, Font, FontId, FontMetrics, GlyphId, Pixels, Point,
RenderGlyphParams, RenderSvgParams, Result, Scene, ShapedLine, SharedString, Size,
AnyWindowHandle, Bounds, DevicePixels, Executor, Font, FontId, FontMetrics, GlyphId, Pixels,
Point, RenderGlyphParams, RenderSvgParams, Result, Scene, ShapedLine, SharedString, Size,
};
use anyhow::anyhow;
use async_task::Runnable;
@ -43,7 +43,7 @@ pub(crate) fn current_platform() -> Arc<dyn Platform> {
}
pub trait Platform: 'static {
fn dispatcher(&self) -> Arc<dyn PlatformDispatcher>;
fn executor(&self) -> Executor;
fn text_system(&self) -> Arc<dyn PlatformTextSystem>;
fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>);
@ -154,7 +154,8 @@ pub trait PlatformWindow {
pub trait PlatformDispatcher: Send + Sync {
fn is_main_thread(&self) -> bool;
fn run_on_main_thread(&self, task: Runnable);
fn dispatch(&self, task: Runnable);
fn dispatch_on_main_thread(&self, task: Runnable);
}
pub trait PlatformTextSystem: Send + Sync {

View file

@ -25,7 +25,17 @@ impl PlatformDispatcher for MacDispatcher {
is_main_thread == YES
}
fn run_on_main_thread(&self, runnable: Runnable) {
fn dispatch(&self, runnable: Runnable) {
unsafe {
dispatch_async_f(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.try_into().unwrap(), 0),
runnable.into_raw() as *mut c_void,
Some(trampoline),
);
}
}
fn dispatch_on_main_thread(&self, runnable: Runnable) {
unsafe {
dispatch_async_f(
dispatch_get_main_queue(),
@ -33,10 +43,31 @@ impl PlatformDispatcher for MacDispatcher {
Some(trampoline),
);
}
extern "C" fn trampoline(runnable: *mut c_void) {
let task = unsafe { Runnable::from_raw(runnable as *mut ()) };
task.run();
}
}
}
extern "C" fn trampoline(runnable: *mut c_void) {
let task = unsafe { Runnable::from_raw(runnable as *mut ()) };
task.run();
}
// #include <dispatch/dispatch.h>
// int main(void) {
// dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// // Do some lengthy background work here...
// printf("Background Work\n");
// dispatch_async(dispatch_get_main_queue(), ^{
// // Once done, update your UI on the main queue here.
// printf("UI Updated\n");
// });
// });
// sleep(3); // prevent the program from terminating immediately
// return 0;
// }
// ```

View file

@ -1,8 +1,8 @@
use super::BoolExt;
use crate::{
AnyWindowHandle, ClipboardItem, CursorStyle, Event, MacDispatcher, MacScreen, MacTextSystem,
MacWindow, PathPromptOptions, Platform, PlatformScreen, PlatformTextSystem, PlatformWindow,
Result, ScreenId, SemanticVersion, WindowOptions,
AnyWindowHandle, ClipboardItem, CursorStyle, Event, Executor, MacDispatcher, MacScreen,
MacTextSystem, MacWindow, PathPromptOptions, Platform, PlatformScreen, PlatformTextSystem,
PlatformWindow, Result, ScreenId, SemanticVersion, WindowOptions,
};
use anyhow::anyhow;
use block::ConcreteBlock;
@ -142,7 +142,7 @@ unsafe fn build_classes() {
pub struct MacPlatform(Mutex<MacPlatformState>);
pub struct MacPlatformState {
dispatcher: Arc<MacDispatcher>,
executor: Executor,
text_system: Arc<MacTextSystem>,
pasteboard: id,
text_hash_pasteboard_type: id,
@ -163,7 +163,7 @@ pub struct MacPlatformState {
impl MacPlatform {
pub fn new() -> Self {
Self(Mutex::new(MacPlatformState {
dispatcher: Arc::new(MacDispatcher),
executor: Executor::new(Arc::new(MacDispatcher)),
text_system: Arc::new(MacTextSystem::new()),
pasteboard: unsafe { NSPasteboard::generalPasteboard(nil) },
text_hash_pasteboard_type: unsafe { ns_string("zed-text-hash") },
@ -343,8 +343,8 @@ impl MacPlatform {
}
impl Platform for MacPlatform {
fn dispatcher(&self) -> Arc<dyn crate::PlatformDispatcher> {
Arc::new(MacDispatcher)
fn executor(&self) -> Executor {
self.0.lock().executor.clone()
}
fn text_system(&self) -> Arc<dyn PlatformTextSystem> {
@ -479,7 +479,7 @@ impl Platform for MacPlatform {
handle: AnyWindowHandle,
options: WindowOptions,
) -> Box<dyn PlatformWindow> {
Box::new(MacWindow::open(handle, options, self))
Box::new(MacWindow::open(handle, options, self.executor()))
}
fn open_url(&self, url: &str) {
@ -566,17 +566,20 @@ impl Platform for MacPlatform {
fn reveal_path(&self, path: &Path) {
unsafe {
let path = path.to_path_buf();
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
];
});
self.0
.lock()
.executor
.spawn_on_main_local(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();
}
}

View file

@ -1,10 +1,10 @@
use super::{ns_string, MetalRenderer, NSRange};
use crate::{
point, px, size, AnyWindowHandle, Bounds, Event, KeyDownEvent, Keystroke, MacScreen, Modifiers,
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent, MouseUpEvent, NSRectExt,
Pixels, Platform, PlatformAtlas, PlatformDispatcher, PlatformInputHandler, PlatformScreen,
PlatformWindow, Point, Scene, Size, Timer, WindowAppearance, WindowBounds, WindowKind,
WindowOptions, WindowPromptLevel,
point, px, size, AnyWindowHandle, Bounds, Event, Executor, KeyDownEvent, Keystroke, MacScreen,
Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent, MouseUpEvent,
NSRectExt, Pixels, PlatformAtlas, PlatformInputHandler, PlatformScreen, PlatformWindow, Point,
Scene, Size, Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions,
WindowPromptLevel,
};
use block::ConcreteBlock;
use cocoa::{
@ -279,7 +279,7 @@ struct InsertText {
struct MacWindowState {
handle: AnyWindowHandle,
dispatcher: Arc<dyn PlatformDispatcher>,
executor: Executor,
native_window: id,
renderer: MetalRenderer,
scene_to_render: Option<Scene>,
@ -415,7 +415,7 @@ unsafe impl Send for MacWindowState {}
pub struct MacWindow(Arc<Mutex<MacWindowState>>);
impl MacWindow {
pub fn open(handle: AnyWindowHandle, options: WindowOptions, platform: &dyn Platform) -> Self {
pub fn open(handle: AnyWindowHandle, options: WindowOptions, executor: Executor) -> Self {
unsafe {
let pool = NSAutoreleasePool::new(nil);
@ -479,7 +479,7 @@ impl MacWindow {
let window = Self(Arc::new(Mutex::new(MacWindowState {
handle,
dispatcher: platform.dispatcher(),
executor,
native_window,
renderer: MetalRenderer::new(true),
scene_to_render: None,
@ -616,12 +616,12 @@ impl MacWindow {
impl Drop for MacWindow {
fn drop(&mut self) {
let this = self.0.clone();
let dispatcher = self.0.lock().dispatcher.clone();
let _ = crate::spawn_on_main(dispatcher, || async move {
unsafe {
let executor = self.0.lock().executor.clone();
executor
.run_on_main(move || unsafe {
this.lock().native_window.close();
}
});
})
.detach();
}
}
@ -739,14 +739,16 @@ impl PlatformWindow for MacWindow {
});
let block = block.copy();
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
];
});
let executor = self.0.lock().executor.clone();
executor
.spawn_on_main_local(async move {
let _: () = msg_send![
alert,
beginSheetModalForWindow: native_window
completionHandler: block
];
})
.detach();
done_rx
}
@ -754,12 +756,14 @@ impl PlatformWindow for MacWindow {
fn activate(&self) {
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];
}
});
let executor = self.0.lock().executor.clone();
executor
.spawn_on_main_local(async move {
unsafe {
let _: () = msg_send![window, makeKeyAndOrderFront: nil];
}
})
.detach();
}
fn set_title(&mut self, title: &str) {
@ -802,23 +806,25 @@ impl PlatformWindow for MacWindow {
fn zoom(&self) {
let this = self.0.lock();
let window = this.native_window;
let dispatcher = this.dispatcher.clone();
let _ = crate::spawn_on_main_local(dispatcher, async move {
unsafe {
window.zoom_(nil);
}
});
this.executor
.spawn_on_main_local(async move {
unsafe {
window.zoom_(nil);
}
})
.detach();
}
fn toggle_full_screen(&self) {
let this = self.0.lock();
let window = this.native_window;
let dispatcher = this.dispatcher.clone();
let _ = crate::spawn_on_main_local(dispatcher, async move {
unsafe {
window.toggleFullScreen_(nil);
}
});
this.executor
.spawn_on_main_local(async move {
unsafe {
window.toggleFullScreen_(nil);
}
})
.detach();
}
fn on_event(&self, callback: Box<dyn FnMut(Event) -> bool>) {
@ -1114,15 +1120,14 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
},
) => {
lock.synthetic_drag_counter += 1;
let dispatcher = lock.dispatcher.clone();
let _ = crate::spawn_on_main_local(
dispatcher,
synthetic_drag(
let executor = lock.executor.clone();
executor
.spawn_on_main_local(synthetic_drag(
weak_window_state,
lock.synthetic_drag_counter,
event.clone(),
),
);
))
.detach();
}
Event::MouseMoved(_) if !(is_active || lock.kind == WindowKind::PopUp) => return,
@ -1241,16 +1246,18 @@ extern "C" fn window_did_change_key_status(this: &Object, selector: Sel, _: id)
}
}
let dispatcher = lock.dispatcher.clone();
let executor = lock.executor.clone();
drop(lock);
let _ = crate::spawn_on_main_local(dispatcher, async move {
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);
};
});
executor
.spawn_on_main_local(async move {
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);
};
})
.detach();
}
extern "C" fn window_should_close(this: &Object, _: Sel, _: id) -> BOOL {

View file

@ -1,5 +1,5 @@
use super::Platform;
use crate::ScreenId;
use crate::{Executor, ScreenId};
pub struct TestPlatform;
@ -11,7 +11,7 @@ impl TestPlatform {
// todo!("implement out what our tests needed in GPUI 1")
impl Platform for TestPlatform {
fn dispatcher(&self) -> std::sync::Arc<dyn crate::PlatformDispatcher> {
fn executor(&self) -> Executor {
unimplemented!()
}

View file

@ -1,18 +1,16 @@
use smol::future::FutureExt;
use std::{future::Future, time::Duration};
pub use util::*;
pub async fn timeout<F, T>(timeout: Duration, f: F) -> Result<T, ()>
where
F: Future<Output = T>,
{
let timer = async {
smol::Timer::after(timeout).await;
Err(())
};
let future = async move { Ok(f.await) };
timer.race(future).await
}
// pub async fn timeout<F, T>(timeout: Duration, f: F) -> Result<T, ()>
// where
// F: Future<Output = T>,
// {
// let timer = async {
// smol::Timer::after(timeout).await;
// Err(())
// };
// let future = async move { Ok(f.await) };
// timer.race(future).await
// }
#[cfg(any(test, feature = "test"))]
pub struct CwdBacktrace<'a>(pub &'a backtrace::Backtrace);

View file

@ -53,8 +53,7 @@ impl Window {
}
}));
let platform_window =
MainThreadOnly::new(Arc::new(platform_window), cx.platform().dispatcher());
let platform_window = MainThreadOnly::new(Arc::new(platform_window), cx.executor.clone());
Window {
handle,
@ -122,7 +121,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
R: Send + 'static,
{
let (tx, rx) = oneshot::channel();
if self.dispatcher.is_main_thread() {
if self.executor.is_main_thread() {
let _ = tx.send(f(unsafe {
mem::transmute::<&mut Self, &mut MainThread<Self>>(self)
}));
@ -600,7 +599,7 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
R: Send + 'static,
{
let (tx, rx) = oneshot::channel();
if self.dispatcher.is_main_thread() {
if self.executor.is_main_thread() {
let cx = unsafe { mem::transmute::<&mut Self, &mut MainThread<Self>>(self) };
let _ = tx.send(f(view, cx));
} else {