Transfer focus to the workspace when window focus is lost

Antonio Scandurra created

Change summary

crates/gpui2/src/app.rs             |  2 --
crates/gpui2/src/window.rs          | 23 +++++++++++++++++++++++
crates/workspace2/src/workspace2.rs |  5 +++++
3 files changed, 28 insertions(+), 2 deletions(-)

Detailed changes

crates/gpui2/src/app.rs 🔗

@@ -646,8 +646,6 @@ impl AppContext {
     }
 
     /// Repeatedly called during `flush_effects` to handle a focused handle being dropped.
-    /// For now, we simply blur the window if this happens, but we may want to support invoking
-    /// a window blur handler to restore focus to some logical element.
     fn release_dropped_focus_handles(&mut self) {
         for window_handle in self.windows() {
             window_handle

crates/gpui2/src/window.rs 🔗

@@ -2419,6 +2419,29 @@ impl<'a, V: 'static> ViewContext<'a, V> {
         subscription
     }
 
+    /// Register a listener to be called when the window loses focus.
+    /// Unlike [on_focus_changed], returns a subscription and persists until the subscription
+    /// is dropped.
+    pub fn on_window_focus_lost(
+        &mut self,
+        mut listener: impl FnMut(&mut V, &mut ViewContext<V>) + 'static,
+    ) -> Subscription {
+        let view = self.view.downgrade();
+        let (subscription, activate) = self.window.focus_listeners.insert(
+            (),
+            Box::new(move |event, cx| {
+                view.update(cx, |view, cx| {
+                    if event.blurred.is_none() && event.focused.is_none() {
+                        listener(view, cx)
+                    }
+                })
+                .is_ok()
+            }),
+        );
+        self.app.defer(move |_| activate());
+        subscription
+    }
+
     /// Register a listener to be called when the given focus handle or one of its descendants loses focus.
     /// Unlike [on_focus_changed], returns a subscription and persists until the subscription
     /// is dropped.

crates/workspace2/src/workspace2.rs 🔗

@@ -532,6 +532,11 @@ impl Workspace {
             cx.notify()
         })
         .detach();
+        cx.on_window_focus_lost(|this, cx| {
+            let focus_handle = this.focus_handle(cx);
+            cx.focus(&focus_handle);
+        })
+        .detach();
 
         let weak_handle = cx.view().downgrade();
         let pane_history_timestamp = Arc::new(AtomicUsize::new(0));