Rework status bar item to use a custom view

This commit is contained in:
Antonio Scandurra 2022-09-13 16:20:34 +02:00
parent a102b3ba4b
commit 97ccb16c97
2 changed files with 75 additions and 34 deletions

View file

@ -21,8 +21,11 @@ impl View for ContactsStatusItem {
}) })
.boxed() .boxed()
}) })
.on_down(gpui::MouseButton::Left, |_, cx| {}) .on_down(gpui::MouseButton::Left, |_, _| {})
.on_up(gpui::MouseButton::Left, |_, cx| {}) .on_down_out(gpui::MouseButton::Left, |_, _| {})
.on_up(gpui::MouseButton::Left, |_, _| {})
.on_up_out(gpui::MouseButton::Left, |_, _| {})
.aligned()
.contained() .contained()
.with_background_color(Color::green()) .with_background_color(Color::green())
.boxed() .boxed()

View file

@ -1,15 +1,12 @@
use crate::{ use crate::{
geometry::vector::{vec2f, Vector2F}, geometry::vector::{vec2f, Vector2F},
platform::{self, mac::renderer::Renderer}, platform::{self, mac::renderer::Renderer},
Event, FontSystem, Scene, Window, Event, FontSystem, Scene,
}; };
use cocoa::{ use cocoa::{
appkit::{ appkit::{NSSquareStatusItemLength, NSStatusBar, NSStatusItem, NSView, NSWindow},
NSApplication, NSButton, NSEventMask, NSSquareStatusItemLength, NSStatusBar, NSStatusItem,
NSView, NSViewHeightSizable, NSViewWidthSizable, NSWindow,
},
base::{id, nil, YES}, base::{id, nil, YES},
foundation::{NSSize, NSUInteger}, foundation::{NSAutoreleasePool, NSPoint, NSRect, NSSize},
}; };
use ctor::ctor; use ctor::ctor;
use foreign_types::ForeignTypeRef; use foreign_types::ForeignTypeRef;
@ -29,21 +26,56 @@ use std::{
sync::Arc, sync::Arc,
}; };
static mut HANDLER_CLASS: *const Class = ptr::null(); static mut VIEW_CLASS: *const Class = ptr::null();
const STATE_IVAR: &str = "state"; const STATE_IVAR: &str = "state";
#[ctor] #[ctor]
unsafe fn build_classes() { unsafe fn build_classes() {
HANDLER_CLASS = { VIEW_CLASS = {
let mut decl = ClassDecl::new("GPUIStatusItemEventHandler", class!(NSObject)).unwrap(); let mut decl = ClassDecl::new("GPUIStatusItemView", class!(NSView)).unwrap();
decl.add_ivar::<*mut c_void>(STATE_IVAR); decl.add_ivar::<*mut c_void>(STATE_IVAR);
decl.add_method(sel!(dealloc), dealloc_view as extern "C" fn(&Object, Sel));
decl.add_method( decl.add_method(
sel!(dealloc), sel!(mouseDown:),
dealloc_handler as extern "C" fn(&Object, Sel), handle_view_event as extern "C" fn(&Object, Sel, id),
); );
decl.add_method( decl.add_method(
sel!(handleEvent), sel!(mouseUp:),
handle_event as extern "C" fn(&Object, Sel), handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(rightMouseDown:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(rightMouseUp:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(otherMouseDown:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(otherMouseUp:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(mouseMoved:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(mouseDragged:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(scrollWheel:),
handle_view_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(flagsChanged:),
handle_view_event as extern "C" fn(&Object, Sel, id),
); );
decl.register() decl.register()
@ -56,36 +88,39 @@ struct StatusItemState {
native_item: StrongPtr, native_item: StrongPtr,
renderer: Renderer, renderer: Renderer,
event_callback: Option<Box<dyn FnMut(Event) -> bool>>, event_callback: Option<Box<dyn FnMut(Event) -> bool>>,
_event_handler: StrongPtr,
} }
impl StatusItem { impl StatusItem {
pub fn add(fonts: Arc<dyn FontSystem>) -> Self { pub fn add(fonts: Arc<dyn FontSystem>) -> Self {
unsafe { unsafe {
let pool = NSAutoreleasePool::new(nil);
let renderer = Renderer::new(false, fonts); let renderer = Renderer::new(false, fonts);
let status_bar = NSStatusBar::systemStatusBar(nil); let status_bar = NSStatusBar::systemStatusBar(nil);
let native_item = let native_item =
StrongPtr::retain(status_bar.statusItemWithLength_(NSSquareStatusItemLength)); StrongPtr::retain(status_bar.statusItemWithLength_(NSSquareStatusItemLength));
let button = native_item.button(); let button = native_item.button();
button.setAutoresizingMask_(NSViewWidthSizable | NSViewHeightSizable); let _: () = msg_send![button, setHidden: YES];
button.setWantsBestResolutionOpenGLSurface_(YES);
button.setLayer(renderer.layer().as_ptr() as id);
let item = Self(Rc::new_cyclic(|state| { let item = Self(Rc::new_cyclic(|state| {
let event_handler = StrongPtr::new(msg_send![HANDLER_CLASS, alloc]); let parent_view = button.superview().superview();
let _: () = msg_send![*event_handler, init];
(**event_handler) let view: id = msg_send![VIEW_CLASS, alloc];
.set_ivar(STATE_IVAR, Weak::into_raw(state.clone()) as *const c_void); NSView::initWithFrame_(
button.setTarget_(*event_handler); view,
button.setAction_(sel!(handleEvent)); NSRect::new(NSPoint::new(0., 0.), NSView::frame(parent_view).size),
let _: () = msg_send![button, sendActionOn: NSEventMask::NSAnyEventMask]; );
view.setWantsBestResolutionOpenGLSurface_(YES);
view.setLayer(renderer.layer().as_ptr() as id);
view.setWantsLayer(true);
(*view).set_ivar(STATE_IVAR, Weak::into_raw(state.clone()) as *const c_void);
parent_view.addSubview_(view.autorelease());
RefCell::new(StatusItemState { RefCell::new(StatusItemState {
native_item, native_item,
renderer, renderer,
event_callback: None, event_callback: None,
_event_handler: event_handler,
}) })
})); }));
@ -98,6 +133,8 @@ impl StatusItem {
layer.set_drawable_size(metal::CGSize::new(size.x().into(), size.y().into())); layer.set_drawable_size(metal::CGSize::new(size.x().into(), size.y().into()));
} }
pool.drain();
item item
} }
} }
@ -192,8 +229,11 @@ impl platform::Window for StatusItem {
impl StatusItemState { impl StatusItemState {
fn size(&self) -> Vector2F { fn size(&self) -> Vector2F {
let NSSize { width, height, .. } = unsafe { NSView::frame(self.native_item.button()) }.size; unsafe {
vec2f(width as f32, height as f32) let NSSize { width, height, .. } =
NSWindow::frame(self.native_item.button().superview().superview()).size;
vec2f(width as f32, height as f32)
}
} }
fn scale_factor(&self) -> f32 { fn scale_factor(&self) -> f32 {
@ -204,19 +244,17 @@ impl StatusItemState {
} }
} }
extern "C" fn dealloc_handler(this: &Object, _: Sel) { extern "C" fn dealloc_view(this: &Object, _: Sel) {
unsafe { unsafe {
drop_state(this); drop_state(this);
let _: () = msg_send![super(this, class!(NSObject)), dealloc]; let _: () = msg_send![super(this, class!(NSView)), dealloc];
} }
} }
extern "C" fn handle_event(this: &Object, _: Sel) { extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
unsafe { unsafe {
if let Some(state) = get_state(this).upgrade() { if let Some(state) = get_state(this).upgrade() {
let mut state_borrow = state.as_ref().borrow_mut(); let mut state_borrow = state.as_ref().borrow_mut();
let app = NSApplication::sharedApplication(nil);
let native_event: id = msg_send![app, currentEvent];
if let Some(event) = Event::from_native(native_event, Some(state_borrow.size().y())) { if let Some(event) = Event::from_native(native_event, Some(state_borrow.size().y())) {
if let Some(mut callback) = state_borrow.event_callback.take() { if let Some(mut callback) = state_borrow.event_callback.take() {
drop(state_borrow); drop(state_borrow);