WIP: Show status bar item with a backing metal layer

Antonio Scandurra and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

crates/gpui/src/platform/mac/status_item.rs | 54 +++++++++++++++++++---
crates/zed/src/main.rs                      |  1 
2 files changed, 45 insertions(+), 10 deletions(-)

Detailed changes

crates/gpui/src/platform/mac/status_item.rs 🔗

@@ -1,22 +1,58 @@
 use cocoa::{
-    appkit::{NSSquareStatusItemLength, NSStatusBar},
-    base::{id, nil},
+    appkit::{NSSquareStatusItemLength, NSStatusBar, NSStatusItem, NSView},
+    base::{id, nil, NO, YES},
+    foundation::NSRect,
+    quartzcore::AutoresizingMask,
 };
 use core_foundation::base::TCFType;
 use core_graphics::color::CGColor;
-use objc::{msg_send, sel, sel_impl};
+use foreign_types::ForeignType;
+use objc::{class, msg_send, rc::StrongPtr, sel, sel_impl};
 
-pub struct StatusItem(id);
+pub struct StatusItem(StrongPtr);
 
 impl StatusItem {
     pub fn add() -> Self {
+        const PIXEL_FORMAT: metal::MTLPixelFormat = metal::MTLPixelFormat::BGRA8Unorm;
+
         unsafe {
             let status_bar = NSStatusBar::systemStatusBar(nil);
-            let native_item: id =
-                msg_send![status_bar, statusItemWithLength: NSSquareStatusItemLength];
-            let button: id = msg_send![native_item, button];
-            let layer: id = msg_send![button, layer];
-            let _: () = msg_send![layer, setBackgroundColor: CGColor::rgb(1., 0., 0., 1.).as_concrete_TypeRef()];
+            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 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)
         }
     }

crates/zed/src/main.rs 🔗

@@ -88,7 +88,6 @@ fn main() {
 
     app.run(move |cx| {
         std::mem::forget(cx.platform().add_status_item());
-
         let client = client::Client::new(http.clone());
         let mut languages = LanguageRegistry::new(login_shell_env_loaded);
         languages.set_language_server_download_dir(zed::paths::LANGUAGES_DIR.clone());