mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-25 01:34:02 +00:00
WIP: Start rendering GPUI views to macOS status bar
This commit is contained in:
parent
f50c6af001
commit
6578af6f3b
5 changed files with 235 additions and 132 deletions
|
@ -1920,19 +1920,134 @@ impl MutableAppContext {
|
|||
},
|
||||
);
|
||||
root_view.update(this, |view, cx| view.on_focus_in(cx.handle().into(), cx));
|
||||
this.open_platform_window(window_id, window_options);
|
||||
|
||||
let mut window =
|
||||
this.cx
|
||||
.platform
|
||||
.open_window(window_id, window_options, this.foreground.clone());
|
||||
let presenter = Rc::new(RefCell::new(
|
||||
this.build_presenter(window_id, window.titlebar_height()),
|
||||
));
|
||||
|
||||
{
|
||||
let mut app = this.upgrade();
|
||||
let presenter = Rc::downgrade(&presenter);
|
||||
window.on_event(Box::new(move |event| {
|
||||
app.update(|cx| {
|
||||
if let Some(presenter) = presenter.upgrade() {
|
||||
if let Event::KeyDown(KeyDownEvent { keystroke, .. }) = &event {
|
||||
if cx.dispatch_keystroke(window_id, keystroke) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
presenter.borrow_mut().dispatch_event(event, false, cx)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
let mut app = this.upgrade();
|
||||
window.on_active_status_change(Box::new(move |is_active| {
|
||||
app.update(|cx| cx.window_changed_active_status(window_id, is_active))
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
let mut app = this.upgrade();
|
||||
window.on_resize(Box::new(move || {
|
||||
app.update(|cx| cx.window_was_resized(window_id))
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
let mut app = this.upgrade();
|
||||
window.on_fullscreen(Box::new(move |is_fullscreen| {
|
||||
app.update(|cx| cx.window_was_fullscreen_changed(window_id, is_fullscreen))
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
let mut app = this.upgrade();
|
||||
window.on_close(Box::new(move || {
|
||||
app.update(|cx| cx.remove_window(window_id));
|
||||
}));
|
||||
}
|
||||
|
||||
window.set_input_handler(Box::new(WindowInputHandler {
|
||||
app: this.upgrade().0,
|
||||
window_id,
|
||||
}));
|
||||
|
||||
let scene = presenter.borrow_mut().build_scene(
|
||||
window.size(),
|
||||
window.scale_factor(),
|
||||
false,
|
||||
this,
|
||||
);
|
||||
window.present_scene(scene);
|
||||
this.presenters_and_platform_windows
|
||||
.insert(window_id, (presenter.clone(), window));
|
||||
|
||||
(window_id, root_view)
|
||||
})
|
||||
}
|
||||
|
||||
// pub fn add_status_bar_item<I, F>(&mut self, build_item: F)
|
||||
// where
|
||||
// I: View,
|
||||
// F: FnOnce(&mut ViewContext<I>) -> I,
|
||||
// {
|
||||
// mem::forget(self.platform.add_status_item());
|
||||
// }
|
||||
pub fn add_status_bar_item<T, F>(&mut self, build_root_view: F) -> (usize, ViewHandle<T>)
|
||||
where
|
||||
T: View,
|
||||
F: FnOnce(&mut ViewContext<T>) -> T,
|
||||
{
|
||||
self.update(|this| {
|
||||
let window_id = post_inc(&mut this.next_window_id);
|
||||
let root_view = this
|
||||
.build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx)))
|
||||
.unwrap();
|
||||
this.cx.windows.insert(
|
||||
window_id,
|
||||
Window {
|
||||
root_view: root_view.clone().into(),
|
||||
focused_view_id: Some(root_view.id()),
|
||||
is_active: false,
|
||||
invalidation: None,
|
||||
is_fullscreen: false,
|
||||
},
|
||||
);
|
||||
root_view.update(this, |view, cx| view.on_focus_in(cx.handle().into(), cx));
|
||||
|
||||
let mut status_item = this.cx.platform.add_status_item();
|
||||
let presenter = Rc::new(RefCell::new(this.build_presenter(window_id, 0.)));
|
||||
|
||||
{
|
||||
let mut app = this.upgrade();
|
||||
let presenter = Rc::downgrade(&presenter);
|
||||
status_item.on_event(Box::new(move |event| {
|
||||
app.update(|cx| {
|
||||
if let Some(presenter) = presenter.upgrade() {
|
||||
presenter.borrow_mut().dispatch_event(event, cx)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
}));
|
||||
}
|
||||
|
||||
let scene = presenter.borrow_mut().build_scene(
|
||||
status_item.size(),
|
||||
status_item.scale_factor(),
|
||||
false,
|
||||
this,
|
||||
);
|
||||
status_item.present_scene(scene);
|
||||
this.presenters_and_platform_windows
|
||||
.insert(window_id, (presenter.clone(), status_item));
|
||||
|
||||
(window_id, root_view)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn replace_root_view<T, F>(&mut self, window_id: usize, build_root_view: F) -> ViewHandle<T>
|
||||
where
|
||||
|
@ -1956,77 +2071,6 @@ impl MutableAppContext {
|
|||
self.flush_effects();
|
||||
}
|
||||
|
||||
fn open_platform_window(&mut self, window_id: usize, window_options: WindowOptions) {
|
||||
let mut window =
|
||||
self.cx
|
||||
.platform
|
||||
.open_window(window_id, window_options, self.foreground.clone());
|
||||
let presenter = Rc::new(RefCell::new(
|
||||
self.build_presenter(window_id, window.titlebar_height()),
|
||||
));
|
||||
|
||||
{
|
||||
let mut app = self.upgrade();
|
||||
let presenter = Rc::downgrade(&presenter);
|
||||
window.on_event(Box::new(move |event| {
|
||||
app.update(|cx| {
|
||||
if let Some(presenter) = presenter.upgrade() {
|
||||
if let Event::KeyDown(KeyDownEvent { keystroke, .. }) = &event {
|
||||
if cx.dispatch_keystroke(window_id, keystroke) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
presenter.borrow_mut().dispatch_event(event, false, cx)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
let mut app = self.upgrade();
|
||||
window.on_active_status_change(Box::new(move |is_active| {
|
||||
app.update(|cx| cx.window_changed_active_status(window_id, is_active))
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
let mut app = self.upgrade();
|
||||
window.on_resize(Box::new(move || {
|
||||
app.update(|cx| cx.window_was_resized(window_id))
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
let mut app = self.upgrade();
|
||||
window.on_fullscreen(Box::new(move |is_fullscreen| {
|
||||
app.update(|cx| cx.window_was_fullscreen_changed(window_id, is_fullscreen))
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
let mut app = self.upgrade();
|
||||
window.on_close(Box::new(move || {
|
||||
app.update(|cx| cx.remove_window(window_id));
|
||||
}));
|
||||
}
|
||||
|
||||
window.set_input_handler(Box::new(WindowInputHandler {
|
||||
app: self.upgrade().0,
|
||||
window_id,
|
||||
}));
|
||||
|
||||
let scene =
|
||||
presenter
|
||||
.borrow_mut()
|
||||
.build_scene(window.size(), window.scale_factor(), false, self);
|
||||
window.present_scene(scene);
|
||||
self.presenters_and_platform_windows
|
||||
.insert(window_id, (presenter.clone(), window));
|
||||
}
|
||||
|
||||
pub fn build_presenter(&mut self, window_id: usize, titlebar_height: f32) -> Presenter {
|
||||
Presenter::new(
|
||||
window_id,
|
||||
|
|
|
@ -52,7 +52,7 @@ pub trait Platform: Send + Sync {
|
|||
) -> Box<dyn Window>;
|
||||
fn key_window_id(&self) -> Option<usize>;
|
||||
|
||||
fn add_status_item(&self) -> Box<dyn StatusItem>;
|
||||
fn add_status_item(&self) -> Box<dyn Window>;
|
||||
|
||||
fn write_to_clipboard(&self, item: ClipboardItem);
|
||||
fn read_from_clipboard(&self) -> Option<ClipboardItem>;
|
||||
|
@ -134,8 +134,6 @@ pub trait Window {
|
|||
fn present_scene(&mut self, scene: Scene);
|
||||
}
|
||||
|
||||
pub trait StatusItem {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WindowOptions<'a> {
|
||||
pub bounds: WindowBounds,
|
||||
|
|
|
@ -495,8 +495,8 @@ impl platform::Platform for MacPlatform {
|
|||
Window::key_window_id()
|
||||
}
|
||||
|
||||
fn add_status_item(&self) -> Box<dyn platform::StatusItem> {
|
||||
Box::new(StatusItem::add())
|
||||
fn add_status_item(&self) -> Box<dyn platform::Window> {
|
||||
Box::new(StatusItem::add(self.fonts()))
|
||||
}
|
||||
|
||||
fn fonts(&self) -> Arc<dyn platform::FontSystem> {
|
||||
|
|
|
@ -1,60 +1,121 @@
|
|||
use cocoa::{
|
||||
appkit::{NSSquareStatusItemLength, NSStatusBar, NSStatusItem, NSView},
|
||||
base::{id, nil, NO, YES},
|
||||
quartzcore::AutoresizingMask,
|
||||
use crate::{
|
||||
geometry::vector::{vec2f, Vector2F},
|
||||
platform::{self, mac::renderer::Renderer},
|
||||
Event, FontSystem, Scene,
|
||||
};
|
||||
use core_foundation::base::TCFType;
|
||||
use core_graphics::color::CGColor;
|
||||
use foreign_types::ForeignType;
|
||||
use objc::{class, msg_send, rc::StrongPtr, sel, sel_impl};
|
||||
use cocoa::{
|
||||
appkit::{
|
||||
NSSquareStatusItemLength, NSStatusBar, NSStatusItem, NSView, NSViewHeightSizable,
|
||||
NSViewWidthSizable, NSWindow,
|
||||
},
|
||||
base::{id, nil, YES},
|
||||
foundation::NSSize,
|
||||
};
|
||||
use foreign_types::ForeignTypeRef;
|
||||
use objc::{msg_send, rc::StrongPtr, sel, sel_impl};
|
||||
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
||||
|
||||
pub struct StatusItem(StrongPtr);
|
||||
pub struct StatusItem(Rc<RefCell<StatusItemState>>);
|
||||
|
||||
struct StatusItemState {
|
||||
native_item: StrongPtr,
|
||||
renderer: Renderer,
|
||||
event_callback: Option<Box<dyn FnMut(Event) -> bool>>,
|
||||
}
|
||||
|
||||
impl StatusItem {
|
||||
pub fn add() -> Self {
|
||||
const PIXEL_FORMAT: metal::MTLPixelFormat = metal::MTLPixelFormat::BGRA8Unorm;
|
||||
|
||||
pub fn add(fonts: Arc<dyn FontSystem>) -> Self {
|
||||
unsafe {
|
||||
let renderer = Renderer::new(fonts);
|
||||
let status_bar = NSStatusBar::systemStatusBar(nil);
|
||||
let native_item =
|
||||
StrongPtr::retain(status_bar.statusItemWithLength_(NSSquareStatusItemLength));
|
||||
native_item.button().setWantsLayer(true);
|
||||
|
||||
let device: metal::Device = if let Some(device) = metal::Device::system_default() {
|
||||
device
|
||||
} else {
|
||||
log::error!("unable to access a compatible graphics device");
|
||||
std::process::exit(1);
|
||||
};
|
||||
let button = native_item.button();
|
||||
button.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable);
|
||||
button.setWantsBestResolutionOpenGLSurface_(YES);
|
||||
button.setLayer(renderer.layer().as_ptr() as id);
|
||||
|
||||
let layer: id = msg_send![class!(CAMetalLayer), layer];
|
||||
let _: () = msg_send![layer, setDevice: device.as_ptr()];
|
||||
let _: () = msg_send![layer, setPixelFormat: PIXEL_FORMAT];
|
||||
let _: () = msg_send![layer, setAllowsNextDrawableTimeout: NO];
|
||||
let _: () = msg_send![layer, setNeedsDisplayOnBoundsChange: YES];
|
||||
let _: () = msg_send![layer, setPresentsWithTransaction: YES];
|
||||
let _: () = msg_send![
|
||||
layer,
|
||||
setAutoresizingMask: AutoresizingMask::WIDTH_SIZABLE
|
||||
| AutoresizingMask::HEIGHT_SIZABLE
|
||||
];
|
||||
let _: () = msg_send![
|
||||
layer,
|
||||
setBackgroundColor: CGColor::rgb(1., 0., 0., 1.).as_concrete_TypeRef()
|
||||
];
|
||||
|
||||
let _: () = msg_send![native_item.button(), setLayer: layer];
|
||||
let native_item_window: id = msg_send![native_item.button(), window];
|
||||
|
||||
dbg!(native_item_window.frame().as_CGRect());
|
||||
// let rect_in_window: NSRect = msg_send![native_item.button(), convertRect: native_item.button().bounds() toView: nil];
|
||||
// let screen_rect: NSRect =
|
||||
// msg_send![native_item_window, convertRectToScreen: rect_in_window];
|
||||
// dbg!(screen_rect.as_CGRect());
|
||||
|
||||
StatusItem(native_item)
|
||||
Self(Rc::new(RefCell::new(StatusItemState {
|
||||
native_item,
|
||||
renderer,
|
||||
event_callback: None,
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::StatusItem for StatusItem {}
|
||||
impl platform::Window for StatusItem {
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn on_event(&mut self, callback: Box<dyn FnMut(crate::Event) -> bool>) {
|
||||
self.0.borrow_mut().event_callback = Some(callback);
|
||||
}
|
||||
|
||||
fn on_active_status_change(&mut self, _: Box<dyn FnMut(bool)>) {}
|
||||
|
||||
fn on_resize(&mut self, _: Box<dyn FnMut()>) {}
|
||||
|
||||
fn on_fullscreen(&mut self, _: Box<dyn FnMut(bool)>) {}
|
||||
|
||||
fn on_should_close(&mut self, _: Box<dyn FnMut() -> bool>) {}
|
||||
|
||||
fn on_close(&mut self, _: Box<dyn FnOnce()>) {}
|
||||
|
||||
fn set_input_handler(&mut self, _: Box<dyn crate::InputHandler>) {}
|
||||
|
||||
fn prompt(
|
||||
&self,
|
||||
_: crate::PromptLevel,
|
||||
_: &str,
|
||||
_: &[&str],
|
||||
) -> postage::oneshot::Receiver<usize> {
|
||||
panic!()
|
||||
}
|
||||
|
||||
fn activate(&self) {}
|
||||
|
||||
fn set_title(&mut self, _: &str) {}
|
||||
|
||||
fn set_edited(&mut self, _: bool) {}
|
||||
|
||||
fn show_character_palette(&self) {}
|
||||
|
||||
fn minimize(&self) {}
|
||||
|
||||
fn zoom(&self) {}
|
||||
|
||||
fn toggle_full_screen(&self) {}
|
||||
|
||||
fn size(&self) -> Vector2F {
|
||||
self.0.borrow().size()
|
||||
}
|
||||
|
||||
fn scale_factor(&self) -> f32 {
|
||||
self.0.borrow().scale_factor()
|
||||
}
|
||||
|
||||
fn titlebar_height(&self) -> f32 {
|
||||
0.
|
||||
}
|
||||
|
||||
fn present_scene(&mut self, scene: Scene) {
|
||||
self.0.borrow_mut().renderer.render(&scene);
|
||||
}
|
||||
}
|
||||
|
||||
impl StatusItemState {
|
||||
fn size(&self) -> Vector2F {
|
||||
let NSSize { width, height, .. } = unsafe { NSView::frame(self.native_item.button()) }.size;
|
||||
vec2f(width as f32, height as f32)
|
||||
}
|
||||
|
||||
fn scale_factor(&self) -> f32 {
|
||||
unsafe {
|
||||
let window: id = msg_send![self.native_item.button(), window];
|
||||
window.screen().backingScaleFactor() as f32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,8 +144,8 @@ impl super::Platform for Platform {
|
|||
None
|
||||
}
|
||||
|
||||
fn add_status_item(&self) -> Box<dyn crate::StatusItem> {
|
||||
todo!()
|
||||
fn add_status_item(&self) -> Box<dyn crate::Window> {
|
||||
Box::new(Window::new(vec2f(24., 24.)))
|
||||
}
|
||||
|
||||
fn write_to_clipboard(&self, item: ClipboardItem) {
|
||||
|
|
Loading…
Reference in a new issue