From 69bb0a0597f74704604805a5ddff5df7207b0f3b Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 4 Feb 2025 12:23:20 -0800 Subject: [PATCH] Fix slow focus transitions to the terminal panel (#24172) This long standing bug was caused by `Pane`'s focus_in handler bouncing the focus to another handle. Because focus resolution happens _after_ a frame has been rendered, the only way to deal with this case is to schedule another frame to be redrawn. However, we where suppressing all window refreshes that occur during a focus transfer, causing this focus change to be completely missed. However, changing this behavior can lead to infinite notify loops, due to drawing a frame causing another to be rendered. This PR fixes this problem narrowly by adding an `on_next_frame()` callback in the pane's focus handle, so that the focus changes take effect almost immediately. But only for this case, where we know it doesn't cause infinite notify loops. TODO: - [x] Fix the infinite notify loop bug or determine a third way to fix this lag Release Notes: - Fixed a bug where shifting focus to the terminal panel could be slow --- crates/gpui/src/window.rs | 4 ++-- crates/workspace/src/pane.rs | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index e522ea85957..1b5b6bc7178 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -137,7 +137,7 @@ impl WindowInvalidator { self.inner.borrow_mut().dirty_views = views; } - pub fn not_painting(&self) -> bool { + pub fn not_drawing(&self) -> bool { self.inner.borrow().draw_phase == DrawPhase::None } @@ -1035,7 +1035,7 @@ impl Window { /// Mark the window as dirty, scheduling it to be redrawn on the next frame. pub fn refresh(&mut self) { - if self.invalidator.not_painting() { + if self.invalidator.not_drawing() { self.refreshing = true; self.invalidator.set_dirty(true); } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index f161501e23c..4480f4acbfc 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -582,6 +582,11 @@ impl Pane { if let Some(active_item) = self.active_item() { if self.focus_handle.is_focused(window) { + // Schedule a redraw next frame, so that the focus changes below take effect + cx.on_next_frame(window, |_, _, cx| { + cx.notify(); + }); + // Pane was focused directly. We need to either focus a view inside the active item, // or focus the active item itself if let Some(weak_last_focus_handle) =