Merge pull request #2329 from zed-industries/new-window-on-click-doc

Max Brunsfeld created

Open a new window when activating Zed from the dock w/ no windows open

Change summary

crates/gpui/src/app.rs                   | 17 +++++++++--
crates/gpui/src/platform.rs              |  4 ++
crates/gpui/src/platform/mac/platform.rs | 37 +++++++++++++++++++------
crates/gpui/src/platform/test.rs         |  5 --
crates/zed/src/main.rs                   |  3 +
5 files changed, 49 insertions(+), 17 deletions(-)

Detailed changes

crates/gpui/src/app.rs 🔗

@@ -254,6 +254,19 @@ impl App {
         self
     }
 
+    /// Handle the application being re-activated when no windows are open.
+    pub fn on_reopen<F>(&mut self, mut callback: F) -> &mut Self
+    where
+        F: 'static + FnMut(&mut MutableAppContext),
+    {
+        let cx = self.0.clone();
+        self.0
+            .borrow_mut()
+            .foreground_platform
+            .on_reopen(Box::new(move || callback(&mut *cx.borrow_mut())));
+        self
+    }
+
     pub fn on_event<F>(&mut self, mut callback: F) -> &mut Self
     where
         F: 'static + FnMut(Event, &mut MutableAppContext) -> bool,
@@ -276,9 +289,7 @@ impl App {
         self.0
             .borrow_mut()
             .foreground_platform
-            .on_open_urls(Box::new(move |paths| {
-                callback(paths, &mut *cx.borrow_mut())
-            }));
+            .on_open_urls(Box::new(move |urls| callback(urls, &mut *cx.borrow_mut())));
         self
     }
 

crates/gpui/src/platform.rs 🔗

@@ -90,6 +90,10 @@ pub(crate) trait ForegroundPlatform {
     fn on_become_active(&self, callback: Box<dyn FnMut()>);
     fn on_resign_active(&self, callback: Box<dyn FnMut()>);
     fn on_quit(&self, callback: Box<dyn FnMut()>);
+
+    /// Handle the application being re-activated with no windows open.
+    fn on_reopen(&self, callback: Box<dyn FnMut()>);
+
     fn on_event(&self, callback: Box<dyn FnMut(Event) -> bool>);
     fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>);
     fn run(&self, on_finish_launching: Box<dyn FnOnce()>);

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

@@ -82,6 +82,10 @@ unsafe fn build_classes() {
             sel!(applicationDidFinishLaunching:),
             did_finish_launching as extern "C" fn(&mut Object, Sel, id),
         );
+        decl.add_method(
+            sel!(applicationShouldHandleReopen:hasVisibleWindows:),
+            should_handle_reopen as extern "C" fn(&mut Object, Sel, id, bool),
+        );
         decl.add_method(
             sel!(applicationDidBecomeActive:),
             did_become_active as extern "C" fn(&mut Object, Sel, id),
@@ -144,6 +148,7 @@ pub struct MacForegroundPlatform(RefCell<MacForegroundPlatformState>);
 pub struct MacForegroundPlatformState {
     become_active: Option<Box<dyn FnMut()>>,
     resign_active: Option<Box<dyn FnMut()>>,
+    reopen: Option<Box<dyn FnMut()>>,
     quit: Option<Box<dyn FnMut()>>,
     event: Option<Box<dyn FnMut(crate::Event) -> bool>>,
     menu_command: Option<Box<dyn FnMut(&dyn Action)>>,
@@ -158,15 +163,16 @@ pub struct MacForegroundPlatformState {
 impl MacForegroundPlatform {
     pub fn new(foreground: Rc<executor::Foreground>) -> Self {
         Self(RefCell::new(MacForegroundPlatformState {
-            become_active: Default::default(),
-            resign_active: Default::default(),
-            quit: Default::default(),
-            event: Default::default(),
-            menu_command: Default::default(),
-            validate_menu_command: Default::default(),
-            will_open_menu: Default::default(),
-            open_urls: Default::default(),
-            finish_launching: Default::default(),
+            become_active: None,
+            resign_active: None,
+            reopen: None,
+            quit: None,
+            event: None,
+            menu_command: None,
+            validate_menu_command: None,
+            will_open_menu: None,
+            open_urls: None,
+            finish_launching: None,
             menu_actions: Default::default(),
             foreground,
         }))
@@ -332,6 +338,10 @@ impl platform::ForegroundPlatform for MacForegroundPlatform {
         self.0.borrow_mut().quit = Some(callback);
     }
 
+    fn on_reopen(&self, callback: Box<dyn FnMut()>) {
+        self.0.borrow_mut().reopen = Some(callback);
+    }
+
     fn on_event(&self, callback: Box<dyn FnMut(crate::Event) -> bool>) {
         self.0.borrow_mut().event = Some(callback);
     }
@@ -943,6 +953,15 @@ extern "C" fn did_finish_launching(this: &mut Object, _: Sel, _: id) {
     }
 }
 
+extern "C" fn should_handle_reopen(this: &mut Object, _: Sel, _: id, has_open_windows: bool) {
+    if !has_open_windows {
+        let platform = unsafe { get_foreground_platform(this) };
+        if let Some(callback) = platform.0.borrow_mut().reopen.as_mut() {
+            callback();
+        }
+    }
+}
+
 extern "C" fn did_become_active(this: &mut Object, _: Sel, _: id) {
     let platform = unsafe { get_foreground_platform(this) };
     if let Some(callback) = platform.0.borrow_mut().become_active.as_mut() {

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

@@ -61,13 +61,10 @@ impl ForegroundPlatform {
 
 impl super::ForegroundPlatform for ForegroundPlatform {
     fn on_become_active(&self, _: Box<dyn FnMut()>) {}
-
     fn on_resign_active(&self, _: Box<dyn FnMut()>) {}
-
     fn on_quit(&self, _: Box<dyn FnMut()>) {}
-
+    fn on_reopen(&self, _: Box<dyn FnMut()>) {}
     fn on_event(&self, _: Box<dyn FnMut(crate::Event) -> bool>) {}
-
     fn on_open_urls(&self, _: Box<dyn FnMut(Vec<String>)>) {}
 
     fn run(&self, _on_finish_launching: Box<dyn FnOnce()>) {

crates/zed/src/main.rs 🔗

@@ -105,7 +105,8 @@ fn main() {
                 .map_err(|_| anyhow!("no listener for open urls requests"))
                 .log_err();
         }
-    });
+    })
+    .on_reopen(move |cx| cx.dispatch_global_action(NewFile));
 
     app.run(move |cx| {
         cx.set_global(*RELEASE_CHANNEL);