Merge pull request #1458 from zed-industries/macos-default-menu-items

Antonio Scandurra created

Implement default macOS menu items

Change summary

assets/keymaps/default.json              |  3 +++
crates/gpui/src/app.rs                   | 18 ++++++++++++++++++
crates/gpui/src/platform.rs              |  5 +++++
crates/gpui/src/platform/mac/platform.rs | 21 +++++++++++++++++++++
crates/gpui/src/platform/mac/window.rs   | 19 +++++++++++++++++++
crates/gpui/src/platform/test.rs         | 10 ++++++++++
crates/zed/src/menus.rs                  | 25 ++++++++++++++++++++++++-
crates/zed/src/zed.rs                    | 24 ++++++++++++++++++++++++
8 files changed, 124 insertions(+), 1 deletion(-)

Detailed changes

assets/keymaps/default.json 🔗

@@ -25,6 +25,9 @@
             "cmd-0": "zed::ResetBufferFontSize",
             "cmd-,": "zed::OpenSettings",
             "cmd-q": "zed::Quit",
+            "cmd-h": "zed::Hide",
+            "alt-cmd-h": "zed::HideOthers",
+            "cmd-m": "zed::Minimize",
             "cmd-n": "workspace::NewFile",
             "cmd-shift-n": "workspace::NewWindow",
             "cmd-o": "workspace::Open"

crates/gpui/src/app.rs 🔗

@@ -1319,6 +1319,16 @@ impl MutableAppContext {
         window.show_character_palette();
     }
 
+    pub fn minimize_window(&self, window_id: usize) {
+        let (_, window) = &self.presenters_and_platform_windows[&window_id];
+        window.minimize();
+    }
+
+    pub fn zoom_window(&self, window_id: usize) {
+        let (_, window) = &self.presenters_and_platform_windows[&window_id];
+        window.zoom();
+    }
+
     fn prompt(
         &self,
         window_id: usize,
@@ -3686,6 +3696,14 @@ impl<'a, T: View> ViewContext<'a, T> {
         self.app.show_character_palette(self.window_id);
     }
 
+    pub fn minimize_window(&self) {
+        self.app.minimize_window(self.window_id)
+    }
+
+    pub fn zoom_window(&self) {
+        self.app.zoom_window(self.window_id)
+    }
+
     pub fn prompt(
         &self,
         level: PromptLevel,

crates/gpui/src/platform.rs 🔗

@@ -46,6 +46,9 @@ pub trait Platform: Send + Sync {
         executor: Rc<executor::Foreground>,
     ) -> Box<dyn Window>;
     fn key_window_id(&self) -> Option<usize>;
+    fn hide(&self);
+    fn hide_other_apps(&self);
+    fn unhide_other_apps(&self);
     fn quit(&self);
 
     fn write_to_clipboard(&self, item: ClipboardItem);
@@ -117,6 +120,8 @@ pub trait Window: WindowContext {
     fn set_title(&mut self, title: &str);
     fn set_edited(&mut self, edited: bool);
     fn show_character_palette(&self);
+    fn minimize(&self);
+    fn zoom(&self);
 }
 
 pub trait WindowContext {

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

@@ -456,6 +456,27 @@ impl platform::Platform for MacPlatform {
         self.fonts.clone()
     }
 
+    fn hide(&self) {
+        unsafe {
+            let app = NSApplication::sharedApplication(nil);
+            let _: () = msg_send![app, hide: nil];
+        }
+    }
+
+    fn hide_other_apps(&self) {
+        unsafe {
+            let app = NSApplication::sharedApplication(nil);
+            let _: () = msg_send![app, hideOtherApplications: nil];
+        }
+    }
+
+    fn unhide_other_apps(&self) {
+        unsafe {
+            let app = NSApplication::sharedApplication(nil);
+            let _: () = msg_send![app, unhideAllApplications: nil];
+        }
+    }
+
     fn quit(&self) {
         // Quitting the app causes us to close windows, which invokes `Window::on_close` callbacks
         // synchronously before this method terminates. If we call `Platform::quit` while holding a

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

@@ -568,6 +568,25 @@ impl platform::Window for Window {
             let _: () = msg_send![app, orderFrontCharacterPalette: window];
         }
     }
+
+    fn minimize(&self) {
+        let window = self.0.borrow().native_window;
+        unsafe {
+            window.miniaturize_(nil);
+        }
+    }
+
+    fn zoom(&self) {
+        let this = self.0.borrow();
+        let window = this.native_window;
+        this.executor
+            .spawn(async move {
+                unsafe {
+                    window.zoom_(nil);
+                }
+            })
+            .detach();
+    }
 }
 
 impl platform::WindowContext for Window {

crates/gpui/src/platform/test.rs 🔗

@@ -135,6 +135,12 @@ impl super::Platform for Platform {
         None
     }
 
+    fn hide(&self) {}
+
+    fn hide_other_apps(&self) {}
+
+    fn unhide_other_apps(&self) {}
+
     fn quit(&self) {}
 
     fn write_to_clipboard(&self, item: ClipboardItem) {
@@ -278,6 +284,10 @@ impl super::Window for Window {
     }
 
     fn show_character_palette(&self) {}
+
+    fn minimize(&self) {}
+
+    fn zoom(&self) {}
 }
 
 pub fn platform() -> Platform {

crates/zed/src/menus.rs 🔗

@@ -45,6 +45,18 @@ pub fn menus() -> Vec<Menu<'static>> {
                     action: Box::new(super::InstallCommandLineInterface),
                 },
                 MenuItem::Separator,
+                MenuItem::Action {
+                    name: "Hide Zed",
+                    action: Box::new(super::Hide),
+                },
+                MenuItem::Action {
+                    name: "Hide Others",
+                    action: Box::new(super::HideOthers),
+                },
+                MenuItem::Action {
+                    name: "Show All",
+                    action: Box::new(super::ShowAll),
+                },
                 MenuItem::Action {
                     name: "Quit",
                     action: Box::new(super::Quit),
@@ -244,6 +256,7 @@ pub fn menus() -> Vec<Menu<'static>> {
                     name: "Diagnostics",
                     action: Box::new(diagnostics::Deploy),
                 },
+                MenuItem::Separator,
             ],
         },
         Menu {
@@ -299,7 +312,17 @@ pub fn menus() -> Vec<Menu<'static>> {
         },
         Menu {
             name: "Window",
-            items: vec![MenuItem::Separator],
+            items: vec![
+                MenuItem::Action {
+                    name: "Minimize",
+                    action: Box::new(super::Minimize),
+                },
+                MenuItem::Action {
+                    name: "Zoom",
+                    action: Box::new(super::Zoom),
+                },
+                MenuItem::Separator,
+            ],
         },
         Menu {
             name: "Help",

crates/zed/src/zed.rs 🔗

@@ -46,6 +46,11 @@ actions!(
     zed,
     [
         About,
+        Hide,
+        HideOthers,
+        ShowAll,
+        Minimize,
+        Zoom,
         Quit,
         DebugElements,
         OpenSettings,
@@ -64,6 +69,25 @@ const MIN_FONT_SIZE: f32 = 6.0;
 
 pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
     cx.add_action(about);
+    cx.add_global_action(|_: &Hide, cx: &mut gpui::MutableAppContext| {
+        cx.platform().hide();
+    });
+    cx.add_global_action(|_: &HideOthers, cx: &mut gpui::MutableAppContext| {
+        cx.platform().hide_other_apps();
+    });
+    cx.add_global_action(|_: &ShowAll, cx: &mut gpui::MutableAppContext| {
+        cx.platform().unhide_other_apps();
+    });
+    cx.add_action(
+        |_: &mut Workspace, _: &Minimize, cx: &mut ViewContext<Workspace>| {
+            cx.minimize_window();
+        },
+    );
+    cx.add_action(
+        |_: &mut Workspace, _: &Zoom, cx: &mut ViewContext<Workspace>| {
+            cx.zoom_window();
+        },
+    );
     cx.add_global_action(quit);
     cx.add_global_action(move |action: &OpenBrowser, cx| cx.platform().open_url(&action.url));
     cx.add_global_action(move |_: &IncreaseBufferFontSize, cx| {