1mod bindings;
2
3use std::{slice, str};
4
5use block::ConcreteBlock;
6use cocoa::{
7 base::{id, nil},
8 foundation::{NSArray, NSString, NSUInteger, NSInteger},
9};
10use gpui::{actions, elements::*, keymap::Binding, Menu, MenuItem};
11use log::LevelFilter;
12use objc::{class, msg_send, sel, sel_impl, declare::ClassDecl, runtime::{Protocol, Object, Sel}};
13use simplelog::SimpleLogger;
14
15use crate::bindings::dispatch_get_main_queue;
16
17#[allow(non_upper_case_globals)]
18const NSUTF8StringEncoding: NSUInteger = 4;
19
20actions!(capture, [Quit]);
21
22fn main() {
23 SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
24
25 gpui::App::new(()).unwrap().run(|cx| {
26 cx.platform().activate(true);
27 cx.add_global_action(quit);
28
29 cx.add_bindings([Binding::new("cmd-q", Quit, None)]);
30 cx.set_menus(vec![Menu {
31 name: "Zed",
32 items: vec![MenuItem::Action {
33 name: "Quit",
34 action: Box::new(Quit),
35 }],
36 }]);
37
38 unsafe {
39 let block = ConcreteBlock::new(move |content: id, error: id| {
40 if !error.is_null() {
41 println!("ERROR {}", string_from_objc(msg_send![error, localizedDescription]));
42 return;
43 }
44
45 let displays: id = msg_send![content, displays];
46
47 if let Some(display) = (0..displays.count())
48 .map(|ix| displays.objectAtIndex(ix))
49 .next()
50 {
51
52 let display_id: u32 = msg_send![display, displayID];
53 println!("display id {:?}", display_id);
54
55 let mut decl = ClassDecl::new("CaptureOutput", class!(NSObject)).unwrap();
56 decl.add_protocol(Protocol::get("SCStreamOutput").unwrap());
57 decl.add_method(sel!(stream:didOutputSampleBuffer:ofType:), sample_output as extern "C" fn(&Object, Sel, id, id, NSInteger));
58 let capture_output_class = decl.register();
59
60 let output: id = msg_send![capture_output_class, alloc];
61 let output: id = msg_send![output, init];
62
63 let conforms: bool = msg_send![output, conformsToProtocol: Protocol::get("SCStreamOutput").unwrap()];
64 dbg!(conforms);
65 assert!(conforms, "expect CaptureOutput instance to conform to SCStreamOutput protocol");
66
67 let excluded_windows: id = msg_send![class!(NSArray), array];
68 let filter: id = msg_send![class!(SCContentFilter), alloc];
69 let filter: id = msg_send![filter, initWithDisplay: display excludingWindows: excluded_windows];
70 let config: id = msg_send![class!(SCStreamConfiguration), alloc];
71 let config: id = msg_send![config, init];
72 // Configure the display content width and height.
73 let _: () = msg_send![config, setWidth: 800];
74 let _: () = msg_send![config, setHeight: 600];
75 let _: () = msg_send![config, setMinimumFrameInterval: bindings::CMTimeMake(1, 60)];
76 let _: () = msg_send![config, setQueueDepth: 5];
77
78 let stream: id = msg_send![class!(SCStream), alloc];
79 let stream: id = msg_send![stream, initWithFilter: filter configuration: config delegate: nil];
80 let error: id = nil;
81 // let queue = dispatch_queue_create(ptr::null(), ptr::null_mut());
82
83 let _: () = msg_send![stream, addStreamOutput: output type: 0 sampleHandlerQueue: dispatch_get_main_queue() error: &error];
84
85 let start_capture_completion = ConcreteBlock::new(move |error: id| {
86 if !error.is_null() {
87 println!("error starting capture... error? {}", string_from_objc(msg_send![error, localizedDescription]));
88 return;
89 }
90
91 println!("starting capture");
92 });
93
94 assert!(!stream.is_null());
95 let _: () = msg_send![stream, startCaptureWithCompletionHandler: start_capture_completion];
96 }
97 });
98
99 let _: id = msg_send![
100 class!(SCShareableContent),
101 getShareableContentWithCompletionHandler: block
102 ];
103 }
104
105 // cx.add_window(Default::default(), |_| ScreenCaptureView);
106 });
107}
108
109struct ScreenCaptureView;
110
111impl gpui::Entity for ScreenCaptureView {
112 type Event = ();
113}
114
115impl gpui::View for ScreenCaptureView {
116 fn ui_name() -> &'static str {
117 "View"
118 }
119
120 fn render(&mut self, _: &mut gpui::RenderContext<Self>) -> gpui::ElementBox {
121 Empty::new().boxed()
122 }
123}
124
125pub unsafe fn string_from_objc(string: id) -> String {
126 let len = msg_send![string, lengthOfBytesUsingEncoding: NSUTF8StringEncoding];
127 let bytes = string.UTF8String() as *const u8;
128 str::from_utf8(slice::from_raw_parts(bytes, len))
129 .unwrap()
130 .to_string()
131}
132
133extern "C" fn sample_output(this: &Object, _: Sel, stream: id, buffer: id, kind: NSInteger) {
134 println!("sample_output");
135}
136
137fn quit(_: &Quit, cx: &mut gpui::MutableAppContext) {
138 cx.platform().quit();
139}