diff --git a/Cargo.lock b/Cargo.lock index 4f6f6fe8392c68e5b41b7c84f19e9207e0994306..aa030b9575372fa5b3fc291b1f9c0bc743808a1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -761,10 +761,13 @@ dependencies = [ "core-foundation", "core-graphics", "foreign-types", + "futures", "gpui", "io_surface", "log", "objc", + "parking_lot 0.11.2", + "postage", "simplelog", ] diff --git a/crates/capture/Cargo.toml b/crates/capture/Cargo.toml index ebb35d8ef2203d6feb7a55dc7c0b6b286d56b421..8c6e901bbd58c76bac4737f9495cb7a8343762ff 100644 --- a/crates/capture/Cargo.toml +++ b/crates/capture/Cargo.toml @@ -17,8 +17,11 @@ cocoa = "0.24" core-foundation = "0.9.3" core-graphics = "0.22.3" foreign-types = "0.3" +futures = "0.3" log = { version = "0.4.16", features = ["kv_unstable_serde"] } objc = "0.2" +parking_lot = "0.11.1" +postage = { version = "0.4.1", features = ["futures-traits"] } simplelog = "0.9" [build-dependencies] diff --git a/crates/capture/src/main.rs b/crates/capture/src/main.rs index ae02002e9eb247c658aa07f87fc410934de9a03b..1b2ce6f8e8805d4894727a6c8f84a9deab2d19a8 100644 --- a/crates/capture/src/main.rs +++ b/crates/capture/src/main.rs @@ -8,8 +8,15 @@ use cocoa::{ }; use core_foundation::{base::TCFType, number::CFNumberRef, string::CFStringRef}; use core_media::{CMSampleBuffer, CMSampleBufferRef}; -use gpui::elements::Canvas; -use gpui::{actions, elements::*, keymap::Binding, Menu, MenuItem}; +use futures::StreamExt; +use gpui::{ + actions, + elements::{Canvas, *}, + keymap::Binding, + platform::current::Surface, + Menu, MenuItem, ViewContext, +}; +use io_surface::IOSurface; use log::LevelFilter; use objc::{ class, @@ -18,8 +25,9 @@ use objc::{ runtime::{Object, Sel}, sel, sel_impl, }; +use parking_lot::Mutex; use simplelog::SimpleLogger; -use std::{ffi::c_void, slice, str}; +use std::{cell::RefCell, ffi::c_void, slice, str}; #[allow(non_upper_case_globals)] const NSUTF8StringEncoding: NSUInteger = 4; @@ -42,10 +50,29 @@ fn main() { }], }]); + cx.add_window(Default::default(), |cx| ScreenCaptureView::new(cx)); + }); +} + +struct ScreenCaptureView { + surface: Option, +} + +impl gpui::Entity for ScreenCaptureView { + type Event = (); +} + +impl ScreenCaptureView { + pub fn new(cx: &mut ViewContext) -> Self { + let (surface_tx, mut surface_rx) = postage::watch::channel::>(); + let surface_tx = RefCell::new(surface_tx); unsafe { let block = ConcreteBlock::new(move |content: id, error: id| { if !error.is_null() { - println!("ERROR {}", string_from_objc(msg_send![error, localizedDescription])); + println!( + "ERROR {}", + string_from_objc(msg_send![error, localizedDescription]) + ); return; } @@ -57,11 +84,16 @@ fn main() { let mut decl = ClassDecl::new("CaptureOutput", class!(NSObject)).unwrap(); decl.add_ivar::<*mut c_void>("callback"); - decl.add_method(sel!(stream:didOutputSampleBuffer:ofType:), sample_output as extern "C" fn(&Object, Sel, id, id, SCStreamOutputType)); + decl.add_method( + sel!(stream:didOutputSampleBuffer:ofType:), + sample_output as extern "C" fn(&Object, Sel, id, id, SCStreamOutputType), + ); let capture_output_class = decl.register(); let output: id = msg_send![capture_output_class, alloc]; let output: id = msg_send![output, init]; + + // TODO: we could probably move this into a background queue. let callback = Box::new(|buffer: CMSampleBufferRef| { let buffer = CMSampleBuffer::wrap_under_get_rule(buffer); let attachments = buffer.attachments(); @@ -79,8 +111,11 @@ fn main() { } let image_buffer = buffer.image_buffer(); - dbg!(image_buffer.width(), image_buffer.height()); let io_surface = image_buffer.io_surface(); + println!("before segfault"); + *surface_tx.borrow_mut().borrow_mut() = Some(io_surface); + + println!("!!!!!!!!!!!!!!!!!"); }) as Box; let callback = Box::into_raw(Box::new(callback)); (*output).set_ivar("callback", callback as *mut c_void); @@ -109,7 +144,10 @@ fn main() { let start_capture_completion = ConcreteBlock::new(move |error: id| { if !error.is_null() { - println!("error starting capture... error? {}", string_from_objc(msg_send![error, localizedDescription])); + println!( + "error starting capture... error? {}", + string_from_objc(msg_send![error, localizedDescription]) + ); return; } @@ -117,8 +155,10 @@ fn main() { }); assert!(!stream.is_null()); - let _: () = msg_send![stream, startCaptureWithCompletionHandler: start_capture_completion]; - + let _: () = msg_send![ + stream, + startCaptureWithCompletionHandler: start_capture_completion + ]; }); let _: id = msg_send![ @@ -127,31 +167,39 @@ fn main() { ]; } - // cx.add_window(Default::default(), |_| ScreenCaptureView); - }); -} - -struct ScreenCaptureView { - surface: io_surface::IOSurface, -} + cx.spawn_weak(|this, mut cx| async move { + while let Some(surface) = surface_rx.next().await { + if let Some(this) = this.upgrade(&cx) { + this.update(&mut cx, |this, cx| { + this.surface = surface; + cx.notify(); + }) + } else { + break; + } + } + }) + .detach(); -impl gpui::Entity for ScreenCaptureView { - type Event = (); + Self { surface: None } + } } -// impl ScreenCaptureView { -// pub fn new() -> Self {} -// } - impl gpui::View for ScreenCaptureView { fn ui_name() -> &'static str { "View" } fn render(&mut self, _: &mut gpui::RenderContext) -> gpui::ElementBox { - Canvas::new(|bounds, _, cx| { - - // cx.scene.push_surface(surface) + let surface = self.surface.clone(); + Canvas::new(move |bounds, _, cx| { + if let Some(native_surface) = surface.clone() { + dbg!("!!!!"); + cx.scene.push_surface(Surface { + bounds, + native_surface, + }); + } }) .boxed() }