mirror of
https://github.com/zed-industries/zed.git
synced 2024-10-27 16:57:08 +00:00
Checkpoint
This commit is contained in:
parent
177e385bb9
commit
0d0c760d94
10 changed files with 224 additions and 52 deletions
|
@ -8,8 +8,8 @@ pub use model_context::*;
|
|||
use refineable::Refineable;
|
||||
|
||||
use crate::{
|
||||
current_platform, image_cache::ImageCache, AssetSource, Context, Executor, LayoutId,
|
||||
MainThread, MainThreadOnly, Platform, RootView, SvgRenderer, Task, TextStyle,
|
||||
current_platform, image_cache::ImageCache, AssetSource, Context, DisplayLinker, Executor,
|
||||
LayoutId, MainThread, MainThreadOnly, Platform, RootView, SvgRenderer, Task, TextStyle,
|
||||
TextStyleRefinement, TextSystem, Window, WindowContext, WindowHandle, WindowId,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
|
@ -51,15 +51,15 @@ impl App {
|
|||
http_client: Arc<dyn HttpClient>,
|
||||
) -> Self {
|
||||
let executor = platform.executor();
|
||||
let text_system = Arc::new(TextSystem::new(platform.text_system()));
|
||||
let entities = EntityMap::new();
|
||||
let unit_entity = entities.insert(entities.reserve(), ());
|
||||
Self(Arc::new_cyclic(|this| {
|
||||
Mutex::new(AppContext {
|
||||
this: this.clone(),
|
||||
display_linker: Arc::new(DisplayLinker::new(platform.display_linker())),
|
||||
text_system: Arc::new(TextSystem::new(platform.text_system())),
|
||||
platform: MainThreadOnly::new(platform, executor.clone()),
|
||||
executor,
|
||||
text_system,
|
||||
svg_renderer: SvgRenderer::new(asset_source),
|
||||
image_cache: ImageCache::new(http_client),
|
||||
pending_updates: 0,
|
||||
|
@ -97,6 +97,7 @@ pub struct AppContext {
|
|||
text_system: Arc<TextSystem>,
|
||||
pending_updates: usize,
|
||||
pub(crate) executor: Executor,
|
||||
pub(crate) display_linker: Arc<DisplayLinker>,
|
||||
pub(crate) svg_renderer: SvgRenderer,
|
||||
pub(crate) image_cache: ImageCache,
|
||||
pub(crate) text_style_stack: Vec<TextStyleRefinement>,
|
||||
|
@ -359,9 +360,15 @@ impl MainThread<AppContext> {
|
|||
let id = cx.windows.insert(None);
|
||||
let handle = WindowHandle::new(id);
|
||||
let mut window = Window::new(handle.into(), options, cx);
|
||||
let display_id = window.display_id;
|
||||
let root_view = build_root_view(&mut WindowContext::mutable(cx, &mut window));
|
||||
window.root_view.replace(root_view.into_any());
|
||||
cx.windows.get_mut(id).unwrap().replace(window);
|
||||
|
||||
cx.display_linker.on_next_frame(display_id, |_, _| {
|
||||
dbg!("next frame");
|
||||
});
|
||||
|
||||
handle
|
||||
})
|
||||
}
|
||||
|
|
55
crates/gpui3/src/display_linker.rs
Normal file
55
crates/gpui3/src/display_linker.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
use crate::{DisplayId, PlatformDisplayLinker, VideoTimestamp};
|
||||
use collections::HashMap;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
type FrameCallback = Box<dyn FnOnce(&VideoTimestamp, &VideoTimestamp) + Send>;
|
||||
|
||||
pub struct DisplayLinker {
|
||||
platform_linker: Arc<dyn PlatformDisplayLinker>,
|
||||
next_frame_callbacks: Arc<Mutex<HashMap<DisplayId, Vec<FrameCallback>>>>,
|
||||
}
|
||||
|
||||
impl DisplayLinker {
|
||||
pub(crate) fn new(platform_linker: Arc<dyn PlatformDisplayLinker>) -> Self {
|
||||
Self {
|
||||
platform_linker,
|
||||
next_frame_callbacks: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn on_next_frame(
|
||||
&self,
|
||||
display_id: DisplayId,
|
||||
callback: impl FnOnce(&VideoTimestamp, &VideoTimestamp) + Send + 'static,
|
||||
) {
|
||||
let next_frame_callbacks = self.next_frame_callbacks.clone();
|
||||
let callback = Box::new(callback);
|
||||
match self.next_frame_callbacks.lock().entry(display_id) {
|
||||
collections::hash_map::Entry::Occupied(mut entry) => {
|
||||
if entry.get().is_empty() {
|
||||
self.platform_linker.start(display_id)
|
||||
}
|
||||
entry.get_mut().push(callback)
|
||||
}
|
||||
collections::hash_map::Entry::Vacant(entry) => {
|
||||
// let platform_linker = self.platform_linker.clone();
|
||||
self.platform_linker.set_output_callback(
|
||||
display_id,
|
||||
Box::new(move |current_time, output_time| {
|
||||
for callback in next_frame_callbacks
|
||||
.lock()
|
||||
.get_mut(&display_id)
|
||||
.unwrap()
|
||||
.drain(..)
|
||||
{
|
||||
callback(current_time, output_time);
|
||||
}
|
||||
// platform_linker.stop(display_id);
|
||||
}),
|
||||
);
|
||||
entry.insert(vec![callback]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
mod app;
|
||||
mod assets;
|
||||
mod color;
|
||||
mod display_linker;
|
||||
mod element;
|
||||
mod elements;
|
||||
mod executor;
|
||||
|
@ -22,6 +23,7 @@ pub use anyhow::Result;
|
|||
pub use app::*;
|
||||
pub use assets::*;
|
||||
pub use color::*;
|
||||
pub use display_linker::*;
|
||||
pub use element::*;
|
||||
pub use elements::*;
|
||||
pub use executor::*;
|
||||
|
|
|
@ -42,6 +42,7 @@ pub(crate) fn current_platform() -> Arc<dyn Platform> {
|
|||
|
||||
pub trait Platform: 'static {
|
||||
fn executor(&self) -> Executor;
|
||||
fn display_linker(&self) -> Arc<dyn PlatformDisplayLinker>;
|
||||
fn text_system(&self) -> Arc<dyn PlatformTextSystem>;
|
||||
|
||||
fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>);
|
||||
|
@ -99,7 +100,6 @@ pub trait PlatformDisplay: Debug {
|
|||
fn id(&self) -> DisplayId;
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn bounds(&self) -> Bounds<GlobalPixels>;
|
||||
fn link(&self) -> Box<dyn PlatformDisplayLink>;
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
|
||||
|
@ -156,10 +156,14 @@ pub trait PlatformDispatcher: Send + Sync {
|
|||
fn dispatch_on_main_thread(&self, task: Runnable);
|
||||
}
|
||||
|
||||
pub trait PlatformDisplayLink {
|
||||
// fn set_output_callback(&mut self, callback: Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp)>);
|
||||
fn start(&mut self);
|
||||
fn stop(&mut self);
|
||||
pub trait PlatformDisplayLinker: Send + Sync {
|
||||
fn set_output_callback(
|
||||
&self,
|
||||
display_id: DisplayId,
|
||||
callback: Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp)>,
|
||||
);
|
||||
fn start(&self, display_id: DisplayId);
|
||||
fn stop(&self, display_id: DisplayId);
|
||||
}
|
||||
|
||||
pub trait PlatformTextSystem: Send + Sync {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
///! an origin at the bottom left of the main display.
|
||||
mod dispatcher;
|
||||
mod display;
|
||||
// mod display_link;
|
||||
mod display_linker;
|
||||
mod events;
|
||||
mod metal_atlas;
|
||||
mod metal_renderer;
|
||||
|
@ -33,7 +33,7 @@ use std::{
|
|||
|
||||
pub use dispatcher::*;
|
||||
pub use display::*;
|
||||
// pub use display_link::*;
|
||||
pub use display_linker::*;
|
||||
pub use metal_atlas::*;
|
||||
pub use platform::*;
|
||||
pub use text_system::*;
|
||||
|
|
|
@ -98,9 +98,4 @@ impl PlatformDisplay for MacDisplay {
|
|||
display_bounds_from_native(native_bounds)
|
||||
}
|
||||
}
|
||||
|
||||
fn link(&self) -> Box<dyn crate::PlatformDisplayLink> {
|
||||
unimplemented!()
|
||||
// Box::new(unsafe { MacDisplayLink::new(self.0) })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,41 +1,77 @@
|
|||
use crate::PlatformDisplayLink;
|
||||
use std::ffi::c_void;
|
||||
|
||||
use crate::{DisplayId, PlatformDisplayLinker};
|
||||
use collections::HashMap;
|
||||
use parking_lot::Mutex;
|
||||
pub use sys::CVTimeStamp as VideoTimestamp;
|
||||
|
||||
pub struct MacDisplayLink {
|
||||
sys_link: sys::DisplayLink,
|
||||
output_callback: Option<Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp)>>,
|
||||
pub struct MacDisplayLinker {
|
||||
links: Mutex<HashMap<DisplayId, MacDisplayLink>>,
|
||||
}
|
||||
|
||||
impl MacDisplayLink {
|
||||
pub unsafe fn new(display_id: u32) -> Self {
|
||||
Self {
|
||||
sys_link: sys::DisplayLink::on_display(display_id).unwrap(),
|
||||
output_callback: None,
|
||||
struct MacDisplayLink {
|
||||
output_callback: Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp)>,
|
||||
system_link: sys::DisplayLink,
|
||||
}
|
||||
|
||||
unsafe impl Send for MacDisplayLink {}
|
||||
|
||||
impl MacDisplayLinker {
|
||||
pub fn new() -> Self {
|
||||
MacDisplayLinker {
|
||||
links: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformDisplayLink for MacDisplayLink {
|
||||
fn set_output_callback(&mut self, callback: Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp)>) {
|
||||
unsafe {
|
||||
self.sys_link.set_output_callback(
|
||||
trampoline,
|
||||
self.output_callback.as_mut().unwrap()
|
||||
as *mut dyn FnMut(&VideoTimestamp, &VideoTimestamp)
|
||||
as *mut c_void,
|
||||
impl PlatformDisplayLinker for MacDisplayLinker {
|
||||
fn set_output_callback(
|
||||
&self,
|
||||
display_id: DisplayId,
|
||||
mut output_callback: Box<dyn FnMut(&VideoTimestamp, &VideoTimestamp)>,
|
||||
) {
|
||||
if let Some(mut system_link) = unsafe { sys::DisplayLink::on_display(display_id.0) } {
|
||||
unsafe {
|
||||
system_link.set_output_callback(
|
||||
trampoline,
|
||||
output_callback.as_mut() as *mut dyn FnMut(_, _) as *mut c_void,
|
||||
)
|
||||
}
|
||||
|
||||
let previous = self.links.lock().insert(
|
||||
display_id,
|
||||
MacDisplayLink {
|
||||
output_callback,
|
||||
system_link,
|
||||
},
|
||||
);
|
||||
assert!(
|
||||
previous.is_none(),
|
||||
"You can currently only set an output callback once per display."
|
||||
)
|
||||
} else {
|
||||
return log::warn!("DisplayLink could not be obtained for {:?}", display_id);
|
||||
}
|
||||
self.output_callback = Some(callback);
|
||||
}
|
||||
|
||||
fn start(&mut self) {
|
||||
unsafe { self.sys_link.start() }
|
||||
fn start(&self, display_id: DisplayId) {
|
||||
if let Some(link) = self.links.lock().get_mut(&display_id) {
|
||||
unsafe {
|
||||
link.system_link.start();
|
||||
}
|
||||
} else {
|
||||
log::warn!("No DisplayLink callback registered for {:?}", display_id)
|
||||
}
|
||||
}
|
||||
|
||||
fn stop(&mut self) {
|
||||
unsafe { self.sys_link.stop() }
|
||||
fn stop(&self, display_id: DisplayId) {
|
||||
if let Some(link) = self.links.lock().get_mut(&display_id) {
|
||||
unsafe {
|
||||
link.system_link.stop();
|
||||
}
|
||||
} else {
|
||||
log::warn!("No DisplayLink callback registered for {:?}", display_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,11 +84,8 @@ unsafe extern "C" fn trampoline(
|
|||
context: *mut c_void,
|
||||
) -> i32 {
|
||||
let output_callback = &mut (*(context as *mut MacDisplayLink)).output_callback;
|
||||
if let Some(callback) = output_callback {
|
||||
if let Some((current_time, output_time)) = current_time.as_ref().zip(output_time.as_ref()) {
|
||||
// convert sys::CVTimeStamp to VideoTimestamp
|
||||
callback(¤t_time, &output_time);
|
||||
}
|
||||
if let Some((current_time, output_time)) = current_time.as_ref().zip(output_time.as_ref()) {
|
||||
output_callback(¤t_time, &output_time);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
@ -61,9 +94,8 @@ mod sys {
|
|||
//! Derived from display-link crate under the fololwing license:
|
||||
//! https://github.com/BrainiumLLC/display-link/blob/master/LICENSE-MIT
|
||||
//! Apple docs: [CVDisplayLink](https://developer.apple.com/documentation/corevideo/cvdisplaylinkoutputcallback?language=objc)
|
||||
#![allow(dead_code)]
|
||||
#![allow(dead_code, non_upper_case_globals)]
|
||||
|
||||
pub use cocoa::quartzcore::CVTimeStamp;
|
||||
use foreign_types::{foreign_type, ForeignType};
|
||||
use std::{
|
||||
ffi::c_void,
|
||||
|
@ -90,6 +122,64 @@ mod sys {
|
|||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CVTimeStamp {
|
||||
pub version: u32,
|
||||
pub video_time_scale: i32,
|
||||
pub video_time: i64,
|
||||
pub host_time: u64,
|
||||
pub rate_scalar: f64,
|
||||
pub video_refresh_period: i64,
|
||||
pub smpte_time: CVSMPTETime,
|
||||
pub flags: u64,
|
||||
pub reserved: u64,
|
||||
}
|
||||
|
||||
pub type CVTimeStampFlags = u64;
|
||||
|
||||
pub const kCVTimeStampVideoTimeValid: CVTimeStampFlags = 1 << 0;
|
||||
pub const kCVTimeStampHostTimeValid: CVTimeStampFlags = 1 << 1;
|
||||
pub const kCVTimeStampSMPTETimeValid: CVTimeStampFlags = 1 << 2;
|
||||
pub const kCVTimeStampVideoRefreshPeriodValid: CVTimeStampFlags = 1 << 3;
|
||||
pub const kCVTimeStampRateScalarValid: CVTimeStampFlags = 1 << 4;
|
||||
pub const kCVTimeStampTopField: CVTimeStampFlags = 1 << 16;
|
||||
pub const kCVTimeStampBottomField: CVTimeStampFlags = 1 << 17;
|
||||
pub const kCVTimeStampVideoHostTimeValid: CVTimeStampFlags =
|
||||
kCVTimeStampVideoTimeValid | kCVTimeStampHostTimeValid;
|
||||
pub const kCVTimeStampIsInterlaced: CVTimeStampFlags =
|
||||
kCVTimeStampTopField | kCVTimeStampBottomField;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CVSMPTETime {
|
||||
pub subframes: i16,
|
||||
pub subframe_divisor: i16,
|
||||
pub counter: u32,
|
||||
pub time_type: u32,
|
||||
pub flags: u32,
|
||||
pub hours: i16,
|
||||
pub minutes: i16,
|
||||
pub seconds: i16,
|
||||
pub frames: i16,
|
||||
}
|
||||
|
||||
pub type CVSMPTETimeType = u32;
|
||||
|
||||
pub const kCVSMPTETimeType24: CVSMPTETimeType = 0;
|
||||
pub const kCVSMPTETimeType25: CVSMPTETimeType = 1;
|
||||
pub const kCVSMPTETimeType30Drop: CVSMPTETimeType = 2;
|
||||
pub const kCVSMPTETimeType30: CVSMPTETimeType = 3;
|
||||
pub const kCVSMPTETimeType2997: CVSMPTETimeType = 4;
|
||||
pub const kCVSMPTETimeType2997Drop: CVSMPTETimeType = 5;
|
||||
pub const kCVSMPTETimeType60: CVSMPTETimeType = 6;
|
||||
pub const kCVSMPTETimeType5994: CVSMPTETimeType = 7;
|
||||
|
||||
pub type CVSMPTETimeFlags = u32;
|
||||
|
||||
pub const kCVSMPTETimeValid: CVSMPTETimeFlags = 1 << 0;
|
||||
pub const kCVSMPTETimeRunning: CVSMPTETimeFlags = 1 << 1;
|
||||
|
||||
pub type CVDisplayLinkOutputCallback = unsafe extern "C" fn(
|
||||
display_link_out: *mut CVDisplayLink,
|
||||
// A pointer to the current timestamp. This represents the timestamp when the callback is called.
|
|
@ -1,8 +1,9 @@
|
|||
use super::BoolExt;
|
||||
use crate::{
|
||||
AnyWindowHandle, ClipboardItem, CursorStyle, DisplayId, Event, Executor, MacDispatcher,
|
||||
MacDisplay, MacTextSystem, MacWindow, PathPromptOptions, Platform, PlatformDisplay,
|
||||
PlatformTextSystem, PlatformWindow, Result, SemanticVersion, WindowOptions,
|
||||
MacDisplay, MacDisplayLinker, MacTextSystem, MacWindow, PathPromptOptions, Platform,
|
||||
PlatformDisplay, PlatformDisplayLinker, PlatformTextSystem, PlatformWindow, Result,
|
||||
SemanticVersion, WindowOptions,
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
use block::ConcreteBlock;
|
||||
|
@ -347,6 +348,10 @@ impl Platform for MacPlatform {
|
|||
self.0.lock().executor.clone()
|
||||
}
|
||||
|
||||
fn display_linker(&self) -> Arc<dyn PlatformDisplayLinker> {
|
||||
Arc::new(MacDisplayLinker::new())
|
||||
}
|
||||
|
||||
fn text_system(&self) -> Arc<dyn PlatformTextSystem> {
|
||||
self.0.lock().text_system.clone()
|
||||
}
|
||||
|
|
|
@ -15,6 +15,10 @@ impl Platform for TestPlatform {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
fn display_linker(&self) -> std::sync::Arc<dyn crate::PlatformDisplayLinker> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn text_system(&self) -> std::sync::Arc<dyn crate::PlatformTextSystem> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use crate::{
|
||||
image_cache::RenderImageParams, px, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
|
||||
BorrowAppContext, Bounds, Context, Corners, DevicePixels, Effect, Element, EntityId, FontId,
|
||||
GlyphId, Handle, Hsla, ImageData, IsZero, LayerId, LayoutId, MainThread, MainThreadOnly,
|
||||
MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Reference,
|
||||
RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene, SharedString, Size, Style,
|
||||
TaffyLayoutEngine, Task, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
|
||||
BorrowAppContext, Bounds, Context, Corners, DevicePixels, DisplayId, Effect, Element, EntityId,
|
||||
FontId, GlyphId, Handle, Hsla, ImageData, IsZero, LayerId, LayoutId, MainThread,
|
||||
MainThreadOnly, MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point,
|
||||
PolychromeSprite, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene,
|
||||
SharedString, Size, Style, TaffyLayoutEngine, Task, WeakHandle, WindowOptions,
|
||||
SUBPIXEL_VARIANTS,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use smallvec::SmallVec;
|
||||
|
@ -16,6 +17,7 @@ pub struct AnyWindow {}
|
|||
pub struct Window {
|
||||
handle: AnyWindowHandle,
|
||||
platform_window: MainThreadOnly<Box<dyn PlatformWindow>>,
|
||||
pub(crate) display_id: DisplayId, // todo!("make private again?")
|
||||
sprite_atlas: Arc<dyn PlatformAtlas>,
|
||||
rem_size: Pixels,
|
||||
content_size: Size<Pixels>,
|
||||
|
@ -35,6 +37,7 @@ impl Window {
|
|||
cx: &mut MainThread<AppContext>,
|
||||
) -> Self {
|
||||
let platform_window = cx.platform().open_window(handle, options);
|
||||
let display_id = platform_window.display().id();
|
||||
let sprite_atlas = platform_window.sprite_atlas();
|
||||
let mouse_position = platform_window.mouse_position();
|
||||
let content_size = platform_window.content_size();
|
||||
|
@ -46,6 +49,12 @@ impl Window {
|
|||
cx.update_window(handle, |cx| {
|
||||
cx.window.scene = Scene::new(scale_factor);
|
||||
cx.window.content_size = content_size;
|
||||
cx.window.display_id = cx
|
||||
.window
|
||||
.platform_window
|
||||
.borrow_on_main_thread()
|
||||
.display()
|
||||
.id();
|
||||
cx.window.dirty = true;
|
||||
})
|
||||
.log_err();
|
||||
|
@ -57,6 +66,7 @@ impl Window {
|
|||
Window {
|
||||
handle,
|
||||
platform_window,
|
||||
display_id,
|
||||
sprite_atlas,
|
||||
rem_size: px(16.),
|
||||
content_size,
|
||||
|
|
Loading…
Reference in a new issue